Merge pull request #1450 from MISL-EBU-System-SW/marvell-support-v6
authordanh-arm <dan.handley@arm.com>
Thu, 19 Jul 2018 16:11:32 +0000 (17:11 +0100)
committerGitHub <noreply@github.com>
Thu, 19 Jul 2018 16:11:32 +0000 (17:11 +0100)
Marvell support for Armada 8K SoC family

116 files changed:
.gitignore
acknowledgements.rst
docs/marvell/build.txt [new file with mode: 0644]
docs/marvell/misc/mvebu-a8k-addr-map.txt [new file with mode: 0644]
docs/marvell/misc/mvebu-amb.txt [new file with mode: 0644]
docs/marvell/misc/mvebu-ccu.txt [new file with mode: 0644]
docs/marvell/misc/mvebu-io-win.txt [new file with mode: 0644]
docs/marvell/misc/mvebu-iob.txt [new file with mode: 0644]
docs/marvell/porting.txt [new file with mode: 0644]
drivers/io/io_fip.c
drivers/io/io_memmap.c
drivers/io/io_semihosting.c
drivers/io/io_storage.c
drivers/marvell/amb_adec.c [new file with mode: 0644]
drivers/marvell/cache_llc.c [new file with mode: 0644]
drivers/marvell/ccu.c [new file with mode: 0644]
drivers/marvell/comphy.h [new file with mode: 0644]
drivers/marvell/comphy/comphy-cp110.h [new file with mode: 0644]
drivers/marvell/comphy/phy-comphy-cp110.c [new file with mode: 0644]
drivers/marvell/comphy/phy-comphy-cp110.h [new file with mode: 0644]
drivers/marvell/gwin.c [new file with mode: 0644]
drivers/marvell/i2c/a8k_i2c.c [new file with mode: 0644]
drivers/marvell/io_win.c [new file with mode: 0644]
drivers/marvell/iob.c [new file with mode: 0644]
drivers/marvell/mci.c [new file with mode: 0644]
drivers/marvell/mochi/ap807_setup.c [new file with mode: 0644]
drivers/marvell/mochi/apn806_setup.c [new file with mode: 0644]
drivers/marvell/mochi/cp110_setup.c [new file with mode: 0644]
drivers/marvell/thermal.c [new file with mode: 0644]
include/drivers/marvell/a8k_i2c.h [new file with mode: 0644]
include/drivers/marvell/addr_map.h [new file with mode: 0644]
include/drivers/marvell/amb_adec.h [new file with mode: 0644]
include/drivers/marvell/aro.h [new file with mode: 0644]
include/drivers/marvell/cache_llc.h [new file with mode: 0644]
include/drivers/marvell/ccu.h [new file with mode: 0644]
include/drivers/marvell/gwin.h [new file with mode: 0644]
include/drivers/marvell/i2c.h [new file with mode: 0644]
include/drivers/marvell/io_win.h [new file with mode: 0644]
include/drivers/marvell/iob.h [new file with mode: 0644]
include/drivers/marvell/mci.h [new file with mode: 0644]
include/drivers/marvell/mochi/ap_setup.h [new file with mode: 0644]
include/drivers/marvell/mochi/cp110_setup.h [new file with mode: 0644]
include/drivers/marvell/thermal.h [new file with mode: 0644]
include/lib/cpus/aarch64/cortex_a72.h
include/plat/marvell/a8k/common/a8k_common.h [new file with mode: 0644]
include/plat/marvell/a8k/common/board_marvell_def.h [new file with mode: 0644]
include/plat/marvell/a8k/common/marvell_def.h [new file with mode: 0644]
include/plat/marvell/a8k/common/plat_marvell.h [new file with mode: 0644]
include/plat/marvell/a8k/common/plat_pm_trace.h [new file with mode: 0644]
include/plat/marvell/common/aarch64/cci_macros.S [new file with mode: 0644]
include/plat/marvell/common/aarch64/marvell_macros.S [new file with mode: 0644]
include/plat/marvell/common/marvell_plat_priv.h [new file with mode: 0644]
include/plat/marvell/common/marvell_pm.h [new file with mode: 0644]
include/plat/marvell/common/mvebu.h [new file with mode: 0644]
maintainers.rst
make_helpers/build_macros.mk
plat/marvell/a8k/a70x0/board/dram_port.c [new file with mode: 0644]
plat/marvell/a8k/a70x0/board/marvell_plat_config.c [new file with mode: 0644]
plat/marvell/a8k/a70x0/mvebu_def.h [new file with mode: 0644]
plat/marvell/a8k/a70x0/platform.mk [new file with mode: 0644]
plat/marvell/a8k/a70x0_amc/board/dram_port.c [new file with mode: 0644]
plat/marvell/a8k/a70x0_amc/board/marvell_plat_config.c [new file with mode: 0644]
plat/marvell/a8k/a70x0_amc/mvebu_def.h [new file with mode: 0644]
plat/marvell/a8k/a70x0_amc/platform.mk [new file with mode: 0644]
plat/marvell/a8k/a80x0/board/dram_port.c [new file with mode: 0644]
plat/marvell/a8k/a80x0/board/marvell_plat_config.c [new file with mode: 0644]
plat/marvell/a8k/a80x0/mvebu_def.h [new file with mode: 0644]
plat/marvell/a8k/a80x0/platform.mk [new file with mode: 0644]
plat/marvell/a8k/a80x0_mcbin/board/dram_port.c [new file with mode: 0644]
plat/marvell/a8k/a80x0_mcbin/board/marvell_plat_config.c [new file with mode: 0644]
plat/marvell/a8k/a80x0_mcbin/mvebu_def.h [new file with mode: 0644]
plat/marvell/a8k/a80x0_mcbin/platform.mk [new file with mode: 0644]
plat/marvell/a8k/common/a8k_common.mk [new file with mode: 0644]
plat/marvell/a8k/common/aarch64/a8k_common.c [new file with mode: 0644]
plat/marvell/a8k/common/aarch64/plat_arch_config.c [new file with mode: 0644]
plat/marvell/a8k/common/aarch64/plat_helpers.S [new file with mode: 0644]
plat/marvell/a8k/common/include/a8k_plat_def.h [new file with mode: 0644]
plat/marvell/a8k/common/include/ddr_info.h [new file with mode: 0644]
plat/marvell/a8k/common/include/plat_macros.S [new file with mode: 0644]
plat/marvell/a8k/common/include/platform_def.h [new file with mode: 0644]
plat/marvell/a8k/common/mss/mss_a8k.mk [new file with mode: 0644]
plat/marvell/a8k/common/mss/mss_bl2_setup.c [new file with mode: 0644]
plat/marvell/a8k/common/mss/mss_pm_ipc.c [new file with mode: 0644]
plat/marvell/a8k/common/mss/mss_pm_ipc.h [new file with mode: 0644]
plat/marvell/a8k/common/plat_bl1_setup.c [new file with mode: 0644]
plat/marvell/a8k/common/plat_bl31_setup.c [new file with mode: 0644]
plat/marvell/a8k/common/plat_ble_setup.c [new file with mode: 0644]
plat/marvell/a8k/common/plat_pm.c [new file with mode: 0644]
plat/marvell/a8k/common/plat_pm_trace.c [new file with mode: 0644]
plat/marvell/a8k/common/plat_thermal.c [new file with mode: 0644]
plat/marvell/common/aarch64/marvell_common.c [new file with mode: 0644]
plat/marvell/common/aarch64/marvell_helpers.S [new file with mode: 0644]
plat/marvell/common/marvell_bl1_setup.c [new file with mode: 0644]
plat/marvell/common/marvell_bl2_setup.c [new file with mode: 0644]
plat/marvell/common/marvell_bl31_setup.c [new file with mode: 0644]
plat/marvell/common/marvell_cci.c [new file with mode: 0644]
plat/marvell/common/marvell_common.mk [new file with mode: 0644]
plat/marvell/common/marvell_ddr_info.c [new file with mode: 0644]
plat/marvell/common/marvell_gicv2.c [new file with mode: 0644]
plat/marvell/common/marvell_io_storage.c [new file with mode: 0644]
plat/marvell/common/marvell_pm.c [new file with mode: 0644]
plat/marvell/common/marvell_topology.c [new file with mode: 0644]
plat/marvell/common/mrvl_sip_svc.c [new file with mode: 0644]
plat/marvell/common/mss/mss_common.mk [new file with mode: 0644]
plat/marvell/common/mss/mss_ipc_drv.c [new file with mode: 0644]
plat/marvell/common/mss/mss_ipc_drv.h [new file with mode: 0644]
plat/marvell/common/mss/mss_mem.h [new file with mode: 0644]
plat/marvell/common/mss/mss_scp_bl2_format.h [new file with mode: 0644]
plat/marvell/common/mss/mss_scp_bootloader.c [new file with mode: 0644]
plat/marvell/common/mss/mss_scp_bootloader.h [new file with mode: 0644]
plat/marvell/common/plat_delay_timer.c [new file with mode: 0644]
plat/marvell/marvell.mk [new file with mode: 0644]
plat/marvell/version.mk [new file with mode: 0644]
tools/doimage/Makefile [new file with mode: 0644]
tools/doimage/doimage.c [new file with mode: 0644]
tools/doimage/doimage.mk [new file with mode: 0644]

index 4ece189ab25b664a651b34e2d005d1c11341218a..7f8642e3447e0495b72bb1d15db00cb972ff339d 100644 (file)
@@ -18,6 +18,7 @@ tools/cert_create/src/*.o
 tools/cert_create/src/**/*.o
 tools/cert_create/cert_create
 tools/cert_create/cert_create.exe
+tools/doimage/doimage
 
 # GNU GLOBAL files
 GPATH
index 9b81b6c5e97169808eef0d8b14170dd2c8be9b53..5686a580daaaa639366ec09de1c0637bac6e76ab 100644 (file)
@@ -14,5 +14,7 @@ Xilinx, Inc.
 
 NXP Semiconductors
 
+Marvell International Ltd.
+
 Individuals
 -----------
diff --git a/docs/marvell/build.txt b/docs/marvell/build.txt
new file mode 100644 (file)
index 0000000..63a40a8
--- /dev/null
@@ -0,0 +1,181 @@
+TF-A Build Instructions
+======================
+
+This section describes how to compile the ARM Trusted Firmware (TF-A) project for Marvell's platforms.
+
+Build Instructions
+------------------
+(1) Set the cross compiler::
+
+               > export CROSS_COMPILE=/path/to/toolchain/aarch64-linux-gnu-
+
+(2) Set path for FIP images:
+
+       Set U-Boot image path (relatively to TF-A root or absolute path)::
+
+               > export BL33=path/to/u-boot.bin
+
+       For example: if U-Boot project (and its images) is located at ~/project/u-boot,
+       BL33 should be ~/project/u-boot/u-boot.bin
+
+       .. note::
+
+          u-boot.bin should be used and not u-boot-spl.bin
+
+       Set MSS/SCP image path (mandatory only for Armada80x0 and Aramada8xxy)::
+
+               > export SCP_BL2=path/to/mrvl_scp_bl2*.img
+
+(3) Armada-37x0 build requires WTP tools installation.
+
+       See below in the section "Tools Installation for Armada37x0 Builds".
+       Install ARM 32-bit cross compiler, which is required by building WTMI image for CM3::
+
+               > sudo apt-get install gcc-arm-linux-gnueabi
+
+(4) Clean previous build residuals (if any)::
+
+               > make distclean
+
+(5) Build TF-A:
+
+       There are several build options:
+
+       - DEBUG: default is without debug information (=0). in order to enable it use DEBUG=1
+
+       - LOG_LEVEL: defines the level of logging which will be purged to the default output port.
+
+               LOG_LEVEL_NONE          0
+               LOG_LEVEL_ERROR         10
+               LOG_LEVEL_NOTICE        20
+               LOG_LEVEL_WARNING       30
+               LOG_LEVEL_INFO          40
+               LOG_LEVEL_VERBOSE       50
+
+       - USE_COHERENT_MEM: This flag determines whether to include the coherent memory region in the
+               BL memory map or not.
+
+       -LLC_ENABLE: Flag defining the LLC (L3) cache state. The cache is enabled by default (LLC_ENABLE=1).
+
+       - MARVELL_SECURE_BOOT: build trusted(=1)/non trusted(=0) image, default is non trusted.
+
+       - BLE_PATH:
+               Points to BLE (Binary ROM extension) sources folder. Only required for A8K and A8K+ builds.
+               The parameter is optional, its default value is "ble".
+
+       - MV_DDR_PATH:
+               For A7/8K, use this parameter to point to mv_ddr driver sources to allow BLE build. For A37x0,
+               it is used for ddr_tool build.
+               Usage example: MV_DDR_PATH=path/to/mv_ddr
+               The parameter is optional for A7/8K, when this parameter is not set, the mv_ddr
+               sources are expected to be located at: drivers/marvell/mv_ddr. However, the parameter
+               is necessary for A37x0.
+
+       - DDR_TOPOLOGY: For Armada37x0 only, the DDR topology map index/name, default is 0.
+               Supported Options:
+                       - DDR3 1CS (0): DB-88F3720-DDR3-Modular (512MB); EspressoBIN (512MB)
+                       - DDR4 1CS (1): DB-88F3720-DDR4-Modular (512MB)
+                       - DDR3 2CS (2): EspressoBIN (1GB)
+                       - DDR4 2CS (3): DB-88F3720-DDR4-Modular (4GB)
+                       - DDR3 1CS (4): DB-88F3720-DDR3-Modular (1GB)
+                       - CUSTOMER (CUST): Customer board, DDR3 1CS 512MB
+
+       - CLOCKSPRESET: For Armada37x0 only, the clock tree configuration preset including CPU and DDR frequency,
+               default is CPU_800_DDR_800.
+                       - CPU_600_DDR_600       -       CPU at 600 MHz, DDR at 600 MHz
+                       - CPU_800_DDR_800       -       CPU at 800 MHz, DDR at 800 MHz
+                       - CPU_1000_DDR_800      -       CPU at 1000 MHz, DDR at 800 MHz
+                       - CPU_1200_DDR_750      -       CPU at 1200 MHz, DDR at 750 MHz
+
+       - BOOTDEV: For Armada37x0 only, the flash boot device, default is SPINOR,
+                       Currently, Armada37x0 only supports SPINOR, SPINAND, EMMCNORM and SATA:
+
+                               - SPINOR - SPI NOR flash boot
+                               - SPINAND - SPI NAND flash boot
+                               - EMMCNORM - eMMC Download Mode
+                                       Download boot loader or program code from eMMC flash into CM3 or CA53
+                                       Requires full initialization and command sequence
+                               - SATA - SATA device boot
+
+       - PARTNUM: For Armada37x0 only, the boot partition number, default is 0. To boot from eMMC, the value
+               should be aligned with the parameter in U-Boot with name of CONFIG_SYS_MMC_ENV_PART, whose
+               value by default is 1.
+               For details about CONFIG_SYS_MMC_ENV_PART, please refer to the U-Boot build instructions.
+
+       - WTMI_IMG: For Armada37x0 only, the path of the WTMI image can point to an image which does
+               nothing, an image which supports EFUSE or a customized CM3 firmware binary. The default image
+               is wtmi.bin that built from sources in WTP folder, which is the next option. If the default
+               image is OK, then this option should be skipped.
+       - WTP: For Armada37x0 only, use this parameter to point to wtptools source code directory, which
+               can be found as a3700_utils.zip in the release.
+               Usage example: WTP=/path/to/a3700_utils
+
+       - CP_NUM: Total amount of CPs (South Bridge) chips wired to the interconnected APs.
+               When the parameter is omitted, the build is uses the default number of CPs equal to 2.
+               The parameter is valid for Armada 8K-plus SoC family (PLAT=a8xxy) and results in a build of images
+               suitable for a8xxY SoC, where "Y" is a number of connected CPs and "xx" is a number of CPU cores.
+               Valid values with CP_NUM is in a range of 0 to 8.
+               The CPs defined by this parameter are evenly distributed across interconnected APs that in turn
+               are dynamically detected. For instance, if the CP_NUM=6 and the TF-A detects 2 interconnected
+               APs, each AP assumed to have 3 attached CPs. With the same amount of APs and CP_NUM=3, the AP0
+               will have 2 CPs connected and AP1 - a just single CP.
+
+       For example, in order to build the image in debug mode with log level up to 'notice' level run::
+
+               > make DEBUG=1 USE_COHERENT_MEM=0 LOG_LEVEL=20 PLAT=<MARVELL_PLATFORM> all fip
+
+       And if we want to build a Armada37x0 image in debug mode with log level up to 'notice' level,
+       the image has the preset CPU at 1000 MHz, preset DDR3 at 800 MHz, the DDR topology of DDR3 2CS,
+       the image boot from SPI NOR flash partition 0, and the image is non trusted in WTP, the command
+       line is as following::
+
+               > make DEBUG=1 USE_COHERENT_MEM=0 LOG_LEVEL=20 SECURE=0 CLOCKSPRESET=CPU_1000_DDR_800 \
+                       DDR_TOPOLOGY=2 BOOTDEV=SPINOR PARTNUM=0 PLAT=a3700 all fip
+
+       Supported MARVELL_PLATFORM are:
+               - a3700
+               - a70x0
+               - a70x0_amc (for AMC board)
+               - a70x0_cust (for customers)
+               - a80x0
+               - a80x0_mcbin (for MacciatoBin)
+
+Special Build Flags
+--------------------
+       - PLAT_RECOVERY_IMAGE_ENABLE: When set this option to enable secondary recovery function when build
+               atf. In order to build uart recovery image this operation should be disabled for a70x0 and a80x0
+                because of hardware limitation(boot from secondary image can interrupt uart recovery process).
+               This MACRO definition is set in plat/marvell/a8k/common/include/platform_def.h file
+
+(for more information about build options, please refer to section 'Summary of build options' in  TF-A user-guide:
+ https://github.com/ARM-software/arm-trusted-firmware/blob/master/docs/user-guide.md)
+
+
+Build output
+-------------
+Marvell's TF-A compilation generates 7 files:
+       - ble.bin               - BLe image
+       - bl1.bin               - BL1 image
+       - bl2.bin               - BL2 image
+       - bl31.bin              - BL31 image
+       - fip.bin               - FIP image (contains BL2, BL31 & BL33 (U-Boot) images)
+       - boot-image.bin        - TF-A image (contains BL1 and FIP images)
+       - flash-image.bin       - Image which contains boot-image.bin and SPL image; should be placed on the boot flash/device.
+
+
+Tools Installation for Armada37x0 Builds
+-----------------------------------------
+Install a cross GNU ARM tool chain for building the WTMI binary.
+Any cross GNU ARM tool chain that is able to build ARM Cortex M3 binaries
+is suitable.
+
+On Debian/Uboot hosts the default GNU ARM tool chain can be installed
+using the following command::
+
+               > sudo apt-get install gcc-arm-linux-gnueabi
+
+If required, the default tool chain prefix "arm-linux-gnueabi-" can be
+overwritten using the environment variable CROSS_CM3.
+Example for BASH shell::
+
+               > export CROSS_CM3=/opt/arm-cross/bin/arm-linux-gnueabi
diff --git a/docs/marvell/misc/mvebu-a8k-addr-map.txt b/docs/marvell/misc/mvebu-a8k-addr-map.txt
new file mode 100644 (file)
index 0000000..586e8b7
--- /dev/null
@@ -0,0 +1,47 @@
+Address decoding flow and address translation units of Marvell Armada 8K SoC family
+
++--------------------------------------------------------------------------------------------------+
+|                                                              +-------------+    +--------------+ |
+|                                                              | Memory      +-----   DRAM CS    | |
+|+------------+ +-----------+ +-----------+                    | Controller  |    +--------------+ |
+||  AP DMA    | |           | |           |                    +-------------+                     |
+||  SD/eMMC   | | CA72 CPUs | |  AP MSS   |                    +-------------+                     |
+||  MCI-0/1   | |           | |           |                    | Memory      |                     |
+|+------+-----+ +--+--------+ +--------+--+  +------------+    | Controller  |     +-------------+ |
+|       |          |                   |     |            +----- Translaton  |     |AP           | |
+|       |          |                   |     |            |    +-------------+     |Configuration| |
+|       |          |                   +-----+            +-------------------------Space        | |
+|       |          | +-------------+         |  CCU       |                        +-------------+ |
+|       |          | | MMU         +---------+  Windows   |   +-----------+        +-------------+ |
+|       |          +-| translation |         |  Lookup    +----           +---------   AP SPI    | |
+|       |            +-------------+         |            |   |           |        +-------------+ |
+|       |            +-------------+         |            |   |  IO       |        +-------------+ |
+|       +------------| SMMU        +---------+            |   |  Windows  +---------  AP MCI0/1  | |
+|                    | translation |         +------------+   |  Lookup   |        +-------------+ |
+|                    +---------+---+                          |           |        +-------------+ |
+|             -                |                              |           +---------   AP STM    | |
+|             +-----------------                              |           |        +-------------+ |
+| AP          |                |                              +-+---------+                        |
++---------------------------------------------------------------|----------------------------------+
++-------------|-------------------------------------------------|----------------------------------+
+| CP          |            +-------------+               +------+-----+      +-------------------+ |
+|             |            |             |               |            +-------   SB CFG Space    | |
+|             |            |   DIOB      |               |            |      +-------------------+ |
+|             |            |   Windows   -----------------  IOB       |      +-------------------+ |
+|             |            |   Control   |               |  Windows   +------| SB PCIe-0 - PCIe2 | |
+|             |            |             |               |  Lookup    |      +-------------------+ |
+|             |            +------+------+               |            |      +-------------------+ |
+|             |                   |                      |            +------+      SB NAND      | |
+|             |                   |                      +------+-----+      +-------------------+ |
+|             |                   |                             |                                  |
+|             |                   |                             |                                  |
+|   +------------------+   +------------+                +------+-----+      +-------------------+ |
+|   | Network Engine   |   |            |                |            +-------  SB SPI-0/SPI-1   | |
+|   | Security Engine  |   | PCIe, MSS  |                |  RUNIT     |      +-------------------+ |
+|   | SATA, USB        |   | DMA        |                |  Windows   |      +-------------------+ |
+|   | SD/eMMC          |   |            |                |  Lookup    +-------   SB Device Bus   | |
+|   | TDM, I2C         |   |            |                |            |      +-------------------+ |
+|   +------------------+   +------------+                +------------+                            |
+|                                                                                                  |
++--------------------------------------------------------------------------------------------------+
+
diff --git a/docs/marvell/misc/mvebu-amb.txt b/docs/marvell/misc/mvebu-amb.txt
new file mode 100644 (file)
index 0000000..2a7a41e
--- /dev/null
@@ -0,0 +1,45 @@
+AMB - AXI MBUS address decoding
+-------------------------------
+
+AXI to M-bridge decoding unit driver for Marvell Armada 8K and 8K+ SoCs.
+
+- The Runit offers a second level of address windows lookup. It is used to map transaction towards
+the CD BootROM, SPI0, SPI1 and Device bus (NOR).
+- The Runit contains eight configurable windows. Each window defines a contiguous,
+address space and the properties associated with that address space.
+
+Unit           Bank            ATTR
+Device-Bus     DEV_BOOT_CS     0x2F
+               DEV_CS0         0x3E
+               DEV_CS1         0x3D
+               DEV_CS2         0x3B
+               DEV_CS3         0x37
+SPI-0          SPI_A_CS0       0x1E
+               SPI_A_CS1       0x5E
+               SPI_A_CS2       0x9E
+               SPI_A_CS3       0xDE
+               SPI_A_CS4       0x1F
+               SPI_A_CS5       0x5F
+               SPI_A_CS6       0x9F
+               SPI_A_CS7       0xDF
+SPI1           SPI_B_CS0       0x1A
+               SPI_B_CS1       0x5A
+               SPI_B_CS2       0x9A
+               SPI_B_CS3       0xDA
+BOOT_ROM       BOOT_ROM        0x1D
+UART           UART            0x01
+
+Mandatory functions:
+       - marvell_get_amb_memory_map
+               returns the AMB windows configuration and the number of windows
+
+Mandatory structures:
+       amb_memory_map - Array that include the configuration of the windows
+         every window/entry is a struct which has 2 parameters:
+         - base address of the window
+         - Attribute of the window
+
+Examples:
+       struct addr_map_win amb_memory_map[] = {
+               {0xf900,        AMB_DEV_CS0_ID},
+       };
diff --git a/docs/marvell/misc/mvebu-ccu.txt b/docs/marvell/misc/mvebu-ccu.txt
new file mode 100644 (file)
index 0000000..9764027
--- /dev/null
@@ -0,0 +1,23 @@
+Marvell CCU address decoding bindings
+=====================================
+
+CCU configration driver (1st stage address translation) for Marvell Armada 8K and 8K+ SoCs.
+
+The CCU node includes a description of the address decoding configuration.
+
+Mandatory functions:
+       - marvell_get_ccu_memory_map
+               return the CCU windows configuration and the number of windows
+               of the specific AP.
+
+Mandatory structures:
+       ccu_memory_map - Array that includes the configuration of the windows
+         every window/entry is a struct which has 3 parameters:
+         - Base address of the window
+         - Size of the window
+         - Target-ID of the window
+
+Example:
+       struct addr_map_win ccu_memory_map[] = {
+               {0x00000000f2000000,     0x00000000e000000,      IO_0_TID}, /* IO window */
+       };
diff --git a/docs/marvell/misc/mvebu-io-win.txt b/docs/marvell/misc/mvebu-io-win.txt
new file mode 100644 (file)
index 0000000..c83ad1f
--- /dev/null
@@ -0,0 +1,35 @@
+Marvell IO WIN address decoding bindings
+=====================================
+
+IO Window configration driver (2nd stage address translation) for Marvell Armada 8K and 8K+ SoCs.
+
+The IO WIN includes a description of the address decoding configuration.
+
+Transactions that are decoded by CCU windows as IO peripheral, have an additional
+layer of decoding. This additional address decoding layer defines one of the
+following targets:
+       0x0 = BootRom
+       0x1 = STM (Serial Trace Macro-cell, a programmer's port into trace stream)
+       0x2 = SPI direct access
+       0x3 = PCIe registers
+       0x4 = MCI Port
+       0x5 = PCIe port
+
+Mandatory functions:
+       - marvell_get_io_win_memory_map
+               returns the IO windows configuration and the number of windows
+               of the specific AP.
+
+Mandatory structures:
+       io_win_memory_map - Array that include the configuration of the windows
+         every window/entry is a struct which has 3 parameters:
+         - Base address of the window
+         - Size of the window
+         - Target-ID of the window
+
+Example:
+       struct addr_map_win io_win_memory_map[] = {
+               {0x00000000fe000000,    0x000000001f00000,      PCIE_PORT_TID}, /* PCIe window 31Mb for PCIe port*/
+               {0x00000000ffe00000,    0x000000000100000,      PCIE_REGS_TID}, /* PCI-REG window 64Kb for PCIe-reg*/
+               {0x00000000f6000000,    0x000000000100000,      MCIPHY_TID},    /* MCI window  1Mb for PHY-reg*/
+       };
diff --git a/docs/marvell/misc/mvebu-iob.txt b/docs/marvell/misc/mvebu-iob.txt
new file mode 100644 (file)
index 0000000..97ec09d
--- /dev/null
@@ -0,0 +1,40 @@
+Marvell IOB address decoding bindings
+=====================================
+
+IO bridge configration driver (3rd stage address translation) for Marvell Armada 8K and 8K+ SoCs.
+
+The IOB includes a description of the address decoding configuration.
+
+IOB supports up to n (in CP110 n=24) windows for external memory transaction.
+When a transaction passes through the IOB, its address is compared to each of
+the enabled windows. If there is a hit and it passes the security checks, it is
+advanced to the target port.
+
+Mandatory functions:
+       - marvell_get_iob_memory_map
+               returns the IOB windows configuration and the number of windows
+
+Mandatory structures:
+       iob_memory_map - Array that include the configuration of the windows
+         every window/entry is a struct which has 3 parameters:
+         - Base address of the window
+         - Size of the window
+         - Target-ID of the window
+
+Target ID options:
+       - 0x0 = Internal configuration space
+       - 0x1 = MCI0
+       - 0x2 = PEX1_X1
+       - 0x3 = PEX2_X1
+       - 0x4 = PEX0_X4
+       - 0x5 = NAND flash
+       - 0x6 = RUNIT (NOR/SPI/BootRoom)
+       - 0x7 = MCI1
+
+Example:
+       struct addr_map_win iob_memory_map[] = {
+               {0x00000000f7000000,    0x0000000001000000,     PEX1_TID}, /* PEX1_X1 window */
+               {0x00000000f8000000,    0x0000000001000000,     PEX2_TID}, /* PEX2_X1 window */
+               {0x00000000f6000000,    0x0000000001000000,     PEX0_TID}, /* PEX0_X4 window */
+               {0x00000000f9000000,    0x0000000001000000,     NAND_TID}  /* NAND window */
+       };
diff --git a/docs/marvell/porting.txt b/docs/marvell/porting.txt
new file mode 100644 (file)
index 0000000..78000e9
--- /dev/null
@@ -0,0 +1,66 @@
+TF-A Porting Guide
+=================
+
+This section describes how to port TF-A to a customer board, assuming that the SoC being used is already supported
+in TF-A.
+
+
+Source Code Structure
+---------------------
+- The customer platform specific code shall reside under "plat/marvell/<soc family>/<soc>_cust"
+       (e.g. 'plat/marvell/a8k/a7040_cust').
+- The platform name for build purposes is called "<soc>_cust" (e.g. a7040_cust).
+- The build system will reuse all files from within the soc directory, and take only the porting
+  files from the customer platform directory.
+
+Files that require porting are located at "plat/marvell/<soc family>/<soc>_cust" directory.
+
+
+Armada-70x0/Armada-80x0 Porting
+-------------------------------
+
+  - SoC Physical Address Map (marvell_plat_config.c):
+       - This file describes the SoC physical memory mapping to be used for the CCU, IOWIN, AXI-MBUS and IOB
+         address decode units (Refer to the functional spec for more details).
+       - In most cases, using the default address decode windows should work OK.
+       - In cases where a special physical address map is needed (e.g. Special size for PCIe MEM windows,
+         large memory mapped SPI flash...), then porting of the SoC memory map is required.
+       - Note: For a detailed information on how CCU, IOWIN, AXI-MBUS & IOB work, please refer to the SoC functional spec,
+         and under "docs/marvell/misc/mvebu-[ccu/iob/amb/io-win].txt" files.
+
+  - boot loader recovery (marvell_plat_config.c):
+       - Background:
+               boot rom can skip the current image and choose to boot from next position if a specific value
+               (0xDEADB002) is returned by the ble main function. This feature is used for boot loader recovery
+               by booting from a valid flash-image saved in next position on flash (e.g. address 2M in SPI flash).
+
+               Supported options to implement the skip request are:
+                       - GPIO
+                       - I2C
+                       - User defined
+
+       - Porting:
+               Under marvell_plat_config.c, implement struct skip_image that includes specific board parameters.
+               .. warning:: to disable this feature make sure the struct skip_image is not implemented.
+
+       - Example:
+               In A7040-DB specific implementation (plat/marvell/a8k/a70x0/board/marvell_plat_config.c),
+               the image skip is implemented using GPIO: mpp 33 (SW5).
+
+               Before resetting the board make sure there is a valid image on the next flash address:
+                       -tftp [valid address] flash-image.bin
+                       -sf update [valid address] 0x2000000 [size]
+
+               Press reset and keep pressing the button connected to the chosen GPIO pin. A skip image request
+               message is printed on the screen and boot rom boots from the saved image at the next position.
+
+  - DDR Porting (dram_port.c):
+       - This file defines the dram topology and parameters of the target board.
+       - The DDR code is part of the BLE component, which is an extension of ARM Trusted Firmware (TF-A).
+       - The DDR driver called mv_ddr is released separately apart from TF-A sources.
+       - The BLE and consequently, the DDR init code is executed at the early stage of the boot process.
+       - Each supported platform of the TF-A has its own DDR porting file called dram_port.c located at
+         ``atf/plat/marvell/a8k/<platform>/board`` directory.
+       - Please refer to '<path_to_mv_ddr_sources>/doc/porting_guide.txt' for detailed porting description.
+       - The build target directory is "build/<platform>/release/ble".
+
index 6e7103dbee9374aad685a5de8da2c70f481ba8d3..9d6c763e8969bb92597a6c59fba4c25d76c05050 100644 (file)
@@ -372,7 +372,6 @@ static int fip_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
        uintptr_t backend_handle;
 
        assert(entity != NULL);
-       assert(buffer != (uintptr_t)NULL);
        assert(length_read != NULL);
        assert(entity->info != (uintptr_t)NULL);
 
index bf59d6a5c742cdcf93afb5ff1ac3e00ac9e4030e..5595e60a424909a8a7b295b0bbbdaa17c98ddcc4 100644 (file)
@@ -9,6 +9,7 @@
 #include <io_driver.h>
 #include <io_memmap.h>
 #include <io_storage.h>
+#include <platform_def.h>
 #include <string.h>
 #include <utils.h>
 
@@ -169,7 +170,6 @@ static int memmap_block_read(io_entity_t *entity, uintptr_t buffer,
        size_t pos_after;
 
        assert(entity != NULL);
-       assert(buffer != (uintptr_t)NULL);
        assert(length_read != NULL);
 
        fp = (file_state_t *) entity->info;
@@ -197,7 +197,6 @@ static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer,
        size_t pos_after;
 
        assert(entity != NULL);
-       assert(buffer != (uintptr_t)NULL);
        assert(length_written != NULL);
 
        fp = (file_state_t *) entity->info;
index 4abf44f7d2e21b0b4c4a62f5227dd6b033883695..9ca0a9dc9c2262dd3e0db38ef603f453045fc12f 100644 (file)
@@ -8,6 +8,7 @@
 #include <io_driver.h>
 #include <io_semihosting.h>
 #include <io_storage.h>
+#include <platform_def.h>
 #include <semihosting.h>
 
 
@@ -133,7 +134,6 @@ static int sh_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
        long file_handle;
 
        assert(entity != NULL);
-       assert(buffer != (uintptr_t)NULL);
        assert(length_read != NULL);
 
        file_handle = (long)entity->info;
@@ -158,7 +158,6 @@ static int sh_file_write(io_entity_t *entity, const uintptr_t buffer,
        size_t bytes = length;
 
        assert(entity != NULL);
-       assert(buffer != (uintptr_t)NULL);
        assert(length_written != NULL);
 
        file_handle = (long)entity->info;
index 0918de0a23daefb7ddb14c902e84818d266b1dc4..948f84813768d8c2204d4496cacd7adf9c1dbe4c 100644 (file)
@@ -279,7 +279,7 @@ int io_read(uintptr_t handle,
                size_t *length_read)
 {
        int result = -ENODEV;
-       assert(is_valid_entity(handle) && (buffer != (uintptr_t)NULL));
+       assert(is_valid_entity(handle));
 
        io_entity_t *entity = (io_entity_t *)handle;
 
@@ -299,7 +299,7 @@ int io_write(uintptr_t handle,
                size_t *length_written)
 {
        int result = -ENODEV;
-       assert(is_valid_entity(handle) && (buffer != (uintptr_t)NULL));
+       assert(is_valid_entity(handle));
 
        io_entity_t *entity = (io_entity_t *)handle;
 
diff --git a/drivers/marvell/amb_adec.c b/drivers/marvell/amb_adec.c
new file mode 100644 (file)
index 0000000..06a1957
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* AXI to M-Bridge decoding unit driver for Marvell Armada 8K and 8K+ SoCs */
+
+#include <a8k_common.h>
+#include <debug.h>
+#include <mmio.h>
+#include <mvebu.h>
+#include <mvebu_def.h>
+
+#if LOG_LEVEL >= LOG_LEVEL_INFO
+#define DEBUG_ADDR_MAP
+#endif
+
+/* common defines */
+#define WIN_ENABLE_BIT                 (0x1)
+
+#define MVEBU_AMB_ADEC_OFFSET          (0x70ff00)
+
+#define AMB_WIN_CR_OFFSET(win)         (amb_base + 0x0 + (0x8 * win))
+#define AMB_ATTR_OFFSET                        8
+#define AMB_ATTR_MASK                  0xFF
+#define AMB_SIZE_OFFSET                        16
+#define AMB_SIZE_MASK                  0xFF
+
+#define AMB_WIN_BASE_OFFSET(win)       (amb_base + 0x4 + (0x8 * win))
+#define AMB_BASE_OFFSET                        16
+#define AMB_BASE_ADDR_MASK             ((1 << (32 - AMB_BASE_OFFSET)) - 1)
+
+#define AMB_WIN_ALIGNMENT_64K          (0x10000)
+#define AMB_WIN_ALIGNMENT_1M           (0x100000)
+
+uintptr_t amb_base;
+
+static void amb_check_win(struct addr_map_win *win, uint32_t win_num)
+{
+       uint32_t base_addr;
+
+       /* make sure the base address is in 16-bit range */
+       if (win->base_addr > AMB_BASE_ADDR_MASK) {
+               WARN("Window %d: base address is too big 0x%llx\n",
+                      win_num, win->base_addr);
+               win->base_addr = AMB_BASE_ADDR_MASK;
+               WARN("Set the base address to 0x%llx\n", win->base_addr);
+       }
+
+       base_addr  = win->base_addr << AMB_BASE_OFFSET;
+       /* for AMB The base is always 1M aligned */
+       /* check if address is aligned to 1M */
+       if (IS_NOT_ALIGN(base_addr, AMB_WIN_ALIGNMENT_1M)) {
+               win->base_addr = ALIGN_UP(base_addr, AMB_WIN_ALIGNMENT_1M);
+               WARN("Window %d: base address unaligned to 0x%x\n",
+                      win_num, AMB_WIN_ALIGNMENT_1M);
+               WARN("Align up the base address to 0x%llx\n", win->base_addr);
+       }
+
+       /* size parameter validity check */
+       if (!IS_POWER_OF_2(win->win_size)) {
+               WARN("Window %d: window size is not power of 2 (0x%llx)\n",
+                      win_num, win->win_size);
+               win->win_size = ROUND_UP_TO_POW_OF_2(win->win_size);
+               WARN("Rounding size to 0x%llx\n", win->win_size);
+       }
+}
+
+static void amb_enable_win(struct addr_map_win *win, uint32_t win_num)
+{
+       uint32_t ctrl, base, size;
+
+       /*
+        * size is 64KB granularity.
+        * The number of ones specifies the size of the
+        * window in 64 KB granularity. 0 is 64KB
+        */
+       size = (win->win_size / AMB_WIN_ALIGNMENT_64K) - 1;
+       ctrl = (size << AMB_SIZE_OFFSET) | (win->target_id << AMB_ATTR_OFFSET);
+       base = win->base_addr << AMB_BASE_OFFSET;
+
+       mmio_write_32(AMB_WIN_BASE_OFFSET(win_num), base);
+       mmio_write_32(AMB_WIN_CR_OFFSET(win_num), ctrl);
+
+       /* enable window after configuring window size (and attributes) */
+       ctrl |= WIN_ENABLE_BIT;
+       mmio_write_32(AMB_WIN_CR_OFFSET(win_num), ctrl);
+}
+
+#ifdef DEBUG_ADDR_MAP
+static void dump_amb_adec(void)
+{
+       uint32_t ctrl, base, win_id, attr;
+       uint32_t size, size_count;
+
+       /* Dump all AMB windows */
+       tf_printf("bank  attribute     base          size\n");
+       tf_printf("--------------------------------------------\n");
+       for (win_id = 0; win_id < AMB_MAX_WIN_ID; win_id++) {
+               ctrl = mmio_read_32(AMB_WIN_CR_OFFSET(win_id));
+               if (ctrl & WIN_ENABLE_BIT) {
+                       base = mmio_read_32(AMB_WIN_BASE_OFFSET(win_id));
+                       attr = (ctrl >> AMB_ATTR_OFFSET) & AMB_ATTR_MASK;
+                       size_count = (ctrl >> AMB_SIZE_OFFSET) & AMB_SIZE_MASK;
+                       size = (size_count + 1) * AMB_WIN_ALIGNMENT_64K;
+                       tf_printf("amb   0x%04x        0x%08x    0x%08x\n",
+                                 attr, base, size);
+               }
+       }
+}
+#endif
+
+int init_amb_adec(uintptr_t base)
+{
+       struct addr_map_win *win;
+       uint32_t win_id, win_reg;
+       uint32_t win_count;
+
+       INFO("Initializing AXI to MBus Bridge Address decoding\n");
+
+       /* Get the base address of the AMB address decoding */
+       amb_base = base + MVEBU_AMB_ADEC_OFFSET;
+
+       /* Get the array of the windows and its size */
+       marvell_get_amb_memory_map(&win, &win_count, base);
+       if (win_count <= 0)
+               INFO("no windows configurations found\n");
+
+       if (win_count > AMB_MAX_WIN_ID) {
+               INFO("number of windows is bigger than %d\n", AMB_MAX_WIN_ID);
+               return 0;
+       }
+
+       /* disable all AMB windows */
+       for (win_id = 0; win_id < AMB_MAX_WIN_ID; win_id++) {
+               win_reg = mmio_read_32(AMB_WIN_CR_OFFSET(win_id));
+               win_reg &= ~WIN_ENABLE_BIT;
+               mmio_write_32(AMB_WIN_CR_OFFSET(win_id), win_reg);
+       }
+
+       /* enable relevant windows */
+       for (win_id = 0; win_id < win_count; win_id++, win++) {
+               amb_check_win(win, win_id);
+               amb_enable_win(win, win_id);
+       }
+
+#ifdef DEBUG_ADDR_MAP
+       dump_amb_adec();
+#endif
+
+       INFO("Done AXI to MBus Bridge Address decoding Initializing\n");
+
+       return 0;
+}
diff --git a/drivers/marvell/cache_llc.c b/drivers/marvell/cache_llc.c
new file mode 100644 (file)
index 0000000..e13e6ce
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* LLC driver is the Last Level Cache (L3C) driver
+ * for Marvell SoCs in AP806, AP807, and AP810
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <cache_llc.h>
+#include <ccu.h>
+#include <mmio.h>
+#include <mvebu_def.h>
+
+#define CCU_HTC_CR(ap_index)           (MVEBU_CCU_BASE(ap_index) + 0x200)
+#define CCU_SET_POC_OFFSET             5
+
+extern void ca72_l2_enable_unique_clean(void);
+
+void llc_cache_sync(int ap_index)
+{
+       mmio_write_32(LLC_SYNC(ap_index), 0);
+       /* Atomic write, no need to wait */
+}
+
+void llc_flush_all(int ap_index)
+{
+       mmio_write_32(L2X0_CLEAN_INV_WAY(ap_index), LLC_WAY_MASK);
+       llc_cache_sync(ap_index);
+}
+
+void llc_clean_all(int ap_index)
+{
+       mmio_write_32(L2X0_CLEAN_WAY(ap_index), LLC_WAY_MASK);
+       llc_cache_sync(ap_index);
+}
+
+void llc_inv_all(int ap_index)
+{
+       mmio_write_32(L2X0_INV_WAY(ap_index), LLC_WAY_MASK);
+       llc_cache_sync(ap_index);
+}
+
+void llc_disable(int ap_index)
+{
+       llc_flush_all(ap_index);
+       mmio_write_32(LLC_CTRL(ap_index), 0);
+       dsbishst();
+}
+
+void llc_enable(int ap_index, int excl_mode)
+{
+       uint32_t val;
+
+       dsbsy();
+       llc_inv_all(ap_index);
+       dsbsy();
+
+       val = LLC_CTRL_EN;
+       if (excl_mode)
+               val |= LLC_EXCLUSIVE_EN;
+
+       mmio_write_32(LLC_CTRL(ap_index), val);
+       dsbsy();
+}
+
+int llc_is_exclusive(int ap_index)
+{
+       uint32_t reg;
+
+       reg = mmio_read_32(LLC_CTRL(ap_index));
+
+       if ((reg & (LLC_CTRL_EN | LLC_EXCLUSIVE_EN)) ==
+                  (LLC_CTRL_EN | LLC_EXCLUSIVE_EN))
+               return 1;
+
+       return 0;
+}
+
+void llc_runtime_enable(int ap_index)
+{
+       uint32_t reg;
+
+       reg = mmio_read_32(LLC_CTRL(ap_index));
+       if (reg & LLC_CTRL_EN)
+               return;
+
+       INFO("Enabling LLC\n");
+
+       /*
+        * Enable L2 UniqueClean evictions with data
+        *  Note: this configuration assumes that LLC is configured
+        *        in exclusive mode.
+        *        Later on in the code this assumption will be validated
+        */
+       ca72_l2_enable_unique_clean();
+       llc_enable(ap_index, 1);
+
+       /* Set point of coherency to DDR.
+        * This is required by units which have SW cache coherency
+        */
+       reg = mmio_read_32(CCU_HTC_CR(ap_index));
+       reg |= (0x1 << CCU_SET_POC_OFFSET);
+       mmio_write_32(CCU_HTC_CR(ap_index), reg);
+}
diff --git a/drivers/marvell/ccu.c b/drivers/marvell/ccu.c
new file mode 100644 (file)
index 0000000..e478d63
--- /dev/null
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* CCU unit device driver for Marvell AP807, AP807 and AP810 SoCs */
+
+#include <a8k_common.h>
+#include <ccu.h>
+#include <debug.h>
+#include <mmio.h>
+#include <mvebu.h>
+#include <mvebu_def.h>
+
+#if LOG_LEVEL >= LOG_LEVEL_INFO
+#define DEBUG_ADDR_MAP
+#endif
+
+/* common defines */
+#define WIN_ENABLE_BIT                 (0x1)
+/* Physical address of the base of the window = {AddrLow[19:0],20’h0} */
+#define ADDRESS_SHIFT                  (20 - 4)
+#define ADDRESS_MASK                   (0xFFFFFFF0)
+#define CCU_WIN_ALIGNMENT              (0x100000)
+
+#define IS_DRAM_TARGET(tgt)            ((((tgt) == DRAM_0_TID) || \
+                                       ((tgt) == DRAM_1_TID) || \
+                                       ((tgt) == RAR_TID)) ? 1 : 0)
+
+/* For storage of CR, SCR, ALR, AHR abd GCR */
+static uint32_t ccu_regs_save[MVEBU_CCU_MAX_WINS * 4 + 1];
+
+#ifdef DEBUG_ADDR_MAP
+static void dump_ccu(int ap_index)
+{
+       uint32_t win_id, win_cr, alr, ahr;
+       uint8_t target_id;
+       uint64_t start, end;
+
+       /* Dump all AP windows */
+       tf_printf("\tbank  target     start              end\n");
+       tf_printf("\t----------------------------------------------------\n");
+       for (win_id = 0; win_id < MVEBU_CCU_MAX_WINS; win_id++) {
+               win_cr = mmio_read_32(CCU_WIN_CR_OFFSET(ap_index, win_id));
+               if (win_cr & WIN_ENABLE_BIT) {
+                       target_id = (win_cr >> CCU_TARGET_ID_OFFSET) &
+                                    CCU_TARGET_ID_MASK;
+                       alr = mmio_read_32(CCU_WIN_ALR_OFFSET(ap_index,
+                                                             win_id));
+                       ahr = mmio_read_32(CCU_WIN_AHR_OFFSET(ap_index,
+                                                             win_id));
+                       start = ((uint64_t)alr << ADDRESS_SHIFT);
+                       end = (((uint64_t)ahr + 0x10) << ADDRESS_SHIFT);
+                       tf_printf("\tccu    %02x     0x%016llx 0x%016llx\n",
+                                 target_id, start, end);
+               }
+       }
+       win_cr = mmio_read_32(CCU_WIN_GCR_OFFSET(ap_index));
+       target_id = (win_cr >> CCU_GCR_TARGET_OFFSET) & CCU_GCR_TARGET_MASK;
+       tf_printf("\tccu   GCR %d - all other transactions\n", target_id);
+}
+#endif
+
+void ccu_win_check(struct addr_map_win *win)
+{
+       /* check if address is aligned to 1M */
+       if (IS_NOT_ALIGN(win->base_addr, CCU_WIN_ALIGNMENT)) {
+               win->base_addr = ALIGN_UP(win->base_addr, CCU_WIN_ALIGNMENT);
+               NOTICE("%s: Align up the base address to 0x%llx\n",
+                      __func__, win->base_addr);
+       }
+
+       /* size parameter validity check */
+       if (IS_NOT_ALIGN(win->win_size, CCU_WIN_ALIGNMENT)) {
+               win->win_size = ALIGN_UP(win->win_size, CCU_WIN_ALIGNMENT);
+               NOTICE("%s: Aligning size to 0x%llx\n",
+                      __func__, win->win_size);
+       }
+}
+
+void ccu_enable_win(int ap_index, struct addr_map_win *win, uint32_t win_id)
+{
+       uint32_t ccu_win_reg;
+       uint32_t alr, ahr;
+       uint64_t end_addr;
+
+       if ((win_id == 0) || (win_id > MVEBU_CCU_MAX_WINS)) {
+               ERROR("Enabling wrong CCU window %d!\n", win_id);
+               return;
+       }
+
+       end_addr = (win->base_addr + win->win_size - 1);
+       alr = (uint32_t)((win->base_addr >> ADDRESS_SHIFT) & ADDRESS_MASK);
+       ahr = (uint32_t)((end_addr >> ADDRESS_SHIFT) & ADDRESS_MASK);
+
+       mmio_write_32(CCU_WIN_ALR_OFFSET(ap_index, win_id), alr);
+       mmio_write_32(CCU_WIN_AHR_OFFSET(ap_index, win_id), ahr);
+
+       ccu_win_reg = WIN_ENABLE_BIT;
+       ccu_win_reg |= (win->target_id & CCU_TARGET_ID_MASK)
+                       << CCU_TARGET_ID_OFFSET;
+       mmio_write_32(CCU_WIN_CR_OFFSET(ap_index, win_id), ccu_win_reg);
+}
+
+static void ccu_disable_win(int ap_index, uint32_t win_id)
+{
+       uint32_t win_reg;
+
+       if ((win_id == 0) || (win_id > MVEBU_CCU_MAX_WINS)) {
+               ERROR("Disabling wrong CCU window %d!\n", win_id);
+               return;
+       }
+
+       win_reg = mmio_read_32(CCU_WIN_CR_OFFSET(ap_index, win_id));
+       win_reg &= ~WIN_ENABLE_BIT;
+       mmio_write_32(CCU_WIN_CR_OFFSET(ap_index, win_id), win_reg);
+}
+
+/* Insert/Remove temporary window for using the out-of reset default
+ * CPx base address to access the CP configuration space prior to
+ * the further base address update in accordance with address mapping
+ * design.
+ *
+ * NOTE: Use the same window array for insertion and removal of
+ *       temporary windows.
+ */
+void ccu_temp_win_insert(int ap_index, struct addr_map_win *win, int size)
+{
+       uint32_t win_id;
+
+       for (int i = 0; i < size; i++) {
+               win_id = MVEBU_CCU_MAX_WINS - 1 - i;
+               ccu_win_check(win);
+               ccu_enable_win(ap_index, win, win_id);
+               win++;
+       }
+}
+
+/*
+ * NOTE: Use the same window array for insertion and removal of
+ *       temporary windows.
+ */
+void ccu_temp_win_remove(int ap_index, struct addr_map_win *win, int size)
+{
+       uint32_t win_id;
+
+       for (int i = 0; i < size; i++) {
+               uint64_t base;
+               uint32_t target;
+
+               win_id = MVEBU_CCU_MAX_WINS - 1 - i;
+
+               target = mmio_read_32(CCU_WIN_CR_OFFSET(ap_index, win_id));
+               target >>= CCU_TARGET_ID_OFFSET;
+               target &= CCU_TARGET_ID_MASK;
+
+               base = mmio_read_32(CCU_WIN_ALR_OFFSET(ap_index, win_id));
+               base <<= ADDRESS_SHIFT;
+
+               if ((win->target_id != target) || (win->base_addr != base)) {
+                       ERROR("%s: Trying to remove bad window-%d!\n",
+                             __func__, win_id);
+                       continue;
+               }
+               ccu_disable_win(ap_index, win_id);
+               win++;
+       }
+}
+
+/* Returns current DRAM window target (DRAM_0_TID, DRAM_1_TID, RAR_TID)
+ * NOTE: Call only once for each AP.
+ * The AP0 DRAM window is located at index 2 only at the BL31 execution start.
+ * Then it relocated to index 1 for matching the rest of APs DRAM settings.
+ * Calling this function after relocation will produce wrong results on AP0
+ */
+static uint32_t ccu_dram_target_get(int ap_index)
+{
+       /* On BLE stage the AP0 DRAM window is opened by the BootROM at index 2.
+        * All the rest of detected APs will use window at index 1.
+        * The AP0 DRAM window is moved from index 2 to 1 during
+        * init_ccu() execution.
+        */
+       const uint32_t win_id = (ap_index == 0) ? 2 : 1;
+       uint32_t target;
+
+       target = mmio_read_32(CCU_WIN_CR_OFFSET(ap_index, win_id));
+       target >>= CCU_TARGET_ID_OFFSET;
+       target &= CCU_TARGET_ID_MASK;
+
+       return target;
+}
+
+void ccu_dram_target_set(int ap_index, uint32_t target)
+{
+       /* On BLE stage the AP0 DRAM window is opened by the BootROM at index 2.
+        * All the rest of detected APs will use window at index 1.
+        * The AP0 DRAM window is moved from index 2 to 1
+        * during init_ccu() execution.
+        */
+       const uint32_t win_id = (ap_index == 0) ? 2 : 1;
+       uint32_t dram_cr;
+
+       dram_cr = mmio_read_32(CCU_WIN_CR_OFFSET(ap_index, win_id));
+       dram_cr &= ~(CCU_TARGET_ID_MASK << CCU_TARGET_ID_OFFSET);
+       dram_cr |= (target & CCU_TARGET_ID_MASK) << CCU_TARGET_ID_OFFSET;
+       mmio_write_32(CCU_WIN_CR_OFFSET(ap_index, win_id), dram_cr);
+}
+
+/* Setup CCU DRAM window and enable it */
+void ccu_dram_win_config(int ap_index, struct addr_map_win *win)
+{
+#if IMAGE_BLE /* BLE */
+       /* On BLE stage the AP0 DRAM window is opened by the BootROM at index 2.
+        * Since the BootROM is not accessing DRAM at BLE stage,
+        * the DRAM window can be temporarely disabled.
+        */
+       const uint32_t win_id = (ap_index == 0) ? 2 : 1;
+#else /* end of BLE */
+       /* At the ccu_init() execution stage, DRAM windows of all APs
+        * are arranged at index 1.
+        * The AP0 still has the old window BootROM DRAM at index 2, so
+        * the window-1 can be safely disabled without breaking the DRAM access.
+        */
+       const uint32_t win_id = 1;
+#endif
+
+       ccu_disable_win(ap_index, win_id);
+       /* enable write secure (and clear read secure) */
+       mmio_write_32(CCU_WIN_SCR_OFFSET(ap_index, win_id),
+                     CCU_WIN_ENA_WRITE_SECURE);
+       ccu_win_check(win);
+       ccu_enable_win(ap_index, win, win_id);
+}
+
+/* Save content of CCU window + GCR */
+static void ccu_save_win_range(int ap_id, int win_first,
+                              int win_last, uint32_t *buffer)
+{
+       int win_id, idx;
+       /* Save CCU */
+       for (idx = 0, win_id = win_first; win_id <= win_last; win_id++) {
+               buffer[idx++] = mmio_read_32(CCU_WIN_CR_OFFSET(ap_id, win_id));
+               buffer[idx++] = mmio_read_32(CCU_WIN_SCR_OFFSET(ap_id, win_id));
+               buffer[idx++] = mmio_read_32(CCU_WIN_ALR_OFFSET(ap_id, win_id));
+               buffer[idx++] = mmio_read_32(CCU_WIN_AHR_OFFSET(ap_id, win_id));
+       }
+       buffer[idx] = mmio_read_32(CCU_WIN_GCR_OFFSET(ap_id));
+}
+
+/* Restore content of CCU window + GCR */
+static void ccu_restore_win_range(int ap_id, int win_first,
+                                 int win_last, uint32_t *buffer)
+{
+       int win_id, idx;
+       /* Restore CCU */
+       for (idx = 0, win_id = win_first; win_id <= win_last; win_id++) {
+               mmio_write_32(CCU_WIN_CR_OFFSET(ap_id, win_id),  buffer[idx++]);
+               mmio_write_32(CCU_WIN_SCR_OFFSET(ap_id, win_id), buffer[idx++]);
+               mmio_write_32(CCU_WIN_ALR_OFFSET(ap_id, win_id), buffer[idx++]);
+               mmio_write_32(CCU_WIN_AHR_OFFSET(ap_id, win_id), buffer[idx++]);
+       }
+       mmio_write_32(CCU_WIN_GCR_OFFSET(ap_id), buffer[idx]);
+}
+
+void ccu_save_win_all(int ap_id)
+{
+       ccu_save_win_range(ap_id, 0, MVEBU_CCU_MAX_WINS - 1, ccu_regs_save);
+}
+
+void ccu_restore_win_all(int ap_id)
+{
+       ccu_restore_win_range(ap_id, 0, MVEBU_CCU_MAX_WINS - 1, ccu_regs_save);
+}
+
+int init_ccu(int ap_index)
+{
+       struct addr_map_win *win, *dram_win;
+       uint32_t win_id, win_reg;
+       uint32_t win_count, array_id;
+       uint32_t dram_target;
+#if IMAGE_BLE
+       /* In BootROM context CCU Window-1
+        * has SRAM_TID target and should not be disabled
+        */
+       const uint32_t win_start = 2;
+#else
+       const uint32_t win_start = 1;
+#endif
+
+       INFO("Initializing CCU Address decoding\n");
+
+       /* Get the array of the windows and fill the map data */
+       marvell_get_ccu_memory_map(ap_index, &win, &win_count);
+       if (win_count <= 0) {
+               INFO("No windows configurations found\n");
+       } else if (win_count > (MVEBU_CCU_MAX_WINS - 1)) {
+               ERROR("CCU mem map array > than max available windows (%d)\n",
+                     MVEBU_CCU_MAX_WINS);
+               win_count = MVEBU_CCU_MAX_WINS;
+       }
+
+       /* Need to set GCR to DRAM before all CCU windows are disabled for
+        * securing the normal access to DRAM location, which the ATF is running
+        * from. Once all CCU windows are set, which have to include the
+        * dedicated DRAM window as well, the GCR can be switched to the target
+        * defined by the platform configuration.
+        */
+       dram_target = ccu_dram_target_get(ap_index);
+       win_reg = (dram_target & CCU_GCR_TARGET_MASK) << CCU_GCR_TARGET_OFFSET;
+       mmio_write_32(CCU_WIN_GCR_OFFSET(ap_index), win_reg);
+
+       /* If the DRAM window was already configured at the BLE stage,
+        * only the window target considered valid, the address range should be
+        * updated according to the platform configuration.
+        */
+       for (dram_win = win, array_id = 0; array_id < win_count;
+            array_id++, dram_win++) {
+               if (IS_DRAM_TARGET(dram_win->target_id)) {
+                       dram_win->target_id = dram_target;
+                       break;
+               }
+       }
+
+       /* Disable all AP CCU windows
+        * Window-0 is always bypassed since it already contains
+        * data allowing the internal configuration space access
+        */
+       for (win_id = win_start; win_id < MVEBU_CCU_MAX_WINS; win_id++) {
+               ccu_disable_win(ap_index, win_id);
+               /* enable write secure (and clear read secure) */
+               mmio_write_32(CCU_WIN_SCR_OFFSET(ap_index, win_id),
+                             CCU_WIN_ENA_WRITE_SECURE);
+       }
+
+       /* win_id is the index of the current ccu window
+        * array_id is the index of the current memory map window entry
+        */
+       for (win_id = win_start, array_id = 0;
+           ((win_id < MVEBU_CCU_MAX_WINS) && (array_id < win_count));
+           win_id++) {
+               ccu_win_check(win);
+               ccu_enable_win(ap_index, win, win_id);
+               win++;
+               array_id++;
+       }
+
+       /* Get & set the default target according to board topology */
+       win_reg = (marvell_get_ccu_gcr_target(ap_index) & CCU_GCR_TARGET_MASK)
+                  << CCU_GCR_TARGET_OFFSET;
+       mmio_write_32(CCU_WIN_GCR_OFFSET(ap_index), win_reg);
+
+#ifdef DEBUG_ADDR_MAP
+       dump_ccu(ap_index);
+#endif
+
+       INFO("Done CCU Address decoding Initializing\n");
+
+       return 0;
+}
diff --git a/drivers/marvell/comphy.h b/drivers/marvell/comphy.h
new file mode 100644 (file)
index 0000000..788b1b6
--- /dev/null
@@ -0,0 +1,473 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* Driver for COMPHY unit that is part or Marvell A8K SoCs */
+
+#ifndef _COMPHY_H_
+#define _COMPHY_H_
+
+/* COMPHY registers */
+#define COMMON_PHY_CFG1_REG                    0x0
+#define COMMON_PHY_CFG1_PWR_UP_OFFSET          1
+#define COMMON_PHY_CFG1_PWR_UP_MASK            \
+                               (0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET)
+#define COMMON_PHY_CFG1_PIPE_SELECT_OFFSET     2
+#define COMMON_PHY_CFG1_PIPE_SELECT_MASK       \
+                               (0x1 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET)
+#define COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET    13
+#define COMMON_PHY_CFG1_PWR_ON_RESET_MASK      \
+                               (0x1 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET)
+#define COMMON_PHY_CFG1_CORE_RSTN_OFFSET       14
+#define COMMON_PHY_CFG1_CORE_RSTN_MASK         \
+                               (0x1 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET)
+#define COMMON_PHY_PHY_MODE_OFFSET             15
+#define COMMON_PHY_PHY_MODE_MASK               \
+                               (0x1 << COMMON_PHY_PHY_MODE_OFFSET)
+
+#define COMMON_SELECTOR_PHY_OFFSET                     0x140
+#define COMMON_SELECTOR_PIPE_OFFSET                    0x144
+
+#define COMMON_PHY_SD_CTRL1                            0x148
+#define COMMON_PHY_SD_CTRL1_COMPHY_0_4_PORT_OFFSET     0
+#define COMMON_PHY_SD_CTRL1_COMPHY_0_4_PORT_MASK       0xFFFF
+#define COMMON_PHY_SD_CTRL1_PCIE_X4_EN_OFFSET          24
+#define COMMON_PHY_SD_CTRL1_PCIE_X4_EN_MASK            \
+                               (0x1 << COMMON_PHY_SD_CTRL1_PCIE_X4_EN_OFFSET)
+#define COMMON_PHY_SD_CTRL1_PCIE_X2_EN_OFFSET          25
+#define COMMON_PHY_SD_CTRL1_PCIE_X2_EN_MASK            \
+                               (0x1 << COMMON_PHY_SD_CTRL1_PCIE_X2_EN_OFFSET)
+
+#define DFX_DEV_GEN_CTRL12                     0x80
+#define DFX_DEV_GEN_PCIE_CLK_SRC_OFFSET                7
+#define DFX_DEV_GEN_PCIE_CLK_SRC_MASK          \
+                               (0x3 << DFX_DEV_GEN_PCIE_CLK_SRC_OFFSET)
+
+/* HPIPE register */
+#define HPIPE_PWR_PLL_REG                      0x4
+#define HPIPE_PWR_PLL_REF_FREQ_OFFSET          0
+#define HPIPE_PWR_PLL_REF_FREQ_MASK            \
+                               (0x1f << HPIPE_PWR_PLL_REF_FREQ_OFFSET)
+#define HPIPE_PWR_PLL_PHY_MODE_OFFSET          5
+#define HPIPE_PWR_PLL_PHY_MODE_MASK            \
+                               (0x7 << HPIPE_PWR_PLL_PHY_MODE_OFFSET)
+
+#define HPIPE_DFE_REG0                         0x01C
+#define HPIPE_DFE_RES_FORCE_OFFSET             15
+#define HPIPE_DFE_RES_FORCE_MASK               \
+                               (0x1 << HPIPE_DFE_RES_FORCE_OFFSET)
+
+#define HPIPE_G2_SET_1_REG                     0x040
+#define HPIPE_G2_SET_1_G2_RX_SELMUPI_OFFSET    0
+#define HPIPE_G2_SET_1_G2_RX_SELMUPI_MASK      \
+                               (0x7 << HPIPE_G2_SET_1_G2_RX_SELMUPI_OFFSET)
+#define HPIPE_G2_SET_1_G2_RX_SELMUPP_OFFSET    3
+#define HPIPE_G2_SET_1_G2_RX_SELMUPP_MASK      \
+                               (0x7 << HPIPE_G2_SET_1_G2_RX_SELMUPP_OFFSET)
+#define HPIPE_G2_SET_1_G2_RX_SELMUFI_OFFSET    6
+#define HPIPE_G2_SET_1_G2_RX_SELMUFI_MASK      \
+                               (0x3 << HPIPE_G2_SET_1_G2_RX_SELMUFI_OFFSET)
+
+#define HPIPE_G3_SETTINGS_1_REG                        0x048
+#define HPIPE_G3_RX_SELMUPI_OFFSET             0
+#define HPIPE_G3_RX_SELMUPI_MASK               \
+                               (0x7 << HPIPE_G3_RX_SELMUPI_OFFSET)
+#define HPIPE_G3_RX_SELMUPF_OFFSET             3
+#define HPIPE_G3_RX_SELMUPF_MASK               \
+                               (0x7 << HPIPE_G3_RX_SELMUPF_OFFSET)
+#define HPIPE_G3_SETTING_BIT_OFFSET            13
+#define HPIPE_G3_SETTING_BIT_MASK              \
+                               (0x1 << HPIPE_G3_SETTING_BIT_OFFSET)
+
+#define HPIPE_INTERFACE_REG                    0x94
+#define HPIPE_INTERFACE_GEN_MAX_OFFSET         10
+#define HPIPE_INTERFACE_GEN_MAX_MASK           \
+                               (0x3 << HPIPE_INTERFACE_GEN_MAX_OFFSET)
+#define HPIPE_INTERFACE_DET_BYPASS_OFFSET      12
+#define HPIPE_INTERFACE_DET_BYPASS_MASK                \
+                               (0x1 << HPIPE_INTERFACE_DET_BYPASS_OFFSET)
+#define HPIPE_INTERFACE_LINK_TRAIN_OFFSET      14
+#define HPIPE_INTERFACE_LINK_TRAIN_MASK                \
+                               (0x1 << HPIPE_INTERFACE_LINK_TRAIN_OFFSET)
+
+#define HPIPE_VDD_CAL_CTRL_REG                 0x114
+#define HPIPE_EXT_SELLV_RXSAMPL_OFFSET         5
+#define HPIPE_EXT_SELLV_RXSAMPL_MASK           \
+                               (0x1f << HPIPE_EXT_SELLV_RXSAMPL_OFFSET)
+
+#define HPIPE_PCIE_REG0                                0x120
+#define HPIPE_PCIE_IDLE_SYNC_OFFSET            12
+#define HPIPE_PCIE_IDLE_SYNC_MASK              \
+                               (0x1 << HPIPE_PCIE_IDLE_SYNC_OFFSET)
+#define HPIPE_PCIE_SEL_BITS_OFFSET             13
+#define HPIPE_PCIE_SEL_BITS_MASK               \
+                               (0x3 << HPIPE_PCIE_SEL_BITS_OFFSET)
+
+#define HPIPE_LANE_ALIGN_REG                   0x124
+#define HPIPE_LANE_ALIGN_OFF_OFFSET            12
+#define HPIPE_LANE_ALIGN_OFF_MASK              \
+                               (0x1 << HPIPE_LANE_ALIGN_OFF_OFFSET)
+
+#define HPIPE_MISC_REG                         0x13C
+#define HPIPE_MISC_CLK100M_125M_OFFSET         4
+#define HPIPE_MISC_CLK100M_125M_MASK           \
+                               (0x1 << HPIPE_MISC_CLK100M_125M_OFFSET)
+#define HPIPE_MISC_ICP_FORCE_OFFSET            5
+#define HPIPE_MISC_ICP_FORCE_MASK              \
+                               (0x1 << HPIPE_MISC_ICP_FORCE_OFFSET)
+#define HPIPE_MISC_TXDCLK_2X_OFFSET            6
+#define HPIPE_MISC_TXDCLK_2X_MASK              \
+                               (0x1 << HPIPE_MISC_TXDCLK_2X_OFFSET)
+#define HPIPE_MISC_CLK500_EN_OFFSET            7
+#define HPIPE_MISC_CLK500_EN_MASK              \
+                               (0x1 << HPIPE_MISC_CLK500_EN_OFFSET)
+#define HPIPE_MISC_REFCLK_SEL_OFFSET           10
+#define HPIPE_MISC_REFCLK_SEL_MASK             \
+                               (0x1 << HPIPE_MISC_REFCLK_SEL_OFFSET)
+
+#define HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG    0x16C
+#define HPIPE_SMAPLER_OFFSET                   12
+#define HPIPE_SMAPLER_MASK                     (0x1 << HPIPE_SMAPLER_OFFSET)
+
+#define HPIPE_PWR_CTR_DTL_REG                  0x184
+#define HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET      2
+#define HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK                \
+                               (0x1 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET)
+
+#define HPIPE_FRAME_DET_CONTROL_REG            0x220
+#define HPIPE_FRAME_DET_LOCK_LOST_TO_OFFSET    12
+#define HPIPE_FRAME_DET_LOCK_LOST_TO_MASK      \
+                               (0x1 << HPIPE_FRAME_DET_LOCK_LOST_TO_OFFSET)
+
+#define HPIPE_TX_TRAIN_CTRL_0_REG              0x268
+#define HPIPE_TX_TRAIN_P2P_HOLD_OFFSET         15
+#define HPIPE_TX_TRAIN_P2P_HOLD_MASK           \
+                               (0x1 << HPIPE_TX_TRAIN_P2P_HOLD_OFFSET)
+
+#define HPIPE_TX_TRAIN_CTRL_REG                        0x26C
+#define HPIPE_TX_TRAIN_CTRL_G1_OFFSET          0
+#define HPIPE_TX_TRAIN_CTRL_G1_MASK            \
+                               (0x1 << HPIPE_TX_TRAIN_CTRL_G1_OFFSET)
+#define HPIPE_TX_TRAIN_CTRL_GN1_OFFSET         1
+#define HPIPE_TX_TRAIN_CTRL_GN1_MASK           \
+                               (0x1 << HPIPE_TX_TRAIN_CTRL_GN1_OFFSET)
+#define HPIPE_TX_TRAIN_CTRL_G0_OFFSET          2
+#define HPIPE_TX_TRAIN_CTRL_G0_MASK            \
+                               (0x1 << HPIPE_TX_TRAIN_CTRL_G0_OFFSET)
+
+#define HPIPE_TX_TRAIN_CTRL_4_REG              0x278
+#define HPIPE_TRX_TRAIN_TIMER_OFFSET           0
+#define HPIPE_TRX_TRAIN_TIMER_MASK             \
+                               (0x3FF << HPIPE_TRX_TRAIN_TIMER_OFFSET)
+
+#define HPIPE_TX_TRAIN_CTRL_5_REG              0x2A4
+#define HPIPE_TX_TRAIN_START_SQ_EN_OFFSET      11
+#define HPIPE_TX_TRAIN_START_SQ_EN_MASK                \
+                               (0x1 << HPIPE_TX_TRAIN_START_SQ_EN_OFFSET)
+#define HPIPE_TX_TRAIN_START_FRM_DET_EN_OFFSET 12
+#define HPIPE_TX_TRAIN_START_FRM_DET_EN_MASK   \
+                               (0x1 << HPIPE_TX_TRAIN_START_FRM_DET_EN_OFFSET)
+#define HPIPE_TX_TRAIN_START_FRM_LOCK_EN_OFFSET        13
+#define HPIPE_TX_TRAIN_START_FRM_LOCK_EN_MASK  \
+                               (0x1 << HPIPE_TX_TRAIN_START_FRM_LOCK_EN_OFFSET)
+#define HPIPE_TX_TRAIN_WAIT_TIME_EN_OFFSET     14
+#define HPIPE_TX_TRAIN_WAIT_TIME_EN_MASK       \
+                               (0x1 << HPIPE_TX_TRAIN_WAIT_TIME_EN_OFFSET)
+
+#define HPIPE_TX_TRAIN_REG                     0x31C
+#define HPIPE_TX_TRAIN_CHK_INIT_OFFSET         4
+#define HPIPE_TX_TRAIN_CHK_INIT_MASK           \
+                               (0x1 << HPIPE_TX_TRAIN_CHK_INIT_OFFSET)
+#define HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_OFFSET 7
+#define HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_MASK   \
+                               (0x1 << HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_OFFSET)
+
+#define HPIPE_CDR_CONTROL_REG                  0x418
+#define HPIPE_CDR_RX_MAX_DFE_ADAPT_0_OFFSET    14
+#define HPIPE_CDR_RX_MAX_DFE_ADAPT_0_MASK      \
+                               (0x3 << HPIPE_CDR_RX_MAX_DFE_ADAPT_0_OFFSET)
+#define HPIPE_CDR_RX_MAX_DFE_ADAPT_1_OFFSET    12
+#define HPIPE_CDR_RX_MAX_DFE_ADAPT_1_MASK      \
+                               (0x3 << HPIPE_CDR_RX_MAX_DFE_ADAPT_1_OFFSET)
+#define HPIPE_CDR_MAX_DFE_ADAPT_0_OFFSET       9
+#define HPIPE_CDR_MAX_DFE_ADAPT_0_MASK         \
+                               (0x7 << HPIPE_CDR_MAX_DFE_ADAPT_0_OFFSET)
+#define HPIPE_CDR_MAX_DFE_ADAPT_1_OFFSET       6
+#define HPIPE_CDR_MAX_DFE_ADAPT_1_MASK         \
+                               (0x7 << HPIPE_CDR_MAX_DFE_ADAPT_1_OFFSET)
+
+#define HPIPE_TX_TRAIN_CTRL_11_REG             0x438
+#define HPIPE_TX_STATUS_CHECK_MODE_OFFSET      6
+#define HPIPE_TX_TX_STATUS_CHECK_MODE_MASK     \
+                               (0x1 << HPIPE_TX_STATUS_CHECK_MODE_OFFSET)
+#define HPIPE_TX_NUM_OF_PRESET_OFFSET          10
+#define HPIPE_TX_NUM_OF_PRESET_MASK            \
+                               (0x7 << HPIPE_TX_NUM_OF_PRESET_OFFSET)
+#define HPIPE_TX_SWEEP_PRESET_EN_OFFSET                15
+#define HPIPE_TX_SWEEP_PRESET_EN_MASK          \
+                               (0x1 << HPIPE_TX_SWEEP_PRESET_EN_OFFSET)
+#define HPIPE_G2_SETTINGS_4_REG                        0x44C
+#define HPIPE_G2_DFE_RES_OFFSET                        8
+#define HPIPE_G2_DFE_RES_MASK                  (0x3 << HPIPE_G2_DFE_RES_OFFSET)
+
+#define HPIPE_G3_SETTING_3_REG                 0x450
+#define HPIPE_G3_FFE_CAP_SEL_OFFSET            0
+#define HPIPE_G3_FFE_CAP_SEL_MASK              \
+                               (0xf << HPIPE_G3_FFE_CAP_SEL_OFFSET)
+#define HPIPE_G3_FFE_RES_SEL_OFFSET            4
+#define HPIPE_G3_FFE_RES_SEL_MASK              \
+                               (0x7 << HPIPE_G3_FFE_RES_SEL_OFFSET)
+#define HPIPE_G3_FFE_SETTING_FORCE_OFFSET      7
+#define HPIPE_G3_FFE_SETTING_FORCE_MASK                \
+                               (0x1 << HPIPE_G3_FFE_SETTING_FORCE_OFFSET)
+#define HPIPE_G3_FFE_DEG_RES_LEVEL_OFFSET      12
+#define HPIPE_G3_FFE_DEG_RES_LEVEL_MASK                \
+                               (0x3 << HPIPE_G3_FFE_DEG_RES_LEVEL_OFFSET)
+#define HPIPE_G3_FFE_LOAD_RES_LEVEL_OFFSET     14
+#define HPIPE_G3_FFE_LOAD_RES_LEVEL_MASK       \
+                               (0x3 << HPIPE_G3_FFE_LOAD_RES_LEVEL_OFFSET)
+
+#define HPIPE_G3_SETTING_4_REG                 0x454
+#define HPIPE_G3_DFE_RES_OFFSET                        8
+#define HPIPE_G3_DFE_RES_MASK                  (0x3 << HPIPE_G3_DFE_RES_OFFSET)
+
+#define HPIPE_DFE_CONTROL_REG                  0x470
+#define HPIPE_DFE_TX_MAX_DFE_ADAPT_OFFSET      14
+#define HPIPE_DFE_TX_MAX_DFE_ADAPT_MASK                \
+                               (0x3 << HPIPE_DFE_TX_MAX_DFE_ADAPT_OFFSET)
+
+#define HPIPE_DFE_CTRL_28_REG                  0x49C
+#define HPIPE_DFE_CTRL_28_PIPE4_OFFSET         7
+#define HPIPE_DFE_CTRL_28_PIPE4_MASK           \
+                               (0x1 << HPIPE_DFE_CTRL_28_PIPE4_OFFSET)
+
+#define HPIPE_G3_SETTING_5_REG                 0x548
+#define HPIPE_G3_SETTING_5_G3_ICP_OFFSET       0
+#define HPIPE_G3_SETTING_5_G3_ICP_MASK         \
+                               (0xf << HPIPE_G3_SETTING_5_G3_ICP_OFFSET)
+
+#define HPIPE_LANE_STATUS1_REG                 0x60C
+#define HPIPE_LANE_STATUS1_PCLK_EN_OFFSET      0
+#define HPIPE_LANE_STATUS1_PCLK_EN_MASK                \
+                               (0x1 << HPIPE_LANE_STATUS1_PCLK_EN_OFFSET)
+
+#define HPIPE_LANE_CFG4_REG                    0x620
+#define HPIPE_LANE_CFG4_DFE_EN_SEL_OFFSET      3
+#define HPIPE_LANE_CFG4_DFE_EN_SEL_MASK                \
+                               (0x1 << HPIPE_LANE_CFG4_DFE_EN_SEL_OFFSET)
+
+#define HPIPE_LANE_EQU_CONFIG_0_REG            0x69C
+#define HPIPE_CFG_EQ_FS_OFFSET                 0
+#define HPIPE_CFG_EQ_FS_MASK                   (0x3f << HPIPE_CFG_EQ_FS_OFFSET)
+#define HPIPE_CFG_EQ_LF_OFFSET                 6
+#define HPIPE_CFG_EQ_LF_MASK                   (0x3f << HPIPE_CFG_EQ_LF_OFFSET)
+#define HPIPE_CFG_PHY_RC_EP_OFFSET             12
+#define HPIPE_CFG_PHY_RC_EP_MASK               \
+                               (0x1 << HPIPE_CFG_PHY_RC_EP_OFFSET)
+
+#define HPIPE_LANE_EQ_CFG1_REG                 0x6a0
+#define HPIPE_CFG_UPDATE_POLARITY_OFFSET       12
+#define HPIPE_CFG_UPDATE_POLARITY_MASK         \
+                               (0x1 << HPIPE_CFG_UPDATE_POLARITY_OFFSET)
+
+#define HPIPE_LANE_EQ_CFG2_REG                 0x6a4
+#define HPIPE_CFG_EQ_BUNDLE_DIS_OFFSET         14
+#define HPIPE_CFG_EQ_BUNDLE_DIS_MASK           \
+                               (0x1 << HPIPE_CFG_EQ_BUNDLE_DIS_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG0_REG             0x6a8
+#define HPIPE_CFG_CURSOR_PRESET0_OFFSET                0
+#define HPIPE_CFG_CURSOR_PRESET0_MASK          \
+                               (0x3f << HPIPE_CFG_CURSOR_PRESET0_OFFSET)
+#define HPIPE_CFG_CURSOR_PRESET1_OFFSET                6
+#define HPIPE_CFG_CURSOR_PRESET1_MASK          \
+                               (0x3f << HPIPE_CFG_CURSOR_PRESET1_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG1_REG             0x6ac
+#define HPIPE_CFG_CURSOR_PRESET2_OFFSET                0
+#define HPIPE_CFG_CURSOR_PRESET2_MASK          \
+                               (0x3f << HPIPE_CFG_CURSOR_PRESET2_OFFSET)
+#define HPIPE_CFG_CURSOR_PRESET3_OFFSET                6
+#define HPIPE_CFG_CURSOR_PRESET3_MASK          \
+                               (0x3f << HPIPE_CFG_CURSOR_PRESET3_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG2_REG             0x6b0
+#define HPIPE_CFG_CURSOR_PRESET4_OFFSET                0
+#define HPIPE_CFG_CURSOR_PRESET4_MASK          \
+                               (0x3f << HPIPE_CFG_CURSOR_PRESET4_OFFSET)
+#define HPIPE_CFG_CURSOR_PRESET5_OFFSET                6
+#define HPIPE_CFG_CURSOR_PRESET5_MASK          \
+                               (0x3f << HPIPE_CFG_CURSOR_PRESET5_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG3_REG             0x6b4
+#define HPIPE_CFG_CURSOR_PRESET6_OFFSET                0
+#define HPIPE_CFG_CURSOR_PRESET6_MASK          \
+                               (0x3f << HPIPE_CFG_CURSOR_PRESET6_OFFSET)
+#define HPIPE_CFG_CURSOR_PRESET7_OFFSET                6
+#define HPIPE_CFG_CURSOR_PRESET7_MASK          \
+                               (0x3f << HPIPE_CFG_CURSOR_PRESET7_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG4_REG             0x6b8
+#define HPIPE_CFG_CURSOR_PRESET8_OFFSET                0
+#define HPIPE_CFG_CURSOR_PRESET8_MASK          \
+                               (0x3f << HPIPE_CFG_CURSOR_PRESET8_OFFSET)
+#define HPIPE_CFG_CURSOR_PRESET9_OFFSET                6
+#define HPIPE_CFG_CURSOR_PRESET9_MASK          \
+                               (0x3f << HPIPE_CFG_CURSOR_PRESET9_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG5_REG             0x6bc
+#define HPIPE_CFG_CURSOR_PRESET10_OFFSET       0
+#define HPIPE_CFG_CURSOR_PRESET10_MASK         \
+                               (0x3f << HPIPE_CFG_CURSOR_PRESET10_OFFSET)
+#define HPIPE_CFG_CURSOR_PRESET11_OFFSET       6
+#define HPIPE_CFG_CURSOR_PRESET11_MASK         \
+                               (0x3f << HPIPE_CFG_CURSOR_PRESET11_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG6_REG             0x6c0
+#define HPIPE_CFG_PRE_CURSOR_PRESET0_OFFSET    0
+#define HPIPE_CFG_PRE_CURSOR_PRESET0_MASK      \
+                               (0x3f << HPIPE_CFG_PRE_CURSOR_PRESET0_OFFSET)
+#define HPIPE_CFG_POST_CURSOR_PRESET0_OFFSET   6
+#define HPIPE_CFG_POST_CURSOR_PRESET0_MASK     \
+                               (0x3f << HPIPE_CFG_POST_CURSOR_PRESET0_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG7_REG             0x6c4
+#define HPIPE_CFG_PRE_CURSOR_PRESET1_OFFSET    0
+#define HPIPE_CFG_PRE_CURSOR_PRESET1_MASK      \
+                               (0x3f << HPIPE_CFG_PRE_CURSOR_PRESET1_OFFSET)
+#define HPIPE_CFG_POST_CURSOR_PRESET1_OFFSET   6
+#define HPIPE_CFG_POST_CURSOR_PRESET1_MASK     \
+                               (0x3f << HPIPE_CFG_POST_CURSOR_PRESET1_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG8_REG             0x6c8
+#define HPIPE_CFG_PRE_CURSOR_PRESET2_OFFSET    0
+#define HPIPE_CFG_PRE_CURSOR_PRESET2_MASK      \
+                               (0x3f << HPIPE_CFG_PRE_CURSOR_PRESET2_OFFSET)
+#define HPIPE_CFG_POST_CURSOR_PRESET2_OFFSET   6
+#define HPIPE_CFG_POST_CURSOR_PRESET2_MASK     \
+                               (0x3f << HPIPE_CFG_POST_CURSOR_PRESET2_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG9_REG             0x6cc
+#define HPIPE_CFG_PRE_CURSOR_PRESET3_OFFSET    0
+#define HPIPE_CFG_PRE_CURSOR_PRESET3_MASK      \
+                               (0x3f << HPIPE_CFG_PRE_CURSOR_PRESET3_OFFSET)
+#define HPIPE_CFG_POST_CURSOR_PRESET3_OFFSET   6
+#define HPIPE_CFG_POST_CURSOR_PRESET3_MASK     \
+                               (0x3f << HPIPE_CFG_POST_CURSOR_PRESET3_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG10_REG            0x6d0
+#define HPIPE_CFG_PRE_CURSOR_PRESET4_OFFSET    0
+#define HPIPE_CFG_PRE_CURSOR_PRESET4_MASK      \
+                               (0x3f << HPIPE_CFG_PRE_CURSOR_PRESET4_OFFSET)
+#define HPIPE_CFG_POST_CURSOR_PRESET4_OFFSET   6
+#define HPIPE_CFG_POST_CURSOR_PRESET4_MASK     \
+                               (0x3f << HPIPE_CFG_POST_CURSOR_PRESET4_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG11_REG            0x6d4
+#define HPIPE_CFG_PRE_CURSOR_PRESET5_OFFSET    0
+#define HPIPE_CFG_PRE_CURSOR_PRESET5_MASK      \
+                               (0x3f << HPIPE_CFG_PRE_CURSOR_PRESET5_OFFSET)
+#define HPIPE_CFG_POST_CURSOR_PRESET5_OFFSET   6
+#define HPIPE_CFG_POST_CURSOR_PRESET5_MASK     \
+                               (0x3f << HPIPE_CFG_POST_CURSOR_PRESET5_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG12_REG            0x6d8
+#define HPIPE_CFG_PRE_CURSOR_PRESET6_OFFSET    0
+#define HPIPE_CFG_PRE_CURSOR_PRESET6_MASK      \
+                               (0x3f << HPIPE_CFG_PRE_CURSOR_PRESET6_OFFSET)
+#define HPIPE_CFG_POST_CURSOR_PRESET6_OFFSET   6
+#define HPIPE_CFG_POST_CURSOR_PRESET6_MASK     \
+                               (0x3f << HPIPE_CFG_POST_CURSOR_PRESET6_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG13_REG            0x6dc
+#define HPIPE_CFG_PRE_CURSOR_PRESET7_OFFSET    0
+#define HPIPE_CFG_PRE_CURSOR_PRESET7_MASK      \
+                               (0x3f << HPIPE_CFG_PRE_CURSOR_PRESET7_OFFSET)
+#define HPIPE_CFG_POST_CURSOR_PRESET7_OFFSET   6
+#define HPIPE_CFG_POST_CURSOR_PRESET7_MASK     \
+                               (0x3f << HPIPE_CFG_POST_CURSOR_PRESET7_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG14_REG            0x6e0
+#define HPIPE_CFG_PRE_CURSOR_PRESET8_OFFSET    0
+#define HPIPE_CFG_PRE_CURSOR_PRESET8_MASK      \
+                               (0x3f << HPIPE_CFG_PRE_CURSOR_PRESET8_OFFSET)
+#define HPIPE_CFG_POST_CURSOR_PRESET8_OFFSET   6
+#define HPIPE_CFG_POST_CURSOR_PRESET8_MASK     \
+                               (0x3f << HPIPE_CFG_POST_CURSOR_PRESET8_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG15_REG            0x6e4
+#define HPIPE_CFG_PRE_CURSOR_PRESET9_OFFSET    0
+#define HPIPE_CFG_PRE_CURSOR_PRESET9_MASK      \
+                               (0x3f << HPIPE_CFG_PRE_CURSOR_PRESET9_OFFSET)
+#define HPIPE_CFG_POST_CURSOR_PRESET9_OFFSET   6
+#define HPIPE_CFG_POST_CURSOR_PRESET9_MASK     \
+                               (0x3f << HPIPE_CFG_POST_CURSOR_PRESET9_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG16_REG            0x6e8
+#define HPIPE_CFG_PRE_CURSOR_PRESET10_OFFSET   0
+#define HPIPE_CFG_PRE_CURSOR_PRESET10_MASK     \
+                               (0x3f << HPIPE_CFG_PRE_CURSOR_PRESET10_OFFSET)
+#define HPIPE_CFG_POST_CURSOR_PRESET10_OFFSET  6
+#define HPIPE_CFG_POST_CURSOR_PRESET10_MASK    \
+                               (0x3f << HPIPE_CFG_POST_CURSOR_PRESET10_OFFSET)
+
+#define HPIPE_LANE_EQ_REMOTE_SETTING_REG       0x6f8
+#define HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_OFFSET        0
+#define HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_MASK  \
+                               (0x1 << HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_OFFSET)
+#define HPIPE_LANE_CFG_FOM_ONLY_MODE_OFFFSET   1
+#define HPIPE_LANE_CFG_FOM_ONLY_MODE_MASK      \
+                               (0x1 << HPIPE_LANE_CFG_FOM_ONLY_MODE_OFFFSET)
+#define HPIPE_LANE_CFG_FOM_PRESET_VECTOR_OFFSET        2
+#define HPIPE_LANE_CFG_FOM_PRESET_VECTOR_MASK  \
+                               (0xf << HPIPE_LANE_CFG_FOM_PRESET_VECTOR_OFFSET)
+
+#define HPIPE_RST_CLK_CTRL_REG                 0x704
+#define HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET     0
+#define HPIPE_RST_CLK_CTRL_PIPE_RST_MASK       \
+                               (0x1 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET)
+#define HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET   2
+#define HPIPE_RST_CLK_CTRL_FIXED_PCLK_MASK     \
+                               (0x1 << HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET)
+#define HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET   3
+#define HPIPE_RST_CLK_CTRL_PIPE_WIDTH_MASK     \
+                               (0x1 << HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET)
+#define HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET        9
+#define HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_MASK  \
+                               (0x1 << HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET)
+
+#define HPIPE_CLK_SRC_LO_REG                           0x70c
+#define HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_OFFSET      1
+#define HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_MASK                \
+                       (0x1 << HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_OFFSET)
+#define HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_OFFSET    2
+#define HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_MASK      \
+                       (0x3 << HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_OFFSET)
+#define HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET             5
+#define HPIPE_CLK_SRC_LO_PLL_RDY_DL_MASK               \
+                       (0x7 << HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET)
+
+#define HPIPE_CLK_SRC_HI_REG                   0x710
+#define HPIPE_CLK_SRC_HI_LANE_STRT_OFFSET      0
+#define HPIPE_CLK_SRC_HI_LANE_STRT_MASK                \
+                       (0x1 << HPIPE_CLK_SRC_HI_LANE_STRT_OFFSET)
+#define HPIPE_CLK_SRC_HI_LANE_BREAK_OFFSET     1
+#define HPIPE_CLK_SRC_HI_LANE_BREAK_MASK       \
+                       (0x1 << HPIPE_CLK_SRC_HI_LANE_BREAK_OFFSET)
+#define HPIPE_CLK_SRC_HI_LANE_MASTER_OFFSET    2
+#define HPIPE_CLK_SRC_HI_LANE_MASTER_MASK      \
+                       (0x1 << HPIPE_CLK_SRC_HI_LANE_MASTER_OFFSET)
+#define HPIPE_CLK_SRC_HI_MODE_PIPE_OFFSET      7
+#define HPIPE_CLK_SRC_HI_MODE_PIPE_MASK                \
+                       (0x1 << HPIPE_CLK_SRC_HI_MODE_PIPE_OFFSET)
+
+#define HPIPE_GLOBAL_PM_CTRL                   0x740
+#define HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET     0
+#define HPIPE_GLOBAL_PM_RXDLOZ_WAIT_MASK       \
+                       (0xFF << HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET)
+
+#endif /* _COMPHY_H_ */
+
diff --git a/drivers/marvell/comphy/comphy-cp110.h b/drivers/marvell/comphy/comphy-cp110.h
new file mode 100644 (file)
index 0000000..925abb5
--- /dev/null
@@ -0,0 +1,775 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* Marvell CP110 SoC COMPHY unit driver */
+
+#ifndef _PHY_COMPHY_CP110_H
+#define _PHY_COMPHY_CP110_H
+
+#define SD_ADDR(base, lane)                    (base + 0x1000 * lane)
+#define HPIPE_ADDR(base, lane)                 (SD_ADDR(base, lane) + 0x800)
+#define COMPHY_ADDR(base, lane)                        (base + 0x28 * lane)
+
+#define MAX_NUM_OF_FFE                         8
+#define RX_TRAINING_TIMEOUT                    500
+
+/* Comphy registers */
+#define COMMON_PHY_CFG1_REG                    0x0
+#define COMMON_PHY_CFG1_PWR_UP_OFFSET          1
+#define COMMON_PHY_CFG1_PWR_UP_MASK            \
+                               (0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET)
+#define COMMON_PHY_CFG1_PIPE_SELECT_OFFSET     2
+#define COMMON_PHY_CFG1_PIPE_SELECT_MASK       \
+                               (0x1 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET)
+#define COMMON_PHY_CFG1_CORE_RSTN_OFFSET       13
+#define COMMON_PHY_CFG1_CORE_RSTN_MASK         \
+                               (0x1 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET)
+#define COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET    14
+#define COMMON_PHY_CFG1_PWR_ON_RESET_MASK      \
+                               (0x1 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET)
+#define COMMON_PHY_PHY_MODE_OFFSET             15
+#define COMMON_PHY_PHY_MODE_MASK               \
+                               (0x1 << COMMON_PHY_PHY_MODE_OFFSET)
+
+#define COMMON_PHY_CFG6_REG                    0x14
+#define COMMON_PHY_CFG6_IF_40_SEL_OFFSET       18
+#define COMMON_PHY_CFG6_IF_40_SEL_MASK         \
+                               (0x1 << COMMON_PHY_CFG6_IF_40_SEL_OFFSET)
+
+#define COMMON_PHY_CFG6_REG                    0x14
+#define COMMON_PHY_CFG6_IF_40_SEL_OFFSET       18
+#define COMMON_PHY_CFG6_IF_40_SEL_MASK         \
+                               (0x1 << COMMON_PHY_CFG6_IF_40_SEL_OFFSET)
+
+#define COMMON_SELECTOR_PHY_REG_OFFSET         0x140
+#define COMMON_SELECTOR_PIPE_REG_OFFSET                0x144
+#define COMMON_SELECTOR_COMPHY_MASK            0xf
+#define COMMON_SELECTOR_COMPHYN_FIELD_WIDTH    4
+#define COMMON_SELECTOR_COMPHYN_SATA           0x4
+#define COMMON_SELECTOR_PIPE_COMPHY_PCIE       0x4
+#define COMMON_SELECTOR_PIPE_COMPHY_USBH       0x1
+#define COMMON_SELECTOR_PIPE_COMPHY_USBD       0x2
+
+/* SGMII/HS-SGMII/SFI/RXAUI */
+#define COMMON_SELECTOR_COMPHY0_1_2_NETWORK    0x1
+#define COMMON_SELECTOR_COMPHY3_RXAUI          0x1
+#define COMMON_SELECTOR_COMPHY3_SGMII          0x2
+#define COMMON_SELECTOR_COMPHY4_PORT1          0x1
+#define COMMON_SELECTOR_COMPHY4_ALL_OTHERS     0x2
+#define COMMON_SELECTOR_COMPHY5_RXAUI          0x2
+#define COMMON_SELECTOR_COMPHY5_SGMII          0x1
+
+#define COMMON_PHY_SD_CTRL1                    0x148
+#define COMMON_PHY_SD_CTRL1_COMPHY_0_PORT_OFFSET       0
+#define COMMON_PHY_SD_CTRL1_COMPHY_1_PORT_OFFSET       4
+#define COMMON_PHY_SD_CTRL1_COMPHY_2_PORT_OFFSET       8
+#define COMMON_PHY_SD_CTRL1_COMPHY_3_PORT_OFFSET       12
+#define COMMON_PHY_SD_CTRL1_COMPHY_0_3_PORT_MASK       0xFFFF
+#define COMMON_PHY_SD_CTRL1_COMPHY_0_1_PORT_MASK       0xFF
+#define COMMON_PHY_SD_CTRL1_PCIE_X4_EN_OFFSET  24
+#define COMMON_PHY_SD_CTRL1_PCIE_X4_EN_MASK    \
+                               (0x1 << COMMON_PHY_SD_CTRL1_PCIE_X4_EN_OFFSET)
+#define COMMON_PHY_SD_CTRL1_PCIE_X2_EN_OFFSET  25
+#define COMMON_PHY_SD_CTRL1_PCIE_X2_EN_MASK    \
+                               (0x1 << COMMON_PHY_SD_CTRL1_PCIE_X2_EN_OFFSET)
+#define COMMON_PHY_SD_CTRL1_RXAUI1_OFFSET      26
+#define COMMON_PHY_SD_CTRL1_RXAUI1_MASK                \
+                               (0x1 << COMMON_PHY_SD_CTRL1_RXAUI1_OFFSET)
+#define COMMON_PHY_SD_CTRL1_RXAUI0_OFFSET      27
+#define COMMON_PHY_SD_CTRL1_RXAUI0_MASK                \
+                               (0x1 << COMMON_PHY_SD_CTRL1_RXAUI0_OFFSET)
+
+/* DFX register */
+#define DFX_BASE                               (0x400000)
+#define DFX_DEV_GEN_CTRL12_REG                 (0x280)
+#define DFX_DEV_GEN_PCIE_CLK_SRC_MUX           (0x3)
+#define DFX_DEV_GEN_PCIE_CLK_SRC_OFFSET                7
+#define DFX_DEV_GEN_PCIE_CLK_SRC_MASK          \
+                               (0x3 << DFX_DEV_GEN_PCIE_CLK_SRC_OFFSET)
+
+/* SerDes IP registers */
+#define SD_EXTERNAL_CONFIG0_REG                                0
+#define SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET           1
+#define SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK             \
+                       (1 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET)
+#define SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET       3
+#define SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_MASK         \
+                       (0xf << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET)
+#define SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET       7
+#define SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_MASK         \
+                       (0xf << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET)
+#define SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET            11
+#define SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK              \
+                       (1 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET)
+#define SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET            12
+#define SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK              \
+                       (1 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET)
+#define SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_OFFSET       14
+#define SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_MASK         \
+                       (1 << SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_OFFSET)
+#define SD_EXTERNAL_CONFIG0_MEDIA_MODE_OFFSET          15
+#define SD_EXTERNAL_CONFIG0_MEDIA_MODE_MASK            \
+                       (0x1 << SD_EXTERNAL_CONFIG0_MEDIA_MODE_OFFSET)
+
+#define SD_EXTERNAL_CONFIG1_REG                        0x4
+#define SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET    3
+#define SD_EXTERNAL_CONFIG1_RESET_IN_MASK      \
+                       (0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET)
+#define SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET     4
+#define SD_EXTERNAL_CONFIG1_RX_INIT_MASK       \
+                       (0x1 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET)
+#define SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET  5
+#define SD_EXTERNAL_CONFIG1_RESET_CORE_MASK    \
+                       (0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET)
+#define SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET 6
+#define SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK   \
+                       (0x1 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET)
+
+#define SD_EXTERNAL_CONFIG2_REG                        0x8
+#define SD_EXTERNAL_CONFIG2_PIN_DFE_EN_OFFSET  4
+#define SD_EXTERNAL_CONFIG2_PIN_DFE_EN_MASK    \
+                       (0x1 << SD_EXTERNAL_CONFIG2_PIN_DFE_EN_OFFSET)
+#define SD_EXTERNAL_CONFIG2_SSC_ENABLE_OFFSET  7
+#define SD_EXTERNAL_CONFIG2_SSC_ENABLE_MASK    \
+                       (0x1 << SD_EXTERNAL_CONFIG2_SSC_ENABLE_OFFSET)
+
+#define SD_EXTERNAL_STATUS_REG                         0xc
+#define SD_EXTERNAL_STATUS_START_RX_TRAINING_OFFSET    7
+#define SD_EXTERNAL_STATUS_START_RX_TRAINING_MASK      \
+                       (1 << SD_EXTERNAL_STATUS_START_RX_TRAINING_OFFSET)
+
+#define SD_EXTERNAL_STATUS0_REG                        0x18
+#define SD_EXTERNAL_STATUS0_PLL_TX_OFFSET      2
+#define SD_EXTERNAL_STATUS0_PLL_TX_MASK                \
+                       (0x1 << SD_EXTERNAL_STATUS0_PLL_TX_OFFSET)
+#define SD_EXTERNAL_STATUS0_PLL_RX_OFFSET      3
+#define SD_EXTERNAL_STATUS0_PLL_RX_MASK                \
+                       (0x1 << SD_EXTERNAL_STATUS0_PLL_RX_OFFSET)
+#define SD_EXTERNAL_STATUS0_RX_INIT_OFFSET     4
+#define SD_EXTERNAL_STATUS0_RX_INIT_MASK       \
+                       (0x1 << SD_EXTERNAL_STATUS0_RX_INIT_OFFSET)
+
+#define SD_EXTERNAL_STATAUS1_REG                       0x1c
+#define SD_EXTERNAL_STATAUS1_REG_RX_TRAIN_COMP_OFFSET  0
+#define SD_EXTERNAL_STATAUS1_REG_RX_TRAIN_COMP_MASK    \
+       (1 << SD_EXTERNAL_STATAUS1_REG_RX_TRAIN_COMP_OFFSET)
+#define SD_EXTERNAL_STATAUS1_REG_RX_TRAIN_FAILED_OFFSET        1
+#define SD_EXTERNAL_STATAUS1_REG_RX_TRAIN_FAILED_MASK  \
+       (1 << SD_EXTERNAL_STATAUS1_REG_RX_TRAIN_FAILED_OFFSET)
+
+/* HPIPE registers */
+#define HPIPE_PWR_PLL_REG                      0x4
+#define HPIPE_PWR_PLL_REF_FREQ_OFFSET          0
+#define HPIPE_PWR_PLL_REF_FREQ_MASK            \
+                       (0x1f << HPIPE_PWR_PLL_REF_FREQ_OFFSET)
+#define HPIPE_PWR_PLL_PHY_MODE_OFFSET          5
+#define HPIPE_PWR_PLL_PHY_MODE_MASK            \
+                       (0x7 << HPIPE_PWR_PLL_PHY_MODE_OFFSET)
+
+#define HPIPE_CAL_REG1_REG                     0xc
+#define HPIPE_CAL_REG_1_EXT_TXIMP_OFFSET       10
+#define HPIPE_CAL_REG_1_EXT_TXIMP_MASK         \
+                       (0x1f << HPIPE_CAL_REG_1_EXT_TXIMP_OFFSET)
+#define HPIPE_CAL_REG_1_EXT_TXIMP_EN_OFFSET    15
+#define HPIPE_CAL_REG_1_EXT_TXIMP_EN_MASK      \
+                       (0x1 << HPIPE_CAL_REG_1_EXT_TXIMP_EN_OFFSET)
+
+#define HPIPE_SQUELCH_FFE_SETTING_REG          0x18
+#define HPIPE_SQUELCH_THRESH_IN_OFFSET         8
+#define HPIPE_SQUELCH_THRESH_IN_MASK           \
+                       (0xf << HPIPE_SQUELCH_THRESH_IN_OFFSET)
+#define HPIPE_SQUELCH_DETECTED_OFFSET          14
+#define HPIPE_SQUELCH_DETECTED_MASK            \
+                       (0x1 << HPIPE_SQUELCH_DETECTED_OFFSET)
+
+#define HPIPE_DFE_REG0                         0x1c
+#define HPIPE_DFE_RES_FORCE_OFFSET             15
+#define HPIPE_DFE_RES_FORCE_MASK               \
+                       (0x1 << HPIPE_DFE_RES_FORCE_OFFSET)
+
+#define HPIPE_DFE_F3_F5_REG                    0x28
+#define HPIPE_DFE_F3_F5_DFE_EN_OFFSET          14
+#define HPIPE_DFE_F3_F5_DFE_EN_MASK            \
+                       (0x1 << HPIPE_DFE_F3_F5_DFE_EN_OFFSET)
+#define HPIPE_DFE_F3_F5_DFE_CTRL_OFFSET                15
+#define HPIPE_DFE_F3_F5_DFE_CTRL_MASK          \
+                       (0x1 << HPIPE_DFE_F3_F5_DFE_CTRL_OFFSET)
+
+#define HPIPE_G1_SET_0_REG                     0x34
+#define HPIPE_G1_SET_0_G1_TX_AMP_OFFSET                1
+#define HPIPE_G1_SET_0_G1_TX_AMP_MASK          \
+                       (0x1f << HPIPE_G1_SET_0_G1_TX_AMP_OFFSET)
+#define HPIPE_G1_SET_0_G1_TX_AMP_ADJ_OFFSET    6
+#define HPIPE_G1_SET_0_G1_TX_AMP_ADJ_MASK      \
+                       (0x1 << HPIPE_G1_SET_0_G1_TX_AMP_ADJ_OFFSET)
+#define HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET      7
+#define HPIPE_G1_SET_0_G1_TX_EMPH1_MASK                \
+                       (0xf << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET)
+#define HPIPE_G1_SET_0_G1_TX_EMPH1_EN_OFFSET   11
+#define HPIPE_G1_SET_0_G1_TX_EMPH1_EN_MASK     \
+                       (0x1 << HPIPE_G1_SET_0_G1_TX_EMPH1_EN_OFFSET)
+
+#define HPIPE_G1_SET_1_REG                     0x38
+#define HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET    0
+#define HPIPE_G1_SET_1_G1_RX_SELMUPI_MASK      \
+                       (0x7 << HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET)
+#define HPIPE_G1_SET_1_G1_RX_SELMUPP_OFFSET    3
+#define HPIPE_G1_SET_1_G1_RX_SELMUPP_MASK      \
+                       (0x7 << HPIPE_G1_SET_1_G1_RX_SELMUPP_OFFSET)
+#define HPIPE_G1_SET_1_G1_RX_SELMUFI_OFFSET    6
+#define HPIPE_G1_SET_1_G1_RX_SELMUFI_MASK      \
+                       (0x3 << HPIPE_G1_SET_1_G1_RX_SELMUFI_OFFSET)
+#define HPIPE_G1_SET_1_G1_RX_SELMUFF_OFFSET    8
+#define HPIPE_G1_SET_1_G1_RX_SELMUFF_MASK      \
+                       (0x3 << HPIPE_G1_SET_1_G1_RX_SELMUFF_OFFSET)
+#define HPIPE_G1_SET_1_G1_RX_DFE_EN_OFFSET     10
+#define HPIPE_G1_SET_1_G1_RX_DFE_EN_MASK       \
+                       (0x1 << HPIPE_G1_SET_1_G1_RX_DFE_EN_OFFSET)
+#define HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_OFFSET  11
+#define HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_MASK    \
+                       (0x3 << HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_OFFSET)
+
+#define HPIPE_G2_SET_0_REG                     0x3c
+#define HPIPE_G2_SET_0_G2_TX_AMP_OFFSET                1
+#define HPIPE_G2_SET_0_G2_TX_AMP_MASK          \
+                       (0x1f << HPIPE_G2_SET_0_G2_TX_AMP_OFFSET)
+#define HPIPE_G2_SET_0_G2_TX_AMP_ADJ_OFFSET    6
+#define HPIPE_G2_SET_0_G2_TX_AMP_ADJ_MASK      \
+                       (0x1 << HPIPE_G2_SET_0_G2_TX_AMP_ADJ_OFFSET)
+#define HPIPE_G2_SET_0_G2_TX_EMPH1_OFFSET      7
+#define HPIPE_G2_SET_0_G2_TX_EMPH1_MASK                \
+                       (0xf << HPIPE_G2_SET_0_G2_TX_EMPH1_OFFSET)
+#define HPIPE_G2_SET_0_G2_TX_EMPH1_EN_OFFSET   11
+#define HPIPE_G2_SET_0_G2_TX_EMPH1_EN_MASK     \
+                       (0x1 << HPIPE_G2_SET_0_G2_TX_EMPH1_EN_OFFSET)
+
+#define HPIPE_G2_SET_1_REG                     0x40
+#define HPIPE_G2_SET_1_G2_RX_SELMUPI_OFFSET    0
+#define HPIPE_G2_SET_1_G2_RX_SELMUPI_MASK      \
+                       (0x7 << HPIPE_G2_SET_1_G2_RX_SELMUPI_OFFSET)
+#define HPIPE_G2_SET_1_G2_RX_SELMUPP_OFFSET    3
+#define HPIPE_G2_SET_1_G2_RX_SELMUPP_MASK      \
+                       (0x7 << HPIPE_G2_SET_1_G2_RX_SELMUPP_OFFSET)
+#define HPIPE_G2_SET_1_G2_RX_SELMUFI_OFFSET    6
+#define HPIPE_G2_SET_1_G2_RX_SELMUFI_MASK      \
+                       (0x3 << HPIPE_G2_SET_1_G2_RX_SELMUFI_OFFSET)
+#define HPIPE_G2_SET_1_G2_RX_SELMUFF_OFFSET    8
+#define HPIPE_G2_SET_1_G2_RX_SELMUFF_MASK      \
+                       (0x3 << HPIPE_G2_SET_1_G2_RX_SELMUFF_OFFSET)
+#define HPIPE_G2_SET_1_G2_RX_DFE_EN_OFFSET     10
+#define HPIPE_G2_SET_1_G2_RX_DFE_EN_MASK       \
+                       (0x1 << HPIPE_G2_SET_1_G2_RX_DFE_EN_OFFSET)
+#define HPIPE_G2_SET_1_G2_RX_DIGCK_DIV_OFFSET  11
+#define HPIPE_G2_SET_1_G2_RX_DIGCK_DIV_MASK    \
+                       (0x3 << HPIPE_G2_SET_1_G2_RX_DIGCK_DIV_OFFSET)
+
+#define HPIPE_G3_SET_0_REG                     0x44
+#define HPIPE_G3_SET_0_G3_TX_AMP_OFFSET                1
+#define HPIPE_G3_SET_0_G3_TX_AMP_MASK          \
+                       (0x1f << HPIPE_G3_SET_0_G3_TX_AMP_OFFSET)
+#define HPIPE_G3_SET_0_G3_TX_AMP_ADJ_OFFSET    6
+#define HPIPE_G3_SET_0_G3_TX_AMP_ADJ_MASK      \
+                       (0x1 << HPIPE_G3_SET_0_G3_TX_AMP_ADJ_OFFSET)
+#define HPIPE_G3_SET_0_G3_TX_EMPH1_OFFSET      7
+#define HPIPE_G3_SET_0_G3_TX_EMPH1_MASK                \
+                       (0xf << HPIPE_G3_SET_0_G3_TX_EMPH1_OFFSET)
+#define HPIPE_G3_SET_0_G3_TX_EMPH1_EN_OFFSET   11
+#define HPIPE_G3_SET_0_G3_TX_EMPH1_EN_MASK     \
+                       (0x1 << HPIPE_G3_SET_0_G3_TX_EMPH1_EN_OFFSET)
+#define HPIPE_G3_SET_0_G3_TX_SLEW_RATE_SEL_OFFSET 12
+#define HPIPE_G3_SET_0_G3_TX_SLEW_RATE_SEL_MASK        \
+                       (0x7 << HPIPE_G3_SET_0_G3_TX_SLEW_RATE_SEL_OFFSET)
+#define HPIPE_G3_SET_0_G3_TX_SLEW_CTRL_EN_OFFSET 15
+#define HPIPE_G3_SET_0_G3_TX_SLEW_CTRL_EN_MASK \
+                       (0x1 << HPIPE_G3_SET_0_G3_TX_SLEW_CTRL_EN_OFFSET)
+
+#define HPIPE_G3_SET_1_REG                             0x48
+#define HPIPE_G3_SET_1_G3_RX_SELMUPI_OFFSET            0
+#define HPIPE_G3_SET_1_G3_RX_SELMUPI_MASK              \
+                       (0x7 << HPIPE_G3_SET_1_G3_RX_SELMUPI_OFFSET)
+#define HPIPE_G3_SET_1_G3_RX_SELMUPF_OFFSET            3
+#define HPIPE_G3_SET_1_G3_RX_SELMUPF_MASK              \
+                       (0x7 << HPIPE_G3_SET_1_G3_RX_SELMUPF_OFFSET)
+#define HPIPE_G3_SET_1_G3_RX_SELMUFI_OFFSET            6
+#define HPIPE_G3_SET_1_G3_RX_SELMUFI_MASK              \
+                       (0x3 << HPIPE_G3_SET_1_G3_RX_SELMUFI_OFFSET)
+#define HPIPE_G3_SET_1_G3_RX_SELMUFF_OFFSET            8
+#define HPIPE_G3_SET_1_G3_RX_SELMUFF_MASK              \
+                       (0x3 << HPIPE_G3_SET_1_G3_RX_SELMUFF_OFFSET)
+#define HPIPE_G3_SET_1_G3_RX_DFE_EN_OFFSET             10
+#define HPIPE_G3_SET_1_G3_RX_DFE_EN_MASK               \
+                       (0x1 << HPIPE_G3_SET_1_G3_RX_DFE_EN_OFFSET)
+#define HPIPE_G3_SET_1_G3_RX_DIGCK_DIV_OFFSET          11
+#define HPIPE_G3_SET_1_G3_RX_DIGCK_DIV_MASK            \
+                       (0x3 << HPIPE_G3_SET_1_G3_RX_DIGCK_DIV_OFFSET)
+#define HPIPE_G3_SET_1_G3_SAMPLER_INPAIRX2_EN_OFFSET   13
+#define HPIPE_G3_SET_1_G3_SAMPLER_INPAIRX2_EN_MASK     \
+                       (0x1 << HPIPE_G3_SET_1_G3_SAMPLER_INPAIRX2_EN_OFFSET)
+
+#define HPIPE_PHY_TEST_CONTROL_REG             0x54
+#define HPIPE_PHY_TEST_PATTERN_SEL_OFFSET      4
+#define HPIPE_PHY_TEST_PATTERN_SEL_MASK                \
+                       (0xf << HPIPE_PHY_TEST_PATTERN_SEL_OFFSET)
+#define HPIPE_PHY_TEST_RESET_OFFSET            14
+#define HPIPE_PHY_TEST_RESET_MASK              \
+                       (0x1 << HPIPE_PHY_TEST_RESET_OFFSET)
+#define HPIPE_PHY_TEST_EN_OFFSET               15
+#define HPIPE_PHY_TEST_EN_MASK                 \
+                       (0x1 << HPIPE_PHY_TEST_EN_OFFSET)
+
+#define HPIPE_PHY_TEST_DATA_REG                        0x6c
+#define HPIPE_PHY_TEST_DATA_OFFSET             0
+#define HPIPE_PHY_TEST_DATA_MASK               \
+                       (0xffff << HPIPE_PHY_TEST_DATA_OFFSET)
+
+#define HPIPE_LOOPBACK_REG                     0x8c
+#define HPIPE_LOOPBACK_SEL_OFFSET              1
+#define HPIPE_LOOPBACK_SEL_MASK                        \
+                       (0x7 << HPIPE_LOOPBACK_SEL_OFFSET)
+#define HPIPE_CDR_LOCK_OFFSET                  7
+#define HPIPE_CDR_LOCK_MASK                    \
+                       (0x1 << HPIPE_CDR_LOCK_OFFSET)
+#define HPIPE_CDR_LOCK_DET_EN_OFFSET           8
+#define HPIPE_CDR_LOCK_DET_EN_MASK             \
+                       (0x1 << HPIPE_CDR_LOCK_DET_EN_OFFSET)
+
+#define HPIPE_INTERFACE_REG                    0x94
+#define HPIPE_INTERFACE_GEN_MAX_OFFSET         10
+#define HPIPE_INTERFACE_GEN_MAX_MASK           \
+                       (0x3 << HPIPE_INTERFACE_GEN_MAX_OFFSET)
+#define HPIPE_INTERFACE_DET_BYPASS_OFFSET      12
+#define HPIPE_INTERFACE_DET_BYPASS_MASK                \
+                       (0x1 << HPIPE_INTERFACE_DET_BYPASS_OFFSET)
+#define HPIPE_INTERFACE_LINK_TRAIN_OFFSET      14
+#define HPIPE_INTERFACE_LINK_TRAIN_MASK                \
+                       (0x1 << HPIPE_INTERFACE_LINK_TRAIN_OFFSET)
+
+#define HPIPE_G1_SET_2_REG                     0xf4
+#define HPIPE_G1_SET_2_G1_TX_EMPH0_OFFSET      0
+#define HPIPE_G1_SET_2_G1_TX_EMPH0_MASK                \
+                       (0xf << HPIPE_G1_SET_2_G1_TX_EMPH0_OFFSET)
+#define HPIPE_G1_SET_2_G1_TX_EMPH0_EN_OFFSET   4
+#define HPIPE_G1_SET_2_G1_TX_EMPH0_EN_MASK     \
+                       (0x1 << HPIPE_G1_SET_2_G1_TX_EMPH0_EN_OFFSET)
+
+#define HPIPE_G2_SET_2_REG                     0xf8
+#define HPIPE_G2_TX_SSC_AMP_OFFSET             9
+#define HPIPE_G2_TX_SSC_AMP_MASK               \
+                       (0x7f << HPIPE_G2_TX_SSC_AMP_OFFSET)
+
+#define HPIPE_VDD_CAL_0_REG                    0x108
+#define HPIPE_CAL_VDD_CONT_MODE_OFFSET         15
+#define HPIPE_CAL_VDD_CONT_MODE_MASK           \
+                       (0x1 << HPIPE_CAL_VDD_CONT_MODE_OFFSET)
+
+#define HPIPE_VDD_CAL_CTRL_REG                 0x114
+#define HPIPE_EXT_SELLV_RXSAMPL_OFFSET         5
+#define HPIPE_EXT_SELLV_RXSAMPL_MASK           \
+                       (0x1f << HPIPE_EXT_SELLV_RXSAMPL_OFFSET)
+
+#define HPIPE_PCIE_REG0                                0x120
+#define HPIPE_PCIE_IDLE_SYNC_OFFSET            12
+#define HPIPE_PCIE_IDLE_SYNC_MASK              \
+                       (0x1 << HPIPE_PCIE_IDLE_SYNC_OFFSET)
+#define HPIPE_PCIE_SEL_BITS_OFFSET             13
+#define HPIPE_PCIE_SEL_BITS_MASK               \
+                       (0x3 << HPIPE_PCIE_SEL_BITS_OFFSET)
+
+#define HPIPE_LANE_ALIGN_REG                   0x124
+#define HPIPE_LANE_ALIGN_OFF_OFFSET            12
+#define HPIPE_LANE_ALIGN_OFF_MASK              \
+                       (0x1 << HPIPE_LANE_ALIGN_OFF_OFFSET)
+
+#define HPIPE_MISC_REG                         0x13C
+#define HPIPE_MISC_CLK100M_125M_OFFSET         4
+#define HPIPE_MISC_CLK100M_125M_MASK           \
+                       (0x1 << HPIPE_MISC_CLK100M_125M_OFFSET)
+#define HPIPE_MISC_ICP_FORCE_OFFSET            5
+#define HPIPE_MISC_ICP_FORCE_MASK              \
+                       (0x1 << HPIPE_MISC_ICP_FORCE_OFFSET)
+#define HPIPE_MISC_TXDCLK_2X_OFFSET            6
+#define HPIPE_MISC_TXDCLK_2X_MASK              \
+                       (0x1 << HPIPE_MISC_TXDCLK_2X_OFFSET)
+#define HPIPE_MISC_CLK500_EN_OFFSET            7
+#define HPIPE_MISC_CLK500_EN_MASK              \
+                       (0x1 << HPIPE_MISC_CLK500_EN_OFFSET)
+#define HPIPE_MISC_REFCLK_SEL_OFFSET           10
+#define HPIPE_MISC_REFCLK_SEL_MASK             \
+                       (0x1 << HPIPE_MISC_REFCLK_SEL_OFFSET)
+
+#define HPIPE_RX_CONTROL_1_REG                 0x140
+#define HPIPE_RX_CONTROL_1_RXCLK2X_SEL_OFFSET  11
+#define HPIPE_RX_CONTROL_1_RXCLK2X_SEL_MASK    \
+                       (0x1 << HPIPE_RX_CONTROL_1_RXCLK2X_SEL_OFFSET)
+#define HPIPE_RX_CONTROL_1_CLK8T_EN_OFFSET     12
+#define HPIPE_RX_CONTROL_1_CLK8T_EN_MASK       \
+                       (0x1 << HPIPE_RX_CONTROL_1_CLK8T_EN_OFFSET)
+
+#define HPIPE_PWR_CTR_REG                      0x148
+#define HPIPE_PWR_CTR_RST_DFE_OFFSET           0
+#define HPIPE_PWR_CTR_RST_DFE_MASK             \
+                       (0x1 << HPIPE_PWR_CTR_RST_DFE_OFFSET)
+#define HPIPE_PWR_CTR_SFT_RST_OFFSET           10
+#define HPIPE_PWR_CTR_SFT_RST_MASK             \
+                       (0x1 << HPIPE_PWR_CTR_SFT_RST_OFFSET)
+
+#define HPIPE_SPD_DIV_FORCE_REG                                0x154
+#define HPIPE_TXDIGCK_DIV_FORCE_OFFSET                 7
+#define HPIPE_TXDIGCK_DIV_FORCE_MASK                   \
+                       (0x1 << HPIPE_TXDIGCK_DIV_FORCE_OFFSET)
+#define HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_OFFSET          8
+#define HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_MASK            \
+                       (0x3 << HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_OFFSET)
+#define HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_FORCE_OFFSET    10
+#define HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_FORCE_MASK      \
+                       (0x1 << HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_FORCE_OFFSET)
+#define HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_OFFSET          13
+#define HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_MASK            \
+                       (0x3 << HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_OFFSET)
+#define HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_OFFSET    15
+#define HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_MASK      \
+                       (0x1 << HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_OFFSET)
+
+#define HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG    0x16C
+#define HPIPE_RX_SAMPLER_OS_GAIN_OFFSET                6
+#define HPIPE_RX_SAMPLER_OS_GAIN_MASK          \
+                       (0x3 << HPIPE_RX_SAMPLER_OS_GAIN_OFFSET)
+#define HPIPE_SMAPLER_OFFSET                   12
+#define HPIPE_SMAPLER_MASK                     \
+                       (0x1 << HPIPE_SMAPLER_OFFSET)
+
+#define HPIPE_TX_REG1_REG                      0x174
+#define HPIPE_TX_REG1_TX_EMPH_RES_OFFSET       5
+#define HPIPE_TX_REG1_TX_EMPH_RES_MASK         \
+                       (0x3 << HPIPE_TX_REG1_TX_EMPH_RES_OFFSET)
+#define HPIPE_TX_REG1_SLC_EN_OFFSET            10
+#define HPIPE_TX_REG1_SLC_EN_MASK              \
+                       (0x3f << HPIPE_TX_REG1_SLC_EN_OFFSET)
+
+#define HPIPE_PWR_CTR_DTL_REG                          0x184
+#define HPIPE_PWR_CTR_DTL_SQ_DET_EN_OFFSET             0
+#define HPIPE_PWR_CTR_DTL_SQ_DET_EN_MASK               \
+                       (0x1 << HPIPE_PWR_CTR_DTL_SQ_DET_EN_OFFSET)
+#define HPIPE_PWR_CTR_DTL_SQ_PLOOP_EN_OFFSET           1
+#define HPIPE_PWR_CTR_DTL_SQ_PLOOP_EN_MASK             \
+                       (0x1 << HPIPE_PWR_CTR_DTL_SQ_PLOOP_EN_OFFSET)
+#define HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET              2
+#define HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK                        \
+                       (0x1 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET)
+#define HPIPE_PWR_CTR_DTL_CLAMPING_SEL_OFFSET          4
+#define HPIPE_PWR_CTR_DTL_CLAMPING_SEL_MASK            \
+                       (0x7 << HPIPE_PWR_CTR_DTL_CLAMPING_SEL_OFFSET)
+#define HPIPE_PWR_CTR_DTL_INTPCLK_DIV_FORCE_OFFSET     10
+#define HPIPE_PWR_CTR_DTL_INTPCLK_DIV_FORCE_MASK       \
+                       (0x1 << HPIPE_PWR_CTR_DTL_INTPCLK_DIV_FORCE_OFFSET)
+#define HPIPE_PWR_CTR_DTL_CLK_MODE_OFFSET              12
+#define HPIPE_PWR_CTR_DTL_CLK_MODE_MASK                        \
+                       (0x3 << HPIPE_PWR_CTR_DTL_CLK_MODE_OFFSET)
+#define HPIPE_PWR_CTR_DTL_CLK_MODE_FORCE_OFFSET                14
+#define HPIPE_PWR_CTR_DTL_CLK_MODE_FORCE_MASK          \
+                       (1 << HPIPE_PWR_CTR_DTL_CLK_MODE_FORCE_OFFSET)
+
+#define HPIPE_PHASE_CONTROL_REG                        0x188
+#define HPIPE_OS_PH_OFFSET_OFFSET              0
+#define HPIPE_OS_PH_OFFSET_MASK                        \
+                       (0x7f << HPIPE_OS_PH_OFFSET_OFFSET)
+#define HPIPE_OS_PH_OFFSET_FORCE_OFFSET                7
+#define HPIPE_OS_PH_OFFSET_FORCE_MASK          \
+                       (0x1 << HPIPE_OS_PH_OFFSET_FORCE_OFFSET)
+#define HPIPE_OS_PH_VALID_OFFSET               8
+#define HPIPE_OS_PH_VALID_MASK                 \
+                       (0x1 << HPIPE_OS_PH_VALID_OFFSET)
+
+#define HPIPE_SQ_GLITCH_FILTER_CTRL            0x1c8
+#define HPIPE_SQ_DEGLITCH_WIDTH_P_OFFSET       0
+#define HPIPE_SQ_DEGLITCH_WIDTH_P_MASK         \
+                       (0xf << HPIPE_SQ_DEGLITCH_WIDTH_P_OFFSET)
+#define HPIPE_SQ_DEGLITCH_WIDTH_N_OFFSET       4
+#define HPIPE_SQ_DEGLITCH_WIDTH_N_MASK         \
+                       (0xf << HPIPE_SQ_DEGLITCH_WIDTH_N_OFFSET)
+#define HPIPE_SQ_DEGLITCH_EN_OFFSET            8
+#define HPIPE_SQ_DEGLITCH_EN_MASK              \
+                       (0x1 << HPIPE_SQ_DEGLITCH_EN_OFFSET)
+
+#define HPIPE_FRAME_DETECT_CTRL_0_REG          0x214
+#define HPIPE_TRAIN_PAT_NUM_OFFSET             0x7
+#define HPIPE_TRAIN_PAT_NUM_MASK               \
+                       (0x1FF << HPIPE_TRAIN_PAT_NUM_OFFSET)
+
+#define HPIPE_FRAME_DETECT_CTRL_3_REG                  0x220
+#define HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_OFFSET      12
+#define HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_MASK                \
+                       (0x1 << HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_OFFSET)
+
+#define HPIPE_DME_REG                          0x228
+#define HPIPE_DME_ETHERNET_MODE_OFFSET         7
+#define HPIPE_DME_ETHERNET_MODE_MASK           \
+                       (0x1 << HPIPE_DME_ETHERNET_MODE_OFFSET)
+
+#define HPIPE_TX_TRAIN_CTRL_0_REG              0x268
+#define HPIPE_TX_TRAIN_P2P_HOLD_OFFSET         15
+#define HPIPE_TX_TRAIN_P2P_HOLD_MASK           \
+                       (0x1 << HPIPE_TX_TRAIN_P2P_HOLD_OFFSET)
+
+#define HPIPE_TX_TRAIN_CTRL_REG                        0x26C
+#define HPIPE_TX_TRAIN_CTRL_G1_OFFSET          0
+#define HPIPE_TX_TRAIN_CTRL_G1_MASK            \
+                       (0x1 << HPIPE_TX_TRAIN_CTRL_G1_OFFSET)
+#define HPIPE_TX_TRAIN_CTRL_GN1_OFFSET         1
+#define HPIPE_TX_TRAIN_CTRL_GN1_MASK           \
+                       (0x1 << HPIPE_TX_TRAIN_CTRL_GN1_OFFSET)
+#define HPIPE_TX_TRAIN_CTRL_G0_OFFSET          2
+#define HPIPE_TX_TRAIN_CTRL_G0_MASK            \
+                       (0x1 << HPIPE_TX_TRAIN_CTRL_G0_OFFSET)
+
+#define HPIPE_TX_TRAIN_CTRL_4_REG              0x278
+#define HPIPE_TRX_TRAIN_TIMER_OFFSET           0
+#define HPIPE_TRX_TRAIN_TIMER_MASK             \
+                       (0x3FF << HPIPE_TRX_TRAIN_TIMER_OFFSET)
+
+#define HPIPE_TX_TRAIN_CTRL_5_REG              0x2A4
+#define HPIPE_RX_TRAIN_TIMER_OFFSET            0
+#define HPIPE_RX_TRAIN_TIMER_MASK              \
+                       (0x3ff << HPIPE_RX_TRAIN_TIMER_OFFSET)
+#define HPIPE_TX_TRAIN_START_SQ_EN_OFFSET      11
+#define HPIPE_TX_TRAIN_START_SQ_EN_MASK                \
+                       (0x1 << HPIPE_TX_TRAIN_START_SQ_EN_OFFSET)
+#define HPIPE_TX_TRAIN_START_FRM_DET_EN_OFFSET 12
+#define HPIPE_TX_TRAIN_START_FRM_DET_EN_MASK   \
+                       (0x1 << HPIPE_TX_TRAIN_START_FRM_DET_EN_OFFSET)
+#define HPIPE_TX_TRAIN_START_FRM_LOCK_EN_OFFSET        13
+#define HPIPE_TX_TRAIN_START_FRM_LOCK_EN_MASK  \
+                       (0x1 << HPIPE_TX_TRAIN_START_FRM_LOCK_EN_OFFSET)
+#define HPIPE_TX_TRAIN_WAIT_TIME_EN_OFFSET     14
+#define HPIPE_TX_TRAIN_WAIT_TIME_EN_MASK       \
+                       (0x1 << HPIPE_TX_TRAIN_WAIT_TIME_EN_OFFSET)
+
+#define HPIPE_TX_TRAIN_REG                     0x31C
+#define HPIPE_TX_TRAIN_CHK_INIT_OFFSET         4
+#define HPIPE_TX_TRAIN_CHK_INIT_MASK           \
+                       (0x1 << HPIPE_TX_TRAIN_CHK_INIT_OFFSET)
+#define HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_OFFSET 7
+#define HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_MASK   \
+                       (0x1 << HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_OFFSET)
+#define HPIPE_TX_TRAIN_16BIT_AUTO_EN_OFFSET    8
+#define HPIPE_TX_TRAIN_16BIT_AUTO_EN_MASK      \
+                       (0x1 << HPIPE_TX_TRAIN_16BIT_AUTO_EN_OFFSET)
+#define HPIPE_TX_TRAIN_PAT_SEL_OFFSET          9
+#define HPIPE_TX_TRAIN_PAT_SEL_MASK            \
+                       (0x1 << HPIPE_TX_TRAIN_PAT_SEL_OFFSET)
+
+#define HPIPE_SAVED_DFE_VALUES_REG             0x328
+#define HPIPE_SAVED_DFE_VALUES_SAV_F0D_OFFSET  10
+#define HPIPE_SAVED_DFE_VALUES_SAV_F0D_MASK    \
+                       (0x3f << HPIPE_SAVED_DFE_VALUES_SAV_F0D_OFFSET)
+
+#define HPIPE_CDR_CONTROL_REG                  0x418
+#define HPIPE_CDR_RX_MAX_DFE_ADAPT_0_OFFSET    14
+#define HPIPE_CDR_RX_MAX_DFE_ADAPT_0_MASK      \
+                       (0x3 << HPIPE_CDR_RX_MAX_DFE_ADAPT_0_OFFSET)
+#define HPIPE_CDR_RX_MAX_DFE_ADAPT_1_OFFSET    12
+#define HPIPE_CDR_RX_MAX_DFE_ADAPT_1_MASK      \
+                       (0x3 << HPIPE_CDR_RX_MAX_DFE_ADAPT_1_OFFSET)
+#define HPIPE_CDR_MAX_DFE_ADAPT_0_OFFSET       9
+#define HPIPE_CDR_MAX_DFE_ADAPT_0_MASK         \
+                       (0x7 << HPIPE_CDR_MAX_DFE_ADAPT_0_OFFSET)
+#define HPIPE_CDR_MAX_DFE_ADAPT_1_OFFSET       6
+#define HPIPE_CDR_MAX_DFE_ADAPT_1_MASK         \
+                       (0x7 << HPIPE_CDR_MAX_DFE_ADAPT_1_OFFSET)
+
+#define HPIPE_TX_TRAIN_CTRL_11_REG             0x438
+#define HPIPE_TX_STATUS_CHECK_MODE_OFFSET      6
+#define HPIPE_TX_TX_STATUS_CHECK_MODE_MASK     \
+                       (0x1 << HPIPE_TX_STATUS_CHECK_MODE_OFFSET)
+#define HPIPE_TX_NUM_OF_PRESET_OFFSET          10
+#define HPIPE_TX_NUM_OF_PRESET_MASK            \
+                       (0x7 << HPIPE_TX_NUM_OF_PRESET_OFFSET)
+#define HPIPE_TX_SWEEP_PRESET_EN_OFFSET                15
+#define HPIPE_TX_SWEEP_PRESET_EN_MASK          \
+                       (0x1 << HPIPE_TX_SWEEP_PRESET_EN_OFFSET)
+
+#define HPIPE_G1_SETTINGS_3_REG                                0x440
+#define HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_OFFSET      0
+#define HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_MASK                \
+                       (0xf << HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_OFFSET)
+#define HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_OFFSET      4
+#define HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_MASK                \
+                       (0x7 << HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_OFFSET)
+#define HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET        7
+#define HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_MASK  \
+                       (0x1 << HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET)
+#define HPIPE_G1_SETTINGS_3_G1_FBCK_SEL_OFFSET         9
+#define HPIPE_G1_SETTINGS_3_G1_FBCK_SEL_MASK           \
+                       (0x1 << HPIPE_G1_SETTINGS_3_G1_FBCK_SEL_OFFSET)
+#define HPIPE_G1_SETTINGS_3_G1_FFE_DEG_RES_LEVEL_OFFSET        12
+#define HPIPE_G1_SETTINGS_3_G1_FFE_DEG_RES_LEVEL_MASK  \
+                       (0x3 << HPIPE_G1_SETTINGS_3_G1_FFE_DEG_RES_LEVEL_OFFSET)
+#define HPIPE_G1_SETTINGS_3_G1_FFE_LOAD_RES_LEVEL_OFFSET       14
+#define HPIPE_G1_SETTINGS_3_G1_FFE_LOAD_RES_LEVEL_MASK \
+               (0x3 << HPIPE_G1_SETTINGS_3_G1_FFE_LOAD_RES_LEVEL_OFFSET)
+
+#define HPIPE_G1_SETTINGS_4_REG                        0x444
+#define HPIPE_G1_SETTINGS_4_G1_DFE_RES_OFFSET  8
+#define HPIPE_G1_SETTINGS_4_G1_DFE_RES_MASK    \
+                       (0x3 << HPIPE_G1_SETTINGS_4_G1_DFE_RES_OFFSET)
+
+#define HPIPE_G2_SETTINGS_4_REG                        0x44c
+#define HPIPE_G2_DFE_RES_OFFSET                        8
+#define HPIPE_G2_DFE_RES_MASK                  \
+                       (0x3 << HPIPE_G2_DFE_RES_OFFSET)
+
+#define HPIPE_G3_SETTING_3_REG                 0x450
+#define HPIPE_G3_FFE_CAP_SEL_OFFSET            0
+#define HPIPE_G3_FFE_CAP_SEL_MASK              \
+                       (0xf << HPIPE_G3_FFE_CAP_SEL_OFFSET)
+#define HPIPE_G3_FFE_RES_SEL_OFFSET            4
+#define HPIPE_G3_FFE_RES_SEL_MASK              \
+                       (0x7 << HPIPE_G3_FFE_RES_SEL_OFFSET)
+#define HPIPE_G3_FFE_SETTING_FORCE_OFFSET      7
+#define HPIPE_G3_FFE_SETTING_FORCE_MASK                \
+                       (0x1 << HPIPE_G3_FFE_SETTING_FORCE_OFFSET)
+#define HPIPE_G3_FFE_DEG_RES_LEVEL_OFFSET      12
+#define HPIPE_G3_FFE_DEG_RES_LEVEL_MASK                \
+                       (0x3 << HPIPE_G3_FFE_DEG_RES_LEVEL_OFFSET)
+#define HPIPE_G3_FFE_LOAD_RES_LEVEL_OFFSET     14
+#define HPIPE_G3_FFE_LOAD_RES_LEVEL_MASK       \
+                       (0x3 << HPIPE_G3_FFE_LOAD_RES_LEVEL_OFFSET)
+
+#define HPIPE_G3_SETTING_4_REG                 0x454
+#define HPIPE_G3_DFE_RES_OFFSET                        8
+#define HPIPE_G3_DFE_RES_MASK                  (0x3 << HPIPE_G3_DFE_RES_OFFSET)
+
+#define HPIPE_TX_PRESET_INDEX_REG              0x468
+#define HPIPE_TX_PRESET_INDEX_OFFSET           0
+#define HPIPE_TX_PRESET_INDEX_MASK             \
+                       (0xf << HPIPE_TX_PRESET_INDEX_OFFSET)
+
+#define HPIPE_DFE_CONTROL_REG                  0x470
+#define HPIPE_DFE_TX_MAX_DFE_ADAPT_OFFSET      14
+#define HPIPE_DFE_TX_MAX_DFE_ADAPT_MASK                \
+                       (0x3 << HPIPE_DFE_TX_MAX_DFE_ADAPT_OFFSET)
+
+#define HPIPE_DFE_CTRL_28_REG                  0x49C
+#define HPIPE_DFE_CTRL_28_PIPE4_OFFSET         7
+#define HPIPE_DFE_CTRL_28_PIPE4_MASK           \
+                       (0x1 << HPIPE_DFE_CTRL_28_PIPE4_OFFSET)
+
+#define HPIPE_G1_SETTING_5_REG                 0x538
+#define HPIPE_G1_SETTING_5_G1_ICP_OFFSET       0
+#define HPIPE_G1_SETTING_5_G1_ICP_MASK         \
+                       (0xf << HPIPE_G1_SETTING_5_G1_ICP_OFFSET)
+
+#define HPIPE_G3_SETTING_5_REG                 0x548
+#define HPIPE_G3_SETTING_5_G3_ICP_OFFSET       0
+#define HPIPE_G3_SETTING_5_G3_ICP_MASK         \
+                       (0xf << HPIPE_G3_SETTING_5_G3_ICP_OFFSET)
+
+#define HPIPE_LANE_CONFIG0_REG                 0x600
+#define HPIPE_LANE_CONFIG0_TXDEEMPH0_OFFSET    0
+#define HPIPE_LANE_CONFIG0_TXDEEMPH0_MASK      \
+                       (0x1 << HPIPE_LANE_CONFIG0_TXDEEMPH0_OFFSET)
+
+#define HPIPE_LANE_STATUS1_REG                 0x60C
+#define HPIPE_LANE_STATUS1_PCLK_EN_OFFSET      0
+#define HPIPE_LANE_STATUS1_PCLK_EN_MASK                \
+                       (0x1 << HPIPE_LANE_STATUS1_PCLK_EN_OFFSET)
+
+#define HPIPE_LANE_CFG4_REG                    0x620
+#define HPIPE_LANE_CFG4_DFE_CTRL_OFFSET                0
+#define HPIPE_LANE_CFG4_DFE_CTRL_MASK          \
+                       (0x7 << HPIPE_LANE_CFG4_DFE_CTRL_OFFSET)
+#define HPIPE_LANE_CFG4_DFE_EN_SEL_OFFSET      3
+#define HPIPE_LANE_CFG4_DFE_EN_SEL_MASK                \
+                       (0x1 << HPIPE_LANE_CFG4_DFE_EN_SEL_OFFSET)
+#define HPIPE_LANE_CFG4_DFE_OVER_OFFSET                6
+#define HPIPE_LANE_CFG4_DFE_OVER_MASK          \
+                       (0x1 << HPIPE_LANE_CFG4_DFE_OVER_OFFSET)
+#define HPIPE_LANE_CFG4_SSC_CTRL_OFFSET                7
+#define HPIPE_LANE_CFG4_SSC_CTRL_MASK          \
+                       (0x1 << HPIPE_LANE_CFG4_SSC_CTRL_OFFSET)
+
+#define HPIPE_LANE_EQ_REMOTE_SETTING_REG       0x6f8
+#define HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_OFFSET        0
+#define HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_MASK  \
+                       (0x1 << HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_OFFSET)
+#define HPIPE_LANE_CFG_FOM_ONLY_MODE_OFFFSET   1
+#define HPIPE_LANE_CFG_FOM_ONLY_MODE_MASK      \
+                       (0x1 << HPIPE_LANE_CFG_FOM_ONLY_MODE_OFFFSET)
+#define HPIPE_LANE_CFG_FOM_PRESET_VECTOR_OFFSET        2
+#define HPIPE_LANE_CFG_FOM_PRESET_VECTOR_MASK  \
+                       (0xf << HPIPE_LANE_CFG_FOM_PRESET_VECTOR_OFFSET)
+
+#define HPIPE_LANE_EQU_CONFIG_0_REG            0x69C
+#define HPIPE_CFG_PHY_RC_EP_OFFSET             12
+#define HPIPE_CFG_PHY_RC_EP_MASK               \
+                       (0x1 << HPIPE_CFG_PHY_RC_EP_OFFSET)
+
+#define HPIPE_LANE_EQ_CFG1_REG                 0x6a0
+#define HPIPE_CFG_UPDATE_POLARITY_OFFSET       12
+#define HPIPE_CFG_UPDATE_POLARITY_MASK         \
+                       (0x1 << HPIPE_CFG_UPDATE_POLARITY_OFFSET)
+
+#define HPIPE_LANE_EQ_CFG2_REG                 0x6a4
+#define HPIPE_CFG_EQ_BUNDLE_DIS_OFFSET         14
+#define HPIPE_CFG_EQ_BUNDLE_DIS_MASK           \
+                       (0x1 << HPIPE_CFG_EQ_BUNDLE_DIS_OFFSET)
+
+#define HPIPE_RST_CLK_CTRL_REG                 0x704
+#define HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET     0
+#define HPIPE_RST_CLK_CTRL_PIPE_RST_MASK       \
+                       (0x1 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET)
+#define HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET   2
+#define HPIPE_RST_CLK_CTRL_FIXED_PCLK_MASK     \
+                       (0x1 << HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET)
+#define HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET   3
+#define HPIPE_RST_CLK_CTRL_PIPE_WIDTH_MASK     \
+                       (0x1 << HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET)
+#define HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET        9
+#define HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_MASK  \
+                       (0x1 << HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET)
+
+#define HPIPE_TST_MODE_CTRL_REG                        0x708
+#define HPIPE_TST_MODE_CTRL_MODE_MARGIN_OFFSET 2
+#define HPIPE_TST_MODE_CTRL_MODE_MARGIN_MASK   \
+                       (0x1 << HPIPE_TST_MODE_CTRL_MODE_MARGIN_OFFSET)
+
+#define HPIPE_CLK_SRC_LO_REG                           0x70c
+#define HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_OFFSET      1
+#define HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_MASK                \
+                       (0x1 << HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_OFFSET)
+#define HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_OFFSET    2
+#define HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_MASK      \
+                       (0x3 << HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_OFFSET)
+#define HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET             5
+#define HPIPE_CLK_SRC_LO_PLL_RDY_DL_MASK               \
+                       (0x7 << HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET)
+
+#define HPIPE_CLK_SRC_HI_REG                   0x710
+#define HPIPE_CLK_SRC_HI_LANE_STRT_OFFSET      0
+#define HPIPE_CLK_SRC_HI_LANE_STRT_MASK                \
+                       (0x1 << HPIPE_CLK_SRC_HI_LANE_STRT_OFFSET)
+#define HPIPE_CLK_SRC_HI_LANE_BREAK_OFFSET     1
+#define HPIPE_CLK_SRC_HI_LANE_BREAK_MASK       \
+                       (0x1 << HPIPE_CLK_SRC_HI_LANE_BREAK_OFFSET)
+#define HPIPE_CLK_SRC_HI_LANE_MASTER_OFFSET    2
+#define HPIPE_CLK_SRC_HI_LANE_MASTER_MASK      \
+                       (0x1 << HPIPE_CLK_SRC_HI_LANE_MASTER_OFFSET)
+#define HPIPE_CLK_SRC_HI_MODE_PIPE_OFFSET      7
+#define HPIPE_CLK_SRC_HI_MODE_PIPE_MASK                \
+                       (0x1 << HPIPE_CLK_SRC_HI_MODE_PIPE_OFFSET)
+
+#define HPIPE_GLOBAL_MISC_CTRL                 0x718
+#define HPIPE_GLOBAL_PM_CTRL                   0x740
+#define HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET     0
+#define HPIPE_GLOBAL_PM_RXDLOZ_WAIT_MASK       \
+                       (0xFF << HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET)
+
+/* General defines */
+#define PLL_LOCK_TIMEOUT                       15000
+
+#endif /* _PHY_COMPHY_CP110_H */
+
diff --git a/drivers/marvell/comphy/phy-comphy-cp110.c b/drivers/marvell/comphy/phy-comphy-cp110.c
new file mode 100644 (file)
index 0000000..8b78280
--- /dev/null
@@ -0,0 +1,2319 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* Marvell CP110 SoC COMPHY unit driver */
+
+#include <debug.h>
+#include <delay_timer.h>
+#include <errno.h>
+#include <mmio.h>
+#include <mvebu_def.h>
+#include <spinlock.h>
+#include "mvebu.h"
+#include "comphy-cp110.h"
+
+/* #define DEBUG_COMPHY */
+#ifdef DEBUG_COMPHY
+#define debug(format...) printf(format)
+#else
+#define debug(format, arg...)
+#endif
+
+/* A lane is described by 4 fields:
+ *      - bit 1~0 represent comphy polarity invert
+ *      - bit 7~2 represent comphy speed
+ *      - bit 11~8 represent unit index
+ *      - bit 16~12 represent mode
+ *      - bit 17 represent comphy indication of clock source
+ *      - bit 19-18 represents pcie width (in case of pcie comphy config.)
+ *      - bit 31~20 reserved
+ */
+
+#define COMPHY_INVERT_OFFSET   0
+#define COMPHY_INVERT_LEN      2
+#define COMPHY_INVERT_MASK     COMPHY_MASK(COMPHY_INVERT_OFFSET, \
+                                               COMPHY_INVERT_LEN)
+#define COMPHY_SPEED_OFFSET    (COMPHY_INVERT_OFFSET + COMPHY_INVERT_LEN)
+#define COMPHY_SPEED_LEN       6
+#define COMPHY_SPEED_MASK      COMPHY_MASK(COMPHY_SPEED_OFFSET, \
+                                               COMPHY_SPEED_LEN)
+#define COMPHY_UNIT_ID_OFFSET  (COMPHY_SPEED_OFFSET + COMPHY_SPEED_LEN)
+#define COMPHY_UNIT_ID_LEN     4
+#define COMPHY_UNIT_ID_MASK    COMPHY_MASK(COMPHY_UNIT_ID_OFFSET, \
+                                               COMPHY_UNIT_ID_LEN)
+#define COMPHY_MODE_OFFSET     (COMPHY_UNIT_ID_OFFSET + COMPHY_UNIT_ID_LEN)
+#define COMPHY_MODE_LEN                5
+#define COMPHY_MODE_MASK       COMPHY_MASK(COMPHY_MODE_OFFSET, COMPHY_MODE_LEN)
+#define COMPHY_CLK_SRC_OFFSET  (COMPHY_MODE_OFFSET + COMPHY_MODE_LEN)
+#define COMPHY_CLK_SRC_LEN     1
+#define COMPHY_CLK_SRC_MASK    COMPHY_MASK(COMPHY_CLK_SRC_OFFSET, \
+                                               COMPHY_CLK_SRC_LEN)
+#define COMPHY_PCI_WIDTH_OFFSET        (COMPHY_CLK_SRC_OFFSET + COMPHY_CLK_SRC_LEN)
+#define COMPHY_PCI_WIDTH_LEN   3
+#define COMPHY_PCI_WIDTH_MASK  COMPHY_MASK(COMPHY_PCI_WIDTH_OFFSET, \
+                                               COMPHY_PCI_WIDTH_LEN)
+
+#define COMPHY_MASK(offset, len)       (((1 << (len)) - 1) << (offset))
+
+/* Macro which extracts mode from lane description */
+#define COMPHY_GET_MODE(x)             (((x) & COMPHY_MODE_MASK) >> \
+                                               COMPHY_MODE_OFFSET)
+/* Macro which extracts unit index from lane description */
+#define COMPHY_GET_ID(x)               (((x) & COMPHY_UNIT_ID_MASK) >> \
+                                               COMPHY_UNIT_ID_OFFSET)
+/* Macro which extracts speed from lane description */
+#define COMPHY_GET_SPEED(x)            (((x) & COMPHY_SPEED_MASK) >> \
+                                               COMPHY_SPEED_OFFSET)
+/* Macro which extracts clock source indication from lane description */
+#define COMPHY_GET_CLK_SRC(x)          (((x) & COMPHY_CLK_SRC_MASK) >> \
+                                               COMPHY_CLK_SRC_OFFSET)
+/* Macro which extracts pcie width indication from lane description */
+#define COMPHY_GET_PCIE_WIDTH(x)       (((x) & COMPHY_PCI_WIDTH_MASK) >> \
+                                               COMPHY_PCI_WIDTH_OFFSET)
+
+#define COMPHY_SATA_MODE       0x1
+#define COMPHY_SGMII_MODE      0x2     /* SGMII 1G */
+#define COMPHY_HS_SGMII_MODE   0x3     /* SGMII 2.5G */
+#define COMPHY_USB3H_MODE      0x4
+#define COMPHY_USB3D_MODE      0x5
+#define COMPHY_PCIE_MODE       0x6
+#define COMPHY_RXAUI_MODE      0x7
+#define COMPHY_XFI_MODE                0x8
+#define COMPHY_SFI_MODE                0x9
+#define COMPHY_USB3_MODE       0xa
+#define COMPHY_AP_MODE         0xb
+
+/* COMPHY speed macro */
+#define COMPHY_SPEED_1_25G             0 /* SGMII 1G */
+#define COMPHY_SPEED_2_5G              1
+#define COMPHY_SPEED_3_125G            2 /* SGMII 2.5G */
+#define COMPHY_SPEED_5G                        3
+#define COMPHY_SPEED_5_15625G          4 /* XFI 5G */
+#define COMPHY_SPEED_6G                        5
+#define COMPHY_SPEED_10_3125G          6 /* XFI 10G */
+#define COMPHY_SPEED_MAX               0x3F
+/* The  default speed for IO with fixed known speed */
+#define COMPHY_SPEED_DEFAULT           COMPHY_SPEED_MAX
+
+/* Commands for comphy driver */
+#define COMPHY_COMMAND_DIGITAL_PWR_OFF         0x00000001
+#define COMPHY_COMMAND_DIGITAL_PWR_ON          0x00000002
+
+#define COMPHY_PIPE_FROM_COMPHY_ADDR(x)        ((x & ~0xffffff) + 0x120000)
+
+/* System controller registers */
+#define PCIE_MAC_RESET_MASK_PORT0      BIT(13)
+#define PCIE_MAC_RESET_MASK_PORT1      BIT(11)
+#define PCIE_MAC_RESET_MASK_PORT2      BIT(12)
+#define SYS_CTRL_UINIT_SOFT_RESET_REG  0x268
+#define SYS_CTRL_FROM_COMPHY_ADDR(x)   ((x & ~0xffffff) + 0x440000)
+
+/* DFX register spaces */
+#define SAR_RST_PCIE0_CLOCK_CONFIG_CP1_OFFSET  (0)
+#define SAR_RST_PCIE0_CLOCK_CONFIG_CP1_MASK    (0x1 << \
+                                       SAR_RST_PCIE0_CLOCK_CONFIG_CP1_OFFSET)
+#define SAR_RST_PCIE1_CLOCK_CONFIG_CP1_OFFSET  (1)
+#define SAR_RST_PCIE1_CLOCK_CONFIG_CP1_MASK    (0x1 << \
+                                       SAR_RST_PCIE1_CLOCK_CONFIG_CP1_OFFSET)
+#define SAR_STATUS_0_REG                       200
+#define DFX_FROM_COMPHY_ADDR(x)                        ((x & ~0xffffff) + DFX_BASE)
+
+/* The same Units Soft Reset Config register are accessed in all PCIe ports
+ * initialization, so a spin lock is defined in case when more than 1 CPUs
+ * resets PCIe MAC and need to access the register in the same time. The spin
+ * lock is shared by all CP110 units.
+ */
+spinlock_t cp110_mac_reset_lock;
+
+enum reg_width_type {
+       REG_16BIT = 0,
+       REG_32BIT,
+};
+
+enum {
+       COMPHY_LANE0 = 0,
+       COMPHY_LANE1,
+       COMPHY_LANE2,
+       COMPHY_LANE3,
+       COMPHY_LANE4,
+       COMPHY_LANE5,
+       COMPHY_LANE_MAX,
+};
+
+/* These values come from the PCI Express Spec */
+enum pcie_link_width {
+       PCIE_LNK_WIDTH_RESRV    = 0x00,
+       PCIE_LNK_X1             = 0x01,
+       PCIE_LNK_X2             = 0x02,
+       PCIE_LNK_X4             = 0x04,
+       PCIE_LNK_X8             = 0x08,
+       PCIE_LNK_X12            = 0x0C,
+       PCIE_LNK_X16            = 0x10,
+       PCIE_LNK_X32            = 0x20,
+       PCIE_LNK_WIDTH_UNKNOWN  = 0xFF,
+};
+
+static inline uint32_t polling_with_timeout(uintptr_t addr,
+                                           uint32_t val,
+                                           uint32_t mask,
+                                           uint32_t usec_timeout,
+                                           enum reg_width_type type)
+{
+       uint32_t data;
+
+       do {
+               udelay(1);
+               if (type == REG_16BIT)
+                       data = mmio_read_16(addr) & mask;
+               else
+                       data = mmio_read_32(addr) & mask;
+       } while (data != val  && --usec_timeout > 0);
+
+       if (usec_timeout == 0)
+               return data;
+
+       return 0;
+}
+
+static inline void reg_set(uintptr_t addr, uint32_t data, uint32_t mask)
+{
+       debug("<atf>: WR to addr = %#010lx, data = %#010x (mask = %#010x) - ",
+             addr, data, mask);
+       debug("old value = %#010x ==> ", mmio_read_32(addr));
+       mmio_clrsetbits_32(addr, mask, data);
+
+       debug("new val %#010x\n", mmio_read_32(addr));
+}
+
+/* Clear PIPE selector - avoid collision with previous configuration */
+static void mvebu_cp110_comphy_clr_pipe_selector(uint64_t comphy_base,
+                                                uint8_t comphy_index)
+{
+       uint32_t reg, mask, field;
+       uint32_t comphy_offset =
+                       COMMON_SELECTOR_COMPHYN_FIELD_WIDTH * comphy_index;
+
+       mask = COMMON_SELECTOR_COMPHY_MASK << comphy_offset;
+       reg = mmio_read_32(comphy_base + COMMON_SELECTOR_PIPE_REG_OFFSET);
+       field = reg & mask;
+
+       if (field) {
+               reg &= ~mask;
+               mmio_write_32(comphy_base + COMMON_SELECTOR_PIPE_REG_OFFSET,
+                            reg);
+       }
+}
+
+/* Clear PHY selector - avoid collision with previous configuration */
+static void mvebu_cp110_comphy_clr_phy_selector(uint64_t comphy_base,
+                                               uint8_t comphy_index)
+{
+       uint32_t reg, mask, field;
+       uint32_t comphy_offset =
+                       COMMON_SELECTOR_COMPHYN_FIELD_WIDTH * comphy_index;
+
+       mask = COMMON_SELECTOR_COMPHY_MASK << comphy_offset;
+       reg = mmio_read_32(comphy_base + COMMON_SELECTOR_PHY_REG_OFFSET);
+       field = reg & mask;
+
+       /* Clear comphy selector - if it was already configured.
+        * (might be that this comphy was configured as PCIe/USB,
+        * in such case, no need to clear comphy selector because PCIe/USB
+        * are controlled by hpipe selector).
+        */
+       if (field) {
+               reg &= ~mask;
+               mmio_write_32(comphy_base + COMMON_SELECTOR_PHY_REG_OFFSET,
+                             reg);
+       }
+}
+
+/* PHY selector configures SATA and Network modes */
+static void mvebu_cp110_comphy_set_phy_selector(uint64_t comphy_base,
+                                    uint8_t comphy_index, uint32_t comphy_mode)
+{
+       uint32_t reg, mask;
+       uint32_t comphy_offset =
+                       COMMON_SELECTOR_COMPHYN_FIELD_WIDTH * comphy_index;
+       int mode;
+
+       /* If phy selector is used the pipe selector should be marked as
+        * unconnected.
+        */
+       mvebu_cp110_comphy_clr_pipe_selector(comphy_base, comphy_index);
+
+       /* Comphy mode (compound of the IO mode and id). Here, only the IO mode
+        * is required to distinguish between SATA and network modes.
+        */
+       mode = COMPHY_GET_MODE(comphy_mode);
+
+       mask = COMMON_SELECTOR_COMPHY_MASK << comphy_offset;
+       reg = mmio_read_32(comphy_base + COMMON_SELECTOR_PHY_REG_OFFSET);
+       reg &= ~mask;
+
+       /* SATA port 0/1 require the same configuration */
+       if (mode == COMPHY_SATA_MODE) {
+               /* SATA selector values is always 4 */
+               reg |= COMMON_SELECTOR_COMPHYN_SATA << comphy_offset;
+       } else {
+               switch (comphy_index) {
+               case(0):
+               case(1):
+               case(2):
+                       /* For comphy 0,1, and 2:
+                        * Network selector value is always 1.
+                        */
+                       reg |= COMMON_SELECTOR_COMPHY0_1_2_NETWORK <<
+                               comphy_offset;
+                       break;
+               case(3):
+                       /* For comphy 3:
+                        * 0x1 = RXAUI_Lane1
+                        * 0x2 = SGMII/HS-SGMII Port1
+                        */
+                       if (mode == COMPHY_RXAUI_MODE)
+                               reg |= COMMON_SELECTOR_COMPHY3_RXAUI <<
+                                       comphy_offset;
+                       else
+                               reg |= COMMON_SELECTOR_COMPHY3_SGMII <<
+                                       comphy_offset;
+                       break;
+               case(4):
+                        /* For comphy 4:
+                         * 0x1 = SGMII/HS-SGMII Port1, XFI1/SFI1
+                         * 0x2 = SGMII/HS-SGMII Port0: XFI0/SFI0, RXAUI_Lane0
+                         *
+                         * We want to check if SGMII1/HS_SGMII1 is the
+                         * requested mode in order to determine which value
+                         * should be set (all other modes use the same value)
+                         * so we need to strip the mode, and check the ID
+                         * because we might handle SGMII0/HS_SGMII0 too.
+                         */
+                         /* TODO: need to distinguish between CP110 and CP115
+                          * as SFI1/XFI1 available only for CP115.
+                          */
+                       if ((mode == COMPHY_SGMII_MODE ||
+                           mode == COMPHY_HS_SGMII_MODE ||
+                           mode == COMPHY_SFI_MODE) &&
+                           COMPHY_GET_ID(comphy_mode) == 1)
+                               reg |= COMMON_SELECTOR_COMPHY4_PORT1 <<
+                                       comphy_offset;
+                       else
+                               reg |= COMMON_SELECTOR_COMPHY4_ALL_OTHERS <<
+                                       comphy_offset;
+                       break;
+               case(5):
+                       /* For comphy 5:
+                        * 0x1 = SGMII/HS-SGMII Port2
+                        * 0x2 = RXAUI Lane1
+                        */
+                       if (mode == COMPHY_RXAUI_MODE)
+                               reg |= COMMON_SELECTOR_COMPHY5_RXAUI <<
+                                       comphy_offset;
+                       else
+                               reg |= COMMON_SELECTOR_COMPHY5_SGMII <<
+                                       comphy_offset;
+                       break;
+               }
+       }
+
+       mmio_write_32(comphy_base + COMMON_SELECTOR_PHY_REG_OFFSET, reg);
+}
+
+/* PIPE selector configures for PCIe, USB 3.0 Host, and USB 3.0 Device mode */
+static void mvebu_cp110_comphy_set_pipe_selector(uint64_t comphy_base,
+                                    uint8_t comphy_index, uint32_t comphy_mode)
+{
+       uint32_t reg;
+       uint32_t shift = COMMON_SELECTOR_COMPHYN_FIELD_WIDTH * comphy_index;
+       int mode = COMPHY_GET_MODE(comphy_mode);
+       uint32_t mask = COMMON_SELECTOR_COMPHY_MASK << shift;
+       uint32_t pipe_sel = 0x0;
+
+       /* If pipe selector is used the phy selector should be marked as
+        * unconnected.
+        */
+       mvebu_cp110_comphy_clr_phy_selector(comphy_base, comphy_index);
+
+       reg = mmio_read_32(comphy_base + COMMON_SELECTOR_PIPE_REG_OFFSET);
+       reg &= ~mask;
+
+       switch (mode) {
+       case (COMPHY_PCIE_MODE):
+               /* For lanes support PCIE, selector value are all same */
+               pipe_sel = COMMON_SELECTOR_PIPE_COMPHY_PCIE;
+               break;
+
+       case (COMPHY_USB3H_MODE):
+               /* Only lane 1-4 support USB host, selector value is same */
+               if (comphy_index == COMPHY_LANE0 ||
+                   comphy_index == COMPHY_LANE5)
+                       ERROR("COMPHY[%d] mode[%d] is invalid\n",
+                             comphy_index, mode);
+               else
+                       pipe_sel = COMMON_SELECTOR_PIPE_COMPHY_USBH;
+               break;
+
+       case (COMPHY_USB3D_MODE):
+               /* Lane 1 and 4 support USB device, selector value is same */
+               if (comphy_index == COMPHY_LANE1 ||
+                   comphy_index == COMPHY_LANE4)
+                       pipe_sel = COMMON_SELECTOR_PIPE_COMPHY_USBD;
+               else
+                       ERROR("COMPHY[%d] mode[%d] is invalid\n", comphy_index,
+                             mode);
+               break;
+
+       default:
+               ERROR("COMPHY[%d] mode[%d] is invalid\n", comphy_index, mode);
+               break;
+       }
+
+       mmio_write_32(comphy_base + COMMON_SELECTOR_PIPE_REG_OFFSET, reg |
+                     (pipe_sel << shift));
+}
+
+int mvebu_cp110_comphy_is_pll_locked(uint64_t comphy_base, uint8_t comphy_index)
+{
+       uintptr_t sd_ip_addr, addr;
+       uint32_t mask, data;
+       int ret = 0;
+
+       debug_enter();
+
+       sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
+                            comphy_index);
+
+       addr = sd_ip_addr + SD_EXTERNAL_STATUS0_REG;
+       data = SD_EXTERNAL_STATUS0_PLL_TX_MASK &
+               SD_EXTERNAL_STATUS0_PLL_RX_MASK;
+       mask = data;
+       data = polling_with_timeout(addr, data, mask,
+                                   PLL_LOCK_TIMEOUT, REG_32BIT);
+       if (data != 0) {
+               if (data & SD_EXTERNAL_STATUS0_PLL_RX_MASK)
+                       ERROR("RX PLL is not locked\n");
+               if (data & SD_EXTERNAL_STATUS0_PLL_TX_MASK)
+                       ERROR("TX PLL is not locked\n");
+
+               ret = -ETIMEDOUT;
+       }
+
+       debug_exit();
+
+       return ret;
+}
+
+static int mvebu_cp110_comphy_sata_power_on(uint64_t comphy_base,
+                                    uint8_t comphy_index, uint32_t comphy_mode)
+{
+       uintptr_t hpipe_addr, sd_ip_addr, comphy_addr;
+       uint32_t mask, data;
+       int ret = 0;
+
+       debug_enter();
+
+       /* configure phy selector for SATA */
+       mvebu_cp110_comphy_set_phy_selector(comphy_base,
+                                           comphy_index, comphy_mode);
+
+       hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
+                               comphy_index);
+       sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
+                            comphy_index);
+       comphy_addr = COMPHY_ADDR(comphy_base, comphy_index);
+
+       debug(" add hpipe 0x%lx, sd 0x%lx, comphy 0x%lx\n",
+                                          hpipe_addr, sd_ip_addr, comphy_addr);
+       debug("stage: RFU configurations - hard reset comphy\n");
+       /* RFU configurations - hard reset comphy */
+       mask = COMMON_PHY_CFG1_PWR_UP_MASK;
+       data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET;
+       mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK;
+       data |= 0x0 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET;
+       mask |= COMMON_PHY_CFG1_PWR_ON_RESET_MASK;
+       data |= 0x0 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET;
+       mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK;
+       data |= 0x0 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET;
+       reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask);
+
+       /* Set select data  width 40Bit - SATA mode only */
+       reg_set(comphy_addr + COMMON_PHY_CFG6_REG,
+               0x1 << COMMON_PHY_CFG6_IF_40_SEL_OFFSET,
+               COMMON_PHY_CFG6_IF_40_SEL_MASK);
+
+       /* release from hard reset in SD external */
+       mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK;
+       data = 0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
+       data |= 0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET;
+       reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
+
+       /* Wait 1ms - until band gap and ref clock ready */
+       mdelay(1);
+
+       debug("stage: Comphy configuration\n");
+       /* Start comphy Configuration */
+       /* Set reference clock to comes from group 1 - choose 25Mhz */
+       reg_set(hpipe_addr + HPIPE_MISC_REG,
+               0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET,
+               HPIPE_MISC_REFCLK_SEL_MASK);
+       /* Reference frequency select set 1 (for SATA = 25Mhz) */
+       mask = HPIPE_PWR_PLL_REF_FREQ_MASK;
+       data = 0x1 << HPIPE_PWR_PLL_REF_FREQ_OFFSET;
+       /* PHY mode select (set SATA = 0x0 */
+       mask |= HPIPE_PWR_PLL_PHY_MODE_MASK;
+       data |= 0x0 << HPIPE_PWR_PLL_PHY_MODE_OFFSET;
+       reg_set(hpipe_addr + HPIPE_PWR_PLL_REG, data, mask);
+       /* Set max PHY generation setting - 6Gbps */
+       reg_set(hpipe_addr + HPIPE_INTERFACE_REG,
+               0x2 << HPIPE_INTERFACE_GEN_MAX_OFFSET,
+               HPIPE_INTERFACE_GEN_MAX_MASK);
+       /* Set select data  width 40Bit (SEL_BITS[2:0]) */
+       reg_set(hpipe_addr + HPIPE_LOOPBACK_REG,
+               0x2 << HPIPE_LOOPBACK_SEL_OFFSET, HPIPE_LOOPBACK_SEL_MASK);
+
+       debug("stage: Analog parameters from ETP(HW)\n");
+       /* G1 settings */
+       mask = HPIPE_G1_SET_1_G1_RX_SELMUPI_MASK;
+       data = 0x0 << HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET;
+       mask |= HPIPE_G1_SET_1_G1_RX_SELMUPP_MASK;
+       data |= 0x1 << HPIPE_G1_SET_1_G1_RX_SELMUPP_OFFSET;
+       mask |= HPIPE_G1_SET_1_G1_RX_SELMUFI_MASK;
+       data |= 0x0 << HPIPE_G1_SET_1_G1_RX_SELMUFI_OFFSET;
+       mask |= HPIPE_G1_SET_1_G1_RX_SELMUFF_MASK;
+       data |= 0x3 << HPIPE_G1_SET_1_G1_RX_SELMUFF_OFFSET;
+       mask |= HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_MASK;
+       data |= 0x1 << HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_OFFSET;
+       reg_set(hpipe_addr + HPIPE_G1_SET_1_REG, data, mask);
+
+       mask = HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_MASK;
+       data = 0xf << HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_OFFSET;
+       mask |= HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_MASK;
+       data |= 0x2 << HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_OFFSET;
+       mask |= HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_MASK;
+       data |= 0x1 << HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET;
+       mask |= HPIPE_G1_SETTINGS_3_G1_FFE_DEG_RES_LEVEL_MASK;
+       data |= 0x1 << HPIPE_G1_SETTINGS_3_G1_FFE_DEG_RES_LEVEL_OFFSET;
+       mask |= HPIPE_G1_SETTINGS_3_G1_FFE_LOAD_RES_LEVEL_MASK;
+       data |= 0x1 << HPIPE_G1_SETTINGS_3_G1_FFE_LOAD_RES_LEVEL_OFFSET;
+       reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask);
+
+       /* G2 settings */
+       mask = HPIPE_G2_SET_1_G2_RX_SELMUPI_MASK;
+       data = 0x0 << HPIPE_G2_SET_1_G2_RX_SELMUPI_OFFSET;
+       mask |= HPIPE_G2_SET_1_G2_RX_SELMUPP_MASK;
+       data |= 0x1 << HPIPE_G2_SET_1_G2_RX_SELMUPP_OFFSET;
+       mask |= HPIPE_G2_SET_1_G2_RX_SELMUFI_MASK;
+       data |= 0x0 << HPIPE_G2_SET_1_G2_RX_SELMUFI_OFFSET;
+       mask |= HPIPE_G2_SET_1_G2_RX_SELMUFF_MASK;
+       data |= 0x3 << HPIPE_G2_SET_1_G2_RX_SELMUFF_OFFSET;
+       mask |= HPIPE_G2_SET_1_G2_RX_DIGCK_DIV_MASK;
+       data |= 0x1 << HPIPE_G2_SET_1_G2_RX_DIGCK_DIV_OFFSET;
+       reg_set(hpipe_addr + HPIPE_G2_SET_1_REG, data, mask);
+
+       /* G3 settings */
+       mask = HPIPE_G3_SET_1_G3_RX_SELMUPI_MASK;
+       data = 0x2 << HPIPE_G3_SET_1_G3_RX_SELMUPI_OFFSET;
+       mask |= HPIPE_G3_SET_1_G3_RX_SELMUPF_MASK;
+       data |= 0x2 << HPIPE_G3_SET_1_G3_RX_SELMUPF_OFFSET;
+       mask |= HPIPE_G3_SET_1_G3_RX_SELMUFI_MASK;
+       data |= 0x3 << HPIPE_G3_SET_1_G3_RX_SELMUFI_OFFSET;
+       mask |= HPIPE_G3_SET_1_G3_RX_SELMUFF_MASK;
+       data |= 0x3 << HPIPE_G3_SET_1_G3_RX_SELMUFF_OFFSET;
+       mask |= HPIPE_G3_SET_1_G3_RX_DFE_EN_MASK;
+       data |= 0x1 << HPIPE_G3_SET_1_G3_RX_DFE_EN_OFFSET;
+       mask |= HPIPE_G3_SET_1_G3_RX_DIGCK_DIV_MASK;
+       data |= 0x2 << HPIPE_G3_SET_1_G3_RX_DIGCK_DIV_OFFSET;
+       mask |= HPIPE_G3_SET_1_G3_SAMPLER_INPAIRX2_EN_MASK;
+       data |= 0x0 << HPIPE_G3_SET_1_G3_SAMPLER_INPAIRX2_EN_OFFSET;
+       reg_set(hpipe_addr + HPIPE_G3_SET_1_REG, data, mask);
+
+       /* DTL Control */
+       mask = HPIPE_PWR_CTR_DTL_SQ_DET_EN_MASK;
+       data = 0x1 << HPIPE_PWR_CTR_DTL_SQ_DET_EN_OFFSET;
+       mask |= HPIPE_PWR_CTR_DTL_SQ_PLOOP_EN_MASK;
+       data |= 0x1 << HPIPE_PWR_CTR_DTL_SQ_PLOOP_EN_OFFSET;
+       mask |= HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK;
+       data |= 0x1 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET;
+       mask |= HPIPE_PWR_CTR_DTL_CLAMPING_SEL_MASK;
+       data |= 0x1 << HPIPE_PWR_CTR_DTL_CLAMPING_SEL_OFFSET;
+       mask |= HPIPE_PWR_CTR_DTL_INTPCLK_DIV_FORCE_MASK;
+       data |= 0x1 << HPIPE_PWR_CTR_DTL_INTPCLK_DIV_FORCE_OFFSET;
+       mask |= HPIPE_PWR_CTR_DTL_CLK_MODE_MASK;
+       data |= 0x1 << HPIPE_PWR_CTR_DTL_CLK_MODE_OFFSET;
+       mask |= HPIPE_PWR_CTR_DTL_CLK_MODE_FORCE_MASK;
+       data |= 0x1 << HPIPE_PWR_CTR_DTL_CLK_MODE_FORCE_OFFSET;
+       reg_set(hpipe_addr + HPIPE_PWR_CTR_DTL_REG, data, mask);
+
+       /* Trigger sampler enable pulse */
+       mask = HPIPE_SMAPLER_MASK;
+       data = 0x1 << HPIPE_SMAPLER_OFFSET;
+       reg_set(hpipe_addr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, data, mask);
+       mask = HPIPE_SMAPLER_MASK;
+       data = 0x0 << HPIPE_SMAPLER_OFFSET;
+       reg_set(hpipe_addr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, data, mask);
+
+       /* VDD Calibration Control 3 */
+       mask = HPIPE_EXT_SELLV_RXSAMPL_MASK;
+       data = 0x10 << HPIPE_EXT_SELLV_RXSAMPL_OFFSET;
+       reg_set(hpipe_addr + HPIPE_VDD_CAL_CTRL_REG, data, mask);
+
+       /* DFE Resolution Control */
+       mask = HPIPE_DFE_RES_FORCE_MASK;
+       data = 0x1 << HPIPE_DFE_RES_FORCE_OFFSET;
+       reg_set(hpipe_addr + HPIPE_DFE_REG0, data, mask);
+
+       /* DFE F3-F5 Coefficient Control */
+       mask = HPIPE_DFE_F3_F5_DFE_EN_MASK;
+       data = 0x0 << HPIPE_DFE_F3_F5_DFE_EN_OFFSET;
+       mask |= HPIPE_DFE_F3_F5_DFE_CTRL_MASK;
+       data = 0x0 << HPIPE_DFE_F3_F5_DFE_CTRL_OFFSET;
+       reg_set(hpipe_addr + HPIPE_DFE_F3_F5_REG, data, mask);
+
+       /* G3 Setting 3 */
+       mask = HPIPE_G3_FFE_CAP_SEL_MASK;
+       data = 0xf << HPIPE_G3_FFE_CAP_SEL_OFFSET;
+       mask |= HPIPE_G3_FFE_RES_SEL_MASK;
+       data |= 0x4 << HPIPE_G3_FFE_RES_SEL_OFFSET;
+       mask |= HPIPE_G3_FFE_SETTING_FORCE_MASK;
+       data |= 0x1 << HPIPE_G3_FFE_SETTING_FORCE_OFFSET;
+       mask |= HPIPE_G3_FFE_DEG_RES_LEVEL_MASK;
+       data |= 0x1 << HPIPE_G3_FFE_DEG_RES_LEVEL_OFFSET;
+       mask |= HPIPE_G3_FFE_LOAD_RES_LEVEL_MASK;
+       data |= 0x3 << HPIPE_G3_FFE_LOAD_RES_LEVEL_OFFSET;
+       reg_set(hpipe_addr + HPIPE_G3_SETTING_3_REG, data, mask);
+
+       /* G3 Setting 4 */
+       mask = HPIPE_G3_DFE_RES_MASK;
+       data = 0x1 << HPIPE_G3_DFE_RES_OFFSET;
+       reg_set(hpipe_addr + HPIPE_G3_SETTING_4_REG, data, mask);
+
+       /* Offset Phase Control */
+       mask = HPIPE_OS_PH_OFFSET_MASK;
+       data = 0x61 << HPIPE_OS_PH_OFFSET_OFFSET;
+       mask |= HPIPE_OS_PH_OFFSET_FORCE_MASK;
+       data |= 0x1 << HPIPE_OS_PH_OFFSET_FORCE_OFFSET;
+       mask |= HPIPE_OS_PH_VALID_MASK;
+       data |= 0x0 << HPIPE_OS_PH_VALID_OFFSET;
+       reg_set(hpipe_addr + HPIPE_PHASE_CONTROL_REG, data, mask);
+       mask = HPIPE_OS_PH_VALID_MASK;
+       data = 0x1 << HPIPE_OS_PH_VALID_OFFSET;
+       reg_set(hpipe_addr + HPIPE_PHASE_CONTROL_REG, data, mask);
+       mask = HPIPE_OS_PH_VALID_MASK;
+       data = 0x0 << HPIPE_OS_PH_VALID_OFFSET;
+       reg_set(hpipe_addr + HPIPE_PHASE_CONTROL_REG, data, mask);
+
+       /* Set G1 TX amplitude and TX post emphasis value */
+       mask = HPIPE_G1_SET_0_G1_TX_AMP_MASK;
+       data = 0x8 << HPIPE_G1_SET_0_G1_TX_AMP_OFFSET;
+       mask |= HPIPE_G1_SET_0_G1_TX_AMP_ADJ_MASK;
+       data |= 0x1 << HPIPE_G1_SET_0_G1_TX_AMP_ADJ_OFFSET;
+       mask |= HPIPE_G1_SET_0_G1_TX_EMPH1_MASK;
+       data |= 0x1 << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET;
+       mask |= HPIPE_G1_SET_0_G1_TX_EMPH1_EN_MASK;
+       data |= 0x1 << HPIPE_G1_SET_0_G1_TX_EMPH1_EN_OFFSET;
+       reg_set(hpipe_addr + HPIPE_G1_SET_0_REG, data, mask);
+
+       /* Set G2 TX amplitude and TX post emphasis value */
+       mask = HPIPE_G2_SET_0_G2_TX_AMP_MASK;
+       data = 0xa << HPIPE_G2_SET_0_G2_TX_AMP_OFFSET;
+       mask |= HPIPE_G2_SET_0_G2_TX_AMP_ADJ_MASK;
+       data |= 0x1 << HPIPE_G2_SET_0_G2_TX_AMP_ADJ_OFFSET;
+       mask |= HPIPE_G2_SET_0_G2_TX_EMPH1_MASK;
+       data |= 0x2 << HPIPE_G2_SET_0_G2_TX_EMPH1_OFFSET;
+       mask |= HPIPE_G2_SET_0_G2_TX_EMPH1_EN_MASK;
+       data |= 0x1 << HPIPE_G2_SET_0_G2_TX_EMPH1_EN_OFFSET;
+       reg_set(hpipe_addr + HPIPE_G2_SET_0_REG, data, mask);
+
+       /* Set G3 TX amplitude and TX post emphasis value */
+       mask = HPIPE_G3_SET_0_G3_TX_AMP_MASK;
+       data = 0x1e << HPIPE_G3_SET_0_G3_TX_AMP_OFFSET;
+       mask |= HPIPE_G3_SET_0_G3_TX_AMP_ADJ_MASK;
+       data |= 0x1 << HPIPE_G3_SET_0_G3_TX_AMP_ADJ_OFFSET;
+       mask |= HPIPE_G3_SET_0_G3_TX_EMPH1_MASK;
+       data |= 0xe << HPIPE_G3_SET_0_G3_TX_EMPH1_OFFSET;
+       mask |= HPIPE_G3_SET_0_G3_TX_EMPH1_EN_MASK;
+       data |= 0x1 << HPIPE_G3_SET_0_G3_TX_EMPH1_EN_OFFSET;
+       mask |= HPIPE_G3_SET_0_G3_TX_SLEW_RATE_SEL_MASK;
+       data |= 0x4 << HPIPE_G3_SET_0_G3_TX_SLEW_RATE_SEL_OFFSET;
+       mask |= HPIPE_G3_SET_0_G3_TX_SLEW_CTRL_EN_MASK;
+       data |= 0x0 << HPIPE_G3_SET_0_G3_TX_SLEW_CTRL_EN_OFFSET;
+       reg_set(hpipe_addr + HPIPE_G3_SET_0_REG, data, mask);
+
+       /* SERDES External Configuration 2 register */
+       mask = SD_EXTERNAL_CONFIG2_SSC_ENABLE_MASK;
+       data = 0x1 << SD_EXTERNAL_CONFIG2_SSC_ENABLE_OFFSET;
+       reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG2_REG, data, mask);
+
+       /* DFE reset sequence */
+       reg_set(hpipe_addr + HPIPE_PWR_CTR_REG,
+               0x1 << HPIPE_PWR_CTR_RST_DFE_OFFSET,
+               HPIPE_PWR_CTR_RST_DFE_MASK);
+       reg_set(hpipe_addr + HPIPE_PWR_CTR_REG,
+               0x0 << HPIPE_PWR_CTR_RST_DFE_OFFSET,
+               HPIPE_PWR_CTR_RST_DFE_MASK);
+       /* SW reset for interrupt logic */
+       reg_set(hpipe_addr + HPIPE_PWR_CTR_REG,
+               0x1 << HPIPE_PWR_CTR_SFT_RST_OFFSET,
+               HPIPE_PWR_CTR_SFT_RST_MASK);
+       reg_set(hpipe_addr + HPIPE_PWR_CTR_REG,
+               0x0 << HPIPE_PWR_CTR_SFT_RST_OFFSET,
+               HPIPE_PWR_CTR_SFT_RST_MASK);
+
+       debug_exit();
+
+       return ret;
+}
+
+static int mvebu_cp110_comphy_sgmii_power_on(uint64_t comphy_base,
+                                    uint8_t comphy_index, uint32_t comphy_mode)
+{
+       uintptr_t hpipe_addr, sd_ip_addr, comphy_addr, addr;
+       uint32_t mask, data, sgmii_speed = COMPHY_GET_SPEED(comphy_mode);
+       int ret = 0;
+
+       debug_enter();
+
+       hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
+                               comphy_index);
+       sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
+                            comphy_index);
+       comphy_addr = COMPHY_ADDR(comphy_base, comphy_index);
+
+       /* configure phy selector for SGMII */
+       mvebu_cp110_comphy_set_phy_selector(comphy_base, comphy_index,
+                                           comphy_mode);
+
+       /* Confiugre the lane */
+       debug("stage: RFU configurations - hard reset comphy\n");
+       /* RFU configurations - hard reset comphy */
+       mask = COMMON_PHY_CFG1_PWR_UP_MASK;
+       data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET;
+       mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK;
+       data |= 0x0 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET;
+       reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask);
+
+       /* Select Baud Rate of Comphy And PD_PLL/Tx/Rx */
+       mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK;
+       data = 0x0 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_MASK;
+       mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_MASK;
+
+       if (sgmii_speed == COMPHY_SPEED_1_25G) {
+               /* SGMII 1G, SerDes speed 1.25G */
+               data |= 0x6 << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET;
+               data |= 0x6 << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET;
+       } else if (sgmii_speed == COMPHY_SPEED_3_125G) {
+               /* HS SGMII (2.5G), SerDes speed 3.125G */
+               data |= 0x8 << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET;
+               data |= 0x8 << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET;
+       } else {
+               /* Other rates are not supported */
+               ERROR("unsupported SGMII speed on comphy%d\n", comphy_index);
+               return -EINVAL;
+       }
+
+       mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK;
+       data |= 0 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK;
+       data |= 0 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_MASK;
+       data |= 1 << SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_OFFSET;
+       reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG0_REG, data, mask);
+
+       /* Set hard reset */
+       mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK;
+       data = 0x0 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
+       data |= 0x0 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK;
+       data |= 0x0 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET;
+       reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
+
+       /* Release hard reset */
+       mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK;
+       data = 0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
+       data |= 0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET;
+       reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
+
+       /* Wait 1ms - until band gap and ref clock ready */
+       mdelay(1);
+
+       /* Make sure that 40 data bits is disabled
+        * This bit is not cleared by reset
+        */
+       mask = COMMON_PHY_CFG6_IF_40_SEL_MASK;
+       data = 0 << COMMON_PHY_CFG6_IF_40_SEL_OFFSET;
+       reg_set(comphy_addr + COMMON_PHY_CFG6_REG, data, mask);
+
+       /* Start comphy Configuration */
+       debug("stage: Comphy configuration\n");
+       /* set reference clock */
+       mask = HPIPE_MISC_REFCLK_SEL_MASK;
+       data = 0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET;
+       reg_set(hpipe_addr + HPIPE_MISC_REG, data, mask);
+       /* Power and PLL Control */
+       mask = HPIPE_PWR_PLL_REF_FREQ_MASK;
+       data = 0x1 << HPIPE_PWR_PLL_REF_FREQ_OFFSET;
+       mask |= HPIPE_PWR_PLL_PHY_MODE_MASK;
+       data |= 0x4 << HPIPE_PWR_PLL_PHY_MODE_OFFSET;
+       reg_set(hpipe_addr + HPIPE_PWR_PLL_REG, data, mask);
+       /* Loopback register */
+       mask = HPIPE_LOOPBACK_SEL_MASK;
+       data = 0x1 << HPIPE_LOOPBACK_SEL_OFFSET;
+       reg_set(hpipe_addr + HPIPE_LOOPBACK_REG, data, mask);
+       /* rx control 1 */
+       mask = HPIPE_RX_CONTROL_1_RXCLK2X_SEL_MASK;
+       data = 0x1 << HPIPE_RX_CONTROL_1_RXCLK2X_SEL_OFFSET;
+       mask |= HPIPE_RX_CONTROL_1_CLK8T_EN_MASK;
+       data |= 0x0 << HPIPE_RX_CONTROL_1_CLK8T_EN_OFFSET;
+       reg_set(hpipe_addr + HPIPE_RX_CONTROL_1_REG, data, mask);
+       /* DTL Control */
+       mask = HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK;
+       data = 0x0 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET;
+       reg_set(hpipe_addr + HPIPE_PWR_CTR_DTL_REG, data, mask);
+
+       /* Set analog parameters from ETP(HW) - for now use the default datas */
+       debug("stage: Analog parameters from ETP(HW)\n");
+
+       reg_set(hpipe_addr + HPIPE_G1_SET_0_REG,
+               0x1 << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET,
+               HPIPE_G1_SET_0_G1_TX_EMPH1_MASK);
+
+       debug("stage: RFU configurations- Power Up PLL,Tx,Rx\n");
+       /* SERDES External Configuration */
+       mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK;
+       data = 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK;
+       data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK;
+       data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET;
+       reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG0_REG, data, mask);
+
+       ret = mvebu_cp110_comphy_is_pll_locked(comphy_base, comphy_index);
+       if (ret)
+               return ret;
+
+       /* RX init */
+       mask = SD_EXTERNAL_CONFIG1_RX_INIT_MASK;
+       data = 0x1 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET;
+       reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
+
+       /* check that RX init done */
+       addr = sd_ip_addr + SD_EXTERNAL_STATUS0_REG;
+       data = SD_EXTERNAL_STATUS0_RX_INIT_MASK;
+       mask = data;
+       data = polling_with_timeout(addr, data, mask, 100, REG_32BIT);
+       if (data != 0) {
+               ERROR("RX init failed\n");
+               ret = -ETIMEDOUT;
+       }
+
+       debug("stage: RF Reset\n");
+       /* RF Reset */
+       mask = SD_EXTERNAL_CONFIG1_RX_INIT_MASK;
+       data = 0x0 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK;
+       data |= 0x1 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET;
+       reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
+
+       debug_exit();
+
+       return ret;
+}
+
+static int mvebu_cp110_comphy_xfi_power_on(uint64_t comphy_base,
+                                          uint8_t comphy_index,
+                                          uint32_t comphy_mode)
+{
+       uintptr_t hpipe_addr, sd_ip_addr, comphy_addr, addr;
+       uint32_t mask, data, speed = COMPHY_GET_SPEED(comphy_mode);
+       int ret = 0;
+
+       debug_enter();
+
+       if ((speed != COMPHY_SPEED_5_15625G) &&
+            (speed != COMPHY_SPEED_10_3125G) &&
+            (speed != COMPHY_SPEED_DEFAULT)) {
+               ERROR("comphy:%d: unsupported sfi/xfi speed\n", comphy_index);
+               return -EINVAL;
+       }
+
+       hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
+                               comphy_index);
+       sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
+                            comphy_index);
+       comphy_addr = COMPHY_ADDR(comphy_base, comphy_index);
+
+       /* configure phy selector for XFI/SFI */
+       mvebu_cp110_comphy_set_phy_selector(comphy_base, comphy_index,
+                                           comphy_mode);
+
+       debug("stage: RFU configurations - hard reset comphy\n");
+       /* RFU configurations - hard reset comphy */
+       mask = COMMON_PHY_CFG1_PWR_UP_MASK;
+       data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET;
+       mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK;
+       data |= 0x0 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET;
+       reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask);
+
+       /* Make sure that 40 data bits is disabled
+        * This bit is not cleared by reset
+        */
+       mask = COMMON_PHY_CFG6_IF_40_SEL_MASK;
+       data = 0 << COMMON_PHY_CFG6_IF_40_SEL_OFFSET;
+       reg_set(comphy_addr + COMMON_PHY_CFG6_REG, data, mask);
+
+       /* Select Baud Rate of Comphy And PD_PLL/Tx/Rx */
+       mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK;
+       data = 0x0 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_MASK;
+       data |= 0xE << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_MASK;
+       data |= 0xE << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK;
+       data |= 0 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK;
+       data |= 0 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_MASK;
+       data |= 0 << SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_OFFSET;
+       reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG0_REG, data, mask);
+
+       /* release from hard reset */
+       mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK;
+       data = 0x0 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
+       data |= 0x0 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK;
+       data |= 0x0 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET;
+       reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
+
+       mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK;
+       data = 0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
+       data |= 0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET;
+       reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
+
+       /* Wait 1ms - until band gap and ref clock ready */
+       mdelay(1);
+
+       /* Start comphy Configuration */
+       debug("stage: Comphy configuration\n");
+       /* set reference clock */
+       mask = HPIPE_MISC_ICP_FORCE_MASK;
+       data = (speed == COMPHY_SPEED_5_15625G) ?
+               (0x0 << HPIPE_MISC_ICP_FORCE_OFFSET) :
+               (0x1 << HPIPE_MISC_ICP_FORCE_OFFSET);
+       mask |= HPIPE_MISC_REFCLK_SEL_MASK;
+       data |= 0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET;
+       reg_set(hpipe_addr + HPIPE_MISC_REG, data, mask);
+       /* Power and PLL Control */
+       mask = HPIPE_PWR_PLL_REF_FREQ_MASK;
+       data = 0x1 << HPIPE_PWR_PLL_REF_FREQ_OFFSET;
+       mask |= HPIPE_PWR_PLL_PHY_MODE_MASK;
+       data |= 0x4 << HPIPE_PWR_PLL_PHY_MODE_OFFSET;
+       reg_set(hpipe_addr + HPIPE_PWR_PLL_REG, data, mask);
+       /* Loopback register */
+       mask = HPIPE_LOOPBACK_SEL_MASK;
+       data = 0x1 << HPIPE_LOOPBACK_SEL_OFFSET;
+       reg_set(hpipe_addr + HPIPE_LOOPBACK_REG, data, mask);
+       /* rx control 1 */
+       mask = HPIPE_RX_CONTROL_1_RXCLK2X_SEL_MASK;
+       data = 0x1 << HPIPE_RX_CONTROL_1_RXCLK2X_SEL_OFFSET;
+       mask |= HPIPE_RX_CONTROL_1_CLK8T_EN_MASK;
+       data |= 0x1 << HPIPE_RX_CONTROL_1_CLK8T_EN_OFFSET;
+       reg_set(hpipe_addr + HPIPE_RX_CONTROL_1_REG, data, mask);
+       /* DTL Control */
+       mask = HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK;
+       data = 0x1 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET;
+       reg_set(hpipe_addr + HPIPE_PWR_CTR_DTL_REG, data, mask);
+
+       /* Transmitter/Receiver Speed Divider Force */
+       if (speed == COMPHY_SPEED_5_15625G) {
+               mask = HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_MASK;
+               data = 1 << HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_OFFSET;
+               mask |= HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_FORCE_MASK;
+               data |= 1 << HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_FORCE_OFFSET;
+               mask |= HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_MASK;
+               data |= 1 << HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_OFFSET;
+               mask |= HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_MASK;
+               data |= 1 << HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_OFFSET;
+       } else {
+               mask = HPIPE_TXDIGCK_DIV_FORCE_MASK;
+               data = 0x1 << HPIPE_TXDIGCK_DIV_FORCE_OFFSET;
+       }
+       reg_set(hpipe_addr + HPIPE_SPD_DIV_FORCE_REG, data, mask);
+
+       /* Set analog parameters from ETP(HW) */
+       debug("stage: Analog parameters from ETP(HW)\n");
+       /* SERDES External Configuration 2 */
+       mask = SD_EXTERNAL_CONFIG2_PIN_DFE_EN_MASK;
+       data = 0x1 << SD_EXTERNAL_CONFIG2_PIN_DFE_EN_OFFSET;
+       reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG2_REG, data, mask);
+       /* 0x7-DFE Resolution control */
+       mask = HPIPE_DFE_RES_FORCE_MASK;
+       data = 0x1 << HPIPE_DFE_RES_FORCE_OFFSET;
+       reg_set(hpipe_addr + HPIPE_DFE_REG0, data, mask);
+       /* 0xd-G1_Setting_0 */
+       if (speed == COMPHY_SPEED_5_15625G) {
+               mask = HPIPE_G1_SET_0_G1_TX_EMPH1_MASK;
+               data = 0x6 << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET;
+       } else {
+               mask = HPIPE_G1_SET_0_G1_TX_AMP_MASK;
+               data = 0x1c << HPIPE_G1_SET_0_G1_TX_AMP_OFFSET;
+               mask |= HPIPE_G1_SET_0_G1_TX_EMPH1_MASK;
+               data |= 0xe << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET;
+       }
+       reg_set(hpipe_addr + HPIPE_G1_SET_0_REG, data, mask);
+       /* Genration 1 setting 2 (G1_Setting_2) */
+       mask = HPIPE_G1_SET_2_G1_TX_EMPH0_MASK;
+       data = 0x0 << HPIPE_G1_SET_2_G1_TX_EMPH0_OFFSET;
+       mask |= HPIPE_G1_SET_2_G1_TX_EMPH0_EN_MASK;
+       data |= 0x1 << HPIPE_G1_SET_2_G1_TX_EMPH0_EN_OFFSET;
+       reg_set(hpipe_addr + HPIPE_G1_SET_2_REG, data, mask);
+       /* Transmitter Slew Rate Control register (tx_reg1) */
+       mask = HPIPE_TX_REG1_TX_EMPH_RES_MASK;
+       data = 0x3 << HPIPE_TX_REG1_TX_EMPH_RES_OFFSET;
+       mask |= HPIPE_TX_REG1_SLC_EN_MASK;
+       data |= 0x3f << HPIPE_TX_REG1_SLC_EN_OFFSET;
+       reg_set(hpipe_addr + HPIPE_TX_REG1_REG, data, mask);
+       /* Impedance Calibration Control register (cal_reg1) */
+       mask = HPIPE_CAL_REG_1_EXT_TXIMP_MASK;
+       data = 0xe << HPIPE_CAL_REG_1_EXT_TXIMP_OFFSET;
+       mask |= HPIPE_CAL_REG_1_EXT_TXIMP_EN_MASK;
+       data |= 0x1 << HPIPE_CAL_REG_1_EXT_TXIMP_EN_OFFSET;
+       reg_set(hpipe_addr + HPIPE_CAL_REG1_REG, data, mask);
+       /* Generation 1 Setting 5 (g1_setting_5) */
+       mask = HPIPE_G1_SETTING_5_G1_ICP_MASK;
+       data = 0 << HPIPE_CAL_REG_1_EXT_TXIMP_OFFSET;
+       reg_set(hpipe_addr + HPIPE_G1_SETTING_5_REG, data, mask);
+
+       /* 0xE-G1_Setting_1 */
+       mask = HPIPE_G1_SET_1_G1_RX_DFE_EN_MASK;
+       data = 0x1 << HPIPE_G1_SET_1_G1_RX_DFE_EN_OFFSET;
+       if (speed == COMPHY_SPEED_5_15625G) {
+               mask |= HPIPE_G1_SET_1_G1_RX_SELMUPI_MASK;
+               data |= 0x1 << HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET;
+               mask |= HPIPE_G1_SET_1_G1_RX_SELMUPP_MASK;
+               data |= 0x1 << HPIPE_G1_SET_1_G1_RX_SELMUPP_OFFSET;
+       } else {
+               mask |= HPIPE_G1_SET_1_G1_RX_SELMUPI_MASK;
+               data |= 0x2 << HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET;
+               mask |= HPIPE_G1_SET_1_G1_RX_SELMUPP_MASK;
+               data |= 0x2 << HPIPE_G1_SET_1_G1_RX_SELMUPP_OFFSET;
+               mask |= HPIPE_G1_SET_1_G1_RX_SELMUFI_MASK;
+               data |= 0x0 << HPIPE_G1_SET_1_G1_RX_SELMUFI_OFFSET;
+               mask |= HPIPE_G1_SET_1_G1_RX_SELMUFF_MASK;
+               data |= 0x1 << HPIPE_G1_SET_1_G1_RX_SELMUFF_OFFSET;
+               mask |= HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_MASK;
+               data |= 0x3 << HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_OFFSET;
+       }
+       reg_set(hpipe_addr + HPIPE_G1_SET_1_REG, data, mask);
+
+       /* 0xA-DFE_Reg3 */
+       mask = HPIPE_DFE_F3_F5_DFE_EN_MASK;
+       data = 0x0 << HPIPE_DFE_F3_F5_DFE_EN_OFFSET;
+       mask |= HPIPE_DFE_F3_F5_DFE_CTRL_MASK;
+       data |= 0x0 << HPIPE_DFE_F3_F5_DFE_CTRL_OFFSET;
+       reg_set(hpipe_addr + HPIPE_DFE_F3_F5_REG, data, mask);
+
+       /* 0x111-G1_Setting_4 */
+       mask = HPIPE_G1_SETTINGS_4_G1_DFE_RES_MASK;
+       data = 0x1 << HPIPE_G1_SETTINGS_4_G1_DFE_RES_OFFSET;
+       reg_set(hpipe_addr + HPIPE_G1_SETTINGS_4_REG, data, mask);
+       /* Genration 1 setting 3 (G1_Setting_3) */
+       mask = HPIPE_G1_SETTINGS_3_G1_FBCK_SEL_MASK;
+       data = 0x1 << HPIPE_G1_SETTINGS_3_G1_FBCK_SEL_OFFSET;
+       if (speed == COMPHY_SPEED_5_15625G) {
+               /* Force FFE (Feed Forward Equalization) to 5G */
+               mask |= HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_MASK;
+               data |= 0xf << HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_OFFSET;
+               mask |= HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_MASK;
+               data |= 0x4 << HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_OFFSET;
+               mask |= HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_MASK;
+               data |= 0x1 << HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET;
+       }
+       reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask);
+
+       /* Connfigure RX training timer */
+       mask = HPIPE_RX_TRAIN_TIMER_MASK;
+       data = 0x13 << HPIPE_RX_TRAIN_TIMER_OFFSET;
+       reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_5_REG, data, mask);
+
+       /* Enable TX train peak to peak hold */
+       mask = HPIPE_TX_TRAIN_P2P_HOLD_MASK;
+       data = 0x1 << HPIPE_TX_TRAIN_P2P_HOLD_OFFSET;
+       reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_0_REG, data, mask);
+
+       /* Configure TX preset index */
+       mask = HPIPE_TX_PRESET_INDEX_MASK;
+       data = 0x2 << HPIPE_TX_PRESET_INDEX_OFFSET;
+       reg_set(hpipe_addr + HPIPE_TX_PRESET_INDEX_REG, data, mask);
+
+       /* Disable pattern lock lost timeout */
+       mask = HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_MASK;
+       data = 0x0 << HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_OFFSET;
+       reg_set(hpipe_addr + HPIPE_FRAME_DETECT_CTRL_3_REG, data, mask);
+
+       /* Configure TX training pattern and TX training 16bit auto */
+       mask = HPIPE_TX_TRAIN_16BIT_AUTO_EN_MASK;
+       data = 0x1 << HPIPE_TX_TRAIN_16BIT_AUTO_EN_OFFSET;
+       mask |= HPIPE_TX_TRAIN_PAT_SEL_MASK;
+       data |= 0x1 << HPIPE_TX_TRAIN_PAT_SEL_OFFSET;
+       reg_set(hpipe_addr + HPIPE_TX_TRAIN_REG, data, mask);
+
+       /* Configure Training patten number */
+       mask = HPIPE_TRAIN_PAT_NUM_MASK;
+       data = 0x88 << HPIPE_TRAIN_PAT_NUM_OFFSET;
+       reg_set(hpipe_addr + HPIPE_FRAME_DETECT_CTRL_0_REG, data, mask);
+
+       /* Configure differencial manchester encoter to ethernet mode */
+       mask = HPIPE_DME_ETHERNET_MODE_MASK;
+       data = 0x1 << HPIPE_DME_ETHERNET_MODE_OFFSET;
+       reg_set(hpipe_addr + HPIPE_DME_REG, data, mask);
+
+       /* Configure VDD Continuous Calibration */
+       mask = HPIPE_CAL_VDD_CONT_MODE_MASK;
+       data = 0x1 << HPIPE_CAL_VDD_CONT_MODE_OFFSET;
+       reg_set(hpipe_addr + HPIPE_VDD_CAL_0_REG, data, mask);
+
+       /* Trigger sampler enable pulse (by toggleing the bit) */
+       mask = HPIPE_RX_SAMPLER_OS_GAIN_MASK;
+       data = 0x3 << HPIPE_RX_SAMPLER_OS_GAIN_OFFSET;
+       mask |= HPIPE_SMAPLER_MASK;
+       data |= 0x1 << HPIPE_SMAPLER_OFFSET;
+       reg_set(hpipe_addr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, data, mask);
+       mask = HPIPE_SMAPLER_MASK;
+       data = 0x0 << HPIPE_SMAPLER_OFFSET;
+       reg_set(hpipe_addr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, data, mask);
+
+       /* Set External RX Regulator Control */
+       mask = HPIPE_EXT_SELLV_RXSAMPL_MASK;
+       data = 0x1A << HPIPE_EXT_SELLV_RXSAMPL_OFFSET;
+       reg_set(hpipe_addr + HPIPE_VDD_CAL_CTRL_REG, data, mask);
+
+       debug("stage: RFU configurations- Power Up PLL,Tx,Rx\n");
+       /* SERDES External Configuration */
+       mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK;
+       data = 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK;
+       data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK;
+       data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET;
+       reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG0_REG, data, mask);
+
+       /* check PLL rx & tx ready */
+       addr = sd_ip_addr + SD_EXTERNAL_STATUS0_REG;
+       data = SD_EXTERNAL_STATUS0_PLL_RX_MASK |
+              SD_EXTERNAL_STATUS0_PLL_TX_MASK;
+       mask = data;
+       data = polling_with_timeout(addr, data, mask,
+                                   PLL_LOCK_TIMEOUT, REG_32BIT);
+       if (data != 0) {
+               if (data & SD_EXTERNAL_STATUS0_PLL_RX_MASK)
+                       ERROR("RX PLL is not locked\n");
+               if (data & SD_EXTERNAL_STATUS0_PLL_TX_MASK)
+                       ERROR("TX PLL is not locked\n");
+
+               ret = -ETIMEDOUT;
+       }
+
+       /* RX init */
+       mask = SD_EXTERNAL_CONFIG1_RX_INIT_MASK;
+       data = 0x1 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET;
+       reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
+
+       /* check that RX init done */
+       addr = sd_ip_addr + SD_EXTERNAL_STATUS0_REG;
+       data = SD_EXTERNAL_STATUS0_RX_INIT_MASK;
+       mask = data;
+       data = polling_with_timeout(addr, data, mask, 100, REG_32BIT);
+       if (data != 0) {
+               ERROR("RX init failed\n");
+               ret = -ETIMEDOUT;
+       }
+
+       debug("stage: RF Reset\n");
+       /* RF Reset */
+       mask =  SD_EXTERNAL_CONFIG1_RX_INIT_MASK;
+       data = 0x0 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK;
+       data |= 0x1 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET;
+       reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
+
+       debug_exit();
+
+       return ret;
+}
+
+static int mvebu_cp110_comphy_pcie_power_on(uint64_t comphy_base,
+                                    uint8_t comphy_index, uint32_t comphy_mode)
+{
+       int ret = 0;
+       uint32_t reg, mask, data, pcie_width;
+       uint32_t clk_dir;
+       uintptr_t hpipe_addr, comphy_addr, addr;
+       _Bool clk_src = COMPHY_GET_CLK_SRC(comphy_mode);
+
+       hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
+                               comphy_index);
+       comphy_addr = COMPHY_ADDR(comphy_base, comphy_index);
+       pcie_width = COMPHY_GET_PCIE_WIDTH(comphy_mode);
+
+       debug_enter();
+
+       spin_lock(&cp110_mac_reset_lock);
+
+       reg = mmio_read_32(SYS_CTRL_FROM_COMPHY_ADDR(comphy_base) +
+                                               SYS_CTRL_UINIT_SOFT_RESET_REG);
+       switch (comphy_index) {
+       case COMPHY_LANE0:
+               reg |= PCIE_MAC_RESET_MASK_PORT0;
+               break;
+       case COMPHY_LANE4:
+               reg |= PCIE_MAC_RESET_MASK_PORT1;
+               break;
+       case COMPHY_LANE5:
+               reg |= PCIE_MAC_RESET_MASK_PORT2;
+               break;
+       }
+
+       mmio_write_32(SYS_CTRL_FROM_COMPHY_ADDR(comphy_base) +
+                                           SYS_CTRL_UINIT_SOFT_RESET_REG, reg);
+       spin_unlock(&cp110_mac_reset_lock);
+
+       /* Configure PIPE selector for PCIE */
+       mvebu_cp110_comphy_set_pipe_selector(comphy_base, comphy_index,
+                                            comphy_mode);
+
+       /*
+        * Read SAR (Sample-At-Reset) configuration for the PCIe clock
+        * direction.
+        *
+        * SerDes Lane 4/5 got the PCIe ref-clock #1,
+        * and SerDes Lane 0 got PCIe ref-clock #0
+        */
+       reg = mmio_read_32(DFX_FROM_COMPHY_ADDR(comphy_base) +
+                          SAR_STATUS_0_REG);
+       if (comphy_index == COMPHY_LANE4 || comphy_index == COMPHY_LANE5)
+               clk_dir = (reg & SAR_RST_PCIE1_CLOCK_CONFIG_CP1_MASK) >>
+                                         SAR_RST_PCIE1_CLOCK_CONFIG_CP1_OFFSET;
+       else
+               clk_dir = (reg & SAR_RST_PCIE0_CLOCK_CONFIG_CP1_MASK) >>
+                                         SAR_RST_PCIE0_CLOCK_CONFIG_CP1_OFFSET;
+
+       debug("On lane %d\n", comphy_index);
+       debug("PCIe clock direction = %x\n", clk_dir);
+       debug("PCIe Width = %d\n", pcie_width);
+
+       /* enable PCIe X4 and X2 */
+       if (comphy_index == COMPHY_LANE0) {
+               if (pcie_width == PCIE_LNK_X4) {
+                       data = 0x1 << COMMON_PHY_SD_CTRL1_PCIE_X4_EN_OFFSET;
+                       mask = COMMON_PHY_SD_CTRL1_PCIE_X4_EN_MASK;
+                       reg_set(comphy_base + COMMON_PHY_SD_CTRL1,
+                               data, mask);
+               } else if (pcie_width == PCIE_LNK_X2) {
+                       data = 0x1 << COMMON_PHY_SD_CTRL1_PCIE_X2_EN_OFFSET;
+                       mask = COMMON_PHY_SD_CTRL1_PCIE_X2_EN_MASK;
+                       reg_set(comphy_base + COMMON_PHY_SD_CTRL1, data, mask);
+               }
+       }
+
+       /* If PCIe clock is output and clock source from SerDes lane 5,
+        * need to configure the clock-source MUX.
+        * By default, the clock source is from lane 4
+        */
+       if (clk_dir && clk_src && (comphy_index == COMPHY_LANE5)) {
+               data = DFX_DEV_GEN_PCIE_CLK_SRC_MUX <<
+                                               DFX_DEV_GEN_PCIE_CLK_SRC_OFFSET;
+               mask = DFX_DEV_GEN_PCIE_CLK_SRC_MASK;
+               reg_set(DFX_FROM_COMPHY_ADDR(comphy_base) +
+                       DFX_DEV_GEN_CTRL12_REG, data, mask);
+       }
+
+       debug("stage: RFU configurations - hard reset comphy\n");
+       /* RFU configurations - hard reset comphy */
+       mask = COMMON_PHY_CFG1_PWR_UP_MASK;
+       data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET;
+       mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK;
+       data |= 0x1 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET;
+       mask |= COMMON_PHY_CFG1_PWR_ON_RESET_MASK;
+       data |= 0x0 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET;
+       mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK;
+       data |= 0x0 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET;
+       mask |= COMMON_PHY_PHY_MODE_MASK;
+       data |= 0x0 << COMMON_PHY_PHY_MODE_OFFSET;
+       reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask);
+
+       /* release from hard reset */
+       mask = COMMON_PHY_CFG1_PWR_ON_RESET_MASK;
+       data = 0x1 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET;
+       mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK;
+       data |= 0x1 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET;
+       reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask);
+
+       /* Wait 1ms - until band gap and ref clock ready */
+       mdelay(1);
+       /* Start comphy Configuration */
+       debug("stage: Comphy configuration\n");
+       /* Set PIPE soft reset */
+       mask = HPIPE_RST_CLK_CTRL_PIPE_RST_MASK;
+       data = 0x1 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET;
+       /* Set PHY datapath width mode for V0 */
+       mask |= HPIPE_RST_CLK_CTRL_FIXED_PCLK_MASK;
+       data |= 0x1 << HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET;
+       /* Set Data bus width USB mode for V0 */
+       mask |= HPIPE_RST_CLK_CTRL_PIPE_WIDTH_MASK;
+       data |= 0x0 << HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET;
+       /* Set CORE_CLK output frequency for 250Mhz */
+       mask |= HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_MASK;
+       data |= 0x0 << HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET;
+       reg_set(hpipe_addr + HPIPE_RST_CLK_CTRL_REG, data, mask);
+       /* Set PLL ready delay for 0x2 */
+       data = 0x2 << HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET;
+       mask = HPIPE_CLK_SRC_LO_PLL_RDY_DL_MASK;
+       if (pcie_width != PCIE_LNK_X1) {
+               data |= 0x1 << HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_OFFSET;
+               mask |= HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_MASK;
+               data |= 0x1 << HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_OFFSET;
+               mask |= HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_MASK;
+       }
+       reg_set(hpipe_addr + HPIPE_CLK_SRC_LO_REG, data, mask);
+
+       /* Set PIPE mode interface to PCIe3 - 0x1  & set lane order */
+       data = 0x1 << HPIPE_CLK_SRC_HI_MODE_PIPE_OFFSET;
+       mask = HPIPE_CLK_SRC_HI_MODE_PIPE_MASK;
+       if (pcie_width != PCIE_LNK_X1) {
+               mask |= HPIPE_CLK_SRC_HI_LANE_STRT_MASK;
+               mask |= HPIPE_CLK_SRC_HI_LANE_MASTER_MASK;
+               mask |= HPIPE_CLK_SRC_HI_LANE_BREAK_MASK;
+               if (comphy_index == 0) {
+                       data |= 0x1 << HPIPE_CLK_SRC_HI_LANE_STRT_OFFSET;
+                       data |= 0x1 << HPIPE_CLK_SRC_HI_LANE_MASTER_OFFSET;
+               } else if (comphy_index == (pcie_width - 1)) {
+                       data |= 0x1 << HPIPE_CLK_SRC_HI_LANE_BREAK_OFFSET;
+               }
+       }
+       reg_set(hpipe_addr + HPIPE_CLK_SRC_HI_REG, data, mask);
+       /* Config update polarity equalization */
+       data = 0x1 << HPIPE_CFG_UPDATE_POLARITY_OFFSET;
+       mask = HPIPE_CFG_UPDATE_POLARITY_MASK;
+       reg_set(hpipe_addr + HPIPE_LANE_EQ_CFG1_REG, data, mask);
+       /* Set PIPE version 4 to mode enable */
+       data = 0x1 << HPIPE_DFE_CTRL_28_PIPE4_OFFSET;
+       mask = HPIPE_DFE_CTRL_28_PIPE4_MASK;
+       reg_set(hpipe_addr + HPIPE_DFE_CTRL_28_REG, data, mask);
+       /* TODO: check if pcie clock is output/input - for bringup use input*/
+       /* Enable PIN clock 100M_125M */
+       mask = 0;
+       data = 0;
+       /* Only if clock is output, configure the clock-source mux */
+       if (clk_dir) {
+               mask |= HPIPE_MISC_CLK100M_125M_MASK;
+               data |= 0x1 << HPIPE_MISC_CLK100M_125M_OFFSET;
+       }
+       /* Set PIN_TXDCLK_2X Clock Freq. Selection for outputs 500MHz clock */
+       mask |= HPIPE_MISC_TXDCLK_2X_MASK;
+       data |= 0x0 << HPIPE_MISC_TXDCLK_2X_OFFSET;
+       /* Enable 500MHz Clock */
+       mask |= HPIPE_MISC_CLK500_EN_MASK;
+       data |= 0x1 << HPIPE_MISC_CLK500_EN_OFFSET;
+       if (clk_dir) { /* output */
+               /* Set reference clock comes from group 1 */
+               mask |= HPIPE_MISC_REFCLK_SEL_MASK;
+               data |= 0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET;
+       } else {
+               /* Set reference clock comes from group 2 */
+               mask |= HPIPE_MISC_REFCLK_SEL_MASK;
+               data |= 0x1 << HPIPE_MISC_REFCLK_SEL_OFFSET;
+       }
+       mask |= HPIPE_MISC_ICP_FORCE_MASK;
+       data |= 0x1 << HPIPE_MISC_ICP_FORCE_OFFSET;
+       reg_set(hpipe_addr + HPIPE_MISC_REG, data, mask);
+       if (clk_dir) { /* output */
+               /* Set reference frequcency select - 0x2 for 25MHz*/
+               mask = HPIPE_PWR_PLL_REF_FREQ_MASK;
+               data = 0x2 << HPIPE_PWR_PLL_REF_FREQ_OFFSET;
+       } else {
+               /* Set reference frequcency select - 0x0 for 100MHz*/
+               mask = HPIPE_PWR_PLL_REF_FREQ_MASK;
+               data = 0x0 << HPIPE_PWR_PLL_REF_FREQ_OFFSET;
+       }
+       /* Set PHY mode to PCIe */
+       mask |= HPIPE_PWR_PLL_PHY_MODE_MASK;
+       data |= 0x3 << HPIPE_PWR_PLL_PHY_MODE_OFFSET;
+       reg_set(hpipe_addr + HPIPE_PWR_PLL_REG, data, mask);
+
+       /* ref clock alignment */
+       if (pcie_width != PCIE_LNK_X1) {
+               mask = HPIPE_LANE_ALIGN_OFF_MASK;
+               data = 0x0 << HPIPE_LANE_ALIGN_OFF_OFFSET;
+               reg_set(hpipe_addr + HPIPE_LANE_ALIGN_REG, data, mask);
+       }
+
+       /* Set the amount of time spent in the LoZ state - set for 0x7 only if
+        * the PCIe clock is output
+        */
+       if (clk_dir)
+               reg_set(hpipe_addr + HPIPE_GLOBAL_PM_CTRL,
+                       0x7 << HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET,
+                       HPIPE_GLOBAL_PM_RXDLOZ_WAIT_MASK);
+
+       /* Set Maximal PHY Generation Setting(8Gbps) */
+       mask = HPIPE_INTERFACE_GEN_MAX_MASK;
+       data = 0x2 << HPIPE_INTERFACE_GEN_MAX_OFFSET;
+       /* Bypass frame detection and sync detection for RX DATA */
+       mask |= HPIPE_INTERFACE_DET_BYPASS_MASK;
+       data |= 0x1 << HPIPE_INTERFACE_DET_BYPASS_OFFSET;
+       /* Set Link Train Mode (Tx training control pins are used) */
+       mask |= HPIPE_INTERFACE_LINK_TRAIN_MASK;
+       data |= 0x1 << HPIPE_INTERFACE_LINK_TRAIN_OFFSET;
+       reg_set(hpipe_addr + HPIPE_INTERFACE_REG, data, mask);
+
+       /* Set Idle_sync enable */
+       mask = HPIPE_PCIE_IDLE_SYNC_MASK;
+       data = 0x1 << HPIPE_PCIE_IDLE_SYNC_OFFSET;
+       /* Select bits for PCIE Gen3(32bit) */
+       mask |= HPIPE_PCIE_SEL_BITS_MASK;
+       data |= 0x2 << HPIPE_PCIE_SEL_BITS_OFFSET;
+       reg_set(hpipe_addr + HPIPE_PCIE_REG0, data, mask);
+
+       /* Enable Tx_adapt_g1 */
+       mask = HPIPE_TX_TRAIN_CTRL_G1_MASK;
+       data = 0x1 << HPIPE_TX_TRAIN_CTRL_G1_OFFSET;
+       /* Enable Tx_adapt_gn1 */
+       mask |= HPIPE_TX_TRAIN_CTRL_GN1_MASK;
+       data |= 0x1 << HPIPE_TX_TRAIN_CTRL_GN1_OFFSET;
+       /* Disable Tx_adapt_g0 */
+       mask |= HPIPE_TX_TRAIN_CTRL_G0_MASK;
+       data |= 0x0 << HPIPE_TX_TRAIN_CTRL_G0_OFFSET;
+       reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_REG, data, mask);
+
+       /* Set reg_tx_train_chk_init */
+       mask = HPIPE_TX_TRAIN_CHK_INIT_MASK;
+       data = 0x0 << HPIPE_TX_TRAIN_CHK_INIT_OFFSET;
+       /* Enable TX_COE_FM_PIN_PCIE3_EN */
+       mask |= HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_MASK;
+       data |= 0x1 << HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_OFFSET;
+       reg_set(hpipe_addr + HPIPE_TX_TRAIN_REG, data, mask);
+
+       debug("stage: TRx training parameters\n");
+       /* Set Preset sweep configurations */
+       mask = HPIPE_TX_TX_STATUS_CHECK_MODE_MASK;
+       data = 0x1 << HPIPE_TX_STATUS_CHECK_MODE_OFFSET;
+       mask |= HPIPE_TX_NUM_OF_PRESET_MASK;
+       data |= 0x7 << HPIPE_TX_NUM_OF_PRESET_OFFSET;
+       mask |= HPIPE_TX_SWEEP_PRESET_EN_MASK;
+       data |= 0x1 << HPIPE_TX_SWEEP_PRESET_EN_OFFSET;
+       reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_11_REG, data, mask);
+
+       /* Tx train start configuration */
+       mask = HPIPE_TX_TRAIN_START_SQ_EN_MASK;
+       data = 0x1 << HPIPE_TX_TRAIN_START_SQ_EN_OFFSET;
+       mask |= HPIPE_TX_TRAIN_START_FRM_DET_EN_MASK;
+       data |= 0x0 << HPIPE_TX_TRAIN_START_FRM_DET_EN_OFFSET;
+       mask |= HPIPE_TX_TRAIN_START_FRM_LOCK_EN_MASK;
+       data |= 0x0 << HPIPE_TX_TRAIN_START_FRM_LOCK_EN_OFFSET;
+       mask |= HPIPE_TX_TRAIN_WAIT_TIME_EN_MASK;
+       data |= 0x1 << HPIPE_TX_TRAIN_WAIT_TIME_EN_OFFSET;
+       reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_5_REG, data, mask);
+
+       /* Enable Tx train P2P */
+       mask = HPIPE_TX_TRAIN_P2P_HOLD_MASK;
+       data = 0x1 << HPIPE_TX_TRAIN_P2P_HOLD_OFFSET;
+       reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_0_REG, data, mask);
+
+       /* Configure Tx train timeout */
+       mask = HPIPE_TRX_TRAIN_TIMER_MASK;
+       data = 0x17 << HPIPE_TRX_TRAIN_TIMER_OFFSET;
+       reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_4_REG, data, mask);
+
+       /* Disable G0/G1/GN1 adaptation */
+       mask = HPIPE_TX_TRAIN_CTRL_G1_MASK | HPIPE_TX_TRAIN_CTRL_GN1_MASK
+               | HPIPE_TX_TRAIN_CTRL_G0_OFFSET;
+       data = 0;
+       reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_REG, data, mask);
+
+       /* Disable DTL frequency loop */
+       mask = HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK;
+       data = 0x0 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET;
+       reg_set(hpipe_addr + HPIPE_PWR_CTR_DTL_REG, data, mask);
+
+       /* Configure G3 DFE */
+       mask = HPIPE_G3_DFE_RES_MASK;
+       data = 0x3 << HPIPE_G3_DFE_RES_OFFSET;
+       reg_set(hpipe_addr + HPIPE_G3_SETTING_4_REG, data, mask);
+
+       /* Use TX/RX training result for DFE */
+       mask = HPIPE_DFE_RES_FORCE_MASK;
+       data = 0x0 << HPIPE_DFE_RES_FORCE_OFFSET;
+       reg_set(hpipe_addr + HPIPE_DFE_REG0,  data, mask);
+
+       /* Configure initial and final coefficient value for receiver */
+       mask = HPIPE_G3_SET_1_G3_RX_SELMUPI_MASK;
+       data = 0x1 << HPIPE_G3_SET_1_G3_RX_SELMUPI_OFFSET;
+
+       mask |= HPIPE_G3_SET_1_G3_RX_SELMUPF_MASK;
+       data |= 0x1 << HPIPE_G3_SET_1_G3_RX_SELMUPF_OFFSET;
+
+       mask |= HPIPE_G3_SET_1_G3_SAMPLER_INPAIRX2_EN_MASK;
+       data |= 0x0 << HPIPE_G3_SET_1_G3_SAMPLER_INPAIRX2_EN_OFFSET;
+       reg_set(hpipe_addr + HPIPE_G3_SET_1_REG,  data, mask);
+
+       /* Trigger sampler enable pulse */
+       mask = HPIPE_SMAPLER_MASK;
+       data = 0x1 << HPIPE_SMAPLER_OFFSET;
+       reg_set(hpipe_addr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, data, mask);
+       udelay(5);
+       reg_set(hpipe_addr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, 0, mask);
+
+       /* FFE resistor tuning for different bandwidth  */
+       mask = HPIPE_G3_FFE_DEG_RES_LEVEL_MASK;
+       data = 0x1 << HPIPE_G3_FFE_DEG_RES_LEVEL_OFFSET;
+       mask |= HPIPE_G3_FFE_LOAD_RES_LEVEL_MASK;
+       data |= 0x3 << HPIPE_G3_FFE_LOAD_RES_LEVEL_OFFSET;
+       reg_set(hpipe_addr + HPIPE_G3_SETTING_3_REG, data, mask);
+
+       /* Pattern lock lost timeout disable */
+       mask = HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_MASK;
+       data = 0x0 << HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_OFFSET;
+       reg_set(hpipe_addr + HPIPE_FRAME_DETECT_CTRL_3_REG, data, mask);
+
+       /* Configure DFE adaptations */
+       mask = HPIPE_CDR_RX_MAX_DFE_ADAPT_0_MASK;
+       data = 0x0 << HPIPE_CDR_RX_MAX_DFE_ADAPT_0_OFFSET;
+       mask |= HPIPE_CDR_RX_MAX_DFE_ADAPT_1_MASK;
+       data |= 0x0 << HPIPE_CDR_RX_MAX_DFE_ADAPT_1_OFFSET;
+       mask |= HPIPE_CDR_MAX_DFE_ADAPT_0_MASK;
+       data |= 0x0 << HPIPE_CDR_MAX_DFE_ADAPT_0_OFFSET;
+       mask |= HPIPE_CDR_MAX_DFE_ADAPT_1_MASK;
+       data |= 0x1 << HPIPE_CDR_MAX_DFE_ADAPT_1_OFFSET;
+       reg_set(hpipe_addr + HPIPE_CDR_CONTROL_REG, data, mask);
+
+       mask = HPIPE_DFE_TX_MAX_DFE_ADAPT_MASK;
+       data = 0x0 << HPIPE_DFE_TX_MAX_DFE_ADAPT_OFFSET;
+       reg_set(hpipe_addr + HPIPE_DFE_CONTROL_REG, data, mask);
+
+       /* Genration 2 setting 1*/
+       mask = HPIPE_G2_SET_1_G2_RX_SELMUPI_MASK;
+       data = 0x0 << HPIPE_G2_SET_1_G2_RX_SELMUPI_OFFSET;
+       mask |= HPIPE_G2_SET_1_G2_RX_SELMUPP_MASK;
+       data |= 0x1 << HPIPE_G2_SET_1_G2_RX_SELMUPP_OFFSET;
+       mask |= HPIPE_G2_SET_1_G2_RX_SELMUFI_MASK;
+       data |= 0x0 << HPIPE_G2_SET_1_G2_RX_SELMUFI_OFFSET;
+       reg_set(hpipe_addr + HPIPE_G2_SET_1_REG, data, mask);
+
+       /* DFE enable */
+       mask = HPIPE_G2_DFE_RES_MASK;
+       data = 0x3 << HPIPE_G2_DFE_RES_OFFSET;
+       reg_set(hpipe_addr + HPIPE_G2_SETTINGS_4_REG, data, mask);
+
+       /* Configure DFE Resolution */
+       mask = HPIPE_LANE_CFG4_DFE_EN_SEL_MASK;
+       data = 0x1 << HPIPE_LANE_CFG4_DFE_EN_SEL_OFFSET;
+       reg_set(hpipe_addr + HPIPE_LANE_CFG4_REG, data, mask);
+
+       /* VDD calibration control */
+       mask = HPIPE_EXT_SELLV_RXSAMPL_MASK;
+       data = 0x16 << HPIPE_EXT_SELLV_RXSAMPL_OFFSET;
+       reg_set(hpipe_addr + HPIPE_VDD_CAL_CTRL_REG, data, mask);
+
+       /* Set PLL Charge-pump Current Control */
+       mask = HPIPE_G3_SETTING_5_G3_ICP_MASK;
+       data = 0x4 << HPIPE_G3_SETTING_5_G3_ICP_OFFSET;
+       reg_set(hpipe_addr + HPIPE_G3_SETTING_5_REG, data, mask);
+
+       /* Set lane rqualization remote setting */
+       mask = HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_MASK;
+       data = 0x1 << HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_OFFSET;
+       mask |= HPIPE_LANE_CFG_FOM_ONLY_MODE_MASK;
+       data |= 0x1 << HPIPE_LANE_CFG_FOM_ONLY_MODE_OFFFSET;
+       mask |= HPIPE_LANE_CFG_FOM_PRESET_VECTOR_MASK;
+       data |= 0x6 << HPIPE_LANE_CFG_FOM_PRESET_VECTOR_OFFSET;
+       reg_set(hpipe_addr + HPIPE_LANE_EQ_REMOTE_SETTING_REG, data, mask);
+
+       mask = HPIPE_CFG_EQ_BUNDLE_DIS_MASK;
+       data = 0x1 << HPIPE_CFG_EQ_BUNDLE_DIS_OFFSET;
+       reg_set(hpipe_addr + HPIPE_LANE_EQ_CFG2_REG, data, mask);
+
+       debug("stage: Comphy power up\n");
+
+       /* For PCIe X4 or X2:
+        * release from reset only after finish to configure all lanes
+        */
+       if ((pcie_width == PCIE_LNK_X1) || (comphy_index == (pcie_width - 1))) {
+               uint32_t i, start_lane, end_lane;
+
+               if (pcie_width != PCIE_LNK_X1) {
+                       /* allows writing to all lanes in one write */
+                       data = 0x0;
+                       if (pcie_width == PCIE_LNK_X2)
+                               mask = COMMON_PHY_SD_CTRL1_COMPHY_0_1_PORT_MASK;
+                       else if (pcie_width == PCIE_LNK_X4)
+                               mask = COMMON_PHY_SD_CTRL1_COMPHY_0_3_PORT_MASK;
+                       reg_set(comphy_base + COMMON_PHY_SD_CTRL1, data, mask);
+                       start_lane = 0;
+                       end_lane = pcie_width;
+
+                       /* Release from PIPE soft reset
+                        * For PCIe by4 or by2:
+                        * release from soft reset all lanes - can't use
+                        * read modify write
+                        */
+                       reg_set(HPIPE_ADDR(
+                               COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base), 0) +
+                               HPIPE_RST_CLK_CTRL_REG, 0x24, 0xffffffff);
+               } else {
+                       start_lane = comphy_index;
+                       end_lane = comphy_index + 1;
+
+                       /* Release from PIPE soft reset
+                        * for PCIe by4 or by2:
+                        * release from soft reset all lanes
+                        */
+                       reg_set(hpipe_addr + HPIPE_RST_CLK_CTRL_REG,
+                               0x0 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET,
+                               HPIPE_RST_CLK_CTRL_PIPE_RST_MASK);
+               }
+
+               if (pcie_width != PCIE_LNK_X1) {
+                       /* disable writing to all lanes with one write */
+                       if (pcie_width == PCIE_LNK_X2) {
+                               data = (COMPHY_LANE0 <<
+                               COMMON_PHY_SD_CTRL1_COMPHY_0_PORT_OFFSET) |
+                               (COMPHY_LANE1 <<
+                               COMMON_PHY_SD_CTRL1_COMPHY_1_PORT_OFFSET);
+                               mask = COMMON_PHY_SD_CTRL1_COMPHY_0_1_PORT_MASK;
+                       } else if (pcie_width == PCIE_LNK_X4) {
+                               data = (COMPHY_LANE0 <<
+                               COMMON_PHY_SD_CTRL1_COMPHY_0_PORT_OFFSET) |
+                               (COMPHY_LANE1 <<
+                               COMMON_PHY_SD_CTRL1_COMPHY_1_PORT_OFFSET) |
+                               (COMPHY_LANE2 <<
+                               COMMON_PHY_SD_CTRL1_COMPHY_2_PORT_OFFSET) |
+                               (COMPHY_LANE3 <<
+                               COMMON_PHY_SD_CTRL1_COMPHY_3_PORT_OFFSET);
+                               mask = COMMON_PHY_SD_CTRL1_COMPHY_0_3_PORT_MASK;
+                       }
+                       reg_set(comphy_base + COMMON_PHY_SD_CTRL1,
+                               data, mask);
+               }
+
+               debug("stage: Check PLL\n");
+               /* Read lane status */
+               for (i = start_lane; i < end_lane; i++) {
+                       addr = HPIPE_ADDR(
+                               COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base), i) +
+                               HPIPE_LANE_STATUS1_REG;
+                       data = HPIPE_LANE_STATUS1_PCLK_EN_MASK;
+                       mask = data;
+                       ret = polling_with_timeout(addr, data, mask,
+                                                  PLL_LOCK_TIMEOUT,
+                                                  REG_32BIT);
+                       if (ret)
+                               ERROR("Failed to lock PCIE PLL\n");
+               }
+       }
+
+       debug_exit();
+
+       return ret;
+}
+
+static int mvebu_cp110_comphy_rxaui_power_on(uint64_t comphy_base,
+                                    uint8_t comphy_index, uint32_t comphy_mode)
+{
+       uintptr_t hpipe_addr, sd_ip_addr, comphy_addr, addr;
+       uint32_t mask, data;
+       int ret = 0;
+
+       debug_enter();
+
+       hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
+                               comphy_index);
+       comphy_addr = COMPHY_ADDR(comphy_base, comphy_index);
+       sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
+                            comphy_index);
+
+       /* configure phy selector for RXAUI */
+       mvebu_cp110_comphy_set_phy_selector(comphy_base, comphy_index,
+                                           comphy_mode);
+
+       /* RFU configurations - hard reset comphy */
+       mask = COMMON_PHY_CFG1_PWR_UP_MASK;
+       data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET;
+       mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK;
+       data |= 0x0 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET;
+       reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask);
+
+       if (comphy_index == 2) {
+               reg_set(comphy_base + COMMON_PHY_SD_CTRL1,
+                       0x1 << COMMON_PHY_SD_CTRL1_RXAUI0_OFFSET,
+                       COMMON_PHY_SD_CTRL1_RXAUI0_MASK);
+       }
+       if (comphy_index == 4) {
+               reg_set(comphy_base + COMMON_PHY_SD_CTRL1,
+                       0x1 << COMMON_PHY_SD_CTRL1_RXAUI1_OFFSET,
+                       COMMON_PHY_SD_CTRL1_RXAUI1_MASK);
+       }
+
+       /* Select Baud Rate of Comphy And PD_PLL/Tx/Rx */
+       mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK;
+       data = 0x0 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_MASK;
+       data |= 0xB << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_MASK;
+       data |= 0xB << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK;
+       data |= 0x0 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK;
+       data |= 0x0 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_MASK;
+       data |= 0x0 << SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG0_MEDIA_MODE_MASK;
+       data |= 0x1 << SD_EXTERNAL_CONFIG0_MEDIA_MODE_OFFSET;
+       reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG0_REG, data, mask);
+
+       /* release from hard reset */
+       mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK;
+       data = 0x0 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
+       data |= 0x0 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK;
+       data |= 0x0 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET;
+       reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
+
+       mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK;
+       data = 0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
+       data |= 0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET;
+       reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
+
+       /* Wait 1ms - until band gap and ref clock ready */
+       mdelay(1);
+
+       /* Start comphy Configuration */
+       debug("stage: Comphy configuration\n");
+       /* set reference clock */
+       reg_set(hpipe_addr + HPIPE_MISC_REG,
+               0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET,
+               HPIPE_MISC_REFCLK_SEL_MASK);
+       /* Power and PLL Control */
+       mask = HPIPE_PWR_PLL_REF_FREQ_MASK;
+       data = 0x1 << HPIPE_PWR_PLL_REF_FREQ_OFFSET;
+       mask |= HPIPE_PWR_PLL_PHY_MODE_MASK;
+       data |= 0x4 << HPIPE_PWR_PLL_PHY_MODE_OFFSET;
+       reg_set(hpipe_addr + HPIPE_PWR_PLL_REG, data, mask);
+       /* Loopback register */
+       reg_set(hpipe_addr + HPIPE_LOOPBACK_REG,
+               0x1 << HPIPE_LOOPBACK_SEL_OFFSET, HPIPE_LOOPBACK_SEL_MASK);
+       /* rx control 1 */
+       mask = HPIPE_RX_CONTROL_1_RXCLK2X_SEL_MASK;
+       data = 0x1 << HPIPE_RX_CONTROL_1_RXCLK2X_SEL_OFFSET;
+       mask |= HPIPE_RX_CONTROL_1_CLK8T_EN_MASK;
+       data |= 0x1 << HPIPE_RX_CONTROL_1_CLK8T_EN_OFFSET;
+       reg_set(hpipe_addr + HPIPE_RX_CONTROL_1_REG, data, mask);
+       /* DTL Control */
+       reg_set(hpipe_addr + HPIPE_PWR_CTR_DTL_REG,
+               0x0 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET,
+               HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK);
+
+       /* Set analog parameters from ETP(HW) */
+       debug("stage: Analog parameters from ETP(HW)\n");
+       /* SERDES External Configuration 2 */
+       reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG2_REG,
+               0x1 << SD_EXTERNAL_CONFIG2_PIN_DFE_EN_OFFSET,
+               SD_EXTERNAL_CONFIG2_PIN_DFE_EN_MASK);
+       /* 0x7-DFE Resolution control */
+       reg_set(hpipe_addr + HPIPE_DFE_REG0, 0x1 << HPIPE_DFE_RES_FORCE_OFFSET,
+               HPIPE_DFE_RES_FORCE_MASK);
+       /* 0xd-G1_Setting_0 */
+       reg_set(hpipe_addr + HPIPE_G1_SET_0_REG,
+               0xd << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET,
+               HPIPE_G1_SET_0_G1_TX_EMPH1_MASK);
+       /* 0xE-G1_Setting_1 */
+       mask = HPIPE_G1_SET_1_G1_RX_SELMUPI_MASK;
+       data = 0x1 << HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET;
+       mask |= HPIPE_G1_SET_1_G1_RX_SELMUPP_MASK;
+       data |= 0x1 << HPIPE_G1_SET_1_G1_RX_SELMUPP_OFFSET;
+       mask |= HPIPE_G1_SET_1_G1_RX_DFE_EN_MASK;
+       data |= 0x1 << HPIPE_G1_SET_1_G1_RX_DFE_EN_OFFSET;
+       reg_set(hpipe_addr + HPIPE_G1_SET_1_REG, data, mask);
+       /* 0xA-DFE_Reg3 */
+       mask = HPIPE_DFE_F3_F5_DFE_EN_MASK;
+       data = 0x0 << HPIPE_DFE_F3_F5_DFE_EN_OFFSET;
+       mask |= HPIPE_DFE_F3_F5_DFE_CTRL_MASK;
+       data |= 0x0 << HPIPE_DFE_F3_F5_DFE_CTRL_OFFSET;
+       reg_set(hpipe_addr + HPIPE_DFE_F3_F5_REG, data, mask);
+
+       /* 0x111-G1_Setting_4 */
+       mask = HPIPE_G1_SETTINGS_4_G1_DFE_RES_MASK;
+       data = 0x1 << HPIPE_G1_SETTINGS_4_G1_DFE_RES_OFFSET;
+       reg_set(hpipe_addr + HPIPE_G1_SETTINGS_4_REG, data, mask);
+
+       debug("stage: RFU configurations- Power Up PLL,Tx,Rx\n");
+       /* SERDES External Configuration */
+       mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK;
+       data = 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK;
+       data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK;
+       data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET;
+       reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG0_REG, data, mask);
+
+
+       /* check PLL rx & tx ready */
+       addr = sd_ip_addr + SD_EXTERNAL_STATUS0_REG;
+       data = SD_EXTERNAL_STATUS0_PLL_RX_MASK |
+               SD_EXTERNAL_STATUS0_PLL_TX_MASK;
+       mask = data;
+       data = polling_with_timeout(addr, data, mask, 15000, REG_32BIT);
+       if (data != 0) {
+               debug("Read from reg = %lx - value = 0x%x\n",
+                     sd_ip_addr + SD_EXTERNAL_STATUS0_REG, data);
+               ERROR("SD_EXTERNAL_STATUS0_PLL_RX is %d, -\"-_PLL_TX is %d\n",
+                     (data & SD_EXTERNAL_STATUS0_PLL_RX_MASK),
+                     (data & SD_EXTERNAL_STATUS0_PLL_TX_MASK));
+               ret = -ETIMEDOUT;
+       }
+
+       /* RX init */
+       reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG,
+               0x1 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET,
+               SD_EXTERNAL_CONFIG1_RX_INIT_MASK);
+
+       /* check that RX init done */
+       addr = sd_ip_addr + SD_EXTERNAL_STATUS0_REG;
+       data = SD_EXTERNAL_STATUS0_RX_INIT_MASK;
+       mask = data;
+       data = polling_with_timeout(addr, data, mask, 100, REG_32BIT);
+       if (data != 0) {
+               debug("Read from reg = %lx - value = 0x%x\n",
+                     sd_ip_addr + SD_EXTERNAL_STATUS0_REG, data);
+               ERROR("SD_EXTERNAL_STATUS0_RX_INIT is 0\n");
+               ret = -ETIMEDOUT;
+       }
+
+       debug("stage: RF Reset\n");
+       /* RF Reset */
+       mask =  SD_EXTERNAL_CONFIG1_RX_INIT_MASK;
+       data = 0x0 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK;
+       data |= 0x1 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET;
+       reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
+
+       debug_exit();
+
+       return ret;
+}
+
+static int mvebu_cp110_comphy_usb3_power_on(uint64_t comphy_base,
+                                    uint8_t comphy_index, uint32_t comphy_mode)
+{
+       uintptr_t hpipe_addr, comphy_addr, addr;
+       uint32_t mask, data;
+       int ret = 0;
+
+       debug_enter();
+
+       /* Configure PIPE selector for USB3 */
+       mvebu_cp110_comphy_set_pipe_selector(comphy_base, comphy_index,
+                                            comphy_mode);
+
+       hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
+                               comphy_index);
+       comphy_addr = COMPHY_ADDR(comphy_base, comphy_index);
+
+       debug("stage: RFU configurations - hard reset comphy\n");
+       /* RFU configurations - hard reset comphy */
+       mask = COMMON_PHY_CFG1_PWR_UP_MASK;
+       data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET;
+       mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK;
+       data |= 0x1 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET;
+       mask |= COMMON_PHY_CFG1_PWR_ON_RESET_MASK;
+       data |= 0x0 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET;
+       mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK;
+       data |= 0x0 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET;
+       mask |= COMMON_PHY_PHY_MODE_MASK;
+       data |= 0x1 << COMMON_PHY_PHY_MODE_OFFSET;
+       reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask);
+
+       /* release from hard reset */
+       mask = COMMON_PHY_CFG1_PWR_ON_RESET_MASK;
+       data = 0x1 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET;
+       mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK;
+       data |= 0x1 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET;
+       reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask);
+
+       /* Wait 1ms - until band gap and ref clock ready */
+       mdelay(1);
+
+       /* Start comphy Configuration */
+       debug("stage: Comphy configuration\n");
+       /* Set PIPE soft reset */
+       mask = HPIPE_RST_CLK_CTRL_PIPE_RST_MASK;
+       data = 0x1 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET;
+       /* Set PHY datapath width mode for V0 */
+       mask |= HPIPE_RST_CLK_CTRL_FIXED_PCLK_MASK;
+       data |= 0x0 << HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET;
+       /* Set Data bus width USB mode for V0 */
+       mask |= HPIPE_RST_CLK_CTRL_PIPE_WIDTH_MASK;
+       data |= 0x0 << HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET;
+       /* Set CORE_CLK output frequency for 250Mhz */
+       mask |= HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_MASK;
+       data |= 0x0 << HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET;
+       reg_set(hpipe_addr + HPIPE_RST_CLK_CTRL_REG, data, mask);
+       /* Set PLL ready delay for 0x2 */
+       reg_set(hpipe_addr + HPIPE_CLK_SRC_LO_REG,
+               0x2 << HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET,
+               HPIPE_CLK_SRC_LO_PLL_RDY_DL_MASK);
+       /* Set reference clock to come from group 1 - 25Mhz */
+       reg_set(hpipe_addr + HPIPE_MISC_REG,
+               0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET,
+               HPIPE_MISC_REFCLK_SEL_MASK);
+       /* Set reference frequcency select - 0x2 */
+       mask = HPIPE_PWR_PLL_REF_FREQ_MASK;
+       data = 0x2 << HPIPE_PWR_PLL_REF_FREQ_OFFSET;
+       /* Set PHY mode to USB - 0x5 */
+       mask |= HPIPE_PWR_PLL_PHY_MODE_MASK;
+       data |= 0x5 << HPIPE_PWR_PLL_PHY_MODE_OFFSET;
+       reg_set(hpipe_addr + HPIPE_PWR_PLL_REG, data, mask);
+       /* Set the amount of time spent in the LoZ state - set for 0x7 */
+       reg_set(hpipe_addr + HPIPE_GLOBAL_PM_CTRL,
+               0x7 << HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET,
+               HPIPE_GLOBAL_PM_RXDLOZ_WAIT_MASK);
+       /* Set max PHY generation setting - 5Gbps */
+       reg_set(hpipe_addr + HPIPE_INTERFACE_REG,
+               0x1 << HPIPE_INTERFACE_GEN_MAX_OFFSET,
+               HPIPE_INTERFACE_GEN_MAX_MASK);
+       /* Set select data width 20Bit (SEL_BITS[2:0]) */
+       reg_set(hpipe_addr + HPIPE_LOOPBACK_REG,
+               0x1 << HPIPE_LOOPBACK_SEL_OFFSET,
+               HPIPE_LOOPBACK_SEL_MASK);
+       /* select de-emphasize 3.5db */
+       reg_set(hpipe_addr + HPIPE_LANE_CONFIG0_REG,
+               0x1 << HPIPE_LANE_CONFIG0_TXDEEMPH0_OFFSET,
+               HPIPE_LANE_CONFIG0_TXDEEMPH0_MASK);
+       /* override tx margining from the MAC */
+       reg_set(hpipe_addr + HPIPE_TST_MODE_CTRL_REG,
+               0x1 << HPIPE_TST_MODE_CTRL_MODE_MARGIN_OFFSET,
+               HPIPE_TST_MODE_CTRL_MODE_MARGIN_MASK);
+
+       /* Start analog parameters from ETP(HW) */
+       debug("stage: Analog parameters from ETP(HW)\n");
+       /* Set Pin DFE_PAT_DIS -> Bit[1]: PIN_DFE_PAT_DIS = 0x0 */
+       mask = HPIPE_LANE_CFG4_DFE_CTRL_MASK;
+       data = 0x1 << HPIPE_LANE_CFG4_DFE_CTRL_OFFSET;
+       /* Set Override PHY DFE control pins for 0x1 */
+       mask |= HPIPE_LANE_CFG4_DFE_OVER_MASK;
+       data |= 0x1 << HPIPE_LANE_CFG4_DFE_OVER_OFFSET;
+       /* Set Spread Spectrum Clock Enable fot 0x1 */
+       mask |= HPIPE_LANE_CFG4_SSC_CTRL_MASK;
+       data |= 0x1 << HPIPE_LANE_CFG4_SSC_CTRL_OFFSET;
+       reg_set(hpipe_addr + HPIPE_LANE_CFG4_REG, data, mask);
+       /* Confifure SSC amplitude */
+       mask = HPIPE_G2_TX_SSC_AMP_MASK;
+       data = 0x1f << HPIPE_G2_TX_SSC_AMP_OFFSET;
+       reg_set(hpipe_addr + HPIPE_G2_SET_2_REG, data, mask);
+       /* End of analog parameters */
+
+       debug("stage: Comphy power up\n");
+       /* Release from PIPE soft reset */
+       reg_set(hpipe_addr + HPIPE_RST_CLK_CTRL_REG,
+               0x0 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET,
+               HPIPE_RST_CLK_CTRL_PIPE_RST_MASK);
+
+       /* wait 15ms - for comphy calibration done */
+       debug("stage: Check PLL\n");
+       /* Read lane status */
+       addr = hpipe_addr + HPIPE_LANE_STATUS1_REG;
+       data = HPIPE_LANE_STATUS1_PCLK_EN_MASK;
+       mask = data;
+       data = polling_with_timeout(addr, data, mask, 15000, REG_32BIT);
+       if (data != 0) {
+               debug("Read from reg = %lx - value = 0x%x\n",
+                       hpipe_addr + HPIPE_LANE_STATUS1_REG, data);
+               ERROR("HPIPE_LANE_STATUS1_PCLK_EN_MASK is 0\n");
+               ret = -ETIMEDOUT;
+       }
+
+       debug_exit();
+
+       return ret;
+}
+
+/* This function performs RX training for one Feed Forward Equalization (FFE)
+ * value.
+ * The RX traiing result is stored in 'Saved DFE values Register' (SAV_F0D).
+ *
+ * Return '0' on success, error code in  a case of failure.
+ */
+static int mvebu_cp110_comphy_test_single_ffe(uint64_t comphy_base,
+                                             uint8_t comphy_index,
+                                             uint32_t ffe, uint32_t *result)
+{
+       uint32_t mask, data, timeout;
+       uintptr_t hpipe_addr, sd_ip_addr;
+
+       hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
+                               comphy_index);
+
+       sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
+                            comphy_index);
+
+       /* Configure PRBS counters */
+       mask = HPIPE_PHY_TEST_PATTERN_SEL_MASK;
+       data = 0xe << HPIPE_PHY_TEST_PATTERN_SEL_OFFSET;
+       reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask);
+
+       mask = HPIPE_PHY_TEST_DATA_MASK;
+       data = 0x64 << HPIPE_PHY_TEST_DATA_OFFSET;
+       reg_set(hpipe_addr + HPIPE_PHY_TEST_DATA_REG, data, mask);
+
+       mask = HPIPE_PHY_TEST_EN_MASK;
+       data = 0x1 << HPIPE_PHY_TEST_EN_OFFSET;
+       reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask);
+
+       mdelay(50);
+
+       /* Set the FFE value */
+       mask = HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_MASK;
+       data = ffe << HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_OFFSET;
+       reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask);
+
+       /* Start RX training */
+       mask = SD_EXTERNAL_STATUS_START_RX_TRAINING_MASK;
+       data = 1 << SD_EXTERNAL_STATUS_START_RX_TRAINING_OFFSET;
+       reg_set(sd_ip_addr + SD_EXTERNAL_STATUS_REG, data, mask);
+
+       /* Check the result of RX training */
+       timeout = RX_TRAINING_TIMEOUT;
+       while (timeout) {
+               data = mmio_read_32(sd_ip_addr + SD_EXTERNAL_STATAUS1_REG);
+               if (data & SD_EXTERNAL_STATAUS1_REG_RX_TRAIN_COMP_MASK)
+                       break;
+               mdelay(1);
+               timeout--;
+       }
+
+       if (timeout == 0)
+               return -ETIMEDOUT;
+
+       if (data & SD_EXTERNAL_STATAUS1_REG_RX_TRAIN_FAILED_MASK)
+               return -EINVAL;
+
+       /* Stop RX training */
+       mask = SD_EXTERNAL_STATUS_START_RX_TRAINING_MASK;
+       data = 0 << SD_EXTERNAL_STATUS_START_RX_TRAINING_OFFSET;
+       reg_set(sd_ip_addr + SD_EXTERNAL_STATUS_REG, data, mask);
+
+       /* Read the result */
+       data = mmio_read_32(hpipe_addr + HPIPE_SAVED_DFE_VALUES_REG);
+       data &= HPIPE_SAVED_DFE_VALUES_SAV_F0D_MASK;
+       data >>= HPIPE_SAVED_DFE_VALUES_SAV_F0D_OFFSET;
+       *result = data;
+
+       mask = HPIPE_PHY_TEST_RESET_MASK;
+       data = 0x1 << HPIPE_PHY_TEST_RESET_OFFSET;
+       mask |= HPIPE_PHY_TEST_EN_MASK;
+       data |= 0x0 << HPIPE_PHY_TEST_EN_OFFSET;
+       reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask);
+
+       mask = HPIPE_PHY_TEST_RESET_MASK;
+       data = 0x0 << HPIPE_PHY_TEST_RESET_OFFSET;
+       reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask);
+
+       return 0;
+}
+
+/* This function runs complete RX training sequence:
+ *     - Run RX training for all possible Feed Forward Equalization values
+ *     - Choose the FFE which gives the best result.
+ *     - Run RX training again with the best result.
+ *
+ * Return '0' on success, error code in  a case of failure.
+ */
+int mvebu_cp110_comphy_xfi_rx_training(uint64_t comphy_base,
+                                             uint8_t comphy_index)
+{
+       uint32_t mask, data, max_rx_train = 0, max_rx_train_index = 0;
+       uintptr_t hpipe_addr;
+       uint32_t rx_train_result;
+       int ret, i;
+
+       hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
+                               comphy_index);
+
+       debug_enter();
+
+       /* Configure SQ threshold and CDR lock */
+       mask = HPIPE_SQUELCH_THRESH_IN_MASK;
+       data = 0xc << HPIPE_SQUELCH_THRESH_IN_OFFSET;
+       reg_set(hpipe_addr + HPIPE_SQUELCH_FFE_SETTING_REG, data, mask);
+
+       mask = HPIPE_SQ_DEGLITCH_WIDTH_P_MASK;
+       data = 0xf << HPIPE_SQ_DEGLITCH_WIDTH_P_OFFSET;
+       mask |= HPIPE_SQ_DEGLITCH_WIDTH_N_MASK;
+       data |= 0xf << HPIPE_SQ_DEGLITCH_WIDTH_N_OFFSET;
+       mask |= HPIPE_SQ_DEGLITCH_EN_MASK;
+       data |= 0x1 << HPIPE_SQ_DEGLITCH_EN_OFFSET;
+       reg_set(hpipe_addr + HPIPE_SQ_GLITCH_FILTER_CTRL, data, mask);
+
+       mask = HPIPE_CDR_LOCK_DET_EN_MASK;
+       data = 0x1 << HPIPE_CDR_LOCK_DET_EN_OFFSET;
+       reg_set(hpipe_addr + HPIPE_LOOPBACK_REG, data, mask);
+
+       udelay(100);
+
+       /* Determine if we have a cable attached to this comphy, if not,
+        * we can't perform RX training.
+        */
+       data = mmio_read_32(hpipe_addr + HPIPE_SQUELCH_FFE_SETTING_REG);
+       if (data & HPIPE_SQUELCH_DETECTED_MASK) {
+               ERROR("Squelsh is not detected, can't perform RX training\n");
+               return -EINVAL;
+       }
+
+       data = mmio_read_32(hpipe_addr + HPIPE_LOOPBACK_REG);
+       if (!(data & HPIPE_CDR_LOCK_MASK)) {
+               ERROR("CDR is not locked, can't perform RX training\n");
+               return -EINVAL;
+       }
+
+       /* Do preparations for RX training */
+       mask = HPIPE_DFE_RES_FORCE_MASK;
+       data = 0x0 << HPIPE_DFE_RES_FORCE_OFFSET;
+       reg_set(hpipe_addr + HPIPE_DFE_REG0, data, mask);
+
+       mask = HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_MASK;
+       data = 0xf << HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_OFFSET;
+       mask |= HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_MASK;
+       data |= 1 << HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET;
+       reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask);
+
+       /* Perform RX training for all possible FFE (Feed Forward
+        * Equalization, possible values are 0-7).
+        * We update the best value reached and the FFE which gave this value.
+        */
+       for (i = 0; i < MAX_NUM_OF_FFE; i++) {
+               rx_train_result = 0;
+               ret = mvebu_cp110_comphy_test_single_ffe(comphy_base,
+                                                        comphy_index, i,
+                                                        &rx_train_result);
+
+               if ((!ret) && (rx_train_result > max_rx_train)) {
+                       max_rx_train = rx_train_result;
+                       max_rx_train_index = i;
+               }
+       }
+
+       /* If we were able to determine which FFE gives the best value,
+        * now we need to set it and run RX training again (only for this
+        * FFE).
+        */
+       if (max_rx_train) {
+               ret = mvebu_cp110_comphy_test_single_ffe(comphy_base,
+                                                        comphy_index,
+                                                        max_rx_train_index,
+                                                        &rx_train_result);
+
+               if (ret == 0)
+                       debug("RX Training passed (FFE = %d, result = 0x%x)\n",
+                              max_rx_train_index, rx_train_result);
+       } else {
+               ERROR("RX Training failed for comphy%d\n", comphy_index);
+               ret = -EINVAL;
+       }
+
+       debug_exit();
+
+       return ret;
+}
+
+/* During AP the proper mode is auto-negotiated and the mac, pcs and serdes
+ * configuration are done by the firmware loaded to the MG's CM3 for appropriate
+ * negotiated mode. Therefore there is no need to configure the mac, pcs and
+ * serdes from u-boot. The only thing that need to be setup is powering up
+ * the comphy, which is done through Common PHY<n> Configuration 1 Register
+ * (CP0: 0xF2441000, CP1: 0xF4441000). This step can't be done by MG's CM3,
+ * since it doesn't have an access to this register-set (but it has access to
+ * the network registers like: MG, AP, MAC, PCS, Serdes etc.)
+ */
+static int mvebu_cp110_comphy_ap_power_on(uint64_t comphy_base,
+                                         uint8_t comphy_index)
+{
+       uint32_t mask, data;
+       uintptr_t comphy_addr = comphy_addr =
+                               COMPHY_ADDR(comphy_base, comphy_index);
+
+       debug_enter();
+       debug("stage: RFU configurations - hard reset comphy\n");
+       /* RFU configurations - hard reset comphy */
+       mask = COMMON_PHY_CFG1_PWR_UP_MASK;
+       data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET;
+       mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK;
+       data |= 0x0 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET;
+       reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask);
+       debug_exit();
+
+       return 0;
+}
+
+/*
+ * This function allows to reset the digital synchronizers between
+ * the MAC and the PHY, it is required when the MAC changes its state.
+ */
+int mvebu_cp110_comphy_digital_reset(uint64_t comphy_base,
+                                    uint8_t comphy_index,
+                                    uint32_t comphy_mode, uint32_t command)
+{
+       int mode = COMPHY_GET_MODE(comphy_mode);
+       uintptr_t sd_ip_addr;
+       uint32_t mask, data;
+
+       sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
+                            comphy_index);
+
+       switch (mode) {
+       case (COMPHY_SGMII_MODE):
+       case (COMPHY_HS_SGMII_MODE):
+       case (COMPHY_XFI_MODE):
+       case (COMPHY_SFI_MODE):
+       case (COMPHY_RXAUI_MODE):
+               mask = SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK;
+               data = ((command == COMPHY_COMMAND_DIGITAL_PWR_OFF) ?
+                       0x0 : 0x1) << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET;
+               reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
+               break;
+       default:
+               ERROR("comphy%d: Digital PWR ON/OFF is not supported\n",
+                       comphy_index);
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
+int mvebu_cp110_comphy_power_on(uint64_t comphy_base, uint64_t comphy_index,
+                               uint64_t comphy_mode)
+{
+       int mode = COMPHY_GET_MODE(comphy_mode);
+       int err = 0;
+
+       debug_enter();
+
+       switch (mode) {
+       case(COMPHY_SATA_MODE):
+               err = mvebu_cp110_comphy_sata_power_on(comphy_base,
+                                                      comphy_index,
+                                                      comphy_mode);
+               break;
+       case(COMPHY_SGMII_MODE):
+       case(COMPHY_HS_SGMII_MODE):
+               err = mvebu_cp110_comphy_sgmii_power_on(comphy_base,
+                                                       comphy_index,
+                                                       comphy_mode);
+               break;
+       /* From comphy perspective, XFI and SFI are the same */
+       case (COMPHY_XFI_MODE):
+       case (COMPHY_SFI_MODE):
+               err = mvebu_cp110_comphy_xfi_power_on(comphy_base,
+                                                     comphy_index,
+                                                     comphy_mode);
+               break;
+       case (COMPHY_PCIE_MODE):
+               err = mvebu_cp110_comphy_pcie_power_on(comphy_base,
+                                                      comphy_index,
+                                                      comphy_mode);
+               break;
+       case (COMPHY_RXAUI_MODE):
+               err = mvebu_cp110_comphy_rxaui_power_on(comphy_base,
+                                                       comphy_index,
+                                                       comphy_mode);
+       case (COMPHY_USB3H_MODE):
+       case (COMPHY_USB3D_MODE):
+               err = mvebu_cp110_comphy_usb3_power_on(comphy_base,
+                                                      comphy_index,
+                                                      comphy_mode);
+               break;
+       case (COMPHY_AP_MODE):
+               err = mvebu_cp110_comphy_ap_power_on(comphy_base, comphy_index);
+               break;
+       default:
+               ERROR("comphy%lld: unsupported comphy mode\n", comphy_index);
+               err = -EINVAL;
+               break;
+       }
+
+       debug_exit();
+
+       return err;
+}
+
+int mvebu_cp110_comphy_power_off(uint64_t comphy_base, uint64_t comphy_index)
+{
+       uintptr_t sd_ip_addr, comphy_ip_addr;
+       uint32_t mask, data;
+
+       debug_enter();
+
+       sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
+                            comphy_index);
+       comphy_ip_addr = COMPHY_ADDR(comphy_base, comphy_index);
+
+       /* Hard reset the comphy, for Ethernet modes and Sata */
+       mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK;
+       data = 0x0 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
+       data |= 0x0 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET;
+       mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK;
+       data |= 0x0 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET;
+       reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
+
+       /* PCIe reset */
+       spin_lock(&cp110_mac_reset_lock);
+
+       /* The mvebu_cp110_comphy_power_off will be called only from Linux (to
+        * override settings done by bootloader) and it will be relevant only
+        * to PCIe (called before check if to skip pcie power off or not).
+        */
+       data = mmio_read_32(SYS_CTRL_FROM_COMPHY_ADDR(comphy_base) +
+                                                SYS_CTRL_UINIT_SOFT_RESET_REG);
+       switch (comphy_index) {
+       case COMPHY_LANE0:
+               data &= ~PCIE_MAC_RESET_MASK_PORT0;
+               break;
+       case COMPHY_LANE4:
+               data &= ~PCIE_MAC_RESET_MASK_PORT1;
+               break;
+       case COMPHY_LANE5:
+               data &= ~PCIE_MAC_RESET_MASK_PORT2;
+               break;
+       }
+
+       mmio_write_32(SYS_CTRL_FROM_COMPHY_ADDR(comphy_base) +
+                                          SYS_CTRL_UINIT_SOFT_RESET_REG, data);
+       spin_unlock(&cp110_mac_reset_lock);
+
+       /* Hard reset the comphy, for PCIe and usb3 */
+       mask = COMMON_PHY_CFG1_PWR_ON_RESET_MASK;
+       data = 0x0 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET;
+       mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK;
+       data |= 0x0 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET;
+       reg_set(comphy_ip_addr + COMMON_PHY_CFG1_REG, data, mask);
+
+       /* Clear comphy PHY and PIPE selector, can't rely on previous config. */
+       mvebu_cp110_comphy_clr_phy_selector(comphy_base, comphy_index);
+       mvebu_cp110_comphy_clr_pipe_selector(comphy_base, comphy_index);
+
+       debug_exit();
+
+       return 0;
+}
diff --git a/drivers/marvell/comphy/phy-comphy-cp110.h b/drivers/marvell/comphy/phy-comphy-cp110.h
new file mode 100644 (file)
index 0000000..ada6aec
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* Marvell CP110 SoC COMPHY unit driver */
+
+int mvebu_cp110_comphy_is_pll_locked(uint64_t comphy_base,
+                                    uint64_t comphy_index);
+int mvebu_cp110_comphy_power_off(uint64_t comphy_base,
+                                uint64_t comphy_index);
+int mvebu_cp110_comphy_power_on(uint64_t comphy_base,
+                               uint64_t comphy_index, uint64_t comphy_mode);
+int mvebu_cp110_comphy_xfi_rx_training(uint64_t comphy_base,
+                                      uint8_t comphy_index);
+int mvebu_cp110_comphy_digital_reset(uint64_t comphy_base, uint8_t comphy_index,
+                                    uint32_t comphy_mode, uint32_t command);
diff --git a/drivers/marvell/gwin.c b/drivers/marvell/gwin.c
new file mode 100644 (file)
index 0000000..2b17f35
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* GWIN unit device driver for Marvell AP810 SoC */
+
+#include <a8k_common.h>
+#include <debug.h>
+#include <gwin.h>
+#include <mmio.h>
+#include <mvebu.h>
+#include <mvebu_def.h>
+
+#if LOG_LEVEL >= LOG_LEVEL_INFO
+#define DEBUG_ADDR_MAP
+#endif
+
+/* common defines */
+#define WIN_ENABLE_BIT                 (0x1)
+#define WIN_TARGET_MASK                        (0xF)
+#define WIN_TARGET_SHIFT               (0x8)
+#define WIN_TARGET(tgt)                        (((tgt) & WIN_TARGET_MASK) \
+                                       << WIN_TARGET_SHIFT)
+
+/* Bits[43:26] of the physical address are the window base,
+ * which is aligned to 64MB
+ */
+#define ADDRESS_RSHIFT                 (26)
+#define ADDRESS_LSHIFT                 (10)
+#define GWIN_ALIGNMENT_64M             (0x4000000)
+
+/* AP registers */
+#define GWIN_CR_OFFSET(ap, win)                (MVEBU_GWIN_BASE(ap) + 0x0 + \
+                                               (0x10 * (win)))
+#define GWIN_ALR_OFFSET(ap, win)       (MVEBU_GWIN_BASE(ap) + 0x8 + \
+                                               (0x10 * (win)))
+#define GWIN_AHR_OFFSET(ap, win)       (MVEBU_GWIN_BASE(ap) + 0xc + \
+                                               (0x10 * (win)))
+
+#define CCU_GRU_CR_OFFSET(ap)          (MVEBU_CCU_GRU_BASE(ap))
+#define CCR_GRU_CR_GWIN_MBYPASS                (1 << 1)
+
+static void gwin_check(struct addr_map_win *win)
+{
+       /* The base is always 64M aligned */
+       if (IS_NOT_ALIGN(win->base_addr, GWIN_ALIGNMENT_64M)) {
+               win->base_addr &= ~(GWIN_ALIGNMENT_64M - 1);
+               NOTICE("%s: Align the base address to 0x%llx\n",
+                      __func__, win->base_addr);
+       }
+
+       /* size parameter validity check */
+       if (IS_NOT_ALIGN(win->win_size, GWIN_ALIGNMENT_64M)) {
+               win->win_size = ALIGN_UP(win->win_size, GWIN_ALIGNMENT_64M);
+               NOTICE("%s: Aligning window size to 0x%llx\n",
+                      __func__, win->win_size);
+       }
+}
+
+static void gwin_enable_window(int ap_index, struct addr_map_win *win,
+                              uint32_t win_num)
+{
+       uint32_t alr, ahr;
+       uint64_t end_addr;
+
+       if ((win->target_id & WIN_TARGET_MASK) != win->target_id) {
+               ERROR("target ID = %d, is invalid\n", win->target_id);
+               return;
+       }
+
+       /* calculate 64bit end-address */
+       end_addr = (win->base_addr + win->win_size - 1);
+
+       alr = (uint32_t)((win->base_addr >> ADDRESS_RSHIFT) << ADDRESS_LSHIFT);
+       ahr = (uint32_t)((end_addr >> ADDRESS_RSHIFT) << ADDRESS_LSHIFT);
+
+       /* write start address and end address for GWIN */
+       mmio_write_32(GWIN_ALR_OFFSET(ap_index, win_num), alr);
+       mmio_write_32(GWIN_AHR_OFFSET(ap_index, win_num), ahr);
+
+       /* write the target ID and enable the window */
+       mmio_write_32(GWIN_CR_OFFSET(ap_index, win_num),
+                     WIN_TARGET(win->target_id) | WIN_ENABLE_BIT);
+}
+
+static void gwin_disable_window(int ap_index, uint32_t win_num)
+{
+       uint32_t win_reg;
+
+       win_reg = mmio_read_32(GWIN_CR_OFFSET(ap_index, win_num));
+       win_reg &= ~WIN_ENABLE_BIT;
+       mmio_write_32(GWIN_CR_OFFSET(ap_index, win_num), win_reg);
+}
+
+/* Insert/Remove temporary window for using the out-of reset default
+ * CPx base address to access the CP configuration space prior to
+ * the further base address update in accordance with address mapping
+ * design.
+ *
+ * NOTE: Use the same window array for insertion and removal of
+ *       temporary windows.
+ */
+void gwin_temp_win_insert(int ap_index, struct addr_map_win *win, int size)
+{
+       uint32_t win_id;
+
+       for (int i = 0; i < size; i++) {
+               win_id = MVEBU_GWIN_MAX_WINS - i - 1;
+               gwin_check(win);
+               gwin_enable_window(ap_index, win, win_id);
+               win++;
+       }
+}
+
+/*
+ * NOTE: Use the same window array for insertion and removal of
+ *       temporary windows.
+ */
+void gwin_temp_win_remove(int ap_index, struct addr_map_win *win, int size)
+{
+       uint32_t win_id;
+
+       for (int i = 0; i < size; i++) {
+               uint64_t base;
+               uint32_t target;
+
+               win_id = MVEBU_GWIN_MAX_WINS - i - 1;
+
+               target = mmio_read_32(GWIN_CR_OFFSET(ap_index, win_id));
+               target >>= WIN_TARGET_SHIFT;
+               target &= WIN_TARGET_MASK;
+
+               base = mmio_read_32(GWIN_ALR_OFFSET(ap_index, win_id));
+               base >>= ADDRESS_LSHIFT;
+               base <<= ADDRESS_RSHIFT;
+
+               if (win->target_id != target) {
+                       ERROR("%s: Trying to remove bad window-%d!\n",
+                             __func__, win_id);
+                       continue;
+               }
+               gwin_disable_window(ap_index, win_id);
+               win++;
+       }
+}
+
+#ifdef DEBUG_ADDR_MAP
+static void dump_gwin(int ap_index)
+{
+       uint32_t win_num;
+
+       /* Dump all GWIN windows */
+       tf_printf("\tbank  target     start              end\n");
+       tf_printf("\t----------------------------------------------------\n");
+       for (win_num = 0; win_num < MVEBU_GWIN_MAX_WINS; win_num++) {
+               uint32_t cr;
+               uint64_t alr, ahr;
+
+               cr  = mmio_read_32(GWIN_CR_OFFSET(ap_index, win_num));
+               /* Window enabled */
+               if (cr & WIN_ENABLE_BIT) {
+                       alr = mmio_read_32(GWIN_ALR_OFFSET(ap_index, win_num));
+                       alr = (alr >> ADDRESS_LSHIFT) << ADDRESS_RSHIFT;
+                       ahr = mmio_read_32(GWIN_AHR_OFFSET(ap_index, win_num));
+                       ahr = (ahr >> ADDRESS_LSHIFT) << ADDRESS_RSHIFT;
+                       tf_printf("\tgwin   %d     0x%016llx 0x%016llx\n",
+                                 (cr >> 8) & 0xF, alr, ahr);
+               }
+       }
+}
+#endif
+
+int init_gwin(int ap_index)
+{
+       struct addr_map_win *win;
+       uint32_t win_id;
+       uint32_t win_count;
+       uint32_t win_reg;
+
+       INFO("Initializing GWIN Address decoding\n");
+
+       /* Get the array of the windows and its size */
+       marvell_get_gwin_memory_map(ap_index, &win, &win_count);
+       if (win_count <= 0) {
+               INFO("no windows configurations found\n");
+               return 0;
+       }
+
+       if (win_count > MVEBU_GWIN_MAX_WINS) {
+               ERROR("number of windows is bigger than %d\n",
+                     MVEBU_GWIN_MAX_WINS);
+               return 0;
+       }
+
+       /* disable all windows */
+       for (win_id = 0; win_id < MVEBU_GWIN_MAX_WINS; win_id++)
+               gwin_disable_window(ap_index, win_id);
+
+       /* enable relevant windows */
+       for (win_id = 0; win_id < win_count; win_id++, win++) {
+               gwin_check(win);
+               gwin_enable_window(ap_index, win, win_id);
+       }
+
+       /* GWIN Miss feature has not verified, therefore any access towards
+        * remote AP should be accompanied with proper configuration to
+        * GWIN registers group and therefore the GWIN Miss feature
+        * should be set into Bypass mode, need to make sure all GWIN regions
+        * are defined correctly that will assure no GWIN miss occurrance
+        * JIRA-AURORA2-1630
+        */
+       INFO("Update GWIN miss bypass\n");
+       win_reg = mmio_read_32(CCU_GRU_CR_OFFSET(ap_index));
+       win_reg |= CCR_GRU_CR_GWIN_MBYPASS;
+       mmio_write_32(CCU_GRU_CR_OFFSET(ap_index), win_reg);
+
+#ifdef DEBUG_ADDR_MAP
+       dump_gwin(ap_index);
+#endif
+
+       INFO("Done GWIN Address decoding Initializing\n");
+
+       return 0;
+}
diff --git a/drivers/marvell/i2c/a8k_i2c.c b/drivers/marvell/i2c/a8k_i2c.c
new file mode 100644 (file)
index 0000000..737dd0a
--- /dev/null
@@ -0,0 +1,613 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* This driver provides I2C support for Marvell A8K and compatible SoCs */
+
+#include <a8k_i2c.h>
+#include <debug.h>
+#include <delay_timer.h>
+#include <errno.h>
+#include <mmio.h>
+#include <mvebu_def.h>
+
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+#define DEBUG_I2C
+#endif
+
+#define CONFIG_SYS_TCLK                        250000000
+#define CONFIG_SYS_I2C_SPEED           100000
+#define CONFIG_SYS_I2C_SLAVE           0x0
+#define I2C_TIMEOUT_VALUE              0x500
+#define I2C_MAX_RETRY_CNT              1000
+#define I2C_CMD_WRITE                  0x0
+#define I2C_CMD_READ                   0x1
+
+#define I2C_DATA_ADDR_7BIT_OFFS                0x1
+#define I2C_DATA_ADDR_7BIT_MASK                (0xFF << I2C_DATA_ADDR_7BIT_OFFS)
+
+#define I2C_CONTROL_ACK                        0x00000004
+#define I2C_CONTROL_IFLG               0x00000008
+#define I2C_CONTROL_STOP               0x00000010
+#define I2C_CONTROL_START              0x00000020
+#define I2C_CONTROL_TWSIEN             0x00000040
+#define I2C_CONTROL_INTEN              0x00000080
+
+#define I2C_STATUS_START                       0x08
+#define I2C_STATUS_REPEATED_START              0x10
+#define I2C_STATUS_ADDR_W_ACK                  0x18
+#define I2C_STATUS_DATA_W_ACK                  0x28
+#define I2C_STATUS_LOST_ARB_DATA_ADDR_TRANSFER 0x38
+#define I2C_STATUS_ADDR_R_ACK                  0x40
+#define I2C_STATUS_DATA_R_ACK                  0x50
+#define I2C_STATUS_DATA_R_NAK                  0x58
+#define I2C_STATUS_LOST_ARB_GENERAL_CALL       0x78
+#define I2C_STATUS_IDLE                                0xF8
+
+#define I2C_UNSTUCK_TRIGGER                    0x1
+#define I2C_UNSTUCK_ONGOING                    0x2
+#define I2C_UNSTUCK_ERROR                      0x4
+struct  marvell_i2c_regs {
+       uint32_t slave_address;
+       uint32_t data;
+       uint32_t control;
+       union {
+               uint32_t status;        /* when reading */
+               uint32_t baudrate;      /* when writing */
+       } u;
+       uint32_t xtnd_slave_addr;
+       uint32_t reserved[2];
+       uint32_t soft_reset;
+       uint8_t  reserved2[0xa0 - 0x20];
+       uint32_t unstuck;
+};
+
+static struct marvell_i2c_regs *base;
+
+static int marvell_i2c_lost_arbitration(uint32_t *status)
+{
+       *status = mmio_read_32((uintptr_t)&base->u.status);
+       if ((*status == I2C_STATUS_LOST_ARB_DATA_ADDR_TRANSFER) ||
+           (*status == I2C_STATUS_LOST_ARB_GENERAL_CALL))
+               return -EAGAIN;
+
+       return 0;
+}
+
+static void marvell_i2c_interrupt_clear(void)
+{
+       uint32_t reg;
+
+       reg = mmio_read_32((uintptr_t)&base->control);
+       reg &= ~(I2C_CONTROL_IFLG);
+       mmio_write_32((uintptr_t)&base->control, reg);
+       /* Wait for 1 us for the clear to take effect */
+       udelay(1);
+}
+
+static int marvell_i2c_interrupt_get(void)
+{
+       uint32_t reg;
+
+       /* get the interrupt flag bit */
+       reg = mmio_read_32((uintptr_t)&base->control);
+       reg &= I2C_CONTROL_IFLG;
+       return reg && I2C_CONTROL_IFLG;
+}
+
+static int marvell_i2c_wait_interrupt(void)
+{
+       uint32_t timeout = 0;
+
+       while (!marvell_i2c_interrupt_get() && (timeout++ < I2C_TIMEOUT_VALUE))
+               ;
+       if (timeout >= I2C_TIMEOUT_VALUE)
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
+static int marvell_i2c_start_bit_set(void)
+{
+       int is_int_flag = 0;
+       uint32_t status;
+
+       if (marvell_i2c_interrupt_get())
+               is_int_flag = 1;
+
+       /* set start bit */
+       mmio_write_32((uintptr_t)&base->control,
+                     mmio_read_32((uintptr_t)&base->control) |
+                     I2C_CONTROL_START);
+
+       /* in case that the int flag was set before i.e. repeated start bit */
+       if (is_int_flag) {
+               VERBOSE("%s: repeated start Bit\n", __func__);
+               marvell_i2c_interrupt_clear();
+       }
+
+       if (marvell_i2c_wait_interrupt()) {
+               ERROR("Start clear bit timeout\n");
+               return -ETIMEDOUT;
+       }
+
+       /* check that start bit went down */
+       if ((mmio_read_32((uintptr_t)&base->control) &
+           I2C_CONTROL_START) != 0) {
+               ERROR("Start bit didn't went down\n");
+               return -EPERM;
+       }
+
+       /* check the status */
+       if (marvell_i2c_lost_arbitration(&status)) {
+               ERROR("%s - %d: Lost arbitration, got status %x\n",
+                     __func__, __LINE__, status);
+               return -EAGAIN;
+       }
+       if ((status != I2C_STATUS_START) &&
+           (status != I2C_STATUS_REPEATED_START)) {
+               ERROR("Got status %x after enable start bit.\n", status);
+               return -EPERM;
+       }
+
+       return 0;
+}
+
+static int marvell_i2c_stop_bit_set(void)
+{
+       int timeout;
+       uint32_t status;
+
+       /* Generate stop bit */
+       mmio_write_32((uintptr_t)&base->control,
+                     mmio_read_32((uintptr_t)&base->control) |
+                     I2C_CONTROL_STOP);
+       marvell_i2c_interrupt_clear();
+
+       timeout = 0;
+       /* Read control register, check the control stop bit */
+       while ((mmio_read_32((uintptr_t)&base->control) & I2C_CONTROL_STOP) &&
+              (timeout++ < I2C_TIMEOUT_VALUE))
+               ;
+       if (timeout >= I2C_TIMEOUT_VALUE) {
+               ERROR("Stop bit didn't went down\n");
+               return -ETIMEDOUT;
+       }
+
+       /* check that stop bit went down */
+       if ((mmio_read_32((uintptr_t)&base->control) & I2C_CONTROL_STOP) != 0) {
+               ERROR("Stop bit didn't went down\n");
+               return -EPERM;
+       }
+
+       /* check the status */
+       if (marvell_i2c_lost_arbitration(&status)) {
+               ERROR("%s - %d: Lost arbitration, got status %x\n",
+                     __func__, __LINE__, status);
+               return -EAGAIN;
+       }
+       if (status != I2C_STATUS_IDLE) {
+               ERROR("Got status %x after enable stop bit.\n", status);
+               return -EPERM;
+       }
+
+       return 0;
+}
+
+static int marvell_i2c_address_set(uint8_t chain, int command)
+{
+       uint32_t reg, status;
+
+       reg = (chain << I2C_DATA_ADDR_7BIT_OFFS) & I2C_DATA_ADDR_7BIT_MASK;
+       reg |= command;
+       mmio_write_32((uintptr_t)&base->data, reg);
+       udelay(1);
+
+       marvell_i2c_interrupt_clear();
+
+       if (marvell_i2c_wait_interrupt()) {
+               ERROR("Start clear bit timeout\n");
+               return -ETIMEDOUT;
+       }
+
+       /* check the status */
+       if (marvell_i2c_lost_arbitration(&status)) {
+               ERROR("%s - %d: Lost arbitration, got status %x\n",
+                     __func__, __LINE__, status);
+               return -EAGAIN;
+       }
+       if (((status != I2C_STATUS_ADDR_R_ACK) && (command == I2C_CMD_READ)) ||
+          ((status != I2C_STATUS_ADDR_W_ACK) && (command == I2C_CMD_WRITE))) {
+               /* only in debug, since in boot we try to read the SPD
+                * of both DRAM, and we don't want error messages in cas
+                * DIMM doesn't exist.
+                */
+               INFO("%s: ERROR - status %x addr in %s mode.\n", __func__,
+                    status, (command == I2C_CMD_WRITE) ? "Write" : "Read");
+               return -EPERM;
+       }
+
+       return 0;
+}
+
+/*
+ * The I2C module contains a clock divider to generate the SCL clock.
+ * This function calculates and sets the <N> and <M> fields in the I2C Baud
+ * Rate Register (t=01) to obtain given 'requested_speed'.
+ * The requested_speed will be equal to:
+ * CONFIG_SYS_TCLK / (10 * (M + 1) * (2 << N))
+ * Where M is the value represented by bits[6:3] and N is the value represented
+ * by bits[2:0] of "I2C Baud Rate Register".
+ * Therefore max M which can be set is 16 (2^4) and max N is 8 (2^3). So the
+ * lowest possible baudrate is:
+ * CONFIG_SYS_TCLK/(10 * (16 +1) * (2 << 8), which equals to:
+ * CONFIG_SYS_TCLK/87040. Assuming that CONFIG_SYS_TCLK=250MHz, the lowest
+ * possible frequency is ~2,872KHz.
+ */
+static unsigned int marvell_i2c_bus_speed_set(unsigned int requested_speed)
+{
+       unsigned int n, m, freq, margin, min_margin = 0xffffffff;
+       unsigned int actual_n = 0, actual_m = 0;
+       int val;
+
+       /* Calculate N and M for the TWSI clock baud rate */
+       for (n = 0; n < 8; n++) {
+               for (m = 0; m < 16; m++) {
+                       freq = CONFIG_SYS_TCLK / (10 * (m + 1) * (2 << n));
+                       val = requested_speed - freq;
+                       margin = (val > 0) ? val : -val;
+
+                       if ((freq <= requested_speed) &&
+                           (margin < min_margin)) {
+                               min_margin = margin;
+                               actual_n = n;
+                               actual_m = m;
+                       }
+               }
+       }
+       VERBOSE("%s: actual_n = %u, actual_m = %u\n",
+               __func__, actual_n, actual_m);
+       /* Set the baud rate */
+       mmio_write_32((uintptr_t)&base->u.baudrate, (actual_m << 3) | actual_n);
+
+       return 0;
+}
+
+#ifdef DEBUG_I2C
+static int marvell_i2c_probe(uint8_t chip)
+{
+       int ret = 0;
+
+       ret = marvell_i2c_start_bit_set();
+       if (ret != 0) {
+               marvell_i2c_stop_bit_set();
+               ERROR("%s - %d: %s", __func__, __LINE__,
+                     "marvell_i2c_start_bit_set failed\n");
+               return -EPERM;
+       }
+
+       ret = marvell_i2c_address_set(chip, I2C_CMD_WRITE);
+       if (ret != 0) {
+               marvell_i2c_stop_bit_set();
+               ERROR("%s - %d: %s", __func__, __LINE__,
+                     "marvell_i2c_address_set failed\n");
+               return -EPERM;
+       }
+
+       marvell_i2c_stop_bit_set();
+
+       VERBOSE("%s: successful I2C probe\n", __func__);
+
+       return ret;
+}
+#endif
+
+/* regular i2c transaction */
+static int marvell_i2c_data_receive(uint8_t *p_block, uint32_t block_size)
+{
+       uint32_t reg, status, block_size_read = block_size;
+
+       /* Wait for cause interrupt */
+       if (marvell_i2c_wait_interrupt()) {
+               ERROR("Start clear bit timeout\n");
+               return -ETIMEDOUT;
+       }
+       while (block_size_read) {
+               if (block_size_read == 1) {
+                       reg = mmio_read_32((uintptr_t)&base->control);
+                       reg &= ~(I2C_CONTROL_ACK);
+                       mmio_write_32((uintptr_t)&base->control, reg);
+               }
+               marvell_i2c_interrupt_clear();
+
+               if (marvell_i2c_wait_interrupt()) {
+                       ERROR("Start clear bit timeout\n");
+                       return -ETIMEDOUT;
+               }
+               /* check the status */
+               if (marvell_i2c_lost_arbitration(&status)) {
+                       ERROR("%s - %d: Lost arbitration, got status %x\n",
+                             __func__, __LINE__, status);
+                       return -EAGAIN;
+               }
+               if ((status != I2C_STATUS_DATA_R_ACK) &&
+                   (block_size_read != 1)) {
+                       ERROR("Status %x in read transaction\n", status);
+                       return -EPERM;
+               }
+               if ((status != I2C_STATUS_DATA_R_NAK) &&
+                   (block_size_read == 1)) {
+                       ERROR("Status %x in Rd Terminate\n", status);
+                       return -EPERM;
+               }
+
+               /* read the data */
+               *p_block = (uint8_t) mmio_read_32((uintptr_t)&base->data);
+               VERBOSE("%s: place %d read %x\n", __func__,
+                       block_size - block_size_read, *p_block);
+               p_block++;
+               block_size_read--;
+       }
+
+       return 0;
+}
+
+static int marvell_i2c_data_transmit(uint8_t *p_block, uint32_t block_size)
+{
+       uint32_t status, block_size_write = block_size;
+
+       if (marvell_i2c_wait_interrupt()) {
+               ERROR("Start clear bit timeout\n");
+               return -ETIMEDOUT;
+       }
+
+       while (block_size_write) {
+               /* write the data */
+               mmio_write_32((uintptr_t)&base->data, (uint32_t) *p_block);
+               VERBOSE("%s: index = %d, data = %x\n", __func__,
+                       block_size - block_size_write, *p_block);
+               p_block++;
+               block_size_write--;
+
+               marvell_i2c_interrupt_clear();
+
+               if (marvell_i2c_wait_interrupt()) {
+                       ERROR("Start clear bit timeout\n");
+                       return -ETIMEDOUT;
+               }
+
+               /* check the status */
+               if (marvell_i2c_lost_arbitration(&status)) {
+                       ERROR("%s - %d: Lost arbitration, got status %x\n",
+                             __func__, __LINE__, status);
+                       return -EAGAIN;
+               }
+               if (status != I2C_STATUS_DATA_W_ACK) {
+                       ERROR("Status %x in write transaction\n", status);
+                       return -EPERM;
+               }
+       }
+
+       return 0;
+}
+
+static int marvell_i2c_target_offset_set(uint8_t chip, uint32_t addr, int alen)
+{
+       uint8_t off_block[2];
+       uint32_t off_size;
+
+       if (alen == 2) { /* 2-byte addresses support */
+               off_block[0] = (addr >> 8) & 0xff;
+               off_block[1] = addr & 0xff;
+               off_size = 2;
+       } else { /* 1-byte addresses support */
+               off_block[0] = addr & 0xff;
+               off_size = 1;
+       }
+       VERBOSE("%s: off_size = %x addr1 = %x addr2 = %x\n", __func__,
+               off_size, off_block[0], off_block[1]);
+       return marvell_i2c_data_transmit(off_block, off_size);
+}
+
+static int marvell_i2c_unstuck(int ret)
+{
+       uint32_t v;
+
+       if (ret != -ETIMEDOUT)
+               return ret;
+       VERBOSE("Trying to \"unstuck i2c\"... ");
+       i2c_init(base);
+       mmio_write_32((uintptr_t)&base->unstuck, I2C_UNSTUCK_TRIGGER);
+       do {
+               v = mmio_read_32((uintptr_t)&base->unstuck);
+       } while (v & I2C_UNSTUCK_ONGOING);
+
+       if (v & I2C_UNSTUCK_ERROR) {
+               VERBOSE("failed - soft reset i2c\n");
+               ret = -EPERM;
+       } else {
+               VERBOSE("ok\n");
+               i2c_init(base);
+               ret = -EAGAIN;
+       }
+       return ret;
+}
+
+/*
+ * API Functions
+ */
+void i2c_init(void *i2c_base)
+{
+       /* For I2C speed and slave address, now we do not set them since
+        * we just provide the working speed and slave address in plat_def.h
+        * for i2c_init
+        */
+       base = (struct marvell_i2c_regs *)i2c_base;
+
+       /* Reset the I2C logic */
+       mmio_write_32((uintptr_t)&base->soft_reset, 0);
+
+       udelay(200);
+
+       marvell_i2c_bus_speed_set(CONFIG_SYS_I2C_SPEED);
+
+       /* Enable the I2C and slave */
+       mmio_write_32((uintptr_t)&base->control,
+                     I2C_CONTROL_TWSIEN | I2C_CONTROL_ACK);
+
+       /* set the I2C slave address */
+       mmio_write_32((uintptr_t)&base->xtnd_slave_addr, 0);
+       mmio_write_32((uintptr_t)&base->slave_address, CONFIG_SYS_I2C_SLAVE);
+
+       /* unmask I2C interrupt */
+       mmio_write_32((uintptr_t)&base->control,
+                     mmio_read_32((uintptr_t)&base->control) |
+                     I2C_CONTROL_INTEN);
+
+       udelay(10);
+}
+
+/*
+ * i2c_read: - Read multiple bytes from an i2c device
+ *
+ * The higher level routines take into account that this function is only
+ * called with len < page length of the device (see configuration file)
+ *
+ * @chip:      address of the chip which is to be read
+ * @addr:      i2c data address within the chip
+ * @alen:      length of the i2c data address (1..2 bytes)
+ * @buffer:    where to write the data
+ * @len:       how much byte do we want to read
+ * @return:    0 in case of success
+ */
+int i2c_read(uint8_t chip, uint32_t addr, int alen, uint8_t *buffer, int len)
+{
+       int ret = 0;
+       uint32_t counter = 0;
+
+#ifdef DEBUG_I2C
+       marvell_i2c_probe(chip);
+#endif
+
+       do {
+               if (ret != -EAGAIN && ret) {
+                       ERROR("i2c transaction failed, after %d retries\n",
+                             counter);
+                       marvell_i2c_stop_bit_set();
+                       return ret;
+               }
+
+               /* wait for 1 us for the interrupt clear to take effect */
+               if (counter > 0)
+                       udelay(1);
+               counter++;
+
+               ret = marvell_i2c_start_bit_set();
+               if (ret) {
+                       ret = marvell_i2c_unstuck(ret);
+                       continue;
+               }
+
+               /* if EEPROM device */
+               if (alen != 0) {
+                       ret = marvell_i2c_address_set(chip, I2C_CMD_WRITE);
+                       if (ret)
+                               continue;
+
+                       ret = marvell_i2c_target_offset_set(chip, addr, alen);
+                       if (ret)
+                               continue;
+                       ret = marvell_i2c_start_bit_set();
+                       if (ret)
+                               continue;
+               }
+
+               ret =  marvell_i2c_address_set(chip, I2C_CMD_READ);
+               if (ret)
+                       continue;
+
+               ret = marvell_i2c_data_receive(buffer, len);
+               if (ret)
+                       continue;
+
+               ret =  marvell_i2c_stop_bit_set();
+       } while ((ret == -EAGAIN) && (counter < I2C_MAX_RETRY_CNT));
+
+       if (counter == I2C_MAX_RETRY_CNT) {
+               ERROR("I2C transactions failed, got EAGAIN %d times\n",
+                     I2C_MAX_RETRY_CNT);
+               ret = -EPERM;
+       }
+       mmio_write_32((uintptr_t)&base->control,
+                     mmio_read_32((uintptr_t)&base->control) |
+                     I2C_CONTROL_ACK);
+
+       udelay(1);
+       return ret;
+}
+
+/*
+ * i2c_write: -  Write multiple bytes to an i2c device
+ *
+ * The higher level routines take into account that this function is only
+ * called with len < page length of the device (see configuration file)
+ *
+ * @chip:      address of the chip which is to be written
+ * @addr:      i2c data address within the chip
+ * @alen:      length of the i2c data address (1..2 bytes)
+ * @buffer:    where to find the data to be written
+ * @len:       how much byte do we want to read
+ * @return:    0 in case of success
+ */
+int i2c_write(uint8_t chip, uint32_t addr, int alen, uint8_t *buffer, int len)
+{
+       int ret = 0;
+       uint32_t counter = 0;
+
+       do {
+               if (ret != -EAGAIN && ret) {
+                       ERROR("i2c transaction failed\n");
+                       marvell_i2c_stop_bit_set();
+                       return ret;
+               }
+               /* wait for 1 us for the interrupt clear to take effect */
+               if (counter > 0)
+                       udelay(1);
+               counter++;
+
+               ret = marvell_i2c_start_bit_set();
+               if (ret) {
+                       ret = marvell_i2c_unstuck(ret);
+                       continue;
+               }
+
+               ret = marvell_i2c_address_set(chip, I2C_CMD_WRITE);
+               if (ret)
+                       continue;
+
+               /* if EEPROM device */
+               if (alen != 0) {
+                       ret = marvell_i2c_target_offset_set(chip, addr, alen);
+                       if (ret)
+                               continue;
+               }
+
+               ret = marvell_i2c_data_transmit(buffer, len);
+               if (ret)
+                       continue;
+
+               ret = marvell_i2c_stop_bit_set();
+       } while ((ret == -EAGAIN) && (counter < I2C_MAX_RETRY_CNT));
+
+       if (counter == I2C_MAX_RETRY_CNT) {
+               ERROR("I2C transactions failed, got EAGAIN %d times\n",
+                     I2C_MAX_RETRY_CNT);
+               ret = -EPERM;
+       }
+
+       udelay(1);
+       return ret;
+}
diff --git a/drivers/marvell/io_win.c b/drivers/marvell/io_win.c
new file mode 100644 (file)
index 0000000..701dbb8
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* IO Window unit device driver for Marvell AP807, AP807 and AP810 SoCs */
+
+#include <a8k_common.h>
+#include <debug.h>
+#include <io_win.h>
+#include <mmio.h>
+#include <mvebu.h>
+#include <mvebu_def.h>
+
+#if LOG_LEVEL >= LOG_LEVEL_INFO
+#define DEBUG_ADDR_MAP
+#endif
+
+/* common defines */
+#define WIN_ENABLE_BIT                 (0x1)
+/* Physical address of the base of the window = {Addr[19:0],20`h0} */
+#define ADDRESS_SHIFT                  (20 - 4)
+#define ADDRESS_MASK                   (0xFFFFFFF0)
+#define IO_WIN_ALIGNMENT_1M            (0x100000)
+#define IO_WIN_ALIGNMENT_64K           (0x10000)
+
+/* AP registers */
+#define IO_WIN_ALR_OFFSET(ap, win)     (MVEBU_IO_WIN_BASE(ap) + 0x0 + \
+                                               (0x10 * win))
+#define IO_WIN_AHR_OFFSET(ap, win)     (MVEBU_IO_WIN_BASE(ap) + 0x8 + \
+                                               (0x10 * win))
+#define IO_WIN_CR_OFFSET(ap, win)      (MVEBU_IO_WIN_BASE(ap) + 0xC + \
+                                               (0x10 * win))
+
+/* For storage of CR, ALR, AHR abd GCR */
+static uint32_t io_win_regs_save[MVEBU_IO_WIN_MAX_WINS * 3 + 1];
+
+static void io_win_check(struct addr_map_win *win)
+{
+       /* for IO The base is always 1M aligned */
+       /* check if address is aligned to 1M */
+       if (IS_NOT_ALIGN(win->base_addr, IO_WIN_ALIGNMENT_1M)) {
+               win->base_addr = ALIGN_UP(win->base_addr, IO_WIN_ALIGNMENT_1M);
+               NOTICE("%s: Align up the base address to 0x%llx\n",
+                      __func__, win->base_addr);
+       }
+
+       /* size parameter validity check */
+       if (IS_NOT_ALIGN(win->win_size, IO_WIN_ALIGNMENT_1M)) {
+               win->win_size = ALIGN_UP(win->win_size, IO_WIN_ALIGNMENT_1M);
+               NOTICE("%s: Aligning size to 0x%llx\n",
+                      __func__, win->win_size);
+       }
+}
+
+static void io_win_enable_window(int ap_index, struct addr_map_win *win,
+                                uint32_t win_num)
+{
+       uint32_t alr, ahr;
+       uint64_t end_addr;
+
+       if (win->target_id < 0 || win->target_id >= MVEBU_IO_WIN_MAX_WINS) {
+               ERROR("target ID = %d, is invalid\n", win->target_id);
+               return;
+       }
+
+       if ((win_num == 0) || (win_num > MVEBU_IO_WIN_MAX_WINS)) {
+               ERROR("Enabling wrong IOW window %d!\n", win_num);
+               return;
+       }
+
+       /* calculate the end-address */
+       end_addr = (win->base_addr + win->win_size - 1);
+
+       alr = (uint32_t)((win->base_addr >> ADDRESS_SHIFT) & ADDRESS_MASK);
+       alr |= WIN_ENABLE_BIT;
+       ahr = (uint32_t)((end_addr >> ADDRESS_SHIFT) & ADDRESS_MASK);
+
+       /* write start address and end address for IO window */
+       mmio_write_32(IO_WIN_ALR_OFFSET(ap_index, win_num), alr);
+       mmio_write_32(IO_WIN_AHR_OFFSET(ap_index, win_num), ahr);
+
+       /* write window target */
+       mmio_write_32(IO_WIN_CR_OFFSET(ap_index, win_num), win->target_id);
+}
+
+static void io_win_disable_window(int ap_index, uint32_t win_num)
+{
+       uint32_t win_reg;
+
+       if ((win_num == 0) || (win_num > MVEBU_IO_WIN_MAX_WINS)) {
+               ERROR("Disabling wrong IOW window %d!\n", win_num);
+               return;
+       }
+
+       win_reg = mmio_read_32(IO_WIN_ALR_OFFSET(ap_index, win_num));
+       win_reg &= ~WIN_ENABLE_BIT;
+       mmio_write_32(IO_WIN_ALR_OFFSET(ap_index, win_num), win_reg);
+}
+
+/* Insert/Remove temporary window for using the out-of reset default
+ * CPx base address to access the CP configuration space prior to
+ * the further base address update in accordance with address mapping
+ * design.
+ *
+ * NOTE: Use the same window array for insertion and removal of
+ *       temporary windows.
+ */
+void iow_temp_win_insert(int ap_index, struct addr_map_win *win, int size)
+{
+       uint32_t win_id;
+
+       for (int i = 0; i < size; i++) {
+               win_id = MVEBU_IO_WIN_MAX_WINS - i - 1;
+               io_win_check(win);
+               io_win_enable_window(ap_index, win, win_id);
+               win++;
+       }
+}
+
+/*
+ * NOTE: Use the same window array for insertion and removal of
+ *       temporary windows.
+ */
+void iow_temp_win_remove(int ap_index, struct addr_map_win *win, int size)
+{
+       uint32_t win_id;
+
+       /* Start from the last window and do not touch Win0 */
+       for (int i = 0; i < size; i++) {
+               uint64_t base;
+               uint32_t target;
+
+               win_id = MVEBU_IO_WIN_MAX_WINS - i - 1;
+
+               target = mmio_read_32(IO_WIN_CR_OFFSET(ap_index, win_id));
+               base = mmio_read_32(IO_WIN_ALR_OFFSET(ap_index, win_id));
+               base &= ~WIN_ENABLE_BIT;
+               base <<= ADDRESS_SHIFT;
+
+               if ((win->target_id != target) || (win->base_addr != base)) {
+                       ERROR("%s: Trying to remove bad window-%d!\n",
+                             __func__, win_id);
+                       continue;
+               }
+               io_win_disable_window(ap_index, win_id);
+               win++;
+       }
+}
+
+#ifdef DEBUG_ADDR_MAP
+static void dump_io_win(int ap_index)
+{
+       uint32_t trgt_id, win_id;
+       uint32_t alr, ahr;
+       uint64_t start, end;
+
+       /* Dump all IO windows */
+       tf_printf("\tbank  target     start              end\n");
+       tf_printf("\t----------------------------------------------------\n");
+       for (win_id = 0; win_id < MVEBU_IO_WIN_MAX_WINS; win_id++) {
+               alr = mmio_read_32(IO_WIN_ALR_OFFSET(ap_index, win_id));
+               if (alr & WIN_ENABLE_BIT) {
+                       alr &= ~WIN_ENABLE_BIT;
+                       ahr = mmio_read_32(IO_WIN_AHR_OFFSET(ap_index, win_id));
+                       trgt_id = mmio_read_32(IO_WIN_CR_OFFSET(ap_index,
+                                                               win_id));
+                       start = ((uint64_t)alr << ADDRESS_SHIFT);
+                       end = (((uint64_t)ahr + 0x10) << ADDRESS_SHIFT);
+                       tf_printf("\tio-win %d     0x%016llx 0x%016llx\n",
+                                 trgt_id, start, end);
+               }
+       }
+       tf_printf("\tio-win gcr is %x\n",
+                 mmio_read_32(MVEBU_IO_WIN_BASE(ap_index) +
+               MVEBU_IO_WIN_GCR_OFFSET));
+}
+#endif
+
+static void iow_save_win_range(int ap_id, int win_first, int win_last,
+                              uint32_t *buffer)
+{
+       int win_id, idx;
+
+       /* Save IOW */
+       for (idx = 0, win_id = win_first; win_id <= win_last; win_id++) {
+               buffer[idx++] = mmio_read_32(IO_WIN_CR_OFFSET(ap_id, win_id));
+               buffer[idx++] = mmio_read_32(IO_WIN_ALR_OFFSET(ap_id, win_id));
+               buffer[idx++] = mmio_read_32(IO_WIN_AHR_OFFSET(ap_id, win_id));
+       }
+       buffer[idx] = mmio_read_32(MVEBU_IO_WIN_BASE(ap_id) +
+                                  MVEBU_IO_WIN_GCR_OFFSET);
+}
+
+static void iow_restore_win_range(int ap_id, int win_first, int win_last,
+                                 uint32_t *buffer)
+{
+       int win_id, idx;
+
+       /* Restore IOW */
+       for (idx = 0, win_id = win_first; win_id <= win_last; win_id++) {
+               mmio_write_32(IO_WIN_CR_OFFSET(ap_id, win_id), buffer[idx++]);
+               mmio_write_32(IO_WIN_ALR_OFFSET(ap_id, win_id), buffer[idx++]);
+               mmio_write_32(IO_WIN_AHR_OFFSET(ap_id, win_id), buffer[idx++]);
+       }
+       mmio_write_32(MVEBU_IO_WIN_BASE(ap_id) + MVEBU_IO_WIN_GCR_OFFSET,
+                     buffer[idx++]);
+}
+
+void iow_save_win_all(int ap_id)
+{
+       iow_save_win_range(ap_id, 0, MVEBU_IO_WIN_MAX_WINS - 1,
+                          io_win_regs_save);
+}
+
+void iow_restore_win_all(int ap_id)
+{
+       iow_restore_win_range(ap_id, 0, MVEBU_IO_WIN_MAX_WINS - 1,
+                             io_win_regs_save);
+}
+
+int init_io_win(int ap_index)
+{
+       struct addr_map_win *win;
+       uint32_t win_id, win_reg;
+       uint32_t win_count;
+
+       INFO("Initializing IO WIN Address decoding\n");
+
+       /* Get the array of the windows and its size */
+       marvell_get_io_win_memory_map(ap_index, &win, &win_count);
+       if (win_count <= 0)
+               INFO("no windows configurations found\n");
+
+       if (win_count > MVEBU_IO_WIN_MAX_WINS) {
+               INFO("number of windows is bigger than %d\n",
+                    MVEBU_IO_WIN_MAX_WINS);
+               return 0;
+       }
+
+       /* Get the default target id to set the GCR */
+       win_reg = marvell_get_io_win_gcr_target(ap_index);
+       mmio_write_32(MVEBU_IO_WIN_BASE(ap_index) + MVEBU_IO_WIN_GCR_OFFSET,
+                     win_reg);
+
+       /* disable all IO windows */
+       for (win_id = 1; win_id < MVEBU_IO_WIN_MAX_WINS; win_id++)
+               io_win_disable_window(ap_index, win_id);
+
+       /* enable relevant windows, starting from win_id = 1 because
+        * index 0 dedicated for BootROM
+        */
+       for (win_id = 1; win_id <= win_count; win_id++, win++) {
+               io_win_check(win);
+               io_win_enable_window(ap_index, win, win_id);
+       }
+
+#ifdef DEBUG_ADDR_MAP
+       dump_io_win(ap_index);
+#endif
+
+       INFO("Done IO WIN Address decoding Initializing\n");
+
+       return 0;
+}
diff --git a/drivers/marvell/iob.c b/drivers/marvell/iob.c
new file mode 100644 (file)
index 0000000..9f9d047
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2016 - 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* IOW unit device driver for Marvell CP110 and CP115 SoCs */
+
+#include <a8k_common.h>
+#include <arch_helpers.h>
+#include <debug.h>
+#include <iob.h>
+#include <mmio.h>
+#include <mvebu.h>
+#include <mvebu_def.h>
+
+#if LOG_LEVEL >= LOG_LEVEL_INFO
+#define DEBUG_ADDR_MAP
+#endif
+
+#define MVEBU_IOB_OFFSET               (0x190000)
+#define MVEBU_IOB_MAX_WINS             16
+
+/* common defines */
+#define WIN_ENABLE_BIT                 (0x1)
+/* Physical address of the base of the window = {AddrLow[19:0],20`h0} */
+#define ADDRESS_SHIFT                  (20 - 4)
+#define ADDRESS_MASK                   (0xFFFFFFF0)
+#define IOB_WIN_ALIGNMENT              (0x100000)
+
+/* IOB registers */
+#define IOB_WIN_CR_OFFSET(win)         (iob_base + 0x0 + (0x20 * win))
+#define IOB_TARGET_ID_OFFSET           (8)
+#define IOB_TARGET_ID_MASK             (0xF)
+
+#define IOB_WIN_SCR_OFFSET(win)                (iob_base + 0x4 + (0x20 * win))
+#define IOB_WIN_ENA_CTRL_WRITE_SECURE  (0x1)
+#define IOB_WIN_ENA_CTRL_READ_SECURE   (0x2)
+#define IOB_WIN_ENA_WRITE_SECURE       (0x4)
+#define IOB_WIN_ENA_READ_SECURE                (0x8)
+
+#define IOB_WIN_ALR_OFFSET(win)                (iob_base + 0x8 + (0x20 * win))
+#define IOB_WIN_AHR_OFFSET(win)                (iob_base + 0xC + (0x20 * win))
+
+uintptr_t iob_base;
+
+static void iob_win_check(struct addr_map_win *win, uint32_t win_num)
+{
+       /* check if address is aligned to the size */
+       if (IS_NOT_ALIGN(win->base_addr, IOB_WIN_ALIGNMENT)) {
+               win->base_addr = ALIGN_UP(win->base_addr, IOB_WIN_ALIGNMENT);
+               ERROR("Window %d: base address unaligned to 0x%x\n",
+                     win_num, IOB_WIN_ALIGNMENT);
+               tf_printf("Align up the base address to 0x%llx\n",
+                         win->base_addr);
+       }
+
+       /* size parameter validity check */
+       if (IS_NOT_ALIGN(win->win_size, IOB_WIN_ALIGNMENT)) {
+               win->win_size = ALIGN_UP(win->win_size, IOB_WIN_ALIGNMENT);
+               ERROR("Window %d: window size unaligned to 0x%x\n", win_num,
+                     IOB_WIN_ALIGNMENT);
+               tf_printf("Aligning size to 0x%llx\n", win->win_size);
+       }
+}
+
+static void iob_enable_win(struct addr_map_win *win, uint32_t win_id)
+{
+       uint32_t iob_win_reg;
+       uint32_t alr, ahr;
+       uint64_t end_addr;
+
+       end_addr = (win->base_addr + win->win_size - 1);
+       alr = (uint32_t)((win->base_addr >> ADDRESS_SHIFT) & ADDRESS_MASK);
+       ahr = (uint32_t)((end_addr >> ADDRESS_SHIFT) & ADDRESS_MASK);
+
+       mmio_write_32(IOB_WIN_ALR_OFFSET(win_id), alr);
+       mmio_write_32(IOB_WIN_AHR_OFFSET(win_id), ahr);
+
+       iob_win_reg = WIN_ENABLE_BIT;
+       iob_win_reg |= (win->target_id & IOB_TARGET_ID_MASK)
+                      << IOB_TARGET_ID_OFFSET;
+       mmio_write_32(IOB_WIN_CR_OFFSET(win_id), iob_win_reg);
+
+}
+
+#ifdef DEBUG_ADDR_MAP
+static void dump_iob(void)
+{
+       uint32_t win_id, win_cr, alr, ahr;
+       uint8_t target_id;
+       uint64_t start, end;
+       char *iob_target_name[IOB_MAX_TID] = {
+               "CFG  ", "MCI0 ", "PEX1 ", "PEX2 ",
+               "PEX0 ", "NAND ", "RUNIT", "MCI1 " };
+
+       /* Dump all IOB windows */
+       tf_printf("bank  id target  start              end\n");
+       tf_printf("----------------------------------------------------\n");
+       for (win_id = 0; win_id < MVEBU_IOB_MAX_WINS; win_id++) {
+               win_cr = mmio_read_32(IOB_WIN_CR_OFFSET(win_id));
+               if (win_cr & WIN_ENABLE_BIT) {
+                       target_id = (win_cr >> IOB_TARGET_ID_OFFSET) &
+                                    IOB_TARGET_ID_MASK;
+                       alr = mmio_read_32(IOB_WIN_ALR_OFFSET(win_id));
+                       start = ((uint64_t)alr << ADDRESS_SHIFT);
+                       if (win_id != 0) {
+                               ahr = mmio_read_32(IOB_WIN_AHR_OFFSET(win_id));
+                               end = (((uint64_t)ahr + 0x10) << ADDRESS_SHIFT);
+                       } else {
+                               /* Window #0 size is hardcoded to 16MB, as it's
+                                * reserved for CP configuration space.
+                                */
+                               end = start + (16 << 20);
+                       }
+                       tf_printf("iob   %02d %s   0x%016llx 0x%016llx\n",
+                                 win_id, iob_target_name[target_id],
+                                 start, end);
+               }
+       }
+}
+#endif
+
+void iob_cfg_space_update(int ap_idx, int cp_idx, uintptr_t base,
+                         uintptr_t new_base)
+{
+       debug_enter();
+
+       iob_base = base + MVEBU_IOB_OFFSET;
+
+       NOTICE("Change the base address of AP%d-CP%d to %lx\n",
+              ap_idx, cp_idx, new_base);
+       mmio_write_32(IOB_WIN_ALR_OFFSET(0), new_base >> ADDRESS_SHIFT);
+
+       iob_base = new_base + MVEBU_IOB_OFFSET;
+
+       /* Make sure the address was configured by the CPU before
+        * any possible access to the CP.
+        */
+       dsb();
+
+       debug_exit();
+}
+
+int init_iob(uintptr_t base)
+{
+       struct addr_map_win *win;
+       uint32_t win_id, win_reg;
+       uint32_t win_count;
+
+       INFO("Initializing IOB Address decoding\n");
+
+       /* Get the base address of the address decoding MBUS */
+       iob_base = base + MVEBU_IOB_OFFSET;
+
+       /* Get the array of the windows and fill the map data */
+       marvell_get_iob_memory_map(&win, &win_count, base);
+       if (win_count <= 0) {
+               INFO("no windows configurations found\n");
+               return 0;
+       } else if (win_count > (MVEBU_IOB_MAX_WINS - 1)) {
+               ERROR("IOB mem map array > than max available windows (%d)\n",
+                     MVEBU_IOB_MAX_WINS);
+               win_count = MVEBU_IOB_MAX_WINS;
+       }
+
+       /* disable all IOB windows, start from win_id = 1
+        * because can't disable internal register window
+        */
+       for (win_id = 1; win_id < MVEBU_IOB_MAX_WINS; win_id++) {
+               win_reg = mmio_read_32(IOB_WIN_CR_OFFSET(win_id));
+               win_reg &= ~WIN_ENABLE_BIT;
+               mmio_write_32(IOB_WIN_CR_OFFSET(win_id), win_reg);
+
+               win_reg = ~IOB_WIN_ENA_CTRL_WRITE_SECURE;
+               win_reg &= ~IOB_WIN_ENA_CTRL_READ_SECURE;
+               win_reg &= ~IOB_WIN_ENA_WRITE_SECURE;
+               win_reg &= ~IOB_WIN_ENA_READ_SECURE;
+               mmio_write_32(IOB_WIN_SCR_OFFSET(win_id), win_reg);
+       }
+
+       for (win_id = 1; win_id < win_count + 1; win_id++, win++) {
+               iob_win_check(win, win_id);
+               iob_enable_win(win, win_id);
+       }
+
+#ifdef DEBUG_ADDR_MAP
+       dump_iob();
+#endif
+
+       INFO("Done IOB Address decoding Initializing\n");
+
+       return 0;
+}
diff --git a/drivers/marvell/mci.c b/drivers/marvell/mci.c
new file mode 100644 (file)
index 0000000..721504e
--- /dev/null
@@ -0,0 +1,832 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* MCI bus driver for Marvell ARMADA 8K and 8K+ SoCs */
+
+#include <debug.h>
+#include <delay_timer.h>
+#include <mmio.h>
+#include <mci.h>
+#include <mvebu.h>
+#include <mvebu_def.h>
+#include <plat_marvell.h>
+
+/* /HB /Units /Direct_regs /Direct regs
+ * /Configuration Register Write/Read Data Register
+ */
+#define MCI_WRITE_READ_DATA_REG(mci_index)     \
+                                       MVEBU_MCI_REG_BASE_REMAP(mci_index)
+/* /HB /Units /Direct_regs /Direct regs
+ * /Configuration Register Access Command Register
+ */
+#define MCI_ACCESS_CMD_REG(mci_index)          \
+                               (MVEBU_MCI_REG_BASE_REMAP(mci_index) + 0x4)
+
+/* Access Command fields :
+ * bit[3:0]   - Sub command: 1 => Peripheral Config Register Read,
+ *                          0 => Peripheral Config Register Write,
+ *                          2 => Peripheral Assign ID request,
+ *                          3 => Circular Config Write
+ * bit[5]     - 1 => Local (same chip access) 0 => Remote
+ * bit[15:8]  - Destination hop ID. Put Global ID (GID) here (see scheme below).
+ * bit[23:22] - 0x3 IHB PHY REG address space, 0x0 IHB Controller space
+ * bit[21:16] - Low 6 bits of offset. Hight 2 bits are taken from bit[28:27]
+ *             of IHB_PHY_CTRL
+ *             (must be set before any PHY register access occurs):
+ *             /IHB_REG /IHB_REGInterchip Hopping Bus Registers
+ *             /IHB Version Control Register
+ *
+ *             ixi_ihb_top             IHB PHY
+ *  AXI -----------------------------   -------------
+ *   <--| axi_hb_top | ihb_pipe_top |-->|           |
+ *   -->|   GID=1    |     GID=0    |<--|           |
+ *      -----------------------------   -------------
+ */
+#define MCI_INDIRECT_CTRL_READ_CMD             0x1
+#define MCI_INDIRECT_CTRL_ASSIGN_CMD           0x2
+#define MCI_INDIRECT_CTRL_CIRCULAR_CMD         0x3
+#define MCI_INDIRECT_CTRL_LOCAL_PKT            (1 << 5)
+#define MCI_INDIRECT_CTRL_CMD_DONE_OFFSET      6
+#define MCI_INDIRECT_CTRL_CMD_DONE             \
+                               (1 << MCI_INDIRECT_CTRL_CMD_DONE_OFFSET)
+#define MCI_INDIRECT_CTRL_DATA_READY_OFFSET    7
+#define MCI_INDIRECT_CTRL_DATA_READY           \
+                               (1 << MCI_INDIRECT_CTRL_DATA_READY_OFFSET)
+#define MCI_INDIRECT_CTRL_HOPID_OFFSET         8
+#define MCI_INDIRECT_CTRL_HOPID(id)            \
+                       (((id) & 0xFF) << MCI_INDIRECT_CTRL_HOPID_OFFSET)
+#define MCI_INDIRECT_CTRL_REG_CHIPID_OFFSET    16
+#define MCI_INDIRECT_REG_CTRL_ADDR(reg_num)    \
+                       (reg_num << MCI_INDIRECT_CTRL_REG_CHIPID_OFFSET)
+
+/* Hop ID values */
+#define GID_IHB_PIPE                                   0
+#define GID_AXI_HB                                     1
+#define GID_IHB_EXT                                    2
+
+#define MCI_DID_GLOBAL_ASSIGNMENT_REQUEST_REG          0x2
+/* Target MCi Local ID (LID, which is = self DID) */
+#define MCI_DID_GLOBAL_ASSIGN_REQ_MCI_LOCAL_ID(val)    (((val) & 0xFF) << 16)
+/* Bits [15:8]: Number of MCis on chip of target MCi */
+#define MCI_DID_GLOBAL_ASSIGN_REQ_MCI_COUNT(val)       (((val) & 0xFF) << 8)
+/* Bits [7:0]: Number of hops on chip of target MCi */
+#define MCI_DID_GLOBAL_ASSIGN_REQ_HOPS_NUM(val)                (((val) & 0xFF) << 0)
+
+/* IHB_REG domain registers */
+/* /HB /Units /IHB_REG /IHB_REGInterchip Hopping Bus Registers/
+ * Rx Memory Configuration Register (RX_MEM_CFG)
+ */
+#define MCI_CTRL_RX_MEM_CFG_REG_NUM                    0x0
+#define MCI_CTRL_RX_TX_MEM_CFG_RQ_THRESH(val)          (((val) & 0xFF) << 24)
+#define MCI_CTRL_RX_TX_MEM_CFG_PQ_THRESH(val)          (((val) & 0xFF) << 16)
+#define MCI_CTRL_RX_TX_MEM_CFG_NQ_THRESH(val)          (((val) & 0xFF) << 8)
+#define MCI_CTRL_RX_TX_MEM_CFG_DELTA_THRESH(val)       (((val) & 0xF) << 4)
+#define MCI_CTRL_RX_TX_MEM_CFG_RTC(val)                        (((val) & 0x3) << 2)
+#define MCI_CTRL_RX_TX_MEM_CFG_WTC(val)                        (((val) & 0x3) << 0)
+#define MCI_CTRL_RX_MEM_CFG_REG_DEF_CP_VAL             \
+                               (MCI_CTRL_RX_TX_MEM_CFG_RQ_THRESH(0x07) | \
+                               MCI_CTRL_RX_TX_MEM_CFG_PQ_THRESH(0x3f) | \
+                               MCI_CTRL_RX_TX_MEM_CFG_NQ_THRESH(0x3f) | \
+                               MCI_CTRL_RX_TX_MEM_CFG_DELTA_THRESH(0xf) | \
+                               MCI_CTRL_RX_TX_MEM_CFG_RTC(1) | \
+                               MCI_CTRL_RX_TX_MEM_CFG_WTC(1))
+
+#define MCI_CTRL_RX_MEM_CFG_REG_DEF_AP_VAL             \
+                               (MCI_CTRL_RX_TX_MEM_CFG_RQ_THRESH(0x3f) | \
+                               MCI_CTRL_RX_TX_MEM_CFG_PQ_THRESH(0x03) | \
+                               MCI_CTRL_RX_TX_MEM_CFG_NQ_THRESH(0x3f) | \
+                               MCI_CTRL_RX_TX_MEM_CFG_DELTA_THRESH(0xf) | \
+                               MCI_CTRL_RX_TX_MEM_CFG_RTC(1) | \
+                               MCI_CTRL_RX_TX_MEM_CFG_WTC(1))
+
+
+/* /HB /Units /IHB_REG /IHB_REGInterchip Hopping Bus Registers/
+ * Tx Memory Configuration Register (TX_MEM_CFG)
+ */
+#define MCI_CTRL_TX_MEM_CFG_REG_NUM                    0x1
+/* field mapping for TX mem config register
+ * are the same as for RX register - see register above
+ */
+#define MCI_CTRL_TX_MEM_CFG_REG_DEF_VAL                        \
+                               (MCI_CTRL_RX_TX_MEM_CFG_RQ_THRESH(0x20) | \
+                               MCI_CTRL_RX_TX_MEM_CFG_PQ_THRESH(0x20) | \
+                               MCI_CTRL_RX_TX_MEM_CFG_NQ_THRESH(0x20) | \
+                               MCI_CTRL_RX_TX_MEM_CFG_DELTA_THRESH(2) | \
+                               MCI_CTRL_RX_TX_MEM_CFG_RTC(1) | \
+                               MCI_CTRL_RX_TX_MEM_CFG_WTC(1))
+
+/* /HB /Units /IHB_REG /IHB_REGInterchip Hopping Bus Registers
+ * /IHB Link CRC Control
+ */
+/* MCi Link CRC Control Register (MCi_CRC_CTRL) */
+#define MCI_LINK_CRC_CTRL_REG_NUM                      0x4
+
+/* /HB /Units /IHB_REG /IHB_REGInterchip Hopping Bus Registers
+ * /IHB Status Register
+ */
+/* MCi Status Register (MCi_STS) */
+#define MCI_CTRL_STATUS_REG_NUM                                0x5
+#define MCI_CTRL_STATUS_REG_PHY_READY                  (1 << 12)
+#define MCI_CTRL_STATUS_REG_LINK_PRESENT               (1 << 15)
+#define MCI_CTRL_STATUS_REG_PHY_CID_VIO_OFFSET         24
+#define MCI_CTRL_STATUS_REG_PHY_CID_VIO_MASK           \
+                               (0xF << MCI_CTRL_STATUS_REG_PHY_CID_VIO_OFFSET)
+/* Expected successful Link result, including reserved bit */
+#define MCI_CTRL_PHY_READY             (MCI_CTRL_STATUS_REG_PHY_READY | \
+                                       MCI_CTRL_STATUS_REG_LINK_PRESENT | \
+                                       MCI_CTRL_STATUS_REG_PHY_CID_VIO_MASK)
+
+/* /HB /Units /IHB_REG /IHB_REGInterchip Hopping Bus Registers/
+ * MCi PHY Speed Settings Register (MCi_PHY_SETTING)
+ */
+#define MCI_CTRL_MCI_PHY_SETTINGS_REG_NUM              0x8
+#define MCI_CTRL_MCI_PHY_SET_DLO_FIFO_FULL_TRESH(val)  (((val) & 0xF) << 28)
+#define MCI_CTRL_MCI_PHY_SET_PHY_MAX_SPEED(val)                (((val) & 0xF) << 12)
+#define MCI_CTRL_MCI_PHY_SET_PHYCLK_SEL(val)           (((val) & 0xF) << 8)
+#define MCI_CTRL_MCI_PHY_SET_REFCLK_FREQ_SEL(val)      (((val) & 0xF) << 4)
+#define MCI_CTRL_MCI_PHY_SET_AUTO_LINK_EN(val)         (((val) & 0x1) << 1)
+#define MCI_CTRL_MCI_PHY_SET_REG_DEF_VAL               \
+                       (MCI_CTRL_MCI_PHY_SET_DLO_FIFO_FULL_TRESH(0x3) | \
+                       MCI_CTRL_MCI_PHY_SET_PHY_MAX_SPEED(0x3) | \
+                       MCI_CTRL_MCI_PHY_SET_PHYCLK_SEL(0x2) | \
+                       MCI_CTRL_MCI_PHY_SET_REFCLK_FREQ_SEL(0x1))
+#define MCI_CTRL_MCI_PHY_SET_REG_DEF_VAL2              \
+                       (MCI_CTRL_MCI_PHY_SET_DLO_FIFO_FULL_TRESH(0x3) | \
+                       MCI_CTRL_MCI_PHY_SET_PHY_MAX_SPEED(0x3) | \
+                       MCI_CTRL_MCI_PHY_SET_PHYCLK_SEL(0x5) | \
+                       MCI_CTRL_MCI_PHY_SET_REFCLK_FREQ_SEL(0x1))
+
+/* /HB /Units /IHB_REG /IHB_REGInterchip Hopping Bus Registers
+ * /IHB Mode Config
+ */
+#define MCI_CTRL_IHB_MODE_CFG_REG_NUM                  0x25
+#define MCI_CTRL_IHB_MODE_HBCLK_DIV(val)               ((val) & 0xFF)
+#define MCI_CTRL_IHB_MODE_CHUNK_MOD_OFFSET             8
+#define MCI_CTRL_IHB_MODE_CHUNK_MOD                    \
+                               (1 << MCI_CTRL_IHB_MODE_CHUNK_MOD_OFFSET)
+#define MCI_CTRL_IHB_MODE_FWD_MOD_OFFSET               9
+#define MCI_CTRL_IHB_MODE_FWD_MOD                      \
+                               (1 << MCI_CTRL_IHB_MODE_FWD_MOD_OFFSET)
+#define MCI_CTRL_IHB_MODE_SEQFF_FINE_MOD(val)          (((val) & 0xF) << 12)
+#define MCI_CTRL_IHB_MODE_RX_COMB_THRESH(val)          (((val) & 0xFF) << 16)
+#define MCI_CTRL_IHB_MODE_TX_COMB_THRESH(val)          (((val) & 0xFF) << 24)
+
+#define MCI_CTRL_IHB_MODE_CFG_REG_DEF_VAL              \
+                               (MCI_CTRL_IHB_MODE_HBCLK_DIV(6) | \
+                               MCI_CTRL_IHB_MODE_FWD_MOD | \
+                               MCI_CTRL_IHB_MODE_SEQFF_FINE_MOD(0xF) | \
+                               MCI_CTRL_IHB_MODE_RX_COMB_THRESH(0x3f) | \
+                               MCI_CTRL_IHB_MODE_TX_COMB_THRESH(0x40))
+/* AXI_HB registers */
+#define MCI_AXI_ACCESS_DATA_REG_NUM                    0x0
+#define MCI_AXI_ACCESS_PCIE_MODE                       1
+#define MCI_AXI_ACCESS_CACHE_CHECK_OFFSET              5
+#define MCI_AXI_ACCESS_CACHE_CHECK                     \
+                               (1 << MCI_AXI_ACCESS_CACHE_CHECK_OFFSET)
+#define MCI_AXI_ACCESS_FORCE_POST_WR_OFFSET            6
+#define MCI_AXI_ACCESS_FORCE_POST_WR                   \
+                               (1 << MCI_AXI_ACCESS_FORCE_POST_WR_OFFSET)
+#define MCI_AXI_ACCESS_DISABLE_CLK_GATING_OFFSET       9
+#define MCI_AXI_ACCESS_DISABLE_CLK_GATING              \
+                               (1 << MCI_AXI_ACCESS_DISABLE_CLK_GATING_OFFSET)
+
+/* /HB /Units /HB_REG /HB_REGHopping Bus Registers
+ * /Window 0 Address Mask Register
+ */
+#define MCI_HB_CTRL_WIN0_ADDRESS_MASK_REG_NUM          0x2
+
+/* /HB /Units /HB_REG /HB_REGHopping Bus Registers
+ * /Window 0 Destination Register
+ */
+#define MCI_HB_CTRL_WIN0_DESTINATION_REG_NUM           0x3
+#define MCI_HB_CTRL_WIN0_DEST_VALID_FLAG(val)          (((val) & 0x1) << 16)
+#define MCI_HB_CTRL_WIN0_DEST_ID(val)                  (((val) & 0xFF) << 0)
+
+/* /HB /Units /HB_REG /HB_REGHopping Bus Registers /Tx Control Register */
+#define MCI_HB_CTRL_TX_CTRL_REG_NUM                    0xD
+#define MCI_HB_CTRL_TX_CTRL_PCIE_MODE_OFFSET           24
+#define MCI_HB_CTRL_TX_CTRL_PCIE_MODE                  \
+                               (1 << MCI_HB_CTRL_TX_CTRL_PCIE_MODE_OFFSET)
+#define MCI_HB_CTRL_TX_CTRL_PRI_TH_QOS(val)            (((val) & 0xF) << 12)
+#define MCI_HB_CTRL_TX_CTRL_MAX_RD_CNT(val)            (((val) & 0x1F) << 6)
+#define MCI_HB_CTRL_TX_CTRL_MAX_WR_CNT(val)            (((val) & 0x1F) << 0)
+
+/* /HB /Units /IHB_REG /IHB_REGInterchip Hopping Bus Registers
+ * /IHB Version Control Register
+ */
+#define MCI_PHY_CTRL_REG_NUM                           0x7
+#define MCI_PHY_CTRL_MCI_MINOR                         0x8 /* BITS [3:0] */
+#define MCI_PHY_CTRL_MCI_MAJOR_OFFSET                  4
+#define MCI_PHY_CTRL_MCI_MAJOR                         \
+                               (1 << MCI_PHY_CTRL_MCI_MAJOR_OFFSET)
+#define MCI_PHY_CTRL_MCI_SLEEP_REQ_OFFSET              11
+#define MCI_PHY_CTRL_MCI_SLEEP_REQ                     \
+                               (1 << MCI_PHY_CTRL_MCI_SLEEP_REQ_OFFSET)
+/* Host=1 / Device=0 PHY mode */
+#define MCI_PHY_CTRL_MCI_PHY_MODE_OFFSET               24
+#define MCI_PHY_CTRL_MCI_PHY_MODE_HOST                 \
+                               (1 << MCI_PHY_CTRL_MCI_PHY_MODE_OFFSET)
+/* Register=1 / PWM=0 interface */
+#define MCI_PHY_CTRL_MCI_PHY_REG_IF_MODE_OFFSET                25
+#define MCI_PHY_CTRL_MCI_PHY_REG_IF_MODE               \
+                               (1 << MCI_PHY_CTRL_MCI_PHY_REG_IF_MODE_OFFSET)
+ /* PHY code InReset=1 */
+#define MCI_PHY_CTRL_MCI_PHY_RESET_CORE_OFFSET         26
+#define MCI_PHY_CTRL_MCI_PHY_RESET_CORE                        \
+                               (1 << MCI_PHY_CTRL_MCI_PHY_RESET_CORE_OFFSET)
+#define MCI_PHY_CTRL_PHY_ADDR_MSB_OFFSET               27
+#define MCI_PHY_CTRL_PHY_ADDR_MSB(addr)                        \
+                               (((addr) & 0x3) << \
+                               MCI_PHY_CTRL_PHY_ADDR_MSB_OFFSET)
+#define MCI_PHY_CTRL_PIDI_MODE_OFFSET                  31
+#define MCI_PHY_CTRL_PIDI_MODE                         \
+                               (1 << MCI_PHY_CTRL_PIDI_MODE_OFFSET)
+
+/* Number of times to wait for the MCI link ready after MCI configurations
+ * Normally takes 34-35 successive reads
+ */
+#define LINK_READY_TIMEOUT                             100
+
+enum mci_register_type {
+       MCI_REG_TYPE_PHY = 0,
+       MCI_REG_TYPE_CTRL,
+};
+
+enum {
+       MCI_CMD_WRITE,
+       MCI_CMD_READ
+};
+
+/* Write wrapper callback for debug:
+ * will print written data in case LOG_LEVEL >= 40
+ */
+static void mci_mmio_write_32(uintptr_t addr, uint32_t value)
+{
+       VERBOSE("Write:\t0x%x = 0x%x\n", (uint32_t)addr, value);
+       mmio_write_32(addr, value);
+}
+/* Read wrapper callback for debug:
+ * will print read data in case LOG_LEVEL >= 40
+ */
+static uint32_t mci_mmio_read_32(uintptr_t addr)
+{
+       uint32_t value;
+
+       value = mmio_read_32(addr);
+       VERBOSE("Read:\t0x%x = 0x%x\n", (uint32_t)addr, value);
+       return value;
+}
+
+/* MCI indirect access command completion polling:
+ * Each write/read command done via MCI indirect registers must be polled
+ * for command completions status.
+ *
+ * Returns 1 in case of error
+ * Returns 0 in case of command completed successfully.
+ */
+static int mci_poll_command_completion(int mci_index, int command_type)
+{
+       uint32_t mci_cmd_value = 0, retry_count = 100, ret = 0;
+       uint32_t completion_flags = MCI_INDIRECT_CTRL_CMD_DONE;
+
+       debug_enter();
+       /* Read commands require validating that requested data is ready */
+       if (command_type == MCI_CMD_READ)
+               completion_flags |= MCI_INDIRECT_CTRL_DATA_READY;
+
+       do {
+               /* wait 1 ms before each polling */
+               mdelay(1);
+               mci_cmd_value = mci_mmio_read_32(MCI_ACCESS_CMD_REG(mci_index));
+       } while (((mci_cmd_value & completion_flags) != completion_flags) &&
+                        (retry_count-- > 0));
+
+       if (retry_count == 0) {
+               ERROR("%s: MCI command timeout (command status = 0x%x)\n",
+                     __func__, mci_cmd_value);
+               ret = 1;
+       }
+
+       debug_exit();
+       return ret;
+}
+
+int mci_read(int mci_idx, uint32_t cmd, uint32_t *value)
+{
+       int rval;
+
+       mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_idx), cmd);
+
+       rval = mci_poll_command_completion(mci_idx, MCI_CMD_READ);
+
+       *value = mci_mmio_read_32(MCI_WRITE_READ_DATA_REG(mci_idx));
+
+       return rval;
+}
+
+int  mci_write(int mci_idx, uint32_t cmd, uint32_t data)
+{
+       mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_idx), data);
+       mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_idx), cmd);
+
+       return mci_poll_command_completion(mci_idx, MCI_CMD_WRITE);
+}
+
+/* Perform 3 configurations in one command: PCI mode,
+ * queues separation and cache bit
+ */
+static int mci_axi_set_pcie_mode(int mci_index)
+{
+       uint32_t reg_data, ret = 1;
+
+       debug_enter();
+       /* This configuration makes MCI IP behave consistently with AXI protocol
+        * It should be configured at one side only (for example locally at AP).
+        * The IP takes care of performing the same configurations at MCI on
+        * another side (for example remotely at CP).
+        */
+       mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index),
+                         MCI_AXI_ACCESS_PCIE_MODE |
+                         MCI_AXI_ACCESS_CACHE_CHECK |
+                         MCI_AXI_ACCESS_FORCE_POST_WR |
+                         MCI_AXI_ACCESS_DISABLE_CLK_GATING);
+       mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+                         MCI_INDIRECT_REG_CTRL_ADDR(
+                               MCI_AXI_ACCESS_DATA_REG_NUM)  |
+                         MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB) |
+                         MCI_INDIRECT_CTRL_LOCAL_PKT |
+                         MCI_INDIRECT_CTRL_CIRCULAR_CMD);
+
+       /* if Write command was successful, verify PCIe mode */
+       if (mci_poll_command_completion(mci_index, MCI_CMD_WRITE) == 0) {
+               /* Verify the PCIe mode selected */
+               mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+                                 MCI_INDIRECT_REG_CTRL_ADDR(
+                                       MCI_HB_CTRL_TX_CTRL_REG_NUM)  |
+                                 MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB) |
+                                 MCI_INDIRECT_CTRL_LOCAL_PKT |
+                                 MCI_INDIRECT_CTRL_READ_CMD);
+               /* if read was completed, verify PCIe mode */
+               if (mci_poll_command_completion(mci_index, MCI_CMD_READ) == 0) {
+                       reg_data = mci_mmio_read_32(
+                                       MCI_WRITE_READ_DATA_REG(mci_index));
+                       if (reg_data & MCI_HB_CTRL_TX_CTRL_PCIE_MODE)
+                               ret = 0;
+               }
+       }
+
+       debug_exit();
+       return ret;
+}
+
+/* Reduce sequence FIFO timer expiration threshold */
+static int mci_axi_set_fifo_thresh(int mci_index)
+{
+       uint32_t reg_data, ret = 0;
+
+       debug_enter();
+       /* This configuration reduces sequence FIFO timer expiration threshold
+        * (to 0x7 instead of 0xA).
+        * In MCI 1.6 version this configuration prevents possible functional
+        * issues.
+        * In version 1.82 the configuration prevents performance degradation
+        */
+
+       /* Configure local AP side */
+       reg_data = MCI_PHY_CTRL_PIDI_MODE |
+                  MCI_PHY_CTRL_MCI_PHY_REG_IF_MODE |
+                  MCI_PHY_CTRL_MCI_PHY_MODE_HOST |
+                  MCI_PHY_CTRL_MCI_MAJOR |
+                  MCI_PHY_CTRL_MCI_MINOR;
+       mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), reg_data);
+       mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+                         MCI_INDIRECT_REG_CTRL_ADDR(MCI_PHY_CTRL_REG_NUM) |
+                         MCI_INDIRECT_CTRL_LOCAL_PKT);
+       ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+       /* Reduce the threshold */
+       mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index),
+                         MCI_CTRL_IHB_MODE_CFG_REG_DEF_VAL);
+
+       mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+                         MCI_INDIRECT_REG_CTRL_ADDR(
+                               MCI_CTRL_IHB_MODE_CFG_REG_NUM) |
+                         MCI_INDIRECT_CTRL_LOCAL_PKT);
+       ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+       /* Exit PIDI mode */
+       reg_data = MCI_PHY_CTRL_MCI_PHY_REG_IF_MODE |
+                  MCI_PHY_CTRL_MCI_PHY_MODE_HOST |
+                  MCI_PHY_CTRL_MCI_MAJOR |
+                  MCI_PHY_CTRL_MCI_MINOR;
+       mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), reg_data);
+       mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+                         MCI_INDIRECT_REG_CTRL_ADDR(MCI_PHY_CTRL_REG_NUM) |
+                         MCI_INDIRECT_CTRL_LOCAL_PKT);
+       ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+       /* Configure remote CP side */
+       reg_data = MCI_PHY_CTRL_PIDI_MODE |
+                  MCI_PHY_CTRL_MCI_MAJOR |
+                  MCI_PHY_CTRL_MCI_MINOR |
+                  MCI_PHY_CTRL_MCI_PHY_REG_IF_MODE;
+       mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), reg_data);
+       mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+                         MCI_INDIRECT_REG_CTRL_ADDR(MCI_PHY_CTRL_REG_NUM) |
+                         MCI_CTRL_IHB_MODE_FWD_MOD);
+       ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+       /* Reduce the threshold */
+       mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index),
+                         MCI_CTRL_IHB_MODE_CFG_REG_DEF_VAL);
+       mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+                         MCI_INDIRECT_REG_CTRL_ADDR(
+                               MCI_CTRL_IHB_MODE_CFG_REG_NUM) |
+                         MCI_INDIRECT_CTRL_HOPID(GID_IHB_EXT));
+       ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+       /* Exit PIDI mode */
+       reg_data = MCI_PHY_CTRL_MCI_MAJOR |
+                  MCI_PHY_CTRL_MCI_MINOR |
+                  MCI_PHY_CTRL_MCI_PHY_REG_IF_MODE;
+       mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), reg_data);
+       mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+                         MCI_INDIRECT_REG_CTRL_ADDR(MCI_PHY_CTRL_REG_NUM) |
+                         MCI_CTRL_IHB_MODE_FWD_MOD);
+
+       ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+       debug_exit();
+       return ret;
+}
+
+/* Configure:
+ * 1. AP & CP TX thresholds and delta configurations
+ * 2. DLO & DLI FIFO full threshold
+ * 3. RX thresholds and delta configurations
+ * 4. CP AR and AW outstanding
+ * 5. AP AR and AW outstanding
+ */
+static int mci_axi_set_fifo_rx_tx_thresh(int mci_index)
+{
+       uint32_t ret = 0;
+
+       debug_enter();
+       /* AP TX thresholds and delta configurations (IHB_reg 0x1) */
+       mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index),
+                         MCI_CTRL_TX_MEM_CFG_REG_DEF_VAL);
+       mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+                         MCI_INDIRECT_REG_CTRL_ADDR(
+                               MCI_CTRL_TX_MEM_CFG_REG_NUM) |
+                         MCI_INDIRECT_CTRL_LOCAL_PKT);
+       ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+       /* CP TX thresholds and delta configurations (IHB_reg 0x1) */
+       mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index),
+                         MCI_CTRL_TX_MEM_CFG_REG_DEF_VAL);
+       mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+                         MCI_INDIRECT_REG_CTRL_ADDR(
+                               MCI_CTRL_TX_MEM_CFG_REG_NUM) |
+                         MCI_INDIRECT_CTRL_HOPID(GID_IHB_EXT));
+       ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+       /* AP DLO & DLI FIFO full threshold & Auto-Link enable (IHB_reg 0x8) */
+       mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index),
+                         MCI_CTRL_MCI_PHY_SET_REG_DEF_VAL |
+                         MCI_CTRL_MCI_PHY_SET_AUTO_LINK_EN(1));
+       mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+                         MCI_INDIRECT_REG_CTRL_ADDR(
+                               MCI_CTRL_MCI_PHY_SETTINGS_REG_NUM) |
+                         MCI_INDIRECT_CTRL_LOCAL_PKT);
+       ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+       /* CP DLO & DLI FIFO full threshold (IHB_reg 0x8) */
+       mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index),
+                         MCI_CTRL_MCI_PHY_SET_REG_DEF_VAL);
+       mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+                         MCI_INDIRECT_REG_CTRL_ADDR(
+                               MCI_CTRL_MCI_PHY_SETTINGS_REG_NUM) |
+                         MCI_INDIRECT_CTRL_HOPID(GID_IHB_EXT));
+       ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+       /* AP RX thresholds and delta configurations (IHB_reg 0x0) */
+       mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index),
+                         MCI_CTRL_RX_MEM_CFG_REG_DEF_AP_VAL);
+       mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+                         MCI_INDIRECT_REG_CTRL_ADDR(
+                               MCI_CTRL_RX_MEM_CFG_REG_NUM) |
+                         MCI_INDIRECT_CTRL_LOCAL_PKT);
+       ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+       /* CP RX thresholds and delta configurations (IHB_reg 0x0) */
+       mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index),
+                         MCI_CTRL_RX_MEM_CFG_REG_DEF_CP_VAL);
+       mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+                         MCI_INDIRECT_REG_CTRL_ADDR(
+                               MCI_CTRL_RX_MEM_CFG_REG_NUM) |
+                         MCI_INDIRECT_CTRL_HOPID(GID_IHB_EXT));
+       ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+       /* AP AR & AW maximum AXI outstanding request cfg (HB_reg 0xd) */
+       mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index),
+                         MCI_HB_CTRL_TX_CTRL_PRI_TH_QOS(8) |
+                         MCI_HB_CTRL_TX_CTRL_MAX_RD_CNT(3) |
+                         MCI_HB_CTRL_TX_CTRL_MAX_WR_CNT(3));
+       mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+                         MCI_INDIRECT_REG_CTRL_ADDR(
+                               MCI_HB_CTRL_TX_CTRL_REG_NUM) |
+                         MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB) |
+                         MCI_INDIRECT_CTRL_LOCAL_PKT);
+       ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+       /* CP AR & AW maximum AXI outstanding request cfg (HB_reg 0xd) */
+       mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index),
+                         MCI_HB_CTRL_TX_CTRL_PRI_TH_QOS(8) |
+                         MCI_HB_CTRL_TX_CTRL_MAX_RD_CNT(0xB) |
+                         MCI_HB_CTRL_TX_CTRL_MAX_WR_CNT(0x11));
+       mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+                         MCI_INDIRECT_REG_CTRL_ADDR(
+                               MCI_HB_CTRL_TX_CTRL_REG_NUM) |
+                         MCI_INDIRECT_CTRL_HOPID(GID_IHB_EXT) |
+                         MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB));
+       ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+       debug_exit();
+       return ret;
+}
+
+/* configure MCI to allow read & write transactions to arrive at the same time.
+ * Without the below configuration, MCI won't sent response to CPU for
+ * transactions which arrived simultaneously and will lead to CPU hang.
+ * The below will configure MCI to be able to pass transactions from/to CP/AP.
+ */
+static int mci_enable_simultaneous_transactions(int mci_index)
+{
+       uint32_t ret = 0;
+
+       debug_enter();
+       /* ID assignment (assigning global ID offset to CP) */
+       mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(0),
+                         MCI_DID_GLOBAL_ASSIGN_REQ_MCI_LOCAL_ID(2) |
+                         MCI_DID_GLOBAL_ASSIGN_REQ_MCI_COUNT(2) |
+                         MCI_DID_GLOBAL_ASSIGN_REQ_HOPS_NUM(2));
+       mci_mmio_write_32(MCI_ACCESS_CMD_REG(0),
+                         MCI_INDIRECT_REG_CTRL_ADDR(
+                               MCI_DID_GLOBAL_ASSIGNMENT_REQUEST_REG) |
+                         MCI_INDIRECT_CTRL_ASSIGN_CMD);
+       ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+       /* Assigning dest. ID=3 to all transactions entering from AXI at AP */
+       mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(0),
+                         MCI_HB_CTRL_WIN0_DEST_VALID_FLAG(1) |
+                         MCI_HB_CTRL_WIN0_DEST_ID(3));
+       mci_mmio_write_32(MCI_ACCESS_CMD_REG(0),
+                         MCI_INDIRECT_REG_CTRL_ADDR(
+                               MCI_HB_CTRL_WIN0_DESTINATION_REG_NUM) |
+                         MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB) |
+                         MCI_INDIRECT_CTRL_LOCAL_PKT);
+       ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+       /* Assigning dest. ID=1 to all transactions entering from AXI at CP */
+       mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(0),
+                         MCI_HB_CTRL_WIN0_DEST_VALID_FLAG(1) |
+                         MCI_HB_CTRL_WIN0_DEST_ID(1));
+       mci_mmio_write_32(MCI_ACCESS_CMD_REG(0),
+                         MCI_INDIRECT_REG_CTRL_ADDR(
+                               MCI_HB_CTRL_WIN0_DESTINATION_REG_NUM) |
+                         MCI_INDIRECT_CTRL_HOPID(GID_IHB_EXT) |
+                         MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB));
+       ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+       /* End address to all transactions entering from AXI at AP.
+        * This will lead to get match for any AXI address
+        * and receive destination ID=3
+        */
+       mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(0), 0xffffffff);
+       mci_mmio_write_32(MCI_ACCESS_CMD_REG(0),
+                         MCI_INDIRECT_REG_CTRL_ADDR(
+                               MCI_HB_CTRL_WIN0_ADDRESS_MASK_REG_NUM) |
+                         MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB) |
+                         MCI_INDIRECT_CTRL_LOCAL_PKT);
+       ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+       /* End address to all transactions entering from AXI at CP.
+        * This will lead to get match for any AXI address
+        * and receive destination ID=1
+        */
+       mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(0), 0xffffffff);
+       mci_mmio_write_32(MCI_ACCESS_CMD_REG(0),
+                         MCI_INDIRECT_REG_CTRL_ADDR(
+                               MCI_HB_CTRL_WIN0_ADDRESS_MASK_REG_NUM) |
+                         MCI_INDIRECT_CTRL_HOPID(GID_IHB_EXT) |
+                         MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB));
+       ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+       debug_exit();
+       return ret;
+}
+
+/* Check if MCI simultaneous transaction was already enabled.
+ * Currently bootrom does this mci configuration only when the boot source is
+ * SAR_MCIX4, in other cases it should be done at this stage.
+ * It is worth noticing that in case of booting from uart, the bootrom
+ * flow is different and this mci initialization is skipped even if boot
+ * source is SAR_MCIX4. Therefore new verification bases on appropriate mci's
+ * register content: if the appropriate reg contains 0x0 it means that the
+ * bootrom didn't perform required mci configuration.
+ *
+ * Returns:
+ * 0 - configuration already done
+ * 1 - configuration missing
+ */
+static _Bool mci_simulatenous_trans_missing(int mci_index)
+{
+       uint32_t reg, ret;
+
+       /* read 'Window 0 Destination ID assignment' from HB register 0x3
+        * (TX_CFG_W0_DST_ID) to check whether ID assignment was already
+        * performed by BootROM.
+        */
+       debug_enter();
+       mci_mmio_write_32(MCI_ACCESS_CMD_REG(0),
+                         MCI_INDIRECT_REG_CTRL_ADDR(
+                               MCI_HB_CTRL_WIN0_DESTINATION_REG_NUM) |
+                         MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB) |
+                         MCI_INDIRECT_CTRL_LOCAL_PKT |
+                         MCI_INDIRECT_CTRL_READ_CMD);
+       ret = mci_poll_command_completion(mci_index, MCI_CMD_READ);
+
+       reg = mci_mmio_read_32(MCI_WRITE_READ_DATA_REG(mci_index));
+
+       if (ret)
+               ERROR("Failed to verify MCI simultaneous read/write status\n");
+
+       debug_exit();
+       /* default ID assignment is 0, so if register doesn't contain zeros
+        * it means that bootrom already performed required configuration.
+        */
+       if (reg != 0)
+               return 0;
+
+       return 1;
+}
+
+/* For A1 revision, configure the MCI link for performance improvement:
+ * - set MCI to support read/write transactions to arrive at the same time
+ * - Switch AXI to PCIe mode
+ * - Reduce sequence FIFO threshold
+ * - Configure RX/TX FIFO thresholds
+ *
+ *   Note:
+ *   We don't exit on error code from any sub routine, to try (best effort) to
+ *   complete the MCI configuration.
+ *   (If we exit - Bootloader will surely fail to boot)
+ */
+int mci_configure(int mci_index)
+{
+       int rval;
+
+       debug_enter();
+       /* According to design guidelines the MCI simultaneous transaction
+        * shouldn't be enabled more then once - therefore make sure that it
+        * wasn't already enabled in bootrom.
+        */
+       if (mci_simulatenous_trans_missing(mci_index)) {
+               VERBOSE("Enabling MCI simultaneous transaction\n");
+               /* set MCI to support read/write transactions
+                * to arrive at the same time
+                */
+               rval = mci_enable_simultaneous_transactions(mci_index);
+               if (rval)
+                       ERROR("Failed to set MCI simultaneous read/write\n");
+       } else
+               VERBOSE("Skip MCI ID assignment - already done by bootrom\n");
+
+       /* Configure MCI for more consistent behavior with AXI protocol */
+       rval = mci_axi_set_pcie_mode(mci_index);
+       if (rval)
+               ERROR("Failed to set MCI to AXI PCIe mode\n");
+
+       /* reduce FIFO global threshold */
+       rval = mci_axi_set_fifo_thresh(mci_index);
+       if (rval)
+               ERROR("Failed to set MCI FIFO global threshold\n");
+
+       /* configure RX/TX FIFO thresholds */
+       rval = mci_axi_set_fifo_rx_tx_thresh(mci_index);
+       if (rval)
+               ERROR("Failed to set MCI RX/TX FIFO threshold\n");
+
+       debug_exit();
+       return 1;
+}
+
+int mci_get_link_status(void)
+{
+       uint32_t cmd, data;
+
+       cmd = (MCI_INDIRECT_REG_CTRL_ADDR(MCI_CTRL_STATUS_REG_NUM) |
+               MCI_INDIRECT_CTRL_LOCAL_PKT | MCI_INDIRECT_CTRL_READ_CMD);
+       if (mci_read(0, cmd, &data)) {
+               ERROR("Failed to read status register\n");
+               return -1;
+       }
+
+       /* Check if the link is ready */
+       if (data != MCI_CTRL_PHY_READY) {
+               ERROR("Bad link status %x\n", data);
+               return -1;
+       }
+
+       return 0;
+}
+
+void mci_turn_link_down(void)
+{
+       uint32_t cmd, data;
+       int rval = 0;
+
+       debug_enter();
+
+       /* Turn off auto-link */
+       cmd = (MCI_INDIRECT_REG_CTRL_ADDR(MCI_CTRL_MCI_PHY_SETTINGS_REG_NUM) |
+                       MCI_INDIRECT_CTRL_LOCAL_PKT);
+       data = (MCI_CTRL_MCI_PHY_SET_REG_DEF_VAL2 |
+               MCI_CTRL_MCI_PHY_SET_AUTO_LINK_EN(0));
+       rval = mci_write(0, cmd, data);
+       if (rval)
+               ERROR("Failed to turn off auto-link\n");
+
+       /* Reset AP PHY */
+       cmd = (MCI_INDIRECT_REG_CTRL_ADDR(MCI_PHY_CTRL_REG_NUM) |
+               MCI_INDIRECT_CTRL_LOCAL_PKT);
+       data = (MCI_PHY_CTRL_MCI_MINOR |
+               MCI_PHY_CTRL_MCI_MAJOR |
+               MCI_PHY_CTRL_MCI_PHY_MODE_HOST |
+               MCI_PHY_CTRL_MCI_PHY_RESET_CORE);
+       rval = mci_write(0, cmd, data);
+       if (rval)
+               ERROR("Failed to reset AP PHY\n");
+
+       /* Clear all status & CRC values */
+       cmd = (MCI_INDIRECT_REG_CTRL_ADDR(MCI_LINK_CRC_CTRL_REG_NUM) |
+              MCI_INDIRECT_CTRL_LOCAL_PKT);
+       data = 0x0;
+       mci_write(0, cmd, data);
+       cmd = (MCI_INDIRECT_REG_CTRL_ADDR(MCI_CTRL_STATUS_REG_NUM) |
+              MCI_INDIRECT_CTRL_LOCAL_PKT);
+       data = 0x0;
+       rval = mci_write(0, cmd, data);
+       if (rval)
+               ERROR("Failed to reset AP PHY\n");
+
+       /* Wait 5ms before un-reset the PHY */
+       mdelay(5);
+
+       /* Un-reset AP PHY */
+       cmd = (MCI_INDIRECT_REG_CTRL_ADDR(MCI_PHY_CTRL_REG_NUM) |
+              MCI_INDIRECT_CTRL_LOCAL_PKT);
+       data = (MCI_PHY_CTRL_MCI_MINOR | MCI_PHY_CTRL_MCI_MAJOR |
+               MCI_PHY_CTRL_MCI_PHY_MODE_HOST);
+       rval = mci_write(0, cmd, data);
+       if (rval)
+               ERROR("Failed to un-reset AP PHY\n");
+
+       debug_exit();
+}
+
+void mci_turn_link_on(void)
+{
+       uint32_t cmd, data;
+       int rval = 0;
+
+       debug_enter();
+       /* Turn on auto-link */
+       cmd = (MCI_INDIRECT_REG_CTRL_ADDR(MCI_CTRL_MCI_PHY_SETTINGS_REG_NUM) |
+                       MCI_INDIRECT_CTRL_LOCAL_PKT);
+       data = (MCI_CTRL_MCI_PHY_SET_REG_DEF_VAL2 |
+               MCI_CTRL_MCI_PHY_SET_AUTO_LINK_EN(1));
+       rval = mci_write(0, cmd, data);
+       if (rval)
+               ERROR("Failed to turn on auto-link\n");
+
+       debug_exit();
+}
+
+/* Initialize MCI for performance improvements */
+int mci_initialize(int mci_index)
+{
+       int ret;
+
+       debug_enter();
+       INFO("MCI%d initialization:\n", mci_index);
+
+       ret = mci_configure(mci_index);
+
+       debug_exit();
+       return ret;
+}
diff --git a/drivers/marvell/mochi/ap807_setup.c b/drivers/marvell/mochi/ap807_setup.c
new file mode 100644 (file)
index 0000000..075ca31
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:    BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* AP807 Marvell SoC driver */
+
+#include <ap_setup.h>
+#include <cache_llc.h>
+#include <ccu.h>
+#include <debug.h>
+#include <io_win.h>
+#include <mci.h>
+#include <mmio.h>
+#include <mvebu_def.h>
+
+#define SMMU_sACR                              (MVEBU_SMMU_BASE + 0x10)
+#define SMMU_sACR_PG_64K                       (1 << 16)
+
+#define CCU_GSPMU_CR                           (MVEBU_CCU_BASE(MVEBU_AP0) \
+                                                               + 0x3F0)
+#define GSPMU_CPU_CONTROL                      (0x1 << 0)
+
+#define CCU_HTC_CR                             (MVEBU_CCU_BASE(MVEBU_AP0) \
+                                                               + 0x200)
+#define CCU_SET_POC_OFFSET                     5
+
+#define DSS_CR0                                        (MVEBU_RFU_BASE + 0x100)
+#define DVM_48BIT_VA_ENABLE                    (1 << 21)
+
+/* Secure MoChi incoming access */
+#define SEC_MOCHI_IN_ACC_REG                   (MVEBU_RFU_BASE + 0x4738)
+#define SEC_MOCHI_IN_ACC_IHB0_EN               (1)
+#define SEC_MOCHI_IN_ACC_IHB1_EN               (1 << 3)
+#define SEC_MOCHI_IN_ACC_IHB2_EN               (1 << 6)
+#define SEC_MOCHI_IN_ACC_PIDI_EN               (1 << 9)
+#define SEC_IN_ACCESS_ENA_ALL_MASTERS          (SEC_MOCHI_IN_ACC_IHB0_EN | \
+                                                SEC_MOCHI_IN_ACC_IHB1_EN | \
+                                                SEC_MOCHI_IN_ACC_IHB2_EN | \
+                                                SEC_MOCHI_IN_ACC_PIDI_EN)
+
+/* SYSRST_OUTn Config definitions */
+#define MVEBU_SYSRST_OUT_CONFIG_REG            (MVEBU_MISC_SOC_BASE + 0x4)
+#define WD_MASK_SYS_RST_OUT                    (1 << 2)
+
+/* DSS PHY for DRAM */
+#define DSS_SCR_REG                            (MVEBU_RFU_BASE + 0x208)
+#define DSS_PPROT_OFFS                         4
+#define DSS_PPROT_MASK                         0x7
+#define DSS_PPROT_PRIV_SECURE_DATA             0x1
+
+/* Used for Units of AP-807 (e.g. SDIO and etc) */
+#define MVEBU_AXI_ATTR_BASE                    (MVEBU_REGS_BASE + 0x6F4580)
+#define MVEBU_AXI_ATTR_REG(index)              (MVEBU_AXI_ATTR_BASE + \
+                                                       0x4 * index)
+
+enum axi_attr {
+       AXI_SDIO_ATTR = 0,
+       AXI_DFX_ATTR,
+       AXI_MAX_ATTR,
+};
+
+static void ap_sec_masters_access_en(uint32_t enable)
+{
+       uint32_t reg;
+
+       /* Open/Close incoming access for all masters.
+        * The access is disabled in trusted boot mode
+        * Could only be done in EL3
+        */
+       reg = mmio_read_32(SEC_MOCHI_IN_ACC_REG);
+       if (enable)
+               mmio_write_32(SEC_MOCHI_IN_ACC_REG, reg |
+                             SEC_IN_ACCESS_ENA_ALL_MASTERS);
+       else
+               mmio_write_32(SEC_MOCHI_IN_ACC_REG,
+                             reg & ~SEC_IN_ACCESS_ENA_ALL_MASTERS);
+}
+
+static void setup_smmu(void)
+{
+       uint32_t reg;
+
+       /* Set the SMMU page size to 64 KB */
+       reg = mmio_read_32(SMMU_sACR);
+       reg |= SMMU_sACR_PG_64K;
+       mmio_write_32(SMMU_sACR, reg);
+}
+
+static void init_aurora2(void)
+{
+       uint32_t reg;
+
+       /* Enable GSPMU control by CPU */
+       reg = mmio_read_32(CCU_GSPMU_CR);
+       reg |= GSPMU_CPU_CONTROL;
+       mmio_write_32(CCU_GSPMU_CR, reg);
+
+#if LLC_ENABLE
+       /* Enable LLC for AP807 in exclusive mode */
+       llc_enable(0, 1);
+
+       /* Set point of coherency to DDR.
+        * This is required by units which have
+        * SW cache coherency
+        */
+       reg = mmio_read_32(CCU_HTC_CR);
+       reg |= (0x1 << CCU_SET_POC_OFFSET);
+       mmio_write_32(CCU_HTC_CR, reg);
+#endif /* LLC_ENABLE */
+}
+
+
+/* MCIx indirect access register are based by default at 0xf4000000/0xf6000000
+ * to avoid conflict of internal registers of units connected via MCIx, which
+ * can be based on the same address (i.e CP1 base is also 0xf4000000),
+ * the following routines remaps the MCIx indirect bases to another domain
+ */
+static void mci_remap_indirect_access_base(void)
+{
+       uint32_t mci;
+
+       for (mci = 0; mci < MCI_MAX_UNIT_ID; mci++)
+               mmio_write_32(MCIX4_REG_START_ADDRESS_REG(mci),
+                                 MVEBU_MCI_REG_BASE_REMAP(mci) >>
+                                 MCI_REMAP_OFF_SHIFT);
+}
+
+static void ap807_axi_attr_init(void)
+{
+       uint32_t index, data;
+
+       /* Initialize AXI attributes for AP807 */
+       /* Go over the AXI attributes and set Ax-Cache and Ax-Domain */
+       for (index = 0; index < AXI_MAX_ATTR; index++) {
+               switch (index) {
+               /* DFX works with no coherent only -
+                * there's no option to configure the Ax-Cache and Ax-Domain
+                */
+               case AXI_DFX_ATTR:
+                       continue;
+               default:
+                       /* Set Ax-Cache as cacheable, no allocate, modifiable,
+                        * bufferable.
+                        * The values are different because Read & Write
+                        * definition is different in Ax-Cache
+                        */
+                       data = mmio_read_32(MVEBU_AXI_ATTR_REG(index));
+                       data &= ~MVEBU_AXI_ATTR_ARCACHE_MASK;
+                       data |= (CACHE_ATTR_WRITE_ALLOC |
+                                CACHE_ATTR_CACHEABLE   |
+                                CACHE_ATTR_BUFFERABLE) <<
+                                MVEBU_AXI_ATTR_ARCACHE_OFFSET;
+                       data &= ~MVEBU_AXI_ATTR_AWCACHE_MASK;
+                       data |= (CACHE_ATTR_READ_ALLOC |
+                                CACHE_ATTR_CACHEABLE  |
+                                CACHE_ATTR_BUFFERABLE) <<
+                                MVEBU_AXI_ATTR_AWCACHE_OFFSET;
+                       /* Set Ax-Domain as Outer domain */
+                       data &= ~MVEBU_AXI_ATTR_ARDOMAIN_MASK;
+                       data |= DOMAIN_OUTER_SHAREABLE <<
+                               MVEBU_AXI_ATTR_ARDOMAIN_OFFSET;
+                       data &= ~MVEBU_AXI_ATTR_AWDOMAIN_MASK;
+                       data |= DOMAIN_OUTER_SHAREABLE <<
+                               MVEBU_AXI_ATTR_AWDOMAIN_OFFSET;
+                       mmio_write_32(MVEBU_AXI_ATTR_REG(index), data);
+               }
+       }
+}
+
+static void misc_soc_configurations(void)
+{
+       uint32_t reg;
+
+       /* Enable 48-bit VA */
+       mmio_setbits_32(DSS_CR0, DVM_48BIT_VA_ENABLE);
+
+       /* Un-mask Watchdog reset from influencing the SYSRST_OUTn.
+        * Otherwise, upon WD timeout, the WD reset signal won't trigger reset
+        */
+       reg = mmio_read_32(MVEBU_SYSRST_OUT_CONFIG_REG);
+       reg &= ~(WD_MASK_SYS_RST_OUT);
+       mmio_write_32(MVEBU_SYSRST_OUT_CONFIG_REG, reg);
+}
+
+void ap_init(void)
+{
+       /* Setup Aurora2. */
+       init_aurora2();
+
+       /* configure MCI mapping */
+       mci_remap_indirect_access_base();
+
+       /* configure IO_WIN windows */
+       init_io_win(MVEBU_AP0);
+
+       /* configure CCU windows */
+       init_ccu(MVEBU_AP0);
+
+       /* configure the SMMU */
+       setup_smmu();
+
+       /* Open AP incoming access for all masters */
+       ap_sec_masters_access_en(1);
+
+       /* configure axi for AP */
+       ap807_axi_attr_init();
+
+       /* misc configuration of the SoC */
+       misc_soc_configurations();
+}
+
+static void ap807_dram_phy_access_config(void)
+{
+       uint32_t reg_val;
+       /* Update DSS port access permission to DSS_PHY */
+       reg_val = mmio_read_32(DSS_SCR_REG);
+       reg_val &= ~(DSS_PPROT_MASK << DSS_PPROT_OFFS);
+       reg_val |= ((DSS_PPROT_PRIV_SECURE_DATA & DSS_PPROT_MASK) <<
+                   DSS_PPROT_OFFS);
+       mmio_write_32(DSS_SCR_REG, reg_val);
+}
+
+void ap_ble_init(void)
+{
+       /* Enable DSS port */
+       ap807_dram_phy_access_config();
+}
+
+int ap_get_count(void)
+{
+       return 1;
+}
+
+
diff --git a/drivers/marvell/mochi/apn806_setup.c b/drivers/marvell/mochi/apn806_setup.c
new file mode 100644 (file)
index 0000000..1d33be9
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* AP806 Marvell SoC driver */
+
+#include <ap_setup.h>
+#include <ccu.h>
+#include <cache_llc.h>
+#include <debug.h>
+#include <io_win.h>
+#include <mci.h>
+#include <mmio.h>
+#include <mvebu_def.h>
+
+#define SMMU_sACR                              (MVEBU_SMMU_BASE + 0x10)
+#define SMMU_sACR_PG_64K                       (1 << 16)
+
+#define CCU_GSPMU_CR                           (MVEBU_CCU_BASE(MVEBU_AP0) + \
+                                                       0x3F0)
+#define GSPMU_CPU_CONTROL                      (0x1 << 0)
+
+#define CCU_HTC_CR                             (MVEBU_CCU_BASE(MVEBU_AP0) + \
+                                                       0x200)
+#define CCU_SET_POC_OFFSET                     5
+
+#define CCU_RGF(win)                           (MVEBU_CCU_BASE(MVEBU_AP0) + \
+                                                       0x90 + 4 * (win))
+
+#define DSS_CR0                                        (MVEBU_RFU_BASE + 0x100)
+#define DVM_48BIT_VA_ENABLE                    (1 << 21)
+
+/* Secure MoChi incoming access */
+#define SEC_MOCHI_IN_ACC_REG                   (MVEBU_RFU_BASE + 0x4738)
+#define SEC_MOCHI_IN_ACC_IHB0_EN               (1)
+#define SEC_MOCHI_IN_ACC_IHB1_EN               (1 << 3)
+#define SEC_MOCHI_IN_ACC_IHB2_EN               (1 << 6)
+#define SEC_MOCHI_IN_ACC_PIDI_EN               (1 << 9)
+#define SEC_IN_ACCESS_ENA_ALL_MASTERS          (SEC_MOCHI_IN_ACC_IHB0_EN | \
+                                                SEC_MOCHI_IN_ACC_IHB1_EN | \
+                                                SEC_MOCHI_IN_ACC_IHB2_EN | \
+                                                SEC_MOCHI_IN_ACC_PIDI_EN)
+
+/* SYSRST_OUTn Config definitions */
+#define MVEBU_SYSRST_OUT_CONFIG_REG            (MVEBU_MISC_SOC_BASE + 0x4)
+#define WD_MASK_SYS_RST_OUT                    (1 << 2)
+
+/* Generic Timer System Controller */
+#define MVEBU_MSS_GTCR_REG                     (MVEBU_REGS_BASE + 0x581000)
+#define MVEBU_MSS_GTCR_ENABLE_BIT              0x1
+
+/*
+ * AXI Configuration.
+ */
+
+/* Used for Units of AP-806 (e.g. SDIO and etc) */
+#define MVEBU_AXI_ATTR_BASE                    (MVEBU_REGS_BASE + 0x6F4580)
+#define MVEBU_AXI_ATTR_REG(index)              (MVEBU_AXI_ATTR_BASE + \
+                                                       0x4 * index)
+
+enum axi_attr {
+       AXI_SDIO_ATTR = 0,
+       AXI_DFX_ATTR,
+       AXI_MAX_ATTR,
+};
+
+static void apn_sec_masters_access_en(uint32_t enable)
+{
+       uint32_t reg;
+
+       /* Open/Close incoming access for all masters.
+        * The access is disabled in trusted boot mode
+        * Could only be done in EL3
+        */
+       reg = mmio_read_32(SEC_MOCHI_IN_ACC_REG);
+       if (enable)
+               mmio_write_32(SEC_MOCHI_IN_ACC_REG, reg |
+                             SEC_IN_ACCESS_ENA_ALL_MASTERS);
+       else
+               mmio_write_32(SEC_MOCHI_IN_ACC_REG, reg &
+                             ~SEC_IN_ACCESS_ENA_ALL_MASTERS);
+}
+
+static void setup_smmu(void)
+{
+       uint32_t reg;
+
+       /* Set the SMMU page size to 64 KB */
+       reg = mmio_read_32(SMMU_sACR);
+       reg |= SMMU_sACR_PG_64K;
+       mmio_write_32(SMMU_sACR, reg);
+}
+
+static void apn806_errata_wa_init(void)
+{
+       /*
+        * ERRATA ID: RES-3033912 - Internal Address Space Init state causes
+        * a hang upon accesses to [0xf070_0000, 0xf07f_ffff]
+        * Workaround: Boot Firmware (ATF) should configure CCU_RGF_WIN(4) to
+        * split [0x6e_0000, 0xff_ffff] to values [0x6e_0000, 0x6f_ffff] and
+        * [0x80_0000, 0xff_ffff] that cause accesses to the
+        * segment of [0xf070_0000, 0xf07f_ffff] to act as RAZWI.
+        */
+       mmio_write_32(CCU_RGF(4), 0x37f9b809);
+       mmio_write_32(CCU_RGF(5), 0x7ffa0009);
+}
+
+static void init_aurora2(void)
+{
+       uint32_t reg;
+
+       /* Enable GSPMU control by CPU */
+       reg = mmio_read_32(CCU_GSPMU_CR);
+       reg |= GSPMU_CPU_CONTROL;
+       mmio_write_32(CCU_GSPMU_CR, reg);
+
+#if LLC_ENABLE
+       /* Enable LLC for AP806 in exclusive mode */
+       llc_enable(0, 1);
+
+       /* Set point of coherency to DDR.
+        * This is required by units which have
+        * SW cache coherency
+        */
+       reg = mmio_read_32(CCU_HTC_CR);
+       reg |= (0x1 << CCU_SET_POC_OFFSET);
+       mmio_write_32(CCU_HTC_CR, reg);
+#endif /* LLC_ENABLE */
+
+       apn806_errata_wa_init();
+}
+
+
+/* MCIx indirect access register are based by default at 0xf4000000/0xf6000000
+ * to avoid conflict of internal registers of units connected via MCIx, which
+ * can be based on the same address (i.e CP1 base is also 0xf4000000),
+ * the following routines remaps the MCIx indirect bases to another domain
+ */
+static void mci_remap_indirect_access_base(void)
+{
+       uint32_t mci;
+
+       for (mci = 0; mci < MCI_MAX_UNIT_ID; mci++)
+               mmio_write_32(MCIX4_REG_START_ADDRESS_REG(mci),
+                             MVEBU_MCI_REG_BASE_REMAP(mci) >>
+                             MCI_REMAP_OFF_SHIFT);
+}
+
+static void apn806_axi_attr_init(void)
+{
+       uint32_t index, data;
+
+       /* Initialize AXI attributes for APN806 */
+
+       /* Go over the AXI attributes and set Ax-Cache and Ax-Domain */
+       for (index = 0; index < AXI_MAX_ATTR; index++) {
+               switch (index) {
+               /* DFX works with no coherent only -
+                * there's no option to configure the Ax-Cache and Ax-Domain
+                */
+               case AXI_DFX_ATTR:
+                       continue;
+               default:
+                       /* Set Ax-Cache as cacheable, no allocate, modifiable,
+                        * bufferable
+                        * The values are different because Read & Write
+                        * definition is different in Ax-Cache
+                        */
+                       data = mmio_read_32(MVEBU_AXI_ATTR_REG(index));
+                       data &= ~MVEBU_AXI_ATTR_ARCACHE_MASK;
+                       data |= (CACHE_ATTR_WRITE_ALLOC |
+                                CACHE_ATTR_CACHEABLE   |
+                                CACHE_ATTR_BUFFERABLE) <<
+                                MVEBU_AXI_ATTR_ARCACHE_OFFSET;
+                       data &= ~MVEBU_AXI_ATTR_AWCACHE_MASK;
+                       data |= (CACHE_ATTR_READ_ALLOC |
+                                CACHE_ATTR_CACHEABLE  |
+                                CACHE_ATTR_BUFFERABLE) <<
+                                MVEBU_AXI_ATTR_AWCACHE_OFFSET;
+                       /* Set Ax-Domain as Outer domain */
+                       data &= ~MVEBU_AXI_ATTR_ARDOMAIN_MASK;
+                       data |= DOMAIN_OUTER_SHAREABLE <<
+                               MVEBU_AXI_ATTR_ARDOMAIN_OFFSET;
+                       data &= ~MVEBU_AXI_ATTR_AWDOMAIN_MASK;
+                       data |= DOMAIN_OUTER_SHAREABLE <<
+                               MVEBU_AXI_ATTR_AWDOMAIN_OFFSET;
+                       mmio_write_32(MVEBU_AXI_ATTR_REG(index), data);
+               }
+       }
+}
+
+static void dss_setup(void)
+{
+       /* Enable 48-bit VA */
+       mmio_setbits_32(DSS_CR0, DVM_48BIT_VA_ENABLE);
+}
+
+void misc_soc_configurations(void)
+{
+       uint32_t reg;
+
+       /* Un-mask Watchdog reset from influencing the SYSRST_OUTn.
+        * Otherwise, upon WD timeout, the WD reset signal won't trigger reset
+        */
+       reg = mmio_read_32(MVEBU_SYSRST_OUT_CONFIG_REG);
+       reg &= ~(WD_MASK_SYS_RST_OUT);
+       mmio_write_32(MVEBU_SYSRST_OUT_CONFIG_REG, reg);
+}
+
+void ap_init(void)
+{
+       /* Setup Aurora2. */
+       init_aurora2();
+
+       /* configure MCI mapping */
+       mci_remap_indirect_access_base();
+
+       /* configure IO_WIN windows */
+       init_io_win(MVEBU_AP0);
+
+       /* configure CCU windows */
+       init_ccu(MVEBU_AP0);
+
+       /* configure DSS */
+       dss_setup();
+
+       /* configure the SMMU */
+       setup_smmu();
+
+       /* Open APN incoming access for all masters */
+       apn_sec_masters_access_en(1);
+
+       /* configure axi for APN*/
+       apn806_axi_attr_init();
+
+       /* misc configuration of the SoC */
+       misc_soc_configurations();
+}
+
+void ap_ble_init(void)
+{
+}
+
+int ap_get_count(void)
+{
+       return 1;
+}
+
diff --git a/drivers/marvell/mochi/cp110_setup.c b/drivers/marvell/mochi/cp110_setup.c
new file mode 100644 (file)
index 0000000..c4cb307
--- /dev/null
@@ -0,0 +1,429 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* CP110 Marvell SoC driver */
+
+#include <amb_adec.h>
+#include <cp110_setup.h>
+#include <debug.h>
+#include <delay_timer.h>
+#include <iob.h>
+#include <plat_marvell.h>
+
+/*
+ * AXI Configuration.
+ */
+
+ /* Used for Units of CP-110 (e.g. USB device, USB Host, and etc) */
+#define MVEBU_AXI_ATTR_OFFSET                  (0x441300)
+#define MVEBU_AXI_ATTR_REG(index)              (MVEBU_AXI_ATTR_OFFSET + \
+                                                       0x4 * index)
+
+/* AXI Protection bits */
+#define MVEBU_AXI_PROT_OFFSET                          (0x441200)
+
+/* AXI Protection regs */
+#define MVEBU_AXI_PROT_REG(index)              ((index <= 4) ? \
+                                               (MVEBU_AXI_PROT_OFFSET + \
+                                                       0x4 * index) : \
+                                               (MVEBU_AXI_PROT_OFFSET + 0x18))
+#define MVEBU_AXI_PROT_REGS_NUM                        (6)
+
+#define MVEBU_SOC_CFGS_OFFSET                  (0x441900)
+#define MVEBU_SOC_CFG_REG(index)               (MVEBU_SOC_CFGS_OFFSET + \
+                                                       0x4 * index)
+#define MVEBU_SOC_CFG_REG_NUM                  (0)
+#define MVEBU_SOC_CFG_GLOG_SECURE_EN_MASK      (0xE)
+
+/* SATA3 MBUS to AXI regs */
+#define MVEBU_BRIDGE_WIN_DIS_REG               (MVEBU_SOC_CFGS_OFFSET + 0x10)
+#define MVEBU_BRIDGE_WIN_DIS_OFF               (0x0)
+
+/* SATA3 MBUS to AXI regs */
+#define MVEBU_SATA_M2A_AXI_PORT_CTRL_REG       (0x54ff04)
+
+/* AXI to MBUS bridge registers */
+#define MVEBU_AMB_IP_OFFSET                    (0x13ff00)
+#define MVEBU_AMB_IP_BRIDGE_WIN_REG(win)       (MVEBU_AMB_IP_OFFSET + \
+                                                       (win * 0x8))
+#define MVEBU_AMB_IP_BRIDGE_WIN_EN_OFFSET      0
+#define MVEBU_AMB_IP_BRIDGE_WIN_EN_MASK                \
+                               (0x1 << MVEBU_AMB_IP_BRIDGE_WIN_EN_OFFSET)
+#define MVEBU_AMB_IP_BRIDGE_WIN_SIZE_OFFSET    16
+#define MVEBU_AMB_IP_BRIDGE_WIN_SIZE_MASK      \
+                               (0xffff << MVEBU_AMB_IP_BRIDGE_WIN_SIZE_OFFSET)
+
+#define MVEBU_SAMPLE_AT_RESET_REG      (0x440600)
+#define SAR_PCIE1_CLK_CFG_OFFSET       31
+#define SAR_PCIE1_CLK_CFG_MASK         (0x1 << SAR_PCIE1_CLK_CFG_OFFSET)
+#define SAR_PCIE0_CLK_CFG_OFFSET       30
+#define SAR_PCIE0_CLK_CFG_MASK         (0x1 << SAR_PCIE0_CLK_CFG_OFFSET)
+#define SAR_I2C_INIT_EN_OFFSET         24
+#define SAR_I2C_INIT_EN_MASK           (1 << SAR_I2C_INIT_EN_OFFSET)
+
+/*******************************************************************************
+ * PCIE clock buffer control
+ ******************************************************************************/
+#define MVEBU_PCIE_REF_CLK_BUF_CTRL                    (0x4404F0)
+#define PCIE1_REFCLK_BUFF_SOURCE                       0x800
+#define PCIE0_REFCLK_BUFF_SOURCE                       0x400
+
+/*******************************************************************************
+ * MSS Device Push Set Register
+ ******************************************************************************/
+#define MVEBU_CP_MSS_DPSHSR_REG                                (0x280040)
+#define MSS_DPSHSR_REG_PCIE_CLK_SEL                    0x8
+
+/*******************************************************************************
+ * RTC Configuration
+ ******************************************************************************/
+#define MVEBU_RTC_BASE                                 (0x284000)
+#define MVEBU_RTC_STATUS_REG                           (MVEBU_RTC_BASE + 0x0)
+#define MVEBU_RTC_STATUS_ALARM1_MASK                   0x1
+#define MVEBU_RTC_STATUS_ALARM2_MASK                   0x2
+#define MVEBU_RTC_IRQ_1_CONFIG_REG                     (MVEBU_RTC_BASE + 0x4)
+#define MVEBU_RTC_IRQ_2_CONFIG_REG                     (MVEBU_RTC_BASE + 0x8)
+#define MVEBU_RTC_TIME_REG                             (MVEBU_RTC_BASE + 0xC)
+#define MVEBU_RTC_ALARM_1_REG                          (MVEBU_RTC_BASE + 0x10)
+#define MVEBU_RTC_ALARM_2_REG                          (MVEBU_RTC_BASE + 0x14)
+#define MVEBU_RTC_CCR_REG                              (MVEBU_RTC_BASE + 0x18)
+#define MVEBU_RTC_NOMINAL_TIMING                       0x2000
+#define MVEBU_RTC_NOMINAL_TIMING_MASK                  0x7FFF
+#define MVEBU_RTC_TEST_CONFIG_REG                      (MVEBU_RTC_BASE + 0x1C)
+#define MVEBU_RTC_BRIDGE_TIMING_CTRL0_REG              (MVEBU_RTC_BASE + 0x80)
+#define MVEBU_RTC_WRCLK_PERIOD_MASK                    0xFFFF
+#define MVEBU_RTC_WRCLK_PERIOD_DEFAULT                 0x3FF
+#define MVEBU_RTC_WRCLK_SETUP_OFFS                     16
+#define MVEBU_RTC_WRCLK_SETUP_MASK                     0xFFFF0000
+#define MVEBU_RTC_WRCLK_SETUP_DEFAULT                  0x29
+#define MVEBU_RTC_BRIDGE_TIMING_CTRL1_REG              (MVEBU_RTC_BASE + 0x84)
+#define MVEBU_RTC_READ_OUTPUT_DELAY_MASK               0xFFFF
+#define MVEBU_RTC_READ_OUTPUT_DELAY_DEFAULT            0x1F
+
+enum axi_attr {
+       AXI_ADUNIT_ATTR = 0,
+       AXI_COMUNIT_ATTR,
+       AXI_EIP197_ATTR,
+       AXI_USB3D_ATTR,
+       AXI_USB3H0_ATTR,
+       AXI_USB3H1_ATTR,
+       AXI_SATA0_ATTR,
+       AXI_SATA1_ATTR,
+       AXI_DAP_ATTR,
+       AXI_DFX_ATTR,
+       AXI_DBG_TRC_ATTR = 12,
+       AXI_SDIO_ATTR,
+       AXI_MSS_ATTR,
+       AXI_MAX_ATTR,
+};
+
+/* Most stream IDS are configured centrally in the CP-110 RFU
+ * but some are configured inside the unit registers
+ */
+#define RFU_STREAM_ID_BASE     (0x450000)
+#define USB3H_0_STREAM_ID_REG  (RFU_STREAM_ID_BASE + 0xC)
+#define USB3H_1_STREAM_ID_REG  (RFU_STREAM_ID_BASE + 0x10)
+#define SATA_0_STREAM_ID_REG   (RFU_STREAM_ID_BASE + 0x14)
+#define SATA_1_STREAM_ID_REG   (RFU_STREAM_ID_BASE + 0x18)
+
+#define CP_DMA_0_STREAM_ID_REG  (0x6B0010)
+#define CP_DMA_1_STREAM_ID_REG  (0x6D0010)
+
+/* We allocate IDs 128-255 for PCIe */
+#define MAX_STREAM_ID          (0x80)
+
+uintptr_t stream_id_reg[] = {
+       USB3H_0_STREAM_ID_REG,
+       USB3H_1_STREAM_ID_REG,
+       CP_DMA_0_STREAM_ID_REG,
+       CP_DMA_1_STREAM_ID_REG,
+       SATA_0_STREAM_ID_REG,
+       SATA_1_STREAM_ID_REG,
+       0
+};
+
+static void cp110_errata_wa_init(uintptr_t base)
+{
+       uint32_t data;
+
+       /* ERRATA GL-4076863:
+        * Reset value for global_secure_enable inputs must be changed
+        * from '1' to '0'.
+        * When asserted, only "secured" transactions can enter IHB
+        * configuration space.
+        * However, blocking AXI transactions is performed by IOB.
+        * Performing it also at IHB/HB complicates programming model.
+        *
+        * Enable non-secure access in SOC configuration register
+        */
+       data = mmio_read_32(base + MVEBU_SOC_CFG_REG(MVEBU_SOC_CFG_REG_NUM));
+       data &= ~MVEBU_SOC_CFG_GLOG_SECURE_EN_MASK;
+       mmio_write_32(base + MVEBU_SOC_CFG_REG(MVEBU_SOC_CFG_REG_NUM), data);
+}
+
+static void cp110_pcie_clk_cfg(uintptr_t base)
+{
+       uint32_t pcie0_clk, pcie1_clk, reg;
+
+       /*
+        * Determine the pcie0/1 clock direction (input/output) from the
+        * sample at reset.
+        */
+       reg = mmio_read_32(base + MVEBU_SAMPLE_AT_RESET_REG);
+       pcie0_clk = (reg & SAR_PCIE0_CLK_CFG_MASK) >> SAR_PCIE0_CLK_CFG_OFFSET;
+       pcie1_clk = (reg & SAR_PCIE1_CLK_CFG_MASK) >> SAR_PCIE1_CLK_CFG_OFFSET;
+
+       /* CP110 revision A2 */
+       if (cp110_rev_id_get(base) == MVEBU_CP110_REF_ID_A2) {
+               /*
+                * PCIe Reference Clock Buffer Control register must be
+                * set according to the clock direction (input/output)
+                */
+               reg = mmio_read_32(base + MVEBU_PCIE_REF_CLK_BUF_CTRL);
+               reg &= ~(PCIE0_REFCLK_BUFF_SOURCE | PCIE1_REFCLK_BUFF_SOURCE);
+               if (!pcie0_clk)
+                       reg |= PCIE0_REFCLK_BUFF_SOURCE;
+               if (!pcie1_clk)
+                       reg |= PCIE1_REFCLK_BUFF_SOURCE;
+
+               mmio_write_32(base + MVEBU_PCIE_REF_CLK_BUF_CTRL, reg);
+       }
+
+       /* CP110 revision A1 */
+       if (cp110_rev_id_get(base) == MVEBU_CP110_REF_ID_A1) {
+               if (!pcie0_clk || !pcie1_clk) {
+                       /*
+                        * if one of the pcie clocks is set to input,
+                        * we need to set mss_push[131] field, otherwise,
+                        * the pcie clock might not work.
+                        */
+                       reg = mmio_read_32(base + MVEBU_CP_MSS_DPSHSR_REG);
+                       reg |= MSS_DPSHSR_REG_PCIE_CLK_SEL;
+                       mmio_write_32(base + MVEBU_CP_MSS_DPSHSR_REG, reg);
+               }
+       }
+}
+
+/* Set a unique stream id for all DMA capable devices */
+static void cp110_stream_id_init(uintptr_t base, uint32_t stream_id)
+{
+       int i = 0;
+
+       while (stream_id_reg[i]) {
+               if (i > MAX_STREAM_ID_PER_CP) {
+                       NOTICE("Only first %d (maximum) Stream IDs allocated\n",
+                              MAX_STREAM_ID_PER_CP);
+                       return;
+               }
+
+               if ((stream_id_reg[i] == CP_DMA_0_STREAM_ID_REG) ||
+                   (stream_id_reg[i] == CP_DMA_1_STREAM_ID_REG))
+                       mmio_write_32(base + stream_id_reg[i],
+                                     stream_id << 16 |  stream_id);
+               else
+                       mmio_write_32(base + stream_id_reg[i], stream_id);
+
+               /* SATA port 0/1 are in the same SATA unit, and they should use
+                * the same STREAM ID number
+                */
+               if (stream_id_reg[i] != SATA_0_STREAM_ID_REG)
+                       stream_id++;
+
+               i++;
+       }
+}
+
+static void cp110_axi_attr_init(uintptr_t base)
+{
+       uint32_t index, data;
+
+       /* Initialize AXI attributes for Armada-7K/8K SoC */
+
+       /* Go over the AXI attributes and set Ax-Cache and Ax-Domain */
+       for (index = 0; index < AXI_MAX_ATTR; index++) {
+               switch (index) {
+               /* DFX and MSS unit works with no coherent only -
+                * there's no option to configure the Ax-Cache and Ax-Domain
+                */
+               case AXI_DFX_ATTR:
+               case AXI_MSS_ATTR:
+                       continue;
+               default:
+                       /* Set Ax-Cache as cacheable, no allocate, modifiable,
+                        * bufferable
+                        * The values are different because Read & Write
+                        * definition is different in Ax-Cache
+                        */
+                       data = mmio_read_32(base + MVEBU_AXI_ATTR_REG(index));
+                       data &= ~MVEBU_AXI_ATTR_ARCACHE_MASK;
+                       data |= (CACHE_ATTR_WRITE_ALLOC |
+                                CACHE_ATTR_CACHEABLE   |
+                                CACHE_ATTR_BUFFERABLE) <<
+                                MVEBU_AXI_ATTR_ARCACHE_OFFSET;
+                       data &= ~MVEBU_AXI_ATTR_AWCACHE_MASK;
+                       data |= (CACHE_ATTR_READ_ALLOC |
+                                CACHE_ATTR_CACHEABLE  |
+                                CACHE_ATTR_BUFFERABLE) <<
+                                MVEBU_AXI_ATTR_AWCACHE_OFFSET;
+                       /* Set Ax-Domain as Outer domain */
+                       data &= ~MVEBU_AXI_ATTR_ARDOMAIN_MASK;
+                       data |= DOMAIN_OUTER_SHAREABLE <<
+                               MVEBU_AXI_ATTR_ARDOMAIN_OFFSET;
+                       data &= ~MVEBU_AXI_ATTR_AWDOMAIN_MASK;
+                       data |= DOMAIN_OUTER_SHAREABLE <<
+                               MVEBU_AXI_ATTR_AWDOMAIN_OFFSET;
+                       mmio_write_32(base + MVEBU_AXI_ATTR_REG(index), data);
+               }
+       }
+
+       /* SATA IOCC supported, cache attributes
+        * for SATA MBUS to AXI configuration.
+        */
+       data = mmio_read_32(base + MVEBU_SATA_M2A_AXI_PORT_CTRL_REG);
+       data &= ~MVEBU_SATA_M2A_AXI_AWCACHE_MASK;
+       data |= (CACHE_ATTR_WRITE_ALLOC |
+                CACHE_ATTR_CACHEABLE   |
+                CACHE_ATTR_BUFFERABLE) <<
+                MVEBU_SATA_M2A_AXI_AWCACHE_OFFSET;
+       data &= ~MVEBU_SATA_M2A_AXI_ARCACHE_MASK;
+       data |= (CACHE_ATTR_READ_ALLOC |
+                CACHE_ATTR_CACHEABLE  |
+                CACHE_ATTR_BUFFERABLE) <<
+                MVEBU_SATA_M2A_AXI_ARCACHE_OFFSET;
+       mmio_write_32(base + MVEBU_SATA_M2A_AXI_PORT_CTRL_REG, data);
+
+       /* Set all IO's AXI attribute to non-secure access. */
+       for (index = 0; index < MVEBU_AXI_PROT_REGS_NUM; index++)
+               mmio_write_32(base + MVEBU_AXI_PROT_REG(index),
+                             DOMAIN_SYSTEM_SHAREABLE);
+}
+
+static void amb_bridge_init(uintptr_t base)
+{
+       uint32_t reg;
+
+       /* Open AMB bridge Window to Access COMPHY/MDIO registers */
+       reg = mmio_read_32(base + MVEBU_AMB_IP_BRIDGE_WIN_REG(0));
+       reg &= ~(MVEBU_AMB_IP_BRIDGE_WIN_SIZE_MASK |
+                MVEBU_AMB_IP_BRIDGE_WIN_EN_MASK);
+       reg |= (0x7ff << MVEBU_AMB_IP_BRIDGE_WIN_SIZE_OFFSET) |
+              (0x1 << MVEBU_AMB_IP_BRIDGE_WIN_EN_OFFSET);
+       mmio_write_32(base + MVEBU_AMB_IP_BRIDGE_WIN_REG(0), reg);
+}
+
+static void cp110_rtc_init(uintptr_t base)
+{
+       /* Update MBus timing parameters before accessing RTC registers */
+       mmio_clrsetbits_32(base + MVEBU_RTC_BRIDGE_TIMING_CTRL0_REG,
+                          MVEBU_RTC_WRCLK_PERIOD_MASK,
+                          MVEBU_RTC_WRCLK_PERIOD_DEFAULT);
+
+       mmio_clrsetbits_32(base + MVEBU_RTC_BRIDGE_TIMING_CTRL0_REG,
+                          MVEBU_RTC_WRCLK_SETUP_MASK,
+                          MVEBU_RTC_WRCLK_SETUP_DEFAULT <<
+                          MVEBU_RTC_WRCLK_SETUP_OFFS);
+
+       mmio_clrsetbits_32(base + MVEBU_RTC_BRIDGE_TIMING_CTRL1_REG,
+                          MVEBU_RTC_READ_OUTPUT_DELAY_MASK,
+                          MVEBU_RTC_READ_OUTPUT_DELAY_DEFAULT);
+
+       /*
+        * Issue reset to the RTC if Clock Correction register
+        * contents did not sustain the reboot/power-on.
+        */
+       if ((mmio_read_32(base + MVEBU_RTC_CCR_REG) &
+           MVEBU_RTC_NOMINAL_TIMING_MASK) != MVEBU_RTC_NOMINAL_TIMING) {
+               /* Reset Test register */
+               mmio_write_32(base + MVEBU_RTC_TEST_CONFIG_REG, 0);
+               mdelay(500);
+
+               /* Reset Time register */
+               mmio_write_32(base + MVEBU_RTC_TIME_REG, 0);
+               udelay(62);
+
+               /* Reset Status register */
+               mmio_write_32(base + MVEBU_RTC_STATUS_REG,
+                             (MVEBU_RTC_STATUS_ALARM1_MASK |
+                             MVEBU_RTC_STATUS_ALARM2_MASK));
+               udelay(62);
+
+               /* Turn off Int1 and Int2 sources & clear the Alarm count */
+               mmio_write_32(base + MVEBU_RTC_IRQ_1_CONFIG_REG, 0);
+               mmio_write_32(base + MVEBU_RTC_IRQ_2_CONFIG_REG, 0);
+               mmio_write_32(base + MVEBU_RTC_ALARM_1_REG, 0);
+               mmio_write_32(base + MVEBU_RTC_ALARM_2_REG, 0);
+
+               /* Setup nominal register access timing */
+               mmio_write_32(base + MVEBU_RTC_CCR_REG,
+                             MVEBU_RTC_NOMINAL_TIMING);
+
+               /* Reset Time register */
+               mmio_write_32(base + MVEBU_RTC_TIME_REG, 0);
+               udelay(10);
+
+               /* Reset Status register */
+               mmio_write_32(base + MVEBU_RTC_STATUS_REG,
+                             (MVEBU_RTC_STATUS_ALARM1_MASK |
+                             MVEBU_RTC_STATUS_ALARM2_MASK));
+               udelay(50);
+       }
+}
+
+static void cp110_amb_adec_init(uintptr_t base)
+{
+       /* enable AXI-MBUS by clearing "Bridge Windows Disable" */
+       mmio_clrbits_32(base + MVEBU_BRIDGE_WIN_DIS_REG,
+                       (1 << MVEBU_BRIDGE_WIN_DIS_OFF));
+
+       /* configure AXI-MBUS windows for CP */
+       init_amb_adec(base);
+}
+
+void cp110_init(uintptr_t cp110_base, uint32_t stream_id)
+{
+       INFO("%s: Initialize CPx - base = %lx\n", __func__, cp110_base);
+
+       /* configure IOB windows for CP0*/
+       init_iob(cp110_base);
+
+       /* configure AXI-MBUS windows for CP0*/
+       cp110_amb_adec_init(cp110_base);
+
+       /* configure axi for CP0*/
+       cp110_axi_attr_init(cp110_base);
+
+       /* Execute SW WA for erratas */
+       cp110_errata_wa_init(cp110_base);
+
+       /* Confiure pcie clock according to clock direction */
+       cp110_pcie_clk_cfg(cp110_base);
+
+       /* configure stream id for CP0 */
+       cp110_stream_id_init(cp110_base, stream_id);
+
+       /* Open AMB bridge for comphy for CP0 & CP1*/
+       amb_bridge_init(cp110_base);
+
+       /* Reset RTC if needed */
+       cp110_rtc_init(cp110_base);
+}
+
+/* Do the minimal setup required to configure the CP in BLE */
+void cp110_ble_init(uintptr_t cp110_base)
+{
+#if PCI_EP_SUPPORT
+       INFO("%s: Initialize CPx - base = %lx\n", __func__, cp110_base);
+
+       amb_bridge_init(cp110_base);
+
+       /* Configure PCIe clock */
+       cp110_pcie_clk_cfg(cp110_base);
+
+       /* Configure PCIe endpoint */
+       ble_plat_pcie_ep_setup();
+#endif
+}
diff --git a/drivers/marvell/thermal.c b/drivers/marvell/thermal.c
new file mode 100644 (file)
index 0000000..c7ceb92
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:    BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* Driver for thermal unit located in Marvell ARMADA 8K and compatible SoCs */
+
+#include <debug.h>
+#include <thermal.h>
+
+int marvell_thermal_init(struct tsen_config *tsen_cfg)
+{
+       if (tsen_cfg->tsen_ready == 1) {
+               INFO("thermal sensor is already initialized\n");
+               return 0;
+       }
+
+       if (tsen_cfg->ptr_tsen_probe == NULL) {
+               ERROR("initial thermal sensor configuration is missing\n");
+               return -1;
+       }
+
+       if (tsen_cfg->ptr_tsen_probe(tsen_cfg)) {
+               ERROR("thermal sensor initialization failed\n");
+               return -1;
+       }
+
+       VERBOSE("thermal sensor was initialized\n");
+
+       return 0;
+}
+
+int marvell_thermal_read(struct tsen_config *tsen_cfg, int *temp)
+{
+       if (temp == NULL) {
+               ERROR("NULL pointer for temperature read\n");
+               return -1;
+       }
+
+       if (tsen_cfg->ptr_tsen_read == NULL ||
+           tsen_cfg->tsen_ready == 0) {
+               ERROR("thermal sensor was not initialized\n");
+               return -1;
+       }
+
+       if (tsen_cfg->ptr_tsen_read(tsen_cfg, temp)) {
+               ERROR("temperature read failed\n");
+               return -1;
+       }
+
+       return 0;
+}
diff --git a/include/drivers/marvell/a8k_i2c.h b/include/drivers/marvell/a8k_i2c.h
new file mode 100644 (file)
index 0000000..8a9abe8
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* This driver provides I2C support for Marvell A8K and compatible SoCs */
+
+#ifndef _A8K_I2C_H_
+#define _A8K_I2C_H_
+
+#include <stdint.h>
+
+/*
+ * Initialization, must be called once on start up, may be called
+ * repeatedly to change the speed and slave addresses.
+ */
+void i2c_init(void *i2c_base);
+
+/*
+ * Read/Write interface:
+ *   chip:    I2C chip address, range 0..127
+ *   addr:    Memory (register) address within the chip
+ *   alen:    Number of bytes to use for addr (typically 1, 2 for larger
+ *              memories, 0 for register type devices with only one
+ *              register)
+ *   buffer:  Where to read/write the data
+ *   len:     How many bytes to read/write
+ *
+ *   Returns: 0 on success, not 0 on failure
+ */
+int i2c_read(uint8_t chip,
+            unsigned int addr, int alen, uint8_t *buffer, int len);
+
+int i2c_write(uint8_t chip,
+             unsigned int addr, int alen, uint8_t *buffer, int len);
+#endif
diff --git a/include/drivers/marvell/addr_map.h b/include/drivers/marvell/addr_map.h
new file mode 100644 (file)
index 0000000..6b957a1
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* Address map types for Marvell address translation unit drivers */
+
+#ifndef _ADDR_MAP_H_
+#define _ADDR_MAP_H_
+
+#include <stdint.h>
+
+struct addr_map_win {
+       uint64_t base_addr;
+       uint64_t win_size;
+       uint32_t target_id;
+};
+
+#endif /* _ADDR_MAP_H_ */
diff --git a/include/drivers/marvell/amb_adec.h b/include/drivers/marvell/amb_adec.h
new file mode 100644 (file)
index 0000000..087864a
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* AXI to M-Bridge decoding unit driver for Marvell Armada 8K and 8K+ SoCs */
+
+#ifndef _AMB_ADEC_H_
+#define _AMB_ADEC_H_
+
+#include <stdint.h>
+
+enum amb_attribute_ids {
+       AMB_SPI0_CS0_ID = 0x1E,
+       AMB_SPI0_CS1_ID = 0x5E,
+       AMB_SPI0_CS2_ID = 0x9E,
+       AMB_SPI0_CS3_ID = 0xDE,
+       AMB_SPI1_CS0_ID = 0x1A,
+       AMB_SPI1_CS1_ID = 0x5A,
+       AMB_SPI1_CS2_ID = 0x9A,
+       AMB_SPI1_CS3_ID = 0xDA,
+       AMB_DEV_CS0_ID = 0x3E,
+       AMB_DEV_CS1_ID = 0x3D,
+       AMB_DEV_CS2_ID = 0x3B,
+       AMB_DEV_CS3_ID = 0x37,
+       AMB_BOOT_CS_ID = 0x2f,
+       AMB_BOOT_ROM_ID = 0x1D,
+};
+
+#define AMB_MAX_WIN_ID         7
+
+int init_amb_adec(uintptr_t base);
+
+#endif /* _AMB_ADEC_H_ */
diff --git a/include/drivers/marvell/aro.h b/include/drivers/marvell/aro.h
new file mode 100644 (file)
index 0000000..3627a20
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+#ifndef _ARO_H_
+#define _ARO_H_
+
+enum hws_freq {
+       CPU_FREQ_2000,
+       CPU_FREQ_1800,
+       CPU_FREQ_1600,
+       CPU_FREQ_1400,
+       CPU_FREQ_1300,
+       CPU_FREQ_1200,
+       CPU_FREQ_1000,
+       CPU_FREQ_600,
+       CPU_FREQ_800,
+       DDR_FREQ_LAST,
+       DDR_FREQ_SAR
+};
+
+enum cpu_clock_freq_mode {
+       CPU_2000_DDR_1200_RCLK_1200 = 0x0,
+       CPU_2000_DDR_1050_RCLK_1050 = 0x1,
+       CPU_1600_DDR_800_RCLK_800   = 0x4,
+       CPU_1800_DDR_1200_RCLK_1200 = 0x6,
+       CPU_1800_DDR_1050_RCLK_1050 = 0x7,
+       CPU_1600_DDR_900_RCLK_900   = 0x0B,
+       CPU_1600_DDR_1050_RCLK_1050 = 0x0D,
+       CPU_1600_DDR_900_RCLK_900_2 = 0x0E,
+       CPU_1000_DDR_650_RCLK_650   = 0x13,
+       CPU_1300_DDR_800_RCLK_800   = 0x14,
+       CPU_1300_DDR_650_RCLK_650   = 0x17,
+       CPU_1200_DDR_800_RCLK_800   = 0x19,
+       CPU_1400_DDR_800_RCLK_800   = 0x1a,
+       CPU_600_DDR_800_RCLK_800    = 0x1B,
+       CPU_800_DDR_800_RCLK_800    = 0x1C,
+       CPU_1000_DDR_800_RCLK_800   = 0x1D,
+       CPU_DDR_RCLK_INVALID
+};
+
+int init_aro(void);
+
+#endif /* _ARO_H_ */
diff --git a/include/drivers/marvell/cache_llc.h b/include/drivers/marvell/cache_llc.h
new file mode 100644 (file)
index 0000000..9e41793
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* LLC driver is the Last Level Cache (L3C) driver
+ * for Marvell SoCs in AP806, AP807, and AP810
+ */
+
+#ifndef _CACHE_LLC_H_
+#define _CACHE_LLC_H_
+
+#define LLC_CTRL(ap)                   (MVEBU_LLC_BASE(ap) + 0x100)
+#define LLC_SYNC(ap)                   (MVEBU_LLC_BASE(ap) + 0x700)
+#define L2X0_INV_WAY(ap)               (MVEBU_LLC_BASE(ap) + 0x77C)
+#define L2X0_CLEAN_WAY(ap)             (MVEBU_LLC_BASE(ap) + 0x7BC)
+#define L2X0_CLEAN_INV_WAY(ap)         (MVEBU_LLC_BASE(ap) + 0x7FC)
+#define LLC_TC0_LOCK(ap)               (MVEBU_LLC_BASE(ap) + 0x920)
+
+#define MASTER_LLC_CTRL                        LLC_CTRL(MVEBU_AP0)
+#define MASTER_L2X0_INV_WAY            L2X0_INV_WAY(MVEBU_AP0)
+#define MASTER_LLC_TC0_LOCK            LLC_TC0_LOCK(MVEBU_AP0)
+
+#define LLC_CTRL_EN                    1
+#define LLC_EXCLUSIVE_EN               0x100
+#define LLC_WAY_MASK                   0xFFFFFFFF
+
+#ifndef __ASSEMBLY__
+void llc_cache_sync(int ap_index);
+void llc_flush_all(int ap_index);
+void llc_clean_all(int ap_index);
+void llc_inv_all(int ap_index);
+void llc_disable(int ap_index);
+void llc_enable(int ap_index, int excl_mode);
+int llc_is_exclusive(int ap_index);
+void llc_runtime_enable(int ap_index);
+#endif
+
+#endif /* _CACHE_LLC_H_ */
+
diff --git a/include/drivers/marvell/ccu.h b/include/drivers/marvell/ccu.h
new file mode 100644 (file)
index 0000000..ff30a76
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* CCU unit device driver for Marvell AP807, AP807 and AP810 SoCs */
+
+#ifndef _CCU_H_
+#define _CCU_H_
+
+#ifndef __ASSEMBLY__
+#include <addr_map.h>
+#endif
+
+/* CCU registers definitions */
+#define CCU_WIN_CR_OFFSET(ap, win)             (MVEBU_CCU_BASE(ap) + 0x0 + \
+                                               (0x10 * win))
+#define CCU_TARGET_ID_OFFSET                   (8)
+#define CCU_TARGET_ID_MASK                     (0x7F)
+
+#define CCU_WIN_SCR_OFFSET(ap, win)            (MVEBU_CCU_BASE(ap) + 0x4 + \
+                                               (0x10 * win))
+#define CCU_WIN_ENA_WRITE_SECURE               (0x1)
+#define CCU_WIN_ENA_READ_SECURE                        (0x2)
+
+#define CCU_WIN_ALR_OFFSET(ap, win)            (MVEBU_CCU_BASE(ap) + 0x8 + \
+                                               (0x10 * win))
+#define CCU_WIN_AHR_OFFSET(ap, win)            (MVEBU_CCU_BASE(ap) + 0xC + \
+                                               (0x10 * win))
+
+#define CCU_WIN_GCR_OFFSET(ap)                 (MVEBU_CCU_BASE(ap) + 0xD0)
+#define CCU_GCR_TARGET_OFFSET                  (8)
+#define CCU_GCR_TARGET_MASK                    (0xFF)
+
+#define CCU_SRAM_WIN_CR                                CCU_WIN_CR_OFFSET(MVEBU_AP0, 1)
+
+#ifndef __ASSEMBLY__
+int init_ccu(int);
+void ccu_win_check(struct addr_map_win *win);
+void ccu_enable_win(int ap_index, struct addr_map_win *win, uint32_t win_id);
+void ccu_temp_win_insert(int ap_index, struct addr_map_win *win, int size);
+void ccu_temp_win_remove(int ap_index, struct addr_map_win *win, int size);
+void ccu_dram_win_config(int ap_index, struct addr_map_win *win);
+void ccu_dram_target_set(int ap_index, uint32_t target);
+void ccu_save_win_all(int ap_id);
+void ccu_restore_win_all(int ap_id);
+#endif
+
+#endif /* _CCU_H_ */
diff --git a/include/drivers/marvell/gwin.h b/include/drivers/marvell/gwin.h
new file mode 100644 (file)
index 0000000..5dc9f24
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* GWIN unit device driver for Marvell AP810 SoC */
+
+#ifndef _GWIN_H_
+#define _GWIN_H_
+
+#include <addr_map.h>
+
+int init_gwin(int ap_index);
+void gwin_temp_win_insert(int ap_index, struct addr_map_win *win, int size);
+void gwin_temp_win_remove(int ap_index, struct addr_map_win *win, int size);
+
+#endif /* _GWIN_H_ */
diff --git a/include/drivers/marvell/i2c.h b/include/drivers/marvell/i2c.h
new file mode 100644 (file)
index 0000000..bd14385
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef _I2C_H_
+#define _I2C_H_
+
+
+void i2c_init(void);
+
+int i2c_read(uint8_t chip,
+            unsigned int addr, int alen, uint8_t *buffer, int len);
+
+int i2c_write(uint8_t chip,
+             unsigned int addr, int alen, uint8_t *buffer, int len);
+#endif
diff --git a/include/drivers/marvell/io_win.h b/include/drivers/marvell/io_win.h
new file mode 100644 (file)
index 0000000..4102a11
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* IO Window unit device driver for Marvell AP807, AP807 and AP810 SoCs */
+
+#ifndef _IO_WIN_H_
+#define _IO_WIN_H_
+
+#include <addr_map.h>
+
+int init_io_win(int ap_index);
+void iow_temp_win_insert(int ap_index, struct addr_map_win *win, int size);
+void iow_temp_win_remove(int ap_index, struct addr_map_win *win, int size);
+void iow_save_win_all(int ap_id);
+void iow_restore_win_all(int ap_id);
+
+#endif /* _IO_WIN_H_ */
diff --git a/include/drivers/marvell/iob.h b/include/drivers/marvell/iob.h
new file mode 100644 (file)
index 0000000..9848c0a
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* IOW unit device driver for Marvell CP110 and CP115 SoCs */
+
+#ifndef _IOB_H_
+#define _IOB_H_
+
+#include <addr_map.h>
+
+enum target_ids_iob {
+       INTERNAL_TID    = 0x0,
+       MCI0_TID        = 0x1,
+       PEX1_TID        = 0x2,
+       PEX2_TID        = 0x3,
+       PEX0_TID        = 0x4,
+       NAND_TID        = 0x5,
+       RUNIT_TID       = 0x6,
+       MCI1_TID        = 0x7,
+       IOB_MAX_TID
+};
+
+int init_iob(uintptr_t base);
+void iob_cfg_space_update(int ap_idx, int cp_idx,
+                         uintptr_t base, uintptr_t new_base);
+
+#endif /* _IOB_H_ */
diff --git a/include/drivers/marvell/mci.h b/include/drivers/marvell/mci.h
new file mode 100644 (file)
index 0000000..789b3b9
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* MCI bus driver for Marvell ARMADA 8K and 8K+ SoCs */
+
+#ifndef _MCI_H_
+#define _MCI_H_
+
+int mci_initialize(int mci_index);
+void mci_turn_link_down(void);
+void mci_turn_link_on(void);
+int mci_get_link_status(void);
+
+#endif /* _MCI_H_ */
diff --git a/include/drivers/marvell/mochi/ap_setup.h b/include/drivers/marvell/mochi/ap_setup.h
new file mode 100644 (file)
index 0000000..41f2bac
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* AP8xx Marvell SoC driver */
+
+#ifndef __AP_SETUP_H__
+#define __AP_SETUP_H__
+
+void ap_init(void);
+void ap_ble_init(void);
+int ap_get_count(void);
+
+#endif /* __AP_SETUP_H__ */
diff --git a/include/drivers/marvell/mochi/cp110_setup.h b/include/drivers/marvell/mochi/cp110_setup.h
new file mode 100644 (file)
index 0000000..1c88980
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* CP110 Marvell SoC driver */
+
+#ifndef __CP110_SETUP_H__
+#define __CP110_SETUP_H__
+
+#include <mmio.h>
+#include <mvebu_def.h>
+
+#define MVEBU_DEVICE_ID_REG            (MVEBU_CP_DFX_OFFSET + 0x40)
+#define MVEBU_DEVICE_ID_OFFSET         (0)
+#define MVEBU_DEVICE_ID_MASK           (0xffff << MVEBU_DEVICE_ID_OFFSET)
+#define MVEBU_DEVICE_REV_OFFSET                (16)
+#define MVEBU_DEVICE_REV_MASK          (0xf << MVEBU_DEVICE_REV_OFFSET)
+#define MVEBU_70X0_DEV_ID              (0x7040)
+#define MVEBU_70X0_CP115_DEV_ID                (0x7045)
+#define MVEBU_80X0_DEV_ID              (0x8040)
+#define MVEBU_80X0_CP115_DEV_ID                (0x8045)
+#define MVEBU_CP110_SA_DEV_ID          (0x110)
+#define MVEBU_CP110_REF_ID_A1          1
+#define MVEBU_CP110_REF_ID_A2          2
+#define MAX_STREAM_ID_PER_CP           (0x10)
+#define STREAM_ID_BASE                 (0x40)
+
+static inline uint32_t cp110_device_id_get(uintptr_t base)
+{
+       /* Returns:
+        * - MVEBU_70X0_DEV_ID for A70X0 family
+        * - MVEBU_80X0_DEV_ID for A80X0 family
+        * - MVEBU_CP110_SA_DEV_ID for CP that connected stand alone
+        */
+       return (mmio_read_32(base + MVEBU_DEVICE_ID_REG) >>
+               MVEBU_DEVICE_ID_OFFSET) &
+               MVEBU_DEVICE_ID_MASK;
+}
+
+static inline uint32_t cp110_rev_id_get(uintptr_t base)
+{
+       return (mmio_read_32(base + MVEBU_DEVICE_ID_REG) &
+               MVEBU_DEVICE_REV_MASK) >>
+               MVEBU_DEVICE_REV_OFFSET;
+}
+
+void cp110_init(uintptr_t cp110_base, uint32_t stream_id);
+void cp110_ble_init(uintptr_t cp110_base);
+
+#endif /* __CP110_SETUP_H__ */
diff --git a/include/drivers/marvell/thermal.h b/include/drivers/marvell/thermal.h
new file mode 100644 (file)
index 0000000..191f97b
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:    BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* Driver for thermal unit located in Marvell ARMADA 8K and compatible SoCs */
+
+#ifndef _THERMAL_H
+#define _THERMAL_H
+
+struct tsen_config {
+       /* thermal temperature parameters */
+       int tsen_offset;
+       int tsen_gain;
+       int tsen_divisor;
+       /* thermal data */
+       int tsen_ready;
+       void *regs_base;
+       /* thermal functionality */
+       int (*ptr_tsen_probe)(struct tsen_config *cfg);
+       int (*ptr_tsen_read)(struct tsen_config *cfg, int *temp);
+};
+
+/* Thermal driver APIs */
+int marvell_thermal_init(struct tsen_config *tsen_cfg);
+int marvell_thermal_read(struct tsen_config *tsen_cfg, int *temp);
+struct tsen_config *marvell_thermal_config_get(void);
+
+#endif /* _THERMAL_H */
index 9f1847061ded40eefdd9610cfbca90227c9d26ab..f5ca2ee7a41b44ad6ecd1c203fdeaca7b3d5f03a 100644 (file)
 #define CORTEX_A72_CPUACTLR_EL1_DCC_AS_DCCI                    (ULL(1) << 44)
 #define CORTEX_A72_CPUACTLR_EL1_DIS_INSTR_PREFETCH             (ULL(1) << 32)
 
+/*******************************************************************************
+ *  L2 Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A72_L2ACTLR_EL1                                 S3_1_C15_C0_0
+
+#define CORTEX_A72_L2ACTLR_ENABLE_UNIQUE_CLEAN                 (ULL(1) << 14)
+
 /*******************************************************************************
  * L2 Control register specific definitions.
  ******************************************************************************/
diff --git a/include/plat/marvell/a8k/common/a8k_common.h b/include/plat/marvell/a8k/common/a8k_common.h
new file mode 100644 (file)
index 0000000..e727467
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef __A8K_COMMON_H__
+#define __A8K_COMMON_H__
+
+#include <amb_adec.h>
+#include <io_win.h>
+#include <iob.h>
+#include <ccu.h>
+
+/*
+ * This struct supports skip image request
+ * detection_method: the method used to detect the request "signal".
+ * info:
+ *     GPIO:
+ *             detection_method: HIGH (pressed button), LOW (unpressed button),
+ *             num (button mpp number).
+ *     i2c:
+ *             i2c_addr: the address of the i2c chosen.
+ *             i2d_reg: the i2c register chosen.
+ *     test:
+ *             choose the DIE you picked the button in (AP or CP).
+ *             in case of CP(cp_index = 0 if CP0, cp_index = 1 if CP1)
+ */
+struct skip_image {
+       enum {
+               GPIO,
+               I2C,
+               USER_DEFINED
+       } detection_method;
+
+       struct {
+               struct {
+                       int num;
+                       enum {
+                               HIGH,
+                               LOW
+                       } button_state;
+
+               } gpio;
+
+               struct {
+                       int i2c_addr;
+                       int i2c_reg;
+               } i2c;
+
+               struct {
+                       enum {
+                               CP,
+                               AP
+                       } cp_ap;
+                       int cp_index;
+               } test;
+       } info;
+};
+
+/*
+ * This struct supports SoC power off method
+ * type: the method used to power off the SoC
+ * cfg:
+ *     PMIC_GPIO:
+ *     pin_count: current GPIO pin number used for toggling the signal for
+ *                notifying external PMIC
+ *     info:      holds the GPIOs information, CP GPIO should be used and
+ *                all GPIOs should be within same GPIO config. register
+ *     step_count: current step number to toggle the GPIO for PMIC
+ *     seq:       GPIO toggling values in sequence, each bit represents a GPIO.
+ *                For example, bit0 represents first GPIO used for toggling
+ *                the GPIO the last step is used to trigger the power off
+ *                signal
+ *     delay_ms:  transition interval for the GPIO setting to take effect
+ *                in unit of ms
+ */
+/* Max GPIO number used to notify PMIC to power off the SoC */
+#define PMIC_GPIO_MAX_NUMBER           8
+/* Max GPIO toggling steps in sequence to power off the SoC */
+#define PMIC_GPIO_MAX_TOGGLE_STEP      8
+
+enum gpio_output_state {
+       GPIO_LOW = 0,
+       GPIO_HIGH
+};
+
+typedef struct gpio_info {
+       int cp_index;
+       int gpio_index;
+} gpio_info_t;
+
+struct power_off_method {
+       enum {
+               PMIC_GPIO,
+       } type;
+
+       struct {
+               struct {
+                       int pin_count;
+                       struct gpio_info info[PMIC_GPIO_MAX_NUMBER];
+                       int step_count;
+                       uint32_t seq[PMIC_GPIO_MAX_TOGGLE_STEP];
+                       int delay_ms;
+               } gpio;
+       } cfg;
+};
+
+int marvell_gpio_config(void);
+uint32_t marvell_get_io_win_gcr_target(int ap_idx);
+uint32_t marvell_get_ccu_gcr_target(int ap_idx);
+
+
+/*
+ * The functions below are defined as Weak and may be overridden
+ * in specific Marvell standard platform
+ */
+int marvell_get_amb_memory_map(struct addr_map_win **win,
+                              uint32_t *size, uintptr_t base);
+int marvell_get_io_win_memory_map(int ap_idx, struct addr_map_win **win,
+                                 uint32_t *size);
+int marvell_get_iob_memory_map(struct addr_map_win **win,
+                              uint32_t *size, uintptr_t base);
+int marvell_get_ccu_memory_map(int ap_idx, struct addr_map_win **win,
+                              uint32_t *size);
+
+#endif /* __A8K_COMMON_H__ */
diff --git a/include/plat/marvell/a8k/common/board_marvell_def.h b/include/plat/marvell/a8k/common/board_marvell_def.h
new file mode 100644 (file)
index 0000000..b1054db
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef __BOARD_MARVELL_DEF_H__
+#define __BOARD_MARVELL_DEF_H__
+
+/*
+ * Required platform porting definitions common to all ARM
+ * development platforms
+ */
+
+/* Size of cacheable stacks */
+#if DEBUG_XLAT_TABLE
+# define PLATFORM_STACK_SIZE 0x800
+#elif IMAGE_BL1
+#if TRUSTED_BOARD_BOOT
+# define PLATFORM_STACK_SIZE 0x1000
+#else
+# define PLATFORM_STACK_SIZE 0x440
+#endif
+#elif IMAGE_BL2
+# if TRUSTED_BOARD_BOOT
+#  define PLATFORM_STACK_SIZE 0x1000
+# else
+#  define PLATFORM_STACK_SIZE 0x400
+# endif
+#elif IMAGE_BL31
+# define PLATFORM_STACK_SIZE 0x400
+#elif IMAGE_BL32
+# define PLATFORM_STACK_SIZE 0x440
+#endif
+
+/*
+ * PLAT_MARVELL_MMAP_ENTRIES depends on the number of entries in the
+ * plat_arm_mmap array defined for each BL stage.
+ */
+#if IMAGE_BLE
+#  define PLAT_MARVELL_MMAP_ENTRIES    3
+#endif
+#if IMAGE_BL1
+#  if TRUSTED_BOARD_BOOT
+#   define PLAT_MARVELL_MMAP_ENTRIES   7
+#  else
+#   define PLAT_MARVELL_MMAP_ENTRIES   6
+#  endif       /* TRUSTED_BOARD_BOOT */
+#endif
+#if IMAGE_BL2
+#  define PLAT_MARVELL_MMAP_ENTRIES            8
+#endif
+#if IMAGE_BL31
+#define PLAT_MARVELL_MMAP_ENTRIES              5
+#endif
+
+/*
+ * Platform specific page table and MMU setup constants
+ */
+#if IMAGE_BL1
+#define MAX_XLAT_TABLES                        4
+#elif IMAGE_BLE
+#  define MAX_XLAT_TABLES              4
+#elif IMAGE_BL2
+#  define MAX_XLAT_TABLES              4
+#elif IMAGE_BL31
+# define MAX_XLAT_TABLES               4
+#elif IMAGE_BL32
+#  define MAX_XLAT_TABLES               4
+#endif
+
+#define MAX_IO_DEVICES                 3
+#define MAX_IO_HANDLES                 4
+
+#define PLAT_MARVELL_TRUSTED_SRAM_SIZE 0x80000 /* 512 KB */
+
+
+#endif /* __BOARD_MARVELL_DEF_H__ */
diff --git a/include/plat/marvell/a8k/common/marvell_def.h b/include/plat/marvell/a8k/common/marvell_def.h
new file mode 100644 (file)
index 0000000..7dacf82
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef __MARVELL_DEF_H__
+#define __MARVELL_DEF_H__
+
+#include <arch.h>
+#include <common_def.h>
+#include <platform_def.h>
+#include <tbbr_img_def.h>
+#include <xlat_tables.h>
+
+
+/******************************************************************************
+ * Definitions common to all MARVELL standard platforms
+ *****************************************************************************/
+
+/* Special value used to verify platform parameters from BL2 to BL31 */
+#define MARVELL_BL31_PLAT_PARAM_VAL            0x0f1e2d3c4b5a6978ULL
+
+
+#define MARVELL_CACHE_WRITEBACK_SHIFT  6
+
+/*
+ * Macros mapping the MPIDR Affinity levels to MARVELL Platform Power levels.
+ * The power levels have a 1:1 mapping with the MPIDR affinity levels.
+ */
+#define MARVELL_PWR_LVL0               MPIDR_AFFLVL0
+#define MARVELL_PWR_LVL1               MPIDR_AFFLVL1
+#define MARVELL_PWR_LVL2               MPIDR_AFFLVL2
+
+/*
+ *  Macros for local power states in Marvell platforms encoded by
+ *  State-ID field within the power-state parameter.
+ */
+/* Local power state for power domains in Run state. */
+#define MARVELL_LOCAL_STATE_RUN        0
+/* Local power state for retention. Valid only for CPU power domains */
+#define MARVELL_LOCAL_STATE_RET        1
+/*
+ * Local power state for OFF/power-down. Valid for CPU
+ * and cluster power domains
+ */
+#define MARVELL_LOCAL_STATE_OFF        2
+
+/* The first 4KB of Trusted SRAM are used as shared memory */
+#define MARVELL_TRUSTED_SRAM_BASE      PLAT_MARVELL_ATF_BASE
+#define MARVELL_SHARED_RAM_BASE                MARVELL_TRUSTED_SRAM_BASE
+#define MARVELL_SHARED_RAM_SIZE                0x00001000      /* 4 KB */
+
+/* The remaining Trusted SRAM is used to load the BL images */
+#define MARVELL_BL_RAM_BASE            (MARVELL_SHARED_RAM_BASE +      \
+                                        MARVELL_SHARED_RAM_SIZE)
+#define MARVELL_BL_RAM_SIZE            (PLAT_MARVELL_TRUSTED_SRAM_SIZE - \
+                                        MARVELL_SHARED_RAM_SIZE)
+/* Non-shared DRAM */
+#define MARVELL_DRAM_BASE              ULL(0x0)
+#define MARVELL_DRAM_SIZE              ULL(0x80000000)
+#define MARVELL_DRAM_END               (MARVELL_DRAM_BASE + \
+                                        MARVELL_DRAM_SIZE - 1)
+
+#define MARVELL_IRQ_SEC_PHY_TIMER      29
+
+#define MARVELL_IRQ_SEC_SGI_0          8
+#define MARVELL_IRQ_SEC_SGI_1          9
+#define MARVELL_IRQ_SEC_SGI_2          10
+#define MARVELL_IRQ_SEC_SGI_3          11
+#define MARVELL_IRQ_SEC_SGI_4          12
+#define MARVELL_IRQ_SEC_SGI_5          13
+#define MARVELL_IRQ_SEC_SGI_6          14
+#define MARVELL_IRQ_SEC_SGI_7          15
+
+#define MARVELL_MAP_SHARED_RAM         MAP_REGION_FLAT(                \
+                                               MARVELL_SHARED_RAM_BASE,\
+                                               MARVELL_SHARED_RAM_SIZE,\
+                                               MT_MEMORY | MT_RW | MT_SECURE)
+
+#define MARVELL_MAP_DRAM               MAP_REGION_FLAT(                \
+                                               MARVELL_DRAM_BASE,      \
+                                               MARVELL_DRAM_SIZE,      \
+                                               MT_MEMORY | MT_RW | MT_NS)
+
+
+/*
+ * The number of regions like RO(code), coherent and data required by
+ * different BL stages which need to be mapped in the MMU.
+ */
+#if USE_COHERENT_MEM
+#define MARVELL_BL_REGIONS             3
+#else
+#define MARVELL_BL_REGIONS             2
+#endif
+
+#define MAX_MMAP_REGIONS               (PLAT_MARVELL_MMAP_ENTRIES +    \
+                                        MARVELL_BL_REGIONS)
+
+#define MARVELL_CONSOLE_BAUDRATE       115200
+
+/******************************************************************************
+ * Required platform porting definitions common to all MARVELL std. platforms
+ *****************************************************************************/
+
+#define PLAT_PHY_ADDR_SPACE_SIZE       (1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE      (1ULL << 32)
+
+/*
+ * This macro defines the deepest retention state possible. A higher state
+ * id will represent an invalid or a power down state.
+ */
+#define PLAT_MAX_RET_STATE             MARVELL_LOCAL_STATE_RET
+
+/*
+ * This macro defines the deepest power down states possible. Any state ID
+ * higher than this is invalid.
+ */
+#define PLAT_MAX_OFF_STATE             MARVELL_LOCAL_STATE_OFF
+
+
+#define PLATFORM_CORE_COUNT            PLAT_MARVELL_CORE_COUNT
+#define PLAT_NUM_PWR_DOMAINS           (PLAT_MARVELL_CLUSTER_COUNT +   \
+                                        PLATFORM_CORE_COUNT)
+
+/*
+ * Some data must be aligned on the biggest cache line size in the platform.
+ * This is known only to the platform as it might have a combination of
+ * integrated and external caches.
+ */
+#define CACHE_WRITEBACK_GRANULE                (1 << MARVELL_CACHE_WRITEBACK_SHIFT)
+
+
+/*******************************************************************************
+ * BL1 specific defines.
+ * BL1 RW data is relocated from ROM to RAM at runtime so we need 2 sets of
+ * addresses.
+ ******************************************************************************/
+#define BL1_RO_BASE                    PLAT_MARVELL_TRUSTED_ROM_BASE
+#define BL1_RO_LIMIT                   (PLAT_MARVELL_TRUSTED_ROM_BASE  \
+                                        + PLAT_MARVELL_TRUSTED_ROM_SIZE)
+/*
+ * Put BL1 RW at the top of the Trusted SRAM.
+ */
+#define BL1_RW_BASE            (MARVELL_BL_RAM_BASE +          \
+                                       MARVELL_BL_RAM_SIZE -   \
+                                       PLAT_MARVELL_MAX_BL1_RW_SIZE)
+#define BL1_RW_LIMIT           (MARVELL_BL_RAM_BASE + MARVELL_BL_RAM_SIZE)
+
+/*******************************************************************************
+ * BLE specific defines.
+ ******************************************************************************/
+#define BLE_BASE                       PLAT_MARVELL_SRAM_BASE
+#define BLE_LIMIT                      PLAT_MARVELL_SRAM_END
+
+/*******************************************************************************
+ * BL2 specific defines.
+ ******************************************************************************/
+/*
+ * Put BL2 just below BL31.
+ */
+#define BL2_BASE                       (BL31_BASE - PLAT_MARVELL_MAX_BL2_SIZE)
+#define BL2_LIMIT                      BL31_BASE
+
+/*******************************************************************************
+ * BL31 specific defines.
+ ******************************************************************************/
+/*
+ * Put BL31 at the top of the Trusted SRAM.
+ */
+#define BL31_BASE                      (MARVELL_BL_RAM_BASE +          \
+                                               MARVELL_BL_RAM_SIZE -   \
+                                               PLAT_MARVEL_MAX_BL31_SIZE)
+#define BL31_PROGBITS_LIMIT            BL1_RW_BASE
+#define BL31_LIMIT                     (MARVELL_BL_RAM_BASE +  \
+                                        MARVELL_BL_RAM_SIZE)
+
+
+#endif /* __MARVELL_DEF_H__ */
diff --git a/include/plat/marvell/a8k/common/plat_marvell.h b/include/plat/marvell/a8k/common/plat_marvell.h
new file mode 100644 (file)
index 0000000..aad5da7
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef __PLAT_MARVELL_H__
+#define __PLAT_MARVELL_H__
+
+#include <cassert.h>
+#include <cpu_data.h>
+#include <stdint.h>
+#include <utils.h>
+#include <xlat_tables.h>
+
+/*
+ * Extern declarations common to Marvell standard platforms
+ */
+extern const mmap_region_t plat_marvell_mmap[];
+
+#define MARVELL_CASSERT_MMAP                                           \
+       CASSERT((ARRAY_SIZE(plat_marvell_mmap) + MARVELL_BL_REGIONS)    \
+               <= MAX_MMAP_REGIONS,                                    \
+               assert_max_mmap_regions)
+
+/*
+ * Utility functions common to Marvell standard platforms
+ */
+void marvell_setup_page_tables(uintptr_t total_base,
+                              size_t total_size,
+                              uintptr_t code_start,
+                              uintptr_t code_limit,
+                              uintptr_t rodata_start,
+                              uintptr_t rodata_limit
+#if USE_COHERENT_MEM
+                            , uintptr_t coh_start,
+                              uintptr_t coh_limit
+#endif
+);
+
+/* IO storage utility functions */
+void marvell_io_setup(void);
+
+/* Systimer utility function */
+void marvell_configure_sys_timer(void);
+
+/* Topology utility function */
+int marvell_check_mpidr(u_register_t mpidr);
+
+/* BLE utility functions */
+int ble_plat_setup(int *skip);
+void plat_marvell_dram_update_topology(void);
+void ble_plat_pcie_ep_setup(void);
+struct pci_hw_cfg *plat_get_pcie_hw_data(void);
+
+/* BL1 utility functions */
+void marvell_bl1_early_platform_setup(void);
+void marvell_bl1_platform_setup(void);
+void marvell_bl1_plat_arch_setup(void);
+
+/* BL2 utility functions */
+void marvell_bl2_early_platform_setup(meminfo_t *mem_layout);
+void marvell_bl2_platform_setup(void);
+void marvell_bl2_plat_arch_setup(void);
+uint32_t marvell_get_spsr_for_bl32_entry(void);
+uint32_t marvell_get_spsr_for_bl33_entry(void);
+
+/* BL31 utility functions */
+void marvell_bl31_early_platform_setup(bl31_params_t *from_bl2,
+                               void *plat_params_from_bl2);
+void marvell_bl31_platform_setup(void);
+void marvell_bl31_plat_runtime_setup(void);
+void marvell_bl31_plat_arch_setup(void);
+
+/* Power management config to power off the SoC */
+void *plat_marvell_get_pm_cfg(void);
+
+/* Check if MSS AP CM3 firmware contains PM support */
+_Bool is_pm_fw_running(void);
+
+/* Bootrom image recovery utility functions */
+void *plat_marvell_get_skip_image_data(void);
+
+/* FIP TOC validity check */
+int marvell_io_is_toc_valid(void);
+
+/*
+ * PSCI functionality
+ */
+void marvell_psci_arch_init(int ap_idx);
+void plat_marvell_system_reset(void);
+
+/*
+ * Optional functions required in Marvell standard platforms
+ */
+void plat_marvell_io_setup(void);
+int plat_marvell_get_alt_image_source(
+       unsigned int image_id,
+       uintptr_t *dev_handle,
+       uintptr_t *image_spec);
+unsigned int plat_marvell_calc_core_pos(u_register_t mpidr);
+
+const mmap_region_t *plat_marvell_get_mmap(void);
+void marvell_ble_prepare_exit(void);
+void marvell_exit_bootrom(uintptr_t base);
+
+int plat_marvell_early_cpu_powerdown(void);
+#endif /* __PLAT_MARVELL_H__ */
diff --git a/include/plat/marvell/a8k/common/plat_pm_trace.h b/include/plat/marvell/a8k/common/plat_pm_trace.h
new file mode 100644 (file)
index 0000000..0878959
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef __PLAT_PM_TRACE_H
+#define __PLAT_PM_TRACE_H
+
+
+/*
+ * PM Trace is for Debug purpose only!!!
+ * It should not be enabled during System Run time
+ */
+#undef PM_TRACE_ENABLE
+
+
+/* trace entry time */
+struct pm_trace_entry {
+       /* trace entry time stamp */
+       unsigned int timestamp;
+
+       /* trace info
+        * [16-31] - API Trace Id
+        * [00-15] - API Step Id
+        */
+       unsigned int trace_info;
+};
+
+struct pm_trace_ctrl {
+       /* trace pointer - points to next free entry in trace cyclic queue */
+       unsigned int trace_pointer;
+
+       /* trace count - number of entries in the queue, clear upon read */
+       unsigned int trace_count;
+};
+
+/* trace size definition */
+#define AP_MSS_ATF_CORE_INFO_SIZE      (256)
+#define AP_MSS_ATF_CORE_ENTRY_SIZE     (8)
+#define AP_MSS_ATF_TRACE_SIZE_MASK     (0xFF)
+
+/* trace address definition */
+#define AP_MSS_TIMER_BASE              (MVEBU_REGS_BASE_MASK + 0x580110)
+
+#define AP_MSS_ATF_CORE_0_CTRL_BASE    (MVEBU_REGS_BASE_MASK + 0x520140)
+#define AP_MSS_ATF_CORE_1_CTRL_BASE    (MVEBU_REGS_BASE_MASK + 0x520150)
+#define AP_MSS_ATF_CORE_2_CTRL_BASE    (MVEBU_REGS_BASE_MASK + 0x520160)
+#define AP_MSS_ATF_CORE_3_CTRL_BASE    (MVEBU_REGS_BASE_MASK + 0x520170)
+#define AP_MSS_ATF_CORE_CTRL_BASE      (AP_MSS_ATF_CORE_0_CTRL_BASE)
+
+#define AP_MSS_ATF_CORE_0_INFO_BASE    (MVEBU_REGS_BASE_MASK + 0x5201C0)
+#define AP_MSS_ATF_CORE_0_INFO_TRACE   (MVEBU_REGS_BASE_MASK + 0x5201C4)
+#define AP_MSS_ATF_CORE_1_INFO_BASE    (MVEBU_REGS_BASE_MASK + 0x5209C0)
+#define AP_MSS_ATF_CORE_1_INFO_TRACE   (MVEBU_REGS_BASE_MASK + 0x5209C4)
+#define AP_MSS_ATF_CORE_2_INFO_BASE    (MVEBU_REGS_BASE_MASK + 0x5211C0)
+#define AP_MSS_ATF_CORE_2_INFO_TRACE   (MVEBU_REGS_BASE_MASK + 0x5211C4)
+#define AP_MSS_ATF_CORE_3_INFO_BASE    (MVEBU_REGS_BASE_MASK + 0x5219C0)
+#define AP_MSS_ATF_CORE_3_INFO_TRACE   (MVEBU_REGS_BASE_MASK + 0x5219C4)
+#define AP_MSS_ATF_CORE_INFO_BASE      (AP_MSS_ATF_CORE_0_INFO_BASE)
+
+/* trace info definition */
+#define TRACE_PWR_DOMAIN_OFF           (0x10000)
+#define TRACE_PWR_DOMAIN_SUSPEND       (0x20000)
+#define TRACE_PWR_DOMAIN_SUSPEND_FINISH        (0x30000)
+#define TRACE_PWR_DOMAIN_ON            (0x40000)
+#define TRACE_PWR_DOMAIN_ON_FINISH     (0x50000)
+
+#define TRACE_PWR_DOMAIN_ON_MASK       (0xFF)
+
+#ifdef PM_TRACE_ENABLE
+
+/* trace API definition */
+void pm_core_0_trace(unsigned int trace);
+void pm_core_1_trace(unsigned int trace);
+void pm_core_2_trace(unsigned int trace);
+void pm_core_3_trace(unsigned int trace);
+
+typedef void (*core_trace_func)(unsigned int);
+
+extern core_trace_func funcTbl[PLATFORM_CORE_COUNT];
+
+#define PM_TRACE(trace) funcTbl[plat_my_core_pos()](trace)
+
+#else
+
+#define PM_TRACE(trace)
+
+#endif
+
+/*******************************************************************************
+ * pm_trace_add
+ *
+ * DESCRIPTION: Add PM trace
+ ******************************************************************************
+ */
+void pm_trace_add(unsigned int trace, unsigned int core);
+
+#endif /* __PLAT_PM_TRACE_H */
diff --git a/include/plat/marvell/common/aarch64/cci_macros.S b/include/plat/marvell/common/aarch64/cci_macros.S
new file mode 100644 (file)
index 0000000..d6080cf
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef __CCI_MACROS_S__
+#define __CCI_MACROS_S__
+
+#include <cci.h>
+#include <platform_def.h>
+
+.section .rodata.cci_reg_name, "aS"
+cci_iface_regs:
+       .asciz "cci_snoop_ctrl_cluster0", "cci_snoop_ctrl_cluster1" , ""
+
+       /* ------------------------------------------------
+        * The below required platform porting macro prints
+        * out relevant interconnect registers whenever an
+        * unhandled exception is taken in BL31.
+        * Clobbers: x0 - x9, sp
+        * ------------------------------------------------
+        */
+       .macro print_cci_regs
+       adr     x6, cci_iface_regs
+       /* Store in x7 the base address of the first interface */
+       mov_imm x7, (PLAT_MARVELL_CCI_BASE + SLAVE_IFACE_OFFSET(        \
+                       PLAT_MARVELL_CCI_CLUSTER0_SL_IFACE_IX))
+       ldr     w8, [x7, #SNOOP_CTRL_REG]
+       /* Store in x7 the base address of the second interface */
+       mov_imm x7, (PLAT_MARVELL_CCI_BASE + SLAVE_IFACE_OFFSET(        \
+                       PLAT_MARVELL_CCI_CLUSTER1_SL_IFACE_IX))
+       ldr     w9, [x7, #SNOOP_CTRL_REG]
+       /* Store to the crash buf and print to console */
+       bl      str_in_crash_buf_print
+       .endm
+
+#endif /* __CCI_MACROS_S__ */
diff --git a/include/plat/marvell/common/aarch64/marvell_macros.S b/include/plat/marvell/common/aarch64/marvell_macros.S
new file mode 100644 (file)
index 0000000..0102af0
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef __MARVELL_MACROS_S__
+#define __MARVELL_MACROS_S__
+
+#include <cci.h>
+#include <gic_common.h>
+#include <gicv2.h>
+#include <gicv3.h>
+#include <platform_def.h>
+
+/*
+ *     These Macros are required by ATF
+ */
+
+.section .rodata.gic_reg_name, "aS"
+/* Applicable only to GICv2 and GICv3 with SRE disabled (legacy mode) */
+gicc_regs:
+       .asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", ""
+
+#ifdef USE_CCI
+/* Applicable only to GICv3 with SRE enabled */
+icc_regs:
+       .asciz "icc_hppir0_el1", "icc_hppir1_el1", "icc_ctlr_el3", ""
+#endif
+/* Registers common to both GICv2 and GICv3 */
+gicd_pend_reg:
+       .asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n"    \
+               " Offset:\t\t\tvalue\n"
+newline:
+       .asciz "\n"
+spacer:
+       .asciz ":\t\t0x"
+
+       /* ---------------------------------------------
+        * The below utility macro prints out relevant GIC
+        * registers whenever an unhandled exception is
+        * taken in BL31 on ARM standard platforms.
+        * Expects: GICD base in x16, GICC base in x17
+        * Clobbers: x0 - x10, sp
+        * ---------------------------------------------
+        */
+       .macro arm_print_gic_regs
+       /* Check for GICv3 system register access */
+       mrs     x7, id_aa64pfr0_el1
+       ubfx    x7, x7, #ID_AA64PFR0_GIC_SHIFT, #ID_AA64PFR0_GIC_WIDTH
+       cmp     x7, #1
+       b.ne    print_gicv2
+
+       /* Check for SRE enable */
+       mrs     x8, ICC_SRE_EL3
+       tst     x8, #ICC_SRE_SRE_BIT
+       b.eq    print_gicv2
+
+#ifdef USE_CCI
+       /* Load the icc reg list to x6 */
+       adr     x6, icc_regs
+       /* Load the icc regs to gp regs used by str_in_crash_buf_print */
+       mrs     x8, ICC_HPPIR0_EL1
+       mrs     x9, ICC_HPPIR1_EL1
+       mrs     x10, ICC_CTLR_EL3
+       /* Store to the crash buf and print to console */
+       bl      str_in_crash_buf_print
+#endif
+       b       print_gic_common
+
+print_gicv2:
+       /* Load the gicc reg list to x6 */
+       adr     x6, gicc_regs
+       /* Load the gicc regs to gp regs used by str_in_crash_buf_print */
+       ldr     w8, [x17, #GICC_HPPIR]
+       ldr     w9, [x17, #GICC_AHPPIR]
+       ldr     w10, [x17, #GICC_CTLR]
+       /* Store to the crash buf and print to console */
+       bl      str_in_crash_buf_print
+
+print_gic_common:
+       /* Print the GICD_ISPENDR regs */
+       add     x7, x16, #GICD_ISPENDR
+       adr     x4, gicd_pend_reg
+       bl      asm_print_str
+gicd_ispendr_loop:
+       sub     x4, x7, x16
+       cmp     x4, #0x280
+       b.eq    exit_print_gic_regs
+       bl      asm_print_hex
+
+       adr     x4, spacer
+       bl      asm_print_str
+
+       ldr     x4, [x7], #8
+       bl      asm_print_hex
+
+       adr     x4, newline
+       bl      asm_print_str
+       b       gicd_ispendr_loop
+exit_print_gic_regs:
+       .endm
+
+
+.section .rodata.cci_reg_name, "aS"
+cci_iface_regs:
+       .asciz "cci_snoop_ctrl_cluster0", "cci_snoop_ctrl_cluster1" , ""
+
+       /* ------------------------------------------------
+        * The below required platform porting macro prints
+        * out relevant interconnect registers whenever an
+        * unhandled exception is taken in BL31.
+        * Clobbers: x0 - x9, sp
+        * ------------------------------------------------
+        */
+       .macro print_cci_regs
+#ifdef USE_CCI
+       adr     x6, cci_iface_regs
+       /* Store in x7 the base address of the first interface */
+       mov_imm x7, (PLAT_MARVELL_CCI_BASE + SLAVE_IFACE_OFFSET(        \
+                       PLAT_MARVELL_CCI_CLUSTER0_SL_IFACE_IX))
+       ldr     w8, [x7, #SNOOP_CTRL_REG]
+       /* Store in x7 the base address of the second interface */
+       mov_imm x7, (PLAT_MARVELL_CCI_BASE + SLAVE_IFACE_OFFSET(        \
+                       PLAT_MARVELL_CCI_CLUSTER1_SL_IFACE_IX))
+       ldr     w9, [x7, #SNOOP_CTRL_REG]
+       /* Store to the crash buf and print to console */
+       bl      str_in_crash_buf_print
+#endif
+       .endm
+
+
+#endif /* __MARVELL_MACROS_S__ */
diff --git a/include/plat/marvell/common/marvell_plat_priv.h b/include/plat/marvell/common/marvell_plat_priv.h
new file mode 100644 (file)
index 0000000..c1dad0e
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef __MARVELL_PLAT_PRIV_H__
+#define __MARVELL_PLAT_PRIV_H__
+
+#include <utils.h>
+
+/*****************************************************************************
+ * Function and variable prototypes
+ *****************************************************************************
+ */
+void plat_delay_timer_init(void);
+
+uint64_t mvebu_get_dram_size(uint64_t ap_base_addr);
+
+/*
+ * GIC operation, mandatory functions required in Marvell standard platforms
+ */
+void plat_marvell_gic_driver_init(void);
+void plat_marvell_gic_init(void);
+void plat_marvell_gic_cpuif_enable(void);
+void plat_marvell_gic_cpuif_disable(void);
+void plat_marvell_gic_pcpu_init(void);
+void plat_marvell_gic_irq_save(void);
+void plat_marvell_gic_irq_restore(void);
+void plat_marvell_gic_irq_pcpu_save(void);
+void plat_marvell_gic_irq_pcpu_restore(void);
+
+#endif /* __MARVELL_PLAT_PRIV_H__ */
diff --git a/include/plat/marvell/common/marvell_pm.h b/include/plat/marvell/common/marvell_pm.h
new file mode 100644 (file)
index 0000000..2817a46
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef _MARVELL_PM_H_
+#define _MARVELL_PM_H_
+
+#define MVEBU_MAILBOX_MAGIC_NUM                PLAT_MARVELL_MAILBOX_MAGIC_NUM
+#define MVEBU_MAILBOX_SUSPEND_STATE    0xb007de7c
+
+/* Mailbox entry indexes */
+/* Magic number for validity check */
+#define        MBOX_IDX_MAGIC                  0
+/* Recovery from suspend entry point */
+#define        MBOX_IDX_SEC_ADDR               1
+/* Suspend state magic number */
+#define        MBOX_IDX_SUSPEND_MAGIC          2
+/* Recovery jump address for ROM bypass */
+#define        MBOX_IDX_ROM_EXIT_ADDR          3
+/* BLE execution start counter value */
+#define        MBOX_IDX_START_CNT              4
+
+#endif /* _MARVELL_PM_H_ */
diff --git a/include/plat/marvell/common/mvebu.h b/include/plat/marvell/common/mvebu.h
new file mode 100644 (file)
index 0000000..a20e538
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C)  2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef _MVEBU_H_
+#define _MVEBU_H_
+
+/* Use this functions only when printf is allowed */
+#define debug_enter()  VERBOSE("----> Enter %s\n", __func__)
+#define debug_exit()   VERBOSE("<---- Exit  %s\n", __func__)
+
+/* Macro for testing alignment. Positive if number is NOT aligned */
+#define IS_NOT_ALIGN(number, align)    ((number) & ((align) - 1))
+
+/* Macro for alignment up. For example, ALIGN_UP(0x0330, 0x20) = 0x0340 */
+#define ALIGN_UP(number, align) (((number) & ((align) - 1)) ? \
+               (((number) + (align)) & ~((align)-1)) : (number))
+
+/* Macro for testing whether a number is a power of 2. Positive if so */
+#define IS_POWER_OF_2(number)  ((number) != 0 && \
+                               (((number) & ((number) - 1)) == 0))
+
+/*
+ * Macro for ronding up to next power of 2
+ * it is done by count leading 0 (clz assembly opcode) and see msb set bit.
+ * then you can shift it left and get number which power of 2
+ * Note: this Macro is for 32 bit number
+ */
+#define ROUND_UP_TO_POW_OF_2(number)   (1 << \
+                                       (32 - __builtin_clz((number) - 1)))
+
+#define _1MB_                          (1024ULL*1024ULL)
+#define _1GB_                          (_1MB_*1024ULL)
+
+#endif /* MVEBU_H */
index 638f66a7ce9d95ccfd3cbb23dcbddbb3a4f7aae9..76fede821dd82efce3cb41a4d23f0e47551b560a 100644 (file)
@@ -66,6 +66,14 @@ MediaTek platform ports
 :G: `mtk09422`_
 :F: plat/mediatek/
 
+Marvell platform ports and SoC drivers
+--------------------------------------
+:M: Konstantin Porotchkin <kostap@marvell.com>
+:G: `kostapr`_
+:F: docs/plat/marvell/
+:F: plat/marvell/
+:F: drivers/marvell/
+
 NVidia platform ports
 ---------------------
 :M: Varun Wadekar <vwadekar@nvidia.com>
@@ -165,6 +173,7 @@ Xilinx platform port
 .. _glneo: https://github.com/glneo
 .. _hzhuang1: https://github.com/hzhuang1
 .. _jenswi-linaro: https://github.com/jenswi-linaro
+.. _kostapr: https://github.com/kostapr
 .. _masahir0y: https://github.com/masahir0y
 .. _mtk09422: https://github.com/mtk09422
 .. _qoriq-open-source: https://github.com/qoriq-open-source
index 2a6ded497064a09e24266ad5f94effd1803f9fa1..1184b7af8996f6b4df30b28ebcf768b069d47b2a 100644 (file)
@@ -290,6 +290,7 @@ define MAKE_BL
         $(eval DUMP       := $(call IMG_DUMP,$(1)))
         $(eval BIN        := $(call IMG_BIN,$(1)))
         $(eval BL_LINKERFILE := $(BL$(call uppercase,$(1))_LINKERFILE))
+        $(eval BL_LIBS    := $(BL$(call uppercase,$(1))_LIBS))
         # We use sort only to get a list of unique object directory names.
         # ordering is not relevant but sort removes duplicates.
         $(eval TEMP_OBJ_DIRS := $(sort $(dir ${OBJS} ${LINKERFILE})))
@@ -312,7 +313,7 @@ bl${1}_dirs: | ${OBJ_DIRS}
 $(eval $(call MAKE_OBJS,$(BUILD_DIR),$(SOURCES),$(1)))
 $(eval $(call MAKE_LD,$(LINKERFILE),$(BL_LINKERFILE),$(1)))
 
-$(ELF): $(OBJS) $(LINKERFILE) | bl$(1)_dirs
+$(ELF): $(OBJS) $(LINKERFILE) | bl$(1)_dirs $(BL_LIBS)
        @echo "  LD      $$@"
 ifdef MAKE_BUILD_STRINGS
        $(call MAKE_BUILD_STRINGS, $(BUILD_DIR)/build_message.o)
@@ -322,7 +323,7 @@ else
                $$(CC) $$(TF_CFLAGS) $$(CFLAGS) -xc -c - -o $(BUILD_DIR)/build_message.o
 endif
        $$(Q)$$(LD) -o $$@ $$(TF_LDFLAGS) $$(LDFLAGS) -Map=$(MAPFILE) \
-               --script $(LINKERFILE) $(BUILD_DIR)/build_message.o $(OBJS) $(LDLIBS)
+               --script $(LINKERFILE) $(BUILD_DIR)/build_message.o $(OBJS) $(LDLIBS) $(BL_LIBS)
 
 $(DUMP): $(ELF)
        @echo "  OD      $$@"
diff --git a/plat/marvell/a8k/a70x0/board/dram_port.c b/plat/marvell/a8k/a70x0/board/dram_port.c
new file mode 100644 (file)
index 0000000..c670258
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <arch_helpers.h>
+#include <debug.h>
+#include <mv_ddr_if.h>
+#include <plat_marvell.h>
+
+/*
+ * This function may modify the default DRAM parameters
+ * based on information received from SPD or bootloader
+ * configuration located on non volatile storage
+ */
+void plat_marvell_dram_update_topology(void)
+{
+}
+
+/*
+ * This struct provides the DRAM training code with
+ * the appropriate board DRAM configuration
+ */
+static struct mv_ddr_topology_map board_topology_map = {
+/* FIXME: MISL board 2CS 4Gb x8 devices of micron - 2133P */
+       DEBUG_LEVEL_ERROR,
+       0x1, /* active interfaces */
+       /* cs_mask, mirror, dqs_swap, ck_swap X subphys */
+       { { { {0x3, 0x2, 0, 0},
+             {0x3, 0x2, 0, 0},
+             {0x3, 0x2, 0, 0},
+             {0x3, 0x2, 0, 0},
+             {0x3, 0x2, 0, 0},
+             {0x3, 0x2, 0, 0},
+             {0x3, 0x2, 0, 0},
+             {0x3, 0x2, 0, 0},
+             {0x3, 0x2, 0, 0} },
+          SPEED_BIN_DDR_2133P,         /* speed_bin */
+          MV_DDR_DEV_WIDTH_8BIT,       /* sdram device width */
+          MV_DDR_DIE_CAP_4GBIT,        /* die capacity */
+          MV_DDR_FREQ_SAR,             /* frequency */
+          0, 0,                        /* cas_l, cas_wl */
+          MV_DDR_TEMP_LOW} },          /* temperature */
+       MV_DDR_32BIT_ECC_PUP8_BUS_MASK, /* subphys mask */
+       MV_DDR_CFG_DEFAULT,             /* ddr configuration data source */
+       { {0} },                        /* raw spd data */
+       {0},                            /* timing parameters */
+       {                               /* electrical configuration */
+               {                       /* memory electrical configuration */
+                       MV_DDR_RTT_NOM_PARK_RZQ_DISABLE,        /* rtt_nom */
+                       {
+                               MV_DDR_RTT_NOM_PARK_RZQ_DIV4, /* rtt_park 1cs */
+                               MV_DDR_RTT_NOM_PARK_RZQ_DIV1  /* rtt_park 2cs */
+                       },
+                       {
+                               MV_DDR_RTT_WR_DYN_ODT_OFF,      /* rtt_wr 1cs */
+                               MV_DDR_RTT_WR_RZQ_DIV2          /* rtt_wr 2cs */
+                       },
+                       MV_DDR_DIC_RZQ_DIV7     /* dic */
+               },
+               {                       /* phy electrical configuration */
+                       MV_DDR_OHM_30,  /* data_drv_p */
+                       MV_DDR_OHM_30,  /* data_drv_n */
+                       MV_DDR_OHM_30,  /* ctrl_drv_p */
+                       MV_DDR_OHM_30,  /* ctrl_drv_n */
+                       {
+                               MV_DDR_OHM_60,  /* odt_p 1cs */
+                               MV_DDR_OHM_120  /* odt_p 2cs */
+                       },
+                       {
+                               MV_DDR_OHM_60,  /* odt_n 1cs */
+                               MV_DDR_OHM_120  /* odt_n 2cs */
+                       },
+               },
+               {                       /* mac electrical configuration */
+                       MV_DDR_ODT_CFG_NORMAL,          /* odtcfg_pattern */
+                       MV_DDR_ODT_CFG_ALWAYS_ON,       /* odtcfg_write */
+                       MV_DDR_ODT_CFG_NORMAL,          /* odtcfg_read */
+               },
+       }
+};
+
+struct mv_ddr_topology_map *mv_ddr_topology_map_get(void)
+{
+       /* Return the board topology as defined in the board code */
+       return &board_topology_map;
+}
diff --git a/plat/marvell/a8k/a70x0/board/marvell_plat_config.c b/plat/marvell/a8k/a70x0/board/marvell_plat_config.c
new file mode 100644 (file)
index 0000000..9171986
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <a8k_common.h>
+
+/*
+ * If bootrom is currently at BLE there's no need to include the memory
+ * maps structure at this point
+ */
+#include <mvebu_def.h>
+#ifndef IMAGE_BLE
+
+/*****************************************************************************
+ * AMB Configuration
+ *****************************************************************************
+ */
+struct addr_map_win amb_memory_map[] = {
+       /* CP0 SPI1 CS0 Direct Mode access */
+       {0xf900,        0x1000000,      AMB_SPI1_CS0_ID},
+};
+
+int marvell_get_amb_memory_map(struct addr_map_win **win,
+                              uint32_t *size, uintptr_t base)
+{
+       *win = amb_memory_map;
+       if (*win == NULL)
+               *size = 0;
+       else
+               *size = ARRAY_SIZE(amb_memory_map);
+
+       return 0;
+}
+#endif
+
+/*****************************************************************************
+ * IO_WIN Configuration
+ *****************************************************************************
+ */
+struct addr_map_win io_win_memory_map[] = {
+#ifndef IMAGE_BLE
+       /* MCI 0 indirect window */
+       {MVEBU_MCI_REG_BASE_REMAP(0),   0x100000, MCI_0_TID},
+       /* MCI 1 indirect window */
+       {MVEBU_MCI_REG_BASE_REMAP(1),   0x100000, MCI_1_TID},
+#endif
+};
+
+uint32_t marvell_get_io_win_gcr_target(int ap_index)
+{
+       return PIDI_TID;
+}
+
+int marvell_get_io_win_memory_map(int ap_index, struct addr_map_win **win,
+                                 uint32_t *size)
+{
+       *win = io_win_memory_map;
+       if (*win == NULL)
+               *size = 0;
+       else
+               *size = ARRAY_SIZE(io_win_memory_map);
+
+       return 0;
+}
+
+#ifndef IMAGE_BLE
+/*****************************************************************************
+ * IOB Configuration
+ *****************************************************************************
+ */
+struct addr_map_win iob_memory_map[] = {
+       /* PEX1_X1 window */
+       {0x00000000f7000000,    0x1000000,      PEX1_TID},
+       /* PEX2_X1 window */
+       {0x00000000f8000000,    0x1000000,      PEX2_TID},
+       /* PEX0_X4 window */
+       {0x00000000f6000000,    0x1000000,      PEX0_TID},
+       /* SPI1_CS0 (RUNIT) window */
+       {0x00000000f9000000,    0x1000000,      RUNIT_TID},
+};
+
+int marvell_get_iob_memory_map(struct addr_map_win **win, uint32_t *size,
+                              uintptr_t base)
+{
+       *win = iob_memory_map;
+       *size = ARRAY_SIZE(iob_memory_map);
+
+       return 0;
+}
+#endif
+
+/*****************************************************************************
+ * CCU Configuration
+ *****************************************************************************
+ */
+struct addr_map_win ccu_memory_map[] = {       /* IO window */
+#ifdef IMAGE_BLE
+       {0x00000000f2000000,    0x4000000,      IO_0_TID}, /* IO window */
+#else
+       {0x00000000f2000000,    0xe000000,      IO_0_TID},
+#endif
+};
+
+uint32_t marvell_get_ccu_gcr_target(int ap)
+{
+       return DRAM_0_TID;
+}
+
+int marvell_get_ccu_memory_map(int ap_index, struct addr_map_win **win,
+                              uint32_t *size)
+{
+       *win = ccu_memory_map;
+       *size = ARRAY_SIZE(ccu_memory_map);
+
+       return 0;
+}
+
+#ifdef IMAGE_BLE
+/*****************************************************************************
+ * SKIP IMAGE Configuration
+ *****************************************************************************
+ */
+#if PLAT_RECOVERY_IMAGE_ENABLE
+struct skip_image skip_im = {
+       .detection_method = GPIO,
+       .info.gpio.num = 33,
+       .info.gpio.button_state = HIGH,
+       .info.test.cp_ap = CP,
+       .info.test.cp_index = 0,
+};
+
+void *plat_marvell_get_skip_image_data(void)
+{
+       /* Return the skip_image configurations */
+       return &skip_im;
+}
+#endif
+#endif
diff --git a/plat/marvell/a8k/a70x0/mvebu_def.h b/plat/marvell/a8k/a70x0/mvebu_def.h
new file mode 100644 (file)
index 0000000..a7c5abb
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef __MVEBU_DEF_H__
+#define __MVEBU_DEF_H__
+
+#include <a8k_plat_def.h>
+
+#define CP_COUNT               1       /* A70x0 has single CP0 */
+
+#endif /* __MVEBU_DEF_H__ */
diff --git a/plat/marvell/a8k/a70x0/platform.mk b/plat/marvell/a8k/a70x0/platform.mk
new file mode 100644 (file)
index 0000000..29dfd95
--- /dev/null
@@ -0,0 +1,16 @@
+#
+# Copyright (C) 2018 Marvell International Ltd.
+#
+# SPDX-License-Identifier:     BSD-3-Clause
+# https://spdx.org/licenses
+#
+
+PCI_EP_SUPPORT         := 0
+
+DOIMAGE_SEC            :=      tools/doimage/secure/sec_img_7K.cfg
+
+MARVELL_MOCHI_DRV      :=      drivers/marvell/mochi/apn806_setup.c
+
+include plat/marvell/a8k/common/a8k_common.mk
+
+include plat/marvell/common/marvell_common.mk
diff --git a/plat/marvell/a8k/a70x0_amc/board/dram_port.c b/plat/marvell/a8k/a70x0_amc/board/dram_port.c
new file mode 100644 (file)
index 0000000..ab1df46
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <arch_helpers.h>
+#include <debug.h>
+#include <mv_ddr_if.h>
+#include <plat_marvell.h>
+
+/*
+ * This function may modify the default DRAM parameters
+ * based on information received from SPD or bootloader
+ * configuration located on non volatile storage
+ */
+void plat_marvell_dram_update_topology(void)
+{
+}
+
+/*
+ * This struct provides the DRAM training code with
+ * the appropriate board DRAM configuration
+ */
+static struct mv_ddr_topology_map board_topology_map = {
+/* FIXME: MISL board 2CS 8Gb x8 devices of micron - 2133P */
+       DEBUG_LEVEL_ERROR,
+       0x1, /* active interfaces */
+       /* cs_mask, mirror, dqs_swap, ck_swap X subphys */
+       { { { {0x3, 0x2, 0, 0},
+             {0x3, 0x2, 0, 0},
+             {0x3, 0x2, 0, 0},
+             {0x3, 0x2, 0, 0},
+             {0x3, 0x2, 0, 0},
+             {0x3, 0x2, 0, 0},
+             {0x3, 0x2, 0, 0},
+             {0x3, 0x2, 0, 0},
+             {0x3, 0x2, 0, 0} },
+          SPEED_BIN_DDR_2400T,         /* speed_bin */
+          MV_DDR_DEV_WIDTH_8BIT,       /* sdram device width */
+          MV_DDR_DIE_CAP_8GBIT,        /* die capacity */
+          MV_DDR_FREQ_SAR,             /* frequency */
+          0, 0,                        /* cas_l, cas_wl */
+          MV_DDR_TEMP_LOW} },          /* temperature */
+       MV_DDR_32BIT_ECC_PUP8_BUS_MASK, /* subphys mask */
+       MV_DDR_CFG_DEFAULT,             /* ddr configuration data source */
+       { {0} },                        /* raw spd data */
+       {0},                            /* timing parameters */
+       {                               /* electrical configuration */
+               {                       /* memory electrical configuration */
+                       MV_DDR_RTT_NOM_PARK_RZQ_DISABLE,        /* rtt_nom */
+                       {
+                               MV_DDR_RTT_NOM_PARK_RZQ_DIV4, /* rtt_park 1cs */
+                               MV_DDR_RTT_NOM_PARK_RZQ_DIV1  /* rtt_park 2cs */
+                       },
+                       {
+                               MV_DDR_RTT_WR_DYN_ODT_OFF,      /* rtt_wr 1cs */
+                               MV_DDR_RTT_WR_RZQ_DIV2          /* rtt_wr 2cs */
+                       },
+                       MV_DDR_DIC_RZQ_DIV7     /* dic */
+               },
+               {                       /* phy electrical configuration */
+                       MV_DDR_OHM_30,  /* data_drv_p */
+                       MV_DDR_OHM_30,  /* data_drv_n */
+                       MV_DDR_OHM_30,  /* ctrl_drv_p */
+                       MV_DDR_OHM_30,  /* ctrl_drv_n */
+                       {
+                               MV_DDR_OHM_60,  /* odt_p 1cs */
+                               MV_DDR_OHM_120  /* odt_p 2cs */
+                       },
+                       {
+                               MV_DDR_OHM_60,  /* odt_n 1cs */
+                               MV_DDR_OHM_120  /* odt_n 2cs */
+                       },
+               },
+               {                       /* mac electrical configuration */
+                       MV_DDR_ODT_CFG_NORMAL,          /* odtcfg_pattern */
+                       MV_DDR_ODT_CFG_ALWAYS_ON,       /* odtcfg_write */
+                       MV_DDR_ODT_CFG_NORMAL,          /* odtcfg_read */
+               },
+       }
+};
+
+struct mv_ddr_topology_map *mv_ddr_topology_map_get(void)
+{
+       /* Return the board topology as defined in the board code */
+       return &board_topology_map;
+}
diff --git a/plat/marvell/a8k/a70x0_amc/board/marvell_plat_config.c b/plat/marvell/a8k/a70x0_amc/board/marvell_plat_config.c
new file mode 100644 (file)
index 0000000..ec4124c
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <a8k_common.h>
+
+/*
+ * If bootrom is currently at BLE there's no need to include the memory
+ * maps structure at this point
+ */
+#include <mvebu_def.h>
+#ifndef IMAGE_BLE
+
+/*****************************************************************************
+ * AMB Configuration
+ *****************************************************************************
+ */
+struct addr_map_win *amb_memory_map;
+
+int marvell_get_amb_memory_map(struct addr_map_win **win, uint32_t *size,
+                              uintptr_t base)
+{
+       *win = amb_memory_map;
+       if (*win == NULL)
+               *size = 0;
+       else
+               *size = ARRAY_SIZE(amb_memory_map);
+
+       return 0;
+}
+#endif
+
+/*****************************************************************************
+ * IO WIN Configuration
+ *****************************************************************************
+ */
+struct addr_map_win io_win_memory_map[] = {
+#ifndef IMAGE_BLE
+       /* MCI 0 indirect window */
+       {MVEBU_MCI_REG_BASE_REMAP(0),   0x100000,       MCI_0_TID},
+       /* MCI 1 indirect window */
+       {MVEBU_MCI_REG_BASE_REMAP(1),   0x100000,       MCI_1_TID},
+#endif
+};
+
+uint32_t marvell_get_io_win_gcr_target(int ap_index)
+{
+       return PIDI_TID;
+}
+
+int marvell_get_io_win_memory_map(int ap_index, struct addr_map_win **win,
+                                 uint32_t *size)
+{
+       *win = io_win_memory_map;
+       if (*win == NULL)
+               *size = 0;
+       else
+               *size = ARRAY_SIZE(io_win_memory_map);
+
+       return 0;
+}
+
+#ifndef IMAGE_BLE
+/*****************************************************************************
+ * IOB Configuration
+ *****************************************************************************
+ */
+struct addr_map_win iob_memory_map[] = {
+       /* PEX0_X4 window */
+       {0x00000000f6000000,    0x6000000,      PEX0_TID},
+       {0x00000000c0000000,    0x30000000,     PEX0_TID},
+       {0x0000000800000000,    0x200000000,    PEX0_TID},
+};
+
+int marvell_get_iob_memory_map(struct addr_map_win **win, uint32_t *size,
+                              uintptr_t base)
+{
+       *win = iob_memory_map;
+       *size = ARRAY_SIZE(iob_memory_map);
+
+       return 0;
+}
+#endif
+
+/*****************************************************************************
+ * CCU Configuration
+ *****************************************************************************
+ */
+struct addr_map_win ccu_memory_map[] = {
+#ifdef IMAGE_BLE
+       {0x00000000f2000000,    0x4000000,      IO_0_TID}, /* IO window */
+#else
+       {0x00000000f2000000,    0xe000000,      IO_0_TID},
+       {0x00000000c0000000,    0x30000000,     IO_0_TID}, /* IO window */
+       {0x0000000800000000,    0x200000000,    IO_0_TID}, /* IO window */
+#endif
+};
+
+uint32_t marvell_get_ccu_gcr_target(int ap)
+{
+       return DRAM_0_TID;
+}
+
+int marvell_get_ccu_memory_map(int ap_index, struct addr_map_win **win,
+                              uint32_t *size)
+{
+       *win = ccu_memory_map;
+       *size = ARRAY_SIZE(ccu_memory_map);
+
+       return 0;
+}
+
+#ifdef IMAGE_BLE
+
+struct pci_hw_cfg *plat_get_pcie_hw_data(void)
+{
+       return NULL;
+}
+
+/*****************************************************************************
+ * SKIP IMAGE Configuration
+ *****************************************************************************
+ */
+#if PLAT_RECOVERY_IMAGE_ENABLE
+struct skip_image skip_im = {
+       .detection_method = GPIO,
+       .info.gpio.num = 33,
+       .info.gpio.button_state = HIGH,
+       .info.test.cp_ap = CP,
+       .info.test.cp_index = 0,
+};
+
+void *plat_marvell_get_skip_image_data(void)
+{
+       /* Return the skip_image configurations */
+       return &skip_im;
+}
+#endif
+#endif
diff --git a/plat/marvell/a8k/a70x0_amc/mvebu_def.h b/plat/marvell/a8k/a70x0_amc/mvebu_def.h
new file mode 100644 (file)
index 0000000..5c66552
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef __MVEBU_DEF_H__
+#define __MVEBU_DEF_H__
+
+#include <a8k_plat_def.h>
+
+#define CP_COUNT               1       /* A70x0 has single CP0 */
+
+/***********************************************************************
+ * Required platform porting definitions common to all
+ * Management Compute SubSystems (MSS)
+ ***********************************************************************
+ */
+/*
+ * Load address of SCP_BL2
+ * SCP_BL2 is loaded to the same place as BL31.
+ * Once SCP_BL2 is transferred to the SCP,
+ * it is discarded and BL31 is loaded over the top.
+ */
+#ifdef SCP_IMAGE
+#define SCP_BL2_BASE           BL31_BASE
+#endif
+
+
+#endif /* __MVEBU_DEF_H__ */
diff --git a/plat/marvell/a8k/a70x0_amc/platform.mk b/plat/marvell/a8k/a70x0_amc/platform.mk
new file mode 100644 (file)
index 0000000..29dfd95
--- /dev/null
@@ -0,0 +1,16 @@
+#
+# Copyright (C) 2018 Marvell International Ltd.
+#
+# SPDX-License-Identifier:     BSD-3-Clause
+# https://spdx.org/licenses
+#
+
+PCI_EP_SUPPORT         := 0
+
+DOIMAGE_SEC            :=      tools/doimage/secure/sec_img_7K.cfg
+
+MARVELL_MOCHI_DRV      :=      drivers/marvell/mochi/apn806_setup.c
+
+include plat/marvell/a8k/common/a8k_common.mk
+
+include plat/marvell/common/marvell_common.mk
diff --git a/plat/marvell/a8k/a80x0/board/dram_port.c b/plat/marvell/a8k/a80x0/board/dram_port.c
new file mode 100644 (file)
index 0000000..c720c11
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <arch_helpers.h>
+#include <a8k_i2c.h>
+#include <debug.h>
+#include <mmio.h>
+#include <mv_ddr_if.h>
+#include <mvebu_def.h>
+#include <plat_marvell.h>
+
+#define MVEBU_AP_MPP_CTRL0_7_REG               MVEBU_AP_MPP_REGS(0)
+#define MVEBU_AP_MPP_CTRL4_OFFS                        16
+#define MVEBU_AP_MPP_CTRL5_OFFS                        20
+#define MVEBU_AP_MPP_CTRL4_I2C0_SDA_ENA                0x3
+#define MVEBU_AP_MPP_CTRL5_I2C0_SCK_ENA                0x3
+
+#define MVEBU_CP_MPP_CTRL37_OFFS               20
+#define MVEBU_CP_MPP_CTRL38_OFFS               24
+#define MVEBU_CP_MPP_CTRL37_I2C0_SCK_ENA       0x2
+#define MVEBU_CP_MPP_CTRL38_I2C0_SDA_ENA       0x2
+
+#define MVEBU_MPP_CTRL_MASK                    0xf
+
+/*
+ * This struct provides the DRAM training code with
+ * the appropriate board DRAM configuration
+ */
+static struct mv_ddr_topology_map board_topology_map = {
+       /* MISL board with 1CS 8Gb x4 devices of Micron 2400T */
+       DEBUG_LEVEL_ERROR,
+       0x1, /* active interfaces */
+       /* cs_mask, mirror, dqs_swap, ck_swap X subphys */
+       { { { {0x1, 0x0, 0, 0}, /* FIXME: change the cs mask for all 64 bit */
+             {0x1, 0x0, 0, 0},
+             {0x1, 0x0, 0, 0},
+             {0x1, 0x0, 0, 0},
+             {0x1, 0x0, 0, 0},
+             {0x1, 0x0, 0, 0},
+             {0x1, 0x0, 0, 0},
+             {0x1, 0x0, 0, 0},
+             {0x1, 0x0, 0, 0} },
+          /* TODO: double check if the speed bin is 2400T */
+          SPEED_BIN_DDR_2400T,         /* speed_bin */
+          MV_DDR_DEV_WIDTH_8BIT,       /* sdram device width */
+          MV_DDR_DIE_CAP_8GBIT,        /* die capacity */
+          MV_DDR_FREQ_SAR,             /* frequency */
+          0, 0,                        /* cas_l, cas_wl */
+          MV_DDR_TEMP_LOW} },          /* temperature */
+       MV_DDR_64BIT_ECC_PUP8_BUS_MASK, /* subphys mask */
+       MV_DDR_CFG_SPD,                 /* ddr configuration data source */
+       { {0} },                        /* raw spd data */
+       {0},                            /* timing parameters */
+       {                               /* electrical configuration */
+               {                       /* memory electrical configuration */
+                       MV_DDR_RTT_NOM_PARK_RZQ_DISABLE,        /* rtt_nom */
+                       {
+                               MV_DDR_RTT_NOM_PARK_RZQ_DIV4, /* rtt_park 1cs */
+                               MV_DDR_RTT_NOM_PARK_RZQ_DIV1  /* rtt_park 2cs */
+                       },
+                       {
+                               MV_DDR_RTT_WR_DYN_ODT_OFF,      /* rtt_wr 1cs */
+                               MV_DDR_RTT_WR_RZQ_DIV2          /* rtt_wr 2cs */
+                       },
+                       MV_DDR_DIC_RZQ_DIV7     /* dic */
+               },
+               {                       /* phy electrical configuration */
+                       MV_DDR_OHM_30,  /* data_drv_p */
+                       MV_DDR_OHM_30,  /* data_drv_n */
+                       MV_DDR_OHM_30,  /* ctrl_drv_p */
+                       MV_DDR_OHM_30,  /* ctrl_drv_n */
+                       {
+                               MV_DDR_OHM_60,  /* odt_p 1cs */
+                               MV_DDR_OHM_120  /* odt_p 2cs */
+                       },
+                       {
+                               MV_DDR_OHM_60,  /* odt_n 1cs */
+                               MV_DDR_OHM_120  /* odt_n 2cs */
+                       },
+               },
+               {                       /* mac electrical configuration */
+                       MV_DDR_ODT_CFG_NORMAL,          /* odtcfg_pattern */
+                       MV_DDR_ODT_CFG_ALWAYS_ON,       /* odtcfg_write */
+                       MV_DDR_ODT_CFG_NORMAL,          /* odtcfg_read */
+               },
+       }
+};
+
+struct mv_ddr_topology_map *mv_ddr_topology_map_get(void)
+{
+       /* Return the board topology as defined in the board code */
+       return &board_topology_map;
+}
+
+static void mpp_config(void)
+{
+       uintptr_t reg;
+       uint32_t val;
+
+       reg = MVEBU_CP_MPP_REGS(0, 4);
+       /* configure CP0 MPP 37 and 38 to i2c */
+       val = mmio_read_32(reg);
+       val &= ~((MVEBU_MPP_CTRL_MASK << MVEBU_CP_MPP_CTRL37_OFFS) |
+               (MVEBU_MPP_CTRL_MASK << MVEBU_CP_MPP_CTRL38_OFFS));
+       val |= (MVEBU_CP_MPP_CTRL37_I2C0_SCK_ENA <<
+                       MVEBU_CP_MPP_CTRL37_OFFS) |
+               (MVEBU_CP_MPP_CTRL38_I2C0_SDA_ENA <<
+                       MVEBU_CP_MPP_CTRL38_OFFS);
+       mmio_write_32(reg, val);
+}
+
+/*
+ * This function may modify the default DRAM parameters
+ * based on information received from SPD or bootloader
+ * configuration located on non volatile storage
+ */
+void plat_marvell_dram_update_topology(void)
+{
+       struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get();
+
+       INFO("Gathering DRAM information\n");
+
+       if (tm->cfg_src == MV_DDR_CFG_SPD) {
+               /* configure MPPs to enable i2c */
+               mpp_config();
+
+               /* initialize i2c */
+               i2c_init((void *)MVEBU_CP0_I2C_BASE);
+
+               /* select SPD memory page 0 to access DRAM configuration */
+               i2c_write(I2C_SPD_P0_ADDR, 0x0, 1, tm->spd_data.all_bytes, 1);
+
+               /* read data from spd */
+               i2c_read(I2C_SPD_ADDR, 0x0, 1, tm->spd_data.all_bytes,
+                        sizeof(tm->spd_data.all_bytes));
+       }
+}
diff --git a/plat/marvell/a8k/a80x0/board/marvell_plat_config.c b/plat/marvell/a8k/a80x0/board/marvell_plat_config.c
new file mode 100644 (file)
index 0000000..43beffa
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <a8k_common.h>
+/*
+ * If bootrom is currently at BLE there's no need to include the memory
+ * maps structure at this point
+ */
+#include <mvebu_def.h>
+#ifndef IMAGE_BLE
+
+/*****************************************************************************
+ * AMB Configuration
+ *****************************************************************************
+ */
+struct addr_map_win amb_memory_map[] = {
+       /* CP1 SPI1 CS0 Direct Mode access */
+       {0xf900,        0x1000000,      AMB_SPI1_CS0_ID},
+};
+
+int marvell_get_amb_memory_map(struct addr_map_win **win, uint32_t *size,
+                              uintptr_t base)
+{
+       *win = amb_memory_map;
+       if (*win == NULL)
+               *size = 0;
+       else
+               *size = ARRAY_SIZE(amb_memory_map);
+
+       return 0;
+}
+#endif
+
+/*****************************************************************************
+ * IO WIN Configuration
+ *****************************************************************************
+ */
+struct addr_map_win io_win_memory_map[] = {
+       /* CP1 (MCI0) internal regs */
+       {0x00000000f4000000,            0x2000000,  MCI_0_TID},
+#ifndef IMAGE_BLE
+       /* PCIe0 and SPI1_CS0 (RUNIT) on CP1*/
+       {0x00000000f9000000,            0x2000000,  MCI_0_TID},
+       /* PCIe1 on CP1*/
+       {0x00000000fb000000,            0x1000000,  MCI_0_TID},
+       /* PCIe2 on CP1*/
+       {0x00000000fc000000,            0x1000000,  MCI_0_TID},
+       /* MCI 0 indirect window */
+       {MVEBU_MCI_REG_BASE_REMAP(0),   0x100000,  MCI_0_TID},
+       /* MCI 1 indirect window */
+       {MVEBU_MCI_REG_BASE_REMAP(1),   0x100000,  MCI_1_TID},
+#endif
+};
+
+uint32_t marvell_get_io_win_gcr_target(int ap_index)
+{
+       return PIDI_TID;
+}
+
+int marvell_get_io_win_memory_map(int ap_index, struct addr_map_win **win,
+                                 uint32_t *size)
+{
+       *win = io_win_memory_map;
+       if (*win == NULL)
+               *size = 0;
+       else
+               *size = ARRAY_SIZE(io_win_memory_map);
+
+       return 0;
+}
+
+#ifndef IMAGE_BLE
+/*****************************************************************************
+ * IOB Configuration
+ *****************************************************************************
+ */
+struct addr_map_win iob_memory_map_cp0[] = {
+       /* CP0 */
+       /* PEX1_X1 window */
+       {0x00000000f7000000,    0x1000000,      PEX1_TID},
+       /* PEX2_X1 window */
+       {0x00000000f8000000,    0x1000000,      PEX2_TID},
+       /* PEX0_X4 window */
+       {0x00000000f6000000,    0x1000000,      PEX0_TID}
+};
+
+struct addr_map_win iob_memory_map_cp1[] = {
+       /* CP1 */
+       /* SPI1_CS0 (RUNIT) window */
+       {0x00000000f9000000,    0x1000000,      RUNIT_TID},
+       /* PEX1_X1 window */
+       {0x00000000fb000000,    0x1000000,      PEX1_TID},
+       /* PEX2_X1 window */
+       {0x00000000fc000000,    0x1000000,      PEX2_TID},
+       /* PEX0_X4 window */
+       {0x00000000fa000000,    0x1000000,      PEX0_TID}
+};
+
+int marvell_get_iob_memory_map(struct addr_map_win **win, uint32_t *size,
+                              uintptr_t base)
+{
+       switch (base) {
+       case MVEBU_CP_REGS_BASE(0):
+               *win = iob_memory_map_cp0;
+               *size = ARRAY_SIZE(iob_memory_map_cp0);
+               return 0;
+       case MVEBU_CP_REGS_BASE(1):
+               *win = iob_memory_map_cp1;
+               *size = ARRAY_SIZE(iob_memory_map_cp1);
+               return 0;
+       default:
+               *size = 0;
+               *win = 0;
+               return 1;
+       }
+}
+#endif
+
+/*****************************************************************************
+ * CCU Configuration
+ *****************************************************************************
+ */
+struct addr_map_win ccu_memory_map[] = {
+#ifdef IMAGE_BLE
+       {0x00000000f2000000,    0x4000000,  IO_0_TID}, /* IO window */
+#else
+       {0x00000000f2000000,    0xe000000,  IO_0_TID}, /* IO window */
+#endif
+};
+
+uint32_t marvell_get_ccu_gcr_target(int ap)
+{
+       return DRAM_0_TID;
+}
+
+int marvell_get_ccu_memory_map(int ap, struct addr_map_win **win,
+                              uint32_t *size)
+{
+       *win = ccu_memory_map;
+       *size = ARRAY_SIZE(ccu_memory_map);
+
+       return 0;
+}
+
+#ifndef IMAGE_BLE
+/*****************************************************************************
+ * SoC PM configuration
+ *****************************************************************************
+ */
+/* CP GPIO should be used and the GPIOs should be within same GPIO register */
+struct power_off_method pm_cfg = {
+       .type = PMIC_GPIO,
+       .cfg.gpio.pin_count = 1,
+       .cfg.gpio.info = {{0, 35} },
+       .cfg.gpio.step_count = 7,
+       .cfg.gpio.seq = {1, 0, 1, 0, 1, 0, 1},
+       .cfg.gpio.delay_ms = 10,
+};
+
+void *plat_marvell_get_pm_cfg(void)
+{
+       /* Return the PM configurations */
+       return &pm_cfg;
+}
+
+/* In reference to #ifndef IMAGE_BLE, this part is used for BLE only. */
+#else
+/*****************************************************************************
+ * SKIP IMAGE Configuration
+ *****************************************************************************
+ */
+#if PLAT_RECOVERY_IMAGE_ENABLE
+struct skip_image skip_im = {
+       .detection_method = GPIO,
+       .info.gpio.num = 33,
+       .info.gpio.button_state = HIGH,
+       .info.test.cp_ap = CP,
+       .info.test.cp_index = 0,
+};
+
+void *plat_marvell_get_skip_image_data(void)
+{
+       /* Return the skip_image configurations */
+       return &skip_im;
+}
+#endif
+#endif
diff --git a/plat/marvell/a8k/a80x0/mvebu_def.h b/plat/marvell/a8k/a80x0/mvebu_def.h
new file mode 100644 (file)
index 0000000..5bff12c
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef __MVEBU_DEF_H__
+#define __MVEBU_DEF_H__
+
+#include <a8k_plat_def.h>
+
+#define CP_COUNT               2       /* A80x0 has both CP0 & CP1 */
+#define I2C_SPD_ADDR           0x53    /* Access SPD data */
+#define I2C_SPD_P0_ADDR                0x36    /* Select SPD data page 0 */
+
+#endif /* __MVEBU_DEF_H__ */
diff --git a/plat/marvell/a8k/a80x0/platform.mk b/plat/marvell/a8k/a80x0/platform.mk
new file mode 100644 (file)
index 0000000..0fe235b
--- /dev/null
@@ -0,0 +1,16 @@
+#
+# Copyright (C) 2018 Marvell International Ltd.
+#
+# SPDX-License-Identifier:     BSD-3-Clause
+# https://spdx.org/licenses
+#
+
+PCI_EP_SUPPORT         := 0
+
+DOIMAGE_SEC            :=      tools/doimage/secure/sec_img_8K.cfg
+
+MARVELL_MOCHI_DRV      :=      drivers/marvell/mochi/apn806_setup.c
+
+include plat/marvell/a8k/common/a8k_common.mk
+
+include plat/marvell/common/marvell_common.mk
diff --git a/plat/marvell/a8k/a80x0_mcbin/board/dram_port.c b/plat/marvell/a8k/a80x0_mcbin/board/dram_port.c
new file mode 100644 (file)
index 0000000..b455b83
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <arch_helpers.h>
+#include <a8k_i2c.h>
+#include <debug.h>
+#include <mmio.h>
+#include <mv_ddr_if.h>
+#include <mvebu_def.h>
+#include <plat_marvell.h>
+
+#define MVEBU_CP_MPP_CTRL37_OFFS               20
+#define MVEBU_CP_MPP_CTRL38_OFFS               24
+#define MVEBU_CP_MPP_CTRL37_I2C0_SCK_ENA       0x2
+#define MVEBU_CP_MPP_CTRL38_I2C0_SDA_ENA       0x2
+
+#define MVEBU_MPP_CTRL_MASK                    0xf
+
+/*
+ * This struct provides the DRAM training code with
+ * the appropriate board DRAM configuration
+ */
+static struct mv_ddr_topology_map board_topology_map = {
+       /* Board with 1CS 8Gb x4 devices of Micron 2400T */
+       DEBUG_LEVEL_ERROR,
+       0x1, /* active interfaces */
+       /* cs_mask, mirror, dqs_swap, ck_swap X subphys */
+       { { { {0x1, 0x0, 0, 0}, /* FIXME: change the cs mask for all 64 bit */
+             {0x1, 0x0, 0, 0},
+             {0x1, 0x0, 0, 0},
+             {0x1, 0x0, 0, 0},
+             {0x1, 0x0, 0, 0},
+             {0x1, 0x0, 0, 0},
+             {0x1, 0x0, 0, 0},
+             {0x1, 0x0, 0, 0},
+             {0x1, 0x0, 0, 0} },
+          /* TODO: double check if the speed bin is 2400T */
+          SPEED_BIN_DDR_2400T,         /* speed_bin */
+          MV_DDR_DEV_WIDTH_8BIT,       /* sdram device width */
+          MV_DDR_DIE_CAP_8GBIT,        /* die capacity */
+          MV_DDR_FREQ_SAR,             /* frequency */
+          0, 0,                        /* cas_l, cas_wl */
+          MV_DDR_TEMP_LOW} },          /* temperature */
+          MV_DDR_64BIT_BUS_MASK,       /* subphys mask */
+          MV_DDR_CFG_SPD,              /* ddr configuration data source */
+       { {0} },                        /* raw spd data */
+       {0},                            /* timing parameters */
+       {                               /* electrical configuration */
+               {                       /* memory electrical configuration */
+                       MV_DDR_RTT_NOM_PARK_RZQ_DISABLE,        /* rtt_nom */
+                       {
+                               MV_DDR_RTT_NOM_PARK_RZQ_DIV4, /* rtt_park 1cs */
+                               MV_DDR_RTT_NOM_PARK_RZQ_DIV1  /* rtt_park 2cs */
+                       },
+                       {
+                               MV_DDR_RTT_WR_DYN_ODT_OFF,      /* rtt_wr 1cs */
+                               MV_DDR_RTT_WR_RZQ_DIV2          /* rtt_wr 2cs */
+                       },
+                       MV_DDR_DIC_RZQ_DIV7     /* dic */
+               },
+               {                       /* phy electrical configuration */
+                       MV_DDR_OHM_30,  /* data_drv_p */
+                       MV_DDR_OHM_30,  /* data_drv_n */
+                       MV_DDR_OHM_30,  /* ctrl_drv_p */
+                       MV_DDR_OHM_30,  /* ctrl_drv_n */
+                       {
+                               MV_DDR_OHM_60,  /* odt_p 1cs */
+                               MV_DDR_OHM_120  /* odt_p 2cs */
+                       },
+                       {
+                               MV_DDR_OHM_60,  /* odt_n 1cs */
+                               MV_DDR_OHM_120  /* odt_n 2cs */
+                       },
+               },
+               {                       /* mac electrical configuration */
+                       MV_DDR_ODT_CFG_NORMAL,          /* odtcfg_pattern */
+                       MV_DDR_ODT_CFG_ALWAYS_ON,       /* odtcfg_write */
+                       MV_DDR_ODT_CFG_NORMAL,          /* odtcfg_read */
+               },
+       }
+};
+
+struct mv_ddr_topology_map *mv_ddr_topology_map_get(void)
+{
+       /* Return the board topology as defined in the board code */
+       return &board_topology_map;
+}
+
+static void mpp_config(void)
+{
+       uint32_t val;
+       uintptr_t reg = MVEBU_CP_MPP_REGS(0, 4);
+
+       /* configure CP0 MPP 37 and 38 to i2c */
+       val = mmio_read_32(reg);
+       val &= ~((MVEBU_MPP_CTRL_MASK << MVEBU_CP_MPP_CTRL37_OFFS) |
+               (MVEBU_MPP_CTRL_MASK << MVEBU_CP_MPP_CTRL38_OFFS));
+       val |= (MVEBU_CP_MPP_CTRL37_I2C0_SCK_ENA << MVEBU_CP_MPP_CTRL37_OFFS) |
+               (MVEBU_CP_MPP_CTRL38_I2C0_SDA_ENA << MVEBU_CP_MPP_CTRL38_OFFS);
+       mmio_write_32(reg, val);
+}
+
+/*
+ * This function may modify the default DRAM parameters
+ * based on information received from SPD or bootloader
+ * configuration located on non volatile storage
+ */
+void plat_marvell_dram_update_topology(void)
+{
+       struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get();
+
+       INFO("Gathering DRAM information\n");
+
+       if (tm->cfg_src == MV_DDR_CFG_SPD) {
+               /* configure MPPs to enable i2c */
+               mpp_config();
+               /* initialize the i2c */
+               i2c_init((void *)MVEBU_CP0_I2C_BASE);
+               /* select SPD memory page 0 to access DRAM configuration */
+               i2c_write(I2C_SPD_P0_ADDR, 0x0, 1, tm->spd_data.all_bytes, 1);
+               /* read data from spd */
+               i2c_read(I2C_SPD_ADDR, 0x0, 1, tm->spd_data.all_bytes,
+                        sizeof(tm->spd_data.all_bytes));
+       }
+}
diff --git a/plat/marvell/a8k/a80x0_mcbin/board/marvell_plat_config.c b/plat/marvell/a8k/a80x0_mcbin/board/marvell_plat_config.c
new file mode 100644 (file)
index 0000000..079bd8f
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <a8k_common.h>
+#include <delay_timer.h>
+#include <mmio.h>
+/*
+ * If bootrom is currently at BLE there's no need to include the memory
+ * maps structure at this point
+ */
+#include <mvebu_def.h>
+#ifndef IMAGE_BLE
+
+/*****************************************************************************
+ * GPIO Configuration
+ *****************************************************************************
+ */
+#define MPP_CONTROL_REGISTER           0xf2440018
+#define MPP_CONTROL_MPP_SEL_52_MASK    0xf0000
+#define GPIO_DATA_OUT1_REGISTER                0xf2440140
+#define GPIO_DATA_OUT_EN_CTRL1_REGISTER 0xf2440144
+#define GPIO52_MASK                    0x100000
+
+/* Reset PCIe via GPIO number 52 */
+int marvell_gpio_config(void)
+{
+       uint32_t reg;
+
+       reg = mmio_read_32(MPP_CONTROL_REGISTER);
+       reg |= MPP_CONTROL_MPP_SEL_52_MASK;
+       mmio_write_32(MPP_CONTROL_REGISTER, reg);
+
+       reg = mmio_read_32(GPIO_DATA_OUT1_REGISTER);
+       reg |= GPIO52_MASK;
+       mmio_write_32(GPIO_DATA_OUT1_REGISTER, reg);
+
+       reg = mmio_read_32(GPIO_DATA_OUT_EN_CTRL1_REGISTER);
+       reg &= ~GPIO52_MASK;
+       mmio_write_32(GPIO_DATA_OUT_EN_CTRL1_REGISTER, reg);
+       udelay(100);
+
+       return 0;
+}
+
+/*****************************************************************************
+ * AMB Configuration
+ *****************************************************************************
+ */
+struct addr_map_win amb_memory_map[] = {
+       /* CP1 SPI1 CS0 Direct Mode access */
+       {0xf900,        0x1000000,      AMB_SPI1_CS0_ID},
+};
+
+int marvell_get_amb_memory_map(struct addr_map_win **win, uint32_t *size,
+                              uintptr_t base)
+{
+       *win = amb_memory_map;
+       if (*win == NULL)
+               *size = 0;
+       else
+               *size = ARRAY_SIZE(amb_memory_map);
+
+       return 0;
+}
+#endif
+
+/*****************************************************************************
+ * IO WIN Configuration
+ *****************************************************************************
+ */
+struct addr_map_win io_win_memory_map[] = {
+       /* CP1 (MCI0) internal regs */
+       {0x00000000f4000000,            0x2000000,  MCI_0_TID},
+#ifndef IMAGE_BLE
+       /* PCIe0 and SPI1_CS0 (RUNIT) on CP1*/
+       {0x00000000f9000000,            0x2000000,  MCI_0_TID},
+       /* PCIe1 on CP1*/
+       {0x00000000fb000000,            0x1000000,  MCI_0_TID},
+       /* PCIe2 on CP1*/
+       {0x00000000fc000000,            0x1000000,  MCI_0_TID},
+       /* MCI 0 indirect window */
+       {MVEBU_MCI_REG_BASE_REMAP(0),   0x100000,   MCI_0_TID},
+       /* MCI 1 indirect window */
+       {MVEBU_MCI_REG_BASE_REMAP(1),   0x100000,   MCI_1_TID},
+#endif
+};
+
+uint32_t marvell_get_io_win_gcr_target(int ap_index)
+{
+       return PIDI_TID;
+}
+
+int marvell_get_io_win_memory_map(int ap_index, struct addr_map_win **win,
+                                 uint32_t *size)
+{
+       *win = io_win_memory_map;
+       if (*win == NULL)
+               *size = 0;
+       else
+               *size = ARRAY_SIZE(io_win_memory_map);
+
+       return 0;
+}
+
+#ifndef IMAGE_BLE
+/*****************************************************************************
+ * IOB Configuration
+ *****************************************************************************
+ */
+struct addr_map_win iob_memory_map_cp0[] = {
+       /* CP0 */
+       /* PEX1_X1 window */
+       {0x00000000f7000000,    0x1000000,      PEX1_TID},
+       /* PEX2_X1 window */
+       {0x00000000f8000000,    0x1000000,      PEX2_TID},
+       /* PEX0_X4 window */
+       {0x00000000f6000000,    0x1000000,      PEX0_TID},
+       {0x00000000c0000000,    0x30000000,     PEX0_TID},
+       {0x0000000800000000,    0x100000000,    PEX0_TID},
+};
+
+struct addr_map_win iob_memory_map_cp1[] = {
+       /* CP1 */
+       /* SPI1_CS0 (RUNIT) window */
+       {0x00000000f9000000,    0x1000000,      RUNIT_TID},
+       /* PEX1_X1 window */
+       {0x00000000fb000000,    0x1000000,      PEX1_TID},
+       /* PEX2_X1 window */
+       {0x00000000fc000000,    0x1000000,      PEX2_TID},
+       /* PEX0_X4 window */
+       {0x00000000fa000000,    0x1000000,      PEX0_TID}
+};
+
+int marvell_get_iob_memory_map(struct addr_map_win **win, uint32_t *size,
+                              uintptr_t base)
+{
+       switch (base) {
+       case MVEBU_CP_REGS_BASE(0):
+               *win = iob_memory_map_cp0;
+               *size = ARRAY_SIZE(iob_memory_map_cp0);
+               return 0;
+       case MVEBU_CP_REGS_BASE(1):
+               *win = iob_memory_map_cp1;
+               *size = ARRAY_SIZE(iob_memory_map_cp1);
+               return 0;
+       default:
+               *size = 0;
+               *win = 0;
+               return 1;
+       }
+}
+#endif
+
+/*****************************************************************************
+ * CCU Configuration
+ *****************************************************************************
+ */
+struct addr_map_win ccu_memory_map[] = {
+#ifdef IMAGE_BLE
+       {0x00000000f2000000,    0x4000000,  IO_0_TID}, /* IO window */
+#else
+       {0x00000000f2000000,    0xe000000,  IO_0_TID}, /* IO window */
+       {0x00000000c0000000,    0x30000000,  IO_0_TID}, /* IO window */
+       {0x0000000800000000,    0x100000000,  IO_0_TID}, /* IO window */
+#endif
+};
+
+uint32_t marvell_get_ccu_gcr_target(int ap)
+{
+       return DRAM_0_TID;
+}
+
+int marvell_get_ccu_memory_map(int ap_index, struct addr_map_win **win,
+                              uint32_t *size)
+{
+       *win = ccu_memory_map;
+       *size = ARRAY_SIZE(ccu_memory_map);
+
+       return 0;
+}
+
+/* In reference to #ifndef IMAGE_BLE, this part is used for BLE only. */
+
+/*****************************************************************************
+ * SKIP IMAGE Configuration
+ *****************************************************************************
+ */
+void *plat_marvell_get_skip_image_data(void)
+{
+       /* No recovery button on A8k-MCBIN board */
+       return NULL;
+}
diff --git a/plat/marvell/a8k/a80x0_mcbin/mvebu_def.h b/plat/marvell/a8k/a80x0_mcbin/mvebu_def.h
new file mode 100644 (file)
index 0000000..5bff12c
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef __MVEBU_DEF_H__
+#define __MVEBU_DEF_H__
+
+#include <a8k_plat_def.h>
+
+#define CP_COUNT               2       /* A80x0 has both CP0 & CP1 */
+#define I2C_SPD_ADDR           0x53    /* Access SPD data */
+#define I2C_SPD_P0_ADDR                0x36    /* Select SPD data page 0 */
+
+#endif /* __MVEBU_DEF_H__ */
diff --git a/plat/marvell/a8k/a80x0_mcbin/platform.mk b/plat/marvell/a8k/a80x0_mcbin/platform.mk
new file mode 100644 (file)
index 0000000..0fe235b
--- /dev/null
@@ -0,0 +1,16 @@
+#
+# Copyright (C) 2018 Marvell International Ltd.
+#
+# SPDX-License-Identifier:     BSD-3-Clause
+# https://spdx.org/licenses
+#
+
+PCI_EP_SUPPORT         := 0
+
+DOIMAGE_SEC            :=      tools/doimage/secure/sec_img_8K.cfg
+
+MARVELL_MOCHI_DRV      :=      drivers/marvell/mochi/apn806_setup.c
+
+include plat/marvell/a8k/common/a8k_common.mk
+
+include plat/marvell/common/marvell_common.mk
diff --git a/plat/marvell/a8k/common/a8k_common.mk b/plat/marvell/a8k/common/a8k_common.mk
new file mode 100644 (file)
index 0000000..3bcce96
--- /dev/null
@@ -0,0 +1,122 @@
+#
+# Copyright (C) 2016 - 2018 Marvell International Ltd.
+#
+# SPDX-License-Identifier:     BSD-3-Clause
+# https://spdx.org/licenses
+
+include tools/doimage/doimage.mk
+
+PLAT_FAMILY            := a8k
+PLAT_FAMILY_BASE       := plat/marvell/$(PLAT_FAMILY)
+PLAT_INCLUDE_BASE      := include/plat/marvell/$(PLAT_FAMILY)
+PLAT_COMMON_BASE       := $(PLAT_FAMILY_BASE)/common
+MARVELL_DRV_BASE       := drivers/marvell
+MARVELL_COMMON_BASE    := plat/marvell/common
+
+ERRATA_A72_859971      := 1
+
+# Enable MSS support for a8k family
+MSS_SUPPORT            := 1
+
+# Disable EL3 cache for power management
+BL31_CACHE_DISABLE     := 1
+$(eval $(call add_define,BL31_CACHE_DISABLE))
+
+$(eval $(call add_define,PCI_EP_SUPPORT))
+$(eval $(call assert_boolean,PCI_EP_SUPPORT))
+
+DOIMAGEPATH            ?=      tools/doimage
+DOIMAGETOOL            ?=      ${DOIMAGEPATH}/doimage
+
+ROM_BIN_EXT ?= $(BUILD_PLAT)/ble.bin
+DOIMAGE_FLAGS  += -b $(ROM_BIN_EXT) $(NAND_DOIMAGE_FLAGS) $(DOIMAGE_SEC_FLAGS)
+
+# This define specifies DDR type for BLE
+$(eval $(call add_define,CONFIG_DDR4))
+
+MARVELL_GIC_SOURCES    :=      drivers/arm/gic/common/gic_common.c     \
+                               drivers/arm/gic/v2/gicv2_main.c         \
+                               drivers/arm/gic/v2/gicv2_helpers.c      \
+                               plat/common/plat_gicv2.c
+
+ATF_INCLUDES           :=      -Iinclude/common/tbbr
+
+PLAT_INCLUDES          :=      -I$(PLAT_FAMILY_BASE)/$(PLAT)           \
+                               -I$(PLAT_COMMON_BASE)/include           \
+                               -I$(PLAT_INCLUDE_BASE)/common           \
+                               -Iinclude/drivers/marvell               \
+                               -Iinclude/drivers/marvell/mochi         \
+                               $(ATF_INCLUDES)
+
+PLAT_BL_COMMON_SOURCES :=      $(PLAT_COMMON_BASE)/aarch64/a8k_common.c \
+                               drivers/console/aarch64/console.S        \
+                               drivers/ti/uart/aarch64/16550_console.S
+
+BLE_PORTING_SOURCES    :=      $(PLAT_FAMILY_BASE)/$(PLAT)/board/dram_port.c \
+                               $(PLAT_FAMILY_BASE)/$(PLAT)/board/marvell_plat_config.c
+
+MARVELL_MOCHI_DRV      +=      $(MARVELL_DRV_BASE)/mochi/cp110_setup.c
+
+BLE_SOURCES            :=      $(PLAT_COMMON_BASE)/plat_ble_setup.c            \
+                               $(MARVELL_MOCHI_DRV)                           \
+                               $(MARVELL_DRV_BASE)/i2c/a8k_i2c.c               \
+                               $(PLAT_COMMON_BASE)/plat_pm.c                   \
+                               $(MARVELL_DRV_BASE)/thermal.c                   \
+                               $(PLAT_COMMON_BASE)/plat_thermal.c              \
+                               $(BLE_PORTING_SOURCES)                          \
+                               $(MARVELL_DRV_BASE)/ccu.c                       \
+                               $(MARVELL_DRV_BASE)/io_win.c
+
+BL1_SOURCES            +=      $(PLAT_COMMON_BASE)/aarch64/plat_helpers.S \
+                               lib/cpus/aarch64/cortex_a72.S
+
+MARVELL_DRV            :=      $(MARVELL_DRV_BASE)/io_win.c    \
+                               $(MARVELL_DRV_BASE)/iob.c       \
+                               $(MARVELL_DRV_BASE)/mci.c       \
+                               $(MARVELL_DRV_BASE)/amb_adec.c  \
+                               $(MARVELL_DRV_BASE)/ccu.c       \
+                               $(MARVELL_DRV_BASE)/cache_llc.c \
+                               $(MARVELL_DRV_BASE)/comphy/phy-comphy-cp110.c
+
+BL31_PORTING_SOURCES   :=      $(PLAT_FAMILY_BASE)/$(PLAT)/board/marvell_plat_config.c
+
+BL31_SOURCES           +=      lib/cpus/aarch64/cortex_a72.S                  \
+                               $(PLAT_COMMON_BASE)/aarch64/plat_helpers.S     \
+                               $(PLAT_COMMON_BASE)/aarch64/plat_arch_config.c \
+                               $(PLAT_COMMON_BASE)/plat_pm.c                  \
+                               $(PLAT_COMMON_BASE)/plat_bl31_setup.c          \
+                               $(MARVELL_COMMON_BASE)/marvell_gicv2.c         \
+                               $(MARVELL_COMMON_BASE)/mrvl_sip_svc.c          \
+                               $(MARVELL_COMMON_BASE)/marvell_ddr_info.c      \
+                               $(BL31_PORTING_SOURCES)                        \
+                               $(MARVELL_DRV)                                 \
+                               $(MARVELL_MOCHI_DRV)                           \
+                               $(MARVELL_GIC_SOURCES)
+
+# Add trace functionality for PM
+BL31_SOURCES           +=      $(PLAT_COMMON_BASE)/plat_pm_trace.c
+
+# Disable the PSCI platform compatibility layer (allows porting
+# from Old Platform APIs to the new APIs).
+# It is not needed since Marvell platform already used the new platform APIs.
+ENABLE_PLAT_COMPAT     :=      0
+
+# Force builds with BL2 image on a80x0 platforms
+ifndef SCP_BL2
+ $(error "Error: SCP_BL2 image is mandatory for a8k family")
+endif
+
+# MSS (SCP) build
+include $(PLAT_COMMON_BASE)/mss/mss_a8k.mk
+
+# BLE (ROM context execution code, AKA binary extension)
+BLE_PATH       ?=  ble
+
+include ${BLE_PATH}/ble.mk
+$(eval $(call MAKE_BL,e))
+
+mrvl_flash: ${BUILD_PLAT}/${FIP_NAME} ${DOIMAGETOOL} ${BUILD_PLAT}/ble.bin
+       $(shell truncate -s %128K ${BUILD_PLAT}/bl1.bin)
+       $(shell cat ${BUILD_PLAT}/bl1.bin ${BUILD_PLAT}/${FIP_NAME} > ${BUILD_PLAT}/${BOOT_IMAGE})
+       ${DOIMAGETOOL} ${DOIMAGE_FLAGS} ${BUILD_PLAT}/${BOOT_IMAGE} ${BUILD_PLAT}/${FLASH_IMAGE}
+
diff --git a/plat/marvell/a8k/common/aarch64/a8k_common.c b/plat/marvell/a8k/common/aarch64/a8k_common.c
new file mode 100644 (file)
index 0000000..7c2bf31
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <plat_marvell.h>
+
+
+/* MMU entry for internal (register) space access */
+#define MAP_DEVICE0    MAP_REGION_FLAT(DEVICE0_BASE,                   \
+                                       DEVICE0_SIZE,                   \
+                                       MT_DEVICE | MT_RW | MT_SECURE)
+
+/*
+ * Table of regions for various BL stages to map using the MMU.
+ */
+#if IMAGE_BL1
+const mmap_region_t plat_marvell_mmap[] = {
+       MARVELL_MAP_SHARED_RAM,
+       MAP_DEVICE0,
+       {0}
+};
+#endif
+#if IMAGE_BL2
+const mmap_region_t plat_marvell_mmap[] = {
+       MARVELL_MAP_SHARED_RAM,
+       MAP_DEVICE0,
+       MARVELL_MAP_DRAM,
+       {0}
+};
+#endif
+
+#if IMAGE_BL2U
+const mmap_region_t plat_marvell_mmap[] = {
+       MAP_DEVICE0,
+       {0}
+};
+#endif
+
+#if IMAGE_BLE
+const mmap_region_t plat_marvell_mmap[] = {
+       MAP_DEVICE0,
+       {0}
+};
+#endif
+
+#if IMAGE_BL31
+const mmap_region_t plat_marvell_mmap[] = {
+       MARVELL_MAP_SHARED_RAM,
+       MAP_DEVICE0,
+       MARVELL_MAP_DRAM,
+       {0}
+};
+#endif
+#if IMAGE_BL32
+const mmap_region_t plat_marvell_mmap[] = {
+       MAP_DEVICE0,
+       {0}
+};
+#endif
+
+MARVELL_CASSERT_MMAP;
diff --git a/plat/marvell/a8k/common/aarch64/plat_arch_config.c b/plat/marvell/a8k/common/aarch64/plat_arch_config.c
new file mode 100644 (file)
index 0000000..8667331
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <platform.h>
+#include <arch_helpers.h>
+#include <mmio.h>
+#include <debug.h>
+#include <cache_llc.h>
+
+
+#define CCU_HTC_ASET                   (MVEBU_CCU_BASE(MVEBU_AP0) + 0x264)
+#define MVEBU_IO_AFFINITY              (0xF00)
+
+
+static void plat_enable_affinity(void)
+{
+       int cluster_id;
+       int affinity;
+
+       /* set CPU Affinity */
+       cluster_id = plat_my_core_pos() / PLAT_MARVELL_CLUSTER_CORE_COUNT;
+       affinity = (MVEBU_IO_AFFINITY | (1 << cluster_id));
+       mmio_write_32(CCU_HTC_ASET, affinity);
+
+       /* set barier */
+       isb();
+}
+
+void marvell_psci_arch_init(int die_index)
+{
+#if LLC_ENABLE
+       /* check if LLC is in exclusive mode
+        * as L2 is configured to UniqueClean eviction
+        * (in a8k reset handler)
+        */
+       if (llc_is_exclusive(0) == 0)
+               ERROR("LLC should be configured to exclusice mode\n");
+#endif
+
+       /* Enable Affinity */
+       plat_enable_affinity();
+}
diff --git a/plat/marvell/a8k/common/aarch64/plat_helpers.S b/plat/marvell/a8k/common/aarch64/plat_helpers.S
new file mode 100644 (file)
index 0000000..fadc4c2
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <asm_macros.S>
+#include <platform_def.h>
+#include <marvell_pm.h>
+
+       .globl  plat_secondary_cold_boot_setup
+       .globl  plat_get_my_entrypoint
+       .globl  plat_is_my_cpu_primary
+       .globl  plat_reset_handler
+
+       /* -----------------------------------------------------
+        * void plat_secondary_cold_boot_setup (void);
+        *
+        * This function performs any platform specific actions
+        * needed for a secondary cpu after a cold reset. Right
+        * now this is a stub function.
+        * -----------------------------------------------------
+        */
+func plat_secondary_cold_boot_setup
+       mov     x0, #0
+       ret
+endfunc plat_secondary_cold_boot_setup
+
+       /* ---------------------------------------------------------------------
+        * unsigned long plat_get_my_entrypoint (void);
+        *
+        * Main job of this routine is to distinguish
+        * between a cold and warm boot
+        * For a cold boot, return 0.
+        * For a warm boot, read the mailbox and return the address it contains.
+        *
+        * ---------------------------------------------------------------------
+        */
+func plat_get_my_entrypoint
+       /* Read first word and compare it with magic num */
+       mov_imm x0, PLAT_MARVELL_MAILBOX_BASE
+       ldr     x1, [x0]
+       mov_imm x2, MVEBU_MAILBOX_MAGIC_NUM
+       cmp     x1, x2
+       beq     warm_boot  /* If compare failed, return 0, i.e. cold boot */
+       mov     x0, #0
+       ret
+warm_boot:
+       mov_imm x1, MBOX_IDX_SEC_ADDR           /* Get the jump address */
+       subs    x1, x1, #1
+       mov     x2, #(MBOX_IDX_SEC_ADDR * 8)
+       lsl     x3, x2, x1
+       add     x0, x0, x3
+       ldr     x0, [x0]
+       ret
+endfunc plat_get_my_entrypoint
+
+       /* -----------------------------------------------------
+        * unsigned int plat_is_my_cpu_primary (void);
+        *
+        * Find out whether the current cpu is the primary
+        * cpu.
+        * -----------------------------------------------------
+        */
+func plat_is_my_cpu_primary
+       mrs     x0, mpidr_el1
+       and     x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
+       cmp     x0, #MVEBU_PRIMARY_CPU
+       cset    w0, eq
+       ret
+endfunc plat_is_my_cpu_primary
+
+        /* -----------------------------------------------------
+        * void plat_reset_handler (void);
+         *
+        * Platform specific configuration right after cpu is
+        * is our of reset.
+        *
+         * The plat_reset_handler can clobber x0 - x18, x30.
+         * -----------------------------------------------------
+         */
+func plat_reset_handler
+       /*
+        * Note: the configurations below  should be done before MMU,
+        *        I Cache and L2are enabled.
+        *        The reset handler is executed right after reset
+        *        and before Caches are enabled.
+        */
+
+       /* Enable L1/L2 ECC and Parity */
+       mrs x5, s3_1_c11_c0_2  /* L2 Ctrl */
+       orr x5, x5, #(1 << 21) /* Enable L1/L2 cache ECC & Parity */
+       msr s3_1_c11_c0_2, x5  /* L2 Ctrl */
+
+#if LLC_ENABLE
+       /*
+        * Enable L2 UniqueClean evictions
+        *  Note: this configuration assumes that LLC is configured
+        *        in exclusive mode.
+        *        Later on in the code this assumption will be validated
+        */
+       mrs x5, s3_1_c15_c0_0  /* L2 Ctrl */
+       orr x5, x5, #(1 << 14) /* Enable UniqueClean evictions with data */
+       msr s3_1_c15_c0_0, x5  /* L2 Ctrl */
+#endif
+
+       /* Instruction Barrier to allow msr command completion */
+       isb
+
+        ret
+endfunc plat_reset_handler
diff --git a/plat/marvell/a8k/common/include/a8k_plat_def.h b/plat/marvell/a8k/common/include/a8k_plat_def.h
new file mode 100644 (file)
index 0000000..4ed8c7e
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef __A8K_PLAT_DEF_H__
+#define __A8K_PLAT_DEF_H__
+
+#include <marvell_def.h>
+
+#define MVEBU_PRIMARY_CPU              0x0
+#define MVEBU_AP0                      0x0
+
+/* APN806 revision ID */
+#define MVEBU_CSS_GWD_CTRL_IIDR2_REG   (MVEBU_REGS_BASE + 0x610FCC)
+#define GWD_IIDR2_REV_ID_OFFSET                12
+#define GWD_IIDR2_REV_ID_MASK          0xF
+#define GWD_IIDR2_CHIP_ID_OFFSET       20
+#define GWD_IIDR2_CHIP_ID_MASK         (0xFFF << GWD_IIDR2_CHIP_ID_OFFSET)
+
+#define CHIP_ID_AP806                  0x806
+#define CHIP_ID_AP807                  0x807
+
+#define COUNTER_FREQUENCY              25000000
+
+#define MVEBU_REGS_BASE                        0xF0000000
+#define MVEBU_REGS_BASE_MASK           0xF0000000
+#define MVEBU_REGS_BASE_AP(ap)         MVEBU_REGS_BASE
+#define MVEBU_CP_REGS_BASE(cp_index)   (0xF2000000 + (cp_index) * 0x2000000)
+#define MVEBU_RFU_BASE                 (MVEBU_REGS_BASE + 0x6F0000)
+#define MVEBU_IO_WIN_BASE(ap_index)    (MVEBU_RFU_BASE)
+#define MVEBU_IO_WIN_GCR_OFFSET                (0x70)
+#define MVEBU_IO_WIN_MAX_WINS          (7)
+
+/* Misc SoC configurations Base */
+#define MVEBU_MISC_SOC_BASE            (MVEBU_REGS_BASE + 0x6F4300)
+
+#define MVEBU_CCU_BASE(ap_index)       (MVEBU_REGS_BASE + 0x4000)
+#define MVEBU_CCU_MAX_WINS             (8)
+
+#define MVEBU_LLC_BASE(ap_index)       (MVEBU_REGS_BASE + 0x8000)
+#define MVEBU_DRAM_MAC_BASE            (MVEBU_REGS_BASE + 0x20000)
+#define MVEBU_DRAM_PHY_BASE            (MVEBU_REGS_BASE + 0x20000)
+#define MVEBU_SMMU_BASE                        (MVEBU_REGS_BASE + 0x100000)
+#define MVEBU_CP_MPP_REGS(cp_index, n) (MVEBU_CP_REGS_BASE(cp_index) + \
+                                               0x440000 + ((n) << 2))
+#define MVEBU_PM_MPP_REGS(cp_index, n) (MVEBU_CP_REGS_BASE(cp_index) + \
+                                               0x440000 + ((n / 8) << 2))
+#define MVEBU_CP_GPIO_DATA_OUT(cp_index, n) \
+                                       (MVEBU_CP_REGS_BASE(cp_index) + \
+                                       0x440100 + ((n > 32) ? 0x40 : 0x00))
+#define MVEBU_CP_GPIO_DATA_OUT_EN(cp_index, n) \
+                                       (MVEBU_CP_REGS_BASE(cp_index) + \
+                                       0x440104 + ((n > 32) ? 0x40 : 0x00))
+#define MVEBU_CP_GPIO_DATA_IN(cp_index, n) (MVEBU_CP_REGS_BASE(cp_index) + \
+                                       0x440110 + ((n > 32) ? 0x40 : 0x00))
+#define MVEBU_AP_MPP_REGS(n)           (MVEBU_RFU_BASE + 0x4000 + ((n) << 2))
+#define MVEBU_AP_GPIO_REGS             (MVEBU_RFU_BASE + 0x5040)
+#define MVEBU_AP_GPIO_DATA_IN          (MVEBU_AP_GPIO_REGS + 0x10)
+#define MVEBU_AP_I2C_BASE              (MVEBU_REGS_BASE + 0x511000)
+#define MVEBU_CP0_I2C_BASE             (MVEBU_CP_REGS_BASE(0) + 0x701000)
+#define MVEBU_AP_EXT_TSEN_BASE         (MVEBU_RFU_BASE + 0x8084)
+
+#define MVEBU_AP_MC_TRUSTZONE_REG_LOW(ap, win) (MVEBU_REGS_BASE_AP(ap) + \
+                                                       0x20080 + ((win) * 0x8))
+#define MVEBU_AP_MC_TRUSTZONE_REG_HIGH(ap, win)        (MVEBU_REGS_BASE_AP(ap) + \
+                                                       0x20084 + ((win) * 0x8))
+
+/* MCI indirect access definitions */
+#define MCI_MAX_UNIT_ID                                2
+/* SoC RFU / IHBx4 Control */
+#define MCIX4_REG_START_ADDRESS_REG(unit_id)   (MVEBU_RFU_BASE + \
+                                               0x4218 + (unit_id * 0x20))
+#define MCI_REMAP_OFF_SHIFT                    8
+
+#define MVEBU_MCI_REG_BASE_REMAP(index)                (0xFD000000 + \
+                                               ((index) * 0x1000000))
+
+#define MVEBU_PCIE_X4_MAC_BASE(x)      (MVEBU_CP_REGS_BASE(x) + 0x600000)
+#define MVEBU_COMPHY_BASE(x)           (MVEBU_CP_REGS_BASE(x) + 0x441000)
+#define MVEBU_HPIPE_BASE(x)            (MVEBU_CP_REGS_BASE(x) + 0x120000)
+#define MVEBU_CP_DFX_OFFSET            (0x400200)
+
+/*****************************************************************************
+ * MVEBU memory map related constants
+ *****************************************************************************
+ */
+/* Aggregate of all devices in the first GB */
+#define DEVICE0_BASE                   MVEBU_REGS_BASE
+#define DEVICE0_SIZE                   0x10000000
+
+/*****************************************************************************
+ * GIC-400 & interrupt handling related constants
+ *****************************************************************************
+ */
+/* Base MVEBU compatible GIC memory map */
+#define MVEBU_GICD_BASE                        0x210000
+#define MVEBU_GICC_BASE                        0x220000
+
+
+/*****************************************************************************
+ * AXI Configuration
+ *****************************************************************************
+ */
+#define MVEBU_AXI_ATTR_ARCACHE_OFFSET          4
+#define MVEBU_AXI_ATTR_ARCACHE_MASK            (0xF << \
+                                                MVEBU_AXI_ATTR_ARCACHE_OFFSET)
+#define MVEBU_AXI_ATTR_ARDOMAIN_OFFSET         12
+#define MVEBU_AXI_ATTR_ARDOMAIN_MASK           (0x3 << \
+                                                MVEBU_AXI_ATTR_ARDOMAIN_OFFSET)
+#define MVEBU_AXI_ATTR_AWCACHE_OFFSET          20
+#define MVEBU_AXI_ATTR_AWCACHE_MASK            (0xF << \
+                                                MVEBU_AXI_ATTR_AWCACHE_OFFSET)
+#define MVEBU_AXI_ATTR_AWDOMAIN_OFFSET         28
+#define MVEBU_AXI_ATTR_AWDOMAIN_MASK           (0x3 << \
+                                                MVEBU_AXI_ATTR_AWDOMAIN_OFFSET)
+
+/* SATA MBUS to AXI configuration */
+#define MVEBU_SATA_M2A_AXI_ARCACHE_OFFSET      1
+#define MVEBU_SATA_M2A_AXI_ARCACHE_MASK                (0xF << \
+                                       MVEBU_SATA_M2A_AXI_ARCACHE_OFFSET)
+#define MVEBU_SATA_M2A_AXI_AWCACHE_OFFSET      5
+#define MVEBU_SATA_M2A_AXI_AWCACHE_MASK                (0xF << \
+                                       MVEBU_SATA_M2A_AXI_AWCACHE_OFFSET)
+
+/* ARM cache attributes */
+#define CACHE_ATTR_BUFFERABLE                  0x1
+#define CACHE_ATTR_CACHEABLE                   0x2
+#define CACHE_ATTR_READ_ALLOC                  0x4
+#define CACHE_ATTR_WRITE_ALLOC                 0x8
+/* Domain */
+#define DOMAIN_NON_SHAREABLE                   0x0
+#define DOMAIN_INNER_SHAREABLE                 0x1
+#define DOMAIN_OUTER_SHAREABLE                 0x2
+#define DOMAIN_SYSTEM_SHAREABLE                        0x3
+
+/************************************************************************
+ * Required platform porting definitions common to all
+ * Management Compute SubSystems (MSS)
+ ************************************************************************
+ */
+/*
+ * Load address of SCP_BL2
+ * SCP_BL2 is loaded to the same place as BL31.
+ * Once SCP_BL2 is transferred to the SCP,
+ * it is discarded and BL31 is loaded over the top.
+ */
+#ifdef SCP_IMAGE
+#define SCP_BL2_BASE                    BL31_BASE
+#endif
+
+#ifndef __ASSEMBLER__
+enum ap806_sar_target_dev {
+       SAR_PIDI_MCIX2          = 0x0,
+       SAR_MCIX4               = 0x1,
+       SAR_SPI                 = 0x2,
+       SAR_SD                  = 0x3,
+       SAR_PIDI_MCIX2_BD       = 0x4, /* BootRom disabled */
+       SAR_MCIX4_DB            = 0x5, /* BootRom disabled */
+       SAR_SPI_DB              = 0x6, /* BootRom disabled */
+       SAR_EMMC                = 0x7
+};
+
+enum io_win_target_ids {
+       MCI_0_TID        = 0x0,
+       MCI_1_TID        = 0x1,
+       MCI_2_TID        = 0x2,
+       PIDI_TID         = 0x3,
+       SPI_TID          = 0x4,
+       STM_TID          = 0x5,
+       BOOTROM_TID      = 0x6,
+       IO_WIN_MAX_TID
+};
+
+enum ccu_target_ids {
+       IO_0_TID        = 0x00,
+       DRAM_0_TID      = 0x03,
+       IO_1_TID        = 0x0F,
+       CFG_REG_TID     = 0x10,
+       RAR_TID         = 0x20,
+       SRAM_TID        = 0x40,
+       DRAM_1_TID      = 0xC0,
+       CCU_MAX_TID,
+       INVALID_TID     = 0xFF
+};
+#endif /* __ASSEMBLER__ */
+
+#endif /* __A8K_PLAT_DEF_H__ */
diff --git a/plat/marvell/a8k/common/include/ddr_info.h b/plat/marvell/a8k/common/include/ddr_info.h
new file mode 100644 (file)
index 0000000..e19036a
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#define DRAM_MAX_IFACE                 1
+#define DRAM_CH0_MMAP_LOW_OFFSET       0x20200
diff --git a/plat/marvell/a8k/common/include/plat_macros.S b/plat/marvell/a8k/common/include/plat_macros.S
new file mode 100644 (file)
index 0000000..2a6ccf2
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef __PLAT_MACROS_S__
+#define __PLAT_MACROS_S__
+
+#include <marvell_macros.S>
+
+/*
+ * Required platform porting macros
+ * (Provided by included headers)
+ */
+.macro plat_crash_print_regs
+.endm
+
+#endif /* __PLAT_MACROS_S__ */
diff --git a/plat/marvell/a8k/common/include/platform_def.h b/plat/marvell/a8k/common/include/platform_def.h
new file mode 100644 (file)
index 0000000..f7bd23f
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef __PLATFORM_DEF_H__
+#define __PLATFORM_DEF_H__
+
+#include <board_marvell_def.h>
+#include <gic_common.h>
+#include <interrupt_props.h>
+#include <mvebu_def.h>
+#ifndef __ASSEMBLY__
+#include <stdio.h>
+#endif /* __ASSEMBLY__ */
+
+/*
+ * Most platform porting definitions provided by included headers
+ */
+
+/*
+ * DRAM Memory layout:
+ *             +-----------------------+
+ *             :                       :
+ *             :       Linux           :
+ * 0x04X00000-->+-----------------------+
+ *             |       BL3-3(u-boot)   |>>}>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+ *             |-----------------------|  }                                   |
+ *             |       BL3-[0,1, 2]    |  }---------------------------------> |
+ *             |-----------------------|  }                            ||     |
+ *             |       BL2             |  }->FIP (loaded by            ||     |
+ *             |-----------------------|  }       BootROM to DRAM)     ||     |
+ *             |       FIP_TOC         |  }                            ||     |
+ * 0x04120000-->|-----------------------|                              ||     |
+ *             |       BL1 (RO)        |                               ||     |
+ * 0x04100000-->+-----------------------+                              ||     |
+ *             :                       :                               ||     |
+ *             : Trusted SRAM section  :                               \/     |
+ * 0x04040000-->+-----------------------+  Replaced by BL2  +----------------+ |
+ *             |       BL1 (RW)        |  <<<<<<<<<<<<<<<< | BL3-1 NOBITS   | |
+ * 0x04037000-->|-----------------------|  <<<<<<<<<<<<<<<< |----------------| |
+ *             |                       |  <<<<<<<<<<<<<<<< | BL3-1 PROGBITS | |
+ * 0x04023000-->|-----------------------|                  +----------------+ |
+ *             |       BL2             |                                      |
+ *             |-----------------------|                                      |
+ *             |                       |                                      |
+ * 0x04001000-->|-----------------------|                                     |
+ *             |       Shared          |                                      |
+ * 0x04000000-->+-----------------------+                                     |
+ *             :                       :                                      |
+ *             :       Linux           :                                      |
+ *             :                       :                                      |
+ *             |-----------------------|                                      |
+ *             |                       |       U-Boot(BL3-3) Loaded by BL2    |
+ *             |       U-Boot          |       <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+ * 0x00000000-->+-----------------------+
+ *
+ * Trusted SRAM section 0x4000000..0x4200000:
+ * ----------------------------------------
+ * SRAM_BASE           = 0x4001000
+ * BL2_BASE                    = 0x4006000
+ * BL2_LIMIT           = BL31_BASE
+ * BL31_BASE           = 0x4023000 = (64MB + 256KB - 0x1D000)
+ * BL31_PROGBITS_LIMIT = BL1_RW_BASE
+ * BL1_RW_BASE         = 0x4037000 = (64MB + 256KB - 0x9000)
+ * BL1_RW_LIMIT                = BL31_LIMIT = 0x4040000
+ *
+ *
+ * PLAT_MARVELL_FIP_BASE       = 0x4120000
+ */
+
+/*
+ * Since BL33 is loaded by BL2 (and validated by BL31) to DRAM offset 0,
+ * it is allowed to load/copy images to 'NULL' pointers
+ */
+#if defined(IMAGE_BL2) || defined(IMAGE_BL31)
+#define PLAT_ALLOW_ZERO_ADDR_COPY
+#endif
+
+#define PLAT_MARVELL_SRAM_BASE                 0xFFE1C048
+#define PLAT_MARVELL_SRAM_END                  0xFFE78000
+
+#define PLAT_MARVELL_ATF_BASE                  0x4000000
+#define PLAT_MARVELL_ATF_LOAD_ADDR             (PLAT_MARVELL_ATF_BASE + \
+                                                               0x100000)
+
+#define PLAT_MARVELL_FIP_BASE                  (PLAT_MARVELL_ATF_LOAD_ADDR + \
+                                                               0x20000)
+#define PLAT_MARVELL_FIP_MAX_SIZE              0x4000000
+
+#define PLAT_MARVELL_NORTHB_COUNT              1
+
+#define PLAT_MARVELL_CLUSTER_COUNT             2
+#define PLAT_MARVELL_CLUSTER_CORE_COUNT                2
+
+#define PLAT_MARVELL_CORE_COUNT                        (PLAT_MARVELL_CLUSTER_COUNT * \
+                                               PLAT_MARVELL_CLUSTER_CORE_COUNT)
+
+/* DRAM[2MB..66MB] is used as Trusted ROM */
+#define PLAT_MARVELL_TRUSTED_ROM_BASE          PLAT_MARVELL_ATF_LOAD_ADDR
+/* 64 MB TODO: reduce this to minimum needed according to fip image size */
+#define PLAT_MARVELL_TRUSTED_ROM_SIZE          0x04000000
+/* Reserve 16M for SCP (Secure PayLoad) Trusted DRAM */
+#define PLAT_MARVELL_TRUSTED_DRAM_BASE         0x04400000
+#define PLAT_MARVELL_TRUSTED_DRAM_SIZE         0x01000000      /* 16 MB */
+
+/*
+ * PLAT_ARM_MAX_BL1_RW_SIZE is calculated using the current BL1 RW debug size
+ * plus a little space for growth.
+ */
+#define PLAT_MARVELL_MAX_BL1_RW_SIZE           0xA000
+
+/*
+ * PLAT_ARM_MAX_BL2_SIZE is calculated using the current BL2 debug size plus a
+ * little space for growth.
+ */
+#define PLAT_MARVELL_MAX_BL2_SIZE              0xF000
+
+/*
+ * PLAT_ARM_MAX_BL31_SIZE is calculated using the current BL31 debug size plus a
+ * little space for growth.
+ */
+#define PLAT_MARVEL_MAX_BL31_SIZE              0x5D000
+
+#define PLAT_MARVELL_CPU_ENTRY_ADDR            BL1_RO_BASE
+
+/* GIC related definitions */
+#define PLAT_MARVELL_GICD_BASE         (MVEBU_REGS_BASE + MVEBU_GICD_BASE)
+#define PLAT_MARVELL_GICC_BASE         (MVEBU_REGS_BASE + MVEBU_GICC_BASE)
+
+#define PLAT_MARVELL_G0_IRQ_PROPS(grp) \
+       INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, grp, \
+                       GIC_INTR_CFG_LEVEL), \
+       INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, grp, \
+                       GIC_INTR_CFG_LEVEL)
+
+#define PLAT_MARVELL_G1S_IRQ_PROPS(grp) \
+       INTR_PROP_DESC(MARVELL_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, \
+                       grp, GIC_INTR_CFG_LEVEL), \
+       INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, grp, \
+                       GIC_INTR_CFG_LEVEL), \
+       INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, grp, \
+                       GIC_INTR_CFG_LEVEL), \
+       INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, grp, \
+                       GIC_INTR_CFG_LEVEL), \
+       INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, grp, \
+                       GIC_INTR_CFG_LEVEL), \
+       INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, grp, \
+                       GIC_INTR_CFG_LEVEL), \
+       INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \
+                       GIC_INTR_CFG_LEVEL)
+
+#define PLAT_MARVELL_SHARED_RAM_CACHED         1
+
+/*
+ * Load address of BL3-3 for this platform port
+ */
+#define PLAT_MARVELL_NS_IMAGE_OFFSET           0x0
+
+/* System Reference Clock*/
+#define PLAT_REF_CLK_IN_HZ                     COUNTER_FREQUENCY
+
+/*
+ * PL011 related constants
+ */
+#define PLAT_MARVELL_BOOT_UART_BASE            (MVEBU_REGS_BASE + 0x512000)
+#define PLAT_MARVELL_BOOT_UART_CLK_IN_HZ       200000000
+
+#define PLAT_MARVELL_CRASH_UART_BASE           PLAT_MARVELL_BOOT_UART_BASE
+#define PLAT_MARVELL_CRASH_UART_CLK_IN_HZ      PLAT_MARVELL_BOOT_UART_CLK_IN_HZ
+
+#define PLAT_MARVELL_BL31_RUN_UART_BASE                PLAT_MARVELL_BOOT_UART_BASE
+#define PLAT_MARVELL_BL31_RUN_UART_CLK_IN_HZ   PLAT_MARVELL_BOOT_UART_CLK_IN_HZ
+
+/* Recovery image enable */
+#define PLAT_RECOVERY_IMAGE_ENABLE             0
+
+/* Required platform porting definitions */
+#define PLAT_MAX_PWR_LVL                       MPIDR_AFFLVL1
+
+/* System timer related constants */
+#define PLAT_MARVELL_NSTIMER_FRAME_ID          1
+
+/* Mailbox base address (note the lower memory space
+ * is reserved for BLE data)
+ */
+#define PLAT_MARVELL_MAILBOX_BASE              (MARVELL_TRUSTED_SRAM_BASE \
+                                                       + 0x400)
+#define PLAT_MARVELL_MAILBOX_SIZE              0x100
+#define PLAT_MARVELL_MAILBOX_MAGIC_NUM         0x6D72766C      /* mrvl */
+
+/* Securities */
+#define IRQ_SEC_OS_TICK_INT                    MARVELL_IRQ_SEC_PHY_TIMER
+
+#define TRUSTED_DRAM_BASE                      PLAT_MARVELL_TRUSTED_DRAM_BASE
+#define TRUSTED_DRAM_SIZE                      PLAT_MARVELL_TRUSTED_DRAM_SIZE
+
+#define BL32_BASE                              TRUSTED_DRAM_BASE
+
+#endif /* __PLATFORM_DEF_H__ */
diff --git a/plat/marvell/a8k/common/mss/mss_a8k.mk b/plat/marvell/a8k/common/mss/mss_a8k.mk
new file mode 100644 (file)
index 0000000..58f23d8
--- /dev/null
@@ -0,0 +1,20 @@
+#
+# Copyright (C) 2018 Marvell International Ltd.
+#
+# SPDX-License-Identifier:     BSD-3-Clause
+# https://spdx.org/licenses
+#
+
+PLAT_MARVELL           :=      plat/marvell
+A8K_MSS_SOURCE         :=      $(PLAT_MARVELL)/a8k/common/mss
+
+BL2_SOURCES            +=      $(A8K_MSS_SOURCE)/mss_bl2_setup.c
+
+BL31_SOURCES           +=      $(A8K_MSS_SOURCE)/mss_pm_ipc.c
+
+PLAT_INCLUDES          +=      -I$(A8K_MSS_SOURCE)
+
+ifneq (${SCP_BL2},)
+# This define is used to inidcate the SCP image is present
+$(eval $(call add_define,SCP_IMAGE))
+endif
diff --git a/plat/marvell/a8k/common/mss/mss_bl2_setup.c b/plat/marvell/a8k/common/mss/mss_bl2_setup.c
new file mode 100644 (file)
index 0000000..6688551
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <a8k_common.h>
+#include <bl_common.h>
+#include <ccu.h>
+#include <cp110_setup.h>
+#include <debug.h>
+#include <marvell_plat_priv.h> /* timer functionality */
+#include <mmio.h>
+#include <platform_def.h>
+
+#include "mss_scp_bootloader.h"
+
+/* IO windows configuration */
+#define IOW_GCR_OFFSET         (0x70)
+
+/* MSS windows configuration */
+#define MSS_AEBR(base)                 (base + 0x160)
+#define MSS_AIBR(base)                 (base + 0x164)
+#define MSS_AEBR_MASK                  0xFFF
+#define MSS_AIBR_MASK                  0xFFF
+
+#define MSS_EXTERNAL_SPACE             0x50000000
+#define MSS_EXTERNAL_ACCESS_BIT                28
+#define MSS_EXTERNAL_ADDR_MASK         0xfffffff
+#define MSS_INTERNAL_ACCESS_BIT                28
+
+struct addr_map_win ccu_mem_map[] = {
+       {MVEBU_CP_REGS_BASE(0), 0x4000000, IO_0_TID}
+};
+
+/* Since the scp_bl2 image can contain firmware for cp1 and cp0 coprocessors,
+ * the access to cp0 and cp1 need to be provided. More precisely it is
+ * required to:
+ *  - get the information about device id which is stored in CP0 registers
+ *    (to distinguish between cases where we have cp0 and cp1 or standalone cp0)
+ *  - get the access to cp which is needed for loading fw for cp0/cp1
+ *    coprocessors
+ * This function configures ccu windows accordingly.
+ *
+ * Note: there is no need to restore previous ccu configuration, since in next
+ * phase (BL31) the init_ccu will be called (via apn806_init/
+ * bl31_plat_arch_setu) and therefore the ccu configuration will be overwritten.
+ */
+static int bl2_plat_mmap_init(void)
+{
+       int cfg_num, win_id, cfg_idx;
+
+       cfg_num =  ARRAY_SIZE(ccu_mem_map);
+
+       /* CCU window-0 should not be counted - it's already used */
+       if (cfg_num > (MVEBU_CCU_MAX_WINS - 1)) {
+               ERROR("BL2: %s: trying to open too many windows\n", __func__);
+               return -1;
+       }
+
+       /* Enable required CCU windows
+        * Do not touch CCU window 0,
+        * it's used for the internal registers access
+        */
+       for (cfg_idx = 0, win_id = 1; cfg_idx < cfg_num; cfg_idx++, win_id++) {
+               /* Enable required CCU windows */
+               ccu_win_check(&ccu_mem_map[cfg_idx]);
+               ccu_enable_win(MVEBU_AP0, &ccu_mem_map[cfg_idx], win_id);
+       }
+
+       /* Set the default target id to PIDI */
+       mmio_write_32(MVEBU_IO_WIN_BASE(MVEBU_AP0) + IOW_GCR_OFFSET, PIDI_TID);
+
+       return 0;
+}
+
+/*****************************************************************************
+ * Transfer SCP_BL2 from Trusted RAM using the SCP Download protocol.
+ * Return 0 on success, -1 otherwise.
+ *****************************************************************************
+ */
+int bl2_plat_handle_scp_bl2(image_info_t *scp_bl2_image_info)
+{
+       int ret;
+
+       INFO("BL2: Initiating SCP_BL2 transfer to SCP\n");
+       printf("BL2: Initiating SCP_BL2 transfer to SCP\n");
+
+       /* initialize time (for delay functionality) */
+       plat_delay_timer_init();
+
+       ret = bl2_plat_mmap_init();
+       if (ret != 0)
+               return ret;
+
+       ret = scp_bootloader_transfer((void *)scp_bl2_image_info->image_base,
+               scp_bl2_image_info->image_size);
+
+       if (ret == 0)
+               INFO("BL2: SCP_BL2 transferred to SCP\n");
+       else
+               ERROR("BL2: SCP_BL2 transfer failure\n");
+
+       return ret;
+}
+
+uintptr_t bl2_plat_get_cp_mss_regs(int ap_idx, int cp_idx)
+{
+       return MVEBU_CP_REGS_BASE(cp_idx) + 0x280000;
+}
+
+uintptr_t bl2_plat_get_ap_mss_regs(int ap_idx)
+{
+       return MVEBU_REGS_BASE + 0x580000;
+}
+
+uint32_t bl2_plat_get_cp_count(int ap_idx)
+{
+       uint32_t revision = cp110_device_id_get(MVEBU_CP_REGS_BASE(0));
+       /* A8040: two CPs.
+        * A7040: one CP.
+        */
+       if (revision == MVEBU_80X0_DEV_ID ||
+           revision == MVEBU_80X0_CP115_DEV_ID)
+               return 2;
+       else
+               return 1;
+}
+
+uint32_t bl2_plat_get_ap_count(void)
+{
+       /* A8040 and A7040 have only one AP */
+       return 1;
+}
+
+void bl2_plat_configure_mss_windows(uintptr_t mss_regs)
+{
+       /* set AXI External and Internal Address Bus extension */
+       mmio_write_32(MSS_AEBR(mss_regs),
+                     ((0x0 >> MSS_EXTERNAL_ACCESS_BIT) & MSS_AEBR_MASK));
+       mmio_write_32(MSS_AIBR(mss_regs),
+                     ((mss_regs >> MSS_INTERNAL_ACCESS_BIT) & MSS_AIBR_MASK));
+}
diff --git a/plat/marvell/a8k/common/mss/mss_pm_ipc.c b/plat/marvell/a8k/common/mss/mss_pm_ipc.c
new file mode 100644 (file)
index 0000000..6ff4abc
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <debug.h>
+#include <mmio.h>
+#include <psci.h>
+#include <string.h>
+
+#include <mss_pm_ipc.h>
+
+/*
+ * SISR is 32 bit interrupt register representing 32 interrupts
+ *
+ * +======+=============+=============+
+ * + Bits + 31          + 30 - 00     +
+ * +======+=============+=============+
+ * + Desc + MSS Msg Int + Reserved    +
+ * +======+=============+=============+
+ */
+#define MSS_SISR               (MVEBU_REGS_BASE + 0x5800D0)
+#define MSS_SISTR              (MVEBU_REGS_BASE + 0x5800D8)
+
+#define MSS_MSG_INT_MASK       (0x80000000)
+#define MSS_TIMER_BASE         (MVEBU_REGS_BASE_MASK + 0x580110)
+#define MSS_TRIGGER_TIMEOUT    (1000)
+
+/*****************************************************************************
+ * mss_pm_ipc_msg_send
+ *
+ * DESCRIPTION: create and transmit IPC message
+ *****************************************************************************
+ */
+int mss_pm_ipc_msg_send(unsigned int channel_id, unsigned int msg_id,
+                       const psci_power_state_t *target_state)
+{
+       /* Transmit IPC message */
+#ifndef DISABLE_CLUSTER_LEVEL
+       mv_pm_ipc_msg_tx(channel_id, msg_id,
+                        (unsigned int)target_state->pwr_domain_state[
+                                       MPIDR_AFFLVL1]);
+#else
+       mv_pm_ipc_msg_tx(channel_id, msg_id, 0);
+#endif
+
+       return 0;
+}
+
+/*****************************************************************************
+ * mss_pm_ipc_msg_trigger
+ *
+ * DESCRIPTION: Trigger IPC message interrupt to MSS
+ *****************************************************************************
+ */
+int mss_pm_ipc_msg_trigger(void)
+{
+       unsigned int timeout;
+       unsigned int t_end;
+       unsigned int t_start = mmio_read_32(MSS_TIMER_BASE);
+
+       mmio_write_32(MSS_SISR, MSS_MSG_INT_MASK);
+
+       do {
+               /* wait while SCP process incoming interrupt */
+               if (mmio_read_32(MSS_SISTR) != MSS_MSG_INT_MASK)
+                       break;
+
+               /* check timeout */
+               t_end = mmio_read_32(MSS_TIMER_BASE);
+
+               timeout = ((t_start > t_end) ?
+                          (t_start - t_end) : (t_end - t_start));
+               if (timeout > MSS_TRIGGER_TIMEOUT) {
+                       ERROR("PM MSG Trigger Timeout\n");
+                       break;
+               }
+
+       } while (1);
+
+       return 0;
+}
diff --git a/plat/marvell/a8k/common/mss/mss_pm_ipc.h b/plat/marvell/a8k/common/mss/mss_pm_ipc.h
new file mode 100644 (file)
index 0000000..0f69457
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef __MSS_PM_IPC_H
+#define __MSS_PM_IPC_H
+
+#include <mss_ipc_drv.h>
+
+/* Currently MSS does not support Cluster level Power Down */
+#define DISABLE_CLUSTER_LEVEL
+
+
+/*****************************************************************************
+ * mss_pm_ipc_msg_send
+ *
+ * DESCRIPTION: create and transmit IPC message
+ *****************************************************************************
+ */
+int mss_pm_ipc_msg_send(unsigned int channel_id, unsigned int msg_id,
+                       const psci_power_state_t *target_state);
+
+/*****************************************************************************
+ * mss_pm_ipc_msg_trigger
+ *
+ * DESCRIPTION: Trigger IPC message interrupt to MSS
+ *****************************************************************************
+ */
+int mss_pm_ipc_msg_trigger(void);
+
+
+#endif /* __MSS_PM_IPC_H */
diff --git a/plat/marvell/a8k/common/plat_bl1_setup.c b/plat/marvell/a8k/common/plat_bl1_setup.c
new file mode 100644 (file)
index 0000000..5d85102
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <mmio.h>
+#include <plat_marvell.h>
+
+void marvell_bl1_setup_mpps(void)
+{
+       /* Enable UART MPPs.
+        ** In a normal system, this is done by Bootrom.
+        */
+       mmio_write_32(MVEBU_AP_MPP_REGS(1), 0x3000);
+       mmio_write_32(MVEBU_AP_MPP_REGS(2), 0x3000);
+}
diff --git a/plat/marvell/a8k/common/plat_bl31_setup.c b/plat/marvell/a8k/common/plat_bl31_setup.c
new file mode 100644 (file)
index 0000000..6c85fcc
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <a8k_common.h>
+#include <ap_setup.h>
+#include <cp110_setup.h>
+#include <debug.h>
+#include <marvell_plat_priv.h>
+#include <marvell_pm.h>
+#include <mmio.h>
+#include <mci.h>
+#include <plat_marvell.h>
+
+#include <mss_ipc_drv.h>
+#include <mss_mem.h>
+
+/* In Armada-8k family AP806/AP807, CP0 connected to PIDI
+ * and CP1 connected to IHB via MCI #0
+ */
+#define MVEBU_MCI0             0
+
+static _Bool pm_fw_running;
+
+/* Set a weak stub for platforms that don't need to configure GPIO */
+#pragma weak marvell_gpio_config
+int marvell_gpio_config(void)
+{
+       return 0;
+}
+
+static void marvell_bl31_mpp_init(int cp)
+{
+       uint32_t reg;
+
+       /* need to do for CP#0 only */
+       if (cp)
+               return;
+
+
+       /*
+        * Enable CP0 I2C MPPs (MPP: 37-38)
+        * U-Boot rely on proper MPP settings for I2C EEPROM usage
+        * (only for CP0)
+        */
+       reg = mmio_read_32(MVEBU_CP_MPP_REGS(0, 4));
+       mmio_write_32(MVEBU_CP_MPP_REGS(0, 4), reg | 0x2200000);
+}
+
+void marvell_bl31_mss_init(void)
+{
+       struct mss_pm_ctrl_block *mss_pm_crtl =
+                       (struct mss_pm_ctrl_block *)MSS_SRAM_PM_CONTROL_BASE;
+
+       /* Check that the image was loaded successfully */
+       if (mss_pm_crtl->handshake != HOST_ACKNOWLEDGMENT) {
+               NOTICE("MSS PM is not supported in this build\n");
+               return;
+       }
+
+       /* If we got here it means that the PM firmware is running */
+       pm_fw_running = 1;
+
+       INFO("MSS IPC init\n");
+
+       if (mss_pm_crtl->ipc_state == IPC_INITIALIZED)
+               mv_pm_ipc_init(mss_pm_crtl->ipc_base_address | MVEBU_REGS_BASE);
+}
+
+_Bool is_pm_fw_running(void)
+{
+       return pm_fw_running;
+}
+
+/* This function overruns the same function in marvell_bl31_setup.c */
+void bl31_plat_arch_setup(void)
+{
+       int cp;
+       uintptr_t *mailbox = (void *)PLAT_MARVELL_MAILBOX_BASE;
+
+       /* initialize the timer for mdelay/udelay functionality */
+       plat_delay_timer_init();
+
+       /* configure apn806 */
+       ap_init();
+
+       /* In marvell_bl31_plat_arch_setup, el3 mmu is configured.
+        * el3 mmu configuration MUST be called after apn806_init, if not,
+        * this will cause an hang in init_io_win
+        * (after setting the IO windows GCR values).
+        */
+       if (mailbox[MBOX_IDX_MAGIC] != MVEBU_MAILBOX_MAGIC_NUM ||
+           mailbox[MBOX_IDX_SUSPEND_MAGIC] != MVEBU_MAILBOX_SUSPEND_STATE)
+               marvell_bl31_plat_arch_setup();
+
+       for (cp = 0; cp < CP_COUNT; cp++) {
+       /* configure cp110 for CP0*/
+               if (cp == 1)
+                       mci_initialize(MVEBU_MCI0);
+
+       /* initialize MCI & CP1 */
+               cp110_init(MVEBU_CP_REGS_BASE(cp),
+                          STREAM_ID_BASE + (cp * MAX_STREAM_ID_PER_CP));
+
+       /* Should be called only after setting IOB windows */
+               marvell_bl31_mpp_init(cp);
+       }
+
+       /* initialize IPC between MSS and ATF */
+       if (mailbox[MBOX_IDX_MAGIC] != MVEBU_MAILBOX_MAGIC_NUM ||
+           mailbox[MBOX_IDX_SUSPEND_MAGIC] != MVEBU_MAILBOX_SUSPEND_STATE)
+               marvell_bl31_mss_init();
+
+       /* Configure GPIO */
+       marvell_gpio_config();
+}
diff --git a/plat/marvell/a8k/common/plat_ble_setup.c b/plat/marvell/a8k/common/plat_ble_setup.c
new file mode 100644 (file)
index 0000000..0cd62cb
--- /dev/null
@@ -0,0 +1,570 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <a8k_common.h>
+#include <ap_setup.h>
+#include <aro.h>
+#include <ccu.h>
+#include <cp110_setup.h>
+#include <debug.h>
+#include <io_win.h>
+#include <mv_ddr_if.h>
+#include <mvebu_def.h>
+#include <plat_marvell.h>
+
+/* Register for skip image use */
+#define SCRATCH_PAD_REG2               0xF06F00A8
+#define SCRATCH_PAD_SKIP_VAL           0x01
+#define NUM_OF_GPIO_PER_REG 32
+
+#define MMAP_SAVE_AND_CONFIG   0
+#define MMAP_RESTORE_SAVED     1
+
+/* SAR clock settings */
+#define MVEBU_AP_GEN_MGMT_BASE         (MVEBU_RFU_BASE + 0x8000)
+#define MVEBU_AP_SAR_REG_BASE(r)       (MVEBU_AP_GEN_MGMT_BASE + 0x200 +\
+                                                               ((r) << 2))
+
+#define SAR_CLOCK_FREQ_MODE_OFFSET     (0)
+#define SAR_CLOCK_FREQ_MODE_MASK       (0x1f << SAR_CLOCK_FREQ_MODE_OFFSET)
+#define SAR_PIDI_LOW_SPEED_OFFSET      (20)
+#define SAR_PIDI_LOW_SPEED_MASK                (1 << SAR_PIDI_LOW_SPEED_OFFSET)
+#define SAR_PIDI_LOW_SPEED_SHIFT       (15)
+#define SAR_PIDI_LOW_SPEED_SET         (1 << SAR_PIDI_LOW_SPEED_SHIFT)
+
+#define FREQ_MODE_AP_SAR_REG_NUM       (0)
+#define SAR_CLOCK_FREQ_MODE(v)         (((v) & SAR_CLOCK_FREQ_MODE_MASK) >> \
+                                       SAR_CLOCK_FREQ_MODE_OFFSET)
+
+#define AVS_EN_CTRL_REG                        (MVEBU_AP_GEN_MGMT_BASE + 0x130)
+#define AVS_ENABLE_OFFSET              (0)
+#define AVS_SOFT_RESET_OFFSET          (2)
+#define AVS_LOW_VDD_LIMIT_OFFSET       (4)
+#define AVS_HIGH_VDD_LIMIT_OFFSET      (12)
+#define AVS_TARGET_DELTA_OFFSET                (21)
+#define AVS_VDD_LOW_LIMIT_MASK         (0xFF << AVS_LOW_VDD_LIMIT_OFFSET)
+#define AVS_VDD_HIGH_LIMIT_MASK                (0xFF << AVS_HIGH_VDD_LIMIT_OFFSET)
+/* VDD limit is 0.9V for A70x0 @ CPU frequency < 1600MHz */
+#define AVS_A7K_LOW_CLK_VALUE          ((0x80 << AVS_TARGET_DELTA_OFFSET) | \
+                                        (0x1A << AVS_HIGH_VDD_LIMIT_OFFSET) | \
+                                        (0x1A << AVS_LOW_VDD_LIMIT_OFFSET) | \
+                                        (0x1 << AVS_SOFT_RESET_OFFSET) | \
+                                        (0x1 << AVS_ENABLE_OFFSET))
+/* VDD limit is 1.0V for all A80x0 devices */
+#define AVS_A8K_CLK_VALUE              ((0x80 << AVS_TARGET_DELTA_OFFSET) | \
+                                        (0x24 << AVS_HIGH_VDD_LIMIT_OFFSET) | \
+                                        (0x24 << AVS_LOW_VDD_LIMIT_OFFSET) | \
+                                        (0x1 << AVS_SOFT_RESET_OFFSET) | \
+                                        (0x1 << AVS_ENABLE_OFFSET))
+
+#define AVS_A3900_CLK_VALUE            ((0x80 << 24) | \
+                                        (0x2c2 << 13) | \
+                                        (0x2c2 << 3) | \
+                                        (0x1 << AVS_SOFT_RESET_OFFSET) | \
+                                        (0x1 << AVS_ENABLE_OFFSET))
+
+#define MVEBU_AP_EFUSE_SRV_CTRL_REG    (MVEBU_AP_GEN_MGMT_BASE + 0x8)
+#define EFUSE_SRV_CTRL_LD_SELECT_OFFS  6
+#define EFUSE_SRV_CTRL_LD_SEL_USER_MASK        (1 << EFUSE_SRV_CTRL_LD_SELECT_OFFS)
+
+/* Notify bootloader on DRAM setup */
+#define AP807_CPU_ARO_0_CTRL_0         (MVEBU_RFU_BASE + 0x82A8)
+#define AP807_CPU_ARO_1_CTRL_0         (MVEBU_RFU_BASE + 0x8D00)
+
+/* 0 - ARO clock is enabled, 1 - ARO clock is disabled */
+#define AP807_CPU_ARO_CLK_EN_OFFSET    0
+#define AP807_CPU_ARO_CLK_EN_MASK      (0x1 << AP807_CPU_ARO_CLK_EN_OFFSET)
+
+/* 0 - ARO is the clock source, 1 - PLL is the clock source */
+#define AP807_CPU_ARO_SEL_PLL_OFFSET   5
+#define AP807_CPU_ARO_SEL_PLL_MASK     (0x1 << AP807_CPU_ARO_SEL_PLL_OFFSET)
+
+/*
+ * - AVS work points in the LD0 eFuse:
+ *     SVC1 work point:     LD0[88:81]
+ *     SVC2 work point:     LD0[96:89]
+ *     SVC3 work point:     LD0[104:97]
+ *     SVC4 work point:     LD0[112:105]
+ * - Identification information in the LD-0 eFuse:
+ *     DRO:           LD0[74:65] - Not used by the SW
+ *     Revision:      LD0[78:75] - Not used by the SW
+ *     Bin:           LD0[80:79] - Not used by the SW
+ *     SW Revision:   LD0[115:113]
+ *     Cluster 1 PWR: LD0[193] - if set to 1, power down CPU Cluster-1
+ *                               resulting in 2 CPUs active only (7020)
+ */
+#define MVEBU_AP_LD_EFUSE_BASE         (MVEBU_AP_GEN_MGMT_BASE + 0xF00)
+/* Bits [94:63] - 32 data bits total */
+#define MVEBU_AP_LD0_94_63_EFUSE_OFFS  (MVEBU_AP_LD_EFUSE_BASE + 0x8)
+/* Bits [125:95] - 31 data bits total, 32nd bit is parity for bits [125:63] */
+#define MVEBU_AP_LD0_125_95_EFUSE_OFFS (MVEBU_AP_LD_EFUSE_BASE + 0xC)
+/* Bits [220:189] - 32 data bits total */
+#define MVEBU_AP_LD0_220_189_EFUSE_OFFS        (MVEBU_AP_LD_EFUSE_BASE + 0x18)
+/* Offsets for the above 2 fields combined into single 64-bit value [125:63] */
+#define EFUSE_AP_LD0_DRO_OFFS          2               /* LD0[74:65] */
+#define EFUSE_AP_LD0_DRO_MASK          0x3FF
+#define EFUSE_AP_LD0_REVID_OFFS                12              /* LD0[78:75] */
+#define EFUSE_AP_LD0_REVID_MASK                0xF
+#define EFUSE_AP_LD0_BIN_OFFS          16              /* LD0[80:79] */
+#define EFUSE_AP_LD0_BIN_MASK          0x3
+#define EFUSE_AP_LD0_SWREV_OFFS                50              /* LD0[115:113] */
+#define EFUSE_AP_LD0_SWREV_MASK                0x7
+
+#define EFUSE_AP_LD0_SVC1_OFFS         18              /* LD0[88:81] */
+#define EFUSE_AP_LD0_SVC2_OFFS         26              /* LD0[96:89] */
+#define EFUSE_AP_LD0_SVC3_OFFS         34              /* LD0[104:97] */
+#define EFUSE_AP_LD0_SVC4_OFFS         42              /* LD0[112:105] */
+#define EFUSE_AP_LD0_WP_MASK           0xFF
+
+#define EFUSE_AP_LD0_CLUSTER_DOWN_OFFS 4
+
+/* Return the AP revision of the chip */
+static unsigned int ble_get_ap_type(void)
+{
+       unsigned int chip_rev_id;
+
+       chip_rev_id = mmio_read_32(MVEBU_CSS_GWD_CTRL_IIDR2_REG);
+       chip_rev_id = ((chip_rev_id & GWD_IIDR2_CHIP_ID_MASK) >>
+                       GWD_IIDR2_CHIP_ID_OFFSET);
+
+       return chip_rev_id;
+}
+
+/******************************************************************************
+ * The routine allows to save the CCU and IO windows configuration during DRAM
+ * setup and restore them afterwards before exiting the BLE stage.
+ * Such window configuration is required since not all default settings coming
+ * from the HW and the BootROM allow access to peripherals connected to
+ * all available CPn components.
+ * For instance, when the boot device is located on CP0, the IO window to CP1
+ * is not opened automatically by the HW and if the DRAM SPD is located on CP1
+ * i2c channel, it cannot be read at BLE stage.
+ * Therefore the DRAM init procedure have to provide access to all available
+ * CPn peripherals during the BLE stage by setting the CCU IO window to all
+ * CPnph addresses and by enabling the IO windows accordingly.
+ * Additionally this function configures the CCU GCR to DRAM, which allows
+ * usage or more than 4GB DRAM as it configured by the default CCU DRAM window.
+ *
+ * IN:
+ *     MMAP_SAVE_AND_CONFIG    - save the existing configuration and update it
+ *     MMAP_RESTORE_SAVED      - restore saved configuration
+ * OUT:
+ *     NONE
+ ****************************************************************************
+ */
+static void ble_plat_mmap_config(int restore)
+{
+       if (restore == MMAP_RESTORE_SAVED) {
+               /* Restore all orig. settings that were modified by BLE stage */
+               ccu_restore_win_all(MVEBU_AP0);
+               /* Restore CCU */
+               iow_restore_win_all(MVEBU_AP0);
+               return;
+       }
+
+       /* Store original values */
+       ccu_save_win_all(MVEBU_AP0);
+       /* Save CCU */
+       iow_save_win_all(MVEBU_AP0);
+
+       init_ccu(MVEBU_AP0);
+       /* The configuration saved, now all the changes can be done */
+       init_io_win(MVEBU_AP0);
+}
+
+/****************************************************************************
+ * Setup Adaptive Voltage Switching - this is required for some platforms
+ ****************************************************************************
+ */
+static void ble_plat_avs_config(void)
+{
+       uint32_t reg_val, device_id;
+
+       /* Check which SoC is running and act accordingly */
+       if (ble_get_ap_type() == CHIP_ID_AP807) {
+               VERBOSE("AVS: Setting AP807 AVS CTRL to 0x%x\n",
+                       AVS_A3900_CLK_VALUE);
+               mmio_write_32(AVS_EN_CTRL_REG, AVS_A3900_CLK_VALUE);
+               return;
+       }
+
+       /* Check which SoC is running and act accordingly */
+       device_id = cp110_device_id_get(MVEBU_CP_REGS_BASE(0));
+       switch (device_id) {
+       case MVEBU_80X0_DEV_ID:
+       case MVEBU_80X0_CP115_DEV_ID:
+               /* Set the new AVS value - fix the default one on A80x0 */
+               mmio_write_32(AVS_EN_CTRL_REG, AVS_A8K_CLK_VALUE);
+               break;
+       case MVEBU_70X0_DEV_ID:
+       case MVEBU_70X0_CP115_DEV_ID:
+               /* Only fix AVS for CPU clocks lower than 1600MHz on A70x0 */
+               reg_val = mmio_read_32(MVEBU_AP_SAR_REG_BASE(
+                                               FREQ_MODE_AP_SAR_REG_NUM));
+               reg_val &= SAR_CLOCK_FREQ_MODE_MASK;
+               reg_val >>= SAR_CLOCK_FREQ_MODE_OFFSET;
+               if ((reg_val > CPU_1600_DDR_900_RCLK_900_2) &&
+                   (reg_val < CPU_DDR_RCLK_INVALID))
+                       mmio_write_32(AVS_EN_CTRL_REG, AVS_A7K_LOW_CLK_VALUE);
+               break;
+       default:
+               ERROR("Unsupported Device ID 0x%x\n", device_id);
+       }
+}
+
+/****************************************************************************
+ * SVC flow - v0.10
+ * The feature is intended to configure AVS value according to eFuse values
+ * that are burned individually for each SoC during the test process.
+ * Primary AVS value is stored in HD efuse and processed on power on
+ * by the HW engine
+ * Secondary AVS value is located in LD efuse and contains 4 work points for
+ * various CPU frequencies.
+ * The Secondary AVS value is only taken into account if the SW Revision stored
+ * in the efuse is greater than 0 and the CPU is running in a certain speed.
+ ****************************************************************************
+ */
+static void ble_plat_svc_config(void)
+{
+       uint32_t reg_val, avs_workpoint, freq_pidi_mode;
+       uint64_t efuse;
+       uint32_t device_id, single_cluster;
+       uint8_t  svc[4], perr[4], i, sw_ver;
+
+       /* Due to a bug in A3900 device_id skip SVC config
+        * TODO: add SVC config once it is decided for a3900
+        */
+       if (ble_get_ap_type() == CHIP_ID_AP807) {
+               NOTICE("SVC: SVC is not supported on AP807\n");
+               ble_plat_avs_config();
+               return;
+       }
+
+       /* Set access to LD0 */
+       reg_val = mmio_read_32(MVEBU_AP_EFUSE_SRV_CTRL_REG);
+       reg_val &= ~EFUSE_SRV_CTRL_LD_SELECT_OFFS;
+       mmio_write_32(MVEBU_AP_EFUSE_SRV_CTRL_REG, reg_val);
+
+       /* Obtain the value of LD0[125:63] */
+       efuse = mmio_read_32(MVEBU_AP_LD0_125_95_EFUSE_OFFS);
+       efuse <<= 32;
+       efuse |= mmio_read_32(MVEBU_AP_LD0_94_63_EFUSE_OFFS);
+
+       /* SW Revision:
+        * Starting from SW revision 1 the SVC flow is supported.
+        * SW version 0 (efuse not programmed) should follow the
+        * regular AVS update flow.
+        */
+       sw_ver = (efuse >> EFUSE_AP_LD0_SWREV_OFFS) & EFUSE_AP_LD0_SWREV_MASK;
+       if (sw_ver < 1) {
+               NOTICE("SVC: SW Revision 0x%x. SVC is not supported\n", sw_ver);
+               ble_plat_avs_config();
+               return;
+       }
+
+       /* Frequency mode from SAR */
+       freq_pidi_mode = SAR_CLOCK_FREQ_MODE(
+                               mmio_read_32(
+                                       MVEBU_AP_SAR_REG_BASE(
+                                               FREQ_MODE_AP_SAR_REG_NUM)));
+
+       /* Decode all SVC work points */
+       svc[0] = (efuse >> EFUSE_AP_LD0_SVC1_OFFS) & EFUSE_AP_LD0_WP_MASK;
+       svc[1] = (efuse >> EFUSE_AP_LD0_SVC2_OFFS) & EFUSE_AP_LD0_WP_MASK;
+       svc[2] = (efuse >> EFUSE_AP_LD0_SVC3_OFFS) & EFUSE_AP_LD0_WP_MASK;
+       svc[3] = (efuse >> EFUSE_AP_LD0_SVC4_OFFS) & EFUSE_AP_LD0_WP_MASK;
+       INFO("SVC: Efuse WP: [0]=0x%x, [1]=0x%x, [2]=0x%x, [3]=0x%x\n",
+               svc[0], svc[1], svc[2], svc[3]);
+
+       /* Validate parity of SVC workpoint values */
+       for (i = 0; i < 4; i++) {
+               uint8_t parity, bit;
+
+               perr[i] = 0;
+
+               for (bit = 1, parity = svc[i] & 1; bit < 7; bit++)
+                       parity ^= (svc[i] >> bit) & 1;
+
+               /* Starting from SW version 2, the parity check is mandatory */
+               if ((sw_ver > 1) && (parity != ((svc[i] >> 7) & 1)))
+                       perr[i] = 1; /* register the error */
+       }
+
+       single_cluster = mmio_read_32(MVEBU_AP_LD0_220_189_EFUSE_OFFS);
+       single_cluster = (single_cluster >> EFUSE_AP_LD0_CLUSTER_DOWN_OFFS) & 1;
+
+       device_id = cp110_device_id_get(MVEBU_CP_REGS_BASE(0));
+       if (device_id == MVEBU_80X0_DEV_ID ||
+           device_id == MVEBU_80X0_CP115_DEV_ID) {
+               /* A8040/A8020 */
+               NOTICE("SVC: DEV ID: %s, FREQ Mode: 0x%x\n",
+                       single_cluster == 0 ? "8040" : "8020", freq_pidi_mode);
+               switch (freq_pidi_mode) {
+               case CPU_1800_DDR_1200_RCLK_1200:
+               case CPU_1800_DDR_1050_RCLK_1050:
+                       if (perr[1])
+                               goto perror;
+                       avs_workpoint = svc[1];
+                       break;
+               case CPU_1600_DDR_1050_RCLK_1050:
+               case CPU_1600_DDR_900_RCLK_900_2:
+                       if (perr[2])
+                               goto perror;
+                       avs_workpoint = svc[2];
+                       break;
+               case CPU_1300_DDR_800_RCLK_800:
+               case CPU_1300_DDR_650_RCLK_650:
+                       if (perr[3])
+                               goto perror;
+                       avs_workpoint = svc[3];
+                       break;
+               case CPU_2000_DDR_1200_RCLK_1200:
+               case CPU_2000_DDR_1050_RCLK_1050:
+               default:
+                       if (perr[0])
+                               goto perror;
+                       avs_workpoint = svc[0];
+                       break;
+               }
+       } else if (device_id == MVEBU_70X0_DEV_ID ||
+                  device_id == MVEBU_70X0_CP115_DEV_ID) {
+               /* A7040/A7020/A6040 */
+               NOTICE("SVC: DEV ID: %s, FREQ Mode: 0x%x\n",
+                       single_cluster == 0 ? "7040" : "7020", freq_pidi_mode);
+               switch (freq_pidi_mode) {
+               case CPU_1400_DDR_800_RCLK_800:
+                       if (single_cluster) {/* 7020 */
+                               if (perr[1])
+                                       goto perror;
+                               avs_workpoint = svc[1];
+                       } else {
+                               if (perr[0])
+                                       goto perror;
+                               avs_workpoint = svc[0];
+                       }
+                       break;
+               case CPU_1200_DDR_800_RCLK_800:
+                       if (single_cluster) {/* 7020 */
+                               if (perr[2])
+                                       goto perror;
+                               avs_workpoint = svc[2];
+                       } else {
+                               if (perr[1])
+                                       goto perror;
+                               avs_workpoint = svc[1];
+                       }
+                       break;
+               case CPU_800_DDR_800_RCLK_800:
+               case CPU_1000_DDR_800_RCLK_800:
+                       if (single_cluster) {/* 7020 */
+                               if (perr[3])
+                                       goto perror;
+                               avs_workpoint = svc[3];
+                       } else {
+                               if (perr[2])
+                                       goto perror;
+                               avs_workpoint = svc[2];
+                       }
+                       break;
+               case CPU_600_DDR_800_RCLK_800:
+                       if (perr[3])
+                               goto perror;
+                       avs_workpoint = svc[3]; /* Same for 6040 and 7020 */
+                       break;
+               case CPU_1600_DDR_800_RCLK_800: /* 7020 only */
+               default:
+                       if (single_cluster) {/* 7020 */
+                               if (perr[0])
+                                       goto perror;
+                               avs_workpoint = svc[0];
+                       } else
+                               avs_workpoint = 0;
+                       break;
+               }
+       } else {
+               ERROR("SVC: Unsupported Device ID 0x%x\n", device_id);
+               return;
+       }
+
+       /* Set AVS control if needed */
+       if (avs_workpoint == 0) {
+               ERROR("SVC: AVS work point not changed\n");
+               return;
+       }
+
+       /* Remove parity bit */
+       avs_workpoint &= 0x7F;
+
+       reg_val  = mmio_read_32(AVS_EN_CTRL_REG);
+       NOTICE("SVC: AVS work point changed from 0x%x to 0x%x\n",
+               (reg_val & AVS_VDD_LOW_LIMIT_MASK) >> AVS_LOW_VDD_LIMIT_OFFSET,
+               avs_workpoint);
+       reg_val &= ~(AVS_VDD_LOW_LIMIT_MASK | AVS_VDD_HIGH_LIMIT_MASK);
+       reg_val |= 0x1 << AVS_ENABLE_OFFSET;
+       reg_val |= avs_workpoint << AVS_HIGH_VDD_LIMIT_OFFSET;
+       reg_val |= avs_workpoint << AVS_LOW_VDD_LIMIT_OFFSET;
+       mmio_write_32(AVS_EN_CTRL_REG, reg_val);
+       return;
+
+perror:
+       ERROR("Failed SVC WP[%d] parity check!\n", i);
+       ERROR("Ignoring the WP values\n");
+}
+
+#if PLAT_RECOVERY_IMAGE_ENABLE
+static int ble_skip_image_i2c(struct skip_image *skip_im)
+{
+       ERROR("skipping image using i2c is not supported\n");
+       /* not supported */
+       return 0;
+}
+
+static int ble_skip_image_other(struct skip_image *skip_im)
+{
+       ERROR("implementation missing for skip image request\n");
+       /* not supported, make your own implementation */
+       return 0;
+}
+
+static int ble_skip_image_gpio(struct skip_image *skip_im)
+{
+       unsigned int val;
+       unsigned int mpp_address = 0;
+       unsigned int offset = 0;
+
+       switch (skip_im->info.test.cp_ap) {
+       case(CP):
+               mpp_address = MVEBU_CP_GPIO_DATA_IN(skip_im->info.test.cp_index,
+                                                   skip_im->info.gpio.num);
+               if (skip_im->info.gpio.num > NUM_OF_GPIO_PER_REG)
+                       offset = skip_im->info.gpio.num - NUM_OF_GPIO_PER_REG;
+               else
+                       offset = skip_im->info.gpio.num;
+               break;
+       case(AP):
+               mpp_address = MVEBU_AP_GPIO_DATA_IN;
+               offset = skip_im->info.gpio.num;
+               break;
+       }
+
+       val = mmio_read_32(mpp_address);
+       val &= (1 << offset);
+       if ((!val && skip_im->info.gpio.button_state == HIGH) ||
+           (val && skip_im->info.gpio.button_state == LOW)) {
+               mmio_write_32(SCRATCH_PAD_REG2, SCRATCH_PAD_SKIP_VAL);
+               return 1;
+       }
+
+       return 0;
+}
+
+/*
+ * This function checks if there's a skip image request:
+ * return values:
+ * 1: (true) images request been made.
+ * 0: (false) no image request been made.
+ */
+static int  ble_skip_current_image(void)
+{
+       struct skip_image *skip_im;
+
+       /*fetching skip image info*/
+       skip_im = (struct skip_image *)plat_marvell_get_skip_image_data();
+
+       if (skip_im == NULL)
+               return 0;
+
+       /* check if skipping image request has already been made */
+       if (mmio_read_32(SCRATCH_PAD_REG2) == SCRATCH_PAD_SKIP_VAL)
+               return 0;
+
+       switch (skip_im->detection_method) {
+       case GPIO:
+               return ble_skip_image_gpio(skip_im);
+       case I2C:
+               return ble_skip_image_i2c(skip_im);
+       case USER_DEFINED:
+               return ble_skip_image_other(skip_im);
+       }
+
+       return 0;
+}
+#endif
+
+/* Switch to ARO from PLL in ap807 */
+static void aro_to_pll(void)
+{
+       unsigned int reg;
+
+       /* switch from ARO to PLL */
+       reg = mmio_read_32(AP807_CPU_ARO_0_CTRL_0);
+       reg |= AP807_CPU_ARO_SEL_PLL_MASK;
+       mmio_write_32(AP807_CPU_ARO_0_CTRL_0, reg);
+
+       reg = mmio_read_32(AP807_CPU_ARO_1_CTRL_0);
+       reg |= AP807_CPU_ARO_SEL_PLL_MASK;
+       mmio_write_32(AP807_CPU_ARO_1_CTRL_0, reg);
+
+       mdelay(1000);
+
+       /* disable ARO clk driver */
+       reg = mmio_read_32(AP807_CPU_ARO_0_CTRL_0);
+       reg |= (AP807_CPU_ARO_CLK_EN_MASK);
+       mmio_write_32(AP807_CPU_ARO_0_CTRL_0, reg);
+
+       reg = mmio_read_32(AP807_CPU_ARO_1_CTRL_0);
+       reg |= (AP807_CPU_ARO_CLK_EN_MASK);
+       mmio_write_32(AP807_CPU_ARO_1_CTRL_0, reg);
+}
+
+int ble_plat_setup(int *skip)
+{
+       int ret;
+
+       /* Power down unused CPUs */
+       plat_marvell_early_cpu_powerdown();
+
+       /*
+        * Save the current CCU configuration and make required changes:
+        * - Allow access to DRAM larger than 4GB
+        * - Open memory access to all CPn peripherals
+        */
+       ble_plat_mmap_config(MMAP_SAVE_AND_CONFIG);
+
+#if PLAT_RECOVERY_IMAGE_ENABLE
+       /* Check if there's a skip request to bootRom recovery Image */
+       if (ble_skip_current_image()) {
+               /* close memory access to all CPn peripherals. */
+               ble_plat_mmap_config(MMAP_RESTORE_SAVED);
+               *skip = 1;
+               return 0;
+       }
+#endif
+       /* Do required CP-110 setups for BLE stage */
+       cp110_ble_init(MVEBU_CP_REGS_BASE(0));
+
+       /* Setup AVS */
+       ble_plat_svc_config();
+
+       /* work with PLL clock driver in AP807 */
+       if (ble_get_ap_type() == CHIP_ID_AP807)
+               aro_to_pll();
+
+       /* Do required AP setups for BLE stage */
+       ap_ble_init();
+
+       /* Update DRAM topology (scan DIMM SPDs) */
+       plat_marvell_dram_update_topology();
+
+       /* Kick it in */
+       ret = dram_init();
+
+       /* Restore the original CCU configuration before exit from BLE */
+       ble_plat_mmap_config(MMAP_RESTORE_SAVED);
+
+       return ret;
+}
diff --git a/plat/marvell/a8k/common/plat_pm.c b/plat/marvell/a8k/common/plat_pm.c
new file mode 100644 (file)
index 0000000..c716ee0
--- /dev/null
@@ -0,0 +1,829 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <a8k_common.h>
+#include <assert.h>
+#include <bakery_lock.h>
+#include <debug.h>
+#include <delay_timer.h>
+#include <cache_llc.h>
+#include <console.h>
+#include <gicv2.h>
+#include <marvell_pm.h>
+#include <mmio.h>
+#include <mss_pm_ipc.h>
+#include <plat_marvell.h>
+#include <platform.h>
+#include <plat_pm_trace.h>
+#include <platform.h>
+
+#define MVEBU_PRIVATE_UID_REG          0x30
+#define MVEBU_RFU_GLOBL_SW_RST         0x84
+#define MVEBU_CCU_RVBAR(cpu)           (MVEBU_REGS_BASE + 0x640 + (cpu * 4))
+#define MVEBU_CCU_CPU_UN_RESET(cpu)    (MVEBU_REGS_BASE + 0x650 + (cpu * 4))
+
+#define MPIDR_CPU_GET(mpidr)           ((mpidr) & MPIDR_CPU_MASK)
+#define MPIDR_CLUSTER_GET(mpidr)       MPIDR_AFFLVL1_VAL((mpidr))
+
+#define MVEBU_GPIO_MASK(index)         (1 << (index % 32))
+#define MVEBU_MPP_MASK(index)          (0xF << (4 * (index % 8)))
+#define MVEBU_GPIO_VALUE(index, value) (value << (index % 32))
+
+#define MVEBU_USER_CMD_0_REG           (MVEBU_DRAM_MAC_BASE + 0x20)
+#define MVEBU_USER_CMD_CH0_OFFSET      28
+#define MVEBU_USER_CMD_CH0_MASK                (1 << MVEBU_USER_CMD_CH0_OFFSET)
+#define MVEBU_USER_CMD_CH0_EN          (1 << MVEBU_USER_CMD_CH0_OFFSET)
+#define MVEBU_USER_CMD_CS_OFFSET       24
+#define MVEBU_USER_CMD_CS_MASK         (0xF << MVEBU_USER_CMD_CS_OFFSET)
+#define MVEBU_USER_CMD_CS_ALL          (0xF << MVEBU_USER_CMD_CS_OFFSET)
+#define MVEBU_USER_CMD_SR_OFFSET       6
+#define MVEBU_USER_CMD_SR_MASK         (0x3 << MVEBU_USER_CMD_SR_OFFSET)
+#define MVEBU_USER_CMD_SR_ENTER                (0x1 << MVEBU_USER_CMD_SR_OFFSET)
+#define MVEBU_MC_PWR_CTRL_REG          (MVEBU_DRAM_MAC_BASE + 0x54)
+#define MVEBU_MC_AC_ON_DLY_OFFSET      8
+#define MVEBU_MC_AC_ON_DLY_MASK                (0xF << MVEBU_MC_AC_ON_DLY_OFFSET)
+#define MVEBU_MC_AC_ON_DLY_DEF_VAR     (8 << MVEBU_MC_AC_ON_DLY_OFFSET)
+#define MVEBU_MC_AC_OFF_DLY_OFFSET     4
+#define MVEBU_MC_AC_OFF_DLY_MASK       (0xF << MVEBU_MC_AC_OFF_DLY_OFFSET)
+#define MVEBU_MC_AC_OFF_DLY_DEF_VAR    (0xC << MVEBU_MC_AC_OFF_DLY_OFFSET)
+#define MVEBU_MC_PHY_AUTO_OFF_OFFSET   0
+#define MVEBU_MC_PHY_AUTO_OFF_MASK     (1 << MVEBU_MC_PHY_AUTO_OFF_OFFSET)
+#define MVEBU_MC_PHY_AUTO_OFF_EN       (1 << MVEBU_MC_PHY_AUTO_OFF_OFFSET)
+
+/* this lock synchronize AP multiple cores execution with MSS */
+DEFINE_BAKERY_LOCK(pm_sys_lock);
+
+/* Weak definitions may be overridden in specific board */
+#pragma weak plat_marvell_get_pm_cfg
+
+/* AP806 CPU power down /power up definitions */
+enum CPU_ID {
+       CPU0,
+       CPU1,
+       CPU2,
+       CPU3
+};
+
+#define REG_WR_VALIDATE_TIMEOUT                (2000)
+
+#define FEATURE_DISABLE_STATUS_REG                     \
+                       (MVEBU_REGS_BASE + 0x6F8230)
+#define FEATURE_DISABLE_STATUS_CPU_CLUSTER_OFFSET      4
+#define FEATURE_DISABLE_STATUS_CPU_CLUSTER_MASK                \
+                       (0x1 << FEATURE_DISABLE_STATUS_CPU_CLUSTER_OFFSET)
+
+#ifdef MVEBU_SOC_AP807
+       #define PWRC_CPUN_CR_PWR_DN_RQ_OFFSET           1
+       #define PWRC_CPUN_CR_LDO_BYPASS_RDY_OFFSET      0
+#else
+#define PWRC_CPUN_CR_PWR_DN_RQ_OFFSET          0
+       #define PWRC_CPUN_CR_LDO_BYPASS_RDY_OFFSET      31
+#endif
+
+#define PWRC_CPUN_CR_REG(cpu_id)               \
+                       (MVEBU_REGS_BASE + 0x680000 + (cpu_id * 0x10))
+#define PWRC_CPUN_CR_PWR_DN_RQ_MASK            \
+                       (0x1 << PWRC_CPUN_CR_PWR_DN_RQ_OFFSET)
+#define PWRC_CPUN_CR_ISO_ENABLE_OFFSET         16
+#define PWRC_CPUN_CR_ISO_ENABLE_MASK           \
+                       (0x1 << PWRC_CPUN_CR_ISO_ENABLE_OFFSET)
+#define PWRC_CPUN_CR_LDO_BYPASS_RDY_MASK       \
+                       (0x1 << PWRC_CPUN_CR_LDO_BYPASS_RDY_OFFSET)
+
+#define CCU_B_PRCRN_REG(cpu_id)                        \
+                       (MVEBU_REGS_BASE + 0x1A50 + \
+                       ((cpu_id / 2) * (0x400)) + ((cpu_id % 2) * 4))
+#define CCU_B_PRCRN_CPUPORESET_STATIC_OFFSET   0
+#define CCU_B_PRCRN_CPUPORESET_STATIC_MASK     \
+                       (0x1 << CCU_B_PRCRN_CPUPORESET_STATIC_OFFSET)
+
+/* power switch fingers */
+#define AP807_PWRC_LDO_CR0_REG                 \
+                       (MVEBU_REGS_BASE + 0x680000 + 0x100)
+#define AP807_PWRC_LDO_CR0_OFFSET              16
+#define AP807_PWRC_LDO_CR0_MASK                        \
+                       (0xff << AP807_PWRC_LDO_CR0_OFFSET)
+#define AP807_PWRC_LDO_CR0_VAL                 0xfd
+
+/*
+ * Power down CPU:
+ * Used to reduce power consumption, and avoid SoC unnecessary temperature rise.
+ */
+static int plat_marvell_cpu_powerdown(int cpu_id)
+{
+       uint32_t        reg_val;
+       int             exit_loop = REG_WR_VALIDATE_TIMEOUT;
+
+       INFO("Powering down CPU%d\n", cpu_id);
+
+       /* 1. Isolation enable */
+       reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id));
+       reg_val |= 0x1 << PWRC_CPUN_CR_ISO_ENABLE_OFFSET;
+       mmio_write_32(PWRC_CPUN_CR_REG(cpu_id), reg_val);
+
+       /* 2. Read and check Isolation enabled - verify bit set to 1 */
+       do {
+               reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id));
+               exit_loop--;
+       } while (!(reg_val & (0x1 << PWRC_CPUN_CR_ISO_ENABLE_OFFSET)) &&
+                exit_loop > 0);
+
+       /* 3. Switch off CPU power */
+       reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id));
+       reg_val &= ~PWRC_CPUN_CR_PWR_DN_RQ_MASK;
+       mmio_write_32(PWRC_CPUN_CR_REG(cpu_id), reg_val);
+
+       /* 4. Read and check Switch Off - verify bit set to 0 */
+       exit_loop = REG_WR_VALIDATE_TIMEOUT;
+       do {
+               reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id));
+               exit_loop--;
+       } while (reg_val & PWRC_CPUN_CR_PWR_DN_RQ_MASK && exit_loop > 0);
+
+       if (exit_loop <= 0)
+               goto cpu_poweroff_error;
+
+       /* 5. De-Assert power ready */
+       reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id));
+       reg_val &= ~PWRC_CPUN_CR_LDO_BYPASS_RDY_MASK;
+       mmio_write_32(PWRC_CPUN_CR_REG(cpu_id), reg_val);
+
+       /* 6. Assert CPU POR reset */
+       reg_val = mmio_read_32(CCU_B_PRCRN_REG(cpu_id));
+       reg_val &= ~CCU_B_PRCRN_CPUPORESET_STATIC_MASK;
+       mmio_write_32(CCU_B_PRCRN_REG(cpu_id), reg_val);
+
+       /* 7. Read and poll on Validate the CPU is out of reset */
+       exit_loop = REG_WR_VALIDATE_TIMEOUT;
+       do {
+               reg_val = mmio_read_32(CCU_B_PRCRN_REG(cpu_id));
+               exit_loop--;
+       } while (reg_val & CCU_B_PRCRN_CPUPORESET_STATIC_MASK && exit_loop > 0);
+
+       if (exit_loop <= 0)
+               goto cpu_poweroff_error;
+
+       INFO("Successfully powered down CPU%d\n", cpu_id);
+
+       return 0;
+
+cpu_poweroff_error:
+       ERROR("ERROR: Can't power down CPU%d\n", cpu_id);
+       return -1;
+}
+
+/*
+ * Power down CPUs 1-3 at early boot stage,
+ * to reduce power consumption and SoC temperature.
+ * This is triggered by BLE prior to DDR initialization.
+ *
+ * Note:
+ * All CPUs will be powered up by plat_marvell_cpu_powerup on Linux boot stage,
+ * which is triggered by PSCI ops (pwr_domain_on).
+ */
+int plat_marvell_early_cpu_powerdown(void)
+{
+       uint32_t cpu_cluster_status =
+               mmio_read_32(FEATURE_DISABLE_STATUS_REG) &
+                            FEATURE_DISABLE_STATUS_CPU_CLUSTER_MASK;
+       /* if cpu_cluster_status bit is set,
+        * that means we have only single cluster
+        */
+       int cluster_count = cpu_cluster_status ? 1 : 2;
+
+       INFO("Powering off unused CPUs\n");
+
+       /* CPU1 is in AP806 cluster-0, which always exists, so power it down */
+       if (plat_marvell_cpu_powerdown(CPU1) == -1)
+               return -1;
+
+       /*
+        * CPU2-3 are in AP806 2nd cluster (cluster-1),
+        * which doesn't exists in dual-core systems.
+        * so need to check if we have dual-core (single cluster)
+        * or quad-code (2 clusters)
+        */
+       if (cluster_count == 2) {
+               /* CPU2-3 are part of 2nd cluster */
+               if (plat_marvell_cpu_powerdown(CPU2) == -1)
+                       return -1;
+               if (plat_marvell_cpu_powerdown(CPU3) == -1)
+                       return -1;
+       }
+
+       return 0;
+}
+
+/*
+ * Power up CPU - part of Linux boot stage
+ */
+static int plat_marvell_cpu_powerup(u_register_t mpidr)
+{
+       uint32_t        reg_val;
+       int     cpu_id = MPIDR_CPU_GET(mpidr),
+               cluster = MPIDR_CLUSTER_GET(mpidr);
+       int     exit_loop = REG_WR_VALIDATE_TIMEOUT;
+
+       /* calculate absolute CPU ID */
+       cpu_id = cluster * PLAT_MARVELL_CLUSTER_CORE_COUNT + cpu_id;
+
+       INFO("Powering on CPU%d\n", cpu_id);
+
+#ifdef MVEBU_SOC_AP807
+       /* Activate 2 power switch fingers */
+       reg_val = mmio_read_32(AP807_PWRC_LDO_CR0_REG);
+       reg_val &= ~(AP807_PWRC_LDO_CR0_MASK);
+       reg_val |= (AP807_PWRC_LDO_CR0_VAL << AP807_PWRC_LDO_CR0_OFFSET);
+       mmio_write_32(AP807_PWRC_LDO_CR0_REG, reg_val);
+       udelay(100);
+#endif
+
+       /* 1. Switch CPU power ON */
+       reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id));
+       reg_val |= 0x1 << PWRC_CPUN_CR_PWR_DN_RQ_OFFSET;
+       mmio_write_32(PWRC_CPUN_CR_REG(cpu_id), reg_val);
+
+       /* 2. Wait for CPU on, up to 100 uSec: */
+       udelay(100);
+
+       /* 3. Assert power ready */
+       reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id));
+       reg_val |= 0x1 << PWRC_CPUN_CR_LDO_BYPASS_RDY_OFFSET;
+       mmio_write_32(PWRC_CPUN_CR_REG(cpu_id), reg_val);
+
+       /* 4. Read & Validate power ready
+        * used in order to generate 16 Host CPU cycles
+        */
+       do {
+               reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id));
+               exit_loop--;
+       } while (!(reg_val & (0x1 << PWRC_CPUN_CR_LDO_BYPASS_RDY_OFFSET)) &&
+                exit_loop > 0);
+
+       if (exit_loop <= 0)
+               goto cpu_poweron_error;
+
+       /* 5. Isolation disable */
+       reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id));
+       reg_val &= ~PWRC_CPUN_CR_ISO_ENABLE_MASK;
+       mmio_write_32(PWRC_CPUN_CR_REG(cpu_id), reg_val);
+
+       /* 6. Read and check Isolation enabled - verify bit set to 1 */
+       exit_loop = REG_WR_VALIDATE_TIMEOUT;
+       do {
+               reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id));
+               exit_loop--;
+       } while ((reg_val & (0x1 << PWRC_CPUN_CR_ISO_ENABLE_OFFSET)) &&
+                exit_loop > 0);
+
+       /* 7. De Assert CPU POR reset & Core reset */
+       reg_val = mmio_read_32(CCU_B_PRCRN_REG(cpu_id));
+       reg_val |= 0x1 << CCU_B_PRCRN_CPUPORESET_STATIC_OFFSET;
+       mmio_write_32(CCU_B_PRCRN_REG(cpu_id), reg_val);
+
+       /* 8. Read & Validate CPU POR reset */
+       exit_loop = REG_WR_VALIDATE_TIMEOUT;
+       do {
+               reg_val = mmio_read_32(CCU_B_PRCRN_REG(cpu_id));
+               exit_loop--;
+       } while (!(reg_val & (0x1 << CCU_B_PRCRN_CPUPORESET_STATIC_OFFSET)) &&
+                exit_loop > 0);
+
+       if (exit_loop <= 0)
+               goto cpu_poweron_error;
+
+       INFO("Successfully powered on CPU%d\n", cpu_id);
+
+       return 0;
+
+cpu_poweron_error:
+       ERROR("ERROR: Can't power up CPU%d\n", cpu_id);
+       return -1;
+}
+
+static int plat_marvell_cpu_on(u_register_t mpidr)
+{
+       int cpu_id;
+       int cluster;
+
+       /* Set barierr */
+       dsbsy();
+
+       /* Get cpu number - use CPU ID */
+       cpu_id =  MPIDR_CPU_GET(mpidr);
+
+       /* Get cluster number - use affinity level 1 */
+       cluster = MPIDR_CLUSTER_GET(mpidr);
+
+       /* Set CPU private UID */
+       mmio_write_32(MVEBU_REGS_BASE + MVEBU_PRIVATE_UID_REG, cluster + 0x4);
+
+       /* Set the cpu start address to BL1 entry point (align to 0x10000) */
+       mmio_write_32(MVEBU_CCU_RVBAR(cpu_id),
+                     PLAT_MARVELL_CPU_ENTRY_ADDR >> 16);
+
+       /* Get the cpu out of reset */
+       mmio_write_32(MVEBU_CCU_CPU_UN_RESET(cpu_id), 0x10001);
+
+       return 0;
+}
+
+/*****************************************************************************
+ * A8K handler called to check the validity of the power state
+ * parameter.
+ *****************************************************************************
+ */
+static int a8k_validate_power_state(unsigned int power_state,
+                           psci_power_state_t *req_state)
+{
+       int pstate = psci_get_pstate_type(power_state);
+       int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
+       int i;
+
+       if (pwr_lvl > PLAT_MAX_PWR_LVL)
+               return PSCI_E_INVALID_PARAMS;
+
+       /* Sanity check the requested state */
+       if (pstate == PSTATE_TYPE_STANDBY) {
+               /*
+                * It's possible to enter standby only on power level 0
+                * Ignore any other power level.
+                */
+               if (pwr_lvl != MARVELL_PWR_LVL0)
+                       return PSCI_E_INVALID_PARAMS;
+
+               req_state->pwr_domain_state[MARVELL_PWR_LVL0] =
+                                       MARVELL_LOCAL_STATE_RET;
+       } else {
+               for (i = MARVELL_PWR_LVL0; i <= pwr_lvl; i++)
+                       req_state->pwr_domain_state[i] =
+                                       MARVELL_LOCAL_STATE_OFF;
+       }
+
+       /*
+        * We expect the 'state id' to be zero.
+        */
+       if (psci_get_pstate_id(power_state))
+               return PSCI_E_INVALID_PARAMS;
+
+       return PSCI_E_SUCCESS;
+}
+
+/*****************************************************************************
+ * A8K handler called when a CPU is about to enter standby.
+ *****************************************************************************
+ */
+static void a8k_cpu_standby(plat_local_state_t cpu_state)
+{
+       ERROR("%s: needs to be implemented\n", __func__);
+       panic();
+}
+
+/*****************************************************************************
+ * A8K handler called when a power domain is about to be turned on. The
+ * mpidr determines the CPU to be turned on.
+ *****************************************************************************
+ */
+static int a8k_pwr_domain_on(u_register_t mpidr)
+{
+       /* Power up CPU (CPUs 1-3 are powered off at start of BLE) */
+       plat_marvell_cpu_powerup(mpidr);
+
+       if (is_pm_fw_running()) {
+               unsigned int target =
+                               ((mpidr & 0xFF) + (((mpidr >> 8) & 0xFF) * 2));
+
+               /*
+                * pm system synchronization - used to synchronize
+                * multiple core access to MSS
+                */
+               bakery_lock_get(&pm_sys_lock);
+
+               /* send CPU ON IPC Message to MSS */
+               mss_pm_ipc_msg_send(target, PM_IPC_MSG_CPU_ON, 0);
+
+               /* trigger IPC message to MSS */
+               mss_pm_ipc_msg_trigger();
+
+               /* pm system synchronization */
+               bakery_lock_release(&pm_sys_lock);
+
+               /* trace message */
+               PM_TRACE(TRACE_PWR_DOMAIN_ON | target);
+       } else {
+               /* proprietary CPU ON exection flow */
+               plat_marvell_cpu_on(mpidr);
+       }
+
+       return 0;
+}
+
+/*****************************************************************************
+ * A8K handler called to validate the entry point.
+ *****************************************************************************
+ */
+static int a8k_validate_ns_entrypoint(uintptr_t entrypoint)
+{
+       return PSCI_E_SUCCESS;
+}
+
+/*****************************************************************************
+ * A8K handler called when a power domain is about to be turned off. The
+ * target_state encodes the power state that each level should transition to.
+ *****************************************************************************
+ */
+static void a8k_pwr_domain_off(const psci_power_state_t *target_state)
+{
+       if (is_pm_fw_running()) {
+               unsigned int idx = plat_my_core_pos();
+
+               /* Prevent interrupts from spuriously waking up this cpu */
+               gicv2_cpuif_disable();
+
+               /* pm system synchronization - used to synchronize multiple
+                * core access to MSS
+                */
+               bakery_lock_get(&pm_sys_lock);
+
+               /* send CPU OFF IPC Message to MSS */
+               mss_pm_ipc_msg_send(idx, PM_IPC_MSG_CPU_OFF, target_state);
+
+               /* trigger IPC message to MSS */
+               mss_pm_ipc_msg_trigger();
+
+               /* pm system synchronization */
+               bakery_lock_release(&pm_sys_lock);
+
+               /* trace message */
+               PM_TRACE(TRACE_PWR_DOMAIN_OFF);
+       } else {
+               INFO("%s: is not supported without SCP\n", __func__);
+       }
+}
+
+/* Get PM config to power off the SoC */
+void *plat_marvell_get_pm_cfg(void)
+{
+       return NULL;
+}
+
+/*
+ * This function should be called on restore from
+ * "suspend to RAM" state when the execution flow
+ * has to bypass BootROM image to RAM copy and speed up
+ * the system recovery
+ *
+ */
+static void plat_marvell_exit_bootrom(void)
+{
+       marvell_exit_bootrom(PLAT_MARVELL_TRUSTED_ROM_BASE);
+}
+
+/*
+ * Prepare for the power off of the system via GPIO
+ */
+static void plat_marvell_power_off_gpio(struct power_off_method *pm_cfg,
+                                       register_t *gpio_addr,
+                                       register_t *gpio_data)
+{
+       unsigned int gpio;
+       unsigned int idx;
+       unsigned int shift;
+       unsigned int reg;
+       unsigned int addr;
+       gpio_info_t *info;
+       unsigned int tog_bits;
+
+       assert((pm_cfg->cfg.gpio.pin_count < PMIC_GPIO_MAX_NUMBER) &&
+              (pm_cfg->cfg.gpio.step_count < PMIC_GPIO_MAX_TOGGLE_STEP));
+
+       /* Prepare GPIOs for PMIC */
+       for (gpio = 0; gpio < pm_cfg->cfg.gpio.pin_count; gpio++) {
+               info = &pm_cfg->cfg.gpio.info[gpio];
+               /* Set PMIC GPIO to output mode */
+               reg = mmio_read_32(MVEBU_CP_GPIO_DATA_OUT_EN(
+                                  info->cp_index, info->gpio_index));
+               mmio_write_32(MVEBU_CP_GPIO_DATA_OUT_EN(
+                             info->cp_index, info->gpio_index),
+                             reg & ~MVEBU_GPIO_MASK(info->gpio_index));
+
+               /* Set the appropriate MPP to GPIO mode */
+               reg = mmio_read_32(MVEBU_PM_MPP_REGS(info->cp_index,
+                                                    info->gpio_index));
+               mmio_write_32(MVEBU_PM_MPP_REGS(info->cp_index,
+                                               info->gpio_index),
+                       reg & ~MVEBU_MPP_MASK(info->gpio_index));
+       }
+
+       /* Wait for MPP & GPIO pre-configurations done */
+       mdelay(pm_cfg->cfg.gpio.delay_ms);
+
+       /* Toggle the GPIO values, and leave final step to be triggered
+        * after  DDR self-refresh is enabled
+        */
+       for (idx = 0; idx < pm_cfg->cfg.gpio.step_count; idx++) {
+               tog_bits = pm_cfg->cfg.gpio.seq[idx];
+
+               /* The GPIOs must be within same GPIO register,
+                * thus could get the original value by first GPIO
+                */
+               info = &pm_cfg->cfg.gpio.info[0];
+               reg = mmio_read_32(MVEBU_CP_GPIO_DATA_OUT(
+                                  info->cp_index, info->gpio_index));
+               addr = MVEBU_CP_GPIO_DATA_OUT(info->cp_index, info->gpio_index);
+
+               for (gpio = 0; gpio < pm_cfg->cfg.gpio.pin_count; gpio++) {
+                       shift = pm_cfg->cfg.gpio.info[gpio].gpio_index % 32;
+                       if (GPIO_LOW == (tog_bits & (1 << gpio)))
+                               reg &= ~(1 << shift);
+                       else
+                               reg |= (1 << shift);
+               }
+
+               /* Set the GPIO register, for last step just store
+                * register address and values to system registers
+                */
+               if (idx < pm_cfg->cfg.gpio.step_count - 1) {
+                       mmio_write_32(MVEBU_CP_GPIO_DATA_OUT(
+                                     info->cp_index, info->gpio_index), reg);
+                       mdelay(pm_cfg->cfg.gpio.delay_ms);
+               } else {
+                       /* Save GPIO register and address values for
+                        * finishing the power down operation later
+                        */
+                       *gpio_addr = addr;
+                       *gpio_data = reg;
+               }
+       }
+}
+
+/*
+ * Prepare for the power off of the system
+ */
+static void plat_marvell_power_off_prepare(struct power_off_method *pm_cfg,
+                                          register_t *addr, register_t *data)
+{
+       switch (pm_cfg->type) {
+       case PMIC_GPIO:
+               plat_marvell_power_off_gpio(pm_cfg, addr, data);
+               break;
+       default:
+               break;
+       }
+}
+
+/*****************************************************************************
+ * A8K handler called when a power domain is about to be suspended. The
+ * target_state encodes the power state that each level should transition to.
+ *****************************************************************************
+ */
+static void a8k_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+       if (is_pm_fw_running()) {
+               unsigned int idx;
+
+               /* Prevent interrupts from spuriously waking up this cpu */
+               gicv2_cpuif_disable();
+
+               idx = plat_my_core_pos();
+
+               /* pm system synchronization - used to synchronize multiple
+                * core access to MSS
+                */
+               bakery_lock_get(&pm_sys_lock);
+
+               /* send CPU Suspend IPC Message to MSS */
+               mss_pm_ipc_msg_send(idx, PM_IPC_MSG_CPU_SUSPEND, target_state);
+
+               /* trigger IPC message to MSS */
+               mss_pm_ipc_msg_trigger();
+
+               /* pm system synchronization */
+               bakery_lock_release(&pm_sys_lock);
+
+               /* trace message */
+               PM_TRACE(TRACE_PWR_DOMAIN_SUSPEND);
+       } else {
+               uintptr_t *mailbox = (void *)PLAT_MARVELL_MAILBOX_BASE;
+
+               INFO("Suspending to RAM\n");
+
+               /* Prevent interrupts from spuriously waking up this cpu */
+               gicv2_cpuif_disable();
+
+               mailbox[MBOX_IDX_SUSPEND_MAGIC] = MVEBU_MAILBOX_SUSPEND_STATE;
+               mailbox[MBOX_IDX_ROM_EXIT_ADDR] = (uintptr_t)&plat_marvell_exit_bootrom;
+
+#if PLAT_MARVELL_SHARED_RAM_CACHED
+               flush_dcache_range(PLAT_MARVELL_MAILBOX_BASE +
+               MBOX_IDX_SUSPEND_MAGIC * sizeof(uintptr_t),
+               2 * sizeof(uintptr_t));
+#endif
+               /* Flush and disable LLC before going off-power */
+               llc_disable(0);
+
+               isb();
+               /*
+                * Do not halt here!
+                * The function must return for allowing the caller function
+                * psci_power_up_finish() to do the proper context saving and
+                * to release the CPU lock.
+                */
+       }
+}
+
+/*****************************************************************************
+ * A8K handler called when a power domain has just been powered on after
+ * being turned off earlier. The target_state encodes the low power state that
+ * each level has woken up from.
+ *****************************************************************************
+ */
+static void a8k_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+       /* arch specific configuration */
+       marvell_psci_arch_init(0);
+
+       /* Interrupt initialization */
+       gicv2_pcpu_distif_init();
+       gicv2_cpuif_enable();
+
+       if (is_pm_fw_running()) {
+               /* trace message */
+               PM_TRACE(TRACE_PWR_DOMAIN_ON_FINISH);
+       }
+}
+
+/*****************************************************************************
+ * A8K handler called when a power domain has just been powered on after
+ * having been suspended earlier. The target_state encodes the low power state
+ * that each level has woken up from.
+ * TODO: At the moment we reuse the on finisher and reinitialize the secure
+ * context. Need to implement a separate suspend finisher.
+ *****************************************************************************
+ */
+static void a8k_pwr_domain_suspend_finish(
+                                       const psci_power_state_t *target_state)
+{
+       if (is_pm_fw_running()) {
+               /* arch specific configuration */
+               marvell_psci_arch_init(0);
+
+               /* Interrupt initialization */
+               gicv2_cpuif_enable();
+
+               /* trace message */
+               PM_TRACE(TRACE_PWR_DOMAIN_SUSPEND_FINISH);
+       } else {
+               uintptr_t *mailbox = (void *)PLAT_MARVELL_MAILBOX_BASE;
+
+               /* Only primary CPU requres platform init */
+               if (!plat_my_core_pos()) {
+                       /* Initialize the console to provide
+                        * early debug support
+                        */
+                       console_init(PLAT_MARVELL_BOOT_UART_BASE,
+                       PLAT_MARVELL_BOOT_UART_CLK_IN_HZ,
+                       MARVELL_CONSOLE_BAUDRATE);
+
+                       bl31_plat_arch_setup();
+                       marvell_bl31_platform_setup();
+                       /*
+                        * Remove suspend to RAM marker from the mailbox
+                        * for treating a regular reset as a cold boot
+                        */
+                       mailbox[MBOX_IDX_SUSPEND_MAGIC] = 0;
+                       mailbox[MBOX_IDX_ROM_EXIT_ADDR] = 0;
+#if PLAT_MARVELL_SHARED_RAM_CACHED
+                       flush_dcache_range(PLAT_MARVELL_MAILBOX_BASE +
+                       MBOX_IDX_SUSPEND_MAGIC * sizeof(uintptr_t),
+                       2 * sizeof(uintptr_t));
+#endif
+               }
+       }
+}
+
+/*****************************************************************************
+ * This handler is called by the PSCI implementation during the `SYSTEM_SUSPEND`
+ * call to get the `power_state` parameter. This allows the platform to encode
+ * the appropriate State-ID field within the `power_state` parameter which can
+ * be utilized in `pwr_domain_suspend()` to suspend to system affinity level.
+ *****************************************************************************
+ */
+static void a8k_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+       /* lower affinities use PLAT_MAX_OFF_STATE */
+       for (int i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
+               req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
+}
+
+static void
+__dead2 a8k_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state)
+{
+       struct power_off_method *pm_cfg;
+       unsigned int srcmd;
+       unsigned int sdram_reg;
+       register_t gpio_data = 0, gpio_addr = 0;
+
+       if (is_pm_fw_running()) {
+               psci_power_down_wfi();
+               panic();
+       }
+
+       pm_cfg = (struct power_off_method *)plat_marvell_get_pm_cfg();
+
+       /* Prepare for power off */
+       plat_marvell_power_off_prepare(pm_cfg, &gpio_addr, &gpio_data);
+
+       /* First step to enable DDR self-refresh
+        * to keep the data during suspend
+        */
+       mmio_write_32(MVEBU_MC_PWR_CTRL_REG, 0x8C1);
+
+       /* Save DDR self-refresh second step register
+        * and value to be issued later
+        */
+       sdram_reg = MVEBU_USER_CMD_0_REG;
+       srcmd = mmio_read_32(sdram_reg);
+       srcmd &= ~(MVEBU_USER_CMD_CH0_MASK | MVEBU_USER_CMD_CS_MASK |
+                MVEBU_USER_CMD_SR_MASK);
+       srcmd |= (MVEBU_USER_CMD_CH0_EN | MVEBU_USER_CMD_CS_ALL |
+                MVEBU_USER_CMD_SR_ENTER);
+
+       /*
+        * Wait for DRAM is done using registers access only.
+        * At this stage any access to DRAM (procedure call) will
+        * release it from the self-refresh mode
+        */
+       __asm__ volatile (
+               /* Align to a cache line */
+               "       .balign 64\n\t"
+
+               /* Enter self refresh */
+               "       str %[srcmd], [%[sdram_reg]]\n\t"
+
+               /*
+                * Wait 100 cycles for DDR to enter self refresh, by
+                * doing 50 times two instructions.
+                */
+               "       mov x1, #50\n\t"
+               "1:     subs x1, x1, #1\n\t"
+               "       bne 1b\n\t"
+
+               /* Issue the command to trigger the SoC power off */
+               "       str     %[gpio_data], [%[gpio_addr]]\n\t"
+
+               /* Trap the processor */
+               "       b .\n\t"
+               : : [srcmd] "r" (srcmd), [sdram_reg] "r" (sdram_reg),
+                   [gpio_addr] "r" (gpio_addr),  [gpio_data] "r" (gpio_data)
+               : "x1");
+
+       panic();
+}
+
+/*****************************************************************************
+ * A8K handlers to shutdown/reboot the system
+ *****************************************************************************
+ */
+static void __dead2 a8k_system_off(void)
+{
+       ERROR("%s:  needs to be implemented\n", __func__);
+       panic();
+}
+
+void plat_marvell_system_reset(void)
+{
+       mmio_write_32(MVEBU_RFU_BASE + MVEBU_RFU_GLOBL_SW_RST, 0x0);
+}
+
+static void __dead2 a8k_system_reset(void)
+{
+       plat_marvell_system_reset();
+
+       /* we shouldn't get to this point */
+       panic();
+}
+
+/*****************************************************************************
+ * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard
+ * platform layer will take care of registering the handlers with PSCI.
+ *****************************************************************************
+ */
+const plat_psci_ops_t plat_arm_psci_pm_ops = {
+       .cpu_standby = a8k_cpu_standby,
+       .pwr_domain_on = a8k_pwr_domain_on,
+       .pwr_domain_off = a8k_pwr_domain_off,
+       .pwr_domain_suspend = a8k_pwr_domain_suspend,
+       .pwr_domain_on_finish = a8k_pwr_domain_on_finish,
+       .get_sys_suspend_power_state = a8k_get_sys_suspend_power_state,
+       .pwr_domain_suspend_finish = a8k_pwr_domain_suspend_finish,
+       .pwr_domain_pwr_down_wfi = a8k_pwr_domain_pwr_down_wfi,
+       .system_off = a8k_system_off,
+       .system_reset = a8k_system_reset,
+       .validate_power_state = a8k_validate_power_state,
+       .validate_ns_entrypoint = a8k_validate_ns_entrypoint
+};
diff --git a/plat/marvell/a8k/common/plat_pm_trace.c b/plat/marvell/a8k/common/plat_pm_trace.c
new file mode 100644 (file)
index 0000000..683e56f
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <mmio.h>
+#include <mss_mem.h>
+#include <platform.h>
+#include <plat_pm_trace.h>
+
+#ifdef PM_TRACE_ENABLE
+
+/* core trace APIs */
+core_trace_func funcTbl[PLATFORM_CORE_COUNT] = {
+       pm_core_0_trace,
+       pm_core_1_trace,
+       pm_core_2_trace,
+       pm_core_3_trace};
+
+/*****************************************************************************
+ * pm_core0_trace
+ * pm_core1_trace
+ * pm_core2_trace
+ * pm_core_3trace
+ *
+ * This functions set trace info into core cyclic trace queue in MSS SRAM
+ * memory space
+ *****************************************************************************
+ */
+void pm_core_0_trace(unsigned int trace)
+{
+       unsigned int current_position_core_0 =
+                       mmio_read_32(AP_MSS_ATF_CORE_0_CTRL_BASE);
+       mmio_write_32((AP_MSS_ATF_CORE_0_INFO_BASE  +
+                    (current_position_core_0 * AP_MSS_ATF_CORE_ENTRY_SIZE)),
+                    mmio_read_32(AP_MSS_TIMER_BASE));
+       mmio_write_32((AP_MSS_ATF_CORE_0_INFO_TRACE +
+                    (current_position_core_0 * AP_MSS_ATF_CORE_ENTRY_SIZE)),
+                    trace);
+       mmio_write_32(AP_MSS_ATF_CORE_0_CTRL_BASE,
+                    ((current_position_core_0 + 1) &
+                    AP_MSS_ATF_TRACE_SIZE_MASK));
+}
+
+void pm_core_1_trace(unsigned int trace)
+{
+       unsigned int current_position_core_1 =
+                       mmio_read_32(AP_MSS_ATF_CORE_1_CTRL_BASE);
+       mmio_write_32((AP_MSS_ATF_CORE_1_INFO_BASE +
+                    (current_position_core_1 * AP_MSS_ATF_CORE_ENTRY_SIZE)),
+                    mmio_read_32(AP_MSS_TIMER_BASE));
+       mmio_write_32((AP_MSS_ATF_CORE_1_INFO_TRACE +
+                    (current_position_core_1 * AP_MSS_ATF_CORE_ENTRY_SIZE)),
+                    trace);
+       mmio_write_32(AP_MSS_ATF_CORE_1_CTRL_BASE,
+                    ((current_position_core_1 + 1) &
+                    AP_MSS_ATF_TRACE_SIZE_MASK));
+}
+
+void pm_core_2_trace(unsigned int trace)
+{
+       unsigned int current_position_core_2 =
+                       mmio_read_32(AP_MSS_ATF_CORE_2_CTRL_BASE);
+       mmio_write_32((AP_MSS_ATF_CORE_2_INFO_BASE +
+                    (current_position_core_2 * AP_MSS_ATF_CORE_ENTRY_SIZE)),
+                    mmio_read_32(AP_MSS_TIMER_BASE));
+       mmio_write_32((AP_MSS_ATF_CORE_2_INFO_TRACE +
+                    (current_position_core_2 * AP_MSS_ATF_CORE_ENTRY_SIZE)),
+                    trace);
+       mmio_write_32(AP_MSS_ATF_CORE_2_CTRL_BASE,
+                    ((current_position_core_2 + 1) &
+                    AP_MSS_ATF_TRACE_SIZE_MASK));
+}
+
+void pm_core_3_trace(unsigned int trace)
+{
+       unsigned int current_position_core_3 =
+                       mmio_read_32(AP_MSS_ATF_CORE_3_CTRL_BASE);
+       mmio_write_32((AP_MSS_ATF_CORE_3_INFO_BASE +
+                    (current_position_core_3 * AP_MSS_ATF_CORE_ENTRY_SIZE)),
+                    mmio_read_32(AP_MSS_TIMER_BASE));
+       mmio_write_32((AP_MSS_ATF_CORE_3_INFO_TRACE +
+                    (current_position_core_3 * AP_MSS_ATF_CORE_ENTRY_SIZE)),
+                    trace);
+       mmio_write_32(AP_MSS_ATF_CORE_3_CTRL_BASE,
+                    ((current_position_core_3 + 1) &
+                    AP_MSS_ATF_TRACE_SIZE_MASK));
+}
+#endif /* PM_TRACE_ENABLE */
diff --git a/plat/marvell/a8k/common/plat_thermal.c b/plat/marvell/a8k/common/plat_thermal.c
new file mode 100644 (file)
index 0000000..02fe820
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <debug.h>
+#include <delay_timer.h>
+#include <mmio.h>
+#include <mvebu_def.h>
+#include <thermal.h>
+
+#define THERMAL_TIMEOUT                                        1200
+
+#define THERMAL_SEN_CTRL_LSB_STRT_OFFSET               0
+#define THERMAL_SEN_CTRL_LSB_STRT_MASK                 \
+                               (0x1 << THERMAL_SEN_CTRL_LSB_STRT_OFFSET)
+#define THERMAL_SEN_CTRL_LSB_RST_OFFSET                        1
+#define THERMAL_SEN_CTRL_LSB_RST_MASK                  \
+                               (0x1 << THERMAL_SEN_CTRL_LSB_RST_OFFSET)
+#define THERMAL_SEN_CTRL_LSB_EN_OFFSET                 2
+#define THERMAL_SEN_CTRL_LSB_EN_MASK                   \
+                               (0x1 << THERMAL_SEN_CTRL_LSB_EN_OFFSET)
+
+#define THERMAL_SEN_CTRL_STATS_VALID_OFFSET            16
+#define THERMAL_SEN_CTRL_STATS_VALID_MASK              \
+                               (0x1 << THERMAL_SEN_CTRL_STATS_VALID_OFFSET)
+#define THERMAL_SEN_CTRL_STATS_TEMP_OUT_OFFSET         0
+#define THERMAL_SEN_CTRL_STATS_TEMP_OUT_MASK           \
+                       (0x3FF << THERMAL_SEN_CTRL_STATS_TEMP_OUT_OFFSET)
+
+#define THERMAL_SEN_OUTPUT_MSB                         512
+#define THERMAL_SEN_OUTPUT_COMP                                1024
+
+struct tsen_regs {
+       uint32_t ext_tsen_ctrl_lsb;
+       uint32_t ext_tsen_ctrl_msb;
+       uint32_t ext_tsen_status;
+};
+
+static int ext_tsen_probe(struct tsen_config *tsen_cfg)
+{
+       uint32_t reg, timeout = 0;
+       struct tsen_regs *base;
+
+       if (tsen_cfg == NULL && tsen_cfg->regs_base == NULL) {
+               ERROR("initial thermal sensor configuration is missing\n");
+               return -1;
+       }
+       base = (struct tsen_regs *)tsen_cfg->regs_base;
+
+       INFO("initializing thermal sensor\n");
+
+       /* initialize thermal sensor hardware reset once */
+       reg = mmio_read_32((uintptr_t)&base->ext_tsen_ctrl_lsb);
+       reg &= ~THERMAL_SEN_CTRL_LSB_RST_OFFSET; /* de-assert TSEN_RESET */
+       reg |= THERMAL_SEN_CTRL_LSB_EN_MASK; /* set TSEN_EN to 1 */
+       reg |= THERMAL_SEN_CTRL_LSB_STRT_MASK; /* set TSEN_START to 1 */
+       mmio_write_32((uintptr_t)&base->ext_tsen_ctrl_lsb, reg);
+
+       reg = mmio_read_32((uintptr_t)&base->ext_tsen_status);
+       while ((reg & THERMAL_SEN_CTRL_STATS_VALID_MASK) == 0 &&
+              timeout < THERMAL_TIMEOUT) {
+               udelay(100);
+               reg = mmio_read_32((uintptr_t)&base->ext_tsen_status);
+               timeout++;
+       }
+
+       if ((reg & THERMAL_SEN_CTRL_STATS_VALID_MASK) == 0) {
+               ERROR("thermal sensor is not ready\n");
+               return -1;
+       }
+
+       tsen_cfg->tsen_ready = 1;
+
+       VERBOSE("thermal sensor was initialized\n");
+
+       return 0;
+}
+
+static int ext_tsen_read(struct tsen_config *tsen_cfg, int *temp)
+{
+       uint32_t reg;
+       struct tsen_regs *base;
+
+       if (tsen_cfg == NULL && !tsen_cfg->tsen_ready) {
+               ERROR("thermal sensor was not initialized\n");
+               return -1;
+       }
+       base = (struct tsen_regs *)tsen_cfg->regs_base;
+
+       reg = mmio_read_32((uintptr_t)&base->ext_tsen_status);
+       reg = ((reg & THERMAL_SEN_CTRL_STATS_TEMP_OUT_MASK) >>
+               THERMAL_SEN_CTRL_STATS_TEMP_OUT_OFFSET);
+
+       /*
+        * TSEN output format is signed as a 2s complement number
+        * ranging from-512 to +511. when MSB is set, need to
+        * calculate the complement number
+        */
+       if (reg >= THERMAL_SEN_OUTPUT_MSB)
+               reg -= THERMAL_SEN_OUTPUT_COMP;
+
+       if (tsen_cfg->tsen_divisor == 0) {
+               ERROR("thermal sensor divisor cannot be zero\n");
+               return -1;
+       }
+
+       *temp = ((tsen_cfg->tsen_gain * ((int)reg)) +
+                tsen_cfg->tsen_offset) / tsen_cfg->tsen_divisor;
+
+       return 0;
+}
+
+static struct tsen_config tsen_cfg = {
+       .tsen_offset = 153400,
+       .tsen_gain = 425,
+       .tsen_divisor = 1000,
+       .tsen_ready = 0,
+       .regs_base = (void *)MVEBU_AP_EXT_TSEN_BASE,
+       .ptr_tsen_probe = ext_tsen_probe,
+       .ptr_tsen_read = ext_tsen_read
+};
+
+struct tsen_config *marvell_thermal_config_get(void)
+{
+       return &tsen_cfg;
+}
diff --git a/plat/marvell/common/aarch64/marvell_common.c b/plat/marvell/common/aarch64/marvell_common.c
new file mode 100644 (file)
index 0000000..abc501a
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <debug.h>
+#include <mmio.h>
+#include <plat_marvell.h>
+#include <platform_def.h>
+#include <xlat_tables.h>
+
+
+/* Weak definitions may be overridden in specific ARM standard platform */
+#pragma weak plat_get_ns_image_entrypoint
+#pragma weak plat_marvell_get_mmap
+
+/*
+ * Set up the page tables for the generic and platform-specific memory regions.
+ * The extents of the generic memory regions are specified by the function
+ * arguments and consist of:
+ * - Trusted SRAM seen by the BL image;
+ * - Code section;
+ * - Read-only data section;
+ * - Coherent memory region, if applicable.
+ */
+void marvell_setup_page_tables(uintptr_t total_base,
+                              size_t total_size,
+                              uintptr_t code_start,
+                              uintptr_t code_limit,
+                              uintptr_t rodata_start,
+                              uintptr_t rodata_limit
+#if USE_COHERENT_MEM
+                              ,
+                              uintptr_t coh_start,
+                              uintptr_t coh_limit
+#endif
+                          )
+{
+       /*
+        * Map the Trusted SRAM with appropriate memory attributes.
+        * Subsequent mappings will adjust the attributes for specific regions.
+        */
+       VERBOSE("Trusted SRAM seen by this BL image: %p - %p\n",
+               (void *) total_base, (void *) (total_base + total_size));
+       mmap_add_region(total_base, total_base,
+                       total_size,
+                       MT_MEMORY | MT_RW | MT_SECURE);
+
+       /* Re-map the code section */
+       VERBOSE("Code region: %p - %p\n",
+               (void *) code_start, (void *) code_limit);
+       mmap_add_region(code_start, code_start,
+                       code_limit - code_start,
+                       MT_CODE | MT_SECURE);
+
+       /* Re-map the read-only data section */
+       VERBOSE("Read-only data region: %p - %p\n",
+               (void *) rodata_start, (void *) rodata_limit);
+       mmap_add_region(rodata_start, rodata_start,
+                       rodata_limit - rodata_start,
+                       MT_RO_DATA | MT_SECURE);
+
+#if USE_COHERENT_MEM
+       /* Re-map the coherent memory region */
+       VERBOSE("Coherent region: %p - %p\n",
+               (void *) coh_start, (void *) coh_limit);
+       mmap_add_region(coh_start, coh_start,
+                       coh_limit - coh_start,
+                       MT_DEVICE | MT_RW | MT_SECURE);
+#endif
+
+       /* Now (re-)map the platform-specific memory regions */
+       mmap_add(plat_marvell_get_mmap());
+
+       /* Create the page tables to reflect the above mappings */
+       init_xlat_tables();
+}
+
+unsigned long plat_get_ns_image_entrypoint(void)
+{
+       return PLAT_MARVELL_NS_IMAGE_OFFSET;
+}
+
+/*****************************************************************************
+ * Gets SPSR for BL32 entry
+ *****************************************************************************
+ */
+uint32_t marvell_get_spsr_for_bl32_entry(void)
+{
+       /*
+        * The Secure Payload Dispatcher service is responsible for
+        * setting the SPSR prior to entry into the BL32 image.
+        */
+       return 0;
+}
+
+/*****************************************************************************
+ * Gets SPSR for BL33 entry
+ *****************************************************************************
+ */
+uint32_t marvell_get_spsr_for_bl33_entry(void)
+{
+       unsigned long el_status;
+       unsigned int mode;
+       uint32_t spsr;
+
+       /* Figure out what mode we enter the non-secure world in */
+       el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT;
+       el_status &= ID_AA64PFR0_ELX_MASK;
+
+       mode = (el_status) ? MODE_EL2 : MODE_EL1;
+
+       /*
+        * TODO: Consider the possibility of specifying the SPSR in
+        * the FIP ToC and allowing the platform to have a say as
+        * well.
+        */
+       spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
+       return spsr;
+}
+
+/*****************************************************************************
+ * Returns ARM platform specific memory map regions.
+ *****************************************************************************
+ */
+const mmap_region_t *plat_marvell_get_mmap(void)
+{
+       return plat_marvell_mmap;
+}
+
diff --git a/plat/marvell/common/aarch64/marvell_helpers.S b/plat/marvell/common/aarch64/marvell_helpers.S
new file mode 100644 (file)
index 0000000..a3dc917
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <asm_macros.S>
+#include <cortex_a72.h>
+#include <marvell_def.h>
+#include <platform_def.h>
+#ifndef PLAT_a3700
+#include <ccu.h>
+#include <cache_llc.h>
+#endif
+
+       .weak   plat_marvell_calc_core_pos
+       .weak   plat_my_core_pos
+       .globl  plat_crash_console_init
+       .globl  plat_crash_console_putc
+       .globl  platform_mem_init
+       .globl  disable_mmu_dcache
+       .globl  invalidate_tlb_all
+       .globl  platform_unmap_sram
+       .globl  disable_sram
+       .globl  disable_icache
+       .globl  invalidate_icache_all
+       .globl  marvell_exit_bootrom
+       .globl  ca72_l2_enable_unique_clean
+
+       /* -----------------------------------------------------
+        *  unsigned int plat_my_core_pos(void)
+        *  This function uses the plat_marvell_calc_core_pos()
+        *  definition to get the index of the calling CPU.
+        * -----------------------------------------------------
+        */
+func plat_my_core_pos
+       mrs     x0, mpidr_el1
+       b       plat_marvell_calc_core_pos
+endfunc plat_my_core_pos
+
+       /* -----------------------------------------------------
+        *  unsigned int plat_marvell_calc_core_pos(uint64_t mpidr)
+        *  Helper function to calculate the core position.
+        *  With this function: CorePos = (ClusterId * 2) +
+        *                                CoreId
+        * -----------------------------------------------------
+        */
+func plat_marvell_calc_core_pos
+       and     x1, x0, #MPIDR_CPU_MASK
+       and     x0, x0, #MPIDR_CLUSTER_MASK
+       add     x0, x1, x0, LSR #7
+       ret
+endfunc plat_marvell_calc_core_pos
+
+       /* ---------------------------------------------
+        * int plat_crash_console_init(void)
+        * Function to initialize the crash console
+        * without a C Runtime to print crash report.
+        * Clobber list : x0, x1, x2
+        * ---------------------------------------------
+        */
+func plat_crash_console_init
+       mov_imm x0, PLAT_MARVELL_CRASH_UART_BASE
+       mov_imm x1, PLAT_MARVELL_CRASH_UART_CLK_IN_HZ
+       mov_imm x2, MARVELL_CONSOLE_BAUDRATE
+       b       console_core_init
+endfunc plat_crash_console_init
+
+       /* ---------------------------------------------
+        * int plat_crash_console_putc(int c)
+        * Function to print a character on the crash
+        * console without a C Runtime.
+        * Clobber list : x1, x2
+        * ---------------------------------------------
+        */
+func plat_crash_console_putc
+       mov_imm x1, PLAT_MARVELL_CRASH_UART_BASE
+       b       console_core_putc
+endfunc plat_crash_console_putc
+
+       /* ---------------------------------------------------------------------
+        * We don't need to carry out any memory initialization on ARM
+        * platforms. The Secure RAM is accessible straight away.
+        * ---------------------------------------------------------------------
+        */
+func platform_mem_init
+       ret
+endfunc platform_mem_init
+
+       /* -----------------------------------------------------
+        * Disable icache, dcache, and MMU
+        * -----------------------------------------------------
+        */
+func disable_mmu_dcache
+       mrs     x0, sctlr_el3
+       bic     x0, x0, 0x1             /* M bit - MMU */
+       bic     x0, x0, 0x4             /* C bit - Dcache L1 & L2 */
+       msr     sctlr_el3, x0
+       isb
+       b       mmu_off
+mmu_off:
+       ret
+endfunc disable_mmu_dcache
+
+       /* -----------------------------------------------------
+        * Disable all TLB entries
+        * -----------------------------------------------------
+        */
+func invalidate_tlb_all
+       tlbi    alle3
+       dsb     sy
+       isb
+       ret
+endfunc invalidate_tlb_all
+
+       /* -----------------------------------------------------
+        * Disable the i cache
+        * -----------------------------------------------------
+        */
+func disable_icache
+       mrs     x0, sctlr_el3
+       bic     x0, x0, 0x1000  /* I bit - Icache L1 & L2 */
+       msr     sctlr_el3, x0
+       isb
+       ret
+endfunc disable_icache
+
+       /* -----------------------------------------------------
+        * Disable all of the i caches
+        * -----------------------------------------------------
+        */
+func invalidate_icache_all
+       ic      ialluis
+       isb     sy
+       ret
+endfunc invalidate_icache_all
+
+       /* -----------------------------------------------------
+        * Clear the SRAM enabling bit to unmap SRAM
+        * -----------------------------------------------------
+        */
+func platform_unmap_sram
+       ldr     x0, =CCU_SRAM_WIN_CR
+       str     wzr, [x0]
+       ret
+endfunc platform_unmap_sram
+
+       /* -----------------------------------------------------
+        * Disable the SRAM
+        * -----------------------------------------------------
+        */
+func disable_sram
+       /* Disable the line lockings. They must be disabled expictly
+        * or the OS will have problems using the cache */
+       ldr     x1, =MASTER_LLC_TC0_LOCK
+       str     wzr, [x1]
+
+       /* Invalidate all ways */
+       ldr     w1, =LLC_WAY_MASK
+       ldr     x0, =MASTER_L2X0_INV_WAY
+       str     w1, [x0]
+
+       /* Finally disable LLC */
+       ldr     x0, =MASTER_LLC_CTRL
+       str     wzr, [x0]
+
+       ret
+endfunc disable_sram
+
+       /* -----------------------------------------------------
+        * Operation when exit bootROM:
+        * Disable the MMU
+        * Disable and invalidate the dcache
+        * Unmap and disable the SRAM
+        * Disable and invalidate the icache
+        * -----------------------------------------------------
+        */
+func marvell_exit_bootrom
+       /* Save the system restore address */
+       mov     x28, x0
+
+       /* Close the caches and MMU */
+       bl      disable_mmu_dcache
+
+       /*
+        * There is nothing important in the caches now,
+        * so invalidate them instead of cleaning.
+        */
+       adr     x0, __RW_START__
+       adr     x1, __RW_END__
+       sub     x1, x1, x0
+       bl      inv_dcache_range
+       bl      invalidate_tlb_all
+
+       /*
+        * Clean the memory mapping of SRAM
+        * the DDR mapping will remain to enable boot image to execute
+        */
+       bl      platform_unmap_sram
+
+       /* Disable the SRAM */
+       bl      disable_sram
+
+       /* Disable and invalidate icache */
+       bl      disable_icache
+       bl      invalidate_icache_all
+
+       mov     x0, x28
+       br      x0
+endfunc marvell_exit_bootrom
+
+       /*
+        * Enable L2 UniqueClean evictions with data
+        */
+func ca72_l2_enable_unique_clean
+
+       mrs     x0, CORTEX_A72_L2ACTLR_EL1
+       orr     x0, x0, #CORTEX_A72_L2ACTLR_ENABLE_UNIQUE_CLEAN
+       msr     CORTEX_A72_L2ACTLR_EL1, x0
+
+       ret
+endfunc ca72_l2_enable_unique_clean
diff --git a/plat/marvell/common/marvell_bl1_setup.c b/plat/marvell/common/marvell_bl1_setup.c
new file mode 100644 (file)
index 0000000..981cfbe
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <bl1.h>
+#include <bl1/bl1_private.h>
+#include <bl_common.h>
+#include <console.h>
+#include <debug.h>
+#include <platform.h>
+#include <platform_def.h>
+#include <plat_marvell.h>
+#include <sp805.h>
+
+/* Weak definitions may be overridden in specific Marvell standard platform */
+#pragma weak bl1_early_platform_setup
+#pragma weak bl1_plat_arch_setup
+#pragma weak bl1_platform_setup
+#pragma weak bl1_plat_sec_mem_layout
+
+
+/* Data structure which holds the extents of the RAM for BL1*/
+static meminfo_t bl1_ram_layout;
+
+meminfo_t *bl1_plat_sec_mem_layout(void)
+{
+       return &bl1_ram_layout;
+}
+
+/*
+ * BL1 specific platform actions shared between Marvell standard platforms.
+ */
+void marvell_bl1_early_platform_setup(void)
+{
+       const size_t bl1_size = BL1_RAM_LIMIT - BL1_RAM_BASE;
+
+       /* Initialize the console to provide early debug support */
+       console_init(PLAT_MARVELL_BOOT_UART_BASE,
+                    PLAT_MARVELL_BOOT_UART_CLK_IN_HZ,
+                    MARVELL_CONSOLE_BAUDRATE);
+
+       /* Allow BL1 to see the whole Trusted RAM */
+       bl1_ram_layout.total_base = MARVELL_BL_RAM_BASE;
+       bl1_ram_layout.total_size = MARVELL_BL_RAM_SIZE;
+
+       /* Calculate how much RAM BL1 is using and how much remains free */
+       bl1_ram_layout.free_base = MARVELL_BL_RAM_BASE;
+       bl1_ram_layout.free_size = MARVELL_BL_RAM_SIZE;
+       reserve_mem(&bl1_ram_layout.free_base,
+                   &bl1_ram_layout.free_size,
+                   BL1_RAM_BASE,
+                   bl1_size);
+}
+
+void bl1_early_platform_setup(void)
+{
+       marvell_bl1_early_platform_setup();
+}
+
+/*
+ * Perform the very early platform specific architecture setup shared between
+ * MARVELL standard platforms. This only does basic initialization. Later
+ * architectural setup (bl1_arch_setup()) does not do anything platform
+ * specific.
+ */
+void marvell_bl1_plat_arch_setup(void)
+{
+       marvell_setup_page_tables(bl1_ram_layout.total_base,
+                                 bl1_ram_layout.total_size,
+                                 BL1_RO_BASE,
+                                 BL1_RO_LIMIT,
+                                 BL1_RO_DATA_BASE,
+                                 BL1_RO_DATA_END
+#if USE_COHERENT_MEM
+                               , BL_COHERENT_RAM_BASE,
+                                 BL_COHERENT_RAM_END
+#endif
+                               );
+       enable_mmu_el3(0);
+}
+
+void bl1_plat_arch_setup(void)
+{
+       marvell_bl1_plat_arch_setup();
+}
+
+/*
+ * Perform the platform specific architecture setup shared between
+ * MARVELL standard platforms.
+ */
+void marvell_bl1_platform_setup(void)
+{
+       /* Initialise the IO layer and register platform IO devices */
+       plat_marvell_io_setup();
+}
+
+void bl1_platform_setup(void)
+{
+       marvell_bl1_platform_setup();
+}
+
+void bl1_plat_prepare_exit(entry_point_info_t *ep_info)
+{
+#ifdef EL3_PAYLOAD_BASE
+       /*
+        * Program the EL3 payload's entry point address into the CPUs mailbox
+        * in order to release secondary CPUs from their holding pen and make
+        * them jump there.
+        */
+       marvell_program_trusted_mailbox(ep_info->pc);
+       dsbsy();
+       sev();
+#endif
+}
diff --git a/plat/marvell/common/marvell_bl2_setup.c b/plat/marvell/common/marvell_bl2_setup.c
new file mode 100644 (file)
index 0000000..7c87ce3
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <arch_helpers.h>
+#include <bl_common.h>
+#include <console.h>
+#include <marvell_def.h>
+#include <platform_def.h>
+#include <plat_marvell.h>
+#include <string.h>
+
+/* Data structure which holds the extents of the trusted SRAM for BL2 */
+static meminfo_t bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE);
+
+
+/*****************************************************************************
+ * This structure represents the superset of information that is passed to
+ * BL31, e.g. while passing control to it from BL2, bl31_params
+ * and other platform specific parameters
+ *****************************************************************************
+ */
+typedef struct bl2_to_bl31_params_mem {
+       bl31_params_t bl31_params;
+       image_info_t bl31_image_info;
+       image_info_t bl32_image_info;
+       image_info_t bl33_image_info;
+       entry_point_info_t bl33_ep_info;
+       entry_point_info_t bl32_ep_info;
+       entry_point_info_t bl31_ep_info;
+} bl2_to_bl31_params_mem_t;
+
+
+static bl2_to_bl31_params_mem_t bl31_params_mem;
+
+
+/* Weak definitions may be overridden in specific MARVELL standard platform */
+#pragma weak bl2_early_platform_setup
+#pragma weak bl2_platform_setup
+#pragma weak bl2_plat_arch_setup
+#pragma weak bl2_plat_sec_mem_layout
+#pragma weak bl2_plat_get_bl31_params
+#pragma weak bl2_plat_get_bl31_ep_info
+#pragma weak bl2_plat_flush_bl31_params
+#pragma weak bl2_plat_set_bl31_ep_info
+#pragma weak bl2_plat_get_scp_bl2_meminfo
+#pragma weak bl2_plat_get_bl32_meminfo
+#pragma weak bl2_plat_set_bl32_ep_info
+#pragma weak bl2_plat_get_bl33_meminfo
+#pragma weak bl2_plat_set_bl33_ep_info
+
+
+meminfo_t *bl2_plat_sec_mem_layout(void)
+{
+       return &bl2_tzram_layout;
+}
+
+/*****************************************************************************
+ * This function assigns a pointer to the memory that the platform has kept
+ * aside to pass platform specific and trusted firmware related information
+ * to BL31. This memory is allocated by allocating memory to
+ * bl2_to_bl31_params_mem_t structure which is a superset of all the
+ * structure whose information is passed to BL31
+ * NOTE: This function should be called only once and should be done
+ * before generating params to BL31
+ *****************************************************************************
+ */
+bl31_params_t *bl2_plat_get_bl31_params(void)
+{
+       bl31_params_t *bl2_to_bl31_params;
+
+       /*
+        * Initialise the memory for all the arguments that needs to
+        * be passed to BL31
+        */
+       memset(&bl31_params_mem, 0, sizeof(bl2_to_bl31_params_mem_t));
+
+       /* Assign memory for TF related information */
+       bl2_to_bl31_params = &bl31_params_mem.bl31_params;
+       SET_PARAM_HEAD(bl2_to_bl31_params, PARAM_BL31, VERSION_1, 0);
+
+       /* Fill BL31 related information */
+       bl2_to_bl31_params->bl31_image_info = &bl31_params_mem.bl31_image_info;
+       SET_PARAM_HEAD(bl2_to_bl31_params->bl31_image_info, PARAM_IMAGE_BINARY,
+               VERSION_1, 0);
+
+       /* Fill BL32 related information if it exists */
+#if BL32_BASE
+       bl2_to_bl31_params->bl32_ep_info = &bl31_params_mem.bl32_ep_info;
+       SET_PARAM_HEAD(bl2_to_bl31_params->bl32_ep_info, PARAM_EP,
+               VERSION_1, 0);
+       bl2_to_bl31_params->bl32_image_info = &bl31_params_mem.bl32_image_info;
+       SET_PARAM_HEAD(bl2_to_bl31_params->bl32_image_info, PARAM_IMAGE_BINARY,
+               VERSION_1, 0);
+#endif
+
+       /* Fill BL33 related information */
+       bl2_to_bl31_params->bl33_ep_info = &bl31_params_mem.bl33_ep_info;
+       SET_PARAM_HEAD(bl2_to_bl31_params->bl33_ep_info,
+               PARAM_EP, VERSION_1, 0);
+
+       /* BL33 expects to receive the primary CPU MPID (through x0) */
+       bl2_to_bl31_params->bl33_ep_info->args.arg0 = 0xffff & read_mpidr();
+
+       bl2_to_bl31_params->bl33_image_info = &bl31_params_mem.bl33_image_info;
+       SET_PARAM_HEAD(bl2_to_bl31_params->bl33_image_info, PARAM_IMAGE_BINARY,
+               VERSION_1, 0);
+
+       return bl2_to_bl31_params;
+}
+
+/* Flush the TF params and the TF plat params */
+void bl2_plat_flush_bl31_params(void)
+{
+       flush_dcache_range((unsigned long)&bl31_params_mem,
+                       sizeof(bl2_to_bl31_params_mem_t));
+}
+
+/*****************************************************************************
+ * This function returns a pointer to the shared memory that the platform
+ * has kept to point to entry point information of BL31 to BL2
+ *****************************************************************************
+ */
+struct entry_point_info *bl2_plat_get_bl31_ep_info(void)
+{
+#if DEBUG
+       bl31_params_mem.bl31_ep_info.args.arg1 = MARVELL_BL31_PLAT_PARAM_VAL;
+#endif
+
+       return &bl31_params_mem.bl31_ep_info;
+}
+
+/*****************************************************************************
+ * BL1 has passed the extents of the trusted SRAM that should be visible to BL2
+ * in x0. This memory layout is sitting at the base of the free trusted SRAM.
+ * Copy it to a safe location before its reclaimed by later BL2 functionality.
+ *****************************************************************************
+ */
+void marvell_bl2_early_platform_setup(meminfo_t *mem_layout)
+{
+       /* Initialize the console to provide early debug support */
+       console_init(PLAT_MARVELL_BOOT_UART_BASE,
+                    PLAT_MARVELL_BOOT_UART_CLK_IN_HZ,
+                    MARVELL_CONSOLE_BAUDRATE);
+
+       /* Setup the BL2 memory layout */
+       bl2_tzram_layout = *mem_layout;
+
+       /* Initialise the IO layer and register platform IO devices */
+       plat_marvell_io_setup();
+}
+
+void bl2_early_platform_setup(meminfo_t *mem_layout)
+{
+       marvell_bl2_early_platform_setup(mem_layout);
+}
+
+void bl2_platform_setup(void)
+{
+       /* Nothing to do */
+}
+
+/*****************************************************************************
+ * Perform the very early platform specific architectural setup here. At the
+ * moment this is only initializes the mmu in a quick and dirty way.
+ *****************************************************************************
+ */
+void marvell_bl2_plat_arch_setup(void)
+{
+       marvell_setup_page_tables(bl2_tzram_layout.total_base,
+                                 bl2_tzram_layout.total_size,
+                                 BL_CODE_BASE,
+                                 BL_CODE_END,
+                                 BL_RO_DATA_BASE,
+                                 BL_RO_DATA_END
+#if USE_COHERENT_MEM
+                               , BL_COHERENT_RAM_BASE,
+                                 BL_COHERENT_RAM_END
+#endif
+                             );
+       enable_mmu_el1(0);
+}
+
+void bl2_plat_arch_setup(void)
+{
+       marvell_bl2_plat_arch_setup();
+}
+
+/*****************************************************************************
+ * Populate the extents of memory available for loading SCP_BL2 (if used),
+ * i.e. anywhere in trusted RAM as long as it doesn't overwrite BL2.
+ *****************************************************************************
+ */
+void bl2_plat_get_scp_bl2_meminfo(meminfo_t *scp_bl2_meminfo)
+{
+       *scp_bl2_meminfo = bl2_tzram_layout;
+}
+
+/*****************************************************************************
+ * Before calling this function BL31 is loaded in memory and its entrypoint
+ * is set by load_image. This is a placeholder for the platform to change
+ * the entrypoint of BL31 and set SPSR and security state.
+ * On MARVELL std. platforms we only set the security state of the entrypoint
+ *****************************************************************************
+ */
+void bl2_plat_set_bl31_ep_info(image_info_t *bl31_image_info,
+                              entry_point_info_t *bl31_ep_info)
+{
+       SET_SECURITY_STATE(bl31_ep_info->h.attr, SECURE);
+       bl31_ep_info->spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
+                                       DISABLE_ALL_EXCEPTIONS);
+}
+
+/*****************************************************************************
+ * Populate the extents of memory available for loading BL32
+ *****************************************************************************
+ */
+#ifdef BL32_BASE
+void bl2_plat_get_bl32_meminfo(meminfo_t *bl32_meminfo)
+{
+       /*
+        * Populate the extents of memory available for loading BL32.
+        */
+       bl32_meminfo->total_base = BL32_BASE;
+       bl32_meminfo->free_base = BL32_BASE;
+       bl32_meminfo->total_size =
+                       (TRUSTED_DRAM_BASE + TRUSTED_DRAM_SIZE) - BL32_BASE;
+       bl32_meminfo->free_size =
+                       (TRUSTED_DRAM_BASE + TRUSTED_DRAM_SIZE) - BL32_BASE;
+}
+#endif
+
+/*****************************************************************************
+ * Before calling this function BL32 is loaded in memory and its entrypoint
+ * is set by load_image. This is a placeholder for the platform to change
+ * the entrypoint of BL32 and set SPSR and security state.
+ * On MARVELL std. platforms we only set the security state of the entrypoint
+ *****************************************************************************
+ */
+void bl2_plat_set_bl32_ep_info(image_info_t *bl32_image_info,
+                              entry_point_info_t *bl32_ep_info)
+{
+       SET_SECURITY_STATE(bl32_ep_info->h.attr, SECURE);
+       bl32_ep_info->spsr = marvell_get_spsr_for_bl32_entry();
+}
+
+/*****************************************************************************
+ * Before calling this function BL33 is loaded in memory and its entrypoint
+ * is set by load_image. This is a placeholder for the platform to change
+ * the entrypoint of BL33 and set SPSR and security state.
+ * On MARVELL std. platforms we only set the security state of the entrypoint
+ *****************************************************************************
+ */
+void bl2_plat_set_bl33_ep_info(image_info_t *image,
+                              entry_point_info_t *bl33_ep_info)
+{
+
+       SET_SECURITY_STATE(bl33_ep_info->h.attr, NON_SECURE);
+       bl33_ep_info->spsr = marvell_get_spsr_for_bl33_entry();
+}
+
+/*****************************************************************************
+ * Populate the extents of memory available for loading BL33
+ *****************************************************************************
+ */
+void bl2_plat_get_bl33_meminfo(meminfo_t *bl33_meminfo)
+{
+       bl33_meminfo->total_base = MARVELL_DRAM_BASE;
+       bl33_meminfo->total_size = MARVELL_DRAM_SIZE;
+       bl33_meminfo->free_base = MARVELL_DRAM_BASE;
+       bl33_meminfo->free_size = MARVELL_DRAM_SIZE;
+}
diff --git a/plat/marvell/common/marvell_bl31_setup.c b/plat/marvell/common/marvell_bl31_setup.c
new file mode 100644 (file)
index 0000000..a74816b
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <arch.h>
+#include <assert.h>
+#include <console.h>
+#include <debug.h>
+#include <marvell_def.h>
+#include <marvell_plat_priv.h>
+#include <plat_marvell.h>
+#include <platform.h>
+
+#ifdef USE_CCI
+#include <cci.h>
+#endif
+
+/*
+ * The next 3 constants identify the extents of the code, RO data region and the
+ * limit of the BL31 image.  These addresses are used by the MMU setup code and
+ * therefore they must be page-aligned.  It is the responsibility of the linker
+ * script to ensure that __RO_START__, __RO_END__ & __BL31_END__ linker symbols
+ * refer to page-aligned addresses.
+ */
+#define BL31_END (unsigned long)(&__BL31_END__)
+
+/*
+ * Placeholder variables for copying the arguments that have been passed to
+ * BL31 from BL2.
+ */
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+/* Weak definitions may be overridden in specific ARM standard platform */
+#pragma weak bl31_early_platform_setup
+#pragma weak bl31_platform_setup
+#pragma weak bl31_plat_arch_setup
+#pragma weak bl31_plat_get_next_image_ep_info
+#pragma weak plat_get_syscnt_freq2
+
+/*****************************************************************************
+ * Return a pointer to the 'entry_point_info' structure of the next image for
+ * the security state specified. BL33 corresponds to the non-secure image type
+ * while BL32 corresponds to the secure image type. A NULL pointer is returned
+ * if the image does not exist.
+ *****************************************************************************
+ */
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+       entry_point_info_t *next_image_info;
+
+       assert(sec_state_is_valid(type));
+       next_image_info = (type == NON_SECURE)
+                       ? &bl33_image_ep_info : &bl32_image_ep_info;
+
+       return next_image_info;
+}
+
+/*****************************************************************************
+ * Perform any BL31 early platform setup common to ARM standard platforms.
+ * Here is an opportunity to copy parameters passed by the calling EL (S-EL1
+ * in BL2 & S-EL3 in BL1) before they are lost (potentially). This needs to be
+ * done before the MMU is initialized so that the memory layout can be used
+ * while creating page tables. BL2 has flushed this information to memory, so
+ * we are guaranteed to pick up good data.
+ *****************************************************************************
+ */
+void marvell_bl31_early_platform_setup(bl31_params_t *from_bl2,
+                               void *plat_params_from_bl2)
+{
+       /* Initialize the console to provide early debug support */
+       console_init(PLAT_MARVELL_BOOT_UART_BASE,
+                    PLAT_MARVELL_BOOT_UART_CLK_IN_HZ,
+                    MARVELL_CONSOLE_BAUDRATE);
+
+#if RESET_TO_BL31
+       /* There are no parameters from BL2 if BL31 is a reset vector */
+       assert(from_bl2 == NULL);
+       assert(plat_params_from_bl2 == NULL);
+
+#ifdef BL32_BASE
+       /* Populate entry point information for BL32 */
+       SET_PARAM_HEAD(&bl32_image_ep_info,
+                               PARAM_EP,
+                               VERSION_1,
+                               0);
+       SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE);
+       bl32_image_ep_info.pc = BL32_BASE;
+       bl32_image_ep_info.spsr = marvell_get_spsr_for_bl32_entry();
+#endif /* BL32_BASE */
+
+       /* Populate entry point information for BL33 */
+       SET_PARAM_HEAD(&bl33_image_ep_info,
+                               PARAM_EP,
+                               VERSION_1,
+                               0);
+       /*
+        * Tell BL31 where the non-trusted software image
+        * is located and the entry state information
+        */
+       bl33_image_ep_info.pc = plat_get_ns_image_entrypoint();
+       bl33_image_ep_info.spsr = marvell_get_spsr_for_bl33_entry();
+       SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+
+#else
+       /*
+        * Check params passed from BL2 should not be NULL,
+        */
+       assert(from_bl2 != NULL);
+       assert(from_bl2->h.type == PARAM_BL31);
+       assert(from_bl2->h.version >= VERSION_1);
+       /*
+        * In debug builds, we pass a special value in 'plat_params_from_bl2'
+        * to verify platform parameters from BL2 to BL31.
+        * In release builds, it's not used.
+        */
+       assert(((unsigned long long)plat_params_from_bl2) ==
+               MARVELL_BL31_PLAT_PARAM_VAL);
+
+       /*
+        * Copy BL32 (if populated by BL2) and BL33 entry point information.
+        * They are stored in Secure RAM, in BL2's address space.
+        */
+       if (from_bl2->bl32_ep_info)
+               bl32_image_ep_info = *from_bl2->bl32_ep_info;
+       bl33_image_ep_info = *from_bl2->bl33_ep_info;
+#endif
+}
+
+void bl31_early_platform_setup(bl31_params_t *from_bl2,
+                               void *plat_params_from_bl2)
+{
+       marvell_bl31_early_platform_setup(from_bl2, plat_params_from_bl2);
+
+#ifdef USE_CCI
+       /*
+        * Initialize CCI for this cluster during cold boot.
+        * No need for locks as no other CPU is active.
+        */
+       plat_marvell_interconnect_init();
+
+       /*
+        * Enable CCI coherency for the primary CPU's cluster.
+        * Platform specific PSCI code will enable coherency for other
+        * clusters.
+        */
+       plat_marvell_interconnect_enter_coherency();
+#endif
+}
+
+/*****************************************************************************
+ * Perform any BL31 platform setup common to ARM standard platforms
+ *****************************************************************************
+ */
+void marvell_bl31_platform_setup(void)
+{
+       /* Initialize the GIC driver, cpu and distributor interfaces */
+       plat_marvell_gic_driver_init();
+       plat_marvell_gic_init();
+
+       /* For Armada-8k-plus family, the SoC includes more than
+        * a single AP die, but the default die that boots is AP #0.
+        * For other families there is only one die (#0).
+        * Initialize psci arch from die 0
+        */
+       marvell_psci_arch_init(0);
+}
+
+/*****************************************************************************
+ * Perform any BL31 platform runtime setup prior to BL31 exit common to ARM
+ * standard platforms
+ *****************************************************************************
+ */
+void marvell_bl31_plat_runtime_setup(void)
+{
+       /* Initialize the runtime console */
+       console_init(PLAT_MARVELL_BL31_RUN_UART_BASE,
+                    PLAT_MARVELL_BL31_RUN_UART_CLK_IN_HZ,
+                    MARVELL_CONSOLE_BAUDRATE);
+}
+
+void bl31_platform_setup(void)
+{
+       marvell_bl31_platform_setup();
+}
+
+void bl31_plat_runtime_setup(void)
+{
+       marvell_bl31_plat_runtime_setup();
+}
+
+/*****************************************************************************
+ * Perform the very early platform specific architectural setup shared between
+ * ARM standard platforms. This only does basic initialization. Later
+ * architectural setup (bl31_arch_setup()) does not do anything platform
+ * specific.
+ *****************************************************************************
+ */
+void marvell_bl31_plat_arch_setup(void)
+{
+       marvell_setup_page_tables(BL31_BASE,
+                                 BL31_END - BL31_BASE,
+                                 BL_CODE_BASE,
+                                 BL_CODE_END,
+                                 BL_RO_DATA_BASE,
+                                 BL_RO_DATA_END
+#if USE_COHERENT_MEM
+                               , BL_COHERENT_RAM_BASE,
+                                 BL_COHERENT_RAM_END
+#endif
+                       );
+
+#if BL31_CACHE_DISABLE
+       enable_mmu_el3(DISABLE_DCACHE);
+       INFO("Cache is disabled in BL3\n");
+#else
+       enable_mmu_el3(0);
+#endif
+}
+
+void bl31_plat_arch_setup(void)
+{
+       marvell_bl31_plat_arch_setup();
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+       return PLAT_REF_CLK_IN_HZ;
+}
diff --git a/plat/marvell/common/marvell_cci.c b/plat/marvell/common/marvell_cci.c
new file mode 100644 (file)
index 0000000..2df4802
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <cci.h>
+#include <plat_marvell.h>
+
+static const int cci_map[] = {
+       PLAT_MARVELL_CCI_CLUSTER0_SL_IFACE_IX,
+       PLAT_MARVELL_CCI_CLUSTER1_SL_IFACE_IX
+};
+
+/****************************************************************************
+ * The following functions are defined as weak to allow a platform to override
+ * the way ARM CCI driver is initialised and used.
+ ****************************************************************************
+ */
+#pragma weak plat_marvell_interconnect_init
+#pragma weak plat_marvell_interconnect_enter_coherency
+#pragma weak plat_marvell_interconnect_exit_coherency
+
+
+/****************************************************************************
+ * Helper function to initialize ARM CCI driver.
+ ****************************************************************************
+ */
+void plat_marvell_interconnect_init(void)
+{
+       cci_init(PLAT_MARVELL_CCI_BASE, cci_map, ARRAY_SIZE(cci_map));
+}
+
+/****************************************************************************
+ * Helper function to place current master into coherency
+ ****************************************************************************
+ */
+void plat_marvell_interconnect_enter_coherency(void)
+{
+       cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+}
+
+/****************************************************************************
+ * Helper function to remove current master from coherency
+ ****************************************************************************
+ */
+void plat_marvell_interconnect_exit_coherency(void)
+{
+       cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+}
diff --git a/plat/marvell/common/marvell_common.mk b/plat/marvell/common/marvell_common.mk
new file mode 100644 (file)
index 0000000..3ee2f3d
--- /dev/null
@@ -0,0 +1,67 @@
+# Copyright (C) 2018 Marvell International Ltd.
+#
+# SPDX-License-Identifier:     BSD-3-Clause
+# https://spdx.org/licenses
+
+MARVELL_PLAT_BASE              := plat/marvell
+MARVELL_PLAT_INCLUDE_BASE      := include/plat/marvell
+
+include $(MARVELL_PLAT_BASE)/version.mk
+include $(MARVELL_PLAT_BASE)/marvell.mk
+
+VERSION_STRING                 +=(Marvell-${SUBVERSION})
+
+SEPARATE_CODE_AND_RODATA       := 1
+
+# flag to switch from PLL to ARO
+ARO_ENABLE                     := 0
+$(eval $(call add_define,ARO_ENABLE))
+# Enable/Disable LLC
+LLC_ENABLE                     := 1
+$(eval $(call add_define,LLC_ENABLE))
+
+PLAT_INCLUDES          +=      -I. -Iinclude/common/tbbr               \
+                               -I$(MARVELL_PLAT_INCLUDE_BASE)/common   \
+                               -I$(MARVELL_PLAT_INCLUDE_BASE)/common/aarch64
+
+
+PLAT_BL_COMMON_SOURCES  +=      lib/xlat_tables/xlat_tables_common.c                   \
+                               lib/xlat_tables/aarch64/xlat_tables.c                   \
+                               $(MARVELL_PLAT_BASE)/common/aarch64/marvell_common.c    \
+                               $(MARVELL_PLAT_BASE)/common/aarch64/marvell_helpers.S
+
+BL1_SOURCES            +=      drivers/delay_timer/delay_timer.c                       \
+                               drivers/io/io_fip.c                                     \
+                               drivers/io/io_memmap.c                                  \
+                               drivers/io/io_storage.c                                 \
+                               $(MARVELL_PLAT_BASE)/common/marvell_bl1_setup.c         \
+                               $(MARVELL_PLAT_BASE)/common/marvell_io_storage.c        \
+                               $(MARVELL_PLAT_BASE)/common/plat_delay_timer.c
+
+ifdef EL3_PAYLOAD_BASE
+# Need the arm_program_trusted_mailbox() function to release secondary CPUs from
+# their holding pen
+endif
+
+BL2_SOURCES            +=      drivers/io/io_fip.c                                     \
+                               drivers/io/io_memmap.c                                  \
+                               drivers/io/io_storage.c                                 \
+                               $(MARVELL_PLAT_BASE)/common/marvell_bl2_setup.c         \
+                               $(MARVELL_PLAT_BASE)/common/marvell_io_storage.c
+
+BL31_SOURCES           +=      $(MARVELL_PLAT_BASE)/common/marvell_bl31_setup.c        \
+                               $(MARVELL_PLAT_BASE)/common/marvell_pm.c                \
+                               $(MARVELL_PLAT_BASE)/common/marvell_topology.c          \
+                               plat/common/plat_psci_common.c                          \
+                               $(MARVELL_PLAT_BASE)/common/plat_delay_timer.c          \
+                               drivers/delay_timer/delay_timer.c
+
+# PSCI functionality
+$(eval $(call add_define,CONFIG_ARM64))
+
+# MSS (SCP) build
+ifeq (${MSS_SUPPORT}, 1)
+include $(MARVELL_PLAT_BASE)/common/mss/mss_common.mk
+endif
+
+fip: mrvl_flash
diff --git a/plat/marvell/common/marvell_ddr_info.c b/plat/marvell/common/marvell_ddr_info.c
new file mode 100644 (file)
index 0000000..68bff99
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <debug.h>
+#include <platform_def.h>
+#include <ddr_info.h>
+#include <mmio.h>
+
+#define DRAM_CH0_MMAP_LOW_REG(iface, cs, base) \
+       (base + DRAM_CH0_MMAP_LOW_OFFSET + (iface) * 0x10000 + (cs) * 0x8)
+#define DRAM_CH0_MMAP_HIGH_REG(iface, cs, base)        \
+       (DRAM_CH0_MMAP_LOW_REG(iface, cs, base) + 4)
+#define DRAM_CS_VALID_ENABLED_MASK             0x1
+#define DRAM_AREA_LENGTH_OFFS                  16
+#define DRAM_AREA_LENGTH_MASK                  (0x1f << DRAM_AREA_LENGTH_OFFS)
+#define DRAM_START_ADDRESS_L_OFFS              23
+#define DRAM_START_ADDRESS_L_MASK              \
+                                       (0x1ff << DRAM_START_ADDRESS_L_OFFS)
+#define DRAM_START_ADDR_HTOL_OFFS              32
+
+#define DRAM_MAX_CS_NUM                                2
+
+#define DRAM_CS_ENABLED(iface, cs, base) \
+       (mmio_read_32(DRAM_CH0_MMAP_LOW_REG(iface, cs, base)) & \
+        DRAM_CS_VALID_ENABLED_MASK)
+#define GET_DRAM_REGION_SIZE_CODE(iface, cs, base) \
+       (mmio_read_32(DRAM_CH0_MMAP_LOW_REG(iface, cs, base)) & \
+       DRAM_AREA_LENGTH_MASK) >> DRAM_AREA_LENGTH_OFFS
+
+/* Mapping between DDR area length and real DDR size is specific and looks like
+ * bellow:
+ * 0 => 384 MB
+ * 1 => 768 MB
+ * 2 => 1536 MB
+ * 3 => 3 GB
+ * 4 => 6 GB
+ *
+ * 7 => 8 MB
+ * 8 => 16 MB
+ * 9 => 32 MB
+ * 10 => 64 MB
+ * 11 => 128 MB
+ * 12 => 256 MB
+ * 13 => 512 MB
+ * 14 => 1 GB
+ * 15 => 2 GB
+ * 16 => 4 GB
+ * 17 => 8 GB
+ * 18 => 16 GB
+ * 19 => 32 GB
+ * 20 => 64 GB
+ * 21 => 128 GB
+ * 22 => 256 GB
+ * 23 => 512 GB
+ * 24 => 1 TB
+ * 25 => 2 TB
+ * 26 => 4 TB
+ *
+ * to calculate real size we need to use two different formulas:
+ * -- GET_DRAM_REGION_SIZE_ODD for values 0-4 (DRAM_REGION_SIZE_ODD)
+ * -- GET_DRAM_REGION_SIZE_EVEN for values 7-26 (DRAM_REGION_SIZE_EVEN)
+ * using mentioned formulas we cover whole mapping between "Area length" value
+ * and real size (see above mapping).
+ */
+#define DRAM_REGION_SIZE_EVEN(C)       (((C) >= 7) && ((C) <= 26))
+#define GET_DRAM_REGION_SIZE_EVEN(C)   ((uint64_t)1 << ((C) + 16))
+#define DRAM_REGION_SIZE_ODD(C)                ((C) <= 4)
+#define GET_DRAM_REGION_SIZE_ODD(C)    ((uint64_t)0x18000000 << (C))
+
+
+uint64_t mvebu_get_dram_size(uint64_t ap_base_addr)
+{
+       uint64_t mem_size = 0;
+       uint8_t region_code;
+       uint8_t cs, iface;
+
+       for (iface = 0; iface < DRAM_MAX_IFACE; iface++) {
+               for (cs = 0; cs < DRAM_MAX_CS_NUM; cs++) {
+
+                       /* Exit loop on first disabled DRAM CS */
+                       if (!DRAM_CS_ENABLED(iface, cs, ap_base_addr))
+                               break;
+
+                       /* Decode area length for current CS
+                        * from register value
+                        */
+                       region_code =
+                               GET_DRAM_REGION_SIZE_CODE(iface, cs,
+                                                         ap_base_addr);
+
+                       if (DRAM_REGION_SIZE_EVEN(region_code)) {
+                               mem_size +=
+                                       GET_DRAM_REGION_SIZE_EVEN(region_code);
+                       } else if (DRAM_REGION_SIZE_ODD(region_code)) {
+                               mem_size +=
+                                       GET_DRAM_REGION_SIZE_ODD(region_code);
+                       } else {
+                               WARN("%s: Invalid mem region (0x%x) CS#%d\n",
+                                     __func__, region_code, cs);
+                               return 0;
+                       }
+               }
+       }
+
+       return mem_size;
+}
diff --git a/plat/marvell/common/marvell_gicv2.c b/plat/marvell/common/marvell_gicv2.c
new file mode 100644 (file)
index 0000000..ba8e409
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <gicv2.h>
+#include <plat_marvell.h>
+#include <platform.h>
+#include <platform_def.h>
+
+/*
+ * The following functions are defined as weak to allow a platform to override
+ * the way the GICv2 driver is initialised and used.
+ */
+#pragma weak plat_marvell_gic_driver_init
+#pragma weak plat_marvell_gic_init
+
+/*
+ * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0
+ * interrupts.
+ */
+static const interrupt_prop_t marvell_interrupt_props[] = {
+       PLAT_MARVELL_G1S_IRQ_PROPS(GICV2_INTR_GROUP0),
+       PLAT_MARVELL_G0_IRQ_PROPS(GICV2_INTR_GROUP0)
+};
+
+static unsigned int target_mask_array[PLATFORM_CORE_COUNT];
+
+/*
+ * Ideally `marvell_gic_data` structure definition should be a `const` but it is
+ * kept as modifiable for overwriting with different GICD and GICC base when
+ * running on FVP with VE memory map.
+ */
+static gicv2_driver_data_t marvell_gic_data = {
+       .gicd_base = PLAT_MARVELL_GICD_BASE,
+       .gicc_base = PLAT_MARVELL_GICC_BASE,
+       .interrupt_props = marvell_interrupt_props,
+       .interrupt_props_num = ARRAY_SIZE(marvell_interrupt_props),
+       .target_masks = target_mask_array,
+       .target_masks_num = ARRAY_SIZE(target_mask_array),
+};
+
+/*
+ * ARM common helper to initialize the GICv2 only driver.
+ */
+void plat_marvell_gic_driver_init(void)
+{
+       gicv2_driver_init(&marvell_gic_data);
+}
+
+void plat_marvell_gic_init(void)
+{
+       gicv2_distif_init();
+       gicv2_pcpu_distif_init();
+       gicv2_set_pe_target_mask(plat_my_core_pos());
+       gicv2_cpuif_enable();
+}
diff --git a/plat/marvell/common/marvell_io_storage.c b/plat/marvell/common/marvell_io_storage.c
new file mode 100644 (file)
index 0000000..cb9ece2
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <assert.h>
+#include <bl_common.h>         /* For ARRAY_SIZE */
+#include <debug.h>
+#include <firmware_image_package.h>
+#include <io_driver.h>
+#include <io_fip.h>
+#include <io_memmap.h>
+#include <io_storage.h>
+#include <platform_def.h>
+#include <string.h>
+
+/* IO devices */
+static const io_dev_connector_t *fip_dev_con;
+static uintptr_t fip_dev_handle;
+static const io_dev_connector_t *memmap_dev_con;
+static uintptr_t memmap_dev_handle;
+
+static const io_block_spec_t fip_block_spec = {
+       .offset = PLAT_MARVELL_FIP_BASE,
+       .length = PLAT_MARVELL_FIP_MAX_SIZE
+};
+
+static const io_uuid_spec_t bl2_uuid_spec = {
+       .uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2,
+};
+
+static const io_uuid_spec_t scp_bl2_uuid_spec = {
+       .uuid = UUID_SCP_FIRMWARE_SCP_BL2,
+};
+
+static const io_uuid_spec_t bl31_uuid_spec = {
+       .uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31,
+};
+static const io_uuid_spec_t bl32_uuid_spec = {
+       .uuid = UUID_SECURE_PAYLOAD_BL32,
+};
+static const io_uuid_spec_t bl33_uuid_spec = {
+       .uuid = UUID_NON_TRUSTED_FIRMWARE_BL33,
+};
+
+static int open_fip(const uintptr_t spec);
+static int open_memmap(const uintptr_t spec);
+
+struct plat_io_policy {
+       uintptr_t *dev_handle;
+       uintptr_t image_spec;
+       int (*check)(const uintptr_t spec);
+};
+
+/* By default, Marvell platforms load images from the FIP */
+static const struct plat_io_policy policies[] = {
+       [FIP_IMAGE_ID] = {
+               &memmap_dev_handle,
+               (uintptr_t)&fip_block_spec,
+               open_memmap
+       },
+       [BL2_IMAGE_ID] = {
+               &fip_dev_handle,
+               (uintptr_t)&bl2_uuid_spec,
+               open_fip
+       },
+       [SCP_BL2_IMAGE_ID] = {
+               &fip_dev_handle,
+               (uintptr_t)&scp_bl2_uuid_spec,
+               open_fip
+       },
+       [BL31_IMAGE_ID] = {
+               &fip_dev_handle,
+               (uintptr_t)&bl31_uuid_spec,
+               open_fip
+       },
+       [BL32_IMAGE_ID] = {
+               &fip_dev_handle,
+               (uintptr_t)&bl32_uuid_spec,
+               open_fip
+       },
+       [BL33_IMAGE_ID] = {
+               &fip_dev_handle,
+               (uintptr_t)&bl33_uuid_spec,
+               open_fip
+       },
+};
+
+
+/* Weak definitions may be overridden in specific ARM standard platform */
+#pragma weak plat_marvell_io_setup
+#pragma weak plat_marvell_get_alt_image_source
+
+
+static int open_fip(const uintptr_t spec)
+{
+       int result;
+       uintptr_t local_image_handle;
+
+       /* See if a Firmware Image Package is available */
+       result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID);
+       if (result == 0) {
+               result = io_open(fip_dev_handle, spec, &local_image_handle);
+               if (result == 0) {
+                       VERBOSE("Using FIP\n");
+                       io_close(local_image_handle);
+               }
+       }
+       return result;
+}
+
+
+static int open_memmap(const uintptr_t spec)
+{
+       int result;
+       uintptr_t local_image_handle;
+
+       result = io_dev_init(memmap_dev_handle, (uintptr_t)NULL);
+       if (result == 0) {
+               result = io_open(memmap_dev_handle, spec, &local_image_handle);
+               if (result == 0) {
+                       VERBOSE("Using Memmap\n");
+                       io_close(local_image_handle);
+               }
+       }
+       return result;
+}
+
+
+void marvell_io_setup(void)
+{
+       int io_result;
+
+       io_result = register_io_dev_fip(&fip_dev_con);
+       assert(io_result == 0);
+
+       io_result = register_io_dev_memmap(&memmap_dev_con);
+       assert(io_result == 0);
+
+       /* Open connections to devices and cache the handles */
+       io_result = io_dev_open(fip_dev_con, (uintptr_t)NULL,
+                               &fip_dev_handle);
+       assert(io_result == 0);
+
+       io_result = io_dev_open(memmap_dev_con, (uintptr_t)NULL,
+                               &memmap_dev_handle);
+       assert(io_result == 0);
+
+       /* Ignore improbable errors in release builds */
+       (void)io_result;
+}
+
+void plat_marvell_io_setup(void)
+{
+       marvell_io_setup();
+}
+
+int plat_marvell_get_alt_image_source(
+       unsigned int image_id __attribute__((unused)),
+       uintptr_t *dev_handle __attribute__((unused)),
+       uintptr_t *image_spec __attribute__((unused)))
+{
+       /* By default do not try an alternative */
+       return -ENOENT;
+}
+
+/*
+ * Return an IO device handle and specification which can be used to access
+ * an image. Use this to enforce platform load policy
+ */
+int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
+                         uintptr_t *image_spec)
+{
+       int result;
+       const struct plat_io_policy *policy;
+
+       assert(image_id < ARRAY_SIZE(policies));
+
+       policy = &policies[image_id];
+       result = policy->check(policy->image_spec);
+       if (result == 0) {
+               *image_spec = policy->image_spec;
+               *dev_handle = *(policy->dev_handle);
+       } else {
+               VERBOSE("Trying alternative IO\n");
+               result = plat_marvell_get_alt_image_source(image_id, dev_handle,
+                                                      image_spec);
+       }
+
+       return result;
+}
+
+/*
+ * See if a Firmware Image Package is available,
+ * by checking if TOC is valid or not.
+ */
+int marvell_io_is_toc_valid(void)
+{
+       int result;
+
+       result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID);
+
+       return result == 0;
+}
diff --git a/plat/marvell/common/marvell_pm.c b/plat/marvell/common/marvell_pm.c
new file mode 100644 (file)
index 0000000..2a75790
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <psci.h>
+#include <marvell_pm.h>
+
+/* Standard ARM platforms are expected to export plat_arm_psci_pm_ops */
+extern const plat_psci_ops_t plat_arm_psci_pm_ops;
+
+/*****************************************************************************
+ * Private function to program the mailbox for a cpu before it is released
+ * from reset. This function assumes that the mail box base is within
+ * the MARVELL_SHARED_RAM region
+ *****************************************************************************
+ */
+void marvell_program_mailbox(uintptr_t address)
+{
+       uintptr_t *mailbox = (void *)PLAT_MARVELL_MAILBOX_BASE;
+
+       /*
+        * Ensure that the PLAT_MARVELL_MAILBOX_BASE is within
+        * MARVELL_SHARED_RAM region.
+        */
+       assert((PLAT_MARVELL_MAILBOX_BASE >= MARVELL_SHARED_RAM_BASE) &&
+              ((PLAT_MARVELL_MAILBOX_BASE + sizeof(*mailbox)) <=
+              (MARVELL_SHARED_RAM_BASE + MARVELL_SHARED_RAM_SIZE)));
+
+       mailbox[MBOX_IDX_MAGIC] = MVEBU_MAILBOX_MAGIC_NUM;
+       mailbox[MBOX_IDX_SEC_ADDR] = address;
+
+       /* Flush data cache if the mail box shared RAM is cached */
+#if PLAT_MARVELL_SHARED_RAM_CACHED
+       flush_dcache_range((uintptr_t)PLAT_MARVELL_MAILBOX_BASE +
+                          8 * MBOX_IDX_MAGIC,
+                          2 * sizeof(uint64_t));
+#endif
+}
+
+/*****************************************************************************
+ * The ARM Standard platform definition of platform porting API
+ * `plat_setup_psci_ops`.
+ *****************************************************************************
+ */
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+                       const plat_psci_ops_t **psci_ops)
+{
+       *psci_ops = &plat_arm_psci_pm_ops;
+
+       /* Setup mailbox with entry point. */
+       marvell_program_mailbox(sec_entrypoint);
+       return 0;
+}
diff --git a/plat/marvell/common/marvell_topology.c b/plat/marvell/common/marvell_topology.c
new file mode 100644 (file)
index 0000000..a40ff6f
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <plat_marvell.h>
+
+/* The power domain tree descriptor */
+unsigned char marvell_power_domain_tree_desc[PLAT_MARVELL_CLUSTER_COUNT + 1];
+
+/*****************************************************************************
+ * This function dynamically constructs the topology according to
+ * PLAT_MARVELL_CLUSTER_COUNT and returns it.
+ *****************************************************************************
+ */
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+       int i;
+
+       /*
+        * The power domain tree does not have a single system level power
+        * domain i.e. a single root node. The first entry in the power domain
+        * descriptor specifies the number of power domains at the highest power
+        * level.
+        * For Marvell Platform this is the number of cluster power domains.
+        */
+       marvell_power_domain_tree_desc[0] = PLAT_MARVELL_CLUSTER_COUNT;
+
+       for (i = 0; i < PLAT_MARVELL_CLUSTER_COUNT; i++)
+               marvell_power_domain_tree_desc[i + 1] =
+                                       PLAT_MARVELL_CLUSTER_CORE_COUNT;
+
+       return marvell_power_domain_tree_desc;
+}
+
+/*****************************************************************************
+ * This function validates an MPIDR by checking whether it falls within the
+ * acceptable bounds. An error code (-1) is returned if an incorrect mpidr
+ * is passed.
+ *****************************************************************************
+ */
+int marvell_check_mpidr(u_register_t mpidr)
+{
+       unsigned int nb_id, cluster_id, cpu_id;
+
+       mpidr &= MPIDR_AFFINITY_MASK;
+
+       if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK |
+           MPIDR_AFFLVL_MASK << MPIDR_AFF2_SHIFT))
+               return -1;
+
+       /* Get north bridge ID */
+       nb_id = MPIDR_AFFLVL3_VAL(mpidr);
+       cluster_id = MPIDR_AFFLVL1_VAL(mpidr);
+       cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
+
+       if (nb_id >= PLAT_MARVELL_CLUSTER_COUNT)
+               return -1;
+
+       if (cluster_id >= PLAT_MARVELL_CLUSTER_COUNT)
+               return -1;
+
+       if (cpu_id >= PLAT_MARVELL_CLUSTER_CORE_COUNT)
+               return -1;
+
+       return 0;
+}
+
+/*****************************************************************************
+ * This function implements a part of the critical interface between the PSCI
+ * generic layer and the platform that allows the former to query the platform
+ * to convert an MPIDR to a unique linear index. An error code (-1) is returned
+ * in case the MPIDR is invalid.
+ *****************************************************************************
+ */
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+       if (marvell_check_mpidr(mpidr) == -1)
+               return -1;
+
+       return plat_marvell_calc_core_pos(mpidr);
+}
diff --git a/plat/marvell/common/mrvl_sip_svc.c b/plat/marvell/common/mrvl_sip_svc.c
new file mode 100644 (file)
index 0000000..ec293af
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <ap_setup.h>
+#include <cache_llc.h>
+#include <debug.h>
+#include <marvell_plat_priv.h>
+#include <runtime_svc.h>
+#include <smcc.h>
+#include "comphy/phy-comphy-cp110.h"
+
+/* #define DEBUG_COMPHY */
+#ifdef DEBUG_COMPHY
+#define debug(format...) NOTICE(format)
+#else
+#define debug(format, arg...)
+#endif
+
+/* Comphy related FID's */
+#define MV_SIP_COMPHY_POWER_ON 0x82000001
+#define MV_SIP_COMPHY_POWER_OFF        0x82000002
+#define MV_SIP_COMPHY_PLL_LOCK 0x82000003
+#define MV_SIP_COMPHY_XFI_TRAIN        0x82000004
+#define MV_SIP_COMPHY_DIG_RESET        0x82000005
+
+/* Miscellaneous FID's' */
+#define MV_SIP_DRAM_SIZE       0x82000010
+#define MV_SIP_LLC_ENABLE      0x82000011
+
+#define MAX_LANE_NR            6
+#define MVEBU_COMPHY_OFFSET    0x441000
+#define MVEBU_SD_OFFSET                0x120000
+
+/* This macro is used to identify COMPHY related calls from SMC function ID */
+#define is_comphy_fid(fid)     \
+       ((fid) >= MV_SIP_COMPHY_POWER_ON && (fid) <= MV_SIP_COMPHY_DIG_RESET)
+
+
+uintptr_t mrvl_sip_smc_handler(uint32_t smc_fid,
+                              u_register_t x1,
+                              u_register_t x2,
+                              u_register_t x3,
+                              u_register_t x4,
+                              void *cookie,
+                              void *handle,
+                              u_register_t flags)
+{
+       u_register_t ret;
+       int i;
+
+       debug("%s: got SMC (0x%x) x1 0x%lx, x2 0x%lx, x3 0x%lx\n",
+                                                __func__, smc_fid, x1, x2, x3);
+       if (is_comphy_fid(smc_fid)) {
+
+               /* some systems passes SD phys address instead of COMPHY phys
+                * address - convert it
+                */
+               if (x1 & MVEBU_SD_OFFSET)
+                       x1 = (x1 & ~0xffffff) + MVEBU_COMPHY_OFFSET;
+
+               if ((x1 & 0xffffff) != MVEBU_COMPHY_OFFSET) {
+                       ERROR("%s: Wrong smc (0x%x) address: %lx\n",
+                             __func__, smc_fid, x1);
+                       SMC_RET1(handle, SMC_UNK);
+               }
+
+               if (x2 >= MAX_LANE_NR) {
+                       ERROR("%s: Wrong smc (0x%x) lane nr: %lx\n",
+                             __func__, smc_fid, x2);
+                       SMC_RET1(handle, SMC_UNK);
+               }
+       }
+
+       switch (smc_fid) {
+
+       /* Comphy related FID's */
+       case MV_SIP_COMPHY_POWER_ON:
+               /* x1:  comphy_base, x2: comphy_index, x3: comphy_mode */
+               ret = mvebu_cp110_comphy_power_on(x1, x2, x3);
+               SMC_RET1(handle, ret);
+       case MV_SIP_COMPHY_POWER_OFF:
+               /* x1:  comphy_base, x2: comphy_index */
+               ret = mvebu_cp110_comphy_power_off(x1, x2);
+               SMC_RET1(handle, ret);
+       case MV_SIP_COMPHY_PLL_LOCK:
+               /* x1:  comphy_base, x2: comphy_index */
+               ret = mvebu_cp110_comphy_is_pll_locked(x1, x2);
+               SMC_RET1(handle, ret);
+       case MV_SIP_COMPHY_XFI_TRAIN:
+               /* x1:  comphy_base, x2: comphy_index */
+               ret = mvebu_cp110_comphy_xfi_rx_training(x1, x2);
+               SMC_RET1(handle, ret);
+       case MV_SIP_COMPHY_DIG_RESET:
+               /* x1:  comphy_base, x2: comphy_index, x3: mode, x4: command */
+               ret = mvebu_cp110_comphy_digital_reset(x1, x2, x3, x4);
+               SMC_RET1(handle, ret);
+
+       /* Miscellaneous FID's' */
+       case MV_SIP_DRAM_SIZE:
+               /* x1:  ap_base_addr */
+               ret = mvebu_get_dram_size(x1);
+               SMC_RET1(handle, ret);
+       case MV_SIP_LLC_ENABLE:
+               for (i = 0; i < ap_get_count(); i++)
+                       llc_runtime_enable(i);
+
+               SMC_RET1(handle, 0);
+
+       default:
+               ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
+               SMC_RET1(handle, SMC_UNK);
+       }
+}
+
+/* Define a runtime service descriptor for fast SMC calls */
+DECLARE_RT_SVC(
+       marvell_sip_svc,
+       OEN_SIP_START,
+       OEN_SIP_END,
+       SMC_TYPE_FAST,
+       NULL,
+       mrvl_sip_smc_handler
+);
diff --git a/plat/marvell/common/mss/mss_common.mk b/plat/marvell/common/mss/mss_common.mk
new file mode 100644 (file)
index 0000000..898b6dc
--- /dev/null
@@ -0,0 +1,20 @@
+#
+# Copyright (C) 2018 Marvell International Ltd.
+#
+# SPDX-License-Identifier:     BSD-3-Clause
+# https://spdx.org/licenses
+#
+
+
+PLAT_MARVELL           :=      plat/marvell
+MSS_SOURCE             :=      $(PLAT_MARVELL)/common/mss
+
+BL2_SOURCES            +=      $(MSS_SOURCE)/mss_scp_bootloader.c              \
+                               $(PLAT_MARVELL)/common/plat_delay_timer.c       \
+                               drivers/delay_timer/delay_timer.c               \
+                               $(MARVELL_DRV)                                  \
+                               $(PLAT_FAMILY_BASE)/$(PLAT)/board/marvell_plat_config.c
+
+BL31_SOURCES           +=      $(MSS_SOURCE)/mss_ipc_drv.c
+
+PLAT_INCLUDES           +=      -I$(MSS_SOURCE)
diff --git a/plat/marvell/common/mss/mss_ipc_drv.c b/plat/marvell/common/mss/mss_ipc_drv.c
new file mode 100644 (file)
index 0000000..731c315
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <plat_marvell.h>
+#include <debug.h>
+#include <string.h>
+#include <mss_ipc_drv.h>
+#include <mmio.h>
+
+#define IPC_MSG_BASE_MASK              MVEBU_REGS_BASE_MASK
+
+#define IPC_CH_NUM_OF_MSG              (16)
+#define IPC_CH_MSG_IDX                 (-1)
+
+unsigned long mv_pm_ipc_msg_base;
+unsigned int  mv_pm_ipc_queue_size;
+
+unsigned int msg_sync;
+int msg_index = IPC_CH_MSG_IDX;
+
+/******************************************************************************
+ * mss_pm_ipc_init
+ *
+ * DESCRIPTION: Initialize PM IPC infrastructure
+ ******************************************************************************
+ */
+int mv_pm_ipc_init(unsigned long ipc_control_addr)
+{
+       struct mss_pm_ipc_ctrl *ipc_control =
+                       (struct mss_pm_ipc_ctrl *)ipc_control_addr;
+
+       /* Initialize PM IPC control block */
+       mv_pm_ipc_msg_base     = ipc_control->msg_base_address |
+                                IPC_MSG_BASE_MASK;
+       mv_pm_ipc_queue_size   = ipc_control->queue_size;
+
+       return 0;
+}
+
+/******************************************************************************
+ * mv_pm_ipc_queue_addr_get
+ *
+ * DESCRIPTION: Returns the IPC queue address
+ ******************************************************************************
+ */
+unsigned int mv_pm_ipc_queue_addr_get(void)
+{
+       unsigned int addr;
+
+       inv_dcache_range((uint64_t)&msg_index, sizeof(msg_index));
+       msg_index = msg_index + 1;
+       if (msg_index >= IPC_CH_NUM_OF_MSG)
+               msg_index = 0;
+
+       addr = (unsigned int)(mv_pm_ipc_msg_base +
+              (msg_index * mv_pm_ipc_queue_size));
+
+       flush_dcache_range((uint64_t)&msg_index, sizeof(msg_index));
+
+       return addr;
+}
+
+/******************************************************************************
+ * mv_pm_ipc_msg_rx
+ *
+ * DESCRIPTION: Retrieve message from IPC channel
+ ******************************************************************************
+ */
+int mv_pm_ipc_msg_rx(unsigned int channel_id, struct mss_pm_ipc_msg *msg)
+{
+       unsigned int addr = mv_pm_ipc_queue_addr_get();
+
+       msg->msg_reply = mmio_read_32(addr + IPC_MSG_REPLY_LOC);
+
+       return 0;
+}
+
+/******************************************************************************
+ * mv_pm_ipc_msg_tx
+ *
+ * DESCRIPTION: Send message via IPC channel
+ ******************************************************************************
+ */
+int mv_pm_ipc_msg_tx(unsigned int channel_id, unsigned int msg_id,
+                                       unsigned int cluster_power_state)
+{
+       unsigned int addr = mv_pm_ipc_queue_addr_get();
+
+       /* Validate the entry for message placed by the host is free */
+       if (mmio_read_32(addr + IPC_MSG_STATE_LOC) == IPC_MSG_FREE) {
+               inv_dcache_range((uint64_t)&msg_sync, sizeof(msg_sync));
+               msg_sync = msg_sync + 1;
+               flush_dcache_range((uint64_t)&msg_sync, sizeof(msg_sync));
+
+               mmio_write_32(addr + IPC_MSG_SYNC_ID_LOC, msg_sync);
+               mmio_write_32(addr + IPC_MSG_ID_LOC, msg_id);
+               mmio_write_32(addr + IPC_MSG_CPU_ID_LOC, channel_id);
+               mmio_write_32(addr + IPC_MSG_POWER_STATE_LOC,
+                             cluster_power_state);
+               mmio_write_32(addr + IPC_MSG_STATE_LOC, IPC_MSG_OCCUPY);
+
+       } else {
+               ERROR("%s: FAILED\n", __func__);
+       }
+
+       return 0;
+}
diff --git a/plat/marvell/common/mss/mss_ipc_drv.h b/plat/marvell/common/mss/mss_ipc_drv.h
new file mode 100644 (file)
index 0000000..28eb907
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef __PM_IPC_DRV_H
+#define __PM_IPC_DRV_H
+
+#include <psci.h>
+
+#define MV_PM_FW_IPC_VERSION_MAGIC     (0xCA530000) /* Do NOT change */
+/* Increament for each version */
+#define MV_PM_FW_IPC_VERSION_SEQ       (0x00000001)
+#define MV_PM_FW_IPC_VERSION           (MV_PM_FW_IPC_VERSION_MAGIC | \
+                                        MV_PM_FW_IPC_VERSION_SEQ)
+
+#define IPC_MSG_STATE_LOC              (0x0)
+#define IPC_MSG_SYNC_ID_LOC            (0x4)
+#define IPC_MSG_ID_LOC                 (0x8)
+#define IPC_MSG_RET_CH_ID_LOC  (0xC)
+#define IPC_MSG_CPU_ID_LOC             (0x10)
+#define IPC_MSG_CLUSTER_ID_LOC (0x14)
+#define IPC_MSG_SYSTEM_ID_LOC  (0x18)
+#define IPC_MSG_POWER_STATE_LOC        (0x1C)
+#define IPC_MSG_REPLY_LOC              (0x20)
+#define IPC_MSG_RESERVED_LOC   (0x24)
+
+/* IPC initialization state */
+enum mss_pm_ipc_init_state {
+       IPC_UN_INITIALIZED      = 1,
+       IPC_INITIALIZED         = 2
+};
+
+/* IPC queue direction */
+enum mss_pm_ipc_init_msg_dir {
+       IPC_MSG_TX      = 0,
+       IPC_MSG_RX      = 1
+};
+
+/* IPC message state */
+enum mss_pm_ipc_msg_state {
+       IPC_MSG_FREE    = 1,
+       IPC_MSG_OCCUPY  = 2
+
+};
+
+/* IPC control block */
+struct mss_pm_ipc_ctrl {
+       unsigned int ctrl_base_address;
+       unsigned int msg_base_address;
+       unsigned int num_of_channels;
+       unsigned int channel_size;
+       unsigned int queue_size;
+};
+
+/* IPC message types */
+enum mss_pm_msg_id {
+       PM_IPC_MSG_CPU_SUSPEND          = 1,
+       PM_IPC_MSG_CPU_OFF              = 2,
+       PM_IPC_MSG_CPU_ON               = 3,
+       PM_IPC_MSG_SYSTEM_RESET         = 4,
+       PM_IPC_MSG_SYSTEM_SUSPEND       = 5,
+       PM_IPC_MAX_MSG
+};
+
+struct mss_pm_ipc_msg {
+       unsigned int    msg_sync_id;    /*
+                                        * Sync number, validate message
+                                        * reply corresponding to message
+                                        * received
+                                        */
+       unsigned int    msg_id;         /* Message Id */
+       unsigned int    ret_channel_id; /* IPC channel reply */
+       unsigned int    cpu_id;         /* CPU Id */
+       unsigned int    cluster_id;     /* Cluster Id */
+       unsigned int    system_id;      /* System Id */
+       unsigned int    power_state;
+       unsigned int    msg_reply;      /* Message reply */
+};
+
+/* IPC queue */
+struct mss_pm_ipc_queue {
+       unsigned int    state;
+       struct mss_pm_ipc_msg           msg;
+};
+
+/* IPC channel */
+struct mss_pm_ipc_ch {
+       struct mss_pm_ipc_queue *tx_queue;
+       struct mss_pm_ipc_queue *rx_queue;
+};
+
+/*****************************************************************************
+ * mv_pm_ipc_init
+ *
+ * DESCRIPTION: Initialize PM IPC infrastructure
+ *****************************************************************************
+ */
+int mv_pm_ipc_init(unsigned long ipc_control_addr);
+
+/*****************************************************************************
+ * mv_pm_ipc_msg_rx
+ *
+ * DESCRIPTION: Retrieve message from IPC channel
+ *****************************************************************************
+ */
+int mv_pm_ipc_msg_rx(unsigned int channel_id, struct mss_pm_ipc_msg *msg);
+
+/*****************************************************************************
+ * mv_pm_ipc_msg_tx
+ *
+ * DESCRIPTION: Send message via IPC channel
+ *****************************************************************************
+ */
+int mv_pm_ipc_msg_tx(unsigned int channel_id, unsigned int msg_id,
+                       unsigned int cluster_power_state);
+
+#endif /* __PM_IPC_DRV_H */
diff --git a/plat/marvell/common/mss/mss_mem.h b/plat/marvell/common/mss/mss_mem.h
new file mode 100644 (file)
index 0000000..efff59e
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef __MSS_PM_MEM_H
+#define __MSS_PM_MEM_H
+
+/* MSS SRAM Memory base */
+#define MSS_SRAM_PM_CONTROL_BASE               (MVEBU_REGS_BASE + 0x520000)
+
+enum mss_pm_ctrl_handshake {
+       MSS_UN_INITIALIZED      = 0,
+       MSS_COMPATIBILITY_ERROR = 1,
+       MSS_ACKNOWLEDGMENT      = 2,
+       HOST_ACKNOWLEDGMENT     = 3
+};
+
+enum mss_pm_ctrl_rtos_env {
+       MSS_MULTI_PROCESS_ENV   = 0,
+       MSS_SINGLE_PROCESS_ENV  = 1,
+       MSS_MAX_PROCESS_ENV
+};
+
+struct mss_pm_ctrl_block {
+       /* This field is used to synchronize the Host
+        * and MSS initialization sequence
+        * Valid Values
+        * 0 - Un-Initialized
+        * 1 - Compatibility Error
+        * 2 - MSS Acknowledgment
+        * 3 - Host Acknowledgment
+        */
+       unsigned int handshake;
+
+       /*
+        * This field include Host IPC version. Once received by the MSS
+        * It will be compared to MSS IPC version and set MSS Acknowledge to
+        * "compatibility error" in case there is no match
+        */
+       unsigned int ipc_version;
+       unsigned int ipc_base_address;
+       unsigned int ipc_state;
+
+       /* Following fields defines firmware core architecture */
+       unsigned int num_of_cores;
+       unsigned int num_of_clusters;
+       unsigned int num_of_cores_per_cluster;
+
+       /* Following fields define pm trace debug base address */
+       unsigned int pm_trace_ctrl_base_address;
+       unsigned int pm_trace_info_base_address;
+       unsigned int pm_trace_info_core_size;
+
+       unsigned int ctrl_blk_size;
+};
+
+#endif /* __MSS_PM_MEM_H */
diff --git a/plat/marvell/common/mss/mss_scp_bl2_format.h b/plat/marvell/common/mss/mss_scp_bl2_format.h
new file mode 100644 (file)
index 0000000..c04df72
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef __MSS_SCP_BL2_FORMAT_H
+#define __MSS_SCP_BL2_FORMAT_H
+
+#define MAX_NR_OF_FILES        5
+#define FILE_MAGIC     0xddd01ff
+#define HEADER_VERSION 0x1
+
+#define MSS_IDRAM_SIZE 0x10000 /* 64KB */
+#define MG_SRAM_SIZE   0x20000 /* 128KB */
+
+/* Types definitions */
+typedef struct file_header {
+       /* Magic specific for concatenated file (used for validation) */
+       uint32_t magic;
+       uint32_t nr_of_imgs;    /* Number of images concatenated */
+} file_header_t;
+
+/* Types definitions */
+enum cm3_t {
+       MSS_AP,
+       MSS_CP0,
+       MSS_CP1,
+       MSS_CP2,
+       MSS_CP3,
+       MG_CP0,
+       MG_CP1,
+};
+
+typedef struct img_header {
+       uint32_t type;          /* CM3 type, can be one of cm3_t */
+       uint32_t length;        /* Image length */
+       uint32_t version;       /* For sanity checks and future
+                                * extended functionality
+                                */
+} img_header_t;
+
+#endif /* __MSS_SCP_BL2_FORMAT_H */
diff --git a/plat/marvell/common/mss/mss_scp_bootloader.c b/plat/marvell/common/mss/mss_scp_bootloader.c
new file mode 100644 (file)
index 0000000..334fcfc
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <assert.h>
+#include <debug.h>
+#include <mmio.h>
+#include <arch_helpers.h> /* for cache maintanance operations */
+#include <platform_def.h>
+#include <delay_timer.h>
+
+#include <plat_pm_trace.h>
+#include <mss_scp_bootloader.h>
+#include <mss_ipc_drv.h>
+#include <mss_mem.h>
+#include <mss_scp_bl2_format.h>
+
+#define MSS_DMA_SRCBR(base)            (base + 0xC0)
+#define MSS_DMA_DSTBR(base)            (base + 0xC4)
+#define MSS_DMA_CTRLR(base)            (base + 0xC8)
+#define MSS_M3_RSTCR(base)             (base + 0xFC)
+
+#define MSS_DMA_CTRLR_SIZE_OFFSET      (0)
+#define MSS_DMA_CTRLR_REQ_OFFSET       (15)
+#define MSS_DMA_CTRLR_REQ_SET          (1)
+#define MSS_DMA_CTRLR_ACK_OFFSET       (12)
+#define MSS_DMA_CTRLR_ACK_MASK         (0x1)
+#define MSS_DMA_CTRLR_ACK_READY                (1)
+#define MSS_M3_RSTCR_RST_OFFSET                (0)
+#define MSS_M3_RSTCR_RST_OFF           (1)
+
+#define MSS_DMA_TIMEOUT                        1000
+#define MSS_EXTERNAL_SPACE             0x50000000
+#define MSS_EXTERNAL_ADDR_MASK         0xfffffff
+
+#define DMA_SIZE                       128
+
+#define MSS_HANDSHAKE_TIMEOUT          50
+
+static int mss_check_image_ready(volatile struct mss_pm_ctrl_block *mss_pm_crtl)
+{
+       int timeout = MSS_HANDSHAKE_TIMEOUT;
+
+       /* Wait for SCP to signal it's ready */
+       while ((mss_pm_crtl->handshake != MSS_ACKNOWLEDGMENT) &&
+                                               (timeout-- > 0))
+               mdelay(1);
+
+       if (mss_pm_crtl->handshake != MSS_ACKNOWLEDGMENT)
+               return -1;
+
+       mss_pm_crtl->handshake = HOST_ACKNOWLEDGMENT;
+
+       return 0;
+}
+
+static int mss_image_load(uint32_t src_addr, uint32_t size, uintptr_t mss_regs)
+{
+       uint32_t i, loop_num, timeout;
+
+       /* Check if the img size is not bigger than ID-RAM size of MSS CM3 */
+       if (size > MSS_IDRAM_SIZE) {
+               ERROR("image is too big to fit into MSS CM3 memory\n");
+               return 1;
+       }
+
+       NOTICE("Loading MSS image from addr. 0x%x Size 0x%x to MSS at 0x%lx\n",
+              src_addr, size, mss_regs);
+       /* load image to MSS RAM using DMA */
+       loop_num = (size / DMA_SIZE) + (((size & (DMA_SIZE - 1)) == 0) ? 0 : 1);
+
+       for (i = 0; i < loop_num; i++) {
+               /* write destination and source addresses */
+               mmio_write_32(MSS_DMA_SRCBR(mss_regs),
+                             MSS_EXTERNAL_SPACE |
+                             ((src_addr & MSS_EXTERNAL_ADDR_MASK) +
+                             (i * DMA_SIZE)));
+               mmio_write_32(MSS_DMA_DSTBR(mss_regs), (i * DMA_SIZE));
+
+               dsb(); /* make sure DMA data is ready before triggering it */
+
+               /* set the DMA control register */
+               mmio_write_32(MSS_DMA_CTRLR(mss_regs), ((MSS_DMA_CTRLR_REQ_SET
+                             << MSS_DMA_CTRLR_REQ_OFFSET) |
+                             (DMA_SIZE << MSS_DMA_CTRLR_SIZE_OFFSET)));
+
+               /* Poll DMA_ACK at MSS_DMACTLR until it is ready */
+               timeout = MSS_DMA_TIMEOUT;
+               while (timeout) {
+                       if ((mmio_read_32(MSS_DMA_CTRLR(mss_regs)) >>
+                            MSS_DMA_CTRLR_ACK_OFFSET & MSS_DMA_CTRLR_ACK_MASK)
+                               == MSS_DMA_CTRLR_ACK_READY) {
+                               break;
+                       }
+
+                       udelay(50);
+                       timeout--;
+               }
+
+               if (timeout == 0) {
+                       ERROR("\nDMA failed to load MSS image\n");
+                       return 1;
+               }
+       }
+
+       bl2_plat_configure_mss_windows(mss_regs);
+
+       /* Release M3 from reset */
+       mmio_write_32(MSS_M3_RSTCR(mss_regs), (MSS_M3_RSTCR_RST_OFF <<
+                     MSS_M3_RSTCR_RST_OFFSET));
+
+       NOTICE("Done\n");
+
+       return 0;
+}
+
+/* Load image to MSS AP and do PM related initialization
+ * Note that this routine is different than other CM3 loading routines, because
+ * firmware for AP is dedicated for PM and therefore some additional PM
+ * initialization is required
+ */
+static int mss_ap_load_image(uintptr_t single_img,
+                            uint32_t image_size, uint32_t ap_idx)
+{
+       volatile struct mss_pm_ctrl_block *mss_pm_crtl;
+       int ret;
+
+       /* TODO: add PM Control Info from platform */
+       mss_pm_crtl = (struct mss_pm_ctrl_block *)MSS_SRAM_PM_CONTROL_BASE;
+       mss_pm_crtl->ipc_version                = MV_PM_FW_IPC_VERSION;
+       mss_pm_crtl->num_of_clusters            = PLAT_MARVELL_CLUSTER_COUNT;
+       mss_pm_crtl->num_of_cores_per_cluster   =
+                                               PLAT_MARVELL_CLUSTER_CORE_COUNT;
+       mss_pm_crtl->num_of_cores               = PLAT_MARVELL_CLUSTER_COUNT *
+                                               PLAT_MARVELL_CLUSTER_CORE_COUNT;
+       mss_pm_crtl->pm_trace_ctrl_base_address = AP_MSS_ATF_CORE_CTRL_BASE;
+       mss_pm_crtl->pm_trace_info_base_address = AP_MSS_ATF_CORE_INFO_BASE;
+       mss_pm_crtl->pm_trace_info_core_size    = AP_MSS_ATF_CORE_INFO_SIZE;
+       VERBOSE("MSS Control Block = 0x%x\n", MSS_SRAM_PM_CONTROL_BASE);
+       VERBOSE("mss_pm_crtl->ipc_version                = 0x%x\n",
+               mss_pm_crtl->ipc_version);
+       VERBOSE("mss_pm_crtl->num_of_cores               = 0x%x\n",
+               mss_pm_crtl->num_of_cores);
+       VERBOSE("mss_pm_crtl->num_of_clusters            = 0x%x\n",
+               mss_pm_crtl->num_of_clusters);
+       VERBOSE("mss_pm_crtl->num_of_cores_per_cluster   = 0x%x\n",
+               mss_pm_crtl->num_of_cores_per_cluster);
+       VERBOSE("mss_pm_crtl->pm_trace_ctrl_base_address = 0x%x\n",
+               mss_pm_crtl->pm_trace_ctrl_base_address);
+       VERBOSE("mss_pm_crtl->pm_trace_info_base_address = 0x%x\n",
+               mss_pm_crtl->pm_trace_info_base_address);
+       VERBOSE("mss_pm_crtl->pm_trace_info_core_size    = 0x%x\n",
+               mss_pm_crtl->pm_trace_info_core_size);
+
+       /* TODO: add checksum to image */
+       VERBOSE("Send info about the SCP_BL2 image to be transferred to SCP\n");
+
+       ret = mss_image_load(single_img, image_size,
+                            bl2_plat_get_ap_mss_regs(ap_idx));
+       if (ret != 0) {
+               ERROR("SCP Image load failed\n");
+               return -1;
+       }
+
+       /* check that the image was loaded successfully */
+       ret = mss_check_image_ready(mss_pm_crtl);
+       if (ret != 0)
+               NOTICE("SCP Image doesn't contain PM firmware\n");
+
+       return 0;
+}
+
+/* Load CM3 image (single_img) to CM3 pointed by cm3_type */
+static int load_img_to_cm3(enum cm3_t cm3_type,
+                          uintptr_t single_img, uint32_t image_size)
+{
+       int ret, ap_idx, cp_index;
+       uint32_t ap_count = bl2_plat_get_ap_count();
+
+       switch (cm3_type) {
+       case MSS_AP:
+               for (ap_idx = 0; ap_idx < ap_count; ap_idx++) {
+                       NOTICE("Load image to AP%d MSS\n", ap_idx);
+                       ret = mss_ap_load_image(single_img, image_size, ap_idx);
+                       if (ret != 0)
+                               return ret;
+               }
+               break;
+       case MSS_CP0:
+       case MSS_CP1:
+       case MSS_CP2:
+       case MSS_CP3:
+               /* MSS_AP = 0
+                * MSS_CP1 = 1
+                * .
+                * .
+                * MSS_CP3 = 4
+                * Actual CP index is MSS_CPX - 1
+                */
+               cp_index = cm3_type - 1;
+               for (ap_idx = 0; ap_idx < ap_count; ap_idx++) {
+                       /* Check if we should load this image
+                        * according to number of CPs
+                        */
+                       if (bl2_plat_get_cp_count(ap_idx) <= cp_index) {
+                               NOTICE("Skipping MSS CP%d related image\n",
+                                      cp_index);
+                               break;
+                       }
+
+                       NOTICE("Load image to CP%d MSS AP%d\n",
+                              cp_index, ap_idx);
+                       ret = mss_image_load(single_img, image_size,
+                                            bl2_plat_get_cp_mss_regs(
+                                                    ap_idx, cp_index));
+                       if (ret != 0) {
+                               ERROR("SCP Image load failed\n");
+                               return -1;
+                       }
+               }
+               break;
+       case MG_CP0:
+               /* TODO: */
+               NOTICE("Load image to CP0 MG not supported\n");
+               break;
+       case MG_CP1:
+               /* TODO: */
+               NOTICE("Load image to CP1 MG not supported\n");
+               break;
+       default:
+               ERROR("SCP_BL2 wrong img format (cm3_type=%d)\n", cm3_type);
+               break;
+       }
+
+       return 0;
+}
+
+/* The Armada 8K has 5 service CPUs and Armada 7K has 3. Therefore it was
+ * required to provide a method for loading firmware to all of the service CPUs.
+ * To achieve that, the scp_bl2 image in fact is file containing up to 5
+ * concatenated firmwares and this routine splits concatenated image into single
+ * images dedicated for appropriate service CPU and then load them.
+ */
+static int split_and_load_bl2_image(void *image)
+{
+       file_header_t *file_hdr;
+       img_header_t *img_hdr;
+       uintptr_t single_img;
+       int i;
+
+       file_hdr = (file_header_t *)image;
+
+       if (file_hdr->magic != FILE_MAGIC) {
+               ERROR("SCP_BL2 wrong img format\n");
+               return -1;
+       }
+
+       if (file_hdr->nr_of_imgs > MAX_NR_OF_FILES) {
+               ERROR("SCP_BL2 concatenated image contains to many images\n");
+               return -1;
+       }
+
+       img_hdr = (img_header_t *)((uintptr_t)image + sizeof(file_header_t));
+       single_img = (uintptr_t)image + sizeof(file_header_t) +
+                                   sizeof(img_header_t) * file_hdr->nr_of_imgs;
+
+       NOTICE("SCP_BL2 contains %d concatenated images\n",
+                                                         file_hdr->nr_of_imgs);
+       for (i = 0; i < file_hdr->nr_of_imgs; i++) {
+
+               /* Before loading make sanity check on header */
+               if (img_hdr->version != HEADER_VERSION) {
+                       ERROR("Wrong header, img corrupted exiting\n");
+                       return -1;
+               }
+
+               load_img_to_cm3(img_hdr->type, single_img, img_hdr->length);
+
+               /* Prepare offsets for next run */
+               single_img += img_hdr->length;
+               img_hdr++;
+       }
+
+       return 0;
+}
+
+int scp_bootloader_transfer(void *image, unsigned int image_size)
+{
+#ifdef SCP_BL2_BASE
+       assert((uintptr_t) image == SCP_BL2_BASE);
+#endif
+
+       VERBOSE("Concatenated img size %d\n", image_size);
+
+       if (image_size == 0) {
+               ERROR("SCP_BL2 image size can't be 0 (current size = 0x%x)\n",
+                                                                   image_size);
+               return -1;
+       }
+
+       if (split_and_load_bl2_image(image))
+               return -1;
+
+       return 0;
+}
diff --git a/plat/marvell/common/mss/mss_scp_bootloader.h b/plat/marvell/common/mss/mss_scp_bootloader.h
new file mode 100644 (file)
index 0000000..67c387a
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef __MSS_SCP_BOOTLOADER_H__
+#define __MSS_SCP_BOOTLOADER_H__
+
+int scp_bootloader_transfer(void *image, unsigned int image_size);
+uintptr_t bl2_plat_get_cp_mss_regs(int ap_idx, int cp_idx);
+uintptr_t bl2_plat_get_ap_mss_regs(int ap_idx);
+uint32_t bl2_plat_get_cp_count(int ap_idx);
+uint32_t bl2_plat_get_ap_count(void);
+void bl2_plat_configure_mss_windows(uintptr_t mss_regs);
+int bl2_plat_mss_check_image_ready(void);
+
+#endif /* __MSS_SCP_BOOTLOADER_H__ */
diff --git a/plat/marvell/common/plat_delay_timer.c b/plat/marvell/common/plat_delay_timer.c
new file mode 100644 (file)
index 0000000..dfc77c7
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <arch_helpers.h>
+#include <delay_timer.h>
+#include <mvebu_def.h>
+
+#define SYS_COUNTER_FREQ_IN_MHZ        (COUNTER_FREQUENCY/1000000)
+
+static uint32_t plat_get_timer_value(void)
+{
+       /*
+        * Generic delay timer implementation expects the timer to be a down
+        * counter. We apply bitwise NOT operator to the tick values returned
+        * by read_cntpct_el0() to simulate the down counter.
+        */
+       return (uint32_t)(~read_cntpct_el0());
+}
+
+static const timer_ops_t plat_timer_ops = {
+       .get_timer_value        = plat_get_timer_value,
+       .clk_mult               = 1,
+       .clk_div                = SYS_COUNTER_FREQ_IN_MHZ
+};
+
+void plat_delay_timer_init(void)
+{
+       timer_init(&plat_timer_ops);
+}
diff --git a/plat/marvell/marvell.mk b/plat/marvell/marvell.mk
new file mode 100644 (file)
index 0000000..217ad46
--- /dev/null
@@ -0,0 +1,53 @@
+# Copyright (C) 2018 Marvell International Ltd.
+#
+# SPDX-License-Identifier:     BSD-3-Clause
+# https://spdx.org/licenses
+
+# Marvell images
+BOOT_IMAGE                     := boot-image.bin
+BOOT_ENC_IMAGE                 := boot-image-enc.bin
+FLASH_IMAGE                    := flash-image.bin
+
+# Make non-trusted image by default
+MARVELL_SECURE_BOOT            := 0
+$(eval $(call add_define,MARVELL_SECURE_BOOT))
+
+# Enable compilation for Palladium emulation platform
+PALLADIUM                      := 0
+$(eval $(call add_define,PALLADIUM))
+
+ifeq (${MARVELL_SECURE_BOOT},1)
+DOIMAGE_SEC_FLAGS := -c $(DOIMAGE_SEC)
+DOIMAGE_LIBS_CHECK = \
+        if ! [ -d "/usr/include/mbedtls" ]; then \
+                        echo "****************************************" >&2; \
+                        echo "Missing mbedTLS installation! " >&2; \
+                        echo "Please download it from \"tls.mbed.org\"" >&2; \
+                       echo "Alternatively on Debian/Ubuntu system install" >&2; \
+                       echo "\"libmbedtls-dev\" package" >&2; \
+                        echo "Make sure to use version 2.1.0 or later" >&2; \
+                        echo "****************************************" >&2; \
+                exit 1; \
+        else if ! [ -f "/usr/include/libconfig.h" ]; then \
+                        echo "********************************************************" >&2; \
+                        echo "Missing Libconfig installation!" >&2; \
+                        echo "Please download it from \"www.hyperrealm.com/libconfig/\"" >&2; \
+                        echo "Alternatively on Debian/Ubuntu system install packages" >&2; \
+                        echo "\"libconfig8\" and \"libconfig8-dev\"" >&2; \
+                        echo "********************************************************" >&2; \
+                exit 1; \
+        fi \
+        fi
+else #MARVELL_SECURE_BOOT
+DOIMAGE_LIBS_CHECK =
+DOIMAGE_SEC_FLAGS =
+endif #MARVELL_SECURE_BOOT
+
+mrvl_clean:
+       @echo "  Doimage CLEAN"
+       ${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${DOIMAGEPATH} clean
+
+${DOIMAGETOOL}: mrvl_clean
+       ${Q}${MAKE} --no-print-directory -C ${DOIMAGEPATH} WTMI_IMG=$(WTMI_IMG)
+
+
diff --git a/plat/marvell/version.mk b/plat/marvell/version.mk
new file mode 100644 (file)
index 0000000..017e119
--- /dev/null
@@ -0,0 +1 @@
+SUBVERSION = devel-18.08.0
diff --git a/tools/doimage/Makefile b/tools/doimage/Makefile
new file mode 100644 (file)
index 0000000..bc74369
--- /dev/null
@@ -0,0 +1,48 @@
+#
+# Copyright (C) 2018 Marvell International Ltd.
+#
+# SPDX-License-Identifier:     BSD-3-Clause
+# https://spdx.org/licenses
+
+PROJECT = doimage
+OBJECTS = doimage.o
+
+CFLAGS = -Wall -Werror
+ifeq (${DEBUG},1)
+  CFLAGS += -g -O0 -DDEBUG
+else
+  CFLAGS += -O2
+endif
+
+ifeq (${MARVELL_SECURE_BOOT},1)
+DOIMAGE_CC_FLAGS := -DCONFIG_MVEBU_SECURE_BOOT
+DOIMAGE_LD_FLAGS := -lconfig -lmbedtls -lmbedcrypto -lmbedx509
+endif
+
+CFLAGS += ${DOIMAGE_CC_FLAGS}
+
+# Make soft links and include from local directory otherwise wrong headers
+# could get pulled in from firmware tree.
+INCLUDE_PATHS = -I.
+
+CC := gcc
+RM := rm -rf
+
+.PHONY: all clean
+
+all: ${PROJECT}
+
+${PROJECT}: ${OBJECTS} Makefile
+       @echo "  LD      $@"
+       ${Q}${CC} ${OBJECTS} ${DOIMAGE_LD_FLAGS} -o $@
+       @echo
+       @echo "Built $@ successfully"
+       @echo
+
+%.o: %.c %.h Makefile
+       @echo "  CC      $<"
+       ${Q}${CC} -c ${CFLAGS} ${INCLUDE_PATHS} $< -o $@
+
+clean:
+       ${Q}${RM} ${PROJECT}
+       ${Q}${RM} ${OBJECTS}
diff --git a/tools/doimage/doimage.c b/tools/doimage/doimage.c
new file mode 100644 (file)
index 0000000..56dabba
--- /dev/null
@@ -0,0 +1,1755 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#ifdef CONFIG_MVEBU_SECURE_BOOT
+#include <libconfig.h> /* for parsing config file */
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+/* mbedTLS stuff */
+#if defined(MBEDTLS_BIGNUM_C) && defined(MBEDTLS_ENTROPY_C) && \
+       defined(MBEDTLS_SHA256_C) && \
+       defined(MBEDTLS_PK_PARSE_C) && defined(MBEDTLS_FS_IO) && \
+       defined(MBEDTLS_CTR_DRBG_C)
+#include <mbedtls/error.h>
+#include <mbedtls/entropy.h>
+#include <mbedtls/ctr_drbg.h>
+#include <mbedtls/md.h>
+#include <mbedtls/pk.h>
+#include <mbedtls/sha256.h>
+#include <mbedtls/x509.h>
+#else
+#error "Bad mbedTLS configuration!"
+#endif
+#endif /* CONFIG_MVEBU_SECURE_BOOT */
+
+#define MAX_FILENAME           256
+#define CSK_ARR_SZ             16
+#define CSK_ARR_EMPTY_FILE     "*"
+#define AES_KEY_BIT_LEN                256
+#define AES_KEY_BYTE_LEN       (AES_KEY_BIT_LEN >> 3)
+#define AES_BLOCK_SZ           16
+#define RSA_SIGN_BYTE_LEN      256
+#define MAX_RSA_DER_BYTE_LEN   524
+/* Number of address pairs in control array */
+#define CP_CTRL_EL_ARRAY_SZ    32
+
+#define VERSION_STRING         "Marvell(C) doimage utility version 3.2"
+
+/* A8K definitions */
+
+/* Extension header types */
+#define EXT_TYPE_SECURITY      0x1
+#define EXT_TYPE_BINARY                0x2
+
+#define MAIN_HDR_MAGIC         0xB105B002
+
+/* PROLOG alignment considerations:
+ *  128B: To allow supporting XMODEM protocol.
+ *  8KB: To align the boot image to the largest NAND page size, and simplify
+ *  the read operations from NAND.
+ *  We choose the largest page size, in order to use a single image for all
+ *  NAND page sizes.
+ */
+#define PROLOG_ALIGNMENT       (8 << 10)
+
+/* UART argument bitfield */
+#define UART_MODE_UNMODIFIED   0x0
+#define UART_MODE_DISABLE      0x1
+#define UART_MODE_UPDATE       0x2
+
+typedef struct _main_header {
+       uint32_t        magic;                  /*  0-3  */
+       uint32_t        prolog_size;            /*  4-7  */
+       uint32_t        prolog_checksum;        /*  8-11 */
+       uint32_t        boot_image_size;        /* 12-15 */
+       uint32_t        boot_image_checksum;    /* 16-19 */
+       uint32_t        rsrvd0;                 /* 20-23 */
+       uint32_t        load_addr;              /* 24-27 */
+       uint32_t        exec_addr;              /* 28-31 */
+       uint8_t         uart_cfg;               /*  32   */
+       uint8_t         baudrate;               /*  33   */
+       uint8_t         ext_count;              /*  34   */
+       uint8_t         aux_flags;              /*  35   */
+       uint32_t        io_arg_0;               /* 36-39 */
+       uint32_t        io_arg_1;               /* 40-43 */
+       uint32_t        io_arg_2;               /* 43-47 */
+       uint32_t        io_arg_3;               /* 48-51 */
+       uint32_t        rsrvd1;                 /* 52-55 */
+       uint32_t        rsrvd2;                 /* 56-59 */
+       uint32_t        rsrvd3;                 /* 60-63 */
+} header_t;
+
+typedef struct _ext_header {
+       uint8_t         type;
+       uint8_t         offset;
+       uint16_t        reserved;
+       uint32_t        size;
+} ext_header_t;
+
+typedef struct _sec_entry {
+       uint8_t         kak_key[MAX_RSA_DER_BYTE_LEN];
+       uint32_t        jtag_delay;
+       uint32_t        box_id;
+       uint32_t        flash_id;
+       uint32_t        jtag_en;
+       uint32_t        encrypt_en;
+       uint32_t        efuse_dis;
+       uint8_t         header_sign[RSA_SIGN_BYTE_LEN];
+       uint8_t         image_sign[RSA_SIGN_BYTE_LEN];
+       uint8_t         csk_keys[CSK_ARR_SZ][MAX_RSA_DER_BYTE_LEN];
+       uint8_t         csk_sign[RSA_SIGN_BYTE_LEN];
+       uint32_t        cp_ctrl_arr[CP_CTRL_EL_ARRAY_SZ];
+       uint32_t        cp_efuse_arr[CP_CTRL_EL_ARRAY_SZ];
+} sec_entry_t;
+
+/* A8K definitions end */
+
+/* UART argument bitfield */
+#define UART_MODE_UNMODIFIED   0x0
+#define UART_MODE_DISABLE      0x1
+#define UART_MODE_UPDATE       0x2
+
+#define uart_set_mode(arg, mode)       (arg |= (mode & 0x3))
+
+typedef struct _sec_options {
+#ifdef CONFIG_MVEBU_SECURE_BOOT
+       char aes_key_file[MAX_FILENAME+1];
+       char kak_key_file[MAX_FILENAME+1];
+       char csk_key_file[CSK_ARR_SZ][MAX_FILENAME+1];
+       uint32_t        box_id;
+       uint32_t        flash_id;
+       uint32_t        jtag_delay;
+       uint8_t         csk_index;
+       uint8_t         jtag_enable;
+       uint8_t         efuse_disable;
+       uint32_t        cp_ctrl_arr[CP_CTRL_EL_ARRAY_SZ];
+       uint32_t        cp_efuse_arr[CP_CTRL_EL_ARRAY_SZ];
+       mbedtls_pk_context      kak_pk;
+       mbedtls_pk_context      csk_pk[CSK_ARR_SZ];
+       uint8_t         aes_key[AES_KEY_BYTE_LEN];
+       uint8_t         *encrypted_image;
+       uint32_t        enc_image_sz;
+#endif
+} sec_options;
+
+typedef struct _options {
+       char bin_ext_file[MAX_FILENAME+1];
+       char sec_cfg_file[MAX_FILENAME+1];
+       sec_options *sec_opts;
+       uint32_t  load_addr;
+       uint32_t  exec_addr;
+       uint32_t  baudrate;
+       uint8_t   disable_print;
+       int8_t    key_index; /* For header signatures verification only */
+       uint32_t  nfc_io_args;
+} options_t;
+
+void usage_err(char *msg)
+{
+       fprintf(stderr, "Error: %s\n", msg);
+       fprintf(stderr, "run 'doimage -h' to get usage information\n");
+       exit(-1);
+}
+
+void usage(void)
+{
+       printf("\n\n%s\n\n", VERSION_STRING);
+       printf("Usage: doimage [options] <input_file> [output_file]\n");
+       printf("create bootrom image from u-boot and boot extensions\n\n");
+
+       printf("Arguments\n");
+       printf("  input_file   name of boot image file.\n");
+       printf("               if -p is used, name of the bootrom image file");
+       printf("               to parse.\n");
+       printf("  output_file  name of output bootrom image file\n");
+
+       printf("\nOptions\n");
+       printf("  -s        target SOC name. supports a8020,a7020\n");
+       printf("            different SOCs may have different boot image\n");
+       printf("            format so it's mandatory to know the target SOC\n");
+       printf("  -i        boot I/F name. supports nand, spi, nor\n");
+       printf("            This affects certain parameters coded in the\n");
+       printf("            image header\n");
+       printf("  -l        boot image load address. default is 0x0\n");
+       printf("  -e        boot image entry address. default is 0x0\n");
+       printf("  -b        binary extension image file.\n");
+       printf("            This image is executed before the boot image.\n");
+       printf("            This is typically used to initialize the memory ");
+       printf("            controller.\n");
+       printf("            Currently supports only a single file.\n");
+#ifdef CONFIG_MVEBU_SECURE_BOOT
+       printf("  -c        Make trusted boot image using parameters\n");
+       printf("            from the configuration file.\n");
+#endif
+       printf("  -p        Parse and display a pre-built boot image\n");
+#ifdef CONFIG_MVEBU_SECURE_BOOT
+       printf("  -k        Key index for RSA signatures verification\n");
+       printf("            when parsing the boot image\n");
+#endif
+       printf("  -m        Disable prints of bootrom and binary extension\n");
+       printf("  -u        UART baudrate used for bootrom prints.\n");
+       printf("            Must be multiple of 1200\n");
+       printf("  -h        Show this help message\n");
+       printf(" IO-ROM NFC-NAND boot parameters:\n");
+       printf("  -n        NAND device block size in KB [Default is 64KB].\n");
+       printf("  -t        NAND cell technology (SLC [Default] or MLC)\n");
+
+       exit(-1);
+}
+
+/* globals */
+options_t opts = {
+       .bin_ext_file = "NA",
+       .sec_cfg_file = "NA",
+       .sec_opts = 0,
+       .load_addr = 0x0,
+       .exec_addr = 0x0,
+       .disable_print = 0,
+       .baudrate = 0,
+       .key_index = -1,
+};
+
+int get_file_size(char *filename)
+{
+       struct stat st;
+
+       if (stat(filename, &st) == 0)
+               return st.st_size;
+
+       return -1;
+}
+
+uint32_t checksum32(uint32_t *start, int len)
+{
+       uint32_t sum = 0;
+       uint32_t *startp = start;
+
+       do {
+               sum += *startp;
+               startp++;
+               len -= 4;
+       } while (len > 0);
+
+       return sum;
+}
+
+/*******************************************************************************
+ *    create_rsa_signature (memory buffer content)
+ *          Create RSASSA-PSS/SHA-256 signature for memory buffer
+ *          using RSA Private Key
+ *    INPUT:
+ *          pk_ctx     Private Key context
+ *          input      memory buffer
+ *          ilen       buffer length
+ *          pers       personalization string for seeding the RNG.
+ *                     For instance a private key file name.
+ *    OUTPUT:
+ *          signature  RSA-2048 signature
+ *    RETURN:
+ *          0 on success
+ */
+#ifdef CONFIG_MVEBU_SECURE_BOOT
+int create_rsa_signature(mbedtls_pk_context    *pk_ctx,
+                        const unsigned char    *input,
+                        size_t                 ilen,
+                        const char             *pers,
+                        uint8_t                *signature)
+{
+       mbedtls_entropy_context         entropy;
+       mbedtls_ctr_drbg_context        ctr_drbg;
+       unsigned char                   hash[32];
+       unsigned char                   buf[MBEDTLS_MPI_MAX_SIZE];
+       int                             rval;
+
+       /* Not sure this is required,
+        * but it's safer to start with empty buffers
+        */
+       memset(hash, 0, sizeof(hash));
+       memset(buf, 0, sizeof(buf));
+
+       mbedtls_ctr_drbg_init(&ctr_drbg);
+       mbedtls_entropy_init(&entropy);
+
+       /* Seed the random number generator */
+       rval = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
+                               (const unsigned char *)pers, strlen(pers));
+       if (rval != 0) {
+               fprintf(stderr, " Failed in ctr_drbg_init call (%d)!\n", rval);
+               goto sign_exit;
+       }
+
+       /* The PK context should be already initialized.
+        * Set the padding type for this PK context
+        */
+       mbedtls_rsa_set_padding(mbedtls_pk_rsa(*pk_ctx),
+                               MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);
+
+       /* First compute the SHA256 hash for the input blob */
+       mbedtls_sha256(input, ilen, hash, 0);
+
+       /* Then calculate the hash signature */
+       rval = mbedtls_rsa_rsassa_pss_sign(mbedtls_pk_rsa(*pk_ctx),
+                                          mbedtls_ctr_drbg_random,
+                                          &ctr_drbg,
+                                          MBEDTLS_RSA_PRIVATE,
+                                          MBEDTLS_MD_SHA256, 0, hash, buf);
+       if (rval != 0) {
+               fprintf(stderr,
+                       "Failed to create RSA signature for %s. Error %d\n",
+                       pers, rval);
+               goto sign_exit;
+       }
+       memcpy(signature, buf, 256);
+
+sign_exit:
+       mbedtls_ctr_drbg_free(&ctr_drbg);
+       mbedtls_entropy_free(&entropy);
+
+       return rval;
+} /* end of create_rsa_signature */
+
+/*******************************************************************************
+ *    verify_rsa_signature (memory buffer content)
+ *          Verify RSASSA-PSS/SHA-256 signature for memory buffer
+ *          using RSA Public Key
+ *    INPUT:
+ *          pub_key    Public Key buffer
+ *          ilen       Public Key buffer length
+ *          input      memory buffer
+ *          ilen       buffer length
+ *          pers       personalization string for seeding the RNG.
+ *          signature  RSA-2048 signature
+ *    OUTPUT:
+ *          none
+ *    RETURN:
+ *          0 on success
+ */
+int verify_rsa_signature(const unsigned char   *pub_key,
+                        size_t                 klen,
+                        const unsigned char    *input,
+                        size_t                 ilen,
+                        const char             *pers,
+                        uint8_t                *signature)
+{
+       mbedtls_entropy_context         entropy;
+       mbedtls_ctr_drbg_context        ctr_drbg;
+       mbedtls_pk_context              pk_ctx;
+       unsigned char                   hash[32];
+       int                             rval;
+
+       /* Not sure this is required,
+        * but it's safer to start with empty buffer
+        */
+       memset(hash, 0, sizeof(hash));
+
+       mbedtls_pk_init(&pk_ctx);
+       mbedtls_ctr_drbg_init(&ctr_drbg);
+       mbedtls_entropy_init(&entropy);
+
+       /* Seed the random number generator */
+       rval = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
+                               (const unsigned char *)pers, strlen(pers));
+       if (rval != 0) {
+               fprintf(stderr, " Failed in ctr_drbg_init call (%d)!\n", rval);
+               goto verify_exit;
+       }
+
+       /* Check ability to read the public key */
+       rval = mbedtls_pk_parse_public_key(&pk_ctx, pub_key,
+                                          MAX_RSA_DER_BYTE_LEN);
+       if (rval != 0) {
+               fprintf(stderr, " Failed in pk_parse_public_key (%#x)!\n",
+                       rval);
+               goto verify_exit;
+       }
+
+       /* Set the padding type for the new PK context */
+       mbedtls_rsa_set_padding(mbedtls_pk_rsa(pk_ctx),
+                               MBEDTLS_RSA_PKCS_V21,
+                               MBEDTLS_MD_SHA256);
+
+       /* Compute the SHA256 hash for the input buffer */
+       mbedtls_sha256(input, ilen, hash, 0);
+
+       rval = mbedtls_rsa_rsassa_pss_verify(mbedtls_pk_rsa(pk_ctx),
+                                            mbedtls_ctr_drbg_random,
+                                            &ctr_drbg,
+                                            MBEDTLS_RSA_PUBLIC,
+                                            MBEDTLS_MD_SHA256, 0,
+                                            hash, signature);
+       if (rval != 0)
+               fprintf(stderr, "Failed to verify signature (%d)!\n", rval);
+
+verify_exit:
+
+       mbedtls_pk_free(&pk_ctx);
+       mbedtls_ctr_drbg_free(&ctr_drbg);
+       mbedtls_entropy_free(&entropy);
+       return rval;
+} /* end of verify_rsa_signature */
+
+/*******************************************************************************
+ *    image_encrypt
+ *           Encrypt image buffer using AES-256-CBC scheme.
+ *           The resulting image is saved into opts.sec_opts->encrypted_image
+ *           and the adjusted image size into opts.sec_opts->enc_image_sz
+ *           First AES_BLOCK_SZ bytes of the output image contain IV
+ *    INPUT:
+ *          buf        Source buffer to encrypt
+ *          blen       Source buffer length
+ *    OUTPUT:
+ *          none
+ *    RETURN:
+ *          0 on success
+ */
+int image_encrypt(uint8_t *buf, uint32_t blen)
+{
+       struct timeval          tv;
+       char                    *ptmp = (char *)&tv;
+       unsigned char           digest[32];
+       unsigned char           IV[AES_BLOCK_SZ];
+       int                     i, k;
+       mbedtls_aes_context     aes_ctx;
+       int                     rval = -1;
+       uint8_t                 *test_img = 0;
+
+       if (AES_BLOCK_SZ > 32) {
+               fprintf(stderr, "Unsupported AES block size %d\n",
+                       AES_BLOCK_SZ);
+               return rval;
+       }
+
+       mbedtls_aes_init(&aes_ctx);
+       memset(IV, 0, AES_BLOCK_SZ);
+       memset(digest, 0, 32);
+
+       /* Generate initialization vector and init the AES engine
+        * Use file name XOR current time and finally SHA-256
+        * [0...AES_BLOCK_SZ-1]
+        */
+       k = strlen(opts.sec_opts->aes_key_file);
+       if (k > AES_BLOCK_SZ)
+               k = AES_BLOCK_SZ;
+       memcpy(IV, opts.sec_opts->aes_key_file, k);
+       gettimeofday(&tv, 0);
+
+       for (i = 0, k = 0; i < AES_BLOCK_SZ; i++,
+            k = (k+1) % sizeof(struct timeval))
+               IV[i] ^= ptmp[k];
+
+       /* compute SHA-256 digest of the results
+        * and use it as the init vector (IV)
+        */
+       mbedtls_sha256(IV, AES_BLOCK_SZ, digest, 0);
+       memcpy(IV, digest, AES_BLOCK_SZ);
+       mbedtls_aes_setkey_enc(&aes_ctx, opts.sec_opts->aes_key,
+                              AES_KEY_BIT_LEN);
+
+       /* The output image has to include extra space for IV
+        * and to be aligned to the AES block size.
+        * The input image buffer has to be already aligned to AES_BLOCK_SZ
+        * and padded with zeroes
+        */
+       opts.sec_opts->enc_image_sz = (blen + 2 * AES_BLOCK_SZ - 1) &
+                                     ~(AES_BLOCK_SZ - 1);
+       opts.sec_opts->encrypted_image = calloc(opts.sec_opts->enc_image_sz, 1);
+       if (opts.sec_opts->encrypted_image == 0) {
+               fprintf(stderr, "Failed to allocate encrypted image!\n");
+               goto encrypt_exit;
+       }
+
+       /* Put IV into the output buffer next to the encrypted image
+        * Since the IV is modified by the encryption function,
+        * this should be done now
+        */
+       memcpy(opts.sec_opts->encrypted_image +
+                  opts.sec_opts->enc_image_sz - AES_BLOCK_SZ,
+                  IV, AES_BLOCK_SZ);
+       rval = mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_ENCRYPT,
+                            opts.sec_opts->enc_image_sz - AES_BLOCK_SZ,
+                            IV, buf, opts.sec_opts->encrypted_image);
+       if (rval != 0) {
+               fprintf(stderr, "Failed to encrypt the image! Error %d\n",
+                       rval);
+               goto encrypt_exit;
+       }
+
+       mbedtls_aes_free(&aes_ctx);
+
+       /* Try to decrypt the image and compare it with the original data */
+       mbedtls_aes_init(&aes_ctx);
+       mbedtls_aes_setkey_dec(&aes_ctx, opts.sec_opts->aes_key,
+                              AES_KEY_BIT_LEN);
+
+       test_img = calloc(opts.sec_opts->enc_image_sz - AES_BLOCK_SZ, 1);
+       if (test_img == 0) {
+               fprintf(stderr, "Failed to allocate test image!d\n");
+               rval = -1;
+               goto encrypt_exit;
+       }
+
+       memcpy(IV, opts.sec_opts->encrypted_image +
+                  opts.sec_opts->enc_image_sz - AES_BLOCK_SZ,
+                  AES_BLOCK_SZ);
+       rval = mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT,
+                            opts.sec_opts->enc_image_sz - AES_BLOCK_SZ,
+                            IV, opts.sec_opts->encrypted_image, test_img);
+       if (rval != 0) {
+               fprintf(stderr, "Failed to decrypt the image! Error %d\n",
+                       rval);
+               goto encrypt_exit;
+       }
+
+       for (i = 0; i < blen; i++) {
+               if (buf[i] != test_img[i]) {
+                       fprintf(stderr, "Failed to compare the image after");
+                       fprintf(stderr, " decryption! Byte count is %d\n", i);
+                       rval = -1;
+                       goto encrypt_exit;
+               }
+       }
+
+encrypt_exit:
+
+       mbedtls_aes_free(&aes_ctx);
+       if (test_img)
+               free(test_img);
+
+       return rval;
+} /* end of image_encrypt */
+
+/*******************************************************************************
+ *    verify_secure_header_signatures
+ *          Verify CSK array, header and image signatures and print results
+ *    INPUT:
+ *          main_hdr       Main header
+ *          sec_ext        Secure extension
+ *    OUTPUT:
+ *          none
+ *    RETURN:
+ *          0 on success
+ */
+int verify_secure_header_signatures(header_t *main_hdr, sec_entry_t *sec_ext)
+{
+       uint8_t *image = (uint8_t *)main_hdr + main_hdr->prolog_size;
+       uint8_t signature[RSA_SIGN_BYTE_LEN];
+       int             rval = -1;
+
+       /* Save headers signature and reset it in the secure header */
+       memcpy(signature, sec_ext->header_sign, RSA_SIGN_BYTE_LEN);
+       memset(sec_ext->header_sign, 0, RSA_SIGN_BYTE_LEN);
+
+       fprintf(stdout, "\nCheck RSA Signatures\n");
+       fprintf(stdout, "#########################\n");
+       fprintf(stdout, "CSK Block Signature: ");
+       if (verify_rsa_signature(sec_ext->kak_key,
+                                MAX_RSA_DER_BYTE_LEN,
+                                &sec_ext->csk_keys[0][0],
+                                sizeof(sec_ext->csk_keys),
+                                "CSK Block Signature: ",
+                                sec_ext->csk_sign) != 0) {
+               fprintf(stdout, "ERROR\n");
+               goto ver_error;
+       }
+       fprintf(stdout, "OK\n");
+
+       if (opts.key_index != -1) {
+               fprintf(stdout, "Image Signature:     ");
+               if (verify_rsa_signature(sec_ext->csk_keys[opts.key_index],
+                                        MAX_RSA_DER_BYTE_LEN,
+                                        image, main_hdr->boot_image_size,
+                                        "Image Signature: ",
+                                        sec_ext->image_sign) != 0) {
+                       fprintf(stdout, "ERROR\n");
+                       goto ver_error;
+               }
+               fprintf(stdout, "OK\n");
+
+               fprintf(stdout, "Header Signature:    ");
+               if (verify_rsa_signature(sec_ext->csk_keys[opts.key_index],
+                                        MAX_RSA_DER_BYTE_LEN,
+                                        (uint8_t *)main_hdr,
+                                        main_hdr->prolog_size,
+                                        "Header Signature: ",
+                                        signature) != 0) {
+                       fprintf(stdout, "ERROR\n");
+                       goto ver_error;
+               }
+               fprintf(stdout, "OK\n");
+       } else {
+               fprintf(stdout, "SKIP Image and Header Signatures");
+               fprintf(stdout, " check (undefined key index)\n");
+       }
+
+       rval = 0;
+
+ver_error:
+       memcpy(sec_ext->header_sign, signature, RSA_SIGN_BYTE_LEN);
+       return rval;
+}
+
+/*******************************************************************************
+ *    verify_and_copy_file_name_entry
+ *    INPUT:
+ *          element_name
+ *          element
+ *    OUTPUT:
+ *          copy_to
+ *    RETURN:
+ *          0 on success
+ */
+int verify_and_copy_file_name_entry(const char *element_name,
+                                   const char *element, char *copy_to)
+{
+       int element_length = strlen(element);
+
+       if (element_length >= MAX_FILENAME) {
+               fprintf(stderr, "The file name %s for %s is too long (%d). ",
+                       element, element_name, element_length);
+               fprintf(stderr, "Maximum allowed %d characters!\n",
+                       MAX_FILENAME);
+               return -1;
+       } else if (element_length == 0) {
+               fprintf(stderr, "The file name for %s is empty!\n",
+                       element_name);
+               return -1;
+       }
+       memcpy(copy_to, element, element_length);
+
+       return 0;
+}
+
+/*******************************************************************************
+ *    parse_sec_config_file
+ *          Read the secure boot configuration from a file
+ *          into internal structures
+ *    INPUT:
+ *          filename      File name
+ *    OUTPUT:
+ *          none
+ *    RETURN:
+ *          0 on success
+ */
+int parse_sec_config_file(char *filename)
+{
+       config_t                sec_cfg;
+       int                     array_sz, element, rval = -1;
+       const char              *cfg_string;
+       int32_t                 cfg_int32;
+       const config_setting_t  *csk_array, *control_array;
+       sec_options             *sec_opt = 0;
+
+       config_init(&sec_cfg);
+
+       if (config_read_file(&sec_cfg, filename) != CONFIG_TRUE) {
+               fprintf(stderr, "Failed to read data from config file ");
+               fprintf(stderr, "%s\n\t%s at line %d\n",
+                       filename, config_error_text(&sec_cfg),
+                       config_error_line(&sec_cfg));
+               goto exit_parse;
+       }
+
+       sec_opt = (sec_options *)calloc(sizeof(sec_options), 1);
+       if (sec_opt == 0) {
+               fprintf(stderr,
+                       "Cannot allocate memory for secure boot options!\n");
+               goto exit_parse;
+       }
+
+       /* KAK file name */
+       if (config_lookup_string(&sec_cfg, "kak_key_file",
+                                &cfg_string) != CONFIG_TRUE) {
+               fprintf(stderr, "The \"kak_key_file\" undefined!\n");
+               goto exit_parse;
+       }
+       if (verify_and_copy_file_name_entry("kak_key_file",
+                                           cfg_string, sec_opt->kak_key_file))
+               goto exit_parse;
+
+
+       /* AES file name - can be empty/undefined */
+       if (config_lookup_string(&sec_cfg, "aes_key_file",
+                                &cfg_string) == CONFIG_TRUE) {
+               if (verify_and_copy_file_name_entry("aes_key_file",
+                                                   cfg_string,
+                                                   sec_opt->aes_key_file))
+                       goto exit_parse;
+       }
+
+       /* CSK file names array */
+       csk_array = config_lookup(&sec_cfg, "csk_key_file");
+       if (csk_array == NULL) {
+               fprintf(stderr, "The \"csk_key_file\" undefined!\n");
+               goto exit_parse;
+       }
+       array_sz = config_setting_length(csk_array);
+       if (array_sz > CSK_ARR_SZ) {
+               fprintf(stderr, "The \"csk_key_file\" array is too big! ");
+               fprintf(stderr, "Only first %d elements will be used\n",
+                       CSK_ARR_SZ);
+               array_sz = CSK_ARR_SZ;
+       } else if (array_sz == 0) {
+               fprintf(stderr, "The \"csk_key_file\" array is empty!\n");
+               goto exit_parse;
+       }
+
+       for (element = 0; element < array_sz; element++) {
+               cfg_string = config_setting_get_string_elem(csk_array, element);
+               if (verify_and_copy_file_name_entry(
+                               "csk_key_file", cfg_string,
+                               sec_opt->csk_key_file[element])) {
+                       fprintf(stderr, "Bad csk_key_file[%d] entry!\n",
+                               element);
+                       goto exit_parse;
+               }
+       }
+
+       /* JTAG options */
+       if (config_lookup_bool(&sec_cfg, "jtag.enable",
+                              &cfg_int32) != CONFIG_TRUE) {
+               fprintf(stderr, "Error obtaining \"jtag.enable\" element. ");
+               fprintf(stderr, "Using default - FALSE\n");
+               cfg_int32 = 0;
+       }
+       sec_opt->jtag_enable = cfg_int32;
+
+       if (config_lookup_int(&sec_cfg, "jtag.delay",
+                             &cfg_int32) != CONFIG_TRUE) {
+               fprintf(stderr, "Error obtaining \"jtag.delay\" element. ");
+               fprintf(stderr, "Using default - 0us\n");
+               cfg_int32 = 0;
+       }
+       sec_opt->jtag_delay = cfg_int32;
+
+       /* eFUSE option */
+       if (config_lookup_bool(&sec_cfg, "efuse_disable",
+                              &cfg_int32) != CONFIG_TRUE) {
+               fprintf(stderr, "Error obtaining \"efuse_disable\" element. ");
+               fprintf(stderr, "Using default - TRUE\n");
+               cfg_int32 = 1;
+       }
+       sec_opt->efuse_disable = cfg_int32;
+
+       /* Box ID option */
+       if (config_lookup_int(&sec_cfg, "box_id", &cfg_int32) != CONFIG_TRUE) {
+               fprintf(stderr, "Error obtaining \"box_id\" element. ");
+               fprintf(stderr, "Using default - 0x0\n");
+               cfg_int32 = 0;
+       }
+       sec_opt->box_id = cfg_int32;
+
+       /* Flash ID option */
+       if (config_lookup_int(&sec_cfg, "flash_id",
+                             &cfg_int32) != CONFIG_TRUE) {
+               fprintf(stderr, "Error obtaining \"flash_id\" element. ");
+               fprintf(stderr, "Using default - 0x0\n");
+               cfg_int32 = 0;
+       }
+       sec_opt->flash_id = cfg_int32;
+
+       /* CSK index option */
+       if (config_lookup_int(&sec_cfg, "csk_key_index",
+                             &cfg_int32) != CONFIG_TRUE) {
+               fprintf(stderr, "Error obtaining \"flash_id\" element. "
+               fprintf(stderr, "Using default - 0x0\n");
+               cfg_int32 = 0;
+       }
+       sec_opt->csk_index = cfg_int32;
+
+       /* Secure boot control array */
+       control_array = config_lookup(&sec_cfg, "control");
+       if (control_array != NULL) {
+               array_sz = config_setting_length(control_array);
+               if (array_sz == 0)
+                       fprintf(stderr, "The \"control\" array is empty!\n");
+       } else {
+               fprintf(stderr, "The \"control\" is undefined!\n");
+               array_sz = 0;
+       }
+
+       for (element = 0; element < CP_CTRL_EL_ARRAY_SZ; element++) {
+               sec_opt->cp_ctrl_arr[element] =
+                       config_setting_get_int_elem(control_array, element * 2);
+               sec_opt->cp_efuse_arr[element] =
+                       config_setting_get_int_elem(control_array,
+                                                   element * 2 + 1);
+       }
+
+       opts.sec_opts = sec_opt;
+       rval = 0;
+
+exit_parse:
+       config_destroy(&sec_cfg);
+       if (sec_opt && (rval != 0))
+               free(sec_opt);
+       return rval;
+} /* end of parse_sec_config_file */
+
+int format_sec_ext(char *filename, FILE *out_fd)
+{
+       ext_header_t    header;
+       sec_entry_t     sec_ext;
+       int             index;
+       int             written;
+
+#define DER_BUF_SZ     1600
+
+       /* First, parse the configuration file */
+       if (parse_sec_config_file(filename)) {
+               fprintf(stderr,
+                       "failed parsing configuration file %s\n", filename);
+               return 1;
+       }
+
+       /* Everything except signatures can be created at this stage */
+       header.type = EXT_TYPE_SECURITY;
+       header.offset = 0;
+       header.size = sizeof(sec_entry_t);
+       header.reserved = 0;
+
+       /* Bring up RSA context and read private keys from their files */
+       for (index = 0; index < (CSK_ARR_SZ + 1); index++) {
+               /* for every private key file */
+               mbedtls_pk_context      *pk_ctx = (index == CSK_ARR_SZ) ?
+                                       &opts.sec_opts->kak_pk :
+                                       &opts.sec_opts->csk_pk[index];
+               char            *fname = (index == CSK_ARR_SZ) ?
+                                       opts.sec_opts->kak_key_file :
+                                       opts.sec_opts->csk_key_file[index];
+               uint8_t         *out_der_key = (index == CSK_ARR_SZ) ?
+                                       sec_ext.kak_key :
+                                       sec_ext.csk_keys[index];
+               size_t          output_len;
+               unsigned char   output_buf[DER_BUF_SZ];
+               unsigned char   *der_buf_start;
+
+               /* Handle invalid/reserved file names */
+               if (strncmp(CSK_ARR_EMPTY_FILE, fname,
+                           strlen(CSK_ARR_EMPTY_FILE)) == 0) {
+                       if (opts.sec_opts->csk_index == index) {
+                               fprintf(stderr,
+                                       "CSK file with index %d cannot be %s\n",
+                                       index, CSK_ARR_EMPTY_FILE);
+                               return 1;
+                       } else if (index == CSK_ARR_SZ) {
+                               fprintf(stderr, "KAK file name cannot be %s\n",
+                                       CSK_ARR_EMPTY_FILE);
+                               return 1;
+                       }
+                       /* this key will be empty in CSK array */
+                       continue;
+               }
+
+               mbedtls_pk_init(pk_ctx);
+               /* Read the private RSA key into the context
+                * and verify it (no password)
+                */
+               if (mbedtls_pk_parse_keyfile(pk_ctx, fname, "") != 0) {
+                       fprintf(stderr,
+                               "Cannot read RSA private key file %s\n", fname);
+                       return 1;
+               }
+
+               /* Create a public key out of private one
+                * and store it in DER format
+                */
+               output_len = mbedtls_pk_write_pubkey_der(pk_ctx,
+                                                        output_buf,
+                                                        DER_BUF_SZ);
+               if (output_len < 0) {
+                       fprintf(stderr,
+                               "Failed to create DER coded PUB key (%s)\n",
+                               fname);
+                       return 1;
+               }
+               /* Data in the output buffer is aligned to the buffer end */
+               der_buf_start = output_buf + sizeof(output_buf) - output_len;
+               /* In the header DER data is aligned
+                * to the start of appropriate field
+                */
+               memcpy(out_der_key, der_buf_start, output_len);
+
+       } /* for every private key file */
+
+       /* The CSK block signature can be created here */
+       if (create_rsa_signature(&opts.sec_opts->kak_pk,
+                                &sec_ext.csk_keys[0][0],
+                                sizeof(sec_ext.csk_keys),
+                                opts.sec_opts->csk_key_file[
+                                        opts.sec_opts->csk_index],
+                                sec_ext.csk_sign) != 0) {
+               fprintf(stderr, "Failed to sign CSK keys block!\n");
+               return 1;
+       }
+       /* Check that everything is correct */
+       if (verify_rsa_signature(sec_ext.kak_key, MAX_RSA_DER_BYTE_LEN,
+                                &sec_ext.csk_keys[0][0],
+                                sizeof(sec_ext.csk_keys),
+                                opts.sec_opts->kak_key_file,
+                                sec_ext.csk_sign) != 0) {
+               fprintf(stderr, "Failed to verify CSK keys block signature!\n");
+               return 1;
+       }
+
+       /* AES encryption stuff */
+       if (strlen(opts.sec_opts->aes_key_file) != 0) {
+               FILE            *in_fd;
+
+               in_fd = fopen(opts.sec_opts->aes_key_file, "rb");
+               if (in_fd == NULL) {
+                       fprintf(stderr, "Failed to open AES key file %s\n",
+                               opts.sec_opts->aes_key_file);
+                       return 1;
+               }
+
+               /* Read the AES key in ASCII format byte by byte */
+               for (index = 0; index < AES_KEY_BYTE_LEN; index++) {
+                       if (fscanf(in_fd, "%02hhx",
+                           opts.sec_opts->aes_key + index) != 1) {
+                               fprintf(stderr,
+                                       "Failed to read AES key byte %d ",
+                                       index);
+                               fprintf(stderr,
+                                       "from file %s\n",
+                                       opts.sec_opts->aes_key_file);
+                               fclose(in_fd);
+                               return 1;
+                       }
+               }
+               fclose(in_fd);
+               sec_ext.encrypt_en = 1;
+       } else {
+               sec_ext.encrypt_en = 0;
+       }
+
+       /* Fill the rest of the trusted boot extension fields */
+       sec_ext.box_id          = opts.sec_opts->box_id;
+       sec_ext.flash_id        = opts.sec_opts->flash_id;
+       sec_ext.efuse_dis       = opts.sec_opts->efuse_disable;
+       sec_ext.jtag_delay      = opts.sec_opts->jtag_delay;
+       sec_ext.jtag_en         = opts.sec_opts->jtag_enable;
+
+       memcpy(sec_ext.cp_ctrl_arr,
+              opts.sec_opts->cp_ctrl_arr,
+              sizeof(uint32_t) * CP_CTRL_EL_ARRAY_SZ);
+       memcpy(sec_ext.cp_efuse_arr,
+              opts.sec_opts->cp_efuse_arr,
+              sizeof(uint32_t) * CP_CTRL_EL_ARRAY_SZ);
+
+       /* Write the resulting extension to file
+        * (image and header signature fields are still empty)
+        */
+
+       /* Write extension header */
+       written = fwrite(&header, sizeof(ext_header_t), 1, out_fd);
+       if (written != 1) {
+               fprintf(stderr,
+                       "Failed to write SEC extension header to the file\n");
+               return 1;
+       }
+       /* Write extension body */
+       written = fwrite(&sec_ext, sizeof(sec_entry_t), 1, out_fd);
+       if (written != 1) {
+               fprintf(stderr,
+                       "Failed to write SEC extension body to the file\n");
+               return 1;
+       }
+
+       return 0;
+}
+
+/*******************************************************************************
+ *    finalize_secure_ext
+ *          Make final changes to secure extension - calculate image and header
+ *          signatures and encrypt the image if needed.
+ *          The main header checksum and image size fields updated accordingly
+ *    INPUT:
+ *          header       Main header
+ *          prolog_buf   the entire prolog buffer
+ *          prolog_size  prolog buffer length
+ *          image_buf    buffer containing the input binary image
+ *          image_size   image buffer size.
+ *    OUTPUT:
+ *          none
+ *    RETURN:
+ *          0 on success
+ */
+int finalize_secure_ext(header_t *header,
+                       uint8_t *prolog_buf, uint32_t prolog_size,
+                       uint8_t *image_buf, int image_size)
+{
+       int             cur_ext, offset;
+       uint8_t         *final_image = image_buf;
+       uint32_t        final_image_sz = image_size;
+       uint8_t         hdr_sign[RSA_SIGN_BYTE_LEN];
+       sec_entry_t     *sec_ext = 0;
+
+       /* Find the Trusted Boot Header between available extensions */
+       for (cur_ext = 0, offset = sizeof(header_t);
+            cur_ext < header->ext_count; cur_ext++) {
+               ext_header_t *ext_hdr = (ext_header_t *)(prolog_buf + offset);
+
+               if (ext_hdr->type == EXT_TYPE_SECURITY) {
+                       sec_ext = (sec_entry_t *)(prolog_buf + offset +
+                                  sizeof(ext_header_t) + ext_hdr->offset);
+                       break;
+               }
+
+               offset += sizeof(ext_header_t);
+               /* If offset is Zero, the extension follows its header */
+               if (ext_hdr->offset == 0)
+                       offset += ext_hdr->size;
+       }
+
+       if (sec_ext == 0) {
+               fprintf(stderr, "Error: No Trusted Boot extension found!\n");
+               return -1;
+       }
+
+       if (sec_ext->encrypt_en) {
+               /* Encrypt the image if needed */
+               fprintf(stdout, "Encrypting the image...\n");
+
+               if (image_encrypt(image_buf, image_size) != 0) {
+                       fprintf(stderr, "Failed to encrypt the image!\n");
+                       return -1;
+               }
+
+               /* Image size and checksum should be updated after encryption.
+                * This way the image could be verified by the BootROM
+                * before decryption.
+                */
+               final_image = opts.sec_opts->encrypted_image;
+               final_image_sz = opts.sec_opts->enc_image_sz;
+
+               header->boot_image_size = final_image_sz;
+               header->boot_image_checksum =
+                       checksum32((uint32_t *)final_image, final_image_sz);
+       } /* AES encryption */
+
+       /* Create the image signature first, since it will be later
+        * signed along with the header signature
+        */
+       if (create_rsa_signature(&opts.sec_opts->csk_pk[
+                                       opts.sec_opts->csk_index],
+                                final_image, final_image_sz,
+                                opts.sec_opts->csk_key_file[
+                                       opts.sec_opts->csk_index],
+                                sec_ext->image_sign) != 0) {
+               fprintf(stderr, "Failed to sign image!\n");
+               return -1;
+       }
+       /* Check that the image signature is correct */
+       if (verify_rsa_signature(sec_ext->csk_keys[opts.sec_opts->csk_index],
+                                MAX_RSA_DER_BYTE_LEN,
+                                final_image, final_image_sz,
+                                opts.sec_opts->csk_key_file[
+                                        opts.sec_opts->csk_index],
+                                sec_ext->image_sign) != 0) {
+               fprintf(stderr, "Failed to verify image signature!\n");
+               return -1;
+       }
+
+       /* Sign the headers and all the extensions block
+        * when the header signature field is empty
+        */
+       if (create_rsa_signature(&opts.sec_opts->csk_pk[
+                                        opts.sec_opts->csk_index],
+                                prolog_buf, prolog_size,
+                                opts.sec_opts->csk_key_file[
+                                        opts.sec_opts->csk_index],
+                                hdr_sign) != 0) {
+               fprintf(stderr, "Failed to sign header!\n");
+               return -1;
+       }
+       /* Check that the header signature is correct */
+       if (verify_rsa_signature(sec_ext->csk_keys[opts.sec_opts->csk_index],
+                                MAX_RSA_DER_BYTE_LEN,
+                                prolog_buf, prolog_size,
+                                opts.sec_opts->csk_key_file[
+                                        opts.sec_opts->csk_index],
+                                hdr_sign) != 0) {
+               fprintf(stderr, "Failed to verify header signature!\n");
+               return -1;
+       }
+
+       /* Finally, copy the header signature into the trusted boot extension */
+       memcpy(sec_ext->header_sign, hdr_sign, RSA_SIGN_BYTE_LEN);
+
+       return 0;
+}
+
+#endif /* CONFIG_MVEBU_SECURE_BOOT */
+
+
+#define FMT_HEX                0
+#define FMT_DEC                1
+#define FMT_BIN                2
+#define FMT_NONE       3
+
+void do_print_field(unsigned int value, char *name,
+                   int start, int size, int format)
+{
+       fprintf(stdout, "[0x%05x : 0x%05x]  %-26s",
+               start, start + size - 1, name);
+
+       switch (format) {
+       case FMT_HEX:
+               printf("0x%x\n", value);
+               break;
+       case FMT_DEC:
+               printf("%d\n", value);
+               break;
+       default:
+               printf("\n");
+               break;
+       }
+}
+
+#define print_field(st, type, field, hex, base) \
+                       do_print_field((int)st->field, #field, \
+                       base + offsetof(type, field), sizeof(st->field), hex)
+
+int print_header(uint8_t *buf, int base)
+{
+       header_t *main_hdr;
+
+       main_hdr = (header_t *)buf;
+
+       fprintf(stdout, "########### Header ##############\n");
+       print_field(main_hdr, header_t, magic, FMT_HEX, base);
+       print_field(main_hdr, header_t, prolog_size, FMT_DEC, base);
+       print_field(main_hdr, header_t, prolog_checksum, FMT_HEX, base);
+       print_field(main_hdr, header_t, boot_image_size, FMT_DEC, base);
+       print_field(main_hdr, header_t, boot_image_checksum, FMT_HEX, base);
+       print_field(main_hdr, header_t, rsrvd0, FMT_HEX, base);
+       print_field(main_hdr, header_t, load_addr, FMT_HEX, base);
+       print_field(main_hdr, header_t, exec_addr, FMT_HEX, base);
+       print_field(main_hdr, header_t, uart_cfg, FMT_HEX, base);
+       print_field(main_hdr, header_t, baudrate, FMT_HEX, base);
+       print_field(main_hdr, header_t, ext_count, FMT_DEC, base);
+       print_field(main_hdr, header_t, aux_flags, FMT_HEX, base);
+       print_field(main_hdr, header_t, io_arg_0, FMT_HEX, base);
+       print_field(main_hdr, header_t, io_arg_1, FMT_HEX, base);
+       print_field(main_hdr, header_t, io_arg_2, FMT_HEX, base);
+       print_field(main_hdr, header_t, io_arg_3, FMT_HEX, base);
+       print_field(main_hdr, header_t, rsrvd1, FMT_HEX, base);
+       print_field(main_hdr, header_t, rsrvd2, FMT_HEX, base);
+       print_field(main_hdr, header_t, rsrvd3, FMT_HEX, base);
+
+       return sizeof(header_t);
+}
+
+int print_ext_hdr(ext_header_t *ext_hdr, int base)
+{
+       print_field(ext_hdr, ext_header_t, type, FMT_HEX, base);
+       print_field(ext_hdr, ext_header_t, offset, FMT_HEX, base);
+       print_field(ext_hdr, ext_header_t, reserved, FMT_HEX, base);
+       print_field(ext_hdr, ext_header_t, size, FMT_DEC, base);
+
+       return base + sizeof(ext_header_t);
+}
+
+void print_sec_ext(ext_header_t *ext_hdr, int base)
+{
+       sec_entry_t     *sec_entry;
+       uint32_t        new_base;
+
+       fprintf(stdout, "\n########### Secure extension ###########\n");
+
+       new_base = print_ext_hdr(ext_hdr, base);
+
+       sec_entry = (sec_entry_t *)(ext_hdr + 1);
+
+       do_print_field(0, "KAK key", new_base, MAX_RSA_DER_BYTE_LEN, FMT_NONE);
+       new_base += MAX_RSA_DER_BYTE_LEN;
+       print_field(sec_entry, sec_entry_t, jtag_delay, FMT_DEC, base);
+       print_field(sec_entry, sec_entry_t, box_id, FMT_HEX, base);
+       print_field(sec_entry, sec_entry_t, flash_id, FMT_HEX, base);
+       print_field(sec_entry, sec_entry_t, encrypt_en, FMT_DEC, base);
+       print_field(sec_entry, sec_entry_t, efuse_dis, FMT_DEC, base);
+       new_base += 6 * sizeof(uint32_t);
+       do_print_field(0, "header signature",
+                      new_base, RSA_SIGN_BYTE_LEN, FMT_NONE);
+       new_base += RSA_SIGN_BYTE_LEN;
+       do_print_field(0, "image signature",
+                      new_base, RSA_SIGN_BYTE_LEN, FMT_NONE);
+       new_base += RSA_SIGN_BYTE_LEN;
+       do_print_field(0, "CSK keys", new_base,
+                      CSK_ARR_SZ * MAX_RSA_DER_BYTE_LEN, FMT_NONE);
+       new_base += CSK_ARR_SZ * MAX_RSA_DER_BYTE_LEN;
+       do_print_field(0, "CSK block signature",
+                      new_base, RSA_SIGN_BYTE_LEN, FMT_NONE);
+       new_base += RSA_SIGN_BYTE_LEN;
+       do_print_field(0, "control", new_base,
+                      CP_CTRL_EL_ARRAY_SZ * 2, FMT_NONE);
+
+}
+
+void print_bin_ext(ext_header_t *ext_hdr, int base)
+{
+       fprintf(stdout, "\n########### Binary extension ###########\n");
+       base = print_ext_hdr(ext_hdr, base);
+       do_print_field(0, "binary image", base, ext_hdr->size, FMT_NONE);
+}
+
+int print_extension(void *buf, int base, int count, int ext_size)
+{
+       ext_header_t *ext_hdr = buf;
+       int pad = ext_size;
+       int curr_size;
+
+       while (count--) {
+               if (ext_hdr->type == EXT_TYPE_BINARY)
+                       print_bin_ext(ext_hdr, base);
+               else if (ext_hdr->type == EXT_TYPE_SECURITY)
+                       print_sec_ext(ext_hdr, base);
+
+               curr_size = sizeof(ext_header_t) + ext_hdr->size;
+               base += curr_size;
+               pad  -= curr_size;
+               ext_hdr = (ext_header_t *)((uintptr_t)ext_hdr + curr_size);
+       }
+
+       if (pad)
+               do_print_field(0, "padding", base, pad, FMT_NONE);
+
+       return ext_size;
+}
+
+int parse_image(uint8_t *buf, int size)
+{
+       int base = 0;
+       int ret = 1;
+       header_t *main_hdr;
+       uint32_t checksum, prolog_checksum;
+
+
+       fprintf(stdout,
+               "################### Prolog Start ######################\n\n");
+       main_hdr = (header_t *)buf;
+       base += print_header(buf, base);
+
+       if (main_hdr->ext_count)
+               base += print_extension(buf + base, base,
+                                       main_hdr->ext_count,
+                                       main_hdr->prolog_size -
+                                       sizeof(header_t));
+
+       if (base < main_hdr->prolog_size) {
+               fprintf(stdout, "\n########### Padding ##############\n");
+               do_print_field(0, "prolog padding",
+                              base, main_hdr->prolog_size - base, FMT_HEX);
+               base = main_hdr->prolog_size;
+       }
+       fprintf(stdout,
+               "\n################### Prolog End ######################\n");
+
+       fprintf(stdout,
+               "\n################### Boot image ######################\n");
+
+       do_print_field(0, "boot image", base, size - base - 4, FMT_NONE);
+
+       fprintf(stdout,
+               "################### Image end ########################\n");
+
+       /* Check sanity for certain values */
+       printf("\nChecking values:\n");
+
+       if (main_hdr->magic == MAIN_HDR_MAGIC) {
+               fprintf(stdout, "Headers magic:    OK!\n");
+       } else {
+               fprintf(stderr,
+                       "\n****** ERROR: HEADER MAGIC 0x%08x != 0x%08x\n",
+                       main_hdr->magic, MAIN_HDR_MAGIC);
+               goto error;
+       }
+
+       /* headers checksum */
+       /* clear the checksum field in header to calculate checksum */
+       prolog_checksum = main_hdr->prolog_checksum;
+       main_hdr->prolog_checksum = 0;
+       checksum = checksum32((uint32_t *)buf, main_hdr->prolog_size);
+
+       if (checksum == prolog_checksum) {
+               fprintf(stdout, "Headers checksum: OK!\n");
+       } else {
+               fprintf(stderr,
+                       "\n***** ERROR: BAD HEADER CHECKSUM 0x%08x != 0x%08x\n",
+                       checksum, prolog_checksum);
+               goto error;
+       }
+
+       /* boot image checksum */
+       checksum = checksum32((uint32_t *)(buf + main_hdr->prolog_size),
+                             main_hdr->boot_image_size);
+       if (checksum == main_hdr->boot_image_checksum) {
+               fprintf(stdout, "Image checksum:   OK!\n");
+       } else {
+               fprintf(stderr,
+                       "\n****** ERROR: BAD IMAGE CHECKSUM 0x%08x != 0x%08x\n",
+                       checksum, main_hdr->boot_image_checksum);
+               goto error;
+       }
+
+#ifdef CONFIG_MVEBU_SECURE_BOOT
+       /* RSA signatures */
+       if (main_hdr->ext_count) {
+               uint8_t         ext_num = main_hdr->ext_count;
+               ext_header_t    *ext_hdr = (ext_header_t *)(main_hdr + 1);
+               unsigned char   hash[32];
+               int             i;
+
+               while (ext_num--) {
+                       if (ext_hdr->type == EXT_TYPE_SECURITY) {
+                               sec_entry_t  *sec_entry =
+                                               (sec_entry_t *)(ext_hdr + 1);
+
+                               ret = verify_secure_header_signatures(
+                                                       main_hdr, sec_entry);
+                               if (ret != 0) {
+                                       fprintf(stderr,
+                                               "\n****** FAILED TO VERIFY ");
+                                       fprintf(stderr,
+                                               "RSA SIGNATURES ********\n");
+                                       goto error;
+                               }
+
+                               mbedtls_sha256(sec_entry->kak_key,
+                                              MAX_RSA_DER_BYTE_LEN, hash, 0);
+                               fprintf(stdout,
+                                       ">>>>>>>>>> KAK KEY HASH >>>>>>>>>>\n");
+                               fprintf(stdout, "SHA256: ");
+                               for (i = 0; i < 32; i++)
+                                       fprintf(stdout, "%02X", hash[i]);
+
+                               fprintf(stdout,
+                                       "\n<<<<<<<<< KAK KEY HASH <<<<<<<<<\n");
+
+                               break;
+                       }
+                       ext_hdr =
+                               (ext_header_t *)((uint8_t *)(ext_hdr + 1) +
+                                ext_hdr->size);
+               }
+       }
+#endif
+
+       ret = 0;
+error:
+       return ret;
+}
+
+int format_bin_ext(char *filename, FILE *out_fd)
+{
+       ext_header_t header;
+       FILE *in_fd;
+       int size, written;
+       int aligned_size, pad_bytes;
+       char c;
+
+       in_fd = fopen(filename, "rb");
+       if (in_fd == NULL) {
+               fprintf(stderr, "failed to open bin extension file %s\n",
+                       filename);
+               return 1;
+       }
+
+       size = get_file_size(filename);
+       if (size <= 0) {
+               fprintf(stderr, "bin extension file size is bad\n");
+               return 1;
+       }
+
+       /* Align extension size to 8 bytes */
+       aligned_size = (size + 7) & (~7);
+       pad_bytes    = aligned_size - size;
+
+       header.type = EXT_TYPE_BINARY;
+       header.offset = 0;
+       header.size = aligned_size;
+       header.reserved = 0;
+
+       /* Write header */
+       written = fwrite(&header, sizeof(ext_header_t), 1, out_fd);
+       if (written != 1) {
+               fprintf(stderr, "failed writing header to extension file\n");
+               return 1;
+       }
+
+       /* Write image */
+       while (size--) {
+               c = getc(in_fd);
+               fputc(c, out_fd);
+       }
+
+       while (pad_bytes--)
+               fputc(0, out_fd);
+
+       fclose(in_fd);
+
+       return 0;
+}
+
+/* ****************************************
+ *
+ * Write all extensions (binary, secure
+ * extensions) to file
+ *
+ * ****************************************/
+
+int format_extensions(char *ext_filename)
+{
+       FILE *out_fd;
+       int ret = 0;
+
+       out_fd = fopen(ext_filename, "wb");
+       if (out_fd == NULL) {
+               fprintf(stderr, "failed to open extension output file %s",
+                       ext_filename);
+               return 1;
+       }
+
+       if (strncmp(opts.bin_ext_file, "NA", MAX_FILENAME)) {
+               if (format_bin_ext(opts.bin_ext_file, out_fd)) {
+                       ret = 1;
+                       goto error;
+               }
+       }
+#ifdef CONFIG_MVEBU_SECURE_BOOT
+       if (strncmp(opts.sec_cfg_file, "NA", MAX_FILENAME)) {
+               if (format_sec_ext(opts.sec_cfg_file, out_fd)) {
+                       ret = 1;
+                       goto error;
+               }
+       }
+#endif
+
+error:
+       fflush(out_fd);
+       fclose(out_fd);
+       return ret;
+}
+
+void update_uart(header_t *header)
+{
+       header->uart_cfg = 0;
+       header->baudrate = 0;
+
+       if (opts.disable_print)
+               uart_set_mode(header->uart_cfg, UART_MODE_DISABLE);
+
+       if (opts.baudrate)
+               header->baudrate = (opts.baudrate / 1200);
+}
+
+/* ****************************************
+ *
+ * Write the image prolog, i.e.
+ * main header and extensions, to file
+ *
+ * ****************************************/
+
+int write_prolog(int ext_cnt, char *ext_filename,
+                uint8_t *image_buf, int image_size, FILE *out_fd)
+{
+       header_t                *header;
+       int main_hdr_size = sizeof(header_t);
+       int prolog_size = main_hdr_size;
+       FILE *ext_fd;
+       char *buf;
+       int written, read;
+       int ret = 1;
+
+
+       if (ext_cnt)
+               prolog_size +=  get_file_size(ext_filename);
+
+       prolog_size = ((prolog_size + PROLOG_ALIGNMENT) &
+                    (~(PROLOG_ALIGNMENT-1)));
+
+       /* Allocate a zeroed buffer to zero the padding bytes */
+       buf = calloc(prolog_size, 1);
+       if (buf == NULL) {
+               fprintf(stderr, "Error: failed allocating checksum buffer\n");
+               return 1;
+       }
+
+       header = (header_t *)buf;
+       header->magic       = MAIN_HDR_MAGIC;
+       header->prolog_size = prolog_size;
+       header->load_addr   = opts.load_addr;
+       header->exec_addr   = opts.exec_addr;
+       header->io_arg_0    = opts.nfc_io_args;
+       header->ext_count   = ext_cnt;
+       header->aux_flags   = 0;
+       header->boot_image_size = (image_size + 3) & (~0x3);
+       header->boot_image_checksum = checksum32((uint32_t *)image_buf,
+                                                image_size);
+
+       update_uart(header);
+
+       /* Populate buffer with main header and extensions */
+       if (ext_cnt) {
+               ext_fd = fopen(ext_filename, "rb");
+               if (ext_fd == NULL) {
+                       fprintf(stderr,
+                               "Error: failed to open extensions file\n");
+                       goto error;
+               }
+
+               read = fread(&buf[main_hdr_size],
+                            get_file_size(ext_filename), 1, ext_fd);
+               if (read != 1) {
+                       fprintf(stderr,
+                               "Error: failed to open extensions file\n");
+                       goto error;
+               }
+
+#ifdef CONFIG_MVEBU_SECURE_BOOT
+               /* Secure boot mode? */
+               if (opts.sec_opts != 0) {
+                       ret = finalize_secure_ext(header, (uint8_t *)buf,
+                                                 prolog_size, image_buf,
+                                                 image_size);
+                       if (ret != 0) {
+                               fprintf(stderr, "Error: failed to handle ");
+                               fprintf(stderr, "secure extension!\n");
+                               goto error;
+                       }
+               } /* secure boot mode */
+#endif
+       }
+
+       /* Update the total prolog checksum */
+       header->prolog_checksum = checksum32((uint32_t *)buf, prolog_size);
+
+       /* Now spill everything to output file */
+       written = fwrite(buf, prolog_size, 1, out_fd);
+       if (written != 1) {
+               fprintf(stderr,
+                       "Error: failed to write prolog to output file\n");
+               goto error;
+       }
+
+       ret = 0;
+
+error:
+       free(buf);
+       return ret;
+}
+
+int write_boot_image(uint8_t *buf, uint32_t image_size, FILE *out_fd)
+{
+       int aligned_size;
+       int written;
+
+       /* Image size must be aligned to 4 bytes */
+       aligned_size = (image_size + 3) & (~0x3);
+
+       written = fwrite(buf, aligned_size, 1, out_fd);
+       if (written != 1) {
+               fprintf(stderr, "Error: Failed to write boot image\n");
+               goto error;
+       }
+
+       return 0;
+error:
+       return 1;
+}
+
+int main(int argc, char *argv[])
+{
+       char in_file[MAX_FILENAME+1];
+       char out_file[MAX_FILENAME+1];
+       char ext_file[MAX_FILENAME+1];
+       FILE *in_fd = NULL;
+       FILE *out_fd = NULL;
+       int parse = 0;
+       int ext_cnt = 0;
+       int opt;
+       int ret = 0;
+       int image_size;
+       uint8_t *image_buf = NULL;
+       int read;
+       uint32_t nand_block_size_kb, mlc_nand;
+
+       /* Create temporary file for building extensions
+        * Use process ID for allowing multiple parallel runs
+        */
+       snprintf(ext_file, MAX_FILENAME, "/tmp/ext_file-%x", getpid());
+
+       while ((opt = getopt(argc, argv, "hpms:i:l:e:a:b:u:n:t:c:k:")) != -1) {
+               switch (opt) {
+               case 'h':
+                       usage();
+                       break;
+               case 'l':
+                       opts.load_addr = strtoul(optarg, NULL, 0);
+                       break;
+               case 'e':
+                       opts.exec_addr = strtoul(optarg, NULL, 0);
+                       break;
+               case 'm':
+                       opts.disable_print = 1;
+                       break;
+               case 'u':
+                       opts.baudrate = strtoul(optarg, NULL, 0);
+                       break;
+               case 'b':
+                       strncpy(opts.bin_ext_file, optarg, MAX_FILENAME);
+                       ext_cnt++;
+                       break;
+               case 'p':
+                       parse = 1;
+                       break;
+               case 'n':
+                       nand_block_size_kb = strtoul(optarg, NULL, 0);
+                       opts.nfc_io_args |= (nand_block_size_kb / 64);
+                       break;
+               case 't':
+                       mlc_nand = 0;
+                       if (!strncmp("MLC", optarg, 3))
+                               mlc_nand = 1;
+                       opts.nfc_io_args |= (mlc_nand << 8);
+                       break;
+#ifdef CONFIG_MVEBU_SECURE_BOOT
+               case 'c': /* SEC extension */
+                       strncpy(opts.sec_cfg_file, optarg, MAX_FILENAME);
+                       ext_cnt++;
+                       break;
+               case 'k':
+                       opts.key_index = strtoul(optarg, NULL, 0);
+                       break;
+#endif
+               default: /* '?' */
+                       usage_err("Unknown argument");
+                       exit(EXIT_FAILURE);
+               }
+       }
+
+       /* Check validity of inputes */
+       if (opts.load_addr % 8)
+               usage_err("Load address must be 8 bytes aligned");
+
+       if (opts.baudrate % 1200)
+               usage_err("Baudrate must be a multiple of 1200");
+
+       /* The remaining arguments are the input
+        * and potentially output file
+        */
+       /* Input file must exist so exit if not */
+       if (optind >= argc)
+               usage_err("missing input file name");
+
+       strncpy(in_file, argv[optind], MAX_FILENAME);
+       optind++;
+
+       /* Output file must exist in non parse mode */
+       if (optind < argc)
+               strncpy(out_file, argv[optind], MAX_FILENAME);
+       else if (!parse)
+               usage_err("missing output file name");
+
+       /* open the input file */
+       in_fd = fopen(in_file, "rb");
+       if (in_fd == NULL) {
+               printf("Error: Failed to open input file %s\n", in_file);
+               goto main_exit;
+       }
+
+       /* Read the input file to buffer */
+       image_size = get_file_size(in_file);
+       image_buf = calloc((image_size + AES_BLOCK_SZ - 1) &
+                          ~(AES_BLOCK_SZ - 1), 1);
+       if (image_buf == NULL) {
+               fprintf(stderr, "Error: failed allocating input buffer\n");
+               return 1;
+       }
+
+       read = fread(image_buf, image_size, 1, in_fd);
+       if (read != 1) {
+               fprintf(stderr, "Error: failed to read input file\n");
+               goto main_exit;
+       }
+
+       /* Parse the input image and leave */
+       if (parse) {
+               if (opts.key_index >= CSK_ARR_SZ) {
+                       fprintf(stderr,
+                               "Wrong key IDX value. Valid values 0 - %d\n",
+                               CSK_ARR_SZ - 1);
+                       goto main_exit;
+               }
+               ret = parse_image(image_buf, image_size);
+               goto main_exit;
+       }
+
+       /* Create a blob file from all extensions */
+       if (ext_cnt) {
+               ret = format_extensions(ext_file);
+               if (ret)
+                       goto main_exit;
+       }
+
+       out_fd = fopen(out_file, "wb");
+       if (out_fd == NULL) {
+               fprintf(stderr,
+                       "Error: Failed to open output file %s\n", out_file);
+               goto main_exit;
+       }
+
+       ret = write_prolog(ext_cnt, ext_file, image_buf, image_size, out_fd);
+       if (ret)
+               goto main_exit;
+
+#ifdef CONFIG_MVEBU_SECURE_BOOT
+       if (opts.sec_opts && (opts.sec_opts->encrypted_image != 0) &&
+           (opts.sec_opts->enc_image_sz != 0)) {
+               ret = write_boot_image(opts.sec_opts->encrypted_image,
+                                      opts.sec_opts->enc_image_sz, out_fd);
+       } else
+#endif
+               ret = write_boot_image(image_buf, image_size, out_fd);
+       if (ret)
+               goto main_exit;
+
+main_exit:
+       if (in_fd)
+               fclose(in_fd);
+
+       if (out_fd)
+               fclose(out_fd);
+
+       if (image_buf)
+               free(image_buf);
+
+       unlink(ext_file);
+
+#ifdef CONFIG_MVEBU_SECURE_BOOT
+       if (opts.sec_opts) {
+               if (opts.sec_opts->encrypted_image)
+                       free(opts.sec_opts->encrypted_image);
+               free(opts.sec_opts);
+       }
+#endif
+       exit(ret);
+}
diff --git a/tools/doimage/doimage.mk b/tools/doimage/doimage.mk
new file mode 100644 (file)
index 0000000..2b751d4
--- /dev/null
@@ -0,0 +1,15 @@
+#
+# Copyright (C) 2018 Marvell International Ltd.
+#
+# SPDX-License-Identifier:     BSD-3-Clause
+# https://spdx.org/licenses
+
+DOIMAGE_FLAGS          ?=      -l 0x4100000 -e 0x4100000
+
+
+#NAND params
+#Open and update the below when using NAND as a boot device.
+
+CONFIG_MVEBU_NAND_BLOCK_SIZE   := 256
+CONFIG_MVEBU_NAND_CELL_TYPE    := SLC
+NAND_DOIMAGE_FLAGS := -t $(CONFIG_MVEBU_NAND_CELL_TYPE) -n $(CONFIG_MVEBU_NAND_BLOCK_SIZE)