aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile18
-rw-r--r--common/fdt_fixup.c15
-rw-r--r--docs/change-log-upcoming.rst145
-rw-r--r--docs/components/secure-partition-manager-design.rst4
-rw-r--r--docs/getting_started/initial-build.rst9
-rw-r--r--docs/index.rst1
-rw-r--r--docs/plat/stm32mp1.rst23
-rw-r--r--docs/plat/xilinx-versal.rst10
-rw-r--r--drivers/intel/soc/stratix10/io/s10_memmap_qspi.c18
-rw-r--r--drivers/io/io_block.c60
-rw-r--r--drivers/io/io_fip.c6
-rw-r--r--drivers/io/io_memmap.c30
-rw-r--r--drivers/io/io_mtd.c248
-rw-r--r--drivers/io/io_semihosting.c6
-rw-r--r--drivers/io/io_storage.c2
-rw-r--r--drivers/mtd/nand/core.c118
-rw-r--r--drivers/mtd/nand/raw_nand.c446
-rw-r--r--drivers/mtd/nand/spi_nand.c320
-rw-r--r--drivers/mtd/nor/spi_nor.c387
-rw-r--r--drivers/mtd/spi-mem/spi_mem.c288
-rw-r--r--drivers/renesas/rcar/io/io_emmcdrv.c20
-rw-r--r--drivers/renesas/rcar/io/io_memdrv.c19
-rw-r--r--drivers/st/fmc/stm32_fmc2_nand.c877
-rw-r--r--drivers/st/io/io_mmc.c10
-rw-r--r--drivers/st/spi/stm32_qspi.c500
-rw-r--r--fdts/fvp-base-gicv2-psci-aarch32.dts4
-rw-r--r--fdts/fvp-base-gicv2-psci.dts4
-rw-r--r--fdts/fvp-base-gicv3-psci-1t.dts4
-rw-r--r--fdts/fvp-base-gicv3-psci-aarch32-1t.dts4
-rw-r--r--fdts/fvp-base-gicv3-psci-aarch32-common.dtsi4
-rw-r--r--fdts/fvp-base-gicv3-psci-aarch32.dts4
-rw-r--r--fdts/fvp-base-gicv3-psci-common.dtsi4
-rw-r--r--fdts/fvp-base-gicv3-psci-dynamiq-2t.dts4
-rw-r--r--fdts/fvp-base-gicv3-psci-dynamiq.dts4
-rw-r--r--fdts/fvp-base-gicv3-psci.dts4
-rw-r--r--fdts/fvp-foundation-gicv2-psci.dts4
-rw-r--r--fdts/fvp-foundation-gicv3-psci.dts4
-rw-r--r--fdts/fvp-ve-Cortex-A5x1.dts4
-rw-r--r--fdts/fvp-ve-Cortex-A7x1.dts4
-rw-r--r--fdts/stm32mp157-pinctrl.dtsi27
-rw-r--r--fdts/stm32mp157c-ev1.dts18
-rw-r--r--include/drivers/io/io_driver.h2
-rw-r--r--include/drivers/io/io_mtd.h59
-rw-r--r--include/drivers/io/io_storage.h5
-rw-r--r--include/drivers/nand.h55
-rw-r--r--include/drivers/raw_nand.h187
-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/io_stm32image.h2
-rw-r--r--include/drivers/st/stm32_fmc2_nand.h12
-rw-r--r--include/drivers/st/stm32_qspi.h12
-rw-r--r--include/lib/utils_def.h9
-rw-r--r--lib/compiler-rt/builtins/arm/aeabi_ldivmod.S46
-rw-r--r--lib/compiler-rt/builtins/divdi3.c29
-rw-r--r--lib/compiler-rt/builtins/divmoddi4.c25
-rw-r--r--lib/compiler-rt/builtins/popcountdi2.c36
-rw-r--r--lib/compiler-rt/builtins/popcountsi2.c33
-rw-r--r--lib/compiler-rt/compiler-rt.mk14
-rw-r--r--lib/cpus/cpu-ops.mk4
-rw-r--r--make_helpers/build_macros.mk4
-rw-r--r--plat/allwinner/common/include/platform_def.h2
-rw-r--r--plat/allwinner/common/sunxi_common.c11
-rw-r--r--plat/imx/common/plat_imx8_gic.c4
-rw-r--r--plat/imx/imx8m/imx8mm/imx8mm_bl31_setup.c12
-rw-r--r--plat/imx/imx8m/imx8mm/include/platform_def.h1
-rw-r--r--plat/imx/imx8m/imx8mm/platform.mk6
-rw-r--r--plat/imx/imx8m/imx8mq/imx8mq_bl31_setup.c12
-rw-r--r--plat/imx/imx8m/imx8mq/include/platform_def.h1
-rw-r--r--plat/imx/imx8m/imx8mq/platform.mk6
-rw-r--r--plat/nvidia/tegra/include/t194/tegra_def.h8
-rw-r--r--plat/nvidia/tegra/include/t194/tegra_mc_def.h11
-rw-r--r--plat/nvidia/tegra/soc/t194/drivers/include/mce_private.h5
-rw-r--r--plat/nvidia/tegra/soc/t194/drivers/include/t194_nvg.h7
-rw-r--r--plat/nvidia/tegra/soc/t194/drivers/mce/mce.c20
-rw-r--r--plat/nvidia/tegra/soc/t194/drivers/mce/nvg.c24
-rw-r--r--plat/nvidia/tegra/soc/t194/plat_memctrl.c41
-rw-r--r--plat/nvidia/tegra/soc/t194/plat_psci_handlers.c96
-rw-r--r--plat/nvidia/tegra/soc/t194/plat_setup.c21
-rw-r--r--plat/nvidia/tegra/soc/t194/platform_t194.mk15
-rw-r--r--plat/renesas/rcar/bl2_plat_setup.c3
-rw-r--r--plat/rpi/common/rpi3_pm.c10
-rw-r--r--plat/st/common/bl2_io_storage.c242
-rw-r--r--plat/st/common/include/stm32mp_dt.h2
-rw-r--r--plat/st/common/stm32mp_dt.c92
-rw-r--r--plat/st/stm32mp1/include/boot_api.h9
-rw-r--r--plat/st/stm32mp1/include/platform_def.h1
-rw-r--r--plat/st/stm32mp1/include/stm32mp1_boot_device.h18
-rw-r--r--plat/st/stm32mp1/platform.mk53
-rw-r--r--plat/st/stm32mp1/stm32mp1_boot_device.c170
-rw-r--r--plat/st/stm32mp1/stm32mp1_def.h81
-rw-r--r--plat/xilinx/common/include/plat_startup.h22
-rw-r--r--plat/xilinx/common/include/pm_client.h (renamed from plat/xilinx/zynqmp/pm_service/pm_client.h)11
-rw-r--r--plat/xilinx/common/include/pm_ipi.h5
-rw-r--r--plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c (renamed from plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.c)2
-rw-r--r--plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.h (renamed from plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.h)2
-rw-r--r--plat/xilinx/common/plat_startup.c (renamed from plat/xilinx/zynqmp/plat_startup.c)14
-rw-r--r--plat/xilinx/common/pm_service/pm_ipi.c64
-rw-r--r--plat/xilinx/versal/aarch64/versal_common.c25
-rw-r--r--plat/xilinx/versal/bl31_versal_setup.c42
-rw-r--r--plat/xilinx/versal/include/plat_ipi.h55
-rw-r--r--plat/xilinx/versal/include/plat_pm_common.h26
-rw-r--r--plat/xilinx/versal/include/plat_private.h (renamed from plat/xilinx/versal/versal_private.h)10
-rw-r--r--plat/xilinx/versal/include/platform_def.h13
-rw-r--r--plat/xilinx/versal/include/versal_def.h (renamed from plat/xilinx/versal/versal_def.h)44
-rw-r--r--plat/xilinx/versal/plat_psci.c221
-rw-r--r--plat/xilinx/versal/plat_versal.c5
-rw-r--r--plat/xilinx/versal/platform.mk27
-rw-r--r--plat/xilinx/versal/pm_service/pm_api_sys.c885
-rw-r--r--plat/xilinx/versal/pm_service/pm_api_sys.h75
-rw-r--r--plat/xilinx/versal/pm_service/pm_client.c249
-rw-r--r--plat/xilinx/versal/pm_service/pm_defs.h166
-rw-r--r--plat/xilinx/versal/pm_service/pm_node.h192
-rw-r--r--plat/xilinx/versal/pm_service/pm_svc_main.c328
-rw-r--r--plat/xilinx/versal/pm_service/pm_svc_main.h17
-rw-r--r--plat/xilinx/versal/sip_svc_setup.c22
-rw-r--r--plat/xilinx/versal/versal_gicv3.c5
-rw-r--r--plat/xilinx/versal/versal_ipi.c82
-rw-r--r--plat/xilinx/zynqmp/bl31_zynqmp_setup.c11
-rw-r--r--plat/xilinx/zynqmp/include/plat_pm_common.h13
-rw-r--r--plat/xilinx/zynqmp/include/plat_private.h12
-rw-r--r--plat/xilinx/zynqmp/plat_psci.c5
-rw-r--r--plat/xilinx/zynqmp/platform.mk24
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_api_clock.c67
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_api_clock.h5
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_api_sys.c40
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_api_sys.h4
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_svc_main.c23
-rw-r--r--tools/cert_create/src/cert.c8
-rw-r--r--tools/cert_create/src/key.c8
-rw-r--r--tools/cert_create/src/main.c11
131 files changed, 7858 insertions, 418 deletions
diff --git a/Makefile b/Makefile
index 42fdb73261..c740993f4a 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -209,7 +209,10 @@ PP = $(CC) -E $(TF_CFLAGS_$(ARCH))
else ifneq ($(findstring clang,$(notdir $(CC))),)
TF_CFLAGS_aarch32 = $(target32-directive) $(march32-directive)
TF_CFLAGS_aarch64 = -target aarch64-elf $(march64-directive)
-LD = $(LINKER)
+LD = ld.lld
+ifeq (, $(shell which $(LD)))
+$(error "No $(LD) in PATH, make sure it is installed or set LD to a different linker")
+endif
AS = $(CC) -c -x assembler-with-cpp $(TF_CFLAGS_$(ARCH))
CPP = $(CC) -E
PP = $(CC) -E
@@ -317,10 +320,13 @@ 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
@@ -337,14 +343,20 @@ ifneq (${ERRATA_A53_843419},1)
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 += -nostdinc -Iinclude -undef -x assembler-with-cpp
+DTC_CPPFLAGS += -P -nostdinc -Iinclude -Ifdts -undef -x assembler-with-cpp
################################################################################
# Common sources and include directories
diff --git a/common/fdt_fixup.c b/common/fdt_fixup.c
index 99d0eee982..d518eb2a4f 100644
--- a/common/fdt_fixup.c
+++ b/common/fdt_fixup.c
@@ -95,7 +95,7 @@ int dt_add_psci_node(void *fdt)
* or none have to be patched in the first place.
* Returns 1 if *one* such subnode has been found and successfully changed
* to "psci".
- * Returns -1 on error.
+ * Returns negative values on error.
*
* Call in a loop until it returns 0. Recalculate the node offset after
* it has returned 1.
@@ -109,20 +109,23 @@ static int dt_update_one_cpu_node(void *fdt, int offset)
offs = fdt_next_subnode(fdt, offs)) {
const char *prop;
int len;
+ int ret;
prop = fdt_getprop(fdt, offs, "device_type", &len);
- if (!prop)
+ if (prop == NULL)
continue;
- if (memcmp(prop, "cpu", 4) != 0 || len != 4)
+ 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 && memcmp(prop, "psci", 5) == 0 && len == 5)
+ if ((prop != NULL) &&
+ (strcmp(prop, "psci") == 0) && (len == 5))
continue;
- if (fdt_setprop_string(fdt, offs, "enable-method", "psci"))
- return -1;
+ ret = fdt_setprop_string(fdt, offs, "enable-method", "psci");
+ if (ret < 0)
+ return ret;
/*
* Subnode found and patched.
* Restart to accommodate potentially changed offsets.
diff --git a/docs/change-log-upcoming.rst b/docs/change-log-upcoming.rst
new file mode 100644
index 0000000000..3d7d5094d2
--- /dev/null
+++ b/docs/change-log-upcoming.rst
@@ -0,0 +1,145 @@
+Change Log for Upcoming Release
+===============================
+
+This document contains a summary of the new features, changes, fixes and known
+issues to be included in the upcoming release of Trusted Firmware-A. The contents
+of this file will be moved to the collective change-log.rst file at the time of
+release code freeze.
+
+
+Upcoming Release Version 2.3
+----------------------------
+
+**Trusted Firmware-A Contributors,
+Please log all relevant new features, changes, fixes, and known issues for the
+upcoming release. For the CPU support, drivers, and tools sections please preface
+the log description with the relevant key word, example: "<CPU>: <CPU Support
+addition>". Use the RST format convention already used in the Change Log.**
+
+New Features
+^^^^^^^^^^^^
+
+- Arm Architecture
+ - Example: "Add support for Branch Target Identification (BTI)"
+
+- Build System
+ - Example: "Add support for default stack-protector flag"
+
+- CPU Support
+ - Example: "cortex-a55: Workaround for erratum 1221012"
+
+- Drivers
+ - Example: "console: Allow the console to register multiple times"
+
+- Libraries
+ - Example: "Introduce BTI support in Library at ROM (romlib)"
+
+- New Platforms Support
+ - Example: "qemu/qemu_sbsa: New platform support added for QEMU SBSA platform"
+
+- Platforms
+ - Example: "arm/common: Introduce wrapper functions to setup secure watchdog"
+
+- PSCI
+ - Example: "Adding new optional PSCI hook ``pwr_domain_on_finish_late``"
+
+- Security
+ - Example: "UBSAN support and handlers"
+
+- Tools
+ - Example: "fiptool: Add support to build fiptool on Windows."
+
+
+Changed
+^^^^^^^
+
+- Arm Architecture
+ - Example: "Refactor ARMv8.3 Pointer Authentication support code"
+
+- BL-Specific
+ - Example: "BL2: Invalidate dcache build option for BL2 entry at EL3"
+
+- Boot Flow
+ - Example: "Add helper to parse BL31 parameters (both versions)"
+
+- Drivers
+ - Example: "gicv3: Prevent pending G1S interrupt from becoming G0 interrupt"
+
+- Platforms
+ - Example: "arm/common: Shorten the Firmware Update (FWU) process"
+
+- PSCI
+ - Example: "PSCI: Lookup list of parent nodes to lock only once"
+
+- Secure Partition Manager (SPM)
+ - Example: "Move shim layer to TTBR1_EL1"
+
+- Security
+ - Example: "Refactor SPSR initialisation code"
+
+- Tools
+ - Example: "cert_create: Remove RSA PKCS#1 v1.5 support"
+
+
+Resolved Issues
+^^^^^^^^^^^^^^^
+
+- Arm Architecture
+ - Example: "Fix restoration of PAuth context"
+
+- BL-Specific
+ - Example: "Fix BL31 crash reporting on AArch64 only platforms"
+
+- Build System
+ - Example: "Remove several warnings reported with W=2 and W=1"
+
+- Code Quality
+ - Example: "Unify type of "cpu_idx" across PSCI module"
+
+- CPU Support
+ - Example: "cortex-a12: Fix MIDR mask"
+
+- Drivers
+ - Example: "scmi: Fix wrong payload length"
+
+- Library Code
+ - Example: "libc: Fix memchr implementation"
+
+- Platforms
+ - Example: "rpi: rpi3: Fix compilation error when stack protector is enabled"
+
+- Security
+ - Example: "AArch32: Disable Secure Cycle Counter"
+
+Deprecations
+^^^^^^^^^^^^
+
+- Common Code
+ - Example: "Remove MULTI_CONSOLE_API flag and references to it"
+
+- Drivers
+ - Example: "console: Remove deprecated finish_console_register"
+
+- Secure Partition Manager (SPM):
+ - Example: "Prototype SPCI-based SPM (services/std_svc/spm) will be replaced
+ with alternative methods of secure partitioning support."
+
+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.
+
+- 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
diff --git a/docs/components/secure-partition-manager-design.rst b/docs/components/secure-partition-manager-design.rst
index 9aba954505..52b1c03e8f 100644
--- a/docs/components/secure-partition-manager-design.rst
+++ b/docs/components/secure-partition-manager-design.rst
@@ -119,7 +119,7 @@ Interface). This will be referred to as the *Standalone MM Secure Partition* in
the rest of this document.
To enable SPM support in TF-A, the source code must be compiled with the build
-flag ``ENABLE_SPM=1``, along with ``EL3_EXCEPTION_HANDLING=1``. On Arm
+flag ``SPM_MM=1``, along with ``EL3_EXCEPTION_HANDLING=1``. On Arm
platforms the build option ``ARM_BL31_IN_DRAM`` must be set to 1. Also, the
location of the binary that contains the BL32 image
(``BL32=path/to/image.bin``) must be specified.
@@ -133,7 +133,7 @@ image in the FIP:
.. code:: shell
BL32=path/to/standalone/mm/sp BL33=path/to/bl33.bin \
- make PLAT=fvp ENABLE_SPM=1 ARM_BL31_IN_DRAM=1 fip all
+ make PLAT=fvp SPM_MM=1 EL3_EXCEPTION_HANDLING=1 ARM_BL31_IN_DRAM=1 all fip
Describing Secure Partition resources
-------------------------------------
diff --git a/docs/getting_started/initial-build.rst b/docs/getting_started/initial-build.rst
index 893aba2457..d4a8f0114e 100644
--- a/docs/getting_started/initial-build.rst
+++ b/docs/getting_started/initial-build.rst
@@ -18,9 +18,10 @@ Performing an Initial Build
It is possible to build TF-A using Clang or Arm Compiler 6. To do so
``CC`` needs to point to the clang or armclang binary, which will
- also select the clang or armclang assembler. Be aware that the
- GNU linker is used by default. In case of being needed the linker
- can be overridden using the ``LD`` variable. Clang linker version 6 is
+ also select the clang or armclang assembler. Be aware that for Arm Compiler,
+ the GNU linker is used by default. However for Clang LLVM linker (LLD)
+ is used by default. In case of being needed the linker can be overridden
+ using the ``LD`` variable. LLVM linker (LLD) version 9 is
known to work with TF-A.
In both cases ``CROSS_COMPILE`` should be set as described above.
@@ -114,4 +115,4 @@ Performing an Initial Build
--------------
-*Copyright (c) 2019, Arm Limited. All rights reserved.*
+*Copyright (c) 2020, Arm Limited. All rights reserved.*
diff --git a/docs/index.rst b/docs/index.rst
index baadd42cf2..5088bfd878 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -15,6 +15,7 @@ Trusted Firmware-A Documentation
perf/index
security_advisories/index
change-log
+ change-log-upcoming
glossary
license
diff --git a/docs/plat/stm32mp1.rst b/docs/plat/stm32mp1.rst
index 88251d6afb..2c372a6a38 100644
--- a/docs/plat/stm32mp1.rst
+++ b/docs/plat/stm32mp1.rst
@@ -76,21 +76,34 @@ ROM code -> BL2 (compiled with BL2_AT_EL3) -> OP-TEE -> BL33 (U-Boot)
Build Instructions
------------------
+Boot media(s) supported by BL2 must be specified in the build command.
+Available storage medias are:
+- ``STM32MP_SDMMC``
+- ``STM32MP_EMMC``
+- ``STM32MP_RAW_NAND``
+- ``STM32MP_SPI_NAND``
+- ``STM32MP_SPI_NOR``
-To build with SP_min:
+To build with SP_min and support for all bootable devices:
.. code:: bash
- make CROSS_COMPILE=arm-linux-gnueabihf- PLAT=stm32mp1 ARCH=aarch32 ARM_ARCH_MAJOR=7 AARCH32_SP=sp_min DTB_FILE_NAME=stm32mp157c-ev1.dtb
+ make CROSS_COMPILE=arm-linux-gnueabihf- PLAT=stm32mp1 ARCH=aarch32 ARM_ARCH_MAJOR=7 AARCH32_SP=sp_min STM32MP_SDMMC=1 STM32MP_EMMC=1 STM32MP_RAW_NAND=1 STM32MP_SPI_NAND=1
+ STM32MP_SPI_NOR=1 DTB_FILE_NAME=stm32mp157c-ev1.dtb
cd <u-boot_directory>
make stm32mp15_trusted_defconfig
make DEVICE_TREE=stm32mp157c-ev1 all
-To build TF-A with with Op-TEE support:
-
+To build TF-A with OP-TEE support for all bootable devices:
.. code:: bash
- make CROSS_COMPILE=arm-linux-gnueabihf- PLAT=stm32mp1 ARCH=aarch32 ARM_ARCH_MAJOR=7 AARCH32_SP=optee
+ make CROSS_COMPILE=arm-linux-gnueabihf- PLAT=stm32mp1 ARCH=aarch32 ARM_ARCH_MAJOR=7 AARCH32_SP=optee STM32MP_SDMMC=1 STM32MP_EMMC=1 STM32MP_RAW_NAND=1 STM32MP_SPI_NAND=1 STM32MP_SPI_NOR=1 DTB_FILE_NAME=stm32mp157c-ev1.dtb
+ cd <optee_directory>
+ make CROSS_COMPILE=arm-linux-gnueabihf- ARCH=arm PLATFORM=stm32mp1 CFG_EMBED_DTB_SOURCE_FILE=stm32mp157c-ev1.dts
+ cd <u-boot_directory>
+ make stm32mp15_optee_defconfig
+ make DEVICE_TREE=stm32mp157c-ev1 all
+
The following build options are supported:
diff --git a/docs/plat/xilinx-versal.rst b/docs/plat/xilinx-versal.rst
index 231286e7e7..57a363bc95 100644
--- a/docs/plat/xilinx-versal.rst
+++ b/docs/plat/xilinx-versal.rst
@@ -14,7 +14,7 @@ To build:
make RESET_TO_BL31=1 CROSS_COMPILE=aarch64-none-elf- PLAT=versal bl31
```
-To build ATF for different platform (for now its just versal virtual "versal_virt")
+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
```
@@ -33,3 +33,11 @@ Xilinx Versal platform specific build options
* `VERSAL_PLATFORM`: Select the platform. Options:
- `versal_virt` : Versal Virtual platform
+
+# 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/drivers/intel/soc/stratix10/io/s10_memmap_qspi.c b/drivers/intel/soc/stratix10/io/s10_memmap_qspi.c
index a0fc034d88..dcd1991484 100644
--- a/drivers/intel/soc/stratix10/io/s10_memmap_qspi.c
+++ b/drivers/intel/soc/stratix10/io/s10_memmap_qspi.c
@@ -26,9 +26,9 @@ typedef struct {
* valid.
*/
int in_use;
- uintptr_t base;
- size_t file_pos;
- size_t size;
+ uintptr_t base;
+ unsigned long long file_pos;
+ unsigned long long size;
} file_state_t;
static file_state_t current_file = {0};
@@ -44,7 +44,7 @@ static int memmap_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
io_entity_t *entity);
static int memmap_block_seek(io_entity_t *entity, int mode,
- ssize_t offset);
+ signed long long offset);
static int memmap_block_len(io_entity_t *entity, size_t *length);
static int memmap_block_read(io_entity_t *entity, uintptr_t buffer,
size_t length, size_t *length_read);
@@ -131,7 +131,8 @@ static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
/* Seek to a particular file offset on the memmap device */
-static int memmap_block_seek(io_entity_t *entity, int mode, ssize_t offset)
+static int memmap_block_seek(io_entity_t *entity, int mode,
+ signed long long offset)
{
int result = -ENOENT;
file_state_t *fp;
@@ -143,7 +144,8 @@ static int memmap_block_seek(io_entity_t *entity, int mode, ssize_t offset)
fp = (file_state_t *) entity->info;
/* Assert that new file position is valid */
- assert((offset >= 0) && (offset < fp->size));
+ assert((offset >= 0) &&
+ ((unsigned long long)offset < fp->size));
/* Reset file position */
fp->file_pos = offset;
@@ -171,7 +173,7 @@ static int memmap_block_read(io_entity_t *entity, uintptr_t buffer,
size_t length, size_t *length_read)
{
file_state_t *fp;
- size_t pos_after;
+ unsigned long long pos_after;
assert(entity != NULL);
assert(length_read != NULL);
@@ -198,7 +200,7 @@ static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer,
size_t length, size_t *length_written)
{
file_state_t *fp;
- size_t pos_after;
+ unsigned long long pos_after;
assert(entity != NULL);
assert(length_written != NULL);
diff --git a/drivers/io/io_block.c b/drivers/io/io_block.c
index f190a4307b..5d45c2f176 100644
--- a/drivers/io/io_block.c
+++ b/drivers/io/io_block.c
@@ -19,17 +19,17 @@
typedef struct {
io_block_dev_spec_t *dev_spec;
uintptr_t base;
- size_t file_pos;
- size_t size;
+ unsigned long long file_pos;
+ unsigned long long size;
} block_dev_state_t;
-#define is_power_of_2(x) ((x != 0) && ((x & (x - 1)) == 0))
+#define is_power_of_2(x) (((x) != 0U) && (((x) & ((x) - 1U)) == 0U))
io_type_t device_type_block(void);
static int block_open(io_dev_info_t *dev_info, const uintptr_t spec,
io_entity_t *entity);
-static int block_seek(io_entity_t *entity, int mode, ssize_t offset);
+static int block_seek(io_entity_t *entity, int mode, signed long long offset);
static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length,
size_t *length_read);
static int block_write(io_entity_t *entity, const uintptr_t buffer,
@@ -148,21 +148,21 @@ static int block_open(io_dev_info_t *dev_info, const uintptr_t spec,
}
/* parameter offset is relative address at here */
-static int block_seek(io_entity_t *entity, int mode, ssize_t offset)
+static int block_seek(io_entity_t *entity, int mode, signed long long offset)
{
block_dev_state_t *cur;
assert(entity->info != (uintptr_t)NULL);
cur = (block_dev_state_t *)entity->info;
- assert((offset >= 0) && (offset < cur->size));
+ assert((offset >= 0) && ((unsigned long long)offset < cur->size));
switch (mode) {
case IO_SEEK_SET:
- cur->file_pos = offset;
+ cur->file_pos = (unsigned long long)offset;
break;
case IO_SEEK_CUR:
- cur->file_pos += offset;
+ cur->file_pos += (unsigned long long)offset;
break;
default:
return -EINVAL;
@@ -270,7 +270,7 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length,
buf = &(cur->dev_spec->buffer);
block_size = cur->dev_spec->block_size;
assert((length <= cur->size) &&
- (length > 0) &&
+ (length > 0U) &&
(ops->read != 0));
/*
@@ -279,7 +279,7 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length,
* on the low level driver.
*/
count = 0;
- for (left = length; left > 0; left -= nbytes) {
+ for (left = length; left > 0U; left -= nbytes) {
/*
* We must only request operations aligned to the block
* size. Therefore if file_pos is not block-aligned,
@@ -288,7 +288,7 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length,
* similarly, the number of bytes requested must be a
* block size multiple
*/
- skip = cur->file_pos & (block_size - 1);
+ skip = cur->file_pos & (block_size - 1U);
/*
* Calculate the block number containing file_pos
@@ -296,7 +296,7 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length,
*/
lba = (cur->file_pos + cur->base) / block_size;
- if (skip + left > buf->length) {
+ if ((skip + left) > buf->length) {
/*
* The underlying read buffer is too small to
* read all the required data - limit to just
@@ -311,7 +311,8 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length,
* block size.
*/
request = skip + left;
- request = (request + (block_size - 1)) & ~(block_size - 1);
+ request = (request + (block_size - 1U)) &
+ ~(block_size - 1U);
}
request = ops->read(lba, buf->offset, request);
@@ -330,7 +331,7 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length,
* the read data when copying to the user buffer.
*/
nbytes = request - skip;
- padding = (nbytes > left) ? nbytes - left : 0;
+ padding = (nbytes > left) ? nbytes - left : 0U;
nbytes -= padding;
memcpy((void *)(buffer + count),
@@ -381,7 +382,7 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer,
buf = &(cur->dev_spec->buffer);
block_size = cur->dev_spec->block_size;
assert((length <= cur->size) &&
- (length > 0) &&
+ (length > 0U) &&
(ops->read != 0) &&
(ops->write != 0));
@@ -391,7 +392,7 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer,
* on the low level driver.
*/
count = 0;
- for (left = length; left > 0; left -= nbytes) {
+ for (left = length; left > 0U; left -= nbytes) {
/*
* We must only request operations aligned to the block
* size. Therefore if file_pos is not block-aligned,
@@ -400,7 +401,7 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer,
* similarly, the number of bytes requested must be a
* block size multiple
*/
- skip = cur->file_pos & (block_size - 1);
+ skip = cur->file_pos & (block_size - 1U);
/*
* Calculate the block number containing file_pos
@@ -408,7 +409,7 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer,
*/
lba = (cur->file_pos + cur->base) / block_size;
- if (skip + left > buf->length) {
+ if ((skip + left) > buf->length) {
/*
* The underlying read buffer is too small to
* read all the required data - limit to just
@@ -423,7 +424,8 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer,
* block size.
*/
request = skip + left;
- request = (request + (block_size - 1)) & ~(block_size - 1);
+ request = (request + (block_size - 1U)) &
+ ~(block_size - 1U);
}
/*
@@ -432,7 +434,7 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer,
* of the current request.
*/
nbytes = request - skip;
- padding = (nbytes > left) ? nbytes - left : 0;
+ padding = (nbytes > left) ? nbytes - left : 0U;
nbytes -= padding;
/*
@@ -440,14 +442,14 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer,
* some content and it means that we have to read before
* writing
*/
- if (skip > 0 || padding > 0) {
+ if ((skip > 0U) || (padding > 0U)) {
request = ops->read(lba, buf->offset, request);
/*
* The read may return size less than
* requested. Round down to the nearest block
* boundary
*/
- request &= ~(block_size-1);
+ request &= ~(block_size - 1U);
if (request <= skip) {
/*
* We couldn't read enough bytes to jump over
@@ -458,7 +460,7 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer,
return -EIO;
}
nbytes = request - skip;
- padding = (nbytes > left) ? nbytes - left : 0;
+ padding = (nbytes > left) ? nbytes - left : 0U;
nbytes -= padding;
}
@@ -477,7 +479,7 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer,
* buffer
*/
nbytes = request - skip;
- padding = (nbytes > left) ? nbytes - left : 0;
+ padding = (nbytes > left) ? nbytes - left : 0U;
nbytes -= padding;
cur->file_pos += nbytes;
@@ -505,7 +507,7 @@ static int block_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info)
assert(dev_info != NULL);
result = allocate_dev_info(&info);
- if (result)
+ if (result != 0)
return -ENOENT;
cur = (block_dev_state_t *)info->info;
@@ -513,10 +515,10 @@ static int block_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info)
cur->dev_spec = (io_block_dev_spec_t *)dev_spec;
buffer = &(cur->dev_spec->buffer);
block_size = cur->dev_spec->block_size;
- assert((block_size > 0) &&
- (is_power_of_2(block_size) != 0) &&
- ((buffer->offset % block_size) == 0) &&
- ((buffer->length % block_size) == 0));
+ assert((block_size > 0U) &&
+ (is_power_of_2(block_size) != 0U) &&
+ ((buffer->offset % block_size) == 0U) &&
+ ((buffer->length % block_size) == 0U));
*dev_info = info; /* cast away const */
(void)block_size;
diff --git a/drivers/io/io_fip.c b/drivers/io/io_fip.c
index 544b37dbea..5d49fffaa3 100644
--- a/drivers/io/io_fip.c
+++ b/drivers/io/io_fip.c
@@ -304,7 +304,8 @@ static int fip_file_open(io_dev_info_t *dev_info, const uintptr_t spec,
}
/* Seek past the FIP header into the Table of Contents */
- result = io_seek(backend_handle, IO_SEEK_SET, sizeof(fip_toc_header_t));
+ result = io_seek(backend_handle, IO_SEEK_SET,
+ (signed long long)sizeof(fip_toc_header_t));
if (result != 0) {
WARN("fip_file_open: failed to seek\n");
result = -ENOENT;
@@ -389,7 +390,8 @@ static int fip_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
/* Seek to the position in the FIP where the payload lives */
file_offset = fp->entry.offset_address + fp->file_pos;
- result = io_seek(backend_handle, IO_SEEK_SET, file_offset);
+ result = io_seek(backend_handle, IO_SEEK_SET,
+ (signed long long)file_offset);
if (result != 0) {
WARN("fip_file_read: failed to seek\n");
result = -ENOENT;
diff --git a/drivers/io/io_memmap.c b/drivers/io/io_memmap.c
index 96590b6c03..eed50cc086 100644
--- a/drivers/io/io_memmap.c
+++ b/drivers/io/io_memmap.c
@@ -23,10 +23,10 @@ typedef struct {
/* Use the 'in_use' flag as any value for base and file_pos could be
* valid.
*/
- int in_use;
- uintptr_t base;
- size_t file_pos;
- size_t size;
+ int in_use;
+ uintptr_t base;
+ unsigned long long file_pos;
+ unsigned long long size;
} file_state_t;
static file_state_t current_file = {0};
@@ -42,7 +42,7 @@ static int memmap_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
io_entity_t *entity);
static int memmap_block_seek(io_entity_t *entity, int mode,
- ssize_t offset);
+ signed long long offset);
static int memmap_block_len(io_entity_t *entity, size_t *length);
static int memmap_block_read(io_entity_t *entity, uintptr_t buffer,
size_t length, size_t *length_read);
@@ -129,7 +129,8 @@ static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
/* Seek to a particular file offset on the memmap device */
-static int memmap_block_seek(io_entity_t *entity, int mode, ssize_t offset)
+static int memmap_block_seek(io_entity_t *entity, int mode,
+ signed long long offset)
{
int result = -ENOENT;
file_state_t *fp;
@@ -141,10 +142,11 @@ static int memmap_block_seek(io_entity_t *entity, int mode, ssize_t offset)
fp = (file_state_t *) entity->info;
/* Assert that new file position is valid */
- assert((offset >= 0) && (offset < fp->size));
+ assert((offset >= 0) &&
+ ((unsigned long long)offset < fp->size));
/* Reset file position */
- fp->file_pos = offset;
+ fp->file_pos = (unsigned long long)offset;
result = 0;
}
@@ -158,7 +160,7 @@ static int memmap_block_len(io_entity_t *entity, size_t *length)
assert(entity != NULL);
assert(length != NULL);
- *length = ((file_state_t *)entity->info)->size;
+ *length = (size_t)((file_state_t *)entity->info)->size;
return 0;
}
@@ -169,7 +171,7 @@ static int memmap_block_read(io_entity_t *entity, uintptr_t buffer,
size_t length, size_t *length_read)
{
file_state_t *fp;
- size_t pos_after;
+ unsigned long long pos_after;
assert(entity != NULL);
assert(length_read != NULL);
@@ -180,7 +182,8 @@ static int memmap_block_read(io_entity_t *entity, uintptr_t buffer,
pos_after = fp->file_pos + length;
assert((pos_after >= fp->file_pos) && (pos_after <= fp->size));
- memcpy((void *)buffer, (void *)(fp->base + fp->file_pos), length);
+ memcpy((void *)buffer,
+ (void *)((uintptr_t)(fp->base + fp->file_pos)), length);
*length_read = length;
@@ -196,7 +199,7 @@ static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer,
size_t length, size_t *length_written)
{
file_state_t *fp;
- size_t pos_after;
+ unsigned long long pos_after;
assert(entity != NULL);
assert(length_written != NULL);
@@ -207,7 +210,8 @@ static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer,
pos_after = fp->file_pos + length;
assert((pos_after >= fp->file_pos) && (pos_after <= fp->size));
- memcpy((void *)(fp->base + fp->file_pos), (void *)buffer, length);
+ memcpy((void *)((uintptr_t)(fp->base + fp->file_pos)),
+ (void *)buffer, length);
*length_written = length;
diff --git a/drivers/io/io_mtd.c b/drivers/io/io_mtd.c
new file mode 100644
index 0000000000..7575fa2503
--- /dev/null
+++ b/drivers/io/io_mtd.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_mtd.h>
+#include <lib/utils.h>
+
+typedef struct {
+ io_mtd_dev_spec_t *dev_spec;
+ uintptr_t base;
+ unsigned long long offset; /* Offset in bytes */
+ unsigned long long size; /* Size of device in bytes */
+} mtd_dev_state_t;
+
+io_type_t device_type_mtd(void);
+
+static int mtd_open(io_dev_info_t *dev_info, const uintptr_t spec,
+ io_entity_t *entity);
+static int mtd_seek(io_entity_t *entity, int mode, signed long long offset);
+static int mtd_read(io_entity_t *entity, uintptr_t buffer, size_t length,
+ size_t *length_read);
+static int mtd_close(io_entity_t *entity);
+static int mtd_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
+static int mtd_dev_close(io_dev_info_t *dev_info);
+
+static const io_dev_connector_t mtd_dev_connector = {
+ .dev_open = mtd_dev_open
+};
+
+static const io_dev_funcs_t mtd_dev_funcs = {
+ .type = device_type_mtd,
+ .open = mtd_open,
+ .seek = mtd_seek,
+ .read = mtd_read,
+ .close = mtd_close,
+ .dev_close = mtd_dev_close,
+};
+
+static mtd_dev_state_t state_pool[MAX_IO_MTD_DEVICES];
+static io_dev_info_t dev_info_pool[MAX_IO_MTD_DEVICES];
+
+io_type_t device_type_mtd(void)
+{
+ return IO_TYPE_MTD;
+}
+
+/* Locate a MTD state in the pool, specified by address */
+static int find_first_mtd_state(const io_mtd_dev_spec_t *dev_spec,
+ unsigned int *index_out)
+{
+ unsigned int index;
+ int result = -ENOENT;
+
+ for (index = 0U; index < MAX_IO_MTD_DEVICES; index++) {
+ /* dev_spec is used as identifier since it's unique */
+ if (state_pool[index].dev_spec == dev_spec) {
+ result = 0;
+ *index_out = index;
+ break;
+ }
+ }
+
+ return result;
+}
+
+/* Allocate a device info from the pool */
+static int allocate_dev_info(io_dev_info_t **dev_info)
+{
+ unsigned int index = 0U;
+ int result;
+
+ result = find_first_mtd_state(NULL, &index);
+ if (result != 0) {
+ return -ENOMEM;
+ }
+
+ dev_info_pool[index].funcs = &mtd_dev_funcs;
+ dev_info_pool[index].info = (uintptr_t)&state_pool[index];
+ *dev_info = &dev_info_pool[index];
+
+ return 0;
+}
+
+/* Release a device info from the pool */
+static int free_dev_info(io_dev_info_t *dev_info)
+{
+ int result;
+ unsigned int index = 0U;
+ mtd_dev_state_t *state;
+
+ state = (mtd_dev_state_t *)dev_info->info;
+ result = find_first_mtd_state(state->dev_spec, &index);
+ if (result != 0) {
+ return result;
+ }
+
+ zeromem(state, sizeof(mtd_dev_state_t));
+ zeromem(dev_info, sizeof(io_dev_info_t));
+
+ return 0;
+}
+
+static int mtd_open(io_dev_info_t *dev_info, const uintptr_t spec,
+ io_entity_t *entity)
+{
+ mtd_dev_state_t *cur;
+
+ assert((dev_info->info != 0UL) && (entity->info == 0UL));
+
+ cur = (mtd_dev_state_t *)dev_info->info;
+ entity->info = (uintptr_t)cur;
+ cur->offset = 0U;
+
+ return 0;
+}
+
+/* Seek to a specific position using offset */
+static int mtd_seek(io_entity_t *entity, int mode, signed long long offset)
+{
+ mtd_dev_state_t *cur;
+
+ assert((entity->info != (uintptr_t)NULL) && (offset >= 0));
+
+ cur = (mtd_dev_state_t *)entity->info;
+
+ switch (mode) {
+ case IO_SEEK_SET:
+ if ((offset >= 0) &&
+ ((unsigned long long)offset >= cur->size)) {
+ return -EINVAL;
+ }
+
+ cur->offset = offset;
+ break;
+ case IO_SEEK_CUR:
+ if (((cur->offset + (unsigned long long)offset) >=
+ cur->size) ||
+ ((cur->offset + (unsigned long long)offset) <
+ cur->offset)) {
+ return -EINVAL;
+ }
+
+ cur->offset += (unsigned long long)offset;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mtd_read(io_entity_t *entity, uintptr_t buffer, size_t length,
+ size_t *out_length)
+{
+ mtd_dev_state_t *cur;
+ io_mtd_ops_t *ops;
+ int ret;
+
+ assert(entity->info != (uintptr_t)NULL);
+ assert((length > 0U) && (buffer != (uintptr_t)NULL));
+
+ cur = (mtd_dev_state_t *)entity->info;
+ ops = &cur->dev_spec->ops;
+ assert(ops->read != NULL);
+
+ VERBOSE("Read at %llx into %lx, length %zi\n",
+ cur->offset, buffer, length);
+ if ((cur->offset + length) > cur->dev_spec->device_size) {
+ return -EINVAL;
+ }
+
+ ret = ops->read(cur->offset, buffer, length, out_length);
+ if (ret < 0) {
+ return ret;
+ }
+
+ assert(*out_length == length);
+ cur->offset += *out_length;
+
+ return 0;
+}
+
+static int mtd_close(io_entity_t *entity)
+{
+ entity->info = (uintptr_t)NULL;
+
+ return 0;
+}
+
+static int mtd_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info)
+{
+ mtd_dev_state_t *cur;
+ io_dev_info_t *info;
+ io_mtd_ops_t *ops;
+ int result;
+
+ result = allocate_dev_info(&info);
+ if (result != 0) {
+ return -ENOENT;
+ }
+
+ cur = (mtd_dev_state_t *)info->info;
+ cur->dev_spec = (io_mtd_dev_spec_t *)dev_spec;
+ *dev_info = info;
+ ops = &(cur->dev_spec->ops);
+ if (ops->init != NULL) {
+ result = ops->init(&cur->dev_spec->device_size,
+ &cur->dev_spec->erase_size);
+ }
+
+ if (result == 0) {
+ cur->size = cur->dev_spec->device_size;
+ } else {
+ cur->size = 0ULL;
+ }
+
+ return result;
+}
+
+static int mtd_dev_close(io_dev_info_t *dev_info)
+{
+ return free_dev_info(dev_info);
+}
+
+/* Exported functions */
+
+/* Register the MTD driver in the IO abstraction */
+int register_io_dev_mtd(const io_dev_connector_t **dev_con)
+{
+ int result;
+
+ result = io_register_device(&dev_info_pool[0]);
+ if (result == 0) {
+ *dev_con = &mtd_dev_connector;
+ }
+
+ return result;
+}
diff --git a/drivers/io/io_semihosting.c b/drivers/io/io_semihosting.c
index 23d09c1188..4ceddc6cc0 100644
--- a/drivers/io/io_semihosting.c
+++ b/drivers/io/io_semihosting.c
@@ -25,7 +25,7 @@ static io_type_t device_type_sh(void)
static int sh_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
static int sh_file_open(io_dev_info_t *dev_info, const uintptr_t spec,
io_entity_t *entity);
-static int sh_file_seek(io_entity_t *entity, int mode, ssize_t offset);
+static int sh_file_seek(io_entity_t *entity, int mode, signed long long offset);
static int sh_file_len(io_entity_t *entity, size_t *length);
static int sh_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
size_t *length_read);
@@ -90,7 +90,7 @@ static int sh_file_open(io_dev_info_t *dev_info __unused,
/* Seek to a particular file offset on the semi-hosting device */
-static int sh_file_seek(io_entity_t *entity, int mode, ssize_t offset)
+static int sh_file_seek(io_entity_t *entity, int mode, signed long long offset)
{
long file_handle, sh_result;
@@ -98,7 +98,7 @@ static int sh_file_seek(io_entity_t *entity, int mode, ssize_t offset)
file_handle = (long)entity->info;
- sh_result = semihosting_file_seek(file_handle, offset);
+ sh_result = semihosting_file_seek(file_handle, (ssize_t)offset);
return (sh_result == 0) ? 0 : -ENOENT;
}
diff --git a/drivers/io/io_storage.c b/drivers/io/io_storage.c
index e444f87f72..b8c1d6479f 100644
--- a/drivers/io/io_storage.c
+++ b/drivers/io/io_storage.c
@@ -237,7 +237,7 @@ int io_open(uintptr_t dev_handle, const uintptr_t spec, uintptr_t *handle)
/* Seek to a specific position in an IO entity */
-int io_seek(uintptr_t handle, io_seek_mode_t mode, ssize_t offset)
+int io_seek(uintptr_t handle, io_seek_mode_t mode, signed long long offset)
{
int result = -ENODEV;
assert(is_valid_entity(handle) && is_valid_seek_mode(mode));
diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c
new file mode 100644
index 0000000000..44b001e35b
--- /dev/null
+++ b/drivers/mtd/nand/core.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stddef.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/nand.h>
+#include <lib/utils.h>
+
+/*
+ * Define a single nand_device used by specific NAND frameworks.
+ */
+static struct nand_device nand_dev;
+static uint8_t scratch_buff[PLATFORM_MTD_MAX_PAGE_SIZE];
+
+int nand_read(unsigned int offset, uintptr_t buffer, size_t length,
+ size_t *length_read)
+{
+ unsigned int block = offset / nand_dev.block_size;
+ unsigned int end_block = (offset + length - 1U) / nand_dev.block_size;
+ unsigned int page_start =
+ (offset % nand_dev.block_size) / nand_dev.page_size;
+ unsigned int nb_pages = nand_dev.block_size / nand_dev.page_size;
+ unsigned int start_offset = offset % nand_dev.page_size;
+ unsigned int page;
+ unsigned int bytes_read;
+ int is_bad;
+ int ret;
+
+ VERBOSE("Block %u - %u, page_start %u, nb %u, length %zu, offset %u\n",
+ block, end_block, page_start, nb_pages, length, offset);
+
+ *length_read = 0UL;
+
+ if (((start_offset != 0U) || (length % nand_dev.page_size) != 0U) &&
+ (sizeof(scratch_buff) < nand_dev.page_size)) {
+ return -EINVAL;
+ }
+
+ while (block <= end_block) {
+ is_bad = nand_dev.mtd_block_is_bad(block);
+ if (is_bad < 0) {
+ return is_bad;
+ }
+
+ if (is_bad == 1) {
+ /* Skip the block */
+ uint32_t max_block =
+ nand_dev.size / nand_dev.block_size;
+
+ block++;
+ end_block++;
+ if ((block < max_block) && (end_block < max_block)) {
+ continue;
+ }
+
+ return -EIO;
+ }
+
+ for (page = page_start; page < nb_pages; page++) {
+ if ((start_offset != 0U) ||
+ (length < nand_dev.page_size)) {
+ ret = nand_dev.mtd_read_page(
+ &nand_dev,
+ (block * nb_pages) + page,
+ (uintptr_t)scratch_buff);
+ if (ret != 0) {
+ return ret;
+ }
+
+ bytes_read = MIN((size_t)(nand_dev.page_size -
+ start_offset),
+ length);
+
+ memcpy((uint8_t *)buffer,
+ scratch_buff + start_offset,
+ bytes_read);
+
+ start_offset = 0U;
+ } else {
+ ret = nand_dev.mtd_read_page(&nand_dev,
+ (block * nb_pages) + page,
+ buffer);
+ if (ret != 0) {
+ return ret;
+ }
+
+ bytes_read = nand_dev.page_size;
+ }
+
+ length -= bytes_read;
+ buffer += bytes_read;
+ *length_read += bytes_read;
+
+ if (length == 0U) {
+ break;
+ }
+ }
+
+ page_start = 0U;
+ block++;
+ }
+
+ return 0;
+}
+
+struct nand_device *get_nand_device(void)
+{
+ return &nand_dev;
+}
diff --git a/drivers/mtd/nand/raw_nand.c b/drivers/mtd/nand/raw_nand.c
new file mode 100644
index 0000000000..48131fcb25
--- /dev/null
+++ b/drivers/mtd/nand/raw_nand.c
@@ -0,0 +1,446 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stddef.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/raw_nand.h>
+#include <lib/utils.h>
+
+#define ONFI_SIGNATURE_ADDR 0x20U
+
+/* CRC calculation */
+#define CRC_POLYNOM 0x8005U
+#define CRC_INIT_VALUE 0x4F4EU
+
+/* Status register */
+#define NAND_STATUS_READY BIT(6)
+
+#define SZ_128M 0x08000000U
+#define SZ_512 0x200U
+
+static struct rawnand_device rawnand_dev;
+
+#pragma weak plat_get_raw_nand_data
+int plat_get_raw_nand_data(struct rawnand_device *device)
+{
+ return 0;
+}
+
+static int nand_send_cmd(uint8_t cmd, unsigned int tim)
+{
+ struct nand_req req;
+
+ zeromem(&req, sizeof(struct nand_req));
+ req.nand = rawnand_dev.nand_dev;
+ req.type = NAND_REQ_CMD | cmd;
+ req.inst_delay = tim;
+
+ return rawnand_dev.ops->exec(&req);
+}
+
+static int nand_send_addr(uint8_t addr, unsigned int tim)
+{
+ struct nand_req req;
+
+ zeromem(&req, sizeof(struct nand_req));
+ req.nand = rawnand_dev.nand_dev;
+ req.type = NAND_REQ_ADDR;
+ req.addr = &addr;
+ req.inst_delay = tim;
+
+ return rawnand_dev.ops->exec(&req);
+}
+
+static int nand_send_wait(unsigned int delay, unsigned int tim)
+{
+ struct nand_req req;
+
+ zeromem(&req, sizeof(struct nand_req));
+ req.nand = rawnand_dev.nand_dev;
+ req.type = NAND_REQ_WAIT;
+ req.inst_delay = tim;
+ req.delay_ms = delay;
+
+ return rawnand_dev.ops->exec(&req);
+}
+
+
+static int nand_read_data(uint8_t *data, unsigned int length, bool use_8bit)
+{
+ struct nand_req req;
+
+ zeromem(&req, sizeof(struct nand_req));
+ req.nand = rawnand_dev.nand_dev;
+ req.type = NAND_REQ_DATAIN | (use_8bit ? NAND_REQ_BUS_WIDTH_8 : 0U);
+ req.addr = data;
+ req.length = length;
+
+ return rawnand_dev.ops->exec(&req);
+}
+
+int nand_change_read_column_cmd(unsigned int offset, uintptr_t buffer,
+ unsigned int len)
+{
+ int ret;
+ uint8_t addr[2];
+ unsigned int i;
+
+ ret = nand_send_cmd(NAND_CMD_CHANGE_1ST, 0U);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (rawnand_dev.nand_dev->buswidth == NAND_BUS_WIDTH_16) {
+ offset /= 2U;
+ }
+
+ addr[0] = offset;
+ addr[1] = offset >> 8;
+
+ for (i = 0; i < 2U; i++) {
+ ret = nand_send_addr(addr[i], 0U);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ ret = nand_send_cmd(NAND_CMD_CHANGE_2ND, NAND_TCCS_MIN);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return nand_read_data((uint8_t *)buffer, len, false);
+}
+
+int nand_read_page_cmd(unsigned int page, unsigned int offset,
+ uintptr_t buffer, unsigned int len)
+{
+ uint8_t addr[5];
+ uint8_t i = 0U;
+ uint8_t j;
+ int ret;
+
+ VERBOSE(">%s page %u offset %u buffer 0x%lx\n", __func__, page, offset,
+ buffer);
+
+ if (rawnand_dev.nand_dev->buswidth == NAND_BUS_WIDTH_16) {
+ offset /= 2U;
+ }
+
+ addr[i++] = offset;
+ addr[i++] = offset >> 8;
+
+ addr[i++] = page;
+ addr[i++] = page >> 8;
+ if (rawnand_dev.nand_dev->size > SZ_128M) {
+ addr[i++] = page >> 16;
+ }
+
+ ret = nand_send_cmd(NAND_CMD_READ_1ST, 0U);
+ if (ret != 0) {
+ return ret;
+ }
+
+ for (j = 0U; j < i; j++) {
+ ret = nand_send_addr(addr[j], 0U);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ ret = nand_send_cmd(NAND_CMD_READ_2ND, NAND_TWB_MAX);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = nand_send_wait(PSEC_TO_MSEC(NAND_TR_MAX), NAND_TRR_MIN);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (buffer != 0U) {
+ ret = nand_read_data((uint8_t *)buffer, len, false);
+ }
+
+ return ret;
+}
+
+static int nand_status(uint8_t *status)
+{
+ int ret;
+
+ ret = nand_send_cmd(NAND_CMD_STATUS, NAND_TWHR_MIN);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (status != NULL) {
+ ret = nand_read_data(status, 1U, true);
+ }
+
+ return ret;
+}
+
+int nand_wait_ready(unsigned long delay)
+{
+ uint8_t status;
+ int ret;
+ uint64_t timeout;
+
+ /* Wait before reading status */
+ udelay(1);
+
+ ret = nand_status(NULL);
+ if (ret != 0) {
+ return ret;
+ }
+
+ timeout = timeout_init_us(delay);
+ while (!timeout_elapsed(timeout)) {
+ ret = nand_read_data(&status, 1U, true);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if ((status & NAND_STATUS_READY) != 0U) {
+ return nand_send_cmd(NAND_CMD_READ_1ST, 0U);
+ }
+
+ udelay(10);
+ }
+
+ return -ETIMEDOUT;
+}
+
+#if NAND_ONFI_DETECT
+static uint16_t nand_check_crc(uint16_t crc, uint8_t *data_in,
+ unsigned int data_len)
+{
+ uint32_t i;
+ uint32_t j;
+ uint32_t bit;
+
+ for (i = 0U; i < data_len; i++) {
+ uint8_t cur_param = *data_in++;
+
+ for (j = BIT(7); j != 0U; j >>= 1) {
+ bit = crc & BIT(15);
+ crc <<= 1;
+
+ if ((cur_param & j) != 0U) {
+ bit ^= BIT(15);
+ }
+
+ if (bit != 0U) {
+ crc ^= CRC_POLYNOM;
+ }
+ }
+
+ crc &= GENMASK(15, 0);
+ }
+
+ return crc;
+}
+
+static int nand_read_id(uint8_t addr, uint8_t *id, unsigned int size)
+{
+ int ret;
+
+ ret = nand_send_cmd(NAND_CMD_READID, 0U);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = nand_send_addr(addr, NAND_TWHR_MIN);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return nand_read_data(id, size, true);
+}
+
+static int nand_reset(void)
+{
+ int ret;
+
+ ret = nand_send_cmd(NAND_CMD_RESET, NAND_TWB_MAX);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return nand_send_wait(PSEC_TO_MSEC(NAND_TRST_MAX), 0U);
+}
+
+static int nand_read_param_page(void)
+{
+ struct nand_param_page page;
+ uint8_t addr = 0U;
+ int ret;
+
+ ret = nand_send_cmd(NAND_CMD_READ_PARAM_PAGE, 0U);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = nand_send_addr(addr, NAND_TWB_MAX);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = nand_send_wait(PSEC_TO_MSEC(NAND_TR_MAX), NAND_TRR_MIN);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = nand_read_data((uint8_t *)&page, sizeof(page), true);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (strncmp((char *)&page.page_sig, "ONFI", 4) != 0) {
+ WARN("Error ONFI detection\n");
+ return -EINVAL;
+ }
+
+ if (nand_check_crc(CRC_INIT_VALUE, (uint8_t *)&page, 254U) !=
+ page.crc16) {
+ WARN("Error reading param\n");
+ return -EINVAL;
+ }
+
+ if ((page.features & ONFI_FEAT_BUS_WIDTH_16) != 0U) {
+ rawnand_dev.nand_dev->buswidth = NAND_BUS_WIDTH_16;
+ } else {
+ rawnand_dev.nand_dev->buswidth = NAND_BUS_WIDTH_8;
+ }
+
+ rawnand_dev.nand_dev->block_size = page.num_pages_per_blk *
+ page.bytes_per_page;
+ rawnand_dev.nand_dev->page_size = page.bytes_per_page;
+ rawnand_dev.nand_dev->size = page.num_pages_per_blk *
+ page.bytes_per_page *
+ page.num_blk_in_lun * page.num_lun;
+
+ if (page.nb_ecc_bits != GENMASK_32(7, 0)) {
+ rawnand_dev.nand_dev->ecc.max_bit_corr = page.nb_ecc_bits;
+ rawnand_dev.nand_dev->ecc.size = SZ_512;
+ }
+
+ VERBOSE("Page size %u, block_size %u, Size %llu, ecc %u, buswidth %u\n",
+ rawnand_dev.nand_dev->page_size,
+ rawnand_dev.nand_dev->block_size, rawnand_dev.nand_dev->size,
+ rawnand_dev.nand_dev->ecc.max_bit_corr,
+ rawnand_dev.nand_dev->buswidth);
+
+ return 0;
+}
+
+static int detect_onfi(void)
+{
+ int ret;
+ char id[4];
+
+ ret = nand_reset();
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = nand_read_id(ONFI_SIGNATURE_ADDR, (uint8_t *)id, sizeof(id));
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (strncmp(id, "ONFI", sizeof(id)) != 0) {
+ WARN("NAND Non ONFI detected\n");
+ return -ENODEV;
+ }
+
+ return nand_read_param_page();
+}
+#endif
+
+static int nand_mtd_block_is_bad(unsigned int block)
+{
+ unsigned int nbpages_per_block = rawnand_dev.nand_dev->block_size /
+ rawnand_dev.nand_dev->page_size;
+ uint8_t bbm_marker[2];
+ uint8_t page;
+ int ret;
+
+ for (page = 0U; page < 2U; page++) {
+ ret = nand_read_page_cmd(block * nbpages_per_block,
+ rawnand_dev.nand_dev->page_size,
+ (uintptr_t)bbm_marker,
+ sizeof(bbm_marker));
+ if (ret != 0) {
+ return ret;
+ }
+
+ if ((bbm_marker[0] != GENMASK_32(7, 0)) ||
+ (bbm_marker[1] != GENMASK_32(7, 0))) {
+ WARN("Block %u is bad\n", block);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int nand_mtd_read_page_raw(struct nand_device *nand, unsigned int page,
+ uintptr_t buffer)
+{
+ return nand_read_page_cmd(page, 0U, buffer,
+ rawnand_dev.nand_dev->page_size);
+}
+
+void nand_raw_ctrl_init(const struct nand_ctrl_ops *ops)
+{
+ rawnand_dev.ops = ops;
+}
+
+int nand_raw_init(unsigned long long *size, unsigned int *erase_size)
+{
+ rawnand_dev.nand_dev = get_nand_device();
+ if (rawnand_dev.nand_dev == NULL) {
+ return -EINVAL;
+ }
+
+ rawnand_dev.nand_dev->mtd_block_is_bad = nand_mtd_block_is_bad;
+ rawnand_dev.nand_dev->mtd_read_page = nand_mtd_read_page_raw;
+ rawnand_dev.nand_dev->ecc.mode = NAND_ECC_NONE;
+
+ if ((rawnand_dev.ops->setup == NULL) ||
+ (rawnand_dev.ops->exec == NULL)) {
+ return -ENODEV;
+ }
+
+#if NAND_ONFI_DETECT
+ if (detect_onfi() != 0) {
+ WARN("Detect ONFI failed\n");
+ }
+#endif
+
+ if (plat_get_raw_nand_data(&rawnand_dev) != 0) {
+ return -EINVAL;
+ }
+
+ assert((rawnand_dev.nand_dev->page_size != 0U) &&
+ (rawnand_dev.nand_dev->block_size != 0U) &&
+ (rawnand_dev.nand_dev->size != 0U));
+
+ *size = rawnand_dev.nand_dev->size;
+ *erase_size = rawnand_dev.nand_dev->block_size;
+
+ rawnand_dev.ops->setup(rawnand_dev.nand_dev);
+
+ return 0;
+}
diff --git a/drivers/mtd/nand/spi_nand.c b/drivers/mtd/nand/spi_nand.c
new file mode 100644
index 0000000000..d01a11963f
--- /dev/null
+++ b/drivers/mtd/nand/spi_nand.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stddef.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/spi_nand.h>
+#include <lib/utils.h>
+
+#define SPI_NAND_MAX_ID_LEN 4U
+#define DELAY_US_400MS 400000U
+#define MACRONIX_ID 0xC2U
+
+static struct spinand_device spinand_dev;
+
+#pragma weak plat_get_spi_nand_data
+int plat_get_spi_nand_data(struct spinand_device *device)
+{
+ return 0;
+}
+
+static int spi_nand_reg(bool read_reg, uint8_t reg, uint8_t *val,
+ enum spi_mem_data_dir dir)
+{
+ struct spi_mem_op op;
+
+ zeromem(&op, sizeof(struct spi_mem_op));
+ if (read_reg) {
+ op.cmd.opcode = SPI_NAND_OP_GET_FEATURE;
+ } else {
+ op.cmd.opcode = SPI_NAND_OP_SET_FEATURE;
+ }
+
+ op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ op.addr.val = reg;
+ op.addr.nbytes = 1U;
+ op.addr.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ op.data.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ op.data.dir = dir;
+ op.data.nbytes = 1U;
+ op.data.buf = val;
+
+ return spi_mem_exec_op(&op);
+}
+
+static int spi_nand_read_reg(uint8_t reg, uint8_t *val)
+{
+ return spi_nand_reg(true, reg, val, SPI_MEM_DATA_IN);
+}
+
+static int spi_nand_write_reg(uint8_t reg, uint8_t val)
+{
+ return spi_nand_reg(false, reg, &val, SPI_MEM_DATA_OUT);
+}
+
+static int spi_nand_update_cfg(uint8_t mask, uint8_t val)
+{
+ int ret;
+ uint8_t cfg = spinand_dev.cfg_cache;
+
+ cfg &= ~mask;
+ cfg |= val;
+
+ if (cfg == spinand_dev.cfg_cache) {
+ return 0;
+ }
+
+ ret = spi_nand_write_reg(SPI_NAND_REG_CFG, cfg);
+ if (ret == 0) {
+ spinand_dev.cfg_cache = cfg;
+ }
+
+ return ret;
+}
+
+static int spi_nand_ecc_enable(bool enable)
+{
+ return spi_nand_update_cfg(SPI_NAND_CFG_ECC_EN,
+ enable ? SPI_NAND_CFG_ECC_EN : 0U);
+}
+
+static int spi_nand_quad_enable(uint8_t manufacturer_id)
+{
+ bool enable = false;
+
+ if (manufacturer_id != MACRONIX_ID) {
+ return 0;
+ }
+
+ if (spinand_dev.spi_read_cache_op.data.buswidth ==
+ SPI_MEM_BUSWIDTH_4_LINE) {
+ enable = true;
+ }
+
+ return spi_nand_update_cfg(SPI_NAND_CFG_QE,
+ enable ? SPI_NAND_CFG_QE : 0U);
+}
+
+static int spi_nand_wait_ready(uint8_t *status)
+{
+ int ret;
+ uint64_t timeout = timeout_init_us(DELAY_US_400MS);
+
+ while (!timeout_elapsed(timeout)) {
+ ret = spi_nand_read_reg(SPI_NAND_REG_STATUS, status);
+ if (ret != 0) {
+ return ret;
+ }
+
+ VERBOSE("%s Status %x\n", __func__, *status);
+ if ((*status & SPI_NAND_STATUS_BUSY) == 0U) {
+ return 0;
+ }
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int spi_nand_reset(void)
+{
+ struct spi_mem_op op;
+ uint8_t status;
+ int ret;
+
+ zeromem(&op, sizeof(struct spi_mem_op));
+ op.cmd.opcode = SPI_NAND_OP_RESET;
+ op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+
+ ret = spi_mem_exec_op(&op);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return spi_nand_wait_ready(&status);
+}
+
+static int spi_nand_read_id(uint8_t *id)
+{
+ struct spi_mem_op op;
+
+ zeromem(&op, sizeof(struct spi_mem_op));
+ op.cmd.opcode = SPI_NAND_OP_READ_ID;
+ op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ op.data.dir = SPI_MEM_DATA_IN;
+ op.data.nbytes = SPI_NAND_MAX_ID_LEN;
+ op.data.buf = id;
+ op.data.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+
+ return spi_mem_exec_op(&op);
+}
+
+static int spi_nand_load_page(unsigned int page)
+{
+ struct spi_mem_op op;
+ uint32_t block_nb = page / spinand_dev.nand_dev->block_size;
+ uint32_t page_nb = page - (block_nb * spinand_dev.nand_dev->page_size);
+ uint32_t nbpages_per_block = spinand_dev.nand_dev->block_size /
+ spinand_dev.nand_dev->page_size;
+ uint32_t block_sh = __builtin_ctz(nbpages_per_block) + 1U;
+
+ zeromem(&op, sizeof(struct spi_mem_op));
+ op.cmd.opcode = SPI_NAND_OP_LOAD_PAGE;
+ op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ op.addr.val = (block_nb << block_sh) | page_nb;
+ op.addr.nbytes = 3U;
+ op.addr.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+
+ return spi_mem_exec_op(&op);
+}
+
+static int spi_nand_read_from_cache(unsigned int page, unsigned int offset,
+ uint8_t *buffer, unsigned int len)
+{
+ uint32_t nbpages_per_block = spinand_dev.nand_dev->block_size /
+ spinand_dev.nand_dev->page_size;
+ uint32_t block_nb = page / nbpages_per_block;
+ uint32_t page_sh = __builtin_ctz(spinand_dev.nand_dev->page_size) + 1U;
+
+ spinand_dev.spi_read_cache_op.addr.val = offset;
+
+ if ((spinand_dev.nand_dev->nb_planes > 1U) && ((block_nb % 2U) == 1U)) {
+ spinand_dev.spi_read_cache_op.addr.val |= 1U << page_sh;
+ }
+
+ spinand_dev.spi_read_cache_op.data.buf = buffer;
+ spinand_dev.spi_read_cache_op.data.nbytes = len;
+
+ return spi_mem_exec_op(&spinand_dev.spi_read_cache_op);
+}
+
+static int spi_nand_read_page(unsigned int page, unsigned int offset,
+ uint8_t *buffer, unsigned int len,
+ bool ecc_enabled)
+{
+ uint8_t status;
+ int ret;
+
+ ret = spi_nand_ecc_enable(ecc_enabled);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nand_load_page(page);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nand_wait_ready(&status);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nand_read_from_cache(page, offset, buffer, len);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (ecc_enabled && ((status & SPI_NAND_STATUS_ECC_UNCOR) != 0U)) {
+ return -EBADMSG;
+ }
+
+ return 0;
+}
+
+static int spi_nand_mtd_block_is_bad(unsigned int block)
+{
+ unsigned int nbpages_per_block = spinand_dev.nand_dev->block_size /
+ spinand_dev.nand_dev->page_size;
+ uint8_t bbm_marker[2];
+ int ret;
+
+ ret = spi_nand_read_page(block * nbpages_per_block,
+ spinand_dev.nand_dev->page_size,
+ bbm_marker, sizeof(bbm_marker), false);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if ((bbm_marker[0] != GENMASK_32(7, 0)) ||
+ (bbm_marker[1] != GENMASK_32(7, 0))) {
+ WARN("Block %i is bad\n", block);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int spi_nand_mtd_read_page(struct nand_device *nand, unsigned int page,
+ uintptr_t buffer)
+{
+ return spi_nand_read_page(page, 0, (uint8_t *)buffer,
+ spinand_dev.nand_dev->page_size, true);
+}
+
+int spi_nand_init(unsigned long long *size, unsigned int *erase_size)
+{
+ uint8_t id[SPI_NAND_MAX_ID_LEN];
+ int ret;
+
+ spinand_dev.nand_dev = get_nand_device();
+ if (spinand_dev.nand_dev == NULL) {
+ return -EINVAL;
+ }
+
+ spinand_dev.nand_dev->mtd_block_is_bad = spi_nand_mtd_block_is_bad;
+ spinand_dev.nand_dev->mtd_read_page = spi_nand_mtd_read_page;
+ spinand_dev.nand_dev->nb_planes = 1;
+
+ spinand_dev.spi_read_cache_op.cmd.opcode = SPI_NAND_OP_READ_FROM_CACHE;
+ spinand_dev.spi_read_cache_op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ spinand_dev.spi_read_cache_op.addr.nbytes = 2U;
+ spinand_dev.spi_read_cache_op.addr.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ spinand_dev.spi_read_cache_op.dummy.nbytes = 1U;
+ spinand_dev.spi_read_cache_op.dummy.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ spinand_dev.spi_read_cache_op.data.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+
+ if (plat_get_spi_nand_data(&spinand_dev) != 0) {
+ return -EINVAL;
+ }
+
+ ret = spi_nand_reset();
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nand_read_id(id);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nand_read_reg(SPI_NAND_REG_CFG, &spinand_dev.cfg_cache);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nand_quad_enable(id[0]);
+ if (ret != 0) {
+ return ret;
+ }
+
+ VERBOSE("SPI_NAND Detected ID 0x%x 0x%x\n", id[0], id[1]);
+
+ VERBOSE("Page size %i, Block size %i, size %lli\n",
+ spinand_dev.nand_dev->page_size,
+ spinand_dev.nand_dev->block_size,
+ spinand_dev.nand_dev->size);
+
+ *size = spinand_dev.nand_dev->size;
+ *erase_size = spinand_dev.nand_dev->block_size;
+
+ return 0;
+}
diff --git a/drivers/mtd/nor/spi_nor.c b/drivers/mtd/nor/spi_nor.c
new file mode 100644
index 0000000000..22d3ae3d9e
--- /dev/null
+++ b/drivers/mtd/nor/spi_nor.c
@@ -0,0 +1,387 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stddef.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/spi_nor.h>
+#include <lib/utils.h>
+
+#define SR_WIP BIT(0) /* Write in progress */
+#define CR_QUAD_EN_SPAN BIT(1) /* Spansion Quad I/O */
+#define SR_QUAD_EN_MX BIT(6) /* Macronix Quad I/O */
+#define FSR_READY BIT(7) /* Device status, 0 = Busy, 1 = Ready */
+
+/* Defined IDs for supported memories */
+#define SPANSION_ID 0x01U
+#define MACRONIX_ID 0xC2U
+#define MICRON_ID 0x2CU
+
+#define BANK_SIZE 0x1000000U
+
+#define SPI_READY_TIMEOUT_US 40000U
+
+static struct nor_device nor_dev;
+
+#pragma weak plat_get_nor_data
+int plat_get_nor_data(struct nor_device *device)
+{
+ return 0;
+}
+
+static int spi_nor_reg(uint8_t reg, uint8_t *buf, size_t len,
+ enum spi_mem_data_dir dir)
+{
+ struct spi_mem_op op;
+
+ zeromem(&op, sizeof(struct spi_mem_op));
+ op.cmd.opcode = reg;
+ op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ op.data.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ op.data.dir = dir;
+ op.data.nbytes = len;
+ op.data.buf = buf;
+
+ return spi_mem_exec_op(&op);
+}
+
+static inline int spi_nor_read_id(uint8_t *id)
+{
+ return spi_nor_reg(SPI_NOR_OP_READ_ID, id, 1U, SPI_MEM_DATA_IN);
+}
+
+static inline int spi_nor_read_cr(uint8_t *cr)
+{
+ return spi_nor_reg(SPI_NOR_OP_READ_CR, cr, 1U, SPI_MEM_DATA_IN);
+}
+
+static inline int spi_nor_read_sr(uint8_t *sr)
+{
+ return spi_nor_reg(SPI_NOR_OP_READ_SR, sr, 1U, SPI_MEM_DATA_IN);
+}
+
+static inline int spi_nor_read_fsr(uint8_t *fsr)
+{
+ return spi_nor_reg(SPI_NOR_OP_READ_FSR, fsr, 1U, SPI_MEM_DATA_IN);
+}
+
+static inline int spi_nor_write_en(void)
+{
+ return spi_nor_reg(SPI_NOR_OP_WREN, NULL, 0U, SPI_MEM_DATA_OUT);
+}
+
+/*
+ * Check if device is ready.
+ *
+ * Return 0 if ready, 1 if busy or a negative error code otherwise
+ */
+static int spi_nor_ready(void)
+{
+ uint8_t sr;
+ int ret;
+
+ ret = spi_nor_read_sr(&sr);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if ((nor_dev.flags & SPI_NOR_USE_FSR) != 0U) {
+ uint8_t fsr;
+
+ ret = spi_nor_read_fsr(&fsr);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return (((fsr & FSR_READY) != 0U) && ((sr & SR_WIP) == 0U)) ?
+ 0 : 1;
+ }
+
+ return (((sr & SR_WIP) != 0U) ? 1 : 0);
+}
+
+static int spi_nor_wait_ready(void)
+{
+ int ret;
+ uint64_t timeout = timeout_init_us(SPI_READY_TIMEOUT_US);
+
+ while (!timeout_elapsed(timeout)) {
+ ret = spi_nor_ready();
+ if (ret <= 0) {
+ return ret;
+ }
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int spi_nor_macronix_quad_enable(void)
+{
+ uint8_t sr;
+ int ret;
+
+ ret = spi_nor_read_sr(&sr);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if ((sr & SR_QUAD_EN_MX) == 0U) {
+ return 0;
+ }
+
+ ret = spi_nor_write_en();
+ if (ret != 0) {
+ return ret;
+ }
+
+ sr |= SR_QUAD_EN_MX;
+ ret = spi_nor_reg(SPI_NOR_OP_WRSR, &sr, 1, SPI_MEM_DATA_OUT);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nor_wait_ready();
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nor_read_sr(&sr);
+ if ((ret != 0) || ((sr & SR_QUAD_EN_MX) == 0U)) {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int spi_nor_write_sr_cr(uint8_t *sr_cr)
+{
+ int ret;
+
+ ret = spi_nor_write_en();
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nor_reg(SPI_NOR_OP_WRSR, sr_cr, 2, SPI_MEM_DATA_OUT);
+ if (ret != 0) {
+ return -EINVAL;
+ }
+
+ ret = spi_nor_wait_ready();
+ if (ret != 0) {
+ return ret;
+ }
+
+ return 0;
+}
+
+static int spi_nor_quad_enable(void)
+{
+ uint8_t sr_cr[2];
+ int ret;
+
+ ret = spi_nor_read_cr(&sr_cr[1]);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if ((sr_cr[1] & CR_QUAD_EN_SPAN) != 0U) {
+ return 0;
+ }
+
+ sr_cr[1] |= CR_QUAD_EN_SPAN;
+ ret = spi_nor_read_sr(&sr_cr[0]);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nor_write_sr_cr(sr_cr);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nor_read_cr(&sr_cr[1]);
+ if ((ret != 0) || ((sr_cr[1] & CR_QUAD_EN_SPAN) == 0U)) {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int spi_nor_clean_bar(void)
+{
+ int ret;
+
+ if (nor_dev.selected_bank == 0U) {
+ return 0;
+ }
+
+ nor_dev.selected_bank = 0U;
+
+ ret = spi_nor_write_en();
+ if (ret != 0) {
+ return ret;
+ }
+
+ return spi_nor_reg(nor_dev.bank_write_cmd, &nor_dev.selected_bank,
+ 1, SPI_MEM_DATA_OUT);
+}
+
+static int spi_nor_write_bar(uint32_t offset)
+{
+ uint8_t selected_bank = offset / BANK_SIZE;
+ int ret;
+
+ if (selected_bank == nor_dev.selected_bank) {
+ return 0;
+ }
+
+ ret = spi_nor_write_en();
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nor_reg(nor_dev.bank_write_cmd, &selected_bank,
+ 1, SPI_MEM_DATA_OUT);
+ if (ret != 0) {
+ return ret;
+ }
+
+ nor_dev.selected_bank = selected_bank;
+
+ return 0;
+}
+
+static int spi_nor_read_bar(void)
+{
+ uint8_t selected_bank = 0;
+ int ret;
+
+ ret = spi_nor_reg(nor_dev.bank_read_cmd, &selected_bank,
+ 1, SPI_MEM_DATA_IN);
+ if (ret != 0) {
+ return ret;
+ }
+
+ nor_dev.selected_bank = selected_bank;
+
+ return 0;
+}
+
+int spi_nor_read(unsigned int offset, uintptr_t buffer, size_t length,
+ size_t *length_read)
+{
+ size_t remain_len;
+ int ret;
+
+ *length_read = 0;
+ nor_dev.read_op.addr.val = offset;
+ nor_dev.read_op.data.buf = (void *)buffer;
+
+ VERBOSE("%s offset %i length %zu\n", __func__, offset, length);
+
+ while (length != 0U) {
+ if ((nor_dev.flags & SPI_NOR_USE_BANK) != 0U) {
+ ret = spi_nor_write_bar(nor_dev.read_op.addr.val);
+ if (ret != 0) {
+ return ret;
+ }
+
+ remain_len = (BANK_SIZE * (nor_dev.selected_bank + 1)) -
+ nor_dev.read_op.addr.val;
+ nor_dev.read_op.data.nbytes = MIN(length, remain_len);
+ } else {
+ nor_dev.read_op.data.nbytes = length;
+ }
+
+ ret = spi_mem_exec_op(&nor_dev.read_op);
+ if (ret != 0) {
+ spi_nor_clean_bar();
+ return ret;
+ }
+
+ length -= nor_dev.read_op.data.nbytes;
+ nor_dev.read_op.addr.val += nor_dev.read_op.data.nbytes;
+ nor_dev.read_op.data.buf += nor_dev.read_op.data.nbytes;
+ *length_read += nor_dev.read_op.data.nbytes;
+ }
+
+ if ((nor_dev.flags & SPI_NOR_USE_BANK) != 0U) {
+ ret = spi_nor_clean_bar();
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int spi_nor_init(unsigned long long *size, unsigned int *erase_size)
+{
+ int ret = 0;
+ uint8_t id;
+
+ /* Default read command used */
+ nor_dev.read_op.cmd.opcode = SPI_NOR_OP_READ;
+ nor_dev.read_op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ nor_dev.read_op.addr.nbytes = 3U;
+ nor_dev.read_op.addr.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ nor_dev.read_op.data.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ nor_dev.read_op.data.dir = SPI_MEM_DATA_IN;
+
+ if (plat_get_nor_data(&nor_dev) != 0) {
+ return -EINVAL;
+ }
+
+ assert(nor_dev.size != 0);
+
+ if (nor_dev.size > BANK_SIZE) {
+ nor_dev.flags |= SPI_NOR_USE_BANK;
+ }
+
+ *size = nor_dev.size;
+
+ ret = spi_nor_read_id(&id);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if ((nor_dev.flags & SPI_NOR_USE_BANK) != 0U) {
+ switch (id) {
+ case SPANSION_ID:
+ nor_dev.bank_read_cmd = SPINOR_OP_BRRD;
+ nor_dev.bank_write_cmd = SPINOR_OP_BRWR;
+ break;
+ default:
+ nor_dev.bank_read_cmd = SPINOR_OP_RDEAR;
+ nor_dev.bank_write_cmd = SPINOR_OP_WREAR;
+ break;
+ }
+ }
+
+ if (nor_dev.read_op.data.buswidth == 4U) {
+ switch (id) {
+ case MACRONIX_ID:
+ WARN("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 0000000000..63ea7699b8
--- /dev/null
+++ b/drivers/mtd/spi-mem/spi_mem.c
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <libfdt.h>
+
+#include <drivers/spi_mem.h>
+#include <lib/utils_def.h>
+
+#define SPI_MEM_DEFAULT_SPEED_HZ 100000U
+
+/*
+ * struct spi_slave - Representation of a SPI slave.
+ *
+ * @max_hz: Maximum speed for this slave in Hertz.
+ * @cs: ID of the chip select connected to the slave.
+ * @mode: SPI mode to use for this slave (see SPI mode flags).
+ * @ops: Ops defined by the bus.
+ */
+struct spi_slave {
+ unsigned int max_hz;
+ unsigned int cs;
+ unsigned int mode;
+ const struct spi_bus_ops *ops;
+};
+
+static struct spi_slave spi_slave;
+
+static bool spi_mem_check_buswidth_req(uint8_t buswidth, bool tx)
+{
+ switch (buswidth) {
+ case 1U:
+ return true;
+
+ case 2U:
+ if ((tx && (spi_slave.mode & (SPI_TX_DUAL | SPI_TX_QUAD)) !=
+ 0U) ||
+ (!tx && (spi_slave.mode & (SPI_RX_DUAL | SPI_RX_QUAD)) !=
+ 0U)) {
+ return true;
+ }
+ break;
+
+ case 4U:
+ if ((tx && (spi_slave.mode & SPI_TX_QUAD) != 0U) ||
+ (!tx && (spi_slave.mode & SPI_RX_QUAD) != 0U)) {
+ return true;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+static bool spi_mem_supports_op(const struct spi_mem_op *op)
+{
+ if (!spi_mem_check_buswidth_req(op->cmd.buswidth, true)) {
+ return false;
+ }
+
+ if ((op->addr.nbytes != 0U) &&
+ !spi_mem_check_buswidth_req(op->addr.buswidth, true)) {
+ return false;
+ }
+
+ if ((op->dummy.nbytes != 0U) &&
+ !spi_mem_check_buswidth_req(op->dummy.buswidth, true)) {
+ return false;
+ }
+
+ if ((op->data.nbytes != 0U) &&
+ !spi_mem_check_buswidth_req(op->data.buswidth,
+ op->data.dir == SPI_MEM_DATA_OUT)) {
+ return false;
+ }
+
+ return true;
+}
+
+static int spi_mem_set_speed_mode(void)
+{
+ const struct spi_bus_ops *ops = spi_slave.ops;
+ int ret;
+
+ ret = ops->set_speed(spi_slave.max_hz);
+ if (ret != 0) {
+ VERBOSE("Cannot set speed (err=%d)\n", ret);
+ return ret;
+ }
+
+ ret = ops->set_mode(spi_slave.mode);
+ if (ret != 0) {
+ VERBOSE("Cannot set mode (err=%d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int spi_mem_check_bus_ops(const struct spi_bus_ops *ops)
+{
+ bool error = false;
+
+ if (ops->claim_bus == NULL) {
+ VERBOSE("Ops claim bus is not defined\n");
+ error = true;
+ }
+
+ if (ops->release_bus == NULL) {
+ VERBOSE("Ops release bus is not defined\n");
+ error = true;
+ }
+
+ if (ops->exec_op == NULL) {
+ VERBOSE("Ops exec op is not defined\n");
+ error = true;
+ }
+
+ if (ops->set_speed == NULL) {
+ VERBOSE("Ops set speed is not defined\n");
+ error = true;
+ }
+
+ if (ops->set_mode == NULL) {
+ VERBOSE("Ops set mode is not defined\n");
+ error = true;
+ }
+
+ return error ? -EINVAL : 0;
+}
+
+/*
+ * spi_mem_exec_op() - Execute a memory operation.
+ * @op: The memory operation to execute.
+ *
+ * This function first checks that @op is supported and then tries to execute
+ * it.
+ *
+ * Return: 0 in case of success, a negative error code otherwise.
+ */
+int spi_mem_exec_op(const struct spi_mem_op *op)
+{
+ const struct spi_bus_ops *ops = spi_slave.ops;
+ int ret;
+
+ VERBOSE("%s: cmd:%x mode:%d.%d.%d.%d addqr:%llx len:%x\n",
+ __func__, op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,
+ op->dummy.buswidth, op->data.buswidth,
+ op->addr.val, op->data.nbytes);
+
+ if (!spi_mem_supports_op(op)) {
+ WARN("Error in spi_mem_support\n");
+ return -ENOTSUP;
+ }
+
+ ret = ops->claim_bus(spi_slave.cs);
+ if (ret != 0) {
+ WARN("Error claim_bus\n");
+ return ret;
+ }
+
+ ret = ops->exec_op(op);
+
+ ops->release_bus();
+
+ return ret;
+}
+
+/*
+ * spi_mem_init_slave() - SPI slave device initialization.
+ * @fdt: Pointer to the device tree blob.
+ * @bus_node: Offset of the bus node.
+ * @ops: The SPI bus ops defined.
+ *
+ * This function first checks that @ops are supported and then tries to find
+ * a SPI slave device.
+ *
+ * Return: 0 in case of success, a negative error code otherwise.
+ */
+int spi_mem_init_slave(void *fdt, int bus_node, const struct spi_bus_ops *ops)
+{
+ int ret;
+ int mode = 0;
+ int nchips = 0;
+ int bus_subnode = 0;
+ const fdt32_t *cuint = NULL;
+
+ ret = spi_mem_check_bus_ops(ops);
+ if (ret != 0) {
+ return ret;
+ }
+
+ fdt_for_each_subnode(bus_subnode, fdt, bus_node) {
+ nchips++;
+ }
+
+ if (nchips != 1) {
+ ERROR("Only one SPI device is currently supported\n");
+ return -EINVAL;
+ }
+
+ fdt_for_each_subnode(bus_subnode, fdt, bus_node) {
+ /* Get chip select */
+ cuint = fdt_getprop(fdt, bus_subnode, "reg", NULL);
+ if (cuint == NULL) {
+ ERROR("Chip select not well defined\n");
+ return -EINVAL;
+ }
+ spi_slave.cs = fdt32_to_cpu(*cuint);
+
+ /* Get max slave frequency */
+ spi_slave.max_hz = SPI_MEM_DEFAULT_SPEED_HZ;
+ cuint = fdt_getprop(fdt, bus_subnode,
+ "spi-max-frequency", NULL);
+ if (cuint != NULL) {
+ spi_slave.max_hz = fdt32_to_cpu(*cuint);
+ }
+
+ /* Get mode */
+ if ((fdt_getprop(fdt, bus_subnode, "spi-cpol", NULL)) != NULL) {
+ mode |= SPI_CPOL;
+ }
+ if ((fdt_getprop(fdt, bus_subnode, "spi-cpha", NULL)) != NULL) {
+ mode |= SPI_CPHA;
+ }
+ if ((fdt_getprop(fdt, bus_subnode, "spi-cs-high", NULL)) !=
+ NULL) {
+ mode |= SPI_CS_HIGH;
+ }
+ if ((fdt_getprop(fdt, bus_subnode, "spi-3wire", NULL)) !=
+ NULL) {
+ mode |= SPI_3WIRE;
+ }
+ if ((fdt_getprop(fdt, bus_subnode, "spi-half-duplex", NULL)) !=
+ NULL) {
+ mode |= SPI_PREAMBLE;
+ }
+
+ /* Get dual/quad mode */
+ cuint = fdt_getprop(fdt, bus_subnode, "spi-tx-bus-width", NULL);
+ if (cuint != NULL) {
+ switch (fdt32_to_cpu(*cuint)) {
+ case 1U:
+ break;
+ case 2U:
+ mode |= SPI_TX_DUAL;
+ break;
+ case 4U:
+ mode |= SPI_TX_QUAD;
+ break;
+ default:
+ WARN("spi-tx-bus-width %d not supported\n",
+ fdt32_to_cpu(*cuint));
+ return -EINVAL;
+ }
+ }
+
+ cuint = fdt_getprop(fdt, bus_subnode, "spi-rx-bus-width", NULL);
+ if (cuint != NULL) {
+ switch (fdt32_to_cpu(*cuint)) {
+ case 1U:
+ break;
+ case 2U:
+ mode |= SPI_RX_DUAL;
+ break;
+ case 4U:
+ mode |= SPI_RX_QUAD;
+ break;
+ default:
+ WARN("spi-rx-bus-width %d not supported\n",
+ fdt32_to_cpu(*cuint));
+ return -EINVAL;
+ }
+ }
+
+ spi_slave.mode = mode;
+ spi_slave.ops = ops;
+ }
+
+ return spi_mem_set_speed_mode();
+}
diff --git a/drivers/renesas/rcar/io/io_emmcdrv.c b/drivers/renesas/rcar/io/io_emmcdrv.c
index 4b464fb3e4..84240d2606 100644
--- a/drivers/renesas/rcar/io/io_emmcdrv.c
+++ b/drivers/renesas/rcar/io/io_emmcdrv.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -25,7 +25,7 @@ static int32_t emmcdrv_dev_close(io_dev_info_t *dev_info);
typedef struct {
uint32_t in_use;
uintptr_t base;
- ssize_t file_pos;
+ signed long long file_pos;
EMMC_PARTITION_ID partition;
} file_state_t;
@@ -39,7 +39,7 @@ static io_type_t device_type_emmcdrv(void)
}
static int32_t emmcdrv_block_seek(io_entity_t *entity, int32_t mode,
- ssize_t offset)
+ signed long long offset)
{
if (mode != IO_SEEK_SET)
return IO_FAIL;
@@ -59,12 +59,12 @@ static int32_t emmcdrv_block_read(io_entity_t *entity, uintptr_t buffer,
sector_add = current_file.file_pos >> EMMC_SECTOR_SIZE_SHIFT;
sector_num = (length + EMMC_SECTOR_SIZE - 1U) >> EMMC_SECTOR_SIZE_SHIFT;
- NOTICE("BL2: Load dst=0x%lx src=(p:%d)0x%lx(%d) len=0x%lx(%d)\n",
+ NOTICE("BL2: Load dst=0x%lx src=(p:%d)0x%llx(%d) len=0x%lx(%d)\n",
buffer,
current_file.partition, current_file.file_pos,
sector_add, length, sector_num);
- if (buffer + length - 1 <= UINT32_MAX)
+ if ((buffer + length - 1U) <= (uintptr_t)UINT32_MAX)
emmc_dma = LOADIMAGE_FLAGS_DMA_ENABLE;
if (emmc_read_sector((uint32_t *) buffer, sector_add, sector_num,
@@ -72,7 +72,7 @@ static int32_t emmcdrv_block_read(io_entity_t *entity, uintptr_t buffer,
result = IO_FAIL;
*length_read = length;
- fp->file_pos += length;
+ fp->file_pos += (signed long long)length;
return result;
}
@@ -82,7 +82,7 @@ static int32_t emmcdrv_block_open(io_dev_info_t *dev_info,
{
const io_drv_spec_t *block_spec = (io_drv_spec_t *) spec;
- if (current_file.in_use) {
+ if (current_file.in_use != 0U) {
WARN("mmc_block: Only one open spec at a time\n");
return IO_RESOURCES_EXHAUSTED;
}
@@ -103,9 +103,9 @@ static int32_t emmcdrv_block_open(io_dev_info_t *dev_info,
return IO_FAIL;
}
- if (PARTITION_ID_USER == block_spec->partition ||
- PARTITION_ID_BOOT_1 == block_spec->partition ||
- PARTITION_ID_BOOT_2 == block_spec->partition)
+ if ((PARTITION_ID_USER == block_spec->partition) ||
+ (PARTITION_ID_BOOT_1 == block_spec->partition) ||
+ (PARTITION_ID_BOOT_2 == block_spec->partition))
current_file.partition = block_spec->partition;
else
current_file.partition = emmcdrv_bootpartition;
diff --git a/drivers/renesas/rcar/io/io_memdrv.c b/drivers/renesas/rcar/io/io_memdrv.c
index 3f6b4c71b1..7e8c1d3a65 100644
--- a/drivers/renesas/rcar/io/io_memdrv.c
+++ b/drivers/renesas/rcar/io/io_memdrv.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -28,7 +28,7 @@ static int32_t memdrv_dev_close(io_dev_info_t *dev_info);
typedef struct {
uint32_t in_use;
uintptr_t base;
- ssize_t file_pos;
+ signed long long file_pos;
} file_state_t;
static file_state_t current_file = { 0 };
@@ -47,7 +47,7 @@ static int32_t memdrv_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
* spec at a time. When we have dynamic memory we can malloc and set
* entity->info.
*/
- if (current_file.in_use)
+ if (current_file.in_use != 0U)
return IO_RESOURCES_EXHAUSTED;
/* File cursor offset for seek and incremental reads etc. */
@@ -61,7 +61,7 @@ static int32_t memdrv_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
}
static int32_t memdrv_block_seek(io_entity_t *entity, int32_t mode,
- ssize_t offset)
+ signed long long offset)
{
if (mode != IO_SEEK_SET)
return IO_FAIL;
@@ -78,16 +78,17 @@ static int32_t memdrv_block_read(io_entity_t *entity, uintptr_t buffer,
fp = (file_state_t *) entity->info;
- NOTICE("BL2: dst=0x%lx src=0x%lx len=%ld(0x%lx)\n",
- buffer, fp->base + fp->file_pos, length, length);
+ NOTICE("BL2: dst=0x%lx src=0x%llx len=%ld(0x%lx)\n",
+ buffer, (unsigned long long)fp->base +
+ (unsigned long long)fp->file_pos, length, length);
- if (FLASH_MEMORY_SIZE < fp->file_pos + length) {
+ if (FLASH_MEMORY_SIZE < (fp->file_pos + (signed long long)length)) {
ERROR("BL2: check load image (source address)\n");
return IO_FAIL;
}
- rcar_dma_exec(buffer, fp->base + fp->file_pos, length);
- fp->file_pos += length;
+ rcar_dma_exec(buffer, fp->base + (uintptr_t)fp->file_pos, length);
+ fp->file_pos += (signed long long)length;
*cnt = length;
return IO_SUCCESS;
diff --git a/drivers/st/fmc/stm32_fmc2_nand.c b/drivers/st/fmc/stm32_fmc2_nand.c
new file mode 100644
index 0000000000..b694fff6bf
--- /dev/null
+++ b/drivers/st/fmc/stm32_fmc2_nand.c
@@ -0,0 +1,877 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/raw_nand.h>
+#include <drivers/st/stm32_fmc2_nand.h>
+#include <drivers/st/stm32_gpio.h>
+#include <drivers/st/stm32mp_reset.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+/* FMC2 Compatibility */
+#define DT_FMC2_COMPAT "st,stm32mp15-fmc2"
+#define MAX_CS 2U
+
+/* FMC2 Controller Registers */
+#define FMC2_BCR1 0x00U
+#define FMC2_PCR 0x80U
+#define FMC2_SR 0x84U
+#define FMC2_PMEM 0x88U
+#define FMC2_PATT 0x8CU
+#define FMC2_HECCR 0x94U
+#define FMC2_BCHISR 0x254U
+#define FMC2_BCHDSR0 0x27CU
+#define FMC2_BCHDSR1 0x280U
+#define FMC2_BCHDSR2 0x284U
+#define FMC2_BCHDSR3 0x288U
+#define FMC2_BCHDSR4 0x28CU
+
+/* FMC2_BCR1 register */
+#define FMC2_BCR1_FMC2EN BIT(31)
+/* FMC2_PCR register */
+#define FMC2_PCR_PWAITEN BIT(1)
+#define FMC2_PCR_PBKEN BIT(2)
+#define FMC2_PCR_PWID_MASK GENMASK_32(5, 4)
+#define FMC2_PCR_PWID(x) (((x) << 4) & FMC2_PCR_PWID_MASK)
+#define FMC2_PCR_PWID_8 0x0U
+#define FMC2_PCR_PWID_16 0x1U
+#define FMC2_PCR_ECCEN BIT(6)
+#define FMC2_PCR_ECCALG BIT(8)
+#define FMC2_PCR_TCLR_MASK GENMASK_32(12, 9)
+#define FMC2_PCR_TCLR(x) (((x) << 9) & FMC2_PCR_TCLR_MASK)
+#define FMC2_PCR_TCLR_DEFAULT 0xFU
+#define FMC2_PCR_TAR_MASK GENMASK_32(16, 13)
+#define FMC2_PCR_TAR(x) (((x) << 13) & FMC2_PCR_TAR_MASK)
+#define FMC2_PCR_TAR_DEFAULT 0xFU
+#define FMC2_PCR_ECCSS_MASK GENMASK_32(19, 17)
+#define FMC2_PCR_ECCSS(x) (((x) << 17) & FMC2_PCR_ECCSS_MASK)
+#define FMC2_PCR_ECCSS_512 0x1U
+#define FMC2_PCR_ECCSS_2048 0x3U
+#define FMC2_PCR_BCHECC BIT(24)
+#define FMC2_PCR_WEN BIT(25)
+/* FMC2_SR register */
+#define FMC2_SR_NWRF BIT(6)
+/* FMC2_PMEM register*/
+#define FMC2_PMEM_MEMSET(x) (((x) & GENMASK_32(7, 0)) << 0)
+#define FMC2_PMEM_MEMWAIT(x) (((x) & GENMASK_32(7, 0)) << 8)
+#define FMC2_PMEM_MEMHOLD(x) (((x) & GENMASK_32(7, 0)) << 16)
+#define FMC2_PMEM_MEMHIZ(x) (((x) & GENMASK_32(7, 0)) << 24)
+#define FMC2_PMEM_DEFAULT 0x0A0A0A0AU
+/* FMC2_PATT register */
+#define FMC2_PATT_ATTSET(x) (((x) & GENMASK_32(7, 0)) << 0)
+#define FMC2_PATT_ATTWAIT(x) (((x) & GENMASK_32(7, 0)) << 8)
+#define FMC2_PATT_ATTHOLD(x) (((x) & GENMASK_32(7, 0)) << 16)
+#define FMC2_PATT_ATTHIZ(x) (((x) & GENMASK_32(7, 0)) << 24)
+#define FMC2_PATT_DEFAULT 0x0A0A0A0AU
+/* FMC2_BCHISR register */
+#define FMC2_BCHISR_DERF BIT(1)
+/* FMC2_BCHDSR0 register */
+#define FMC2_BCHDSR0_DUE BIT(0)
+#define FMC2_BCHDSR0_DEF BIT(1)
+#define FMC2_BCHDSR0_DEN_MASK GENMASK_32(7, 4)
+#define FMC2_BCHDSR0_DEN_SHIFT 4U
+/* FMC2_BCHDSR1 register */
+#define FMC2_BCHDSR1_EBP1_MASK GENMASK_32(12, 0)
+#define FMC2_BCHDSR1_EBP2_MASK GENMASK_32(28, 16)
+#define FMC2_BCHDSR1_EBP2_SHIFT 16U
+/* FMC2_BCHDSR2 register */
+#define FMC2_BCHDSR2_EBP3_MASK GENMASK_32(12, 0)
+#define FMC2_BCHDSR2_EBP4_MASK GENMASK_32(28, 16)
+#define FMC2_BCHDSR2_EBP4_SHIFT 16U
+/* FMC2_BCHDSR3 register */
+#define FMC2_BCHDSR3_EBP5_MASK GENMASK_32(12, 0)
+#define FMC2_BCHDSR3_EBP6_MASK GENMASK_32(28, 16)
+#define FMC2_BCHDSR3_EBP6_SHIFT 16U
+/* FMC2_BCHDSR4 register */
+#define FMC2_BCHDSR4_EBP7_MASK GENMASK_32(12, 0)
+#define FMC2_BCHDSR4_EBP8_MASK GENMASK_32(28, 16)
+#define FMC2_BCHDSR4_EBP8_SHIFT 16U
+
+/* Timings */
+#define FMC2_THIZ 0x01U
+#define FMC2_TIO 8000U
+#define FMC2_TSYNC 3000U
+#define FMC2_PCR_TIMING_MASK GENMASK_32(3, 0)
+#define FMC2_PMEM_PATT_TIMING_MASK GENMASK_32(7, 0)
+
+#define FMC2_BBM_LEN 2U
+#define FMC2_MAX_ECC_BYTES 14U
+#define TIMEOUT_US_10_MS 10000U
+#define FMC2_PSEC_PER_MSEC (1000UL * 1000UL * 1000UL)
+
+enum stm32_fmc2_ecc {
+ FMC2_ECC_HAM = 1U,
+ FMC2_ECC_BCH4 = 4U,
+ FMC2_ECC_BCH8 = 8U
+};
+
+struct stm32_fmc2_cs_reg {
+ uintptr_t data_base;
+ uintptr_t cmd_base;
+ uintptr_t addr_base;
+};
+
+struct stm32_fmc2_nand_timings {
+ uint8_t tclr;
+ uint8_t tar;
+ uint8_t thiz;
+ uint8_t twait;
+ uint8_t thold_mem;
+ uint8_t tset_mem;
+ uint8_t thold_att;
+ uint8_t tset_att;
+};
+
+struct stm32_fmc2_nfc {
+ uintptr_t reg_base;
+ struct stm32_fmc2_cs_reg cs[MAX_CS];
+ unsigned long clock_id;
+ unsigned int reset_id;
+ uint8_t cs_sel;
+};
+
+static struct stm32_fmc2_nfc stm32_fmc2;
+
+static uintptr_t fmc2_base(void)
+{
+ return stm32_fmc2.reg_base;
+}
+
+static void stm32_fmc2_nand_setup_timing(void)
+{
+ struct stm32_fmc2_nand_timings tims;
+ unsigned long hclk = stm32mp_clk_get_rate(stm32_fmc2.clock_id);
+ unsigned long hclkp = FMC2_PSEC_PER_MSEC / (hclk / 1000U);
+ unsigned long timing, tar, tclr, thiz, twait;
+ unsigned long tset_mem, tset_att, thold_mem, thold_att;
+ uint32_t pcr, pmem, patt;
+
+ tar = MAX(hclkp, NAND_TAR_MIN);
+ timing = div_round_up(tar, hclkp) - 1U;
+ tims.tar = MIN(timing, (unsigned long)FMC2_PCR_TIMING_MASK);
+
+ tclr = MAX(hclkp, NAND_TCLR_MIN);
+ timing = div_round_up(tclr, hclkp) - 1U;
+ tims.tclr = MIN(timing, (unsigned long)FMC2_PCR_TIMING_MASK);
+
+ tims.thiz = FMC2_THIZ;
+ thiz = (tims.thiz + 1U) * hclkp;
+
+ /*
+ * tWAIT > tRP
+ * tWAIT > tWP
+ * tWAIT > tREA + tIO
+ */
+ twait = MAX(hclkp, NAND_TRP_MIN);
+ twait = MAX(twait, NAND_TWP_MIN);
+ twait = MAX(twait, NAND_TREA_MAX + FMC2_TIO);
+ timing = div_round_up(twait, hclkp);
+ tims.twait = CLAMP(timing, 1UL,
+ (unsigned long)FMC2_PMEM_PATT_TIMING_MASK);
+
+ /*
+ * tSETUP_MEM > tCS - tWAIT
+ * tSETUP_MEM > tALS - tWAIT
+ * tSETUP_MEM > tDS - (tWAIT - tHIZ)
+ */
+ tset_mem = hclkp;
+ if ((twait < NAND_TCS_MIN) && (tset_mem < (NAND_TCS_MIN - twait))) {
+ tset_mem = NAND_TCS_MIN - twait;
+ }
+ if ((twait < NAND_TALS_MIN) && (tset_mem < (NAND_TALS_MIN - twait))) {
+ tset_mem = NAND_TALS_MIN - twait;
+ }
+ if ((twait > thiz) && ((twait - thiz) < NAND_TDS_MIN) &&
+ (tset_mem < (NAND_TDS_MIN - (twait - thiz)))) {
+ tset_mem = NAND_TDS_MIN - (twait - thiz);
+ }
+ timing = div_round_up(tset_mem, hclkp);
+ tims.tset_mem = CLAMP(timing, 1UL,
+ (unsigned long)FMC2_PMEM_PATT_TIMING_MASK);
+
+ /*
+ * tHOLD_MEM > tCH
+ * tHOLD_MEM > tREH - tSETUP_MEM
+ * tHOLD_MEM > max(tRC, tWC) - (tSETUP_MEM + tWAIT)
+ */
+ thold_mem = MAX(hclkp, NAND_TCH_MIN);
+ if ((tset_mem < NAND_TREH_MIN) &&
+ (thold_mem < (NAND_TREH_MIN - tset_mem))) {
+ thold_mem = NAND_TREH_MIN - tset_mem;
+ }
+ if (((tset_mem + twait) < NAND_TRC_MIN) &&
+ (thold_mem < (NAND_TRC_MIN - (tset_mem + twait)))) {
+ thold_mem = NAND_TRC_MIN - (tset_mem + twait);
+ }
+ if (((tset_mem + twait) < NAND_TWC_MIN) &&
+ (thold_mem < (NAND_TWC_MIN - (tset_mem + twait)))) {
+ thold_mem = NAND_TWC_MIN - (tset_mem + twait);
+ }
+ timing = div_round_up(thold_mem, hclkp);
+ tims.thold_mem = CLAMP(timing, 1UL,
+ (unsigned long)FMC2_PMEM_PATT_TIMING_MASK);
+
+ /*
+ * tSETUP_ATT > tCS - tWAIT
+ * tSETUP_ATT > tCLS - tWAIT
+ * tSETUP_ATT > tALS - tWAIT
+ * tSETUP_ATT > tRHW - tHOLD_MEM
+ * tSETUP_ATT > tDS - (tWAIT - tHIZ)
+ */
+ tset_att = hclkp;
+ if ((twait < NAND_TCS_MIN) && (tset_att < (NAND_TCS_MIN - twait))) {
+ tset_att = NAND_TCS_MIN - twait;
+ }
+ if ((twait < NAND_TCLS_MIN) && (tset_att < (NAND_TCLS_MIN - twait))) {
+ tset_att = NAND_TCLS_MIN - twait;
+ }
+ if ((twait < NAND_TALS_MIN) && (tset_att < (NAND_TALS_MIN - twait))) {
+ tset_att = NAND_TALS_MIN - twait;
+ }
+ if ((thold_mem < NAND_TRHW_MIN) &&
+ (tset_att < (NAND_TRHW_MIN - thold_mem))) {
+ tset_att = NAND_TRHW_MIN - thold_mem;
+ }
+ if ((twait > thiz) && ((twait - thiz) < NAND_TDS_MIN) &&
+ (tset_att < (NAND_TDS_MIN - (twait - thiz)))) {
+ tset_att = NAND_TDS_MIN - (twait - thiz);
+ }
+ timing = div_round_up(tset_att, hclkp);
+ tims.tset_att = CLAMP(timing, 1UL,
+ (unsigned long)FMC2_PMEM_PATT_TIMING_MASK);
+
+ /*
+ * tHOLD_ATT > tALH
+ * tHOLD_ATT > tCH
+ * tHOLD_ATT > tCLH
+ * tHOLD_ATT > tCOH
+ * tHOLD_ATT > tDH
+ * tHOLD_ATT > tWB + tIO + tSYNC - tSETUP_MEM
+ * tHOLD_ATT > tADL - tSETUP_MEM
+ * tHOLD_ATT > tWH - tSETUP_MEM
+ * tHOLD_ATT > tWHR - tSETUP_MEM
+ * tHOLD_ATT > tRC - (tSETUP_ATT + tWAIT)
+ * tHOLD_ATT > tWC - (tSETUP_ATT + tWAIT)
+ */
+ thold_att = MAX(hclkp, NAND_TALH_MIN);
+ thold_att = MAX(thold_att, NAND_TCH_MIN);
+ thold_att = MAX(thold_att, NAND_TCLH_MIN);
+ thold_att = MAX(thold_att, NAND_TCOH_MIN);
+ thold_att = MAX(thold_att, NAND_TDH_MIN);
+ if (((NAND_TWB_MAX + FMC2_TIO + FMC2_TSYNC) > tset_mem) &&
+ (thold_att < (NAND_TWB_MAX + FMC2_TIO + FMC2_TSYNC - tset_mem))) {
+ thold_att = NAND_TWB_MAX + FMC2_TIO + FMC2_TSYNC - tset_mem;
+ }
+ if ((tset_mem < NAND_TADL_MIN) &&
+ (thold_att < (NAND_TADL_MIN - tset_mem))) {
+ thold_att = NAND_TADL_MIN - tset_mem;
+ }
+ if ((tset_mem < NAND_TWH_MIN) &&
+ (thold_att < (NAND_TWH_MIN - tset_mem))) {
+ thold_att = NAND_TWH_MIN - tset_mem;
+ }
+ if ((tset_mem < NAND_TWHR_MIN) &&
+ (thold_att < (NAND_TWHR_MIN - tset_mem))) {
+ thold_att = NAND_TWHR_MIN - tset_mem;
+ }
+ if (((tset_att + twait) < NAND_TRC_MIN) &&
+ (thold_att < (NAND_TRC_MIN - (tset_att + twait)))) {
+ thold_att = NAND_TRC_MIN - (tset_att + twait);
+ }
+ if (((tset_att + twait) < NAND_TWC_MIN) &&
+ (thold_att < (NAND_TWC_MIN - (tset_att + twait)))) {
+ thold_att = NAND_TWC_MIN - (tset_att + twait);
+ }
+ timing = div_round_up(thold_att, hclkp);
+ tims.thold_att = CLAMP(timing, 1UL,
+ (unsigned long)FMC2_PMEM_PATT_TIMING_MASK);
+
+ VERBOSE("NAND timings: %u - %u - %u - %u - %u - %u - %u - %u\n",
+ tims.tclr, tims.tar, tims.thiz, tims.twait,
+ tims.thold_mem, tims.tset_mem,
+ tims.thold_att, tims.tset_att);
+
+ /* Set tclr/tar timings */
+ pcr = mmio_read_32(fmc2_base() + FMC2_PCR);
+ pcr &= ~FMC2_PCR_TCLR_MASK;
+ pcr |= FMC2_PCR_TCLR(tims.tclr);
+ pcr &= ~FMC2_PCR_TAR_MASK;
+ pcr |= FMC2_PCR_TAR(tims.tar);
+
+ /* Set tset/twait/thold/thiz timings in common bank */
+ pmem = FMC2_PMEM_MEMSET(tims.tset_mem);
+ pmem |= FMC2_PMEM_MEMWAIT(tims.twait);
+ pmem |= FMC2_PMEM_MEMHOLD(tims.thold_mem);
+ pmem |= FMC2_PMEM_MEMHIZ(tims.thiz);
+
+ /* Set tset/twait/thold/thiz timings in attribute bank */
+ patt = FMC2_PATT_ATTSET(tims.tset_att);
+ patt |= FMC2_PATT_ATTWAIT(tims.twait);
+ patt |= FMC2_PATT_ATTHOLD(tims.thold_att);
+ patt |= FMC2_PATT_ATTHIZ(tims.thiz);
+
+ mmio_write_32(fmc2_base() + FMC2_PCR, pcr);
+ mmio_write_32(fmc2_base() + FMC2_PMEM, pmem);
+ mmio_write_32(fmc2_base() + FMC2_PATT, patt);
+}
+
+static void stm32_fmc2_set_buswidth_16(bool set)
+{
+ mmio_clrsetbits_32(fmc2_base() + FMC2_PCR, FMC2_PCR_PWID_MASK,
+ (set ? FMC2_PCR_PWID(FMC2_PCR_PWID_16) : 0U));
+}
+
+static void stm32_fmc2_set_ecc(bool enable)
+{
+ mmio_clrsetbits_32(fmc2_base() + FMC2_PCR, FMC2_PCR_ECCEN,
+ (enable ? FMC2_PCR_ECCEN : 0U));
+}
+
+static int stm32_fmc2_ham_correct(uint8_t *buffer, uint8_t *eccbuffer,
+ uint8_t *ecc)
+{
+ uint8_t xor_ecc_ones;
+ uint16_t xor_ecc_1b, xor_ecc_2b, xor_ecc_3b;
+ union {
+ uint32_t val;
+ uint8_t bytes[4];
+ } xor_ecc;
+
+ /* Page size--------ECC_Code Size
+ * 256---------------22 bits LSB (ECC_CODE & 0x003FFFFF)
+ * 512---------------24 bits (ECC_CODE & 0x00FFFFFF)
+ * 1024--------------26 bits (ECC_CODE & 0x03FFFFFF)
+ * 2048--------------28 bits (ECC_CODE & 0x0FFFFFFF)
+ * 4096--------------30 bits (ECC_CODE & 0x3FFFFFFF)
+ * 8192--------------32 bits (ECC_CODE & 0xFFFFFFFF)
+ */
+
+ /* For Page size 512, ECC_Code size 24 bits */
+ xor_ecc_1b = ecc[0] ^ eccbuffer[0];
+ xor_ecc_2b = ecc[1] ^ eccbuffer[1];
+ xor_ecc_3b = ecc[2] ^ eccbuffer[2];
+
+ xor_ecc.val = 0L;
+ xor_ecc.bytes[2] = xor_ecc_3b;
+ xor_ecc.bytes[1] = xor_ecc_2b;
+ xor_ecc.bytes[0] = xor_ecc_1b;
+
+ if (xor_ecc.val == 0U) {
+ return 0; /* No Error */
+ }
+
+ xor_ecc_ones = __builtin_popcount(xor_ecc.val);
+ if (xor_ecc_ones < 23U) {
+ if (xor_ecc_ones == 12U) {
+ uint16_t bit_address, byte_address;
+
+ /* Correctable ERROR */
+ bit_address = ((xor_ecc_1b >> 1) & BIT(0)) |
+ ((xor_ecc_1b >> 2) & BIT(1)) |
+ ((xor_ecc_1b >> 3) & BIT(2));
+
+ byte_address = ((xor_ecc_1b >> 7) & BIT(0)) |
+ ((xor_ecc_2b) & BIT(1)) |
+ ((xor_ecc_2b >> 1) & BIT(2)) |
+ ((xor_ecc_2b >> 2) & BIT(3)) |
+ ((xor_ecc_2b >> 3) & BIT(4)) |
+ ((xor_ecc_3b << 4) & BIT(5)) |
+ ((xor_ecc_3b << 3) & BIT(6)) |
+ ((xor_ecc_3b << 2) & BIT(7)) |
+ ((xor_ecc_3b << 1) & BIT(8));
+
+ /* Correct bit error in the data */
+ buffer[byte_address] =
+ buffer[byte_address] ^ BIT(bit_address);
+ VERBOSE("Hamming: 1 ECC error corrected\n");
+
+ return 0;
+ }
+
+ /* Non Correctable ERROR */
+ ERROR("%s: Uncorrectable ECC Errors\n", __func__);
+ return -1;
+ }
+
+ /* ECC ERROR */
+ ERROR("%s: Hamming correction error\n", __func__);
+ return -1;
+}
+
+
+static int stm32_fmc2_ham_calculate(uint8_t *buffer, uint8_t *ecc)
+{
+ uint32_t heccr;
+ uint64_t timeout = timeout_init_us(TIMEOUT_US_10_MS);
+
+ while ((mmio_read_32(fmc2_base() + FMC2_SR) & FMC2_SR_NWRF) == 0U) {
+ if (timeout_elapsed(timeout)) {
+ return -ETIMEDOUT;
+ }
+ }
+
+ heccr = mmio_read_32(fmc2_base() + FMC2_HECCR);
+
+ ecc[0] = heccr;
+ ecc[1] = heccr >> 8;
+ ecc[2] = heccr >> 16;
+
+ /* Disable ECC */
+ stm32_fmc2_set_ecc(false);
+
+ return 0;
+}
+
+static int stm32_fmc2_bch_correct(uint8_t *buffer, unsigned int eccsize)
+{
+ uint32_t bchdsr0, bchdsr1, bchdsr2, bchdsr3, bchdsr4;
+ uint16_t pos[8];
+ int i, den;
+ uint64_t timeout = timeout_init_us(TIMEOUT_US_10_MS);
+
+ while ((mmio_read_32(fmc2_base() + FMC2_BCHISR) &
+ FMC2_BCHISR_DERF) == 0U) {
+ if (timeout_elapsed(timeout)) {
+ return -ETIMEDOUT;
+ }
+ }
+
+ bchdsr0 = mmio_read_32(fmc2_base() + FMC2_BCHDSR0);
+ bchdsr1 = mmio_read_32(fmc2_base() + FMC2_BCHDSR1);
+ bchdsr2 = mmio_read_32(fmc2_base() + FMC2_BCHDSR2);
+ bchdsr3 = mmio_read_32(fmc2_base() + FMC2_BCHDSR3);
+ bchdsr4 = mmio_read_32(fmc2_base() + FMC2_BCHDSR4);
+
+ /* Disable ECC */
+ stm32_fmc2_set_ecc(false);
+
+ /* No error found */
+ if ((bchdsr0 & FMC2_BCHDSR0_DEF) == 0U) {
+ return 0;
+ }
+
+ /* Too many errors detected */
+ if ((bchdsr0 & FMC2_BCHDSR0_DUE) != 0U) {
+ return -EBADMSG;
+ }
+
+ pos[0] = bchdsr1 & FMC2_BCHDSR1_EBP1_MASK;
+ pos[1] = (bchdsr1 & FMC2_BCHDSR1_EBP2_MASK) >> FMC2_BCHDSR1_EBP2_SHIFT;
+ pos[2] = bchdsr2 & FMC2_BCHDSR2_EBP3_MASK;
+ pos[3] = (bchdsr2 & FMC2_BCHDSR2_EBP4_MASK) >> FMC2_BCHDSR2_EBP4_SHIFT;
+ pos[4] = bchdsr3 & FMC2_BCHDSR3_EBP5_MASK;
+ pos[5] = (bchdsr3 & FMC2_BCHDSR3_EBP6_MASK) >> FMC2_BCHDSR3_EBP6_SHIFT;
+ pos[6] = bchdsr4 & FMC2_BCHDSR4_EBP7_MASK;
+ pos[7] = (bchdsr4 & FMC2_BCHDSR4_EBP8_MASK) >> FMC2_BCHDSR4_EBP8_SHIFT;
+
+ den = (bchdsr0 & FMC2_BCHDSR0_DEN_MASK) >> FMC2_BCHDSR0_DEN_SHIFT;
+ for (i = 0; i < den; i++) {
+ if (pos[i] < (eccsize * 8U)) {
+ uint8_t bitmask = BIT(pos[i] % 8U);
+ uint32_t offset = pos[i] / 8U;
+
+ *(buffer + offset) ^= bitmask;
+ }
+ }
+
+ return 0;
+}
+
+static void stm32_fmc2_hwctl(struct nand_device *nand)
+{
+ stm32_fmc2_set_ecc(false);
+
+ if (nand->ecc.max_bit_corr != FMC2_ECC_HAM) {
+ mmio_clrbits_32(fmc2_base() + FMC2_PCR, FMC2_PCR_WEN);
+ }
+
+ stm32_fmc2_set_ecc(true);
+}
+
+static int stm32_fmc2_read_page(struct nand_device *nand,
+ unsigned int page, uintptr_t buffer)
+{
+ unsigned int eccsize = nand->ecc.size;
+ unsigned int eccbytes = nand->ecc.bytes;
+ unsigned int eccsteps = nand->page_size / eccsize;
+ uint8_t ecc_corr[FMC2_MAX_ECC_BYTES];
+ uint8_t ecc_cal[FMC2_MAX_ECC_BYTES] = {0U};
+ uint8_t *p;
+ unsigned int i;
+ unsigned int s;
+ int ret;
+
+ VERBOSE(">%s page %i buffer %lx\n", __func__, page, buffer);
+
+ ret = nand_read_page_cmd(page, 0U, 0U, 0U);
+ if (ret != 0) {
+ return ret;
+ }
+
+ for (s = 0U, i = nand->page_size + FMC2_BBM_LEN, p = (uint8_t *)buffer;
+ s < eccsteps;
+ s++, i += eccbytes, p += eccsize) {
+ stm32_fmc2_hwctl(nand);
+
+ /* Read the NAND page sector (512 bytes) */
+ ret = nand_change_read_column_cmd(s * eccsize, (uintptr_t)p,
+ eccsize);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (nand->ecc.max_bit_corr == FMC2_ECC_HAM) {
+ ret = stm32_fmc2_ham_calculate(p, ecc_cal);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ /* Read the corresponding ECC bytes */
+ ret = nand_change_read_column_cmd(i, (uintptr_t)ecc_corr,
+ eccbytes);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* Correct the data */
+ if (nand->ecc.max_bit_corr == FMC2_ECC_HAM) {
+ ret = stm32_fmc2_ham_correct(p, ecc_corr, ecc_cal);
+ } else {
+ ret = stm32_fmc2_bch_correct(p, eccsize);
+ }
+
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static void stm32_fmc2_read_data(struct nand_device *nand,
+ uint8_t *buff, unsigned int length,
+ bool use_bus8)
+{
+ uintptr_t data_base = stm32_fmc2.cs[stm32_fmc2.cs_sel].data_base;
+
+ if (use_bus8 && (nand->buswidth == NAND_BUS_WIDTH_16)) {
+ stm32_fmc2_set_buswidth_16(false);
+ }
+
+ if ((((uintptr_t)buff & BIT(0)) != 0U) && (length != 0U)) {
+ *buff = mmio_read_8(data_base);
+ buff += sizeof(uint8_t);
+ length -= sizeof(uint8_t);
+ }
+
+ if ((((uintptr_t)buff & GENMASK_32(1, 0)) != 0U) &&
+ (length >= sizeof(uint16_t))) {
+ *(uint16_t *)buff = mmio_read_16(data_base);
+ buff += sizeof(uint16_t);
+ length -= sizeof(uint16_t);
+ }
+
+ /* 32bit aligned */
+ while (length >= sizeof(uint32_t)) {
+ *(uint32_t *)buff = mmio_read_32(data_base);
+ buff += sizeof(uint32_t);
+ length -= sizeof(uint32_t);
+ }
+
+ /* Read remaining bytes */
+ if (length >= sizeof(uint16_t)) {
+ *(uint16_t *)buff = mmio_read_16(data_base);
+ buff += sizeof(uint16_t);
+ length -= sizeof(uint16_t);
+ }
+
+ if (length != 0U) {
+ *buff = mmio_read_8(data_base);
+ }
+
+ if (use_bus8 && (nand->buswidth == NAND_BUS_WIDTH_16)) {
+ /* Reconfigure bus width to 16-bit */
+ stm32_fmc2_set_buswidth_16(true);
+ }
+}
+
+static void stm32_fmc2_write_data(struct nand_device *nand,
+ uint8_t *buff, unsigned int length,
+ bool use_bus8)
+{
+ uintptr_t data_base = stm32_fmc2.cs[stm32_fmc2.cs_sel].data_base;
+
+ if (use_bus8 && (nand->buswidth == NAND_BUS_WIDTH_16)) {
+ /* Reconfigure bus width to 8-bit */
+ stm32_fmc2_set_buswidth_16(false);
+ }
+
+ if ((((uintptr_t)buff & BIT(0)) != 0U) && (length != 0U)) {
+ mmio_write_8(data_base, *buff);
+ buff += sizeof(uint8_t);
+ length -= sizeof(uint8_t);
+ }
+
+ if ((((uintptr_t)buff & GENMASK_32(1, 0)) != 0U) &&
+ (length >= sizeof(uint16_t))) {
+ mmio_write_16(data_base, *(uint16_t *)buff);
+ buff += sizeof(uint16_t);
+ length -= sizeof(uint16_t);
+ }
+
+ /* 32bits aligned */
+ while (length >= sizeof(uint32_t)) {
+ mmio_write_32(data_base, *(uint32_t *)buff);
+ buff += sizeof(uint32_t);
+ length -= sizeof(uint32_t);
+ }
+
+ /* Read remaining bytes */
+ if (length >= sizeof(uint16_t)) {
+ mmio_write_16(data_base, *(uint16_t *)buff);
+ buff += sizeof(uint16_t);
+ length -= sizeof(uint16_t);
+ }
+
+ if (length != 0U) {
+ mmio_write_8(data_base, *buff);
+ }
+
+ if (use_bus8 && (nand->buswidth == NAND_BUS_WIDTH_16)) {
+ /* Reconfigure bus width to 16-bit */
+ stm32_fmc2_set_buswidth_16(true);
+ }
+}
+
+static void stm32_fmc2_ctrl_init(void)
+{
+ uint32_t pcr = mmio_read_32(fmc2_base() + FMC2_PCR);
+ uint32_t bcr1 = mmio_read_32(fmc2_base() + FMC2_BCR1);
+
+ /* Enable wait feature and NAND flash memory bank */
+ pcr |= FMC2_PCR_PWAITEN;
+ pcr |= FMC2_PCR_PBKEN;
+
+ /* Set buswidth to 8 bits mode for identification */
+ pcr &= ~FMC2_PCR_PWID_MASK;
+
+ /* ECC logic is disabled */
+ pcr &= ~FMC2_PCR_ECCEN;
+
+ /* Default mode */
+ pcr &= ~FMC2_PCR_ECCALG;
+ pcr &= ~FMC2_PCR_BCHECC;
+ pcr &= ~FMC2_PCR_WEN;
+
+ /* Set default ECC sector size */
+ pcr &= ~FMC2_PCR_ECCSS_MASK;
+ pcr |= FMC2_PCR_ECCSS(FMC2_PCR_ECCSS_2048);
+
+ /* Set default TCLR/TAR timings */
+ pcr &= ~FMC2_PCR_TCLR_MASK;
+ pcr |= FMC2_PCR_TCLR(FMC2_PCR_TCLR_DEFAULT);
+ pcr &= ~FMC2_PCR_TAR_MASK;
+ pcr |= FMC2_PCR_TAR(FMC2_PCR_TAR_DEFAULT);
+
+ /* Enable FMC2 controller */
+ bcr1 |= FMC2_BCR1_FMC2EN;
+
+ mmio_write_32(fmc2_base() + FMC2_BCR1, bcr1);
+ mmio_write_32(fmc2_base() + FMC2_PCR, pcr);
+ mmio_write_32(fmc2_base() + FMC2_PMEM, FMC2_PMEM_DEFAULT);
+ mmio_write_32(fmc2_base() + FMC2_PATT, FMC2_PATT_DEFAULT);
+}
+
+static int stm32_fmc2_exec(struct nand_req *req)
+{
+ int ret = 0;
+
+ switch (req->type & NAND_REQ_MASK) {
+ case NAND_REQ_CMD:
+ VERBOSE("Write CMD %x\n", (uint8_t)req->type);
+ mmio_write_8(stm32_fmc2.cs[stm32_fmc2.cs_sel].cmd_base,
+ (uint8_t)req->type);
+ break;
+ case NAND_REQ_ADDR:
+ VERBOSE("Write ADDR %x\n", *(req->addr));
+ mmio_write_8(stm32_fmc2.cs[stm32_fmc2.cs_sel].addr_base,
+ *(req->addr));
+ break;
+ case NAND_REQ_DATAIN:
+ VERBOSE("Read data\n");
+ stm32_fmc2_read_data(req->nand, req->addr, req->length,
+ ((req->type & NAND_REQ_BUS_WIDTH_8) !=
+ 0U));
+ break;
+ case NAND_REQ_DATAOUT:
+ VERBOSE("Write data\n");
+ stm32_fmc2_write_data(req->nand, req->addr, req->length,
+ ((req->type & NAND_REQ_BUS_WIDTH_8) !=
+ 0U));
+ break;
+ case NAND_REQ_WAIT:
+ VERBOSE("WAIT Ready\n");
+ ret = nand_wait_ready(req->delay_ms);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ };
+
+ return ret;
+}
+
+static void stm32_fmc2_setup(struct nand_device *nand)
+{
+ uint32_t pcr = mmio_read_32(fmc2_base() + FMC2_PCR);
+
+ /* Set buswidth */
+ pcr &= ~FMC2_PCR_PWID_MASK;
+ if (nand->buswidth == NAND_BUS_WIDTH_16) {
+ pcr |= FMC2_PCR_PWID(FMC2_PCR_PWID_16);
+ }
+
+ if (nand->ecc.mode == NAND_ECC_HW) {
+ nand->mtd_read_page = stm32_fmc2_read_page;
+
+ pcr &= ~FMC2_PCR_ECCALG;
+ pcr &= ~FMC2_PCR_BCHECC;
+
+ pcr &= ~FMC2_PCR_ECCSS_MASK;
+ pcr |= FMC2_PCR_ECCSS(FMC2_PCR_ECCSS_512);
+
+ switch (nand->ecc.max_bit_corr) {
+ case FMC2_ECC_HAM:
+ nand->ecc.bytes = 3;
+ break;
+ case FMC2_ECC_BCH8:
+ pcr |= FMC2_PCR_ECCALG;
+ pcr |= FMC2_PCR_BCHECC;
+ nand->ecc.bytes = 13;
+ break;
+ default:
+ /* Use FMC2 ECC BCH4 */
+ pcr |= FMC2_PCR_ECCALG;
+ nand->ecc.bytes = 7;
+ break;
+ }
+
+ if ((nand->buswidth & NAND_BUS_WIDTH_16) != 0) {
+ nand->ecc.bytes++;
+ }
+ }
+
+ mmio_write_32(stm32_fmc2.reg_base + FMC2_PCR, pcr);
+}
+
+static const struct nand_ctrl_ops ctrl_ops = {
+ .setup = stm32_fmc2_setup,
+ .exec = stm32_fmc2_exec
+};
+
+int stm32_fmc2_init(void)
+{
+ int fmc_node;
+ int fmc_subnode = 0;
+ int nchips = 0;
+ unsigned int i;
+ void *fdt = NULL;
+ const fdt32_t *cuint;
+ struct dt_node_info info;
+
+ if (fdt_get_address(&fdt) == 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ fmc_node = dt_get_node(&info, -1, DT_FMC2_COMPAT);
+ if (fmc_node == -FDT_ERR_NOTFOUND) {
+ WARN("No FMC2 node found\n");
+ return fmc_node;
+ }
+
+ if (info.status == DT_DISABLED) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ stm32_fmc2.reg_base = info.base;
+
+ if ((info.clock < 0) || (info.reset < 0)) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ stm32_fmc2.clock_id = (unsigned long)info.clock;
+ stm32_fmc2.reset_id = (unsigned int)info.reset;
+
+ cuint = fdt_getprop(fdt, fmc_node, "reg", NULL);
+ if (cuint == NULL) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ cuint += 2;
+
+ for (i = 0U; i < MAX_CS; i++) {
+ stm32_fmc2.cs[i].data_base = fdt32_to_cpu(*cuint);
+ stm32_fmc2.cs[i].cmd_base = fdt32_to_cpu(*(cuint + 2));
+ stm32_fmc2.cs[i].addr_base = fdt32_to_cpu(*(cuint + 4));
+ cuint += 6;
+ }
+
+ /* Pinctrl initialization */
+ if (dt_set_pinctrl_config(fmc_node) != 0) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ /* Parse flash nodes */
+ fdt_for_each_subnode(fmc_subnode, fdt, fmc_node) {
+ nchips++;
+ }
+
+ if (nchips != 1) {
+ WARN("Only one SLC NAND device supported\n");
+ return -FDT_ERR_BADVALUE;
+ }
+
+ fdt_for_each_subnode(fmc_subnode, fdt, fmc_node) {
+ /* Get chip select */
+ cuint = fdt_getprop(fdt, fmc_subnode, "reg", NULL);
+ if (cuint == NULL) {
+ WARN("Chip select not well defined\n");
+ return -FDT_ERR_BADVALUE;
+ }
+ stm32_fmc2.cs_sel = fdt32_to_cpu(*cuint);
+ VERBOSE("NAND CS %i\n", stm32_fmc2.cs_sel);
+ }
+
+ /* Enable Clock */
+ stm32mp_clk_enable(stm32_fmc2.clock_id);
+
+ /* Reset IP */
+ stm32mp_reset_assert(stm32_fmc2.reset_id);
+ stm32mp_reset_deassert(stm32_fmc2.reset_id);
+
+ /* 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/io/io_mmc.c b/drivers/st/io/io_mmc.c
index a239b5f3ad..44b7d19074 100644
--- a/drivers/st/io/io_mmc.c
+++ b/drivers/st/io/io_mmc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -20,14 +20,15 @@ static int mmc_dev_open(const uintptr_t init_params, io_dev_info_t **dev_info);
static int mmc_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
io_entity_t *entity);
static int mmc_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params);
-static int mmc_block_seek(io_entity_t *entity, int mode, ssize_t offset);
+static int mmc_block_seek(io_entity_t *entity, int mode,
+ signed long long offset);
static int mmc_block_read(io_entity_t *entity, uintptr_t buffer, size_t length,
size_t *length_read);
static int mmc_block_close(io_entity_t *entity);
static int mmc_dev_close(io_dev_info_t *dev_info);
static io_type_t device_type_mmc(void);
-static ssize_t seek_offset;
+static signed long long seek_offset;
static const io_dev_connector_t mmc_dev_connector = {
.dev_open = mmc_dev_open
@@ -85,7 +86,8 @@ static int mmc_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
}
/* Seek to a particular file offset on the mmc device */
-static int mmc_block_seek(io_entity_t *entity, int mode, ssize_t offset)
+static int mmc_block_seek(io_entity_t *entity, int mode,
+ signed long long offset)
{
seek_offset = offset;
return 0;
diff --git a/drivers/st/spi/stm32_qspi.c b/drivers/st/spi/stm32_qspi.c
new file mode 100644
index 0000000000..188d2ff806
--- /dev/null
+++ b/drivers/st/spi/stm32_qspi.c
@@ -0,0 +1,500 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+ */
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/spi_mem.h>
+#include <drivers/st/stm32_gpio.h>
+#include <drivers/st/stm32mp_reset.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+/* QUADSPI registers */
+#define QSPI_CR 0x00U
+#define QSPI_DCR 0x04U
+#define QSPI_SR 0x08U
+#define QSPI_FCR 0x0CU
+#define QSPI_DLR 0x10U
+#define QSPI_CCR 0x14U
+#define QSPI_AR 0x18U
+#define QSPI_ABR 0x1CU
+#define QSPI_DR 0x20U
+#define QSPI_PSMKR 0x24U
+#define QSPI_PSMAR 0x28U
+#define QSPI_PIR 0x2CU
+#define QSPI_LPTR 0x30U
+
+/* QUADSPI control register */
+#define QSPI_CR_EN BIT(0)
+#define QSPI_CR_ABORT BIT(1)
+#define QSPI_CR_DMAEN BIT(2)
+#define QSPI_CR_TCEN BIT(3)
+#define QSPI_CR_SSHIFT BIT(4)
+#define QSPI_CR_DFM BIT(6)
+#define QSPI_CR_FSEL BIT(7)
+#define QSPI_CR_FTHRES_SHIFT 8U
+#define QSPI_CR_TEIE BIT(16)
+#define QSPI_CR_TCIE BIT(17)
+#define QSPI_CR_FTIE BIT(18)
+#define QSPI_CR_SMIE BIT(19)
+#define QSPI_CR_TOIE BIT(20)
+#define QSPI_CR_APMS BIT(22)
+#define QSPI_CR_PMM BIT(23)
+#define QSPI_CR_PRESCALER_MASK GENMASK_32(31, 24)
+#define QSPI_CR_PRESCALER_SHIFT 24U
+
+/* QUADSPI device configuration register */
+#define QSPI_DCR_CKMODE BIT(0)
+#define QSPI_DCR_CSHT_MASK GENMASK_32(10, 8)
+#define QSPI_DCR_CSHT_SHIFT 8U
+#define QSPI_DCR_FSIZE_MASK GENMASK_32(20, 16)
+#define QSPI_DCR_FSIZE_SHIFT 16U
+
+/* QUADSPI status register */
+#define QSPI_SR_TEF BIT(0)
+#define QSPI_SR_TCF BIT(1)
+#define QSPI_SR_FTF BIT(2)
+#define QSPI_SR_SMF BIT(3)
+#define QSPI_SR_TOF BIT(4)
+#define QSPI_SR_BUSY BIT(5)
+
+/* QUADSPI flag clear register */
+#define QSPI_FCR_CTEF BIT(0)
+#define QSPI_FCR_CTCF BIT(1)
+#define QSPI_FCR_CSMF BIT(3)
+#define QSPI_FCR_CTOF BIT(4)
+
+/* QUADSPI communication configuration register */
+#define QSPI_CCR_DDRM BIT(31)
+#define QSPI_CCR_DHHC BIT(30)
+#define QSPI_CCR_SIOO BIT(28)
+#define QSPI_CCR_FMODE_SHIFT 26U
+#define QSPI_CCR_DMODE_SHIFT 24U
+#define QSPI_CCR_DCYC_SHIFT 18U
+#define QSPI_CCR_ABSIZE_SHIFT 16U
+#define QSPI_CCR_ABMODE_SHIFT 14U
+#define QSPI_CCR_ADSIZE_SHIFT 12U
+#define QSPI_CCR_ADMODE_SHIFT 10U
+#define QSPI_CCR_IMODE_SHIFT 8U
+#define QSPI_CCR_IND_WRITE 0U
+#define QSPI_CCR_IND_READ 1U
+#define QSPI_CCR_MEM_MAP 3U
+
+#define QSPI_MAX_CHIP 2U
+
+#define QSPI_FIFO_TIMEOUT_US 30U
+#define QSPI_CMD_TIMEOUT_US 1000U
+#define QSPI_BUSY_TIMEOUT_US 100U
+#define QSPI_ABT_TIMEOUT_US 100U
+
+#define DT_QSPI_COMPAT "st,stm32f469-qspi"
+
+#define FREQ_100MHZ 100000000U
+
+struct stm32_qspi_ctrl {
+ uintptr_t reg_base;
+ uintptr_t mm_base;
+ size_t mm_size;
+ unsigned long clock_id;
+ unsigned int reset_id;
+};
+
+static struct stm32_qspi_ctrl stm32_qspi;
+
+static uintptr_t qspi_base(void)
+{
+ return stm32_qspi.reg_base;
+}
+
+static int stm32_qspi_wait_for_not_busy(void)
+{
+ uint64_t timeout = timeout_init_us(QSPI_BUSY_TIMEOUT_US);
+
+ while ((mmio_read_32(qspi_base() + QSPI_SR) & QSPI_SR_BUSY) != 0U) {
+ if (timeout_elapsed(timeout)) {
+ ERROR("%s: busy timeout\n", __func__);
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+static int stm32_qspi_wait_cmd(const struct spi_mem_op *op)
+{
+ int ret = 0;
+ uint64_t timeout;
+
+ if (op->data.nbytes == 0U) {
+ return stm32_qspi_wait_for_not_busy();
+ }
+
+ timeout = timeout_init_us(QSPI_CMD_TIMEOUT_US);
+ while ((mmio_read_32(qspi_base() + QSPI_SR) & QSPI_SR_TCF) == 0U) {
+ if (timeout_elapsed(timeout)) {
+ ret = -ETIMEDOUT;
+ break;
+ }
+ }
+
+ if (ret == 0) {
+ if ((mmio_read_32(qspi_base() + QSPI_SR) & QSPI_SR_TEF) != 0U) {
+ ERROR("%s: transfer error\n", __func__);
+ ret = -EIO;
+ }
+ } else {
+ ERROR("%s: cmd timeout\n", __func__);
+ }
+
+ /* Clear flags */
+ mmio_write_32(qspi_base() + QSPI_FCR, QSPI_FCR_CTCF | QSPI_FCR_CTEF);
+
+ return ret;
+}
+
+static void stm32_qspi_read_fifo(uint8_t *val, uintptr_t addr)
+{
+ *val = mmio_read_8(addr);
+}
+
+static void stm32_qspi_write_fifo(uint8_t *val, uintptr_t addr)
+{
+ mmio_write_8(addr, *val);
+}
+
+static int stm32_qspi_poll(const struct spi_mem_op *op)
+{
+ void (*fifo)(uint8_t *val, uintptr_t addr);
+ uint32_t len = op->data.nbytes;
+ uint8_t *buf;
+ uint64_t timeout;
+
+ 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--) {
+ timeout = timeout_init_us(QSPI_FIFO_TIMEOUT_US);
+ while ((mmio_read_32(qspi_base() + QSPI_SR) &
+ QSPI_SR_FTF) == 0U) {
+ if (timeout_elapsed(timeout)) {
+ ERROR("%s: fifo timeout\n", __func__);
+ return -ETIMEDOUT;
+ }
+ }
+
+ fifo(buf++, qspi_base() + QSPI_DR);
+ }
+
+ return 0;
+}
+
+static int stm32_qspi_mm(const struct spi_mem_op *op)
+{
+ memcpy(op->data.buf,
+ (void *)(stm32_qspi.mm_base + (size_t)op->addr.val),
+ op->data.nbytes);
+
+ return 0;
+}
+
+static int stm32_qspi_tx(const struct spi_mem_op *op, uint8_t mode)
+{
+ if (op->data.nbytes == 0U) {
+ return 0;
+ }
+
+ if (mode == QSPI_CCR_MEM_MAP) {
+ return stm32_qspi_mm(op);
+ }
+
+ return stm32_qspi_poll(op);
+}
+
+static unsigned int stm32_qspi_get_mode(uint8_t buswidth)
+{
+ if (buswidth == 4U) {
+ return 3U;
+ }
+
+ return buswidth;
+}
+
+static int stm32_qspi_exec_op(const struct spi_mem_op *op)
+{
+ uint64_t timeout;
+ uint32_t ccr;
+ size_t addr_max;
+ uint8_t mode = QSPI_CCR_IND_WRITE;
+ int ret;
+
+ VERBOSE("%s: cmd:%x mode:%d.%d.%d.%d addr:%llx len:%x\n",
+ __func__, op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,
+ op->dummy.buswidth, op->data.buswidth,
+ op->addr.val, op->data.nbytes);
+
+ ret = stm32_qspi_wait_for_not_busy();
+ if (ret != 0) {
+ return ret;
+ }
+
+ addr_max = op->addr.val + op->data.nbytes + 1U;
+
+ if ((op->data.dir == SPI_MEM_DATA_IN) && (op->data.nbytes != 0U)) {
+ if ((addr_max < stm32_qspi.mm_size) &&
+ (op->addr.buswidth != 0U)) {
+ mode = QSPI_CCR_MEM_MAP;
+ } else {
+ mode = QSPI_CCR_IND_READ;
+ }
+ }
+
+ if (op->data.nbytes != 0U) {
+ mmio_write_32(qspi_base() + QSPI_DLR, op->data.nbytes - 1U);
+ }
+
+ ccr = mode << QSPI_CCR_FMODE_SHIFT;
+ ccr |= op->cmd.opcode;
+ ccr |= stm32_qspi_get_mode(op->cmd.buswidth) << QSPI_CCR_IMODE_SHIFT;
+
+ if (op->addr.nbytes != 0U) {
+ ccr |= (op->addr.nbytes - 1U) << QSPI_CCR_ADSIZE_SHIFT;
+ ccr |= stm32_qspi_get_mode(op->addr.buswidth) <<
+ QSPI_CCR_ADMODE_SHIFT;
+ }
+
+ if ((op->dummy.buswidth != 0U) && (op->dummy.nbytes != 0U)) {
+ ccr |= (op->dummy.nbytes * 8U / op->dummy.buswidth) <<
+ QSPI_CCR_DCYC_SHIFT;
+ }
+
+ if (op->data.nbytes != 0U) {
+ ccr |= stm32_qspi_get_mode(op->data.buswidth) <<
+ QSPI_CCR_DMODE_SHIFT;
+ }
+
+ mmio_write_32(qspi_base() + QSPI_CCR, ccr);
+
+ if ((op->addr.nbytes != 0U) && (mode != QSPI_CCR_MEM_MAP)) {
+ mmio_write_32(qspi_base() + QSPI_AR, op->addr.val);
+ }
+
+ ret = stm32_qspi_tx(op, mode);
+
+ /*
+ * Abort in:
+ * - Error case.
+ * - Memory mapped read: prefetching must be stopped if we read the last
+ * byte of device (device size - fifo size). If device size is not
+ * known then prefetching is always stopped.
+ */
+ if ((ret != 0) || (mode == QSPI_CCR_MEM_MAP)) {
+ goto abort;
+ }
+
+ /* Wait end of TX in indirect mode */
+ ret = stm32_qspi_wait_cmd(op);
+ if (ret != 0) {
+ goto abort;
+ }
+
+ return 0;
+
+abort:
+ mmio_setbits_32(qspi_base() + QSPI_CR, QSPI_CR_ABORT);
+
+ /* Wait clear of abort bit by hardware */
+ timeout = timeout_init_us(QSPI_ABT_TIMEOUT_US);
+ while ((mmio_read_32(qspi_base() + QSPI_CR) & QSPI_CR_ABORT) != 0U) {
+ if (timeout_elapsed(timeout)) {
+ ret = -ETIMEDOUT;
+ break;
+ }
+ }
+
+ mmio_write_32(qspi_base() + QSPI_FCR, QSPI_FCR_CTCF);
+
+ if (ret != 0) {
+ ERROR("%s: exec op error\n", __func__);
+ }
+
+ return ret;
+}
+
+static int stm32_qspi_claim_bus(unsigned int cs)
+{
+ uint32_t cr;
+
+ if (cs >= QSPI_MAX_CHIP) {
+ return -ENODEV;
+ }
+
+ /* Set chip select and enable the controller */
+ cr = QSPI_CR_EN;
+ if (cs == 1U) {
+ cr |= QSPI_CR_FSEL;
+ }
+
+ mmio_clrsetbits_32(qspi_base() + QSPI_CR, QSPI_CR_FSEL, cr);
+
+ return 0;
+}
+
+static void stm32_qspi_release_bus(void)
+{
+ mmio_clrbits_32(qspi_base() + QSPI_CR, QSPI_CR_EN);
+}
+
+static int stm32_qspi_set_speed(unsigned int hz)
+{
+ unsigned long qspi_clk = stm32mp_clk_get_rate(stm32_qspi.clock_id);
+ uint32_t prescaler = UINT8_MAX;
+ uint32_t csht;
+ int ret;
+
+ if (qspi_clk == 0U) {
+ return -EINVAL;
+ }
+
+ if (hz > 0U) {
+ prescaler = div_round_up(qspi_clk, hz) - 1U;
+ if (prescaler > UINT8_MAX) {
+ prescaler = UINT8_MAX;
+ }
+ }
+
+ csht = div_round_up((5U * qspi_clk) / (prescaler + 1U), FREQ_100MHZ);
+ csht = ((csht - 1U) << QSPI_DCR_CSHT_SHIFT) & QSPI_DCR_CSHT_MASK;
+
+ ret = stm32_qspi_wait_for_not_busy();
+ if (ret != 0) {
+ return ret;
+ }
+
+ mmio_clrsetbits_32(qspi_base() + QSPI_CR, QSPI_CR_PRESCALER_MASK,
+ prescaler << QSPI_CR_PRESCALER_SHIFT);
+
+ mmio_clrsetbits_32(qspi_base() + QSPI_DCR, QSPI_DCR_CSHT_MASK, csht);
+
+ VERBOSE("%s: speed=%lu\n", __func__, qspi_clk / (prescaler + 1U));
+
+ return 0;
+}
+
+static int stm32_qspi_set_mode(unsigned int mode)
+{
+ int ret;
+
+ ret = stm32_qspi_wait_for_not_busy();
+ if (ret != 0) {
+ return ret;
+ }
+
+ if ((mode & SPI_CS_HIGH) != 0U) {
+ return -ENODEV;
+ }
+
+ if (((mode & SPI_CPHA) != 0U) && ((mode & SPI_CPOL) != 0U)) {
+ mmio_setbits_32(qspi_base() + QSPI_DCR, QSPI_DCR_CKMODE);
+ } else if (((mode & SPI_CPHA) == 0U) && ((mode & SPI_CPOL) == 0U)) {
+ mmio_clrbits_32(qspi_base() + QSPI_DCR, QSPI_DCR_CKMODE);
+ } else {
+ return -ENODEV;
+ }
+
+ VERBOSE("%s: mode=0x%x\n", __func__, mode);
+
+ if ((mode & SPI_RX_QUAD) != 0U) {
+ VERBOSE("rx: quad\n");
+ } else if ((mode & SPI_RX_DUAL) != 0U) {
+ VERBOSE("rx: dual\n");
+ } else {
+ VERBOSE("rx: single\n");
+ }
+
+ if ((mode & SPI_TX_QUAD) != 0U) {
+ VERBOSE("tx: quad\n");
+ } else if ((mode & SPI_TX_DUAL) != 0U) {
+ VERBOSE("tx: dual\n");
+ } else {
+ VERBOSE("tx: single\n");
+ }
+
+ return 0;
+}
+
+static const struct spi_bus_ops stm32_qspi_bus_ops = {
+ .claim_bus = stm32_qspi_claim_bus,
+ .release_bus = stm32_qspi_release_bus,
+ .set_speed = stm32_qspi_set_speed,
+ .set_mode = stm32_qspi_set_mode,
+ .exec_op = stm32_qspi_exec_op,
+};
+
+int stm32_qspi_init(void)
+{
+ size_t size;
+ int qspi_node;
+ struct dt_node_info info;
+ void *fdt = NULL;
+ int ret;
+
+ if (fdt_get_address(&fdt) == 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ qspi_node = dt_get_node(&info, -1, DT_QSPI_COMPAT);
+ if (qspi_node < 0) {
+ ERROR("No QSPI ctrl found\n");
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ if (info.status == DT_DISABLED) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ ret = fdt_get_reg_props_by_name(qspi_node, "qspi",
+ &stm32_qspi.reg_base, &size);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = fdt_get_reg_props_by_name(qspi_node, "qspi_mm",
+ &stm32_qspi.mm_base,
+ &stm32_qspi.mm_size);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (dt_set_pinctrl_config(qspi_node) != 0) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ if ((info.clock < 0) || (info.reset < 0)) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ stm32_qspi.clock_id = (unsigned long)info.clock;
+ stm32_qspi.reset_id = (unsigned int)info.reset;
+
+ stm32mp_clk_enable(stm32_qspi.clock_id);
+
+ stm32mp_reset_assert(stm32_qspi.reset_id);
+ stm32mp_reset_deassert(stm32_qspi.reset_id);
+
+ 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/fdts/fvp-base-gicv2-psci-aarch32.dts b/fdts/fvp-base-gicv2-psci-aarch32.dts
index 87ac68d67c..e71a39519d 100644
--- a/fdts/fvp-base-gicv2-psci-aarch32.dts
+++ b/fdts/fvp-base-gicv2-psci-aarch32.dts
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -279,7 +279,7 @@
<0 0 41 &gic 0 41 4>,
<0 0 42 &gic 0 42 4>;
- /include/ "rtsm_ve-motherboard-aarch32.dtsi"
+ #include "rtsm_ve-motherboard-aarch32.dtsi"
};
panels {
diff --git a/fdts/fvp-base-gicv2-psci.dts b/fdts/fvp-base-gicv2-psci.dts
index 941040d8e7..c9c9d95947 100644
--- a/fdts/fvp-base-gicv2-psci.dts
+++ b/fdts/fvp-base-gicv2-psci.dts
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -233,7 +233,7 @@
<4 0 0 0x0c000000 0x04000000>,
<5 0 0 0x10000000 0x04000000>;
- /include/ "rtsm_ve-motherboard.dtsi"
+ #include "rtsm_ve-motherboard.dtsi"
};
panels {
diff --git a/fdts/fvp-base-gicv3-psci-1t.dts b/fdts/fvp-base-gicv3-psci-1t.dts
index 36fbd44442..3c82f7b138 100644
--- a/fdts/fvp-base-gicv3-psci-1t.dts
+++ b/fdts/fvp-base-gicv3-psci-1t.dts
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/dts-v1/;
-/include/ "fvp-base-gicv3-psci-common.dtsi"
+#include "fvp-base-gicv3-psci-common.dtsi"
&CPU0 {
reg = <0x0 0x0>;
diff --git a/fdts/fvp-base-gicv3-psci-aarch32-1t.dts b/fdts/fvp-base-gicv3-psci-aarch32-1t.dts
index f7c936210f..d1d33485c9 100644
--- a/fdts/fvp-base-gicv3-psci-aarch32-1t.dts
+++ b/fdts/fvp-base-gicv3-psci-aarch32-1t.dts
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2019, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/dts-v1/;
-/include/ "fvp-base-gicv3-psci-aarch32-common.dtsi"
+#include "fvp-base-gicv3-psci-aarch32-common.dtsi"
&CPU0 {
reg = <0x0>;
diff --git a/fdts/fvp-base-gicv3-psci-aarch32-common.dtsi b/fdts/fvp-base-gicv3-psci-aarch32-common.dtsi
index 6179c66e7d..f9809db8bd 100644
--- a/fdts/fvp-base-gicv3-psci-aarch32-common.dtsi
+++ b/fdts/fvp-base-gicv3-psci-aarch32-common.dtsi
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -286,7 +286,7 @@
<0 0 41 &gic 0 0 0 41 4>,
<0 0 42 &gic 0 0 0 42 4>;
- /include/ "rtsm_ve-motherboard-aarch32.dtsi"
+ #include "rtsm_ve-motherboard-aarch32.dtsi"
};
panels {
diff --git a/fdts/fvp-base-gicv3-psci-aarch32.dts b/fdts/fvp-base-gicv3-psci-aarch32.dts
index 2833cdfaca..513014b324 100644
--- a/fdts/fvp-base-gicv3-psci-aarch32.dts
+++ b/fdts/fvp-base-gicv3-psci-aarch32.dts
@@ -1,9 +1,9 @@
/*
- * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/dts-v1/;
-/include/ "fvp-base-gicv3-psci-aarch32-common.dtsi"
+#include "fvp-base-gicv3-psci-aarch32-common.dtsi"
diff --git a/fdts/fvp-base-gicv3-psci-common.dtsi b/fdts/fvp-base-gicv3-psci-common.dtsi
index 631c4e3453..94ed67d558 100644
--- a/fdts/fvp-base-gicv3-psci-common.dtsi
+++ b/fdts/fvp-base-gicv3-psci-common.dtsi
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -240,7 +240,7 @@
<4 0 0 0x0c000000 0x04000000>,
<5 0 0 0x10000000 0x04000000>;
- /include/ "rtsm_ve-motherboard.dtsi"
+ #include "rtsm_ve-motherboard.dtsi"
};
panels {
diff --git a/fdts/fvp-base-gicv3-psci-dynamiq-2t.dts b/fdts/fvp-base-gicv3-psci-dynamiq-2t.dts
index f35eaf4822..48269a0655 100644
--- a/fdts/fvp-base-gicv3-psci-dynamiq-2t.dts
+++ b/fdts/fvp-base-gicv3-psci-dynamiq-2t.dts
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2019, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/dts-v1/;
-/include/ "fvp-base-gicv3-psci-common.dtsi"
+#include "fvp-base-gicv3-psci-common.dtsi"
&CPU0 {
reg = <0x0 0x0>;
diff --git a/fdts/fvp-base-gicv3-psci-dynamiq.dts b/fdts/fvp-base-gicv3-psci-dynamiq.dts
index 614c5d5c01..51c7acacf0 100644
--- a/fdts/fvp-base-gicv3-psci-dynamiq.dts
+++ b/fdts/fvp-base-gicv3-psci-dynamiq.dts
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/dts-v1/;
-/include/ "fvp-base-gicv3-psci-common.dtsi"
+#include "fvp-base-gicv3-psci-common.dtsi"
&CPU0 {
reg = <0x0 0x0>;
diff --git a/fdts/fvp-base-gicv3-psci.dts b/fdts/fvp-base-gicv3-psci.dts
index 3ea429ce97..65fa4b0d94 100644
--- a/fdts/fvp-base-gicv3-psci.dts
+++ b/fdts/fvp-base-gicv3-psci.dts
@@ -1,9 +1,9 @@
/*
- * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/dts-v1/;
-/include/ "fvp-base-gicv3-psci-common.dtsi"
+#include "fvp-base-gicv3-psci-common.dtsi"
diff --git a/fdts/fvp-foundation-gicv2-psci.dts b/fdts/fvp-foundation-gicv2-psci.dts
index 03b61dd73b..b6da905492 100644
--- a/fdts/fvp-foundation-gicv2-psci.dts
+++ b/fdts/fvp-foundation-gicv2-psci.dts
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -182,6 +182,6 @@
<4 0 0 0x0c000000 0x04000000>,
<5 0 0 0x10000000 0x04000000>;
- /include/ "fvp-foundation-motherboard.dtsi"
+ #include "fvp-foundation-motherboard.dtsi"
};
};
diff --git a/fdts/fvp-foundation-gicv3-psci.dts b/fdts/fvp-foundation-gicv3-psci.dts
index 1488ed7f75..81071e255b 100644
--- a/fdts/fvp-foundation-gicv3-psci.dts
+++ b/fdts/fvp-foundation-gicv3-psci.dts
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -191,6 +191,6 @@
<4 0 0 0x0c000000 0x04000000>,
<5 0 0 0x10000000 0x04000000>;
- /include/ "fvp-foundation-motherboard.dtsi"
+ #include "fvp-foundation-motherboard.dtsi"
};
};
diff --git a/fdts/fvp-ve-Cortex-A5x1.dts b/fdts/fvp-ve-Cortex-A5x1.dts
index 0f766016d7..9d2d1d552d 100644
--- a/fdts/fvp-ve-Cortex-A5x1.dts
+++ b/fdts/fvp-ve-Cortex-A5x1.dts
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -139,6 +139,6 @@
<0 0 5 &gic 0 5 4>,
<0 0 42 &gic 0 42 4>;
- /include/ "rtsm_ve-motherboard-aarch32.dtsi"
+ #include "rtsm_ve-motherboard-aarch32.dtsi"
};
};
diff --git a/fdts/fvp-ve-Cortex-A7x1.dts b/fdts/fvp-ve-Cortex-A7x1.dts
index fca3d90ab5..28de91d3c8 100644
--- a/fdts/fvp-ve-Cortex-A7x1.dts
+++ b/fdts/fvp-ve-Cortex-A7x1.dts
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -71,6 +71,6 @@
<0 0 5 &gic 0 5 4>,
<0 0 42 &gic 0 42 4>;
- /include/ "rtsm_ve-motherboard-aarch32.dtsi"
+ #include "rtsm_ve-motherboard-aarch32.dtsi"
};
};
diff --git a/fdts/stm32mp157-pinctrl.dtsi b/fdts/stm32mp157-pinctrl.dtsi
index 8e480b2c19..7fd902bd2d 100644
--- a/fdts/stm32mp157-pinctrl.dtsi
+++ b/fdts/stm32mp157-pinctrl.dtsi
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/*
- * Copyright (C) STMicroelectronics 2017 - All Rights Reserved
+ * Copyright (C) STMicroelectronics 2017-2019 - All Rights Reserved
* Author: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics.
*/
#include <dt-bindings/pinctrl/stm32-pinfunc.h>
@@ -135,6 +135,31 @@
status = "disabled";
};
+ fmc_pins_a: fmc-0 {
+ pins1 {
+ pinmux = <STM32_PINMUX('D', 4, AF12)>, /* FMC_NOE */
+ <STM32_PINMUX('D', 5, AF12)>, /* FMC_NWE */
+ <STM32_PINMUX('D', 11, AF12)>, /* FMC_A16_FMC_CLE */
+ <STM32_PINMUX('D', 12, AF12)>, /* FMC_A17_FMC_ALE */
+ <STM32_PINMUX('D', 14, AF12)>, /* FMC_D0 */
+ <STM32_PINMUX('D', 15, AF12)>, /* FMC_D1 */
+ <STM32_PINMUX('D', 0, AF12)>, /* FMC_D2 */
+ <STM32_PINMUX('D', 1, AF12)>, /* FMC_D3 */
+ <STM32_PINMUX('E', 7, AF12)>, /* FMC_D4 */
+ <STM32_PINMUX('E', 8, AF12)>, /* FMC_D5 */
+ <STM32_PINMUX('E', 9, AF12)>, /* FMC_D6 */
+ <STM32_PINMUX('E', 10, AF12)>, /* FMC_D7 */
+ <STM32_PINMUX('G', 9, AF12)>; /* FMC_NE2_FMC_NCE */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <1>;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('D', 6, AF12)>; /* FMC_NWAIT */
+ bias-pull-up;
+ };
+ };
+
qspi_bk1_pins_a: qspi-bk1-0 {
pins1 {
pinmux = <STM32_PINMUX('F', 8, AF10)>, /* QSPI_BK1_IO0 */
diff --git a/fdts/stm32mp157c-ev1.dts b/fdts/stm32mp157c-ev1.dts
index cfde8ed90e..50c0b939b3 100644
--- a/fdts/stm32mp157c-ev1.dts
+++ b/fdts/stm32mp157c-ev1.dts
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/*
- * Copyright (C) STMicroelectronics 2017 - All Rights Reserved
+ * Copyright (C) STMicroelectronics 2017-2019 - All Rights Reserved
* Author: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics.
*/
/dts-v1/;
@@ -21,21 +21,20 @@
};
&fmc {
+ pinctrl-names = "default";
+ pinctrl-0 = <&fmc_pins_a>;
status = "okay";
#address-cells = <1>;
#size-cells = <0>;
nand: nand@0 {
reg = <0>;
- nand-on-flash-bbt;
- #address-cells = <1>;
- #size-cells = <1>;
};
};
&qspi {
pinctrl-names = "default";
- pinctrl-0 = <&qspi_clk_pins_a &qspi_bk1_pins_a &qspi_bk2_pins_a>;
+ pinctrl-0 = <&qspi_clk_pins_a &qspi_bk1_pins_a>;
reg = <0x58003000 0x1000>, <0x70000000 0x4000000>;
#address-cells = <1>;
#size-cells = <0>;
@@ -49,15 +48,6 @@
#address-cells = <1>;
#size-cells = <1>;
};
-
- flash1: mx66l51235l@1 {
- compatible = "jedec,spi-nor";
- reg = <1>;
- spi-rx-bus-width = <4>;
- spi-max-frequency = <108000000>;
- #address-cells = <1>;
- #size-cells = <1>;
- };
};
&usart3 {
diff --git a/include/drivers/io/io_driver.h b/include/drivers/io/io_driver.h
index 2b704f491e..d8bb435aa9 100644
--- a/include/drivers/io/io_driver.h
+++ b/include/drivers/io/io_driver.h
@@ -39,7 +39,7 @@ typedef struct io_dev_funcs {
io_type_t (*type)(void);
int (*open)(io_dev_info_t *dev_info, const uintptr_t spec,
io_entity_t *entity);
- int (*seek)(io_entity_t *entity, int mode, ssize_t offset);
+ int (*seek)(io_entity_t *entity, int mode, signed long long offset);
int (*size)(io_entity_t *entity, size_t *length);
int (*read)(io_entity_t *entity, uintptr_t buffer, size_t length,
size_t *length_read);
diff --git a/include/drivers/io/io_mtd.h b/include/drivers/io/io_mtd.h
new file mode 100644
index 0000000000..1395ff6019
--- /dev/null
+++ b/include/drivers/io/io_mtd.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IO_MTD_H
+#define IO_MTD_H
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <drivers/io/io_storage.h>
+
+/* MTD devices ops */
+typedef struct io_mtd_ops {
+ /*
+ * Initialize MTD framework and retrieve device information.
+ *
+ * @size: [out] MTD device size in bytes.
+ * @erase_size: [out] MTD erase size in bytes.
+ * Return 0 on success, a negative error code otherwise.
+ */
+ int (*init)(unsigned long long *size, unsigned int *erase_size);
+
+ /*
+ * Execute a read memory operation.
+ *
+ * @offset: Offset in bytes to start read operation.
+ * @buffer: [out] Buffer to store read data.
+ * @length: Required length to be read in bytes.
+ * @out_length: [out] Length read in bytes.
+ * Return 0 on success, a negative error code otherwise.
+ */
+ int (*read)(unsigned int offset, uintptr_t buffer, size_t length,
+ size_t *out_length);
+
+ /*
+ * Execute a write memory operation.
+ *
+ * @offset: Offset in bytes to start write operation.
+ * @buffer: Buffer to be written in device.
+ * @length: Required length to be written in bytes.
+ * Return 0 on success, a negative error code otherwise.
+ */
+ int (*write)(unsigned int offset, uintptr_t buffer, size_t length);
+} io_mtd_ops_t;
+
+typedef struct io_mtd_dev_spec {
+ unsigned long long device_size;
+ unsigned int erase_size;
+ io_mtd_ops_t ops;
+} io_mtd_dev_spec_t;
+
+struct io_dev_connector;
+
+int register_io_dev_mtd(const struct io_dev_connector **dev_con);
+
+#endif /* IO_MTD_H */
diff --git a/include/drivers/io/io_storage.h b/include/drivers/io/io_storage.h
index 084c67c470..0e6ffd6193 100644
--- a/include/drivers/io/io_storage.h
+++ b/include/drivers/io/io_storage.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -22,6 +22,7 @@ typedef enum {
IO_TYPE_DUMMY,
IO_TYPE_FIRMWARE_IMAGE_PACKAGE,
IO_TYPE_BLOCK,
+ IO_TYPE_MTD,
IO_TYPE_MMC,
IO_TYPE_STM32IMAGE,
IO_TYPE_MAX
@@ -86,7 +87,7 @@ int io_dev_close(uintptr_t dev_handle);
/* Synchronous operations */
int io_open(uintptr_t dev_handle, const uintptr_t spec, uintptr_t *handle);
-int io_seek(uintptr_t handle, io_seek_mode_t mode, ssize_t offset);
+int io_seek(uintptr_t handle, io_seek_mode_t mode, signed long long offset);
int io_size(uintptr_t handle, size_t *length);
diff --git a/include/drivers/nand.h b/include/drivers/nand.h
new file mode 100644
index 0000000000..1dbb008f9c
--- /dev/null
+++ b/include/drivers/nand.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DRIVERS_NAND_H
+#define DRIVERS_NAND_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+#define PSEC_TO_MSEC(x) div_round_up((x), 1000000000ULL)
+
+struct ecc {
+ unsigned int mode; /* ECC mode NAND_ECC_MODE_{NONE|HW|ONDIE} */
+ unsigned int size; /* Data byte per ECC step */
+ unsigned int bytes; /* ECC bytes per step */
+ unsigned int max_bit_corr; /* Max correctible bits per ECC steps */
+};
+
+struct nand_device {
+ unsigned int block_size;
+ unsigned int page_size;
+ unsigned long long size;
+ unsigned int nb_planes;
+ unsigned int buswidth;
+ struct ecc ecc;
+ int (*mtd_block_is_bad)(unsigned int block);
+ int (*mtd_read_page)(struct nand_device *nand, unsigned int page,
+ uintptr_t buffer);
+};
+
+/*
+ * Read bytes from NAND device
+ *
+ * @offset: Byte offset to read from in device
+ * @buffer: [out] Bytes read from device
+ * @length: Number of bytes to read
+ * @length_read: [out] Number of bytes read from device
+ * Return: 0 on success, a negative errno on failure
+ */
+int nand_read(unsigned int offset, uintptr_t buffer, size_t length,
+ size_t *length_read);
+
+/*
+ * Get NAND device instance
+ *
+ * Return: NAND device instance reference
+ */
+struct nand_device *get_nand_device(void);
+
+#endif /* DRIVERS_NAND_H */
diff --git a/include/drivers/raw_nand.h b/include/drivers/raw_nand.h
new file mode 100644
index 0000000000..18e4b73da3
--- /dev/null
+++ b/include/drivers/raw_nand.h
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DRIVERS_RAW_NAND_H
+#define DRIVERS_RAW_NAND_H
+
+#include <stdint.h>
+
+#include <drivers/nand.h>
+
+/* NAND ONFI default value mode 0 in picosecond */
+#define NAND_TADL_MIN 400000UL
+#define NAND_TALH_MIN 20000UL
+#define NAND_TALS_MIN 50000UL
+#define NAND_TAR_MIN 25000UL
+#define NAND_TCCS_MIN 500000UL
+#define NAND_TCEA_MIN 100000UL
+#define NAND_TCEH_MIN 20000UL
+#define NAND_TCH_MIN 20000UL
+#define NAND_TCHZ_MAX 100000UL
+#define NAND_TCLH_MIN 20000UL
+#define NAND_TCLR_MIN 20000UL
+#define NAND_TCLS_MIN 50000UL
+#define NAND_TCOH_MIN 0UL
+#define NAND_TCS_MIN 70000UL
+#define NAND_TDH_MIN 20000UL
+#define NAND_TDS_MIN 40000UL
+#define NAND_TFEAT_MAX 1000000UL
+#define NAND_TIR_MIN 10000UL
+#define NAND_TITC_MIN 1000000UL
+#define NAND_TR_MAX 200000000UL
+#define NAND_TRC_MIN 100000UL
+#define NAND_TREA_MAX 40000UL
+#define NAND_TREH_MIN 30000UL
+#define NAND_TRHOH_MIN 0UL
+#define NAND_TRHW_MIN 200000UL
+#define NAND_TRHZ_MAX 200000UL
+#define NAND_TRLOH_MIN 0UL
+#define NAND_TRP_MIN 50000UL
+#define NAND_TRR_MIN 40000UL
+#define NAND_TRST_MAX 250000000000ULL
+#define NAND_TWB_MAX 200000UL
+#define NAND_TWC_MIN 100000UL
+#define NAND_TWH_MIN 30000UL
+#define NAND_TWHR_MIN 120000UL
+#define NAND_TWP_MIN 50000UL
+#define NAND_TWW_MIN 100000UL
+
+/* NAND request types */
+#define NAND_REQ_CMD 0x0000U
+#define NAND_REQ_ADDR 0x1000U
+#define NAND_REQ_DATAIN 0x2000U
+#define NAND_REQ_DATAOUT 0x3000U
+#define NAND_REQ_WAIT 0x4000U
+#define NAND_REQ_MASK GENMASK(14, 12)
+#define NAND_REQ_BUS_WIDTH_8 BIT(15)
+
+#define PARAM_PAGE_SIZE 256
+
+/* NAND ONFI commands */
+#define NAND_CMD_READ_1ST 0x00U
+#define NAND_CMD_CHANGE_1ST 0x05U
+#define NAND_CMD_READID_SIG_ADDR 0x20U
+#define NAND_CMD_READ_2ND 0x30U
+#define NAND_CMD_STATUS 0x70U
+#define NAND_CMD_READID 0x90U
+#define NAND_CMD_CHANGE_2ND 0xE0U
+#define NAND_CMD_READ_PARAM_PAGE 0xECU
+#define NAND_CMD_RESET 0xFFU
+
+#define ONFI_REV_21 BIT(3)
+#define ONFI_FEAT_BUS_WIDTH_16 BIT(0)
+#define ONFI_FEAT_EXTENDED_PARAM BIT(7)
+
+/* NAND ECC type */
+#define NAND_ECC_NONE U(0)
+#define NAND_ECC_HW U(1)
+#define NAND_ECC_ONDIE U(2)
+
+/* NAND bus width */
+#define NAND_BUS_WIDTH_8 U(0)
+#define NAND_BUS_WIDTH_16 U(1)
+
+struct nand_req {
+ struct nand_device *nand;
+ uint16_t type;
+ uint8_t *addr;
+ unsigned int length;
+ unsigned int delay_ms;
+ unsigned int inst_delay;
+};
+
+struct nand_param_page {
+ /* Rev information and feature block */
+ uint32_t page_sig;
+ uint16_t rev;
+ uint16_t features;
+ uint16_t opt_cmd;
+ uint8_t jtg;
+ uint8_t train_cmd;
+ uint16_t ext_param_length;
+ uint8_t nb_param_pages;
+ uint8_t reserved1[17];
+ /* Manufacturer information */
+ uint8_t manufacturer[12];
+ uint8_t model[20];
+ uint8_t manufacturer_id;
+ uint16_t data_code;
+ uint8_t reserved2[13];
+ /* Memory organization */
+ uint32_t bytes_per_page;
+ uint16_t spare_per_page;
+ uint32_t bytes_per_partial;
+ uint16_t spare_per_partial;
+ uint32_t num_pages_per_blk;
+ uint32_t num_blk_in_lun;
+ uint8_t num_lun;
+ uint8_t num_addr_cycles;
+ uint8_t bit_per_cell;
+ uint16_t max_bb_per_lun;
+ uint16_t blk_endur;
+ uint8_t valid_blk_begin;
+ uint16_t blk_enbur_valid;
+ uint8_t nb_prog_page;
+ uint8_t partial_prog_attr;
+ uint8_t nb_ecc_bits;
+ uint8_t plane_addr;
+ uint8_t mplanes_ops;
+ uint8_t ez_nand;
+ uint8_t reserved3[12];
+ /* Electrical parameters */
+ uint8_t io_pin_cap_max;
+ uint16_t sdr_timing_mode;
+ uint16_t sdr_prog_cache_timing;
+ uint16_t tprog;
+ uint16_t tbers;
+ uint16_t tr;
+ uint16_t tccs;
+ uint8_t nvddr_timing_mode;
+ uint8_t nvddr2_timing_mode;
+ uint8_t nvddr_features;
+ uint16_t clk_input_cap_typ;
+ uint16_t io_pin_cap_typ;
+ uint16_t input_pin_cap_typ;
+ uint8_t input_pin_cap_max;
+ uint8_t drv_strength_support;
+ uint16_t tr_max;
+ uint16_t tadl;
+ uint16_t tr_typ;
+ uint8_t reserved4[6];
+ /* Vendor block */
+ uint16_t vendor_revision;
+ uint8_t vendor[88];
+ uint16_t crc16;
+} __packed;
+
+struct nand_ctrl_ops {
+ int (*exec)(struct nand_req *req);
+ void (*setup)(struct nand_device *nand);
+};
+
+struct rawnand_device {
+ struct nand_device *nand_dev;
+ const struct nand_ctrl_ops *ops;
+};
+
+int nand_raw_init(unsigned long long *size, unsigned int *erase_size);
+int nand_wait_ready(unsigned long delay);
+int nand_read_page_cmd(unsigned int page, unsigned int offset,
+ uintptr_t buffer, unsigned int len);
+int nand_change_read_column_cmd(unsigned int offset, uintptr_t buffer,
+ unsigned int len);
+void nand_raw_ctrl_init(const struct nand_ctrl_ops *ops);
+
+/*
+ * Platform can implement this to override default raw NAND instance
+ * configuration.
+ *
+ * @device: target raw NAND instance.
+ * Return 0 on success, negative value otherwise.
+ */
+int plat_get_raw_nand_data(struct rawnand_device *device);
+
+#endif /* DRIVERS_RAW_NAND_H */
diff --git a/include/drivers/spi_mem.h b/include/drivers/spi_mem.h
new file mode 100644
index 0000000000..d1953acf4c
--- /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 0000000000..40e2063751
--- /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 0000000000..72cfe5b346
--- /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/io_stm32image.h b/include/drivers/st/io_stm32image.h
index 68060558ba..f9fa3630c6 100644
--- a/include/drivers/st/io_stm32image.h
+++ b/include/drivers/st/io_stm32image.h
@@ -23,7 +23,7 @@ struct stm32image_part_info {
struct stm32image_device_info {
struct stm32image_part_info part_info[STM32_PART_NUM];
- uint32_t device_size;
+ unsigned long long device_size;
uint32_t lba_size;
};
diff --git a/include/drivers/st/stm32_fmc2_nand.h b/include/drivers/st/stm32_fmc2_nand.h
new file mode 100644
index 0000000000..81d5b9de19
--- /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_qspi.h b/include/drivers/st/stm32_qspi.h
new file mode 100644
index 0000000000..f47fca445e
--- /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/lib/utils_def.h b/include/lib/utils_def.h
index 35ae33a682..23f59bdc33 100644
--- a/include/lib/utils_def.h
+++ b/include/lib/utils_def.h
@@ -77,6 +77,15 @@
_x > _y ? _x : _y; \
})
+#define CLAMP(x, min, max) __extension__ ({ \
+ __typeof__(x) _x = (x); \
+ __typeof__(min) _min = (min); \
+ __typeof__(max) _max = (max); \
+ (void)(&_x == &_min); \
+ (void)(&_x == &_max); \
+ (_x > _max ? _max : (_x < _min ? _min : _x)); \
+})
+
/*
* The round_up() macro rounds up a value to the given boundary in a
* type-agnostic yet type-safe manner. The boundary must be a power of two.
diff --git a/lib/compiler-rt/builtins/arm/aeabi_ldivmod.S b/lib/compiler-rt/builtins/arm/aeabi_ldivmod.S
new file mode 100644
index 0000000000..038ae5d723
--- /dev/null
+++ b/lib/compiler-rt/builtins/arm/aeabi_ldivmod.S
@@ -0,0 +1,46 @@
+//===-- aeabi_ldivmod.S - EABI ldivmod implementation ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+// struct { int64_t quot, int64_t rem}
+// __aeabi_ldivmod(int64_t numerator, int64_t denominator) {
+// int64_t rem, quot;
+// quot = __divmoddi4(numerator, denominator, &rem);
+// return {quot, rem};
+// }
+
+#if defined(__MINGW32__)
+#define __aeabi_ldivmod __rt_sdiv64
+#endif
+
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__aeabi_ldivmod)
+ push {r6, lr}
+ sub sp, sp, #16
+ add r6, sp, #8
+ str r6, [sp]
+#if defined(__MINGW32__)
+ movs r6, r0
+ movs r0, r2
+ movs r2, r6
+ movs r6, r1
+ movs r1, r3
+ movs r3, r6
+#endif
+ bl SYMBOL_NAME(__divmoddi4)
+ ldr r2, [sp, #8]
+ ldr r3, [sp, #12]
+ add sp, sp, #16
+ pop {r6, pc}
+END_COMPILERRT_FUNCTION(__aeabi_ldivmod)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/lib/compiler-rt/builtins/divdi3.c b/lib/compiler-rt/builtins/divdi3.c
new file mode 100644
index 0000000000..b8eebcb204
--- /dev/null
+++ b/lib/compiler-rt/builtins/divdi3.c
@@ -0,0 +1,29 @@
+/* ===-- divdi3.c - Implement __divdi3 -------------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __divdi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a / b */
+
+COMPILER_RT_ABI di_int
+__divdi3(di_int a, di_int b)
+{
+ const int bits_in_dword_m1 = (int)(sizeof(di_int) * CHAR_BIT) - 1;
+ di_int s_a = a >> bits_in_dword_m1; /* s_a = a < 0 ? -1 : 0 */
+ di_int s_b = b >> bits_in_dword_m1; /* s_b = b < 0 ? -1 : 0 */
+ a = (a ^ s_a) - s_a; /* negate if s_a == -1 */
+ b = (b ^ s_b) - s_b; /* negate if s_b == -1 */
+ s_a ^= s_b; /*sign of quotient */
+ return (__udivmoddi4(a, b, (du_int*)0) ^ s_a) - s_a; /* negate if s_a == -1 */
+}
diff --git a/lib/compiler-rt/builtins/divmoddi4.c b/lib/compiler-rt/builtins/divmoddi4.c
new file mode 100644
index 0000000000..0d4df67a63
--- /dev/null
+++ b/lib/compiler-rt/builtins/divmoddi4.c
@@ -0,0 +1,25 @@
+/*===-- divmoddi4.c - Implement __divmoddi4 --------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __divmoddi4 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a / b, *rem = a % b */
+
+COMPILER_RT_ABI di_int
+__divmoddi4(di_int a, di_int b, di_int* rem)
+{
+ di_int d = __divdi3(a,b);
+ *rem = a - (d*b);
+ return d;
+}
diff --git a/lib/compiler-rt/builtins/popcountdi2.c b/lib/compiler-rt/builtins/popcountdi2.c
new file mode 100644
index 0000000000..5e8a62f075
--- /dev/null
+++ b/lib/compiler-rt/builtins/popcountdi2.c
@@ -0,0 +1,36 @@
+/* ===-- popcountdi2.c - Implement __popcountdi2 ----------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __popcountdi2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: count of 1 bits */
+
+COMPILER_RT_ABI si_int
+__popcountdi2(di_int a)
+{
+ du_int x2 = (du_int)a;
+ x2 = x2 - ((x2 >> 1) & 0x5555555555555555uLL);
+ /* Every 2 bits holds the sum of every pair of bits (32) */
+ x2 = ((x2 >> 2) & 0x3333333333333333uLL) + (x2 & 0x3333333333333333uLL);
+ /* Every 4 bits holds the sum of every 4-set of bits (3 significant bits) (16) */
+ x2 = (x2 + (x2 >> 4)) & 0x0F0F0F0F0F0F0F0FuLL;
+ /* Every 8 bits holds the sum of every 8-set of bits (4 significant bits) (8) */
+ su_int x = (su_int)(x2 + (x2 >> 32));
+ /* The lower 32 bits hold four 16 bit sums (5 significant bits). */
+ /* Upper 32 bits are garbage */
+ x = x + (x >> 16);
+ /* The lower 16 bits hold two 32 bit sums (6 significant bits). */
+ /* Upper 16 bits are garbage */
+ return (x + (x >> 8)) & 0x0000007F; /* (7 significant bits) */
+}
diff --git a/lib/compiler-rt/builtins/popcountsi2.c b/lib/compiler-rt/builtins/popcountsi2.c
new file mode 100644
index 0000000000..44544ff498
--- /dev/null
+++ b/lib/compiler-rt/builtins/popcountsi2.c
@@ -0,0 +1,33 @@
+/* ===-- popcountsi2.c - Implement __popcountsi2 ---------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __popcountsi2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: count of 1 bits */
+
+COMPILER_RT_ABI si_int
+__popcountsi2(si_int a)
+{
+ su_int x = (su_int)a;
+ x = x - ((x >> 1) & 0x55555555);
+ /* Every 2 bits holds the sum of every pair of bits */
+ x = ((x >> 2) & 0x33333333) + (x & 0x33333333);
+ /* Every 4 bits holds the sum of every 4-set of bits (3 significant bits) */
+ x = (x + (x >> 4)) & 0x0F0F0F0F;
+ /* Every 8 bits holds the sum of every 8-set of bits (4 significant bits) */
+ x = (x + (x >> 16));
+ /* The lower 16 bits hold two 8 bit sums (5 significant bits).*/
+ /* Upper 16 bits are garbage */
+ return (x + (x >> 8)) & 0x0000003F; /* (6 significant bits) */
+}
diff --git a/lib/compiler-rt/compiler-rt.mk b/lib/compiler-rt/compiler-rt.mk
index 49e497eb83..40c669f989 100644
--- a/lib/compiler-rt/compiler-rt.mk
+++ b/lib/compiler-rt/compiler-rt.mk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
@@ -28,9 +28,15 @@
# POSSIBILITY OF SUCH DAMAGE.
#
+COMPILER_RT_SRCS := lib/compiler-rt/builtins/popcountdi2.c \
+ lib/compiler-rt/builtins/popcountsi2.c
+
ifeq (${ARCH},aarch32)
-COMPILER_RT_SRCS := lib/compiler-rt/builtins/arm/aeabi_uldivmod.S \
- lib/compiler-rt/builtins/udivmoddi4.c \
+COMPILER_RT_SRCS += lib/compiler-rt/builtins/arm/aeabi_ldivmod.S \
+ lib/compiler-rt/builtins/arm/aeabi_uldivmod.S \
lib/compiler-rt/builtins/ctzdi2.c \
- lib/compiler-rt/builtins/lshrdi3.c
+ lib/compiler-rt/builtins/divdi3.c \
+ lib/compiler-rt/builtins/divmoddi4.c \
+ lib/compiler-rt/builtins/lshrdi3.c \
+ lib/compiler-rt/builtins/udivmoddi4.c
endif
diff --git a/lib/cpus/cpu-ops.mk b/lib/cpus/cpu-ops.mk
index c9b9b387ee..398edf9dc1 100644
--- a/lib/cpus/cpu-ops.mk
+++ b/lib/cpus/cpu-ops.mk
@@ -240,7 +240,7 @@ ERRATA_HERCULES_1688305 ?=0
# Flag to apply T32 CLREX workaround during reset. This erratum applies
# only to r0p0 and r1p0 of the Neoverse N1 cpu.
-ERRATA_N1_1043202 ?=1
+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.
@@ -280,7 +280,7 @@ ERRATA_N1_1275112 ?=0
# Flag to apply erratum 1315703 workaround during reset. This erratum applies
# to revisions before r3p1 of the Neoverse N1 cpu.
-ERRATA_N1_1315703 ?=1
+ERRATA_N1_1315703 ?=0
# Flag to apply erratum 1542419 workaround during reset. This erratum applies
# to revisions r3p0 - r4p0 of the Neoverse N1 cpu.
diff --git a/make_helpers/build_macros.mk b/make_helpers/build_macros.mk
index 47f3ebd861..6b72cfd0d4 100644
--- a/make_helpers/build_macros.mk
+++ b/make_helpers/build_macros.mk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -513,7 +513,7 @@ $(DOBJ): $(2) $(filter-out %.d,$(MAKEFILE_LIST)) | fdt_dirs
$(eval DTBS := $(addprefix $(1)/,$(call SOURCES_TO_DTBS,$(2))))
$$(Q)$$(PP) $$(DTC_CPPFLAGS) -MT $(DTBS) -MMD -MF $(DTSDEP) -o $(DPRE) $$<
$${ECHO} " DTC $$<"
- $$(Q)$$(DTC) $$(DTC_FLAGS) -i fdts -d $(DTBDEP) -o $$@ $(DPRE)
+ $$(Q)$$(DTC) $$(DTC_FLAGS) -d $(DTBDEP) -o $$@ $(DPRE)
-include $(DTBDEP)
-include $(DTSDEP)
diff --git a/plat/allwinner/common/include/platform_def.h b/plat/allwinner/common/include/platform_def.h
index 0a00076679..4de8b0bc46 100644
--- a/plat/allwinner/common/include/platform_def.h
+++ b/plat/allwinner/common/include/platform_def.h
@@ -32,7 +32,7 @@
#define CACHE_WRITEBACK_SHIFT 6
#define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT)
-#define MAX_MMAP_REGIONS (4 + PLATFORM_MMAP_REGIONS)
+#define MAX_MMAP_REGIONS (3 + PLATFORM_MMAP_REGIONS)
#define MAX_XLAT_TABLES 1
#define PLAT_MAX_PWR_LVL_STATES U(2)
diff --git a/plat/allwinner/common/sunxi_common.c b/plat/allwinner/common/sunxi_common.c
index cff8268199..3759c285e2 100644
--- a/plat/allwinner/common/sunxi_common.c
+++ b/plat/allwinner/common/sunxi_common.c
@@ -20,15 +20,15 @@
static const mmap_region_t sunxi_mmap[PLATFORM_MMAP_REGIONS + 1] = {
MAP_REGION_FLAT(SUNXI_SRAM_BASE, SUNXI_SRAM_SIZE,
- MT_MEMORY | MT_RW | MT_SECURE),
+ MT_RW_DATA | MT_SECURE),
MAP_REGION_FLAT(SUNXI_DEV_BASE, SUNXI_DEV_SIZE,
- MT_DEVICE | MT_RW | MT_SECURE),
+ MT_DEVICE | MT_RW | MT_SECURE | MT_EXECUTE_NEVER),
MAP_REGION(SUNXI_DRAM_BASE, SUNXI_DRAM_VIRT_BASE, SUNXI_DRAM_SEC_SIZE,
- MT_MEMORY | MT_RW | MT_SECURE),
+ MT_RW_DATA | MT_SECURE),
MAP_REGION(PLAT_SUNXI_NS_IMAGE_OFFSET,
SUNXI_DRAM_VIRT_BASE + SUNXI_DRAM_SEC_SIZE,
SUNXI_DRAM_MAP_SIZE,
- MT_MEMORY | MT_RO | MT_NS),
+ MT_RO_DATA | MT_NS),
{},
};
@@ -48,9 +48,6 @@ uintptr_t plat_get_ns_image_entrypoint(void)
void sunxi_configure_mmu_el3(int flags)
{
- mmap_add_region(BL31_BASE, BL31_BASE,
- BL31_LIMIT - BL31_BASE,
- MT_MEMORY | MT_RW | MT_SECURE);
mmap_add_region(BL_CODE_BASE, BL_CODE_BASE,
BL_CODE_END - BL_CODE_BASE,
MT_CODE | MT_SECURE);
diff --git a/plat/imx/common/plat_imx8_gic.c b/plat/imx/common/plat_imx8_gic.c
index 3a7dcfec6d..afb9d1f1a9 100644
--- a/plat/imx/common/plat_imx8_gic.c
+++ b/plat/imx/common/plat_imx8_gic.c
@@ -20,9 +20,7 @@
uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT];
static const interrupt_prop_t g01s_interrupt_props[] = {
- INTR_PROP_DESC(6, GIC_HIGHEST_SEC_PRIORITY,
- INTR_GROUP1S, GIC_INTR_CFG_LEVEL),
- INTR_PROP_DESC(7, GIC_HIGHEST_SEC_PRIORITY,
+ INTR_PROP_DESC(8, GIC_HIGHEST_SEC_PRIORITY,
INTR_GROUP0, GIC_INTR_CFG_LEVEL),
};
diff --git a/plat/imx/imx8m/imx8mm/imx8mm_bl31_setup.c b/plat/imx/imx8m/imx8mm/imx8mm_bl31_setup.c
index c3cd0d0cb9..4c5f4f0d19 100644
--- a/plat/imx/imx8m/imx8mm/imx8mm_bl31_setup.c
+++ b/plat/imx/imx8m/imx8mm/imx8mm_bl31_setup.c
@@ -124,6 +124,18 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
bl33_image_ep_info.spsr = get_spsr_for_bl33_entry();
SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+#ifdef SPD_opteed
+ /* 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;
+#endif
+
bl31_tzc380_setup();
}
diff --git a/plat/imx/imx8m/imx8mm/include/platform_def.h b/plat/imx/imx8m/imx8mm/include/platform_def.h
index de9e3b5c85..fc35dac146 100644
--- a/plat/imx/imx8m/imx8mm/include/platform_def.h
+++ b/plat/imx/imx8m/imx8mm/include/platform_def.h
@@ -31,7 +31,6 @@
#define BL31_BASE U(0x920000)
#define BL31_LIMIT U(0x940000)
-#define BL32_BASE U(0xbe000000)
/* non-secure uboot base */
#define PLAT_NS_IMAGE_OFFSET U(0x40200000)
diff --git a/plat/imx/imx8m/imx8mm/platform.mk b/plat/imx/imx8m/imx8mm/platform.mk
index 6d32dbba32..c0cb6c2a5c 100644
--- a/plat/imx/imx8m/imx8mm/platform.mk
+++ b/plat/imx/imx8m/imx8mm/platform.mk
@@ -45,3 +45,9 @@ 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))
diff --git a/plat/imx/imx8m/imx8mq/imx8mq_bl31_setup.c b/plat/imx/imx8m/imx8mq/imx8mq_bl31_setup.c
index 26a3b364e9..a347389a26 100644
--- a/plat/imx/imx8m/imx8mq/imx8mq_bl31_setup.c
+++ b/plat/imx/imx8m/imx8mq/imx8mq_bl31_setup.c
@@ -146,6 +146,18 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
bl33_image_ep_info.spsr = get_spsr_for_bl33_entry();
SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+#ifdef SPD_opteed
+ /* 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;
+#endif
+
bl31_tz380_setup();
}
diff --git a/plat/imx/imx8m/imx8mq/include/platform_def.h b/plat/imx/imx8m/imx8mq/include/platform_def.h
index 3c212e3782..9aa759fd37 100644
--- a/plat/imx/imx8m/imx8mq/include/platform_def.h
+++ b/plat/imx/imx8m/imx8mq/include/platform_def.h
@@ -32,7 +32,6 @@
#define BL31_BASE U(0x910000)
#define BL31_LIMIT U(0x920000)
-#define BL32_BASE U(0xfe000000)
/* non-secure uboot base */
#define PLAT_NS_IMAGE_OFFSET U(0x40200000)
diff --git a/plat/imx/imx8m/imx8mq/platform.mk b/plat/imx/imx8m/imx8mq/platform.mk
index 44ce555871..80ebe40622 100644
--- a/plat/imx/imx8m/imx8mq/platform.mk
+++ b/plat/imx/imx8m/imx8mq/platform.mk
@@ -44,3 +44,9 @@ 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))
diff --git a/plat/nvidia/tegra/include/t194/tegra_def.h b/plat/nvidia/tegra/include/t194/tegra_def.h
index e20b2c6343..a98aa2da8d 100644
--- a/plat/nvidia/tegra/include/t194/tegra_def.h
+++ b/plat/nvidia/tegra/include/t194/tegra_def.h
@@ -172,16 +172,16 @@
* Tegra scratch registers constants
******************************************************************************/
#define TEGRA_SCRATCH_BASE U(0x0C390000)
-#define SECURE_SCRATCH_RSV44_LO U(0x1C4)
-#define SECURE_SCRATCH_RSV44_HI U(0x1C8)
+#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_ADDR SECURE_SCRATCH_RSV44_LO
-#define SCRATCH_BL31_PLAT_PARAMS_ADDR SECURE_SCRATCH_RSV44_HI
+#define SCRATCH_BL31_PARAMS_ADDR SECURE_SCRATCH_RSV81_LO
+#define SCRATCH_BL31_PLAT_PARAMS_ADDR SECURE_SCRATCH_RSV81_HI
#define SCRATCH_SECURE_BOOTP_FCFG SECURE_SCRATCH_RSV97
#define SCRATCH_SMMU_TABLE_ADDR_LO SECURE_SCRATCH_RSV99_LO
#define SCRATCH_SMMU_TABLE_ADDR_HI SECURE_SCRATCH_RSV99_HI
diff --git a/plat/nvidia/tegra/include/t194/tegra_mc_def.h b/plat/nvidia/tegra/include/t194/tegra_mc_def.h
index 1433a2ea6c..09dcce3c05 100644
--- a/plat/nvidia/tegra/include/t194/tegra_mc_def.h
+++ b/plat/nvidia/tegra/include/t194/tegra_mc_def.h
@@ -27,8 +27,8 @@
#define MC_CLIENT_ORDER_ID_28_PCIE5W_MASK (0x3U << 12)
#define MC_CLIENT_ORDER_ID_28_PCIE5W_ORDER_ID (2U << 12)
-#define mc_client_order_id(id, client) \
- (~MC_CLIENT_ORDER_ID_##id##_##client##_MASK | \
+#define mc_client_order_id(val, id, client) \
+ ((val & ~MC_CLIENT_ORDER_ID_##id##_##client##_MASK) | \
MC_CLIENT_ORDER_ID_##id##_##client##_ORDER_ID)
/*******************************************************************************
@@ -53,8 +53,8 @@
#define MC_HUB_PC_VC_ID_4_NIC_VC_ID_MASK (0x3U << 28)
#define MC_HUB_PC_VC_ID_4_NIC_VC_ID (VC_NISO << 28)
-#define mc_hub_vc_id(id, client) \
- (~MC_HUB_PC_VC_ID_##id##_##client##_VC_ID_MASK | \
+#define mc_hub_vc_id(val, id, client) \
+ ((val & ~MC_HUB_PC_VC_ID_##id##_##client##_VC_ID_MASK) | \
MC_HUB_PC_VC_ID_##id##_##client##_VC_ID)
/*******************************************************************************
@@ -530,6 +530,9 @@
#define MC_CLIENT_HOTRESET_CTRL2_PCIE4A_FLUSH_ENB (1U << 25)
#define MC_CLIENT_HOTRESET_STATUS2 0x1898U
+#define MC_COALESCE_CTRL 0x2930U
+#define MC_COALESCE_CTRL_COALESCER_ENABLE (1U << 31)
+
/*******************************************************************************
* Tegra TSA Controller constants
******************************************************************************/
diff --git a/plat/nvidia/tegra/soc/t194/drivers/include/mce_private.h b/plat/nvidia/tegra/soc/t194/drivers/include/mce_private.h
index 226ab5bc51..9741d084fa 100644
--- a/plat/nvidia/tegra/soc/t194/drivers/include/mce_private.h
+++ b/plat/nvidia/tegra/soc/t194/drivers/include/mce_private.h
@@ -7,6 +7,7 @@
#ifndef MCE_PRIVATE_H
#define MCE_PRIVATE_H
+#include <stdbool.h>
#include <tegra_def.h>
/*******************************************************************************
@@ -67,8 +68,12 @@ uint64_t nvg_cache_clean(void);
uint64_t nvg_cache_clean_inval(void);
uint64_t nvg_cache_inval_all(void);
void nvg_enable_strict_checking_mode(void);
+void nvg_system_shutdown(void);
+void nvg_system_reboot(void);
/* MCE helper functions */
void mce_enable_strict_checking(void);
+void mce_system_shutdown(void);
+void mce_system_reboot(void);
#endif /* MCE_PRIVATE_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
index cc0da80bf6..06cbb4a2e2 100644
--- a/plat/nvidia/tegra/soc/t194/drivers/include/t194_nvg.h
+++ b/plat/nvidia/tegra/soc/t194/drivers/include/t194_nvg.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -128,6 +128,11 @@ typedef enum {
TEGRA_NVG_SYSTEM_SC8 = 8
} tegra_nvg_system_sleep_state_t;
+typedef enum {
+ TEGRA_NVG_SHUTDOWN = 0U,
+ TEGRA_NVG_REBOOT = 1U,
+} tegra_nvg_shutdown_reboot_state_t;
+
// ---------------------------------------------------------------------------
// NVG Data subformats
// ---------------------------------------------------------------------------
diff --git a/plat/nvidia/tegra/soc/t194/drivers/mce/mce.c b/plat/nvidia/tegra/soc/t194/drivers/mce/mce.c
index ba8436be42..00c671bcca 100644
--- a/plat/nvidia/tegra/soc/t194/drivers/mce/mce.c
+++ b/plat/nvidia/tegra/soc/t194/drivers/mce/mce.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -186,6 +186,7 @@ void mce_verify_firmware_version(void)
}
}
+#if ENABLE_STRICT_CHECKING_MODE
/*******************************************************************************
* Handler to enable the strict checking mode
******************************************************************************/
@@ -235,3 +236,20 @@ void mce_enable_strict_checking(void)
nvg_enable_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();
+}
diff --git a/plat/nvidia/tegra/soc/t194/drivers/mce/nvg.c b/plat/nvidia/tegra/soc/t194/drivers/mce/nvg.c
index 536ed57c00..a095fdd075 100644
--- a/plat/nvidia/tegra/soc/t194/drivers/mce/nvg.c
+++ b/plat/nvidia/tegra/soc/t194/drivers/mce/nvg.c
@@ -288,6 +288,7 @@ int32_t nvg_enter_cstate(uint32_t state, uint32_t wake_time)
return ret;
}
+#if ENABLE_STRICT_CHECKING_MODE
/*
* Enable strict checking mode
*
@@ -300,3 +301,26 @@ void nvg_enable_strict_checking_mode(void)
nvg_set_request_data(TEGRA_NVG_CHANNEL_SECURITY_CONFIG, params);
}
+#endif
+
+/*
+ * Request a reboot
+ *
+ * NVGDATA[0]: reboot command
+ */
+void nvg_system_reboot(void)
+{
+ /* issue command for reboot */
+ nvg_set_request_data(TEGRA_NVG_CHANNEL_SHUTDOWN, TEGRA_NVG_REBOOT);
+}
+
+/*
+ * Request a shutdown
+ *
+ * NVGDATA[0]: shutdown command
+ */
+void nvg_system_shutdown(void)
+{
+ /* issue command for shutdown */
+ nvg_set_request_data(TEGRA_NVG_CHANNEL_SHUTDOWN, TEGRA_NVG_SHUTDOWN);
+}
diff --git a/plat/nvidia/tegra/soc/t194/plat_memctrl.c b/plat/nvidia/tegra/soc/t194/plat_memctrl.c
index 54dbe7cdb4..57186503bb 100644
--- a/plat/nvidia/tegra/soc/t194/plat_memctrl.c
+++ b/plat/nvidia/tegra/soc/t194/plat_memctrl.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -478,8 +478,9 @@ static void tegra194_memctrl_reconfig_mss_clients(void)
mc_set_txn_override(VICSRD, CGID_TAG_DEFAULT, SO_DEV_ZERO, NO_OVERRIDE, NO_OVERRIDE);
mc_set_txn_override(VICSRD1, CGID_TAG_DEFAULT, SO_DEV_ZERO, NO_OVERRIDE, NO_OVERRIDE);
mc_set_txn_override(VICSWR, CGID_TAG_DEFAULT, SO_DEV_ZERO, NO_OVERRIDE, NO_OVERRIDE);
- mc_set_txn_override(VIFALR, CGID_TAG_DEFAULT, SO_DEV_ZERO, NO_OVERRIDE, NO_OVERRIDE);
- mc_set_txn_override(VIFALW, CGID_TAG_DEFAULT, SO_DEV_ZERO, NO_OVERRIDE, NO_OVERRIDE);
+ mc_set_txn_override(VIW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+ mc_set_txn_override(VIFALR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+ mc_set_txn_override(VIFALW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(XUSB_DEVR, CGID_TAG_DEFAULT, SO_DEV_ZERO, NO_OVERRIDE, NO_OVERRIDE);
mc_set_txn_override(XUSB_DEVW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT,
FORCE_COHERENT_SNOOP);
@@ -577,36 +578,29 @@ static void tegra194_memctrl_reconfig_mss_clients(void)
tegra_mc_write_32(MC_PCFIFO_CLIENT_CONFIG7, reg_val);
/* Set Order Id only for the clients having non zero order id */
- reg_val = MC_CLIENT_ORDER_ID_9_RESET_VAL &
- mc_client_order_id(9, XUSB_HOSTW);
+ reg_val = mc_client_order_id(MC_CLIENT_ORDER_ID_9_RESET_VAL, 9, XUSB_HOSTW);
tegra_mc_write_32(MC_CLIENT_ORDER_ID_9, reg_val);
- reg_val = MC_CLIENT_ORDER_ID_27_RESET_VAL &
- mc_client_order_id(27, PCIE0W);
+ reg_val = mc_client_order_id(MC_CLIENT_ORDER_ID_27_RESET_VAL, 27, PCIE0W);
tegra_mc_write_32(MC_CLIENT_ORDER_ID_27, reg_val);
- reg_val = MC_CLIENT_ORDER_ID_28_RESET_VAL &
- mc_client_order_id(28, PCIE4W) &
- mc_client_order_id(28, PCIE5W);
+ reg_val = mc_client_order_id(MC_CLIENT_ORDER_ID_28_RESET_VAL, 28, PCIE4W);
+ reg_val = mc_client_order_id(reg_val, 28, PCIE5W);
tegra_mc_write_32(MC_CLIENT_ORDER_ID_28, reg_val);
- /* Set VC Id only for the clients having different reset values */
- reg_val = MC_HUB_PC_VC_ID_0_RESET_VAL &
- /*
- * SDMMCRAB, SDMMCWAB, SESRD, SESWR, TSECSRD,TSECSRDB,
- * TSECSWR and TSECSWRB clients
- */
- mc_hub_vc_id(0, APB);
+ /*
+ * Set VC Id only for the clients having different reset values like
+ * SDMMCRAB, SDMMCWAB, SESRD, SESWR, TSECSRD,TSECSRDB, TSECSWR and
+ * TSECSWRB clients
+ */
+ reg_val = mc_hub_vc_id(MC_HUB_PC_VC_ID_0_RESET_VAL, 0, APB);
tegra_mc_write_32(MC_HUB_PC_VC_ID_0, reg_val);
- reg_val = MC_HUB_PC_VC_ID_2_RESET_VAL &
/* SDMMCRAB and SDMMCWAB clients */
- mc_hub_vc_id(2, SD);
+ reg_val = mc_hub_vc_id(MC_HUB_PC_VC_ID_2_RESET_VAL, 2, SD);
tegra_mc_write_32(MC_HUB_PC_VC_ID_2, reg_val);
- reg_val = MC_HUB_PC_VC_ID_4_RESET_VAL &
- /* AXIR and AXIW clients */
- mc_hub_vc_id(4, NIC);
+ reg_val = mc_hub_vc_id(MC_HUB_PC_VC_ID_4_RESET_VAL, 4, NIC);
tegra_mc_write_32(MC_HUB_PC_VC_ID_4, reg_val);
wdata_0 = MC_CLIENT_HOTRESET_CTRL0_RESET_VAL;
@@ -617,6 +611,9 @@ static void tegra194_memctrl_reconfig_mss_clients(void)
wdata_2 = MC_CLIENT_HOTRESET_CTRL2_RESET_VAL;
tegra_mc_write_32(MC_CLIENT_HOTRESET_CTRL2, wdata_2);
+
+ reg_val = MC_COALESCE_CTRL_COALESCER_ENABLE;
+ tegra_mc_write_32(MC_COALESCE_CTRL, reg_val);
}
/*******************************************************************************
diff --git a/plat/nvidia/tegra/soc/t194/plat_psci_handlers.c b/plat/nvidia/tegra/soc/t194/plat_psci_handlers.c
index fa5ba6263f..b7e3703362 100644
--- a/plat/nvidia/tegra/soc/t194/plat_psci_handlers.c
+++ b/plat/nvidia/tegra/soc/t194/plat_psci_handlers.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -77,6 +77,12 @@ int32_t tegra_soc_validate_power_state(uint32_t power_state,
/* Sanity check the requested state id */
switch (state_id) {
case PSTATE_ID_CORE_IDLE:
+
+ /* 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;
+
case PSTATE_ID_CORE_POWERDN:
/* Core powerdown request */
@@ -94,6 +100,25 @@ int32_t tegra_soc_validate_power_state(uint32_t power_state,
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;
@@ -103,6 +128,7 @@ int32_t tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
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,
@@ -117,15 +143,13 @@ int32_t tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] &
TEGRA194_STATE_ID_MASK;
- if ((stateid_afflvl0 == PSTATE_ID_CORE_IDLE) ||
- (stateid_afflvl0 == PSTATE_ID_CORE_POWERDN)) {
+ if ((stateid_afflvl0 == PSTATE_ID_CORE_POWERDN)) {
- /* Enter CPU idle/powerdown */
- val = (stateid_afflvl0 == PSTATE_ID_CORE_IDLE) ?
- (uint32_t)TEGRA_NVG_CORE_C6 : (uint32_t)TEGRA_NVG_CORE_C7;
- ret = mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE, (uint64_t)val,
- t19x_percpu_data[cpu].wake_time, 0);
- assert(ret == 0);
+ /* Enter CPU powerdown */
+ (void)mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE,
+ (uint64_t)TEGRA_NVG_CORE_C7,
+ t19x_percpu_data[cpu].wake_time,
+ 0U);
} else if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
@@ -357,11 +381,13 @@ int32_t tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
*/
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();
@@ -370,6 +396,52 @@ int32_t tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
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
+ */
+ mmio_write_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);
+ mmio_write_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);
+ mmio_write_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);
+
+ /*
* 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
@@ -403,8 +475,7 @@ int32_t tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
__dead2 void tegra_soc_prepare_system_off(void)
{
/* System power off */
-
- /* SC8 */
+ mce_system_shutdown();
wfi();
@@ -416,5 +487,8 @@ __dead2 void tegra_soc_prepare_system_off(void)
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_setup.c b/plat/nvidia/tegra/soc/t194/plat_setup.c
index 8c5710557d..3b582444c0 100644
--- a/plat/nvidia/tegra/soc/t194/plat_setup.c
+++ b/plat/nvidia/tegra/soc/t194/plat_setup.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -197,12 +197,13 @@ void plat_enable_console(int32_t id)
******************************************************************************/
void plat_early_platform_setup(void)
{
-
/* sanity check MCE firmware compatibility */
mce_verify_firmware_version();
- /* Program XUSB STREAMIDs
- * Xavier XUSB has support for XUSB virtualization. It will have one
+ /*
+ * 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.
@@ -227,14 +228,8 @@ void plat_early_platform_setup(void)
* 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
- *
- * Known Limitations:
- * If xusb interface disables SMMU in XUSB DT in non-virtualization
- * setup then there will be SMMU fault. We need to use WAR at
- * https:\\git-master.nvidia.com/r/1529227/ to the issue.
- *
- * More details can be found in the bug 1971161
+ * above registers to support both virtualization and
+ * non-virtualization platforms
*/
mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
XUSB_PADCTL_HOST_AXI_STREAMID_PF_0, TEGRA_SID_XUSB_HOST);
@@ -298,9 +293,11 @@ plat_params_from_bl2_t *plat_get_bl31_plat_params(void)
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();
+#endif
}
diff --git a/plat/nvidia/tegra/soc/t194/platform_t194.mk b/plat/nvidia/tegra/soc/t194/platform_t194.mk
index 5ec1af2966..f114b7e5be 100644
--- a/plat/nvidia/tegra/soc/t194/platform_t194.mk
+++ b/plat/nvidia/tegra/soc/t194/platform_t194.mk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
+# Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -8,17 +8,8 @@
ENABLE_CONSOLE_SPE := 0
$(eval $(call add_define,ENABLE_CONSOLE_SPE))
-ENABLE_ROC_FOR_ORDERING_CLIENT_REQUESTS := 0
-$(eval $(call add_define,ENABLE_ROC_FOR_ORDERING_CLIENT_REQUESTS))
-
-RELOCATE_TO_BL31_BASE := 1
-$(eval $(call add_define,RELOCATE_TO_BL31_BASE))
-
-ENABLE_CHIP_VERIFICATION_HARNESS := 0
-$(eval $(call add_define,ENABLE_CHIP_VERIFICATION_HARNESS))
-
-ENABLE_SMMU_DEVICE := 1
-$(eval $(call add_define,ENABLE_SMMU_DEVICE))
+ENABLE_STRICT_CHECKING_MODE := 1
+$(eval $(call add_define,ENABLE_STRICT_CHECKING_MODE))
RESET_TO_BL31 := 1
diff --git a/plat/renesas/rcar/bl2_plat_setup.c b/plat/renesas/rcar/bl2_plat_setup.c
index b4762f3309..193d80e708 100644
--- a/plat/renesas/rcar/bl2_plat_setup.c
+++ b/plat/renesas/rcar/bl2_plat_setup.c
@@ -415,6 +415,9 @@ static void bl2_populate_compatible_string(void *dt)
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) {
diff --git a/plat/rpi/common/rpi3_pm.c b/plat/rpi/common/rpi3_pm.c
index 8c2d070c44..2a6bf076b0 100644
--- a/plat/rpi/common/rpi3_pm.c
+++ b/plat/rpi/common/rpi3_pm.c
@@ -123,6 +123,15 @@ static void rpi3_pwr_domain_off(const psci_power_state_t *target_state)
#endif
}
+void __dead2 plat_secondary_cold_boot_setup(void);
+
+static void __dead2
+rpi3_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 turned on. The
* mpidr determines the CPU to be turned on.
@@ -224,6 +233,7 @@ static void __dead2 rpi3_system_off(void)
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_pwr_down_wfi = rpi3_pwr_domain_pwr_down_wfi,
.pwr_domain_on = rpi3_pwr_domain_on,
.pwr_domain_on_finish = rpi3_pwr_domain_on_finish,
.system_off = rpi3_system_off,
diff --git a/plat/st/common/bl2_io_storage.c b/plat/st/common/bl2_io_storage.c
index 38b2a0bd79..3ec7d4048a 100644
--- a/plat/st/common/bl2_io_storage.c
+++ b/plat/st/common/bl2_io_storage.c
@@ -14,11 +14,17 @@
#include <drivers/io/io_block.h>
#include <drivers/io/io_driver.h>
#include <drivers/io/io_dummy.h>
+#include <drivers/io/io_mtd.h>
#include <drivers/io/io_storage.h>
#include <drivers/mmc.h>
#include <drivers/partition/partition.h>
+#include <drivers/raw_nand.h>
+#include <drivers/spi_nand.h>
+#include <drivers/spi_nor.h>
#include <drivers/st/io_mmc.h>
#include <drivers/st/io_stm32image.h>
+#include <drivers/st/stm32_fmc2_nand.h>
+#include <drivers/st/stm32_qspi.h>
#include <drivers/st/stm32_sdmmc2.h>
#include <lib/mmio.h>
#include <lib/utils.h>
@@ -30,7 +36,9 @@ static uintptr_t dummy_dev_handle;
static uintptr_t dummy_dev_spec;
static uintptr_t image_dev_handle;
+static uintptr_t storage_dev_handle;
+#if STM32MP_SDMMC || STM32MP_EMMC
static io_block_spec_t gpt_block_spec = {
.offset = 0,
.length = 34 * MMC_BLOCK_SIZE, /* Size of GPT table */
@@ -51,8 +59,41 @@ static const io_block_dev_spec_t mmc_block_dev_spec = {
.block_size = MMC_BLOCK_SIZE,
};
-static uintptr_t storage_dev_handle;
static const io_dev_connector_t *mmc_dev_con;
+#endif /* STM32MP_SDMMC || STM32MP_EMMC */
+
+#if STM32MP_SPI_NOR
+static io_mtd_dev_spec_t spi_nor_dev_spec = {
+ .ops = {
+ .init = spi_nor_init,
+ .read = spi_nor_read,
+ },
+};
+#endif
+
+#if STM32MP_RAW_NAND
+static io_mtd_dev_spec_t nand_dev_spec = {
+ .ops = {
+ .init = nand_raw_init,
+ .read = nand_read,
+ },
+};
+
+static const io_dev_connector_t *nand_dev_con;
+#endif
+
+#if STM32MP_SPI_NAND
+static io_mtd_dev_spec_t spi_nand_dev_spec = {
+ .ops = {
+ .init = spi_nand_init,
+ .read = nand_read,
+ },
+};
+#endif
+
+#if STM32MP_SPI_NAND || STM32MP_SPI_NOR
+static const io_dev_connector_t *spi_dev_con;
+#endif
#ifdef AARCH32_SP_OPTEE
static const struct stm32image_part_info optee_header_partition_spec = {
@@ -96,7 +137,7 @@ enum {
IMG_IDX_NUM
};
-static struct stm32image_device_info stm32image_dev_info_spec = {
+static struct stm32image_device_info stm32image_dev_info_spec __unused = {
.lba_size = MMC_BLOCK_SIZE,
.part_info[IMG_IDX_BL33] = {
.name = BL33_IMAGE_NAME,
@@ -123,7 +164,7 @@ static io_block_spec_t stm32image_block_spec = {
.length = 0,
};
-static const io_dev_connector_t *stm32image_dev_con;
+static const io_dev_connector_t *stm32image_dev_con __unused;
static int open_dummy(const uintptr_t spec);
static int open_image(const uintptr_t spec);
@@ -169,11 +210,13 @@ static const struct plat_io_policy policies[] = {
.image_spec = (uintptr_t)&bl33_partition_spec,
.check = open_image
},
+#if STM32MP_SDMMC || STM32MP_EMMC
[GPT_IMAGE_ID] = {
.dev_handle = &storage_dev_handle,
.image_spec = (uintptr_t)&gpt_block_spec,
.check = open_storage
},
+#endif
[STM32_IMAGE_ID] = {
.dev_handle = &storage_dev_handle,
.image_spec = (uintptr_t)&stm32image_block_spec,
@@ -205,6 +248,15 @@ static void print_boot_device(boot_api_context_t *boot_context)
case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC:
INFO("Using EMMC\n");
break;
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NOR_QSPI:
+ INFO("Using QSPI NOR\n");
+ break;
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_FMC:
+ INFO("Using FMC NAND\n");
+ break;
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_QSPI:
+ INFO("Using SPI NAND\n");
+ break;
default:
ERROR("Boot interface not found\n");
panic();
@@ -216,6 +268,7 @@ static void print_boot_device(boot_api_context_t *boot_context)
}
}
+#if STM32MP_SDMMC || STM32MP_EMMC
static void boot_mmc(enum mmc_device_type mmc_dev_type,
uint16_t boot_interface_instance)
{
@@ -305,6 +358,167 @@ static void boot_mmc(enum mmc_device_type mmc_dev_type,
&image_dev_handle);
assert(io_result == 0);
}
+#endif /* STM32MP_SDMMC || STM32MP_EMMC */
+
+#if STM32MP_SPI_NOR
+static void boot_spi_nor(boot_api_context_t *boot_context)
+{
+ int io_result __unused;
+ uint8_t idx;
+ struct stm32image_part_info *part;
+
+ io_result = stm32_qspi_init();
+ assert(io_result == 0);
+
+ io_result = register_io_dev_mtd(&spi_dev_con);
+ assert(io_result == 0);
+
+ /* Open connections to device */
+ io_result = io_dev_open(spi_dev_con,
+ (uintptr_t)&spi_nor_dev_spec,
+ &storage_dev_handle);
+ assert(io_result == 0);
+
+ stm32image_dev_info_spec.device_size = spi_nor_dev_spec.device_size;
+
+ idx = IMG_IDX_BL33;
+ part = &stm32image_dev_info_spec.part_info[idx];
+ part->part_offset = STM32MP_NOR_BL33_OFFSET;
+ part->bkp_offset = 0U;
+
+#ifdef AARCH32_SP_OPTEE
+ idx = IMG_IDX_OPTEE_HEADER;
+ part = &stm32image_dev_info_spec.part_info[idx];
+ part->part_offset = STM32MP_NOR_TEEH_OFFSET;
+ part->bkp_offset = 0U;
+
+ idx = IMG_IDX_OPTEE_PAGED;
+ part = &stm32image_dev_info_spec.part_info[idx];
+ part->part_offset = STM32MP_NOR_TEED_OFFSET;
+ part->bkp_offset = 0U;
+
+ idx = IMG_IDX_OPTEE_PAGER;
+ part = &stm32image_dev_info_spec.part_info[idx];
+ part->part_offset = STM32MP_NOR_TEEX_OFFSET;
+ part->bkp_offset = 0U;
+#endif
+
+ io_result = register_io_dev_stm32image(&stm32image_dev_con);
+ assert(io_result == 0);
+
+ io_result = io_dev_open(stm32image_dev_con,
+ (uintptr_t)&stm32image_dev_info_spec,
+ &image_dev_handle);
+ assert(io_result == 0);
+}
+#endif /* STM32MP_SPI_NOR */
+
+#if STM32MP_RAW_NAND
+static void boot_fmc2_nand(boot_api_context_t *boot_context)
+{
+ int io_result __unused;
+ uint8_t idx;
+ struct stm32image_part_info *part;
+
+ io_result = stm32_fmc2_init();
+ assert(io_result == 0);
+
+ /* Register the IO device on this platform */
+ io_result = register_io_dev_mtd(&nand_dev_con);
+ assert(io_result == 0);
+
+ /* Open connections to device */
+ io_result = io_dev_open(nand_dev_con, (uintptr_t)&nand_dev_spec,
+ &storage_dev_handle);
+ assert(io_result == 0);
+
+ stm32image_dev_info_spec.device_size = nand_dev_spec.device_size;
+
+ idx = IMG_IDX_BL33;
+ part = &stm32image_dev_info_spec.part_info[idx];
+ part->part_offset = STM32MP_NAND_BL33_OFFSET;
+ part->bkp_offset = nand_dev_spec.erase_size;
+
+#ifdef AARCH32_SP_OPTEE
+ idx = IMG_IDX_OPTEE_HEADER;
+ part = &stm32image_dev_info_spec.part_info[idx];
+ part->part_offset = STM32MP_NAND_TEEH_OFFSET;
+ part->bkp_offset = nand_dev_spec.erase_size;
+
+ idx = IMG_IDX_OPTEE_PAGED;
+ part = &stm32image_dev_info_spec.part_info[idx];
+ part->part_offset = STM32MP_NAND_TEED_OFFSET;
+ part->bkp_offset = nand_dev_spec.erase_size;
+
+ idx = IMG_IDX_OPTEE_PAGER;
+ part = &stm32image_dev_info_spec.part_info[idx];
+ part->part_offset = STM32MP_NAND_TEEX_OFFSET;
+ part->bkp_offset = nand_dev_spec.erase_size;
+#endif
+
+ io_result = register_io_dev_stm32image(&stm32image_dev_con);
+ assert(io_result == 0);
+
+ io_result = io_dev_open(stm32image_dev_con,
+ (uintptr_t)&stm32image_dev_info_spec,
+ &image_dev_handle);
+ assert(io_result == 0);
+}
+#endif /* STM32MP_RAW_NAND */
+
+#if STM32MP_SPI_NAND
+static void boot_spi_nand(boot_api_context_t *boot_context)
+{
+ int io_result __unused;
+ uint8_t idx;
+ struct stm32image_part_info *part;
+
+ io_result = stm32_qspi_init();
+ assert(io_result == 0);
+
+ io_result = register_io_dev_mtd(&spi_dev_con);
+ assert(io_result == 0);
+
+ /* Open connections to device */
+ io_result = io_dev_open(spi_dev_con,
+ (uintptr_t)&spi_nand_dev_spec,
+ &storage_dev_handle);
+ assert(io_result == 0);
+
+ stm32image_dev_info_spec.device_size =
+ spi_nand_dev_spec.device_size;
+
+ idx = IMG_IDX_BL33;
+ part = &stm32image_dev_info_spec.part_info[idx];
+ part->part_offset = STM32MP_NAND_BL33_OFFSET;
+ part->bkp_offset = spi_nand_dev_spec.erase_size;
+
+#ifdef AARCH32_SP_OPTEE
+ idx = IMG_IDX_OPTEE_HEADER;
+ part = &stm32image_dev_info_spec.part_info[idx];
+ part->part_offset = STM32MP_NAND_TEEH_OFFSET;
+ part->bkp_offset = spi_nand_dev_spec.erase_size;
+
+ idx = IMG_IDX_OPTEE_PAGED;
+ part = &stm32image_dev_info_spec.part_info[idx];
+ part->part_offset = STM32MP_NAND_TEED_OFFSET;
+ part->bkp_offset = spi_nand_dev_spec.erase_size;
+
+ idx = IMG_IDX_OPTEE_PAGER;
+ part = &stm32image_dev_info_spec.part_info[idx];
+ part->part_offset = STM32MP_NAND_TEEX_OFFSET;
+ part->bkp_offset = spi_nand_dev_spec.erase_size;
+#endif
+
+ io_result = register_io_dev_stm32image(&stm32image_dev_con);
+ assert(io_result == 0);
+
+ io_result = io_dev_open(stm32image_dev_con,
+ (uintptr_t)&stm32image_dev_info_spec,
+ &image_dev_handle);
+ assert(io_result == 0);
+}
+#endif /* STM32MP_SPI_NAND */
void stm32mp_io_setup(void)
{
@@ -328,14 +542,36 @@ void stm32mp_io_setup(void)
assert(io_result == 0);
switch (boot_context->boot_interface_selected) {
+#if STM32MP_SDMMC
case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_SD:
dmbsy();
boot_mmc(MMC_IS_SD, boot_context->boot_interface_instance);
break;
+#endif
+#if STM32MP_EMMC
case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC:
dmbsy();
boot_mmc(MMC_IS_EMMC, boot_context->boot_interface_instance);
break;
+#endif
+#if STM32MP_SPI_NOR
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NOR_QSPI:
+ dmbsy();
+ boot_spi_nor(boot_context);
+ break;
+#endif
+#if STM32MP_RAW_NAND
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_FMC:
+ dmbsy();
+ boot_fmc2_nand(boot_context);
+ break;
+#endif
+#if STM32MP_SPI_NAND
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_QSPI:
+ dmbsy();
+ boot_spi_nand(boot_context);
+ break;
+#endif
default:
ERROR("Boot interface %d not supported\n",
diff --git a/plat/st/common/include/stm32mp_dt.h b/plat/st/common/include/stm32mp_dt.h
index 74b01b3aa5..a29d9148d0 100644
--- a/plat/st/common/include/stm32mp_dt.h
+++ b/plat/st/common/include/stm32mp_dt.h
@@ -32,6 +32,8 @@ uint32_t fdt_read_uint32_default(int node, const char *prop_name,
uint32_t dflt_value);
int fdt_read_uint32_array(int node, const char *prop_name,
uint32_t *array, uint32_t count);
+int fdt_get_reg_props_by_name(int node, const char *name, uintptr_t *base,
+ size_t *size);
int dt_set_stdout_pinctrl(void);
void dt_fill_device_info(struct dt_node_info *info, int node);
int dt_get_node(struct dt_node_info *info, int offset, const char *compat);
diff --git a/plat/st/common/stm32mp_dt.c b/plat/st/common/stm32mp_dt.c
index 17da4904ac..4fa796f0c8 100644
--- a/plat/st/common/stm32mp_dt.c
+++ b/plat/st/common/stm32mp_dt.c
@@ -93,6 +93,46 @@ uint8_t fdt_get_status(int node)
}
/*******************************************************************************
+ * 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.
+ ******************************************************************************/
+int fdt_get_node_parent_address_cells(int node)
+{
+ int parent;
+
+ parent = fdt_parent_offset(fdt, node);
+ if (parent < 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ return fdt_address_cells(fdt, parent);
+}
+
+/*******************************************************************************
+ * This function returns the size cells from the node parent.
+ * Returns:
+ * - #size-cells value if success.
+ * - invalid value if error.
+ * - a default value if undefined #size-cells property as per libfdt
+ * implementation.
+ ******************************************************************************/
+int fdt_get_node_parent_size_cells(int node)
+{
+ int parent;
+
+ parent = fdt_parent_offset(fdt, node);
+ if (parent < 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ return fdt_size_cells(fdt, parent);
+}
+
+/*******************************************************************************
* This function reads a value of a node property (generic use of fdt
* library).
* Returns value if success, and a default value if property not found.
@@ -146,6 +186,46 @@ int fdt_read_uint32_array(int node, const char *prop_name, uint32_t *array,
}
/*******************************************************************************
+ * This function fills reg node info (base & size) with an index found by
+ * checking the reg-names node.
+ * Returns 0 on success and a negative FDT error code on failure.
+ ******************************************************************************/
+int fdt_get_reg_props_by_name(int node, const char *name, uintptr_t *base,
+ size_t *size)
+{
+ const fdt32_t *cuint;
+ int index, len;
+
+ assert((fdt_get_node_parent_address_cells(node) == 1) &&
+ (fdt_get_node_parent_size_cells(node) == 1));
+
+ index = fdt_stringlist_search(fdt, node, "reg-names", name);
+ if (index < 0) {
+ return index;
+ }
+
+ cuint = fdt_getprop(fdt, node, "reg", &len);
+ if (cuint == NULL) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ if ((index * (int)sizeof(uint32_t)) > len) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ cuint += index << 1;
+ if (base != NULL) {
+ *base = fdt32_to_cpu(*cuint);
+ }
+ cuint++;
+ if (size != NULL) {
+ *size = fdt32_to_cpu(*cuint);
+ }
+
+ return 0;
+}
+
+/*******************************************************************************
* This function gets the stdout path node.
* It reads the value indicated inside the device tree.
* Returns node offset on success and a negative FDT error code on failure.
@@ -215,6 +295,8 @@ void dt_fill_device_info(struct dt_node_info *info, int node)
{
const fdt32_t *cuint;
+ assert(fdt_get_node_parent_address_cells(node) == 1);
+
cuint = fdt_getprop(fdt, node, "reg", NULL);
if (cuint != NULL) {
info->base = fdt32_to_cpu(*cuint);
@@ -309,6 +391,9 @@ uintptr_t dt_get_ddrctrl_base(void)
return 0;
}
+ assert((fdt_get_node_parent_address_cells(node) == 1) &&
+ (fdt_get_node_parent_size_cells(node) == 1));
+
if (fdt_read_uint32_array(node, "reg", array, 4) < 0) {
return 0;
}
@@ -331,6 +416,9 @@ uintptr_t dt_get_ddrphyc_base(void)
return 0;
}
+ assert((fdt_get_node_parent_address_cells(node) == 1) &&
+ (fdt_get_node_parent_size_cells(node) == 1));
+
if (fdt_read_uint32_array(node, "reg", array, 4) < 0) {
return 0;
}
@@ -353,6 +441,8 @@ uintptr_t dt_get_pwr_base(void)
return 0;
}
+ assert(fdt_get_node_parent_address_cells(node) == 1);
+
cuint = fdt_getprop(fdt, node, "reg", NULL);
if (cuint == NULL) {
return 0;
@@ -415,6 +505,8 @@ uintptr_t dt_get_syscfg_base(void)
return 0;
}
+ assert(fdt_get_node_parent_address_cells(node) == 1);
+
cuint = fdt_getprop(fdt, node, "reg", NULL);
if (cuint == NULL) {
return 0;
diff --git a/plat/st/stm32mp1/include/boot_api.h b/plat/st/stm32mp1/include/boot_api.h
index c80aef6dd7..c16639ac40 100644
--- a/plat/st/stm32mp1/include/boot_api.h
+++ b/plat/st/stm32mp1/include/boot_api.h
@@ -33,6 +33,15 @@
/* 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 QSPI NAND */
+#define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_QSPI 0x7U
+
/**
* @brief Possible value of boot context field 'EmmcXferStatus'
*/
diff --git a/plat/st/stm32mp1/include/platform_def.h b/plat/st/stm32mp1/include/platform_def.h
index 263e6d6e1f..450a9d404c 100644
--- a/plat/st/stm32mp1/include/platform_def.h
+++ b/plat/st/stm32mp1/include/platform_def.h
@@ -51,6 +51,7 @@
#define MAX_IO_DEVICES U(4)
#define MAX_IO_HANDLES U(4)
#define MAX_IO_BLOCK_DEVICES U(1)
+#define MAX_IO_MTD_DEVICES U(1)
/*******************************************************************************
* BL2 specific defines.
diff --git a/plat/st/stm32mp1/include/stm32mp1_boot_device.h b/plat/st/stm32mp1/include/stm32mp1_boot_device.h
new file mode 100644
index 0000000000..a74598395f
--- /dev/null
+++ b/plat/st/stm32mp1/include/stm32mp1_boot_device.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP1_BOOT_DEVICE_H
+#define STM32MP1_BOOT_DEVICE_H
+
+#include <drivers/raw_nand.h>
+#include <drivers/spi_nand.h>
+#include <drivers/spi_nor.h>
+
+int plat_get_raw_nand_data(struct rawnand_device *device);
+int plat_get_spi_nand_data(struct spinand_device *device);
+int plat_get_nor_data(struct nor_device *device);
+
+#endif /* STM32MP1_BOOT_DEVICE_H */
diff --git a/plat/st/stm32mp1/platform.mk b/plat/st/stm32mp1/platform.mk
index 90b3e3c1e5..b86287b669 100644
--- a/plat/st/stm32mp1/platform.mk
+++ b/plat/st/stm32mp1/platform.mk
@@ -24,6 +24,29 @@ PLAT_PARTITION_MAX_ENTRIES := $(shell echo $$(($(STM32_TF_A_COPIES) + 1)))
endif
$(eval $(call add_define,PLAT_PARTITION_MAX_ENTRIES))
+# Boot devices
+STM32MP_EMMC ?= 0
+STM32MP_SDMMC ?= 0
+STM32MP_RAW_NAND ?= 0
+STM32MP_SPI_NAND ?= 0
+STM32MP_SPI_NOR ?= 0
+
+ifeq ($(filter 1,${STM32MP_EMMC} ${STM32MP_SDMMC} ${STM32MP_RAW_NAND} \
+ ${STM32MP_SPI_NAND} ${STM32MP_SPI_NOR}),)
+$(error "No boot device driver is enabled")
+endif
+
+$(eval $(call assert_boolean,STM32MP_EMMC))
+$(eval $(call assert_boolean,STM32MP_SDMMC))
+$(eval $(call assert_boolean,STM32MP_RAW_NAND))
+$(eval $(call assert_boolean,STM32MP_SPI_NAND))
+$(eval $(call assert_boolean,STM32MP_SPI_NOR))
+$(eval $(call add_define,STM32MP_EMMC))
+$(eval $(call add_define,STM32MP_SDMMC))
+$(eval $(call add_define,STM32MP_RAW_NAND))
+$(eval $(call add_define,STM32MP_SPI_NAND))
+$(eval $(call add_define,STM32MP_SPI_NOR))
+
PLAT_INCLUDES := -Iplat/st/common/include/
PLAT_INCLUDES += -Iplat/st/stm32mp1/include/
@@ -70,6 +93,7 @@ PLAT_BL_COMMON_SOURCES += drivers/arm/tzc/tzc400.c \
BL2_SOURCES += drivers/io/io_block.c \
drivers/io/io_dummy.c \
+ drivers/io/io_mtd.c \
drivers/io/io_storage.c \
drivers/st/crypto/stm32_hash.c \
drivers/st/io/io_stm32image.c \
@@ -77,11 +101,40 @@ BL2_SOURCES += drivers/io/io_block.c \
plat/st/common/bl2_io_storage.c \
plat/st/stm32mp1/bl2_plat_setup.c
+ifneq ($(filter 1,${STM32MP_EMMC} ${STM32MP_SDMMC}),)
BL2_SOURCES += drivers/mmc/mmc.c \
drivers/partition/gpt.c \
drivers/partition/partition.c \
drivers/st/io/io_mmc.c \
drivers/st/mmc/stm32_sdmmc2.c
+endif
+
+ifeq (${STM32MP_RAW_NAND},1)
+$(eval $(call add_define_val,NAND_ONFI_DETECT,1))
+BL2_SOURCES += drivers/mtd/nand/raw_nand.c \
+ drivers/st/fmc/stm32_fmc2_nand.c
+endif
+
+ifeq (${STM32MP_SPI_NAND},1)
+BL2_SOURCES += drivers/mtd/nand/spi_nand.c
+endif
+
+ifeq (${STM32MP_SPI_NOR},1)
+BL2_SOURCES += drivers/mtd/nor/spi_nor.c
+endif
+
+ifneq ($(filter 1,${STM32MP_SPI_NAND} ${STM32MP_SPI_NOR}),)
+BL2_SOURCES += drivers/mtd/spi-mem/spi_mem.c \
+ drivers/st/spi/stm32_qspi.c
+endif
+
+ifneq ($(filter 1,${STM32MP_RAW_NAND} ${STM32MP_SPI_NAND}),)
+BL2_SOURCES += drivers/mtd/nand/core.c
+endif
+
+ifneq ($(filter 1,${STM32MP_RAW_NAND} ${STM32MP_SPI_NAND} ${STM32MP_SPI_NOR}),)
+BL2_SOURCES += plat/st/stm32mp1/stm32mp1_boot_device.c
+endif
BL2_SOURCES += drivers/st/ddr/stm32mp1_ddr.c \
drivers/st/ddr/stm32mp1_ram.c
diff --git a/plat/st/stm32mp1/stm32mp1_boot_device.c b/plat/st/stm32mp1/stm32mp1_boot_device.c
new file mode 100644
index 0000000000..2d8eccff7d
--- /dev/null
+++ b/plat/st/stm32mp1/stm32mp1_boot_device.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <drivers/nand.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+
+#define SZ_512 0x200U
+#define SZ_64M 0x4000000U
+
+#if STM32MP_RAW_NAND || STM32MP_SPI_NAND
+static int get_data_from_otp(struct nand_device *nand_dev, bool is_slc)
+{
+ int result;
+ uint32_t nand_param;
+
+ /* Check if NAND parameters are stored in OTP */
+ result = bsec_shadow_read_otp(&nand_param, NAND_OTP);
+ if (result != BSEC_OK) {
+ ERROR("BSEC: NAND_OTP Error %i\n", result);
+ return -EACCES;
+ }
+
+ if (nand_param == 0U) {
+ return 0;
+ }
+
+ if ((nand_param & NAND_PARAM_STORED_IN_OTP) == 0U) {
+ goto ecc;
+ }
+
+ /* NAND parameter shall be read from OTP */
+ if ((nand_param & NAND_WIDTH_MASK) != 0U) {
+ nand_dev->buswidth = NAND_BUS_WIDTH_16;
+ } else {
+ nand_dev->buswidth = NAND_BUS_WIDTH_8;
+ }
+
+ switch ((nand_param & NAND_PAGE_SIZE_MASK) >> NAND_PAGE_SIZE_SHIFT) {
+ case NAND_PAGE_SIZE_2K:
+ nand_dev->page_size = 0x800U;
+ break;
+
+ case NAND_PAGE_SIZE_4K:
+ nand_dev->page_size = 0x1000U;
+ break;
+
+ case NAND_PAGE_SIZE_8K:
+ nand_dev->page_size = 0x2000U;
+ break;
+
+ default:
+ ERROR("Cannot read NAND page size\n");
+ return -EINVAL;
+ }
+
+ switch ((nand_param & NAND_BLOCK_SIZE_MASK) >> NAND_BLOCK_SIZE_SHIFT) {
+ case NAND_BLOCK_SIZE_64_PAGES:
+ nand_dev->block_size = 64U * nand_dev->page_size;
+ break;
+
+ case NAND_BLOCK_SIZE_128_PAGES:
+ nand_dev->block_size = 128U * nand_dev->page_size;
+ break;
+
+ case NAND_BLOCK_SIZE_256_PAGES:
+ nand_dev->block_size = 256U * nand_dev->page_size;
+ break;
+
+ default:
+ ERROR("Cannot read NAND block size\n");
+ return -EINVAL;
+ }
+
+ nand_dev->size = ((nand_param & NAND_BLOCK_NB_MASK) >>
+ NAND_BLOCK_NB_SHIFT) *
+ NAND_BLOCK_NB_UNIT * nand_dev->block_size;
+
+ecc:
+ if (is_slc) {
+ switch ((nand_param & NAND_ECC_BIT_NB_MASK) >>
+ NAND_ECC_BIT_NB_SHIFT) {
+ case NAND_ECC_BIT_NB_1_BITS:
+ nand_dev->ecc.max_bit_corr = 1U;
+ break;
+
+ case NAND_ECC_BIT_NB_4_BITS:
+ nand_dev->ecc.max_bit_corr = 4U;
+ break;
+
+ case NAND_ECC_BIT_NB_8_BITS:
+ nand_dev->ecc.max_bit_corr = 8U;
+ break;
+
+ case NAND_ECC_ON_DIE:
+ nand_dev->ecc.mode = NAND_ECC_ONDIE;
+ break;
+
+ default:
+ if (nand_dev->ecc.max_bit_corr == 0U) {
+ ERROR("No valid eccbit number\n");
+ return -EINVAL;
+ }
+ }
+ } else {
+ /* Selected multiple plane NAND */
+ if ((nand_param & NAND_PLANE_BIT_NB_MASK) != 0U) {
+ nand_dev->nb_planes = 2U;
+ } else {
+ nand_dev->nb_planes = 1U;
+ }
+ }
+
+ VERBOSE("OTP: Block %i Page %i Size %lli\n", nand_dev->block_size,
+ nand_dev->page_size, nand_dev->size);
+
+ return 0;
+}
+#endif /* STM32MP_RAW_NAND || STM32MP_SPI_NAND */
+
+#if STM32MP_RAW_NAND
+int plat_get_raw_nand_data(struct rawnand_device *device)
+{
+ device->nand_dev->ecc.mode = NAND_ECC_HW;
+ device->nand_dev->ecc.size = SZ_512;
+
+ return get_data_from_otp(device->nand_dev, true);
+}
+#endif
+
+#if STM32MP_SPI_NAND
+int plat_get_spi_nand_data(struct spinand_device *device)
+{
+ zeromem(&device->spi_read_cache_op, sizeof(struct spi_mem_op));
+ device->spi_read_cache_op.cmd.opcode = SPI_NAND_OP_READ_FROM_CACHE_4X;
+ device->spi_read_cache_op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ device->spi_read_cache_op.addr.nbytes = 2U;
+ device->spi_read_cache_op.addr.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ device->spi_read_cache_op.dummy.nbytes = 1U;
+ device->spi_read_cache_op.dummy.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ device->spi_read_cache_op.data.buswidth = SPI_MEM_BUSWIDTH_4_LINE;
+ device->spi_read_cache_op.data.dir = SPI_MEM_DATA_IN;
+
+ return get_data_from_otp(device->nand_dev, false);
+}
+#endif
+
+#if STM32MP_SPI_NOR
+int plat_get_nor_data(struct nor_device *device)
+{
+ device->size = SZ_64M;
+
+ zeromem(&device->read_op, sizeof(struct spi_mem_op));
+ device->read_op.cmd.opcode = SPI_NOR_OP_READ_1_1_4;
+ device->read_op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ device->read_op.addr.nbytes = 3U;
+ device->read_op.addr.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ device->read_op.dummy.nbytes = 1U;
+ device->read_op.dummy.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ device->read_op.data.buswidth = SPI_MEM_BUSWIDTH_4_LINE;
+ device->read_op.data.dir = SPI_MEM_DATA_IN;
+
+ return 0;
+}
+#endif
diff --git a/plat/st/stm32mp1/stm32mp1_def.h b/plat/st/stm32mp1/stm32mp1_def.h
index a40852bde7..11b01ab882 100644
--- a/plat/st/stm32mp1/stm32mp1_def.h
+++ b/plat/st/stm32mp1/stm32mp1_def.h
@@ -23,6 +23,7 @@
#include <stm32mp_common.h>
#include <stm32mp_dt.h>
#include <stm32mp_shres_helpers.h>
+#include <stm32mp1_boot_device.h>
#include <stm32mp1_dbgmcu.h>
#include <stm32mp1_private.h>
#endif
@@ -74,7 +75,7 @@ enum ddr_type {
#endif
/* Section used inside TF binaries */
-#define STM32MP_PARAM_LOAD_SIZE U(0x00002400) /* 9 Ko for param */
+#define STM32MP_PARAM_LOAD_SIZE U(0x00002400) /* 9 KB for param */
/* 256 Octets reserved for header */
#define STM32MP_HEADER_SIZE U(0x00000100)
@@ -95,9 +96,9 @@ enum ddr_type {
STM32MP_OPTEE_BASE)
#else
#if STACK_PROTECTOR_ENABLED
-#define STM32MP_BL32_SIZE U(0x00012000) /* 72 Ko for BL32 */
+#define STM32MP_BL32_SIZE U(0x00012000) /* 72 KB for BL32 */
#else
-#define STM32MP_BL32_SIZE U(0x00011000) /* 68 Ko for BL32 */
+#define STM32MP_BL32_SIZE U(0x00011000) /* 68 KB for BL32 */
#endif
#endif
@@ -107,23 +108,23 @@ enum ddr_type {
#ifdef AARCH32_SP_OPTEE
#if STACK_PROTECTOR_ENABLED
-#define STM32MP_BL2_SIZE U(0x00019000) /* 100 Ko for BL2 */
+#define STM32MP_BL2_SIZE U(0x0001A000) /* 100 KB for BL2 */
#else
-#define STM32MP_BL2_SIZE U(0x00017000) /* 92 Ko for BL2 */
+#define STM32MP_BL2_SIZE U(0x00018000) /* 92 KB for BL2 */
#endif
#else
#if STACK_PROTECTOR_ENABLED
-#define STM32MP_BL2_SIZE U(0x00018000) /* 96 Ko for BL2 */
+#define STM32MP_BL2_SIZE U(0x00019000) /* 96 KB for BL2 */
#else
-#define STM32MP_BL2_SIZE U(0x00016000) /* 88 Ko for BL2 */
+#define STM32MP_BL2_SIZE U(0x00017000) /* 88 KB for BL2 */
#endif
#endif
#define STM32MP_BL2_BASE (STM32MP_BL32_BASE - \
STM32MP_BL2_SIZE)
-/* BL2 and BL32/sp_min require 5 tables */
-#define MAX_XLAT_TABLES 5
+/* BL2 and BL32/sp_min require 4 tables */
+#define MAX_XLAT_TABLES U(4) /* 16 KB for mapping */
/*
* MAX_MMAP_REGIONS is usually:
@@ -137,13 +138,33 @@ enum ddr_type {
#endif
/* DTB initialization value */
-#define STM32MP_DTB_SIZE U(0x00005000) /* 20Ko for DTB */
+#define STM32MP_DTB_SIZE U(0x00005000) /* 20 KB for DTB */
#define STM32MP_DTB_BASE (STM32MP_BL2_BASE - \
STM32MP_DTB_SIZE)
#define STM32MP_BL33_BASE (STM32MP_DDR_BASE + U(0x100000))
+/* Define maximum page size for NAND devices */
+#define PLATFORM_MTD_MAX_PAGE_SIZE U(0x1000)
+
+/*******************************************************************************
+ * STM32MP1 RAW partition offset for MTD devices
+ ******************************************************************************/
+#define STM32MP_NOR_BL33_OFFSET U(0x00080000)
+#ifdef AARCH32_SP_OPTEE
+#define STM32MP_NOR_TEEH_OFFSET U(0x00280000)
+#define STM32MP_NOR_TEED_OFFSET U(0x002C0000)
+#define STM32MP_NOR_TEEX_OFFSET U(0x00300000)
+#endif
+
+#define STM32MP_NAND_BL33_OFFSET U(0x00200000)
+#ifdef AARCH32_SP_OPTEE
+#define STM32MP_NAND_TEEH_OFFSET U(0x00600000)
+#define STM32MP_NAND_TEED_OFFSET U(0x00680000)
+#define STM32MP_NAND_TEEX_OFFSET U(0x00700000)
+#endif
+
/*******************************************************************************
* STM32MP1 device/io map related constants (used for MMU)
******************************************************************************/
@@ -266,6 +287,7 @@ enum ddr_type {
/* OTP offsets */
#define DATA0_OTP U(0)
#define PART_NUMBER_OTP U(1)
+#define NAND_OTP U(9)
#define PACKAGE_OTP U(16)
#define HW2_OTP U(18)
@@ -289,6 +311,45 @@ enum ddr_type {
/* 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 blocs) */
+#define NAND_BLOCK_NB_MASK GENMASK_32(26, 19)
+#define NAND_BLOCK_NB_SHIFT 19
+#define NAND_BLOCK_NB_UNIT U(256)
+
+/* NAND bus width in bits */
+#define NAND_WIDTH_MASK BIT(18)
+#define NAND_WIDTH_SHIFT 18
+
+/* NAND number of ECC bits per 512 bytes */
+#define NAND_ECC_BIT_NB_MASK GENMASK_32(17, 15)
+#define NAND_ECC_BIT_NB_SHIFT 15
+#define NAND_ECC_BIT_NB_UNSET U(0)
+#define NAND_ECC_BIT_NB_1_BITS U(1)
+#define NAND_ECC_BIT_NB_4_BITS U(2)
+#define NAND_ECC_BIT_NB_8_BITS U(3)
+#define NAND_ECC_ON_DIE U(4)
+
+/* NAND number of planes */
+#define NAND_PLANE_BIT_NB_MASK BIT(14)
+
/*******************************************************************************
* STM32MP1 TAMP
******************************************************************************/
diff --git a/plat/xilinx/common/include/plat_startup.h b/plat/xilinx/common/include/plat_startup.h
new file mode 100644
index 0000000000..66e7933733
--- /dev/null
+++ b/plat/xilinx/common/include/plat_startup.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_STARTUP_H
+#define PLAT_STARTUP_H
+
+/* For FSBL handover */
+enum fsbl_handoff {
+ FSBL_HANDOFF_SUCCESS = 0,
+ FSBL_HANDOFF_NO_STRUCT,
+ FSBL_HANDOFF_INVAL_STRUCT,
+ FSBL_HANDOFF_TOO_MANY_PARTS
+};
+
+enum fsbl_handoff fsbl_atf_handover(entry_point_info_t *bl32_image_ep_info,
+ entry_point_info_t *bl33_image_ep_info,
+ uint64_t atf_handoff_addr);
+
+#endif /* PLAT_STARTUP_H */
diff --git a/plat/xilinx/zynqmp/pm_service/pm_client.h b/plat/xilinx/common/include/pm_client.h
index adbb76f9b1..e91bb8f6c2 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_client.h
+++ b/plat/xilinx/common/include/pm_client.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -19,11 +19,14 @@
void pm_client_suspend(const struct pm_proc *proc, unsigned int state);
void pm_client_abort_suspend(void);
void pm_client_wakeup(const struct pm_proc *proc);
-enum pm_ret_status set_ocm_retention(void);
-enum pm_ret_status pm_set_suspend_mode(uint32_t mode);
-const struct pm_proc *pm_get_proc_by_node(enum pm_node_id nid);
/* Global variables to be set in pm_client.c */
extern const struct pm_proc *primary_proc;
+#ifndef VERSAL_PLATFORM
+enum pm_ret_status set_ocm_retention(void);
+enum pm_ret_status pm_set_suspend_mode(uint32_t mode);
+const struct pm_proc *pm_get_proc_by_node(enum pm_node_id nid);
+#endif
+
#endif /* PM_CLIENT_H */
diff --git a/plat/xilinx/common/include/pm_ipi.h b/plat/xilinx/common/include/pm_ipi.h
index 16db5c5482..7bcf596267 100644
--- a/plat/xilinx/common/include/pm_ipi.h
+++ b/plat/xilinx/common/include/pm_ipi.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -26,5 +26,8 @@ void pm_ipi_buff_read_callb(unsigned int *value, size_t count);
void pm_ipi_irq_enable(const struct pm_proc *proc);
void pm_ipi_irq_clear(const struct pm_proc *proc);
uint32_t pm_ipi_irq_status(const struct pm_proc *proc);
+#if ZYNQMP_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/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.c b/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c
index c499d78e91..f531158853 100644
--- a/plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.c
+++ b/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
diff --git a/plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.h b/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.h
index 197c788193..10682d8356 100644
--- a/plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.h
+++ b/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
diff --git a/plat/xilinx/zynqmp/plat_startup.c b/plat/xilinx/common/plat_startup.c
index cd2c3bac6e..8c9a049dd9 100644
--- a/plat/xilinx/zynqmp/plat_startup.c
+++ b/plat/xilinx/common/plat_startup.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -8,10 +8,8 @@
#include <arch_helpers.h>
#include <common/debug.h>
-#include <lib/mmio.h>
-#include <plat_private.h>
+#include <plat_startup.h>
-#include "zynqmp_def.h"
/*
* ATFHandoffParams
@@ -147,6 +145,7 @@ static int get_fsbl_estate(const struct xfsbl_partition *partition)
* 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.
@@ -154,12 +153,11 @@ static int get_fsbl_estate(const struct xfsbl_partition *partition)
* 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)
+enum fsbl_handoff fsbl_atf_handover(entry_point_info_t *bl32,
+ entry_point_info_t *bl33,
+ uint64_t atf_handoff_addr)
{
- uint64_t atf_handoff_addr;
const struct xfsbl_atf_handoff_params *ATFHandoffParams;
-
- atf_handoff_addr = mmio_read_32(PMU_GLOBAL_GEN_STORAGE6);
assert((atf_handoff_addr < BL31_BASE) ||
(atf_handoff_addr > (uint64_t)&__BL31_END__));
if (!atf_handoff_addr) {
diff --git a/plat/xilinx/common/pm_service/pm_ipi.c b/plat/xilinx/common/pm_service/pm_ipi.c
index 034cd5bc8c..c83d25b0d9 100644
--- a/plat/xilinx/common/pm_service/pm_ipi.c
+++ b/plat/xilinx/common/pm_service/pm_ipi.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -57,6 +57,9 @@ static enum pm_ret_status pm_ipi_send_common(const struct pm_proc *proc,
uintptr_t buffer_base = proc->ipi->buffer_base +
IPI_BUFFER_TARGET_REMOTE_OFFSET +
IPI_BUFFER_REQ_OFFSET;
+#if ZYNQMP_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++) {
@@ -132,6 +135,10 @@ static enum pm_ret_status pm_ipi_buff_read(const struct pm_proc *proc,
unsigned int *value, size_t count)
{
size_t i;
+#if ZYNQMP_IPI_CRC_CHECK
+ size_t j;
+ unsigned int response_payload[PAYLOAD_ARG_CNT];
+#endif
uintptr_t buffer_base = proc->ipi->buffer_base +
IPI_BUFFER_TARGET_REMOTE_OFFSET +
IPI_BUFFER_RESP_OFFSET;
@@ -147,6 +154,16 @@ static enum pm_ret_status pm_ipi_buff_read(const struct pm_proc *proc,
*value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
value++;
}
+#if ZYNQMP_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);
}
@@ -162,6 +179,10 @@ static enum pm_ret_status pm_ipi_buff_read(const struct pm_proc *proc,
void pm_ipi_buff_read_callb(unsigned int *value, size_t count)
{
size_t i;
+#if ZYNQMP_IPI_CRC_CHECK
+ size_t j;
+ unsigned int response_payload[PAYLOAD_ARG_CNT];
+#endif
uintptr_t buffer_base = IPI_BUFFER_REMOTE_BASE +
IPI_BUFFER_TARGET_LOCAL_OFFSET +
IPI_BUFFER_REQ_OFFSET;
@@ -173,6 +194,16 @@ void pm_ipi_buff_read_callb(unsigned int *value, size_t count)
*value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
value++;
}
+#if ZYNQMP_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
}
/**
@@ -228,3 +259,34 @@ uint32_t pm_ipi_irq_status(const struct pm_proc *proc)
else
return 0;
}
+
+#if ZYNQMP_IPI_CRC_CHECK
+uint32_t calculate_crc(uint32_t *payload, 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
index 587b797d76..2fa8476584 100644
--- a/plat/xilinx/versal/aarch64/versal_common.c
+++ b/plat/xilinx/versal/aarch64/versal_common.c
@@ -1,18 +1,18 @@
/*
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * 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>
-#include "../versal_def.h"
-#include "../versal_private.h"
-
/*
* Table of regions to map using the MMU.
* This doesn't include TZRAM as the 'mem_layout' argument passed to
@@ -22,6 +22,8 @@ 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 }
};
@@ -39,11 +41,10 @@ void versal_config_setup(void)
{
uint32_t val;
- versal_print_platform_name();
+ /* Configure IPI data for versal */
+ versal_ipi_config_table_init();
- mmio_write_32(VERSAL_CRL_IOU_SWITCH_CTRL,
- VERSAL_IOU_SWITCH_CTRL_CLKACT_BIT |
- (0x20 << VERSAL_IOU_SWITCH_CTRL_DIVISOR0_SHIFT));
+ versal_print_platform_name();
/* Global timer init - Program time stamp reference clk */
val = mmio_read_32(VERSAL_CRL_TIMESTAMP_REF_CTRL);
@@ -66,11 +67,3 @@ unsigned int plat_get_syscnt_freq2(void)
return VERSAL_CPU_CLOCK;
}
-uintptr_t plat_get_ns_image_entrypoint(void)
-{
-#ifdef PRELOADED_BL33_BASE
- return PRELOADED_BL33_BASE;
-#else
- return PLAT_VERSAL_NS_IMAGE_OFFSET;
-#endif
-}
diff --git a/plat/xilinx/versal/bl31_versal_setup.c b/plat/xilinx/versal/bl31_versal_setup.c
index d7e07e036a..a5cf05e9af 100644
--- a/plat/xilinx/versal/bl31_versal_setup.c
+++ b/plat/xilinx/versal/bl31_versal_setup.c
@@ -1,21 +1,24 @@
/*
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. 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/pl011.h>
#include <drivers/console.h>
+#include <lib/mmio.h>
#include <lib/xlat_tables/xlat_tables.h>
#include <plat/common/platform.h>
-
-#include "versal_private.h"
+#include <versal_def.h>
+#include <plat_private.h>
+#include <plat_startup.h>
static entry_point_info_t bl32_image_ep_info;
static entry_point_info_t bl33_image_ep_info;
@@ -38,6 +41,18 @@ entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
}
/*
+ * 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
@@ -46,6 +61,7 @@ entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
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;
/* Initialize the console to provide early debug support */
int rc = console_pl011_register(VERSAL_UART_BASE,
@@ -77,12 +93,15 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
SET_PARAM_HEAD(&bl33_image_ep_info, PARAM_EP, VERSION_1, 0);
SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
- /* use build time defaults in JTAG boot mode */
- bl32_image_ep_info.pc = BL32_BASE;
- bl32_image_ep_info.spsr = 0;
- bl33_image_ep_info.pc = plat_get_ns_image_entrypoint();
- bl33_image_ep_info.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX,
- DISABLE_ALL_EXCEPTIONS);
+ 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) {
+ bl31_set_default_config();
+ } else if (ret != FSBL_HANDOFF_SUCCESS) {
+ panic();
+ }
NOTICE("BL31: Secure code at 0x%lx\n", bl32_image_ep_info.pc);
NOTICE("BL31: Non secure code at 0x%lx\n", bl33_image_ep_info.pc);
@@ -104,6 +123,9 @@ void bl31_plat_runtime_setup(void)
*/
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),
diff --git a/plat/xilinx/versal/include/plat_ipi.h b/plat/xilinx/versal/include/plat_ipi.h
new file mode 100644
index 0000000000..6b08f322d1
--- /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 0x0U
+#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_pm_common.h b/plat/xilinx/versal/include/plat_pm_common.h
new file mode 100644
index 0000000000..2d00801688
--- /dev/null
+++ b/plat/xilinx/versal/include/plat_pm_common.h
@@ -0,0 +1,26 @@
+/*
+ * 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 PAYLOAD_ARG_CNT 6U
+#define PAYLOAD_ARG_SIZE 4U /* size in bytes */
+
+#define VERSAL_TZ_VERSION_MAJOR 1
+#define VERSAL_TZ_VERSION_MINOR 0
+#define VERSAL_TZ_VERSION ((VERSAL_TZ_VERSION_MAJOR << 16) | \
+ VERSAL_TZ_VERSION_MINOR)
+#endif /* PLAT_PM_COMMON_H */
diff --git a/plat/xilinx/versal/versal_private.h b/plat/xilinx/versal/include/plat_private.h
index 5d98d080c5..e302096ebd 100644
--- a/plat/xilinx/versal/versal_private.h
+++ b/plat/xilinx/versal/include/plat_private.h
@@ -1,11 +1,11 @@
/*
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
-#ifndef VERSAL_PRIVATE_H
-#define VERSAL_PRIVATE_H
+#ifndef PLAT_PRIVATE_H
+#define PLAT_PRIVATE_H
#include <lib/xlat_tables/xlat_tables.h>
@@ -18,7 +18,9 @@ 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);
unsigned int versal_calc_core_pos(u_register_t mpidr);
-#endif /* VERSAL_PRIVATE_H */
+#endif /* PLAT_PRIVATE_H */
diff --git a/plat/xilinx/versal/include/platform_def.h b/plat/xilinx/versal/include/platform_def.h
index 0c4b9544f2..9f8392ce91 100644
--- a/plat/xilinx/versal/include/platform_def.h
+++ b/plat/xilinx/versal/include/platform_def.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -8,8 +8,7 @@
#define PLATFORM_DEF_H
#include <arch.h>
-
-#include "../versal_def.h"
+#include "versal_def.h"
/*******************************************************************************
* Generic platform constants
@@ -32,7 +31,7 @@
* little space for growth.
*/
#ifndef VERSAL_ATF_MEM_BASE
-# define BL31_BASE 0xfffea000
+# define BL31_BASE 0xfffe0000
# define BL31_LIMIT 0xffffffff
#else
# define BL31_BASE (VERSAL_ATF_MEM_BASE)
@@ -57,9 +56,9 @@
* BL33 specific defines.
******************************************************************************/
#ifndef PRELOADED_BL33_BASE
-# define PLAT_VERSAL_NS_IMAGE_OFFSET 0x8000000
+# define PLAT_ARM_NS_IMAGE_BASE 0x8000000
#else
-# define PLAT_VERSAL_NS_IMAGE_OFFSET PRELOADED_BL33_BASE
+# define PLAT_ARM_NS_IMAGE_BASE PRELOADED_BL33_BASE
#endif
/*******************************************************************************
@@ -76,7 +75,7 @@
******************************************************************************/
#define PLAT_PHY_ADDR_SPACE_SIZE (1ull << 32)
#define PLAT_VIRT_ADDR_SPACE_SIZE (1ull << 32)
-#define MAX_MMAP_REGIONS 7
+#define MAX_MMAP_REGIONS 8
#define MAX_XLAT_TABLES 5
#define CACHE_WRITEBACK_SHIFT 6
diff --git a/plat/xilinx/versal/versal_def.h b/plat/xilinx/versal/include/versal_def.h
index 41c65b94de..9a9b7c0178 100644
--- a/plat/xilinx/versal/versal_def.h
+++ b/plat/xilinx/versal/include/versal_def.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -19,6 +19,7 @@
/* List all supported platforms */
#define VERSAL_PLATFORM_ID_versal_virt 1
+#define VERSAL_PLATFORM_ID_silicon 4
#define VERSAL_PLATFORM_IS(con) (VERSAL_PLATFORM_ID_ ## con == VERSAL_PLATFORM)
@@ -35,13 +36,10 @@
/* CRL */
#define VERSAL_CRL 0xFF5E0000
-#define VERSAL_CRL_IOU_SWITCH_CTRL (VERSAL_CRL + 0x114)
#define VERSAL_CRL_TIMESTAMP_REF_CTRL (VERSAL_CRL + 0x14C)
#define VERSAL_CRL_RST_TIMESTAMP_OFFSET (VERSAL_CRL + 0x348)
#define VERSAL_CRL_APB_TIMESTAMP_REF_CTRL_CLKACT_BIT (1 << 25)
-#define VERSAL_IOU_SWITCH_CTRL_CLKACT_BIT (1 << 25)
-#define VERSAL_IOU_SWITCH_CTRL_DIVISOR0_SHIFT 8
/* IOU SCNTRS */
#define VERSAL_IOU_SCNTRS 0xFF140000
@@ -56,6 +54,13 @@
#define VERSAL_IRQ_SEC_PHY_TIMER 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
@@ -80,7 +85,12 @@
# define PLATFORM_NAME "Versal Virt"
# define VERSAL_UART_CLOCK 25000000
# define VERSAL_UART_BAUDRATE 115200
-# define VERSAL_CPU_CLOCK 62500000
+# 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
#endif
/* Access control register defines */
@@ -97,6 +107,9 @@
#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 0xFD5C0000
#define FPD_APU_CONFIG_0 (FPD_APU_BASE + 0x20)
@@ -105,5 +118,26 @@
#define FPD_APU_PWRCTL (FPD_APU_BASE + 0x90)
#define FPD_APU_CONFIG_0_VINITHI_SHIFT 8
+#define APU_0_PWRCTL_CPUPWRDWNREQ_MASK 1
+#define APU_1_PWRCTL_CPUPWRDWNREQ_MASK 2
+
+/* PMC registers and bitfields */
+#define PMC_GLOBAL_BASE 0xF1110000
+#define PMC_GLOBAL_GLOB_GEN_STORAGE4 (PMC_GLOBAL_BASE + 0x40)
+
+/* IPI registers and bitfields */
+#define IPI0_REG_BASE 0xFF330000
+#define IPI0_TRIG_BIT (1 << 2)
+#define PMC_IPI_TRIG_BIT (1 << 1)
+#define IPI1_REG_BASE 0xFF340000
+#define IPI1_TRIG_BIT (1 << 3)
+#define IPI2_REG_BASE 0xFF350000
+#define IPI2_TRIG_BIT (1 << 4)
+#define IPI3_REG_BASE 0xFF360000
+#define IPI3_TRIG_BIT (1 << 5)
+#define IPI4_REG_BASE 0xFF370000
+#define IPI4_TRIG_BIT (1 << 5)
+#define IPI5_REG_BASE 0xFF380000
+#define IPI5_TRIG_BIT (1 << 6)
#endif /* VERSAL_DEF_H */
diff --git a/plat/xilinx/versal/plat_psci.c b/plat/xilinx/versal/plat_psci.c
index 4a443697f0..39550858ad 100644
--- a/plat/xilinx/versal/plat_psci.c
+++ b/plat/xilinx/versal/plat_psci.c
@@ -1,63 +1,109 @@
/*
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
+#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 "versal_private.h"
+#include "pm_api_sys.h"
+#include "pm_client.h"
static uintptr_t versal_sec_entry;
-static int versal_nopmc_pwr_domain_on(u_register_t mpidr)
+static int versal_pwr_domain_on(u_register_t mpidr)
{
- uint32_t r;
unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr);
+ const struct pm_proc *proc;
VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr);
if (cpu_id == -1)
return PSCI_E_INTERN_FAIL;
- /*
- * program RVBAR
- */
- mmio_write_32(FPD_APU_RVBAR_L_0 + (cpu_id << 3), versal_sec_entry);
- mmio_write_32(FPD_APU_RVBAR_H_0 + (cpu_id << 3), versal_sec_entry >> 32);
+ proc = pm_get_proc(cpu_id);
- /*
- * clear VINITHI
- */
- r = mmio_read_32(FPD_APU_CONFIG_0);
- r &= ~(1 << FPD_APU_CONFIG_0_VINITHI_SHIFT << cpu_id);
- mmio_write_32(FPD_APU_CONFIG_0, r);
+ /* Send request to PMC to wake up selected ACPU core */
+ pm_req_wakeup(proc->node_id, (versal_sec_entry & 0xFFFFFFFF) | 0x1,
+ versal_sec_entry >> 32, 0);
- /*
- * FIXME: Add power up sequence, By default it works
- * now without the need of it as it was powered up by
- * default.
- */
+ /* Clear power down request */
+ pm_client_wakeup(proc);
- /*
- * clear power down request
- */
- r = mmio_read_32(FPD_APU_PWRCTL);
- r &= ~(1 << cpu_id);
- mmio_write_32(FPD_APU_PWRCTL, r);
+ return PSCI_E_SUCCESS;
+}
- /*
- * release core reset
- */
- r = mmio_read_32(CRF_RST_APU);
- r &= ~((CRF_RST_APU_ACPU_PWRON_RESET |
- CRF_RST_APU_ACPU_RESET) << cpu_id);
- mmio_write_32(CRF_RST_APU, r);
+/**
+ * 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)
+{
+ unsigned int state;
+ unsigned int cpu_id = plat_my_core_pos();
+ const struct pm_proc *proc = pm_get_proc(cpu_id);
- return PSCI_E_SUCCESS;
+ 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_gic_cpuif_disable();
+
+ 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 */
+ pm_self_suspend(proc->node_id, MAX_LATENCY, state, versal_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();
+ }
+}
+
+/**
+ * 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)
+{
+ unsigned int cpu_id = plat_my_core_pos();
+ const struct pm_proc *proc = pm_get_proc(cpu_id);
+
+ for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
+ VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+ __func__, i, target_state->pwr_domain_state[i]);
+
+ /* Clear the APU power control register for this cpu */
+ pm_client_wakeup(proc);
+
+ /* enable coherency */
+ plat_arm_interconnect_enter_coherency();
+
+ /* APU was turned off, so restore GIC context */
+ if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) {
+ plat_versal_gic_resume();
+ plat_versal_gic_cpuif_enable();
+ } else {
+ plat_versal_gic_cpuif_enable();
+ plat_versal_gic_pcpu_init();
+ }
}
void versal_pwr_domain_on_finish(const psci_power_state_t *target_state)
@@ -69,9 +115,114 @@ void versal_pwr_domain_on_finish(const psci_power_state_t *target_state)
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 */
+ pm_system_shutdown(XPM_SHUTDOWN_TYPE_SHUTDOWN,
+ pm_get_shutdown_scope());
+
+ 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 */
+ pm_system_shutdown(XPM_SHUTDOWN_TYPE_RESET,
+ pm_get_shutdown_scope());
+
+ 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)
+{
+ unsigned int cpu_id = plat_my_core_pos();
+ const struct pm_proc *proc = pm_get_proc(cpu_id);
+
+ for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
+ VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+ __func__, i, target_state->pwr_domain_state[i]);
+
+ /* Prevent interrupts from spuriously waking up this cpu */
+ 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.
+ */
+ pm_self_suspend(proc->node_id, MAX_LATENCY, PM_STATE_CPU_IDLE, 0);
+}
+
+/**
+ * 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 int versal_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;
+}
+
+/**
+ * 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_nopmc_pwr_domain_on,
+ .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,
};
/*******************************************************************************
diff --git a/plat/xilinx/versal/plat_versal.c b/plat/xilinx/versal/plat_versal.c
index 642867da29..a080a76a95 100644
--- a/plat/xilinx/versal/plat_versal.c
+++ b/plat/xilinx/versal/plat_versal.c
@@ -1,13 +1,12 @@
/*
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
+#include <plat_private.h>
#include <plat/common/platform.h>
-#include "versal_private.h"
-
int plat_core_pos_by_mpidr(u_register_t mpidr)
{
if (mpidr & MPIDR_CLUSTER_MASK)
diff --git a/plat/xilinx/versal/platform.mk b/plat/xilinx/versal/platform.mk
index 1c56364c85..1e231cce8f 100644
--- a/plat/xilinx/versal/platform.mk
+++ b/plat/xilinx/versal/platform.mk
@@ -1,4 +1,4 @@
-# Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
@@ -31,33 +31,50 @@ ifdef VERSAL_BL32_MEM_BASE
$(eval $(call add_define,VERSAL_BL32_MEM_SIZE))
endif
-VERSAL_PLATFORM ?= versal_virt
+VERSAL_PLATFORM ?= silicon
$(eval $(call add_define_val,VERSAL_PLATFORM,VERSAL_PLATFORM_ID_${VERSAL_PLATFORM}))
VERSAL_CONSOLE ?= pl011
$(eval $(call add_define_val,VERSAL_CONSOLE,VERSAL_CONSOLE_ID_${VERSAL_CONSOLE}))
-PLAT_INCLUDES := -Iplat/xilinx/versal/include/
+PLAT_INCLUDES := -Iinclude/plat/arm/common/ \
+ -Iplat/xilinx/common/include/ \
+ -Iplat/xilinx/common/ipi_mailbox_service/ \
+ -Iplat/xilinx/versal/include/ \
+ -Iplat/xilinx/versal/pm_service/
PLAT_BL_COMMON_SOURCES := lib/xlat_tables/xlat_tables_common.c \
lib/xlat_tables/aarch64/xlat_tables.c \
drivers/delay_timer/delay_timer.c \
drivers/delay_timer/generic_delay_timer.c \
drivers/arm/gic/common/gic_common.c \
+ drivers/arm/gic/v3/arm_gicv3_common.c \
+ drivers/arm/gic/v3/gic500.c \
drivers/arm/gic/v3/gicv3_main.c \
drivers/arm/gic/v3/gicv3_helpers.c \
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
-BL31_SOURCES += lib/cpus/aarch64/cortex_a53.S \
+BL31_SOURCES += drivers/arm/cci/cci.c \
+ lib/cpus/aarch64/cortex_a53.S \
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_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
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 0000000000..dbe94e6249
--- /dev/null
+++ b/plat/xilinx/versal/pm_service/pm_api_sys.c
@@ -0,0 +1,885 @@
+/*
+ * Copyright (c) 2019, Xilinx, 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"
+
+/*********************************************************************
+ * Target module IDs macros
+ ********************************************************************/
+#define LIBPM_MODULE_ID 0x2
+#define LOADER_MODULE_ID 0x7
+
+/* default shutdown/reboot scope is system(2) */
+static unsigned int pm_shutdown_scope = XPM_SHUTDOWN_SUBTYPE_RST_SYSTEM;
+
+/**
+ * pm_get_shutdown_scope() - Get the currently set shutdown scope
+ *
+ * @return Shutdown scope value
+ */
+unsigned int pm_get_shutdown_scope(void)
+{
+ return pm_shutdown_scope;
+}
+
+/**
+ * Assigning of argument values into array elements.
+ */
+#define PM_PACK_PAYLOAD1(pl, mid, arg0) { \
+ pl[0] = (uint32_t)((uint32_t)((arg0) & 0xFF) | (mid << 8)); \
+}
+
+#define PM_PACK_PAYLOAD2(pl, mid, arg0, arg1) { \
+ pl[1] = (uint32_t)(arg1); \
+ PM_PACK_PAYLOAD1(pl, mid, arg0); \
+}
+
+#define PM_PACK_PAYLOAD3(pl, mid, arg0, arg1, arg2) { \
+ pl[2] = (uint32_t)(arg2); \
+ PM_PACK_PAYLOAD2(pl, mid, arg0, arg1); \
+}
+
+#define PM_PACK_PAYLOAD4(pl, mid, arg0, arg1, arg2, arg3) { \
+ pl[3] = (uint32_t)(arg3); \
+ PM_PACK_PAYLOAD3(pl, mid, arg0, arg1, arg2); \
+}
+
+#define PM_PACK_PAYLOAD5(pl, mid, arg0, arg1, arg2, arg3, arg4) { \
+ pl[4] = (uint32_t)(arg4); \
+ PM_PACK_PAYLOAD4(pl, mid, arg0, arg1, arg2, arg3); \
+}
+
+#define PM_PACK_PAYLOAD6(pl, mid, arg0, arg1, arg2, arg3, arg4, arg5) { \
+ pl[5] = (uint32_t)(arg5); \
+ PM_PACK_PAYLOAD5(pl, mid, arg0, arg1, arg2, arg3, arg4); \
+}
+
+/* PM API functions */
+
+/**
+ * pm_get_api_version() - Get version number of PMC PM firmware
+ * @version Returns 32-bit version number of PMC Power Management Firmware
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_get_api_version(unsigned int *version)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD1(payload, LIBPM_MODULE_ID, PM_GET_API_VERSION);
+ return pm_ipi_send_sync(primary_proc, payload, version, 1);
+}
+
+/**
+ * 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(uint32_t nid,
+ unsigned int latency,
+ unsigned int state,
+ uintptr_t address)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+ unsigned int cpuid = plat_my_core_pos();
+ const struct pm_proc *proc = pm_get_proc(cpuid);
+
+ if (!proc) {
+ 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, 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
+ *
+ * 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 PLM */
+ PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_ABORT_SUSPEND, reason,
+ primary_proc->node_id);
+ return pm_ipi_send(primary_proc, payload);
+}
+
+/**
+ * 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(uint32_t target, uint8_t ack,
+ unsigned int latency, unsigned int state)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, 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
+ *
+ * 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 payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC to perform the wake of the PU */
+ PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, PM_REQ_WAKEUP, target,
+ set_address, address, ack);
+
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_request_device() - Request a device
+ * @device_id Device ID
+ * @capabilities Requested capabilities for the device
+ * @qos Required Quality of Service
+ * @ack Flag to specify whether acknowledge requested
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_request_device(uint32_t device_id, uint32_t capabilities,
+ uint32_t qos, uint32_t ack)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, PM_REQUEST_DEVICE,
+ device_id, capabilities, qos, ack);
+
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_release_device() - Release a device
+ * @device_id Device ID
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_release_device(uint32_t device_id)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_RELEASE_DEVICE,
+ device_id);
+
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_set_requirement() - Set requirement for the device
+ * @device_id Device ID
+ * @capabilities Requested capabilities for the device
+ * @latency Requested maximum latency
+ * @qos Required Quality of Service
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_set_requirement(uint32_t device_id, uint32_t capabilities,
+ uint32_t latency, uint32_t qos)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, PM_SET_REQUIREMENT,
+ device_id, capabilities, latency, qos);
+
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_get_device_status() - Get device's status
+ * @device_id Device ID
+ * @response Buffer to store device status response
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_get_device_status(uint32_t device_id, uint32_t *response)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_GET_DEVICE_STATUS,
+ device_id);
+
+ return pm_ipi_send_sync(primary_proc, payload, response, 3);
+}
+
+/**
+ * pm_reset_assert() - Assert/De-assert reset
+ * @reset Reset ID
+ * @assert Assert (1) or de-assert (0)
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_reset_assert(uint32_t reset, bool assert)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_RESET_ASSERT, reset,
+ assert);
+
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_reset_get_status() - Get current status of a reset line
+ * @reset Reset ID
+ * @status Returns current status of selected reset ID
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_reset_get_status(uint32_t reset, uint32_t *status)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_RESET_ASSERT, reset);
+
+ return pm_ipi_send_sync(primary_proc, payload, status, 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_pinctrl_request() - Request a pin
+ * @pin Pin ID
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_pinctrl_request(uint32_t pin)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_PINCTRL_REQUEST, pin);
+
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_pinctrl_release() - Release a pin
+ * @pin Pin ID
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_pinctrl_release(uint32_t pin)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_PINCTRL_RELEASE, pin);
+
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_pinctrl_set_function() - Set pin function
+ * @pin Pin ID
+ * @function Function ID
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_pinctrl_set_function(uint32_t pin, uint32_t function)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_PINCTRL_SET_FUNCTION, pin,
+ function)
+
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_pinctrl_get_function() - Get function set on the pin
+ * @pin Pin ID
+ * @function Function set on the pin
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_pinctrl_get_function(uint32_t pin, uint32_t *function)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_PINCTRL_SET_FUNCTION,
+ pin);
+
+ return pm_ipi_send_sync(primary_proc, payload, function, 1);
+}
+
+/**
+ * pm_pinctrl_set_pin_param() - Set configuration parameter for the pin
+ * @pin Pin ID
+ * @param Parameter ID
+ * @value Parameter value
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_pinctrl_set_pin_param(uint32_t pin, uint32_t param,
+ uint32_t value)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, PM_PINCTRL_CONFIG_PARAM_SET,
+ pin, param, value);
+
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_pinctrl_get_pin_param() - Get configuration parameter value for the pin
+ * @pin Pin ID
+ * @param Parameter ID
+ * @value Buffer to store parameter value
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_pinctrl_get_pin_param(uint32_t pin, uint32_t param,
+ uint32_t *value)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_PINCTRL_CONFIG_PARAM_GET,
+ pin, param);
+
+ return pm_ipi_send_sync(primary_proc, payload, value, 1);
+}
+
+/**
+ * pm_clock_enable() - Enable the clock
+ * @clk_id Clock ID
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_clock_enable(uint32_t clk_id)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_CLOCK_ENABLE, clk_id);
+
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_clock_disable() - Disable the clock
+ * @clk_id Clock ID
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_clock_disable(uint32_t clk_id)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_CLOCK_DISABLE, clk_id);
+
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_clock_get_state() - Get clock status
+ * @clk_id Clock ID
+ * @state: Buffer to store clock status (1: Enabled, 0:Disabled)
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_clock_get_state(uint32_t clk_id, uint32_t *state)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_CLOCK_GETSTATE, clk_id);
+
+ return pm_ipi_send_sync(primary_proc, payload, state, 1);
+}
+
+/**
+ * pm_clock_set_divider() - Set divider for the clock
+ * @clk_id Clock ID
+ * @divider Divider value
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_clock_set_divider(uint32_t clk_id, uint32_t divider)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_CLOCK_SETDIVIDER, clk_id,
+ divider);
+
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_clock_get_divider() - Get divider value for the clock
+ * @clk_id Clock ID
+ * @divider: Buffer to store clock divider value
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_clock_get_divider(uint32_t clk_id, uint32_t *divider)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_CLOCK_GETDIVIDER, clk_id);
+
+ return pm_ipi_send_sync(primary_proc, payload, divider, 1);
+}
+
+/**
+ * pm_clock_set_parent() - Set parent for the clock
+ * @clk_id Clock ID
+ * @parent Parent ID
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_clock_set_parent(uint32_t clk_id, uint32_t parent)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_CLOCK_SETPARENT, clk_id,
+ parent);
+
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_clock_get_parent() - Get parent value for the clock
+ * @clk_id Clock ID
+ * @parent: Buffer to store clock parent value
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_clock_get_parent(uint32_t clk_id, uint32_t *parent)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_CLOCK_GETPARENT, clk_id);
+
+ return pm_ipi_send_sync(primary_proc, payload, parent, 1);
+}
+
+/**
+ * pm_pll_set_param() - Set PLL parameter
+ * @clk_id PLL clock ID
+ * @param PLL parameter ID
+ * @value Value to set for PLL parameter
+ *
+ * @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 payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, 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
+ * @clk_id PLL clock ID
+ * @param PLL parameter ID
+ * @value: Buffer to store PLL parameter value
+ *
+ * @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 payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_PLL_GET_PARAMETER, clk_id,
+ param);
+
+ return pm_ipi_send_sync(primary_proc, payload, value, 1);
+}
+
+/**
+ * pm_pll_set_mode() - Set PLL mode
+ * @clk_id PLL clock ID
+ * @mode PLL mode
+ *
+ * @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 payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_PLL_SET_MODE, clk_id,
+ mode);
+
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_pll_get_mode() - Get PLL mode
+ * @clk_id PLL clock ID
+ * @mode: Buffer to store PLL mode
+ *
+ * @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 payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, 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
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_force_powerdown(uint32_t target, uint8_t ack)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, 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
+ *
+ * @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 == 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, PM_SYSTEM_SHUTDOWN, type,
+ subtype);
+
+ return pm_ipi_send_non_blocking(primary_proc, payload);
+}
+
+/**
+* pm_query_data() - PM API for querying firmware data
+* @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
+*
+* This function returns requested data.
+*/
+enum pm_ret_status pm_query_data(uint32_t qid, uint32_t arg1, uint32_t arg2,
+ uint32_t arg3, uint32_t *data)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, PM_QUERY_DATA, qid, arg1,
+ arg2, arg3);
+ return pm_ipi_send_sync(primary_proc, payload, data, 4);
+}
+/**
+ * pm_api_ioctl() - PM IOCTL API for device control and configs
+ * @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
+ * @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(uint32_t device_id, uint32_t ioctl_id,
+ uint32_t arg1, uint32_t arg2, uint32_t *value)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ switch (ioctl_id) {
+ case IOCTL_SET_PLL_FRAC_MODE:
+ return pm_pll_set_mode(arg1, arg2);
+ case IOCTL_GET_PLL_FRAC_MODE:
+ return pm_pll_get_mode(arg1, value);
+ case IOCTL_SET_PLL_FRAC_DATA:
+ return pm_pll_set_param(arg1, PM_PLL_PARAM_DATA, arg2);
+ case IOCTL_GET_PLL_FRAC_DATA:
+ return pm_pll_get_param(arg1, PM_PLL_PARAM_DATA, value);
+ default:
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, PM_IOCTL, device_id,
+ ioctl_id, arg1, arg2);
+ return pm_ipi_send_sync(primary_proc, payload, value, 1);
+ }
+}
+
+/**
+ * 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
+ *
+ * @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 payload[PAYLOAD_ARG_CNT];
+
+ PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, PM_SET_WAKEUP_SOURCE, target,
+ wkup_device, enable);
+ return pm_ipi_send(primary_proc, payload);
+}
+
+/**
+ * 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 PMC */
+ PM_PACK_PAYLOAD1(payload, LIBPM_MODULE_ID, PM_GET_CHIPID);
+
+ return pm_ipi_send_sync(primary_proc, payload, value, 2);
+}
+
+/**
+ * pm_feature_check() - Returns the supported API version if supported
+ * @api_id API ID to check
+ * @value Returned supported API version
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_feature_check(uint32_t api_id, unsigned int *version)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT], fw_api_version;
+ uint32_t status;
+
+ switch (api_id) {
+ case PM_GET_CALLBACK_DATA:
+ case PM_GET_TRUSTZONE_VERSION:
+ case PM_INIT_FINALIZE:
+ *version = (PM_API_BASE_VERSION << 16);
+ return PM_RET_SUCCESS;
+ case PM_GET_API_VERSION:
+ case PM_GET_DEVICE_STATUS:
+ case PM_GET_OP_CHARACTERISTIC:
+ case PM_REQ_SUSPEND:
+ case PM_SELF_SUSPEND:
+ case PM_FORCE_POWERDOWN:
+ case PM_ABORT_SUSPEND:
+ case PM_REQ_WAKEUP:
+ case PM_SET_WAKEUP_SOURCE:
+ case PM_SYSTEM_SHUTDOWN:
+ case PM_REQUEST_DEVICE:
+ case PM_RELEASE_DEVICE:
+ case PM_SET_REQUIREMENT:
+ case PM_RESET_ASSERT:
+ case PM_RESET_GET_STATUS:
+ case PM_PINCTRL_REQUEST:
+ case PM_PINCTRL_RELEASE:
+ case PM_PINCTRL_GET_FUNCTION:
+ case PM_PINCTRL_SET_FUNCTION:
+ case PM_PINCTRL_CONFIG_PARAM_GET:
+ case PM_PINCTRL_CONFIG_PARAM_SET:
+ case PM_IOCTL:
+ case PM_QUERY_DATA:
+ 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_FEATURE_CHECK:
+ *version = (PM_API_BASE_VERSION << 16);
+ break;
+ case PM_LOAD_PDI:
+ *version = (PM_API_BASE_VERSION << 16);
+ return PM_RET_SUCCESS;
+ default:
+ *version = 0U;
+ return PM_RET_ERROR_NOFEATURE;
+ }
+
+ PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_FEATURE_CHECK, api_id);
+
+ status = pm_ipi_send_sync(primary_proc, payload, &fw_api_version, 1);
+ if (status != PM_RET_SUCCESS)
+ return status;
+
+ *version |= fw_api_version;
+
+ return PM_RET_SUCCESS;
+}
+
+/**
+ * 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
+ *
+ * @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 payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD4(payload, LOADER_MODULE_ID, PM_LOAD_PDI, src,
+ address_high, address_low);
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_get_op_characteristic() - PM call to request operating characteristics
+ * of a device
+ * @device_id Device id
+ * @type Type of the operating characteristic
+ * (power, temperature and latency)
+ * @result Returns the operating characteristic for the requested device,
+ * specified by the type
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_get_op_characteristic(uint32_t device_id,
+ enum pm_opchar_type type,
+ uint32_t *result)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_GET_OP_CHARACTERISTIC,
+ device_id, type);
+ return pm_ipi_send_sync(primary_proc, payload, result, 1);
+}
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 0000000000..4de592a2f4
--- /dev/null
+++ b/plat/xilinx/versal/pm_service/pm_api_sys.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2019, Xilinx, 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"
+
+/**********************************************************
+ * PM API function declarations
+ **********************************************************/
+
+enum pm_ret_status pm_get_api_version(unsigned int *version);
+enum pm_ret_status pm_self_suspend(uint32_t nid,
+ unsigned int latency,
+ unsigned int state,
+ uintptr_t address);
+enum pm_ret_status pm_abort_suspend(enum pm_abort_reason reason);
+enum pm_ret_status pm_req_suspend(uint32_t target,
+ uint8_t ack,
+ unsigned int latency,
+ unsigned int state);
+enum pm_ret_status pm_req_wakeup(uint32_t target, uint32_t set_address,
+ uintptr_t address, uint8_t ack);
+enum pm_ret_status pm_set_wakeup_source(uint32_t target, uint32_t device_id,
+ uint8_t enable);
+enum pm_ret_status pm_request_device(uint32_t device_id, uint32_t capabilities,
+ uint32_t qos, uint32_t ack);
+enum pm_ret_status pm_release_device(uint32_t device_id);
+enum pm_ret_status pm_set_requirement(uint32_t device_id, uint32_t capabilities,
+ uint32_t latency, uint32_t qos);
+enum pm_ret_status pm_get_device_status(uint32_t device_id, uint32_t *response);
+enum pm_ret_status pm_reset_assert(uint32_t reset, bool assert);
+enum pm_ret_status pm_reset_get_status(uint32_t reset, uint32_t *status);
+void pm_get_callbackdata(uint32_t *data, size_t count);
+enum pm_ret_status pm_pinctrl_request(uint32_t pin);
+enum pm_ret_status pm_pinctrl_release(uint32_t pin);
+enum pm_ret_status pm_pinctrl_set_function(uint32_t pin, uint32_t function);
+enum pm_ret_status pm_pinctrl_get_function(uint32_t pin, uint32_t *function);
+enum pm_ret_status pm_pinctrl_set_pin_param(uint32_t pin, uint32_t param,
+ uint32_t value);
+enum pm_ret_status pm_pinctrl_get_pin_param(uint32_t pin, uint32_t param,
+ uint32_t *value);
+enum pm_ret_status pm_clock_enable(uint32_t clk_id);
+enum pm_ret_status pm_clock_disable(uint32_t clk_id);
+enum pm_ret_status pm_clock_get_state(uint32_t clk_id, uint32_t *state);
+enum pm_ret_status pm_clock_set_divider(uint32_t clk_id, uint32_t divider);
+enum pm_ret_status pm_clock_get_divider(uint32_t clk_id, uint32_t *divider);
+enum pm_ret_status pm_clock_set_parent(uint32_t clk_id, uint32_t parent);
+enum pm_ret_status pm_clock_get_parent(uint32_t clk_id, uint32_t *parent);
+enum pm_ret_status pm_pll_set_param(uint32_t clk_id, uint32_t param,
+ uint32_t value);
+enum pm_ret_status pm_pll_get_param(uint32_t clk_id, uint32_t param,
+ uint32_t *value);
+enum pm_ret_status pm_pll_set_mode(uint32_t clk_id, uint32_t mode);
+enum pm_ret_status pm_pll_get_mode(uint32_t clk_id, uint32_t *mode);
+enum pm_ret_status pm_force_powerdown(uint32_t target, uint8_t ack);
+enum pm_ret_status pm_system_shutdown(uint32_t type, uint32_t subtype);
+enum pm_ret_status pm_api_ioctl(uint32_t device_id, uint32_t ioctl_id,
+ uint32_t arg1, uint32_t arg2, uint32_t *value);
+enum pm_ret_status pm_query_data(uint32_t qid, uint32_t arg1, uint32_t arg2,
+ uint32_t arg3, uint32_t *data);
+unsigned int pm_get_shutdown_scope(void);
+enum pm_ret_status pm_get_chipid(uint32_t *value);
+enum pm_ret_status pm_feature_check(uint32_t api_id, unsigned int *version);
+enum pm_ret_status pm_load_pdi(uint32_t src, uint32_t address_low,
+ uint32_t address_high);
+enum pm_ret_status pm_get_op_characteristic(uint32_t device_id,
+ enum pm_opchar_type type,
+ uint32_t *result);
+#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 0000000000..5b47838e90
--- /dev/null
+++ b/plat/xilinx/versal/pm_service/pm_client.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2019, 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"
+
+#define UNDEFINED_CPUID (~0)
+#define IRQ_MAX 142
+#define NUM_GICD_ISENABLER ((IRQ_MAX >> 5) + 1)
+
+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(unsigned int 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.
+ */
+static void pm_client_set_wakeup_sources(void)
+{
+ 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, sizeof(pm_wakeup_nodes_set));
+
+ for (reg_num = 0; reg_num < NUM_GICD_ISENABLER; reg_num++) {
+ uint32_t base_irq = reg_num << ISENABLER_SHIFT;
+ uint32_t reg = mmio_read_32(isenabler1 + (reg_num << 2));
+
+ if (!reg)
+ continue;
+
+ while (reg) {
+ enum pm_device_node_idx node_idx;
+ uint32_t idx, ret, irq, lowest_set = reg & (-reg);
+
+ 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) &&
+ (!pm_wakeup_nodes_set[node_idx])) {
+ /* Get device ID from node index */
+ device_id = PERIPH_DEVID(node_idx);
+ ret = pm_set_wakeup_source(XPM_DEVID_ACPU_0,
+ device_id, 1);
+ pm_wakeup_nodes_set[node_idx] = !ret;
+ }
+ }
+ }
+}
+
+/**
+ * pm_client_suspend() - Client-specific suspend actions
+ *
+ * This function should contain any PU-specific actions
+ * required prior to sending suspend request to PMU
+ * Actions taken depend on the state system is suspending to.
+ */
+void pm_client_suspend(const struct pm_proc *proc, unsigned int state)
+{
+ bakery_lock_get(&pm_client_secure_lock);
+
+ if (state == PM_STATE_SUSPEND_TO_RAM)
+ pm_client_set_wakeup_sources();
+
+ /* Set powerdown request */
+ mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_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) */
+ 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) &
+ ~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 unsigned int 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
+ */
+void pm_client_wakeup(const struct pm_proc *proc)
+{
+ unsigned int cpuid = pm_get_cpuid(proc->node_id);
+
+ if (cpuid == UNDEFINED_CPUID)
+ return;
+
+ bakery_lock_get(&pm_client_secure_lock);
+
+ /* clear powerdown bit for affected cpu */
+ uint32_t val = mmio_read_32(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(unsigned int 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 0000000000..966b00bb50
--- /dev/null
+++ b/plat/xilinx/versal/pm_service/pm_defs.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2019, 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 0xa01
+#define PM_GET_TRUSTZONE_VERSION 0xa03
+
+/* PM API Versions */
+#define PM_API_BASE_VERSION 1U
+
+/* PM API ids */
+#define PM_GET_API_VERSION 1U
+#define PM_GET_DEVICE_STATUS 3U
+#define PM_GET_OP_CHARACTERISTIC 4U
+#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_REQUEST_DEVICE 13U
+#define PM_RELEASE_DEVICE 14U
+#define PM_SET_REQUIREMENT 15U
+#define PM_RESET_ASSERT 17U
+#define PM_RESET_GET_STATUS 18U
+#define PM_INIT_FINALIZE 21U
+#define PM_GET_CHIPID 24U
+#define PM_PINCTRL_REQUEST 28U
+#define PM_PINCTRL_RELEASE 29U
+#define PM_PINCTRL_GET_FUNCTION 30U
+#define PM_PINCTRL_SET_FUNCTION 31U
+#define PM_PINCTRL_CONFIG_PARAM_GET 32U
+#define PM_PINCTRL_CONFIG_PARAM_SET 33U
+#define PM_IOCTL 34U
+#define PM_QUERY_DATA 35U
+#define PM_CLOCK_ENABLE 36U
+#define PM_CLOCK_DISABLE 37U
+#define PM_CLOCK_GETSTATE 38U
+#define PM_CLOCK_SETDIVIDER 39U
+#define PM_CLOCK_GETDIVIDER 40U
+#define PM_CLOCK_SETRATE 41U
+#define PM_CLOCK_GETRATE 42U
+#define PM_CLOCK_SETPARENT 43U
+#define PM_CLOCK_GETPARENT 44U
+#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
+
+/* IOCTL IDs for clock driver */
+#define IOCTL_SET_PLL_FRAC_MODE 8
+#define IOCTL_GET_PLL_FRAC_MODE 9
+#define IOCTL_SET_PLL_FRAC_DATA 10
+#define IOCTL_GET_PLL_FRAC_DATA 11
+
+/* 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
+};
+#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 0000000000..1b82ec70de
--- /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 0000000000..a3a9f43165
--- /dev/null
+++ b/plat/xilinx/versal/pm_service/pm_svc_main.c
@@ -0,0 +1,328 @@
+/*
+ * Copyright (c) 2019, Xilinx, 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 "pm_api_sys.h"
+#include "pm_client.h"
+#include "pm_ipi.h"
+
+/* pm_up = true - UP, pm_up = false - DOWN */
+static bool pm_up;
+
+/**
+ * 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.
+ */
+int pm_setup(void)
+{
+ int status, ret = 0;
+
+ status = pm_ipi_init(primary_proc);
+
+ if (status < 0) {
+ INFO("BL31: PM Service Init Failed, Error Code %d!\n", status);
+ ret = status;
+ } else {
+ pm_up = true;
+ }
+
+ return ret;
+}
+
+/**
+ * pm_smc_handler() - SMC handler for PM-API calls coming from EL1/EL2.
+ * @smc_fid - Function Identifier
+ * @x1 - x4 - Arguments
+ * @cookie - Unused
+ * @handler - Pointer to caller's context structure
+ *
+ * @return - Unused
+ *
+ * Determines that smc_fid is valid and supported PM SMC Function ID from the
+ * list of pm_api_ids, otherwise completes the request with
+ * the unknown SMC Function ID
+ *
+ * The SMC calls for PM service are forwarded from SIP Service SMC handler
+ * function with rt_svc_handle signature
+ */
+uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
+ uint64_t x4, void *cookie, void *handle, uint64_t flags)
+{
+ enum pm_ret_status ret;
+
+ uint32_t pm_arg[4];
+
+ /* Handle case where PM wasn't initialized properly */
+ if (!pm_up)
+ SMC_RET1(handle, SMC_UNK);
+
+ pm_arg[0] = (uint32_t)x1;
+ pm_arg[1] = (uint32_t)(x1 >> 32);
+ pm_arg[2] = (uint32_t)x2;
+ pm_arg[3] = (uint32_t)(x2 >> 32);
+
+ switch (smc_fid & FUNCID_NUM_MASK) {
+ /* PM API Functions */
+ case PM_SELF_SUSPEND:
+ ret = pm_self_suspend(pm_arg[0], pm_arg[1], pm_arg[2],
+ pm_arg[3]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_FORCE_POWERDOWN:
+ ret = pm_force_powerdown(pm_arg[0], pm_arg[1]);
+ 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_ABORT_SUSPEND:
+ ret = pm_abort_suspend(pm_arg[0]);
+ 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_WAKEUP:
+ ret = pm_req_wakeup(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]);
+ 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_REQUEST_DEVICE:
+ ret = pm_request_device(pm_arg[0], pm_arg[1], pm_arg[2],
+ pm_arg[3]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_RELEASE_DEVICE:
+ ret = pm_release_device(pm_arg[0]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_SET_REQUIREMENT:
+ ret = pm_set_requirement(pm_arg[0], pm_arg[1], pm_arg[2],
+ pm_arg[3]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_GET_API_VERSION:
+ {
+ uint32_t api_version;
+
+ ret = pm_get_api_version(&api_version);
+ SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS |
+ ((uint64_t)api_version << 32));
+ }
+
+ case PM_GET_DEVICE_STATUS:
+ {
+ uint32_t buff[3];
+
+ ret = pm_get_device_status(pm_arg[0], buff);
+ SMC_RET2(handle, (uint64_t)ret | ((uint64_t)buff[0] << 32),
+ (uint64_t)buff[1] | ((uint64_t)buff[2] << 32));
+ }
+
+ case PM_RESET_ASSERT:
+ ret = pm_reset_assert(pm_arg[0], pm_arg[1]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_RESET_GET_STATUS:
+ {
+ uint32_t reset_status;
+
+ ret = pm_reset_get_status(pm_arg[0], &reset_status);
+ SMC_RET1(handle, (uint64_t)ret |
+ ((uint64_t)reset_status << 32));
+ }
+
+ case PM_INIT_FINALIZE:
+ SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS);
+
+ case PM_GET_CALLBACK_DATA:
+ {
+ uint32_t result[4] = {0};
+
+ pm_get_callbackdata(result, sizeof(result));
+ SMC_RET2(handle,
+ (uint64_t)result[0] | ((uint64_t)result[1] << 32),
+ (uint64_t)result[2] | ((uint64_t)result[3] << 32));
+ }
+
+ case PM_PINCTRL_REQUEST:
+ ret = pm_pinctrl_request(pm_arg[0]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_PINCTRL_RELEASE:
+ ret = pm_pinctrl_release(pm_arg[0]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_PINCTRL_GET_FUNCTION:
+ {
+ uint32_t value = 0;
+
+ ret = pm_pinctrl_get_function(pm_arg[0], &value);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+ }
+
+ case PM_PINCTRL_SET_FUNCTION:
+ ret = pm_pinctrl_set_function(pm_arg[0], pm_arg[1]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_PINCTRL_CONFIG_PARAM_GET:
+ {
+ uint32_t value;
+
+ ret = pm_pinctrl_get_pin_param(pm_arg[0], pm_arg[1], &value);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+ }
+
+ case PM_PINCTRL_CONFIG_PARAM_SET:
+ ret = pm_pinctrl_set_pin_param(pm_arg[0], pm_arg[1], pm_arg[2]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_IOCTL:
+ {
+ uint32_t value;
+
+ ret = pm_api_ioctl(pm_arg[0], pm_arg[1], pm_arg[2],
+ pm_arg[3], &value);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+ }
+
+ case PM_QUERY_DATA:
+ {
+ uint32_t data[4] = { 0 };
+
+ ret = pm_query_data(pm_arg[0], pm_arg[1], pm_arg[2],
+ pm_arg[3], data);
+ SMC_RET2(handle, (uint64_t)ret | ((uint64_t)data[0] << 32),
+ (uint64_t)data[1] | ((uint64_t)data[2] << 32));
+ }
+
+ case PM_CLOCK_ENABLE:
+ ret = pm_clock_enable(pm_arg[0]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_CLOCK_DISABLE:
+ ret = pm_clock_disable(pm_arg[0]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_CLOCK_GETSTATE:
+ {
+ uint32_t value;
+
+ ret = pm_clock_get_state(pm_arg[0], &value);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+ }
+
+ case PM_CLOCK_SETDIVIDER:
+ ret = pm_clock_set_divider(pm_arg[0], pm_arg[1]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_CLOCK_GETDIVIDER:
+ {
+ uint32_t value;
+
+ ret = pm_clock_get_divider(pm_arg[0], &value);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+ }
+
+ case PM_CLOCK_SETPARENT:
+ ret = pm_clock_set_parent(pm_arg[0], pm_arg[1]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_CLOCK_GETPARENT:
+ {
+ uint32_t value;
+
+ ret = pm_clock_get_parent(pm_arg[0], &value);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+ }
+
+ case PM_PLL_SET_PARAMETER:
+ ret = pm_pll_set_param(pm_arg[0], pm_arg[1], pm_arg[2]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_PLL_GET_PARAMETER:
+ {
+ uint32_t value;
+
+ ret = pm_pll_get_param(pm_arg[0], pm_arg[1], &value);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value << 32));
+ }
+
+ case PM_PLL_SET_MODE:
+ ret = pm_pll_set_mode(pm_arg[0], pm_arg[1]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_PLL_GET_MODE:
+ {
+ uint32_t mode;
+
+ ret = pm_pll_get_mode(pm_arg[0], &mode);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)mode << 32));
+ }
+
+ case PM_GET_TRUSTZONE_VERSION:
+ SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS |
+ ((uint64_t)VERSAL_TZ_VERSION << 32));
+
+ case PM_GET_CHIPID:
+ {
+ uint32_t result[2];
+
+ ret = pm_get_chipid(result);
+ SMC_RET2(handle, (uint64_t)ret | ((uint64_t)result[0] << 32),
+ result[1]);
+ }
+
+ case PM_FEATURE_CHECK:
+ {
+ uint32_t version;
+
+ ret = pm_feature_check(pm_arg[0], &version);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)version << 32));
+ }
+
+ case PM_LOAD_PDI:
+ {
+ ret = pm_load_pdi(pm_arg[0], pm_arg[1], pm_arg[2]);
+ SMC_RET1(handle, (uint64_t)ret);
+ }
+
+ case PM_GET_OP_CHARACTERISTIC:
+ {
+ uint32_t result;
+
+ ret = pm_get_op_characteristic(pm_arg[0], pm_arg[1], &result);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)result << 32));
+ }
+
+ default:
+ WARN("Unimplemented PM Service Call: 0x%x\n", smc_fid);
+ SMC_RET1(handle, SMC_UNK);
+ }
+}
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 0000000000..71329ca93f
--- /dev/null
+++ b/plat/xilinx/versal/pm_service/pm_svc_main.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2019, 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>
+
+int pm_setup(void);
+uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
+ uint64_t x4, void *cookie, void *handle,
+ uint64_t flags);
+
+#endif /* PM_SVC_MAIN_H */
diff --git a/plat/xilinx/versal/sip_svc_setup.c b/plat/xilinx/versal/sip_svc_setup.c
index 8f2180b211..bc7d8b7af7 100644
--- a/plat/xilinx/versal/sip_svc_setup.c
+++ b/plat/xilinx/versal/sip_svc_setup.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -10,6 +10,9 @@
#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 0x8200ff00
#define VERSAL_SIP_SVC_UID 0x8200ff01
@@ -22,7 +25,9 @@
/* 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,
@@ -36,6 +41,9 @@ DEFINE_SVC_UUID2(versal_sip_uuid,
*/
static int32_t sip_svc_setup(void)
{
+ /* PM implementation as SiP Service */
+ pm_setup();
+
return 0;
}
@@ -55,6 +63,18 @@ uintptr_t sip_svc_smc_handler(uint32_t smc_fid,
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 */
diff --git a/plat/xilinx/versal/versal_gicv3.c b/plat/xilinx/versal/versal_gicv3.c
index dcf23b4253..08e7cf95ac 100644
--- a/plat/xilinx/versal/versal_gicv3.c
+++ b/plat/xilinx/versal/versal_gicv3.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
+#include <plat_private.h>
#include <platform_def.h>
#include <common/interrupt_props.h>
@@ -11,8 +12,6 @@
#include <lib/utils.h>
#include <plat/common/platform.h>
-#include "versal_private.h"
-
/******************************************************************************
* The following functions are defined as weak to allow a platform to override
* the way the GICv3 driver is initialised and used.
diff --git a/plat/xilinx/versal/versal_ipi.c b/plat/xilinx/versal/versal_ipi.c
new file mode 100644
index 0000000000..27541ff4b5
--- /dev/null
+++ b/plat/xilinx/versal/versal_ipi.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2019, 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 = 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_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/zynqmp/bl31_zynqmp_setup.c b/plat/xilinx/zynqmp/bl31_zynqmp_setup.c
index 285a4eb8bd..6e0e811d48 100644
--- a/plat/xilinx/zynqmp/bl31_zynqmp_setup.c
+++ b/plat/xilinx/zynqmp/bl31_zynqmp_setup.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -13,8 +13,11 @@
#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>
static entry_point_info_t bl32_image_ep_info;
static entry_point_info_t bl33_image_ep_info;
@@ -57,6 +60,7 @@ static inline void bl31_set_default_config(void)
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;
/* Register the console to provide early debug support */
static console_cdns_t bl31_boot_console;
(void)console_cdns_register(ZYNQMP_UART_BASE,
@@ -86,12 +90,15 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
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);
+ &bl33_image_ep_info,
+ atf_handoff_addr);
if (ret == FSBL_HANDOFF_NO_STRUCT)
bl31_set_default_config();
else if (ret != FSBL_HANDOFF_SUCCESS)
diff --git a/plat/xilinx/zynqmp/include/plat_pm_common.h b/plat/xilinx/zynqmp/include/plat_pm_common.h
index 1b371cc367..56a747a4f6 100644
--- a/plat/xilinx/zynqmp/include/plat_pm_common.h
+++ b/plat/xilinx/zynqmp/include/plat_pm_common.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -16,7 +16,16 @@
#include <common/debug.h>
#include "pm_defs.h"
-#define PAYLOAD_ARG_CNT 6U
+#if ZYNQMP_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 ZYNQMP_TZ_VERSION_MAJOR 1
diff --git a/plat/xilinx/zynqmp/include/plat_private.h b/plat/xilinx/zynqmp/include/plat_private.h
index 8bdf429677..288cc53011 100644
--- a/plat/xilinx/zynqmp/include/plat_private.h
+++ b/plat/xilinx/zynqmp/include/plat_private.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -21,13 +21,6 @@ unsigned int zynqmp_calc_core_pos(u_register_t mpidr);
unsigned int zynqmp_get_uart_clk(void);
unsigned int zynqmp_get_bootmode(void);
-/* For FSBL handover */
-enum fsbl_handoff {
- FSBL_HANDOFF_SUCCESS = 0,
- FSBL_HANDOFF_NO_STRUCT,
- FSBL_HANDOFF_INVAL_STRUCT,
- FSBL_HANDOFF_TOO_MANY_PARTS,
-};
#if ZYNQMP_WDT_RESTART
/*
@@ -37,7 +30,4 @@ enum fsbl_handoff {
int request_intr_type_el3(uint32_t, interrupt_type_handler_t);
#endif
-enum fsbl_handoff fsbl_atf_handover(entry_point_info_t *bl32_image_ep_info,
- entry_point_info_t *bl33_image_ep_info);
-
#endif /* PLAT_PRIVATE_H */
diff --git a/plat/xilinx/zynqmp/plat_psci.c b/plat/xilinx/zynqmp/plat_psci.c
index a32e08988a..f579f795f2 100644
--- a/plat/xilinx/zynqmp/plat_psci.c
+++ b/plat/xilinx/zynqmp/plat_psci.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -100,9 +100,8 @@ 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();
- gicv2_pcpu_distif_init();
}
static void zynqmp_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
diff --git a/plat/xilinx/zynqmp/platform.mk b/plat/xilinx/zynqmp/platform.mk
index c34a51674a..44f20f69f6 100644
--- a/plat/xilinx/zynqmp/platform.mk
+++ b/plat/xilinx/zynqmp/platform.mk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
@@ -9,7 +9,10 @@ PSCI_EXTENDED_STATE_ID := 1
A53_DISABLE_NON_TEMPORAL_HINT := 0
SEPARATE_CODE_AND_RODATA := 1
ZYNQMP_WDT_RESTART := 0
+ZYNQMP_IPI_CRC_CHECK := 0
override RESET_TO_BL31 := 1
+override GICV2_G0_FOR_EL3 := 1
+override WARMBOOT_ENABLE_DCACHE_EARLY := 1
# Do not enable SVE
ENABLE_SVE_FOR_NS := 0
@@ -45,11 +48,16 @@ ifdef ZYNQMP_WDT_RESTART
$(eval $(call add_define,ZYNQMP_WDT_RESTART))
endif
-PLAT_INCLUDES := -Iinclude/plat/arm/common/aarch64/ \
+ifdef ZYNQMP_IPI_CRC_CHECK
+ $(eval $(call add_define,ZYNQMP_IPI_CRC_CHECK))
+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/ \
- -Iplat/xilinx/zynqmp/ipi_mailbox_service/
PLAT_BL_COMMON_SOURCES := lib/xlat_tables/xlat_tables_common.c \
lib/xlat_tables/aarch64/xlat_tables.c \
@@ -72,11 +80,12 @@ BL31_SOURCES += drivers/arm/cci/cci.c \
lib/cpus/aarch64/aem_generic.S \
lib/cpus/aarch64/cortex_a53.S \
plat/common/plat_psci_common.c \
+ plat/xilinx/common/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_startup.c \
plat/xilinx/zynqmp/plat_topology.c \
plat/xilinx/zynqmp/sip_svc_setup.c \
plat/xilinx/zynqmp/pm_service/pm_svc_main.c \
@@ -84,5 +93,8 @@ BL31_SOURCES += drivers/arm/cci/cci.c \
plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.c \
plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c \
plat/xilinx/zynqmp/pm_service/pm_api_clock.c \
- plat/xilinx/zynqmp/pm_service/pm_client.c \
- plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.c
+ plat/xilinx/zynqmp/pm_service/pm_client.c
+
+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
index e3050724d2..852f92763c 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_clock.c
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_clock.c
@@ -30,6 +30,10 @@
#define CLK_TYPE_SHIFT U(2)
#define CLK_CLKFLAGS_SHIFT U(8)
#define CLK_TYPEFLAGS_SHIFT U(24)
+#define CLK_TYPEFLAGS2_SHIFT U(4)
+#define CLK_TYPEFLAGS_BITS_MASK U(0xFF)
+#define CLK_TYPEFLAGS2_BITS_MASK U(0x0F00)
+#define CLK_TYPEFLAGS_BITS U(8)
#define CLK_EXTERNAL_PARENT (PARENT_CLK_EXTERNAL << CLK_PARENTS_ID_LEN)
@@ -364,9 +368,8 @@ static struct pm_clock_node dp_audio_video_ref_nodes[] = {
.offset = PERIPH_MUX_SHIFT,
.width = PERIPH_MUX_WIDTH,
.clkflags = CLK_SET_RATE_NO_REPARENT |
- CLK_SET_RATE_PARENT |
- CLK_FRAC | CLK_IS_BASIC,
- .typeflags = NA_TYPE_FLAGS,
+ CLK_SET_RATE_PARENT | CLK_IS_BASIC,
+ .typeflags = CLK_FRAC,
.mult = NA_MULT,
.div = NA_DIV,
},
@@ -375,8 +378,9 @@ static struct pm_clock_node dp_audio_video_ref_nodes[] = {
.offset = PERIPH_DIV1_SHIFT,
.width = PERIPH_DIV1_WIDTH,
.clkflags = CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT |
- CLK_FRAC | CLK_IS_BASIC,
- .typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
+ CLK_IS_BASIC,
+ .typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO |
+ CLK_FRAC,
.mult = NA_MULT,
.div = NA_DIV,
},
@@ -385,8 +389,9 @@ static struct pm_clock_node dp_audio_video_ref_nodes[] = {
.offset = PERIPH_DIV2_SHIFT,
.width = PERIPH_DIV2_WIDTH,
.clkflags = CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT |
- CLK_FRAC | CLK_IS_BASIC,
- .typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
+ CLK_IS_BASIC,
+ .typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO |
+ CLK_FRAC,
.mult = NA_MULT,
.div = NA_DIV,
},
@@ -577,7 +582,8 @@ static struct pm_clock_node gem_ref_ungated_nodes[] = {
.type = TYPE_DIV2,
.offset = 16,
.width = 6,
- .clkflags = CLK_SET_RATE_NO_REPARENT | CLK_IS_BASIC,
+ .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,
@@ -2352,7 +2358,6 @@ static uint32_t pm_clk_invalid_list[] = {CLK_USB0, CLK_USB1, CLK_CSU_SPB,
CLK_DBG_TSTMP,
CLK_DDR_REF,
CLK_TOPSW_MAIN,
- CLK_TOPSW_LSBUS,
CLK_GTGREF0_REF,
CLK_LPD_SWITCH,
CLK_CPU_R5,
@@ -2462,6 +2467,7 @@ enum pm_ret_status pm_api_clock_get_topology(unsigned int clock_id,
struct pm_clock_node *clock_nodes;
uint8_t num_nodes;
unsigned int i;
+ uint16_t typeflags;
if (!pm_clock_valid(clock_id))
return PM_RET_ERROR_ARGS;
@@ -2481,11 +2487,14 @@ enum pm_ret_status pm_api_clock_get_topology(unsigned int clock_id,
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].type;
topology[i] |= clock_nodes[index + i].clkflags <<
CLK_CLKFLAGS_SHIFT;
- topology[i] |= clock_nodes[index + i].typeflags <<
+ 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;
@@ -2612,6 +2621,42 @@ enum pm_ret_status pm_api_clock_get_attributes(unsigned int clock_id,
}
/**
+ * 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 = (1 << (BIT(nodes[i].width) - 1));
+ } else {
+ *max_div = BIT(nodes[i].width) - 1;
+ }
+ 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
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_clock.h b/plat/xilinx/zynqmp/pm_service/pm_api_clock.h
index 5bed5a6176..301ed24b65 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_clock.h
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_clock.h
@@ -43,7 +43,6 @@
#define CLK_IS_CRITICAL BIT(11) /* do not gate, ever */
/* parents need enable during gate/ungate, set rate and re-parent */
#define CLK_OPS_PARENT_ENABLE BIT(12)
-#define CLK_FRAC BIT(13)
#define CLK_DIVIDER_ONE_BASED BIT(0)
#define CLK_DIVIDER_POWER_OF_TWO BIT(1)
@@ -52,6 +51,7 @@
#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"
@@ -307,6 +307,9 @@ enum pm_ret_status pm_api_clock_get_parents(unsigned int clock_id,
uint32_t *parents);
enum pm_ret_status pm_api_clock_get_attributes(unsigned int 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);
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
index e0b9816e4f..b1720d9f6c 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -630,6 +630,22 @@ enum pm_ret_status pm_aes_engine(uint32_t address_high,
}
/**
+ * 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_pinctrl_request() - Request Pin from firmware
* @pin Pin number to request
*
@@ -741,6 +757,23 @@ enum pm_ret_status pm_ioctl(enum pm_node_id nid,
}
/**
+ * 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(unsigned int 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
*
@@ -1322,6 +1355,11 @@ enum pm_ret_status pm_query_data(enum pm_query_id qid,
ret = pm_clock_get_num_clocks(&data[1]);
data[0] = (unsigned int)ret;
break;
+
+ case PM_QID_CLOCK_GET_MAX_DIVISOR:
+ ret = pm_clock_get_max_divisor(arg1, arg2, &data[1]);
+ data[0] = (unsigned int)ret;
+ break;
default:
ret = PM_RET_ERROR_ARGS;
WARN("Unimplemented query service call: 0x%x\n", qid);
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.h b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h
index 282ca3dc65..ff66d3f024 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.h
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -25,6 +25,7 @@ enum pm_query_id {
PM_QID_PINCTRL_GET_FUNCTION_GROUPS,
PM_QID_PINCTRL_GET_PIN_GROUPS,
PM_QID_CLOCK_GET_NUM_CLOCKS,
+ PM_QID_CLOCK_GET_MAX_DIVISOR,
};
/**********************************************************
@@ -116,6 +117,7 @@ enum pm_ret_status pm_secure_rsaaes(uint32_t address_high,
uint32_t size,
uint32_t flags);
unsigned int pm_get_shutdown_scope(void);
+void pm_get_callbackdata(uint32_t *data, size_t count);
enum pm_ret_status pm_pinctrl_request(unsigned int pin);
enum pm_ret_status pm_pinctrl_release(unsigned int pin);
enum pm_ret_status pm_pinctrl_get_function(unsigned int pin,
diff --git a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c
index faa2827450..98dbe7d6e8 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c
+++ b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -25,6 +25,7 @@
#include "pm_client.h"
#include "pm_ipi.h"
+#define PM_GET_CALLBACK_DATA 0xa01
#define PM_SET_SUSPEND_MODE 0xa02
#define PM_GET_TRUSTZONE_VERSION 0xa03
@@ -76,8 +77,12 @@ static void trigger_wdt_restart(void)
INFO("Active Cores: %d\n", active_cores);
- /* trigger SGI to active cores */
- gicv2_raise_sgi(ARM_IRQ_SEC_SGI_7, target_cpu_list);
+ 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);
+ }
+ }
}
/**
@@ -105,6 +110,8 @@ static uint64_t ttc_fiq_handler(uint32_t id, uint32_t flags, void *handle,
{
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);
@@ -412,6 +419,16 @@ uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
pm_arg[3]);
SMC_RET1(handle, (uint64_t)ret);
+ case PM_GET_CALLBACK_DATA:
+ {
+ uint32_t result[4] = {0};
+
+ pm_get_callbackdata(result, (sizeof(result)/sizeof(uint32_t)));
+ SMC_RET2(handle,
+ (uint64_t)result[0] | ((uint64_t)result[1] << 32),
+ (uint64_t)result[2] | ((uint64_t)result[3] << 32));
+ }
+
case PM_PINCTRL_REQUEST:
ret = pm_pinctrl_request(pm_arg[0]);
SMC_RET1(handle, (uint64_t)ret);
diff --git a/tools/cert_create/src/cert.c b/tools/cert_create/src/cert.c
index c68a265b43..153f5557df 100644
--- a/tools/cert_create/src/cert.c
+++ b/tools/cert_create/src/cert.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -15,12 +15,6 @@
#include <openssl/sha.h>
#include <openssl/x509v3.h>
-#if USE_TBBR_DEFS
-#include <tbbr_oid.h>
-#else
-#include <platform_oid.h>
-#endif
-
#include "cert.h"
#include "cmd_opt.h"
#include "debug.h"
diff --git a/tools/cert_create/src/key.c b/tools/cert_create/src/key.c
index 0f80cce9b7..fcc9d53162 100644
--- a/tools/cert_create/src/key.c
+++ b/tools/cert_create/src/key.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -13,12 +13,6 @@
#include <openssl/evp.h>
#include <openssl/pem.h>
-#if USE_TBBR_DEFS
-#include <tbbr_oid.h>
-#else
-#include <platform_oid.h>
-#endif
-
#include "cert.h"
#include "cmd_opt.h"
#include "debug.h"
diff --git a/tools/cert_create/src/main.c b/tools/cert_create/src/main.c
index 0cbd2196bc..863db7b6e8 100644
--- a/tools/cert_create/src/main.c
+++ b/tools/cert_create/src/main.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -19,21 +19,12 @@
#include <openssl/sha.h>
#include <openssl/x509v3.h>
-#if USE_TBBR_DEFS
-#include <tbbr_oid.h>
-#else
-#include <platform_oid.h>
-#endif
-
#include "cert.h"
#include "cmd_opt.h"
#include "debug.h"
#include "ext.h"
#include "key.h"
#include "sha.h"
-#include "tbbr/tbb_cert.h"
-#include "tbbr/tbb_ext.h"
-#include "tbbr/tbb_key.h"
/*
* Helper macros to simplify the code. This macro assigns the return value of