summaryrefslogtreecommitdiff
path: root/plat/hisilicon
diff options
context:
space:
mode:
authorHaojian Zhuang <haojian.zhuang@linaro.org>2017-06-01 12:15:14 +0800
committerHaojian Zhuang <haojian.zhuang@linaro.org>2017-06-08 07:31:25 +0800
commit2f2abcf4ba37bdd1332111c240961aae509c5d9c (patch)
tree3d2a553c34bf6bb78169623723a9819ddbbea835 /plat/hisilicon
parente6a993d4277192f7c08a6cf7e39a36367caeeeaa (diff)
hikey960: support BL1 on hikey960 platform
Support BL1 on HiKey960 platform. When recovery mode is detected, BL1 loads NS BL1U that flushs images into UFS. When normal boot mode is detected, BL1 loads BL2. Fix for https://github.com/ARM-software/tf-issues/issues/486 Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
Diffstat (limited to 'plat/hisilicon')
-rw-r--r--plat/hisilicon/hikey960/aarch64/hikey960_common.c109
-rw-r--r--plat/hisilicon/hikey960/aarch64/hikey960_helpers.S145
-rw-r--r--plat/hisilicon/hikey960/hikey960_bl1_setup.c705
-rw-r--r--plat/hisilicon/hikey960/hikey960_boardid.c172
-rw-r--r--plat/hisilicon/hikey960/hikey960_def.h37
-rw-r--r--plat/hisilicon/hikey960/hikey960_io_storage.c190
-rw-r--r--plat/hisilicon/hikey960/hikey960_private.h30
-rw-r--r--plat/hisilicon/hikey960/include/hi3660.h343
-rw-r--r--plat/hisilicon/hikey960/include/hi3660_crg.h179
-rw-r--r--plat/hisilicon/hikey960/include/hi3660_hkadc.h61
-rw-r--r--plat/hisilicon/hikey960/include/hi3660_mem_map.h20
-rw-r--r--plat/hisilicon/hikey960/include/plat_macros.S79
-rw-r--r--plat/hisilicon/hikey960/include/platform_def.h101
-rw-r--r--plat/hisilicon/hikey960/platform.mk43
14 files changed, 2214 insertions, 0 deletions
diff --git a/plat/hisilicon/hikey960/aarch64/hikey960_common.c b/plat/hisilicon/hikey960/aarch64/hikey960_common.c
new file mode 100644
index 00000000..d7894b3e
--- /dev/null
+++ b/plat/hisilicon/hikey960/aarch64/hikey960_common.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <arm_gic.h>
+#include <assert.h>
+#include <bl_common.h>
+#include <debug.h>
+#include <mmio.h>
+#include <platform.h>
+#include <platform_def.h>
+#include <xlat_tables.h>
+
+#include "../hikey960_def.h"
+#include "../hikey960_private.h"
+
+#define MAP_DDR MAP_REGION_FLAT(DDR_BASE, \
+ DDR_SIZE, \
+ MT_MEMORY | MT_RW | MT_NS)
+
+#define MAP_DEVICE MAP_REGION_FLAT(DEVICE_BASE, \
+ DEVICE_SIZE, \
+ MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_BL1_RW MAP_REGION_FLAT(BL1_RW_BASE, \
+ BL1_RW_LIMIT - BL1_RW_BASE, \
+ MT_MEMORY | MT_RW | MT_NS)
+
+#define MAP_UFS_DATA MAP_REGION_FLAT(HIKEY960_UFS_DATA_BASE, \
+ HIKEY960_UFS_DATA_SIZE, \
+ MT_MEMORY | MT_RW | MT_NS)
+
+#define MAP_UFS_DESC MAP_REGION_FLAT(HIKEY960_UFS_DESC_BASE, \
+ HIKEY960_UFS_DESC_SIZE, \
+ MT_MEMORY | MT_RW | MT_NS)
+
+/*
+ * Table of regions for different BL stages to map using the MMU.
+ * This doesn't include Trusted RAM as the 'mem_layout' argument passed to
+ * hikey960_init_mmu_elx() will give the available subset of that,
+ */
+#if IMAGE_BL1
+static const mmap_region_t hikey960_mmap[] = {
+ MAP_UFS_DATA,
+ MAP_BL1_RW,
+ MAP_UFS_DESC,
+ MAP_DEVICE,
+ {0}
+};
+#endif
+
+#if IMAGE_BL2
+static const mmap_region_t hikey960_mmap[] = {
+ MAP_DDR,
+ MAP_DEVICE,
+ {0}
+};
+#endif
+
+#if IMAGE_BL31
+static const mmap_region_t hikey960_mmap[] = {
+ MAP_DEVICE,
+ {0}
+};
+#endif
+
+/*
+ * Macro generating the code for the function setting up the pagetables as per
+ * the platform memory map & initialize the mmu, for the given exception level
+ */
+#define HIKEY960_CONFIGURE_MMU_EL(_el) \
+ void hikey960_init_mmu_el##_el(unsigned long total_base, \
+ unsigned long total_size, \
+ unsigned long ro_start, \
+ unsigned long ro_limit, \
+ unsigned long coh_start, \
+ unsigned long coh_limit) \
+ { \
+ mmap_add_region(total_base, total_base, \
+ total_size, \
+ MT_MEMORY | MT_RW | MT_SECURE); \
+ mmap_add_region(ro_start, ro_start, \
+ ro_limit - ro_start, \
+ MT_MEMORY | MT_RO | MT_SECURE); \
+ mmap_add_region(coh_start, coh_start, \
+ coh_limit - coh_start, \
+ MT_DEVICE | MT_RW | MT_SECURE); \
+ mmap_add(hikey960_mmap); \
+ init_xlat_tables(); \
+ \
+ enable_mmu_el##_el(0); \
+ }
+
+/* Define EL1 and EL3 variants of the function initialising the MMU */
+HIKEY960_CONFIGURE_MMU_EL(1)
+HIKEY960_CONFIGURE_MMU_EL(3)
+
+unsigned long plat_get_ns_image_entrypoint(void)
+{
+ return NS_BL1U_BASE;
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+ return 1920000;
+}
diff --git a/plat/hisilicon/hikey960/aarch64/hikey960_helpers.S b/plat/hisilicon/hikey960/aarch64/hikey960_helpers.S
new file mode 100644
index 00000000..5a0d8b04
--- /dev/null
+++ b/plat/hisilicon/hikey960/aarch64/hikey960_helpers.S
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include "../hikey960_def.h"
+
+ .globl plat_my_core_pos
+ .globl platform_mem_init
+ .globl plat_crash_console_init
+ .globl plat_crash_console_putc
+ .globl plat_report_exception
+ .globl plat_reset_handler
+
+func plat_my_core_pos
+ mrs x0, mpidr_el1
+ and x1, x0, #MPIDR_CPU_MASK
+ and x0, x0, #MPIDR_CLUSTER_MASK
+ add x0, x1, x0, LSR #6
+ ret
+endfunc plat_my_core_pos
+
+ /* -----------------------------------------------------
+ * void platform_mem_init(void);
+ *
+ * We don't need to carry out any memory initialization
+ * on HIKEY. The Secure RAM is accessible straight away.
+ * -----------------------------------------------------
+ */
+func platform_mem_init
+ ret
+endfunc platform_mem_init
+
+ /* ---------------------------------------------
+ * int plat_crash_console_init(void)
+ * Function to initialize the crash console
+ * without a C Runtime to print crash report.
+ * Clobber list : x0, x1, x2
+ * ---------------------------------------------
+ */
+func plat_crash_console_init
+ mov_imm x0, CRASH_CONSOLE_BASE
+ mov_imm x1, PL011_UART_CLK_IN_HZ
+ mov_imm x2, PL011_BAUDRATE
+ b console_core_init
+endfunc plat_crash_console_init
+
+ /* ---------------------------------------------
+ * int plat_crash_console_putc(int c)
+ * Function to print a character on the crash
+ * console without a C Runtime.
+ * Clobber list : x1, x2
+ * ---------------------------------------------
+ */
+func plat_crash_console_putc
+ mov_imm x1, CRASH_CONSOLE_BASE
+ b console_core_putc
+endfunc plat_crash_console_putc
+
+ /* ---------------------------------------------
+ * void plat_report_exception(unsigned int type)
+ * Function to report an unhandled exception
+ * with platform-specific means.
+ * On HIKEY platform, it updates the LEDs
+ * to indicate where we are
+ * ---------------------------------------------
+ */
+func plat_report_exception
+ mov x8, x30
+
+ /* Turn on LED according to x0 (0 -- f) */
+ ldr x2, =0xf7020000
+ and x1, x0, #1
+ str w1, [x2, #4]
+ and x1, x0, #2
+ str w1, [x2, #8]
+ and x1, x0, #4
+ str w1, [x2, #16]
+ and x1, x0, #8
+ str w1, [x2, #32]
+
+ mrs x2, currentel
+ and x2, x2, #0x0c
+ /* Check EL1 */
+ cmp x2, #0x04
+ beq plat_report_el1
+
+ adr x4, plat_err_str
+ bl asm_print_str
+
+ adr x4, esr_el3_str
+ bl asm_print_str
+
+ mrs x4, esr_el3
+ bl asm_print_hex
+
+ adr x4, elr_el3_str
+ bl asm_print_str
+
+ mrs x4, elr_el3
+ bl asm_print_hex
+ b plat_report_end
+
+plat_report_el1:
+ adr x4, plat_err_str
+ bl asm_print_str
+
+ adr x4, esr_el1_str
+ bl asm_print_str
+
+ mrs x4, esr_el1
+ bl asm_print_hex
+
+ adr x4, elr_el1_str
+ bl asm_print_str
+
+ mrs x4, elr_el1
+ bl asm_print_hex
+plat_report_end:
+ mov x30, x8
+ ret
+endfunc plat_report_exception
+
+ /* -----------------------------------------------------
+ * void plat_reset_handler(void);
+ * -----------------------------------------------------
+ */
+func plat_reset_handler
+ ret
+endfunc plat_reset_handler
+
+.section .rodata.rev_err_str, "aS"
+plat_err_str:
+ .asciz "\nPlatform exception reporting:"
+esr_el3_str:
+ .asciz "\nESR_EL3: "
+elr_el3_str:
+ .asciz "\nELR_EL3: "
+esr_el1_str:
+ .asciz "\nESR_EL1: "
+elr_el1_str:
+ .asciz "\nELR_EL1: "
diff --git a/plat/hisilicon/hikey960/hikey960_bl1_setup.c b/plat/hisilicon/hikey960/hikey960_bl1_setup.c
new file mode 100644
index 00000000..f9666df1
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_bl1_setup.c
@@ -0,0 +1,705 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <arm_gic.h>
+#include <assert.h>
+#include <bl_common.h>
+#include <console.h>
+#include <debug.h>
+#include <delay_timer.h>
+#include <dw_ufs.h>
+#include <errno.h>
+#include <gicv2.h>
+#include <hi3660.h>
+#include <mmio.h>
+#include <generic_delay_timer.h>
+#include <platform.h>
+#include <platform_def.h>
+#include <string.h>
+#include <tbbr/tbbr_img_desc.h>
+#include <ufs.h>
+
+#include "../../bl1/bl1_private.h"
+#include "hikey960_def.h"
+#include "hikey960_private.h"
+
+enum {
+ BOOT_MODE_RECOVERY = 0,
+ BOOT_MODE_NORMAL,
+ BOOT_MODE_MASK = 1,
+};
+
+/*
+ * Declarations of linker defined symbols which will help us find the layout
+ * of trusted RAM
+ */
+extern unsigned long __COHERENT_RAM_START__;
+extern unsigned long __COHERENT_RAM_END__;
+
+/*
+ * The next 2 constants identify the extents of the coherent memory region.
+ * These addresses are used by the MMU setup code and therefore they must be
+ * page-aligned. It is the responsibility of the linker script to ensure that
+ * __COHERENT_RAM_START__ and __COHERENT_RAM_END__ linker symbols refer to
+ * page-aligned addresses.
+ */
+#define BL1_COHERENT_RAM_BASE (unsigned long)(&__COHERENT_RAM_START__)
+#define BL1_COHERENT_RAM_LIMIT (unsigned long)(&__COHERENT_RAM_END__)
+
+/* Data structure which holds the extents of the trusted RAM for BL1 */
+static meminfo_t bl1_tzram_layout;
+
+/******************************************************************************
+ * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0
+ * interrupts.
+ *****************************************************************************/
+const unsigned int g0_interrupt_array[] = {
+ IRQ_SEC_PHY_TIMER,
+ IRQ_SEC_SGI_0
+};
+
+const gicv2_driver_data_t hikey960_gic_data = {
+ .gicd_base = GICD_REG_BASE,
+ .gicc_base = GICC_REG_BASE,
+ .g0_interrupt_num = ARRAY_SIZE(g0_interrupt_array),
+ .g0_interrupt_array = g0_interrupt_array,
+};
+
+meminfo_t *bl1_plat_sec_mem_layout(void)
+{
+ return &bl1_tzram_layout;
+}
+
+/*
+ * Perform any BL1 specific platform actions.
+ */
+void bl1_early_platform_setup(void)
+{
+ const size_t bl1_size = BL1_RAM_LIMIT - BL1_RAM_BASE;
+ unsigned int id, uart_base;
+
+ generic_delay_timer_init();
+ hikey960_read_boardid(&id);
+ if (id == 5300)
+ uart_base = PL011_UART5_BASE;
+ else
+ uart_base = PL011_UART6_BASE;
+ /* Initialize the console to provide early debug support */
+ console_init(uart_base, PL011_UART_CLK_IN_HZ, PL011_BAUDRATE);
+
+ /* Allow BL1 to see the whole Trusted RAM */
+ bl1_tzram_layout.total_base = BL1_RW_BASE;
+ bl1_tzram_layout.total_size = BL1_RW_SIZE;
+
+ /* Calculate how much RAM BL1 is using and how much remains free */
+ bl1_tzram_layout.free_base = BL1_RW_BASE;
+ bl1_tzram_layout.free_size = BL1_RW_SIZE;
+ reserve_mem(&bl1_tzram_layout.free_base,
+ &bl1_tzram_layout.free_size,
+ BL1_RAM_BASE,
+ bl1_size);
+
+ INFO("BL1: 0x%lx - 0x%lx [size = %lu]\n", BL1_RAM_BASE, BL1_RAM_LIMIT,
+ bl1_size);
+}
+
+/*
+ * Perform the very early platform specific architecture setup here. At the
+ * moment this only does basic initialization. Later architectural setup
+ * (bl1_arch_setup()) does not do anything platform specific.
+ */
+void bl1_plat_arch_setup(void)
+{
+ hikey960_init_mmu_el3(bl1_tzram_layout.total_base,
+ bl1_tzram_layout.total_size,
+ BL1_RO_BASE,
+ BL1_RO_LIMIT,
+ BL1_COHERENT_RAM_BASE,
+ BL1_COHERENT_RAM_LIMIT);
+}
+
+static void hikey960_clk_init(void)
+{
+ /* change ldi0 sel to ppll2 */
+ mmio_write_32(0xfff350b4, 0xf0002000);
+ /* ldi0 20' */
+ mmio_write_32(0xfff350bc, 0xfc004c00);
+}
+
+static void hikey960_pmu_init(void)
+{
+ /* clear np_xo_abb_dig_START bit in PMIC_CLK_TOP_CTRL7 register */
+ mmio_clrbits_32(PMU_SSI0_CLK_TOP_CTRL7_REG, NP_XO_ABB_DIG);
+}
+
+static void hikey960_enable_ppll3(void)
+{
+ /* enable ppll3 */
+ mmio_write_32(PMC_PPLL3_CTRL0_REG, 0x4904305);
+ mmio_write_32(PMC_PPLL3_CTRL1_REG, 0x2300000);
+ mmio_write_32(PMC_PPLL3_CTRL1_REG, 0x6300000);
+}
+
+static void bus_idle_clear(unsigned int value)
+{
+ unsigned int pmc_value, value1, value2;
+ int timeout = 100;
+
+ pmc_value = value << 16;
+ pmc_value &= ~value;
+ mmio_write_32(PMC_NOC_POWER_IDLEREQ_REG, pmc_value);
+
+ for (;;) {
+ value1 = (unsigned int)mmio_read_32(PMC_NOC_POWER_IDLEACK_REG);
+ value2 = (unsigned int)mmio_read_32(PMC_NOC_POWER_IDLE_REG);
+ if (((value1 & value) == 0) && ((value2 & value) == 0))
+ break;
+ udelay(1);
+ timeout--;
+ if (timeout <= 0) {
+ WARN("%s timeout\n", __func__);
+ break;
+ }
+ }
+}
+
+static void set_vivobus_power_up(void)
+{
+ /* clk enable */
+ mmio_write_32(CRG_CLKDIV20_REG, 0x00020002);
+ mmio_write_32(CRG_PEREN0_REG, 0x00001000);
+}
+
+static void set_dss_power_up(void)
+{
+ /* set edc0 133MHz = 1600MHz / 12 */
+ mmio_write_32(CRG_CLKDIV5_REG, 0x003f000b);
+ /* set ldi0 ppl0 */
+ mmio_write_32(CRG_CLKDIV3_REG, 0xf0001000);
+ /* set ldi0 133MHz, 1600MHz / 12 */
+ mmio_write_32(CRG_CLKDIV5_REG, 0xfc002c00);
+ /* mtcmos on */
+ mmio_write_32(CRG_PERPWREN_REG, 0x00000020);
+ udelay(100);
+ /* DISP CRG */
+ mmio_write_32(CRG_PERRSTDIS4_REG, 0x00000010);
+ /* clk enable */
+ mmio_write_32(CRG_CLKDIV18_REG, 0x01400140);
+ mmio_write_32(CRG_PEREN0_REG, 0x00002000);
+ mmio_write_32(CRG_PEREN3_REG, 0x0003b000);
+ udelay(1);
+ /* clk disable */
+ mmio_write_32(CRG_PERDIS3_REG, 0x0003b000);
+ mmio_write_32(CRG_PERDIS0_REG, 0x00002000);
+ mmio_write_32(CRG_CLKDIV18_REG, 0x01400000);
+ udelay(1);
+ /* iso disable */
+ mmio_write_32(CRG_ISODIS_REG, 0x00000040);
+ /* unreset */
+ mmio_write_32(CRG_PERRSTDIS4_REG, 0x00000006);
+ mmio_write_32(CRG_PERRSTDIS3_REG, 0x00000c00);
+ /* clk enable */
+ mmio_write_32(CRG_CLKDIV18_REG, 0x01400140);
+ mmio_write_32(CRG_PEREN0_REG, 0x00002000);
+ mmio_write_32(CRG_PEREN3_REG, 0x0003b000);
+ /* bus idle clear */
+ bus_idle_clear(PMC_NOC_POWER_IDLEREQ_DSS);
+ /* set edc0 400MHz for 2K 1600MHz / 4 */
+ mmio_write_32(CRG_CLKDIV5_REG, 0x003f0003);
+ /* set ldi 266MHz, 1600MHz / 6 */
+ mmio_write_32(CRG_CLKDIV5_REG, 0xfc001400);
+}
+
+static void set_vcodec_power_up(void)
+{
+ /* clk enable */
+ mmio_write_32(CRG_CLKDIV20_REG, 0x00040004);
+ mmio_write_32(CRG_PEREN0_REG, 0x00000060);
+ mmio_write_32(CRG_PEREN2_REG, 0x10000000);
+ /* unreset */
+ mmio_write_32(CRG_PERRSTDIS0_REG, 0x00000018);
+ /* bus idle clear */
+ bus_idle_clear(PMC_NOC_POWER_IDLEREQ_VCODEC);
+}
+
+static void set_vdec_power_up(void)
+{
+ /* mtcmos on */
+ mmio_write_32(CRG_PERPWREN_REG, 0x00000004);
+ udelay(100);
+ /* clk enable */
+ mmio_write_32(CRG_CLKDIV18_REG, 0x80008000);
+ mmio_write_32(CRG_PEREN2_REG, 0x20080000);
+ mmio_write_32(CRG_PEREN3_REG, 0x00000800);
+ udelay(1);
+ /* clk disable */
+ mmio_write_32(CRG_PERDIS3_REG, 0x00000800);
+ mmio_write_32(CRG_PERDIS2_REG, 0x20080000);
+ mmio_write_32(CRG_CLKDIV18_REG, 0x80000000);
+ udelay(1);
+ /* iso disable */
+ mmio_write_32(CRG_ISODIS_REG, 0x00000004);
+ /* unreset */
+ mmio_write_32(CRG_PERRSTDIS3_REG, 0x00000200);
+ /* clk enable */
+ mmio_write_32(CRG_CLKDIV18_REG, 0x80008000);
+ mmio_write_32(CRG_PEREN2_REG, 0x20080000);
+ mmio_write_32(CRG_PEREN3_REG, 0x00000800);
+ /* bus idle clear */
+ bus_idle_clear(PMC_NOC_POWER_IDLEREQ_VDEC);
+}
+
+static void set_venc_power_up(void)
+{
+ /* set venc ppll3 */
+ mmio_write_32(CRG_CLKDIV8_REG, 0x18001000);
+ /* set venc 258MHz, 1290MHz / 5 */
+ mmio_write_32(CRG_CLKDIV8_REG, 0x07c00100);
+ /* mtcmos on */
+ mmio_write_32(CRG_PERPWREN_REG, 0x00000002);
+ udelay(100);
+ /* clk enable */
+ mmio_write_32(CRG_CLKDIV19_REG, 0x00010001);
+ mmio_write_32(CRG_PEREN2_REG, 0x40000100);
+ mmio_write_32(CRG_PEREN3_REG, 0x00000400);
+ udelay(1);
+ /* clk disable */
+ mmio_write_32(CRG_PERDIS3_REG, 0x00000400);
+ mmio_write_32(CRG_PERDIS2_REG, 0x40000100);
+ mmio_write_32(CRG_CLKDIV19_REG, 0x00010000);
+ udelay(1);
+ /* iso disable */
+ mmio_write_32(CRG_ISODIS_REG, 0x00000002);
+ /* unreset */
+ mmio_write_32(CRG_PERRSTDIS3_REG, 0x00000100);
+ /* clk enable */
+ mmio_write_32(CRG_CLKDIV19_REG, 0x00010001);
+ mmio_write_32(CRG_PEREN2_REG, 0x40000100);
+ mmio_write_32(CRG_PEREN3_REG, 0x00000400);
+ /* bus idle clear */
+ bus_idle_clear(PMC_NOC_POWER_IDLEREQ_VENC);
+ /* set venc 645MHz, 1290MHz / 2 */
+ mmio_write_32(CRG_CLKDIV8_REG, 0x07c00040);
+}
+
+static void set_isp_power_up(void)
+{
+ /* mtcmos on */
+ mmio_write_32(CRG_PERPWREN_REG, 0x00000001);
+ udelay(100);
+ /* clk enable */
+ mmio_write_32(CRG_CLKDIV18_REG, 0x70007000);
+ mmio_write_32(CRG_CLKDIV20_REG, 0x00100010);
+ mmio_write_32(CRG_PEREN5_REG, 0x01000010);
+ mmio_write_32(CRG_PEREN3_REG, 0x0bf00000);
+ udelay(1);
+ /* clk disable */
+ mmio_write_32(CRG_PERDIS5_REG, 0x01000010);
+ mmio_write_32(CRG_PERDIS3_REG, 0x0bf00000);
+ mmio_write_32(CRG_CLKDIV18_REG, 0x70000000);
+ mmio_write_32(CRG_CLKDIV20_REG, 0x00100000);
+ udelay(1);
+ /* iso disable */
+ mmio_write_32(CRG_ISODIS_REG, 0x00000001);
+ /* unreset */
+ mmio_write_32(CRG_ISP_SEC_RSTDIS_REG, 0x0000002f);
+ /* clk enable */
+ mmio_write_32(CRG_CLKDIV18_REG, 0x70007000);
+ mmio_write_32(CRG_CLKDIV20_REG, 0x00100010);
+ mmio_write_32(CRG_PEREN5_REG, 0x01000010);
+ mmio_write_32(CRG_PEREN3_REG, 0x0bf00000);
+ /* bus idle clear */
+ bus_idle_clear(PMC_NOC_POWER_IDLEREQ_ISP);
+ /* csi clk enable */
+ mmio_write_32(CRG_PEREN3_REG, 0x00700000);
+}
+
+static void set_ivp_power_up(void)
+{
+ /* set ivp ppll0 */
+ mmio_write_32(CRG_CLKDIV0_REG, 0xc0000000);
+ /* set ivp 267MHz, 1600MHz / 6 */
+ mmio_write_32(CRG_CLKDIV0_REG, 0x3c001400);
+ /* mtcmos on */
+ mmio_write_32(CRG_PERPWREN_REG, 0x00200000);
+ udelay(100);
+ /* IVP CRG unreset */
+ mmio_write_32(CRG_IVP_SEC_RSTDIS_REG, 0x00000001);
+ /* clk enable */
+ mmio_write_32(CRG_CLKDIV20_REG, 0x02000200);
+ mmio_write_32(CRG_PEREN4_REG, 0x000000a8);
+ udelay(1);
+ /* clk disable */
+ mmio_write_32(CRG_PERDIS4_REG, 0x000000a8);
+ mmio_write_32(CRG_CLKDIV20_REG, 0x02000000);
+ udelay(1);
+ /* iso disable */
+ mmio_write_32(CRG_ISODIS_REG, 0x01000000);
+ /* unreset */
+ mmio_write_32(CRG_IVP_SEC_RSTDIS_REG, 0x00000002);
+ /* clk enable */
+ mmio_write_32(CRG_CLKDIV20_REG, 0x02000200);
+ mmio_write_32(CRG_PEREN4_REG, 0x000000a8);
+ /* bus idle clear */
+ bus_idle_clear(PMC_NOC_POWER_IDLEREQ_IVP);
+ /* set ivp 533MHz, 1600MHz / 3 */
+ mmio_write_32(CRG_CLKDIV0_REG, 0x3c000800);
+}
+
+static void set_audio_power_up(void)
+{
+ unsigned int ret;
+ int timeout = 100;
+ /* mtcmos on */
+ mmio_write_32(SCTRL_SCPWREN_REG, 0x00000001);
+ udelay(100);
+ /* clk enable */
+ mmio_write_32(CRG_CLKDIV19_REG, 0x80108010);
+ mmio_write_32(SCTRL_SCCLKDIV2_REG, 0x00010001);
+ mmio_write_32(SCTRL_SCPEREN0_REG, 0x0c000000);
+ mmio_write_32(CRG_PEREN0_REG, 0x04000000);
+ mmio_write_32(CRG_PEREN5_REG, 0x00000080);
+ mmio_write_32(SCTRL_SCPEREN1_REG, 0x0000000f);
+ udelay(1);
+ /* clk disable */
+ mmio_write_32(SCTRL_SCPERDIS1_REG, 0x0000000f);
+ mmio_write_32(SCTRL_SCPERDIS0_REG, 0x0c000000);
+ mmio_write_32(CRG_PERDIS5_REG, 0x00000080);
+ mmio_write_32(CRG_PERDIS0_REG, 0x04000000);
+ mmio_write_32(SCTRL_SCCLKDIV2_REG, 0x00010000);
+ mmio_write_32(CRG_CLKDIV19_REG, 0x80100000);
+ udelay(1);
+ /* iso disable */
+ mmio_write_32(SCTRL_SCISODIS_REG, 0x00000001);
+ udelay(1);
+ /* unreset */
+ mmio_write_32(SCTRL_PERRSTDIS1_SEC_REG, 0x00000001);
+ mmio_write_32(SCTRL_SCPERRSTDIS0_REG, 0x00000780);
+ /* clk enable */
+ mmio_write_32(CRG_CLKDIV19_REG, 0x80108010);
+ mmio_write_32(SCTRL_SCCLKDIV2_REG, 0x00010001);
+ mmio_write_32(SCTRL_SCPEREN0_REG, 0x0c000000);
+ mmio_write_32(CRG_PEREN0_REG, 0x04000000);
+ mmio_write_32(CRG_PEREN5_REG, 0x00000080);
+ mmio_write_32(SCTRL_SCPEREN1_REG, 0x0000000f);
+ /* bus idle clear */
+ mmio_write_32(SCTRL_SCPERCTRL7_REG, 0x00040000);
+ for (;;) {
+ ret = mmio_read_32(SCTRL_SCPERSTAT6_REG);
+ if (((ret & (1 << 5)) == 0) && ((ret & (1 << 8)) == 0))
+ break;
+ udelay(1);
+ timeout--;
+ if (timeout <= 0) {
+ WARN("%s timeout\n", __func__);
+ break;
+ }
+ }
+ mmio_write_32(ASP_CFG_MMBUF_CTRL_REG, 0x00ff0000);
+}
+
+static void set_pcie_power_up(void)
+{
+ /* mtcmos on */
+ mmio_write_32(SCTRL_SCPWREN_REG, 0x00000010);
+ udelay(100);
+ /* clk enable */
+ mmio_write_32(SCTRL_SCCLKDIV6_REG, 0x08000800);
+ mmio_write_32(SCTRL_SCPEREN2_REG, 0x00104000);
+ mmio_write_32(CRG_PEREN7_REG, 0x000003a0);
+ udelay(1);
+ /* clk disable */
+ mmio_write_32(SCTRL_SCPERDIS2_REG, 0x00104000);
+ mmio_write_32(CRG_PERDIS7_REG, 0x000003a0);
+ mmio_write_32(SCTRL_SCCLKDIV6_REG, 0x08000000);
+ udelay(1);
+ /* iso disable */
+ mmio_write_32(SCTRL_SCISODIS_REG, 0x00000030);
+ /* unreset */
+ mmio_write_32(CRG_PERRSTDIS3_REG, 0x8c000000);
+ /* clk enable */
+ mmio_write_32(SCTRL_SCCLKDIV6_REG, 0x08000800);
+ mmio_write_32(SCTRL_SCPEREN2_REG, 0x00104000);
+ mmio_write_32(CRG_PEREN7_REG, 0x000003a0);
+}
+
+static void ispfunc_enable(void)
+{
+ /* enable ispfunc. Otherwise powerup isp_srt causes exception. */
+ mmio_write_32(0xfff35000, 0x00000008);
+ mmio_write_32(0xfff35460, 0xc004ffff);
+ mmio_write_32(0xfff35030, 0x02000000);
+ mdelay(10);
+}
+
+static void isps_control_clock(int flag)
+{
+ unsigned int ret;
+
+ /* flag: 0 -- disable clock, 1 -- enable clock */
+ if (flag) {
+ ret = mmio_read_32(0xe8420364);
+ ret |= 1;
+ mmio_write_32(0xe8420364, ret);
+ } else {
+ ret = mmio_read_32(0xe8420364);
+ ret &= ~1;
+ mmio_write_32(0xe8420364, ret);
+ }
+}
+
+static void set_isp_srt_power_up(void)
+{
+ unsigned int ret;
+
+ ispfunc_enable();
+ /* reset */
+ mmio_write_32(0xe8420374, 0x00000001);
+ mmio_write_32(0xe8420350, 0x00000000);
+ mmio_write_32(0xe8420358, 0x00000000);
+ /* mtcmos on */
+ mmio_write_32(0xfff35150, 0x00400000);
+ udelay(100);
+ /* clk enable */
+ isps_control_clock(1);
+ udelay(1);
+ isps_control_clock(0);
+ udelay(1);
+ /* iso disable */
+ mmio_write_32(0xfff35148, 0x08000000);
+ /* unreset */
+ ret = mmio_read_32(0xe8420374);
+ ret &= ~0x1;
+ mmio_write_32(0xe8420374, ret);
+ /* clk enable */
+ isps_control_clock(1);
+ /* enable clock gating for accessing csi registers */
+ mmio_write_32(0xe8420010, ~0);
+}
+
+static void hikey960_regulator_enable(void)
+{
+ set_vivobus_power_up();
+ hikey960_enable_ppll3();
+ set_dss_power_up();
+ set_vcodec_power_up();
+ set_vdec_power_up();
+ set_venc_power_up();
+ set_isp_power_up();
+ set_ivp_power_up();
+ set_audio_power_up();
+ set_pcie_power_up();
+ set_isp_srt_power_up();
+}
+
+static void hikey960_ufs_reset(void)
+{
+ unsigned int data, mask;
+
+ mmio_write_32(CRG_PERDIS7_REG, 1 << 14);
+ mmio_clrbits_32(UFS_SYS_PHY_CLK_CTRL_REG, BIT_SYSCTRL_REF_CLOCK_EN);
+ do {
+ data = mmio_read_32(UFS_SYS_PHY_CLK_CTRL_REG);
+ } while (data & BIT_SYSCTRL_REF_CLOCK_EN);
+ /* use abb clk */
+ mmio_clrbits_32(UFS_SYS_UFS_SYSCTRL_REG, BIT_UFS_REFCLK_SRC_SE1);
+ mmio_clrbits_32(UFS_SYS_PHY_ISO_EN_REG, BIT_UFS_REFCLK_ISO_EN);
+ mmio_write_32(PCTRL_PERI_CTRL3_REG, (1 << 0) | (1 << 16));
+ mdelay(1);
+ mmio_write_32(CRG_PEREN7_REG, 1 << 14);
+ mmio_setbits_32(UFS_SYS_PHY_CLK_CTRL_REG, BIT_SYSCTRL_REF_CLOCK_EN);
+
+ mmio_write_32(CRG_PERRSTEN3_REG, PERI_UFS_BIT);
+ do {
+ data = mmio_read_32(CRG_PERRSTSTAT3_REG);
+ } while ((data & PERI_UFS_BIT) == 0);
+ mmio_setbits_32(UFS_SYS_PSW_POWER_CTRL_REG, BIT_UFS_PSW_MTCMOS_EN);
+ mdelay(1);
+ mmio_setbits_32(UFS_SYS_HC_LP_CTRL_REG, BIT_SYSCTRL_PWR_READY);
+ mmio_write_32(UFS_SYS_UFS_DEVICE_RESET_CTRL_REG,
+ MASK_UFS_DEVICE_RESET);
+ /* clear SC_DIV_UFS_PERIBUS */
+ mask = SC_DIV_UFS_PERIBUS << 16;
+ mmio_write_32(CRG_CLKDIV17_REG, mask);
+ /* set SC_DIV_UFSPHY_CFG(3) */
+ mask = SC_DIV_UFSPHY_CFG_MASK << 16;
+ data = SC_DIV_UFSPHY_CFG(3);
+ mmio_write_32(CRG_CLKDIV16_REG, mask | data);
+ data = mmio_read_32(UFS_SYS_PHY_CLK_CTRL_REG);
+ data &= ~MASK_SYSCTRL_CFG_CLOCK_FREQ;
+ data |= 0x39;
+ mmio_write_32(UFS_SYS_PHY_CLK_CTRL_REG, data);
+ mmio_clrbits_32(UFS_SYS_PHY_CLK_CTRL_REG, MASK_SYSCTRL_REF_CLOCK_SEL);
+ mmio_setbits_32(UFS_SYS_CLOCK_GATE_BYPASS_REG,
+ MASK_UFS_CLK_GATE_BYPASS);
+ mmio_setbits_32(UFS_SYS_UFS_SYSCTRL_REG, MASK_UFS_SYSCTRL_BYPASS);
+
+ mmio_setbits_32(UFS_SYS_PSW_CLK_CTRL_REG, BIT_SYSCTRL_PSW_CLK_EN);
+ mmio_clrbits_32(UFS_SYS_PSW_POWER_CTRL_REG, BIT_UFS_PSW_ISO_CTRL);
+ mmio_clrbits_32(UFS_SYS_PHY_ISO_EN_REG, BIT_UFS_PHY_ISO_CTRL);
+ mmio_clrbits_32(UFS_SYS_HC_LP_CTRL_REG, BIT_SYSCTRL_LP_ISOL_EN);
+ mmio_write_32(CRG_PERRSTDIS3_REG, PERI_ARST_UFS_BIT);
+ mmio_setbits_32(UFS_SYS_RESET_CTRL_EN_REG, BIT_SYSCTRL_LP_RESET_N);
+ mdelay(1);
+ mmio_write_32(UFS_SYS_UFS_DEVICE_RESET_CTRL_REG,
+ MASK_UFS_DEVICE_RESET | BIT_UFS_DEVICE_RESET);
+ mdelay(20);
+ mmio_write_32(UFS_SYS_UFS_DEVICE_RESET_CTRL_REG,
+ 0x03300330);
+
+ mmio_write_32(CRG_PERRSTDIS3_REG, PERI_UFS_BIT);
+ do {
+ data = mmio_read_32(CRG_PERRSTSTAT3_REG);
+ } while (data & PERI_UFS_BIT);
+}
+
+static void hikey960_ufs_init(void)
+{
+ dw_ufs_params_t ufs_params;
+
+ memset(&ufs_params, 0, sizeof(ufs_params));
+ ufs_params.reg_base = UFS_REG_BASE;
+ ufs_params.desc_base = HIKEY960_UFS_DESC_BASE;
+ ufs_params.desc_size = HIKEY960_UFS_DESC_SIZE;
+
+ if ((ufs_params.flags & UFS_FLAGS_SKIPINIT) == 0)
+ hikey960_ufs_reset();
+ dw_ufs_init(&ufs_params);
+}
+
+static void hikey960_tzc_init(void)
+{
+ mmio_write_32(TZC_EN0_REG, 0x7fbff066);
+ mmio_write_32(TZC_EN1_REG, 0xfffff5fc);
+ mmio_write_32(TZC_EN2_REG, 0x0007005c);
+ mmio_write_32(TZC_EN3_REG, 0x37030700);
+ mmio_write_32(TZC_EN4_REG, 0xf63fefae);
+ mmio_write_32(TZC_EN5_REG, 0x000410fd);
+ mmio_write_32(TZC_EN6_REG, 0x0063ff68);
+ mmio_write_32(TZC_EN7_REG, 0x030000f3);
+ mmio_write_32(TZC_EN8_REG, 0x00000007);
+}
+
+static void hikey960_peri_init(void)
+{
+ /* unreset */
+ mmio_setbits_32(CRG_PERRSTDIS4_REG, 1);
+}
+
+static void hikey960_pinmux_init(void)
+{
+ unsigned int id;
+
+ hikey960_read_boardid(&id);
+ if (id == 5301) {
+ /* hikey960 hardware v2 */
+ /* GPIO150: LED */
+ mmio_write_32(IOMG_FIX_006_REG, 0);
+ /* GPIO151: LED */
+ mmio_write_32(IOMG_FIX_007_REG, 0);
+ /* GPIO189: LED */
+ mmio_write_32(IOMG_AO_011_REG, 0);
+ /* GPIO190: LED */
+ mmio_write_32(IOMG_AO_012_REG, 0);
+ /* GPIO46 */
+ mmio_write_32(IOMG_044_REG, 0);
+ /* GPIO202 */
+ mmio_write_32(IOMG_AO_023_REG, 0);
+ /* GPIO206 */
+ mmio_write_32(IOMG_AO_026_REG, 0);
+ /* GPIO219 - PD pullup */
+ mmio_write_32(IOMG_AO_039_REG, 0);
+ mmio_write_32(IOCG_AO_043_REG, 1 << 0);
+ }
+ /* GPIO005 - PMU SSI, 10mA */
+ mmio_write_32(IOCG_006_REG, 2 << 4);
+}
+
+/*
+ * Function which will perform any remaining platform-specific setup that can
+ * occur after the MMU and data cache have been enabled.
+ */
+void bl1_platform_setup(void)
+{
+ hikey960_clk_init();
+ hikey960_pmu_init();
+ hikey960_regulator_enable();
+ hikey960_tzc_init();
+ hikey960_peri_init();
+ hikey960_ufs_init();
+ hikey960_pinmux_init();
+ hikey960_io_setup();
+}
+
+/*
+ * The following function checks if Firmware update is needed,
+ * by checking if TOC in FIP image is valid or not.
+ */
+unsigned int bl1_plat_get_next_image_id(void)
+{
+ unsigned int mode, ret;
+
+ mode = mmio_read_32(SCTRL_BAK_DATA0_REG);
+ switch (mode & BOOT_MODE_MASK) {
+ case BOOT_MODE_RECOVERY:
+ ret = NS_BL1U_IMAGE_ID;
+ break;
+ case BOOT_MODE_NORMAL:
+ ret = BL2_IMAGE_ID;
+ break;
+ default:
+ WARN("Invalid boot mode is found:%d\n", mode);
+ panic();
+ }
+ return ret;
+}
+
+image_desc_t *bl1_plat_get_image_desc(unsigned int image_id)
+{
+ unsigned int index = 0;
+
+ while (bl1_tbbr_image_descs[index].image_id != INVALID_IMAGE_ID) {
+ if (bl1_tbbr_image_descs[index].image_id == image_id)
+ return &bl1_tbbr_image_descs[index];
+ index++;
+ }
+
+ return NULL;
+}
+
+void bl1_plat_set_ep_info(unsigned int image_id,
+ entry_point_info_t *ep_info)
+{
+ unsigned int data = 0;
+ uintptr_t tmp = HIKEY960_NS_TMP_OFFSET;
+
+ if (image_id == BL2_IMAGE_ID)
+ return;
+ /* Copy NS BL1U from 0x1AC1_8000 to 0x1AC9_8000 */
+ memcpy((void *)tmp, (void *)HIKEY960_NS_IMAGE_OFFSET,
+ NS_BL1U_SIZE);
+ memcpy((void *)NS_BL1U_BASE, (void *)tmp, NS_BL1U_SIZE);
+ inv_dcache_range(NS_BL1U_BASE, NS_BL1U_SIZE);
+ /* Initialize the GIC driver, cpu and distributor interfaces */
+ gicv2_driver_init(&hikey960_gic_data);
+ gicv2_distif_init();
+ gicv2_pcpu_distif_init();
+ gicv2_cpuif_enable();
+ /* CNTFRQ is read-only in EL1 */
+ write_cntfrq_el0(plat_get_syscnt_freq2());
+ data = read_cpacr_el1();
+ do {
+ data |= 3 << 20;
+ write_cpacr_el1(data);
+ data = read_cpacr_el1();
+ } while ((data & (3 << 20)) != (3 << 20));
+ INFO("cpacr_el1:0x%x\n", data);
+
+ ep_info->args.arg0 = 0xffff & read_mpidr();
+ ep_info->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
+ DISABLE_ALL_EXCEPTIONS);
+}
diff --git a/plat/hisilicon/hikey960/hikey960_boardid.c b/plat/hisilicon/hikey960/hikey960_boardid.c
new file mode 100644
index 00000000..ac3e0385
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_boardid.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <debug.h>
+#include <delay_timer.h>
+#include <errno.h>
+#include <hi3660.h>
+#include <mmio.h>
+
+#include "hikey960_private.h"
+
+#define ADC_ADCIN0 0
+#define ADC_ADCIN1 1
+#define ADC_ADCIN2 2
+
+#define HKADC_DATA_GRADE0 0
+#define HKADC_DATA_GRADE1 100
+#define HKADC_DATA_GRADE2 300
+#define HKADC_DATA_GRADE3 500
+#define HKADC_DATA_GRADE4 700
+#define HKADC_DATA_GRADE5 900
+#define HKADC_DATA_GRADE6 1100
+#define HKADC_DATA_GRADE7 1300
+#define HKADC_DATA_GRADE8 1500
+#define HKADC_DATA_GRADE9 1700
+#define HKADC_DATA_GRADE10 1800
+
+#define BOARDID_VALUE0 0
+#define BOARDID_VALUE1 1
+#define BOARDID_VALUE2 2
+#define BOARDID_VALUE3 3
+#define BOARDID_VALUE4 4
+#define BOARDID_VALUE5 5
+#define BOARDID_VALUE6 6
+#define BOARDID_VALUE7 7
+#define BOARDID_VALUE8 8
+#define BOARDID_VALUE9 9
+#define BOARDID_UNKNOWN 0xF
+
+#define BOARDID3_BASE 5
+
+
+static void init_adc(void)
+{
+ /* reset hkadc */
+ mmio_write_32(CRG_PERRSTEN2_REG, PERRSTEN2_HKADCSSI);
+ /* wait a few clock cycles */
+ udelay(2);
+ mmio_write_32(CRG_PERRSTDIS2_REG, PERRSTEN2_HKADCSSI);
+ udelay(2);
+ /* enable hkadc clock */
+ mmio_write_32(CRG_PERDIS2_REG, PEREN2_HKADCSSI);
+ udelay(2);
+ mmio_write_32(CRG_PEREN2_REG, PEREN2_HKADCSSI);
+ udelay(2);
+}
+
+static int get_adc(unsigned int channel, unsigned int *value)
+{
+ unsigned int data, value1, value0;
+
+ if (channel > HKADC_CHANNEL_MAX) {
+ WARN("invalid channel:%d\n", channel);
+ return -EFAULT;
+ }
+ /* configure the read/write operation for external HKADC */
+ mmio_write_32(HKADC_WR01_DATA_REG, HKADC_WR01_VALUE | channel);
+ mmio_write_32(HKADC_WR23_DATA_REG, HKADC_WR23_VALUE);
+ mmio_write_32(HKADC_WR45_DATA_REG, HKADC_WR45_VALUE);
+ /* configure the number of accessing registers */
+ mmio_write_32(HKADC_WR_NUM_REG, HKADC_WR_NUM_VALUE);
+ /* configure delay of accessing registers */
+ mmio_write_32(HKADC_DELAY01_REG, HKADC_CHANNEL0_DELAY01_VALUE);
+ mmio_write_32(HKADC_DELAY23_REG, HKADC_DELAY23_VALUE);
+
+ /* start HKADC */
+ mmio_write_32(HKADC_DSP_START_REG, 1);
+ do {
+ data = mmio_read_32(HKADC_DSP_START_REG);
+ } while (data & 1);
+
+ /* convert AD result */
+ value1 = mmio_read_32(HKADC_DSP_RD2_DATA_REG) & 0xffff;
+ value0 = mmio_read_32(HKADC_DSP_RD3_DATA_REG) & 0xffff;
+
+ data = ((value1 << 4) & HKADC_VALUE_HIGH) |
+ ((value0 >> 4) & HKADC_VALUE_LOW);
+ *value = data;
+ return 0;
+}
+
+static int get_value(unsigned int channel, unsigned int *value)
+{
+ int ret;
+
+ ret = get_adc(channel, value);
+ if (ret)
+ return ret;
+
+ /* convert ADC value to micro-volt */
+ ret = ((*value & HKADC_VALID_VALUE) * HKADC_VREF_1V8) / HKADC_ACCURACY;
+ *value = ret;
+ return 0;
+}
+
+static int adcin_data_remap(unsigned int adcin_value)
+{
+ int ret;
+
+ if (adcin_value < HKADC_DATA_GRADE0)
+ ret = BOARDID_UNKNOWN;
+ else if (adcin_value < HKADC_DATA_GRADE1)
+ ret = BOARDID_VALUE0;
+ else if (adcin_value < HKADC_DATA_GRADE2)
+ ret = BOARDID_VALUE1;
+ else if (adcin_value < HKADC_DATA_GRADE3)
+ ret = BOARDID_VALUE2;
+ else if (adcin_value < HKADC_DATA_GRADE4)
+ ret = BOARDID_VALUE3;
+ else if (adcin_value < HKADC_DATA_GRADE5)
+ ret = BOARDID_VALUE4;
+ else if (adcin_value < HKADC_DATA_GRADE6)
+ ret = BOARDID_VALUE5;
+ else if (adcin_value < HKADC_DATA_GRADE7)
+ ret = BOARDID_VALUE6;
+ else if (adcin_value < HKADC_DATA_GRADE8)
+ ret = BOARDID_VALUE7;
+ else if (adcin_value < HKADC_DATA_GRADE9)
+ ret = BOARDID_VALUE8;
+ else if (adcin_value < HKADC_DATA_GRADE10)
+ ret = BOARDID_VALUE9;
+ else
+ ret = BOARDID_UNKNOWN;
+ return ret;
+}
+
+int hikey960_read_boardid(unsigned int *id)
+{
+ unsigned int adcin0, adcin1, adcin2;
+ unsigned int adcin0_remap, adcin1_remap, adcin2_remap;
+
+ assert(id != NULL);
+
+ init_adc();
+
+ /* read ADC channel0 data */
+ get_value(ADC_ADCIN0, &adcin0);
+ adcin0_remap = adcin_data_remap(adcin0);
+ INFO("[BDID]adcin0:%d adcin0_remap:%d\n", adcin0, adcin0_remap);
+ if (adcin0_remap == BOARDID_UNKNOWN)
+ return -EINVAL;
+ /* read ADC channel1 data */
+ get_value(ADC_ADCIN1, &adcin1);
+ adcin1_remap = adcin_data_remap(adcin1);
+ INFO("[BDID]adcin1:%d adcin1_remap:%d\n", adcin1, adcin1_remap);
+ if (adcin1_remap == BOARDID_UNKNOWN)
+ return -EINVAL;
+ /* read ADC channel2 data */
+ get_value(ADC_ADCIN2, &adcin2);
+ adcin2_remap = adcin_data_remap(adcin2);
+ INFO("[BDID]adcin2:%d adcin2_remap:%d\n", adcin2, adcin2_remap);
+ if (adcin2_remap == BOARDID_UNKNOWN)
+ return -EINVAL;
+ *id = BOARDID3_BASE * 1000 + (adcin2_remap * 100) +
+ (adcin1_remap * 10) + adcin0_remap;
+ INFO("[BDID]boardid: %d\n", *id);
+ return 0;
+}
diff --git a/plat/hisilicon/hikey960/hikey960_def.h b/plat/hisilicon/hikey960/hikey960_def.h
new file mode 100644
index 00000000..e713e2e0
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_def.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __HIKEY960_DEF_H__
+#define __HIKEY960_DEF_H__
+
+#include <common_def.h>
+#include <tbbr_img_def.h>
+
+#define DDR_BASE 0x0
+#define DDR_SIZE 0xC0000000
+
+#define DEVICE_BASE 0xE0000000
+#define DEVICE_SIZE 0x20000000
+
+/*
+ * PL011 related constants
+ */
+#define PL011_UART5_BASE 0xFDF05000
+#define PL011_UART6_BASE 0xFFF32000
+#define PL011_BAUDRATE 115200
+#define PL011_UART_CLK_IN_HZ 19200000
+
+#define UFS_BASE 0
+/* FIP partition */
+#define HIKEY960_FIP_BASE (UFS_BASE + 0x1400000)
+#define HIKEY960_FIP_MAX_SIZE (12 << 20)
+
+#define HIKEY960_UFS_DESC_BASE 0x20000000
+#define HIKEY960_UFS_DESC_SIZE 0x00200000 /* 2MB */
+#define HIKEY960_UFS_DATA_BASE 0x10000000
+#define HIKEY960_UFS_DATA_SIZE 0x0A000000 /* 160MB */
+
+#endif /* __HIKEY960_DEF_H__ */
diff --git a/plat/hisilicon/hikey960/hikey960_io_storage.c b/plat/hisilicon/hikey960/hikey960_io_storage.c
new file mode 100644
index 00000000..de54e886
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_io_storage.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+#include <firmware_image_package.h>
+#include <io_block.h>
+#include <io_driver.h>
+#include <io_fip.h>
+#include <io_memmap.h>
+#include <io_storage.h>
+#include <mmio.h>
+#include <platform_def.h>
+#include <semihosting.h> /* For FOPEN_MODE_... */
+#include <string.h>
+#include <ufs.h>
+
+struct plat_io_policy {
+ uintptr_t *dev_handle;
+ uintptr_t image_spec;
+ int (*check)(const uintptr_t spec);
+};
+
+static const io_dev_connector_t *ufs_dev_con, *fip_dev_con;
+static uintptr_t ufs_dev_handle, fip_dev_handle;
+
+static int check_ufs(const uintptr_t spec);
+static int check_fip(const uintptr_t spec);
+size_t ufs_read_lun3_blks(int lba, uintptr_t buf, size_t size);
+size_t ufs_write_lun3_blks(int lba, const uintptr_t buf, size_t size);
+
+static const io_block_spec_t ufs_fip_spec = {
+ .offset = HIKEY960_FIP_BASE,
+ .length = HIKEY960_FIP_MAX_SIZE,
+};
+
+static const io_block_spec_t ufs_data_spec = {
+ .offset = 0,
+ .length = 256 << 20,
+};
+
+static const io_block_dev_spec_t ufs_dev_spec = {
+ /* It's used as temp buffer in block driver. */
+ .buffer = {
+ .offset = HIKEY960_UFS_DATA_BASE,
+ .length = HIKEY960_UFS_DATA_SIZE,
+ },
+ .ops = {
+ .read = ufs_read_lun3_blks,
+ .write = ufs_write_lun3_blks,
+ },
+ .block_size = UFS_BLOCK_SIZE,
+};
+
+static const io_uuid_spec_t 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 bl33_uuid_spec = {
+ .uuid = UUID_NON_TRUSTED_FIRMWARE_BL33,
+};
+
+static const struct plat_io_policy policies[] = {
+ [FIP_IMAGE_ID] = {
+ &ufs_dev_handle,
+ (uintptr_t)&ufs_fip_spec,
+ check_ufs
+ },
+ [BL2_IMAGE_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&bl2_uuid_spec,
+ check_fip
+ },
+ [SCP_BL2_IMAGE_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&scp_bl2_uuid_spec,
+ check_fip
+ },
+ [BL31_IMAGE_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&bl31_uuid_spec,
+ check_fip
+ },
+ [BL33_IMAGE_ID] = {
+ &fip_dev_handle,
+ (uintptr_t)&bl33_uuid_spec,
+ check_fip
+ },
+ [BL2U_IMAGE_ID] = {
+ &ufs_dev_handle,
+ (uintptr_t)&ufs_data_spec,
+ check_ufs
+ }
+};
+
+static int check_ufs(const uintptr_t spec)
+{
+ int result;
+ uintptr_t local_handle;
+
+ result = io_dev_init(ufs_dev_handle, (uintptr_t)NULL);
+ if (result == 0) {
+ result = io_open(ufs_dev_handle, spec, &local_handle);
+ if (result == 0)
+ io_close(local_handle);
+ }
+ return result;
+}
+
+static int check_fip(const uintptr_t spec)
+{
+ int result;
+ uintptr_t local_image_handle;
+
+ /* See if a Firmware Image Package is available */
+ result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID);
+ if (result == 0) {
+ result = io_open(fip_dev_handle, spec, &local_image_handle);
+ if (result == 0) {
+ VERBOSE("Using FIP\n");
+ io_close(local_image_handle);
+ }
+ }
+ return result;
+}
+
+void hikey960_io_setup(void)
+{
+ int result;
+
+ result = register_io_dev_block(&ufs_dev_con);
+ assert(result == 0);
+
+ result = register_io_dev_fip(&fip_dev_con);
+ assert(result == 0);
+
+ result = io_dev_open(ufs_dev_con, (uintptr_t)&ufs_dev_spec,
+ &ufs_dev_handle);
+ assert(result == 0);
+
+ result = io_dev_open(fip_dev_con, (uintptr_t)NULL, &fip_dev_handle);
+ assert(result == 0);
+
+ /* Ignore improbable errors in release builds */
+ (void)result;
+}
+
+/* Return an IO device handle and specification which can be used to access
+ * an image. Use this to enforce platform load policy
+ */
+int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
+ uintptr_t *image_spec)
+{
+ int result;
+ const struct plat_io_policy *policy;
+
+ assert(image_id < ARRAY_SIZE(policies));
+
+ policy = &policies[image_id];
+ result = policy->check(policy->image_spec);
+ assert(result == 0);
+
+ *image_spec = policy->image_spec;
+ *dev_handle = *(policy->dev_handle);
+
+ return result;
+}
+
+size_t ufs_read_lun3_blks(int lba, uintptr_t buf, size_t size)
+{
+ return ufs_read_blocks(3, lba, buf, size);
+}
+
+size_t ufs_write_lun3_blks(int lba, const uintptr_t buf, size_t size)
+{
+ return ufs_write_blocks(3, lba, buf, size);
+}
diff --git a/plat/hisilicon/hikey960/hikey960_private.h b/plat/hisilicon/hikey960/hikey960_private.h
new file mode 100644
index 00000000..7e95f81d
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_private.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __HIKEY960_PRIVATE_H__
+#define __HIKEY960_PRIVATE_H__
+
+#include <bl_common.h>
+
+/*
+ * Function and variable prototypes
+ */
+void hikey960_init_mmu_el1(unsigned long total_base,
+ unsigned long total_size,
+ unsigned long ro_start,
+ unsigned long ro_limit,
+ unsigned long coh_start,
+ unsigned long coh_limit);
+void hikey960_init_mmu_el3(unsigned long total_base,
+ unsigned long total_size,
+ unsigned long ro_start,
+ unsigned long ro_limit,
+ unsigned long coh_start,
+ unsigned long coh_limit);
+void hikey960_io_setup(void);
+int hikey960_read_boardid(unsigned int *id);
+
+#endif /* __HIKEY960_PRIVATE_H__ */
diff --git a/plat/hisilicon/hikey960/include/hi3660.h b/plat/hisilicon/hikey960/include/hi3660.h
new file mode 100644
index 00000000..83d1b363
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/hi3660.h
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef __HI3660_H__
+#define __HI3660_H__
+
+#include <hi3660_crg.h>
+#include <hi3660_hkadc.h>
+#include <hi3660_mem_map.h>
+
+#define ASP_CFG_REG_BASE 0xE804E000
+
+#define ASP_CFG_MMBUF_CTRL_REG (ASP_CFG_REG_BASE + 0x148)
+
+#define LP_RAM_BASE 0xFFF50000
+
+#define SCTRL_REG_BASE 0xFFF0A000
+
+#define SCTRL_CONTROL_REG (SCTRL_REG_BASE + 0x000)
+#define SCTRL_CONTROL_SYS_MODE(x) (((x) & 0xf) << 3)
+#define SCTRL_CONTROL_SYS_MODE_NORMAL ((1 << 2) << 3)
+#define SCTRL_CONTROL_SYS_MODE_SLOW ((1 << 1) << 3)
+#define SCTRL_CONTROL_SYS_MODE_MASK (0xf << 3)
+#define SCTRL_CONTROL_MODE_CTRL_NORMAL (1 << 2)
+#define SCTRL_CONTROL_MODE_CTRL_SLOW (1 << 1)
+#define SCTRL_CONTROL_MODE_CTRL_MASK 0x7
+
+#define SCTRL_SCSYSSTAT_REG (SCTRL_REG_BASE + 0x004)
+
+#define SCTRL_DEEPSLEEPED_REG (SCTRL_REG_BASE + 0x008)
+#define SCTRL_EFUSE_USB_MASK (1 << 30)
+#define SCTRL_EFUSE_USB_PLL (1 << 30)
+#define SCTRL_EFUSE_USB_ABB (0 << 30)
+#define SCTRL_EFUSE_UFS_MASK (3 << 6)
+#define SCTRL_EFUSE_UFS_PLL (1 << 6)
+#define SCTRL_EFUSE_UFS_ABB (0 << 6)
+
+#define SCTRL_SCISOEN_REG (SCTRL_REG_BASE + 0x040)
+#define SCTRL_SCISODIS_REG (SCTRL_REG_BASE + 0x044)
+#define SCISO_MMBUFISO (1 << 3)
+
+#define SCTRL_SCPWREN_REG (SCTRL_REG_BASE + 0x060)
+#define SCPWREN_MMBUFPWREN (1 << 3)
+
+#define SCTRL_PLL_CTRL0_REG (SCTRL_REG_BASE + 0x100)
+#define SCTRL_PLL0_POSTDIV2(x) (((x) & 0x7) << 23)
+#define SCTRL_PLL0_POSTDIV1(x) (((x) & 0x7) << 20)
+#define SCTRL_PLL0_FBDIV(x) (((x) & 0xfff) << 8)
+#define SCTRL_PLL0_REFDIV(x) (((x) & 0x3f) << 2)
+#define SCTRL_PLL0_EN (1 << 0)
+
+#define SCTRL_PLL_CTRL1_REG (SCTRL_REG_BASE + 0x104)
+#define SCTRL_PLL0_CLK_NO_GATE (1 << 26)
+#define SCTRL_PLL0_CFG_VLD (1 << 25)
+#define SCTRL_PLL0_FRACDIV(x) ((x) & 0xFFFFFF)
+
+#define SCTRL_PLL_STAT_REG (SCTRL_REG_BASE + 0x10C)
+#define SCTRL_PLL0_STAT (1 << 0)
+
+#define SCTRL_SCPEREN0_REG (SCTRL_REG_BASE + 0x160)
+#define SCTRL_SCPERDIS0_REG (SCTRL_REG_BASE + 0x164)
+#define SCTRL_SCPERSTAT0_REG (SCTRL_REG_BASE + 0x168)
+
+#define SCTRL_SCPEREN1_REG (SCTRL_REG_BASE + 0x170)
+#define SCTRL_SCPERDIS1_REG (SCTRL_REG_BASE + 0x174)
+#define SCTRL_SCPEREN1_REG (SCTRL_REG_BASE + 0x170)
+#define SCTRL_SCPERDIS1_REG (SCTRL_REG_BASE + 0x174)
+#define SCPEREN1_WAIT_DDR_SELFREFRESH_DONE_BYPASS (1 << 31)
+#define SCPEREN_GT_PCLK_MMBUFCFG (1 << 25)
+#define SCPEREN_GT_PCLK_MMBUF (1 << 23)
+#define SCPEREN_GT_ACLK_MMBUF (1 << 22)
+#define SCPEREN_GT_CLK_NOC_AOBUS2MMBUF (1 << 6)
+
+#define SCTRL_SCPEREN2_REG (SCTRL_REG_BASE + 0x190)
+#define SCTRL_SCPERDIS2_REG (SCTRL_REG_BASE + 0x194)
+#define SCTRL_SCPERSTAT2_REG (SCTRL_REG_BASE + 0x198)
+#define SCTRL_SCPERRSTEN0_REG (SCTRL_REG_BASE + 0x200)
+#define SCTRL_SCPERRSTDIS0_REG (SCTRL_REG_BASE + 0x204)
+#define SCTRL_SCPERRSTSTAT0_REG (SCTRL_REG_BASE + 0x208)
+#define SCTRL_SCPERRSTEN1_REG (SCTRL_REG_BASE + 0x20C)
+#define SCTRL_SCPERRSTDIS1_REG (SCTRL_REG_BASE + 0x210)
+#define SCTRL_SCPERRSTSTAT1_REG (SCTRL_REG_BASE + 0x214)
+#define IP_RST_MMBUFCFG (1 << 12)
+#define IP_RST_MMBUF (1 << 11)
+
+#define SCTRL_SCPERRSTEN2_REG (SCTRL_REG_BASE + 0x218)
+#define SCTRL_SCPERRSTDIS2_REG (SCTRL_REG_BASE + 0x21C)
+#define SCTRL_SCPERRSTSTAT2_REG (SCTRL_REG_BASE + 0x220)
+
+#define SCTRL_SCCLKDIV2_REG (SCTRL_REG_BASE + 0x258)
+#define SEL_CLK_MMBUF_MASK (0x3 << 8)
+#define SEL_CLK_MMBUF_PLL0 (0x3 << 8)
+#define SCCLKDIV2_GT_PCLK_MMBUF (1 << 7)
+
+#define SCTRL_SCCLKDIV4_REG (SCTRL_REG_BASE + 0x260)
+#define GT_MMBUF_SYS (1 << 13)
+#define GT_MMBUF_FLL (1 << 12)
+#define GT_PLL_CLK_MMBUF (1 << 11)
+
+#define SCTRL_SCCLKDIV6_REG (SCTRL_REG_BASE + 0x268)
+
+#define SCTRL_SCPERCTRL7_REG (SCTRL_REG_BASE + 0x31C)
+#define SCTRL_SCPERSTAT6_REG (SCTRL_REG_BASE + 0x378)
+
+#define SCTRL_SCINNERSTAT_REG (SCTRL_REG_BASE + 0x3A0)
+#define EMMC_UFS_SEL (1 << 15)
+
+#define SCTRL_BAK_DATA0_REG (SCTRL_REG_BASE + 0x40C)
+#define SCTRL_BAK_DATA4_REG (SCTRL_REG_BASE + 0x41C)
+
+#define SCTRL_LPMCU_CLKEN_REG (SCTRL_REG_BASE + 0x480)
+#define SCTRL_LPMCU_CLKDIS_REG (SCTRL_REG_BASE + 0x484)
+#define SCTRL_LPMCU_RSTEN_REG (SCTRL_REG_BASE + 0x500)
+#define SCTRL_LPMCU_RSTDIS_REG (SCTRL_REG_BASE + 0x504)
+#define DDRC_SOFT_BIT (1 << 6)
+#define DDRC_CLK_BIT (1 << 5)
+
+#define SCTRL_SCPEREN0_SEC_REG (SCTRL_REG_BASE + 0x900)
+#define SCTRL_SCPERDIS0_SEC_REG (SCTRL_REG_BASE + 0x904)
+#define MMBUF_SEC_CTRL_MASK (0xfff << 20)
+#define MMBUF_SEC_CTRL(x) (((x) & 0xfff) << 20)
+
+#define SCTRL_PERRSTEN1_SEC_REG (SCTRL_REG_BASE + 0xA50)
+#define SCTRL_PERRSTDIS1_SEC_REG (SCTRL_REG_BASE + 0xA54)
+#define SCTRL_PERRSTSTAT1_SEC_REG (SCTRL_REG_BASE + 0xA58)
+#define RST_ASP_SUBSYS_BIT (1 << 0)
+
+#define SCTRL_PERRSTEN2_SEC_REG (SCTRL_REG_BASE + 0xB50)
+#define SCTRL_PERRSTDIS2_SEC_REG (SCTRL_REG_BASE + 0xB54)
+#define SCTRL_PERRSTSTAT2_SEC_REG (SCTRL_REG_BASE + 0xB58)
+
+#define SCTRL_HISEECLKDIV_REG (SCTRL_REG_BASE + 0xC28)
+#define SC_SEL_HISEE_PLL_MASK (1 << 4)
+#define SC_SEL_HISEE_PLL0 (1 << 4)
+#define SC_SEL_HISEE_PLL2 (0 << 4)
+#define SC_DIV_HISEE_PLL_MASK (7 << 16)
+#define SC_DIV_HISEE_PLL(x) ((x) & 0x7)
+
+#define SCTRL_SCSOCID0_REG (SCTRL_REG_BASE + 0xE00)
+
+#define PMC_REG_BASE 0xFFF31000
+#define PMC_PPLL1_CTRL0_REG (PMC_REG_BASE + 0x038)
+#define PMC_PPLL1_CTRL1_REG (PMC_REG_BASE + 0x03C)
+#define PMC_PPLL2_CTRL0_REG (PMC_REG_BASE + 0x040)
+#define PMC_PPLL2_CTRL1_REG (PMC_REG_BASE + 0x044)
+#define PMC_PPLL3_CTRL0_REG (PMC_REG_BASE + 0x048)
+#define PMC_PPLL3_CTRL1_REG (PMC_REG_BASE + 0x04C)
+#define PPLLx_LOCK (1 << 26)
+#define PPLLx_WITHOUT_CLK_GATE (1 << 26)
+#define PPLLx_CFG_VLD (1 << 25)
+#define PPLLx_INT_MOD (1 << 24)
+#define PPLLx_POSTDIV2_MASK (0x7 << 23)
+#define PPLLx_POSTDIV2(x) (((x) & 0x7) << 23)
+#define PPLLx_POSTDIV1_MASK (0x7 << 20)
+#define PPLLx_POSTDIV1(x) (((x) & 0x7) << 20)
+#define PPLLx_FRACDIV_MASK (0x00FFFFFF)
+#define PPLLx_FRACDIV(x) ((x) & 0x00FFFFFF)
+#define PPLLx_FBDIV_MASK (0xfff << 8)
+#define PPLLx_FBDIV(x) (((x) & 0xfff) << 8)
+#define PPLLx_REFDIV_MASK (0x3f << 2)
+#define PPLLx_REFDIV(x) (((x) & 0x3f) << 2)
+#define PPLLx_BP (1 << 1)
+#define PPLLx_EN (1 << 0)
+
+#define PMC_DDRLP_CTRL_REG (PMC_REG_BASE + 0x30C)
+#define DDRC_CSYSREQ_CFG(x) ((x) & 0xF)
+
+#define PMC_NOC_POWER_IDLEREQ_REG (PMC_REG_BASE + 0x380)
+#define PMC_NOC_POWER_IDLEREQ_IVP (1 << 14)
+#define PMC_NOC_POWER_IDLEREQ_DSS (1 << 13)
+#define PMC_NOC_POWER_IDLEREQ_VENC (1 << 11)
+#define PMC_NOC_POWER_IDLEREQ_VDEC (1 << 10)
+#define PMC_NOC_POWER_IDLEREQ_ISP (1 << 5)
+#define PMC_NOC_POWER_IDLEREQ_VCODEC (1 << 4)
+#define DDRPHY_BYPASS_MODE (1 << 0)
+
+#define PMC_NOC_POWER_IDLEACK_REG (PMC_REG_BASE + 0x384)
+#define PMC_NOC_POWER_IDLE_REG (PMC_REG_BASE + 0x388)
+
+#define PMU_SSI0_REG_BASE 0xFFF34000
+
+#define PMU_SSI0_LDO8_CTRL0_REG (PMU_SSI0_REG_BASE + (0x68 << 2))
+#define LDO8_CTRL0_EN_1_8V 0x02
+
+#define PMU_SSI0_CLK_TOP_CTRL7_REG (PMU_SSI0_REG_BASE + (0x10C << 2))
+#define NP_XO_ABB_DIG (1 << 1)
+
+#define LP_CONFIG_REG_BASE 0xFFF3F000
+
+#define DMAC_BASE 0xFDF30000
+
+#define CCI400_REG_BASE 0xE8100000
+#define CCI400_SL_IFACE3_CLUSTER_IX 0
+#define CCI400_SL_IFACE4_CLUSTER_IX 1
+
+#define GICD_REG_BASE 0xE82B1000
+#define GICC_REG_BASE 0xE82B2000
+/*
+ * GIC400 interrupt handling related constants
+ */
+#define IRQ_SEC_PHY_TIMER 29
+#define IRQ_SEC_SGI_0 8
+#define IRQ_SEC_SGI_1 9
+#define IRQ_SEC_SGI_2 10
+#define IRQ_SEC_SGI_3 11
+#define IRQ_SEC_SGI_4 12
+#define IRQ_SEC_SGI_5 13
+#define IRQ_SEC_SGI_6 14
+#define IRQ_SEC_SGI_7 15
+#define IRQ_SEC_SGI_8 16
+
+#define IPC_REG_BASE 0xE896A000
+#define IPC_BASE (IPC_REG_BASE)
+
+#define IOMG_REG_BASE 0xE896C000
+
+/* GPIO46: HUB 3.3V enable. active low */
+#define IOMG_044_REG (IOMG_REG_BASE + 0x0B0)
+#define IOMG_UART5_RX_REG (IOMG_REG_BASE + 0x0BC)
+#define IOMG_UART5_TX_REG (IOMG_REG_BASE + 0x0C0)
+
+#define IOCG_REG_BASE 0xE896C800
+
+/* GPIO005: PMIC SSI. (2 << 4) */
+#define IOCG_006_REG (IOCG_REG_BASE + 0x018)
+
+#define TIMER9_REG_BASE 0xE8A00000
+
+#define WDT0_REG_BASE 0xE8A06000
+#define WDT1_REG_BASE 0xE8A07000
+#define WDT_CONTROL_OFFSET 0x008
+#define WDT_LOCK_OFFSET 0xC00
+
+#define WDT_UNLOCK 0x1ACCE551
+#define WDT_LOCKED 1
+
+#define PCTRL_REG_BASE 0xE8A09000
+#define PCTRL_PERI_CTRL3_REG (PCTRL_REG_BASE + 0x010)
+#define PCTRL_PERI_CTRL24_REG (PCTRL_REG_BASE + 0x064)
+
+#define TZC_REG_BASE 0xE8A21000
+#define TZC_STAT0_REG (TZC_REG_BASE + 0x800)
+#define TZC_EN0_REG (TZC_REG_BASE + 0x804)
+#define TZC_DIS0_REG (TZC_REG_BASE + 0x808)
+#define TZC_STAT1_REG (TZC_REG_BASE + 0x80C)
+#define TZC_EN1_REG (TZC_REG_BASE + 0x810)
+#define TZC_DIS1_REG (TZC_REG_BASE + 0x814)
+#define TZC_STAT2_REG (TZC_REG_BASE + 0x818)
+#define TZC_EN2_REG (TZC_REG_BASE + 0x81C)
+#define TZC_DIS2_REG (TZC_REG_BASE + 0x820)
+#define TZC_STAT3_REG (TZC_REG_BASE + 0x824)
+#define TZC_EN3_REG (TZC_REG_BASE + 0x828)
+#define TZC_DIS3_REG (TZC_REG_BASE + 0x82C)
+#define TZC_STAT4_REG (TZC_REG_BASE + 0x830)
+#define TZC_EN4_REG (TZC_REG_BASE + 0x834)
+#define TZC_DIS4_REG (TZC_REG_BASE + 0x838)
+#define TZC_STAT5_REG (TZC_REG_BASE + 0x83C)
+#define TZC_EN5_REG (TZC_REG_BASE + 0x840)
+#define TZC_DIS5_REG (TZC_REG_BASE + 0x844)
+#define TZC_STAT6_REG (TZC_REG_BASE + 0x848)
+#define TZC_EN6_REG (TZC_REG_BASE + 0x84C)
+#define TZC_DIS6_REG (TZC_REG_BASE + 0x850)
+#define TZC_STAT7_REG (TZC_REG_BASE + 0x854)
+#define TZC_EN7_REG (TZC_REG_BASE + 0x858)
+#define TZC_DIS7_REG (TZC_REG_BASE + 0x85C)
+#define TZC_STAT8_REG (TZC_REG_BASE + 0x860)
+#define TZC_EN8_REG (TZC_REG_BASE + 0x864)
+#define TZC_DIS8_REG (TZC_REG_BASE + 0x868)
+
+#define MMBUF_BASE 0xEA800000
+
+#define ACPU_DMCPACK0_BASE 0xEA900000
+
+#define ACPU_DMCPACK1_BASE 0xEA920000
+
+#define ACPU_DMCPACK2_BASE 0xEA940000
+
+#define ACPU_DMCPACK3_BASE 0xEA960000
+
+#define UART5_REG_BASE 0xFDF05000
+
+#define USB3OTG_REG_BASE 0xFF100000
+
+#define UFS_REG_BASE 0xFF3B0000
+
+#define UFS_SYS_REG_BASE 0xFF3B1000
+
+#define UFS_SYS_PSW_POWER_CTRL_REG (UFS_SYS_REG_BASE + 0x004)
+#define UFS_SYS_PHY_ISO_EN_REG (UFS_SYS_REG_BASE + 0x008)
+#define UFS_SYS_HC_LP_CTRL_REG (UFS_SYS_REG_BASE + 0x00C)
+#define UFS_SYS_PHY_CLK_CTRL_REG (UFS_SYS_REG_BASE + 0x010)
+#define UFS_SYS_PSW_CLK_CTRL_REG (UFS_SYS_REG_BASE + 0x014)
+#define UFS_SYS_CLOCK_GATE_BYPASS_REG (UFS_SYS_REG_BASE + 0x018)
+#define UFS_SYS_RESET_CTRL_EN_REG (UFS_SYS_REG_BASE + 0x01C)
+#define UFS_SYS_MONITOR_HH_REG (UFS_SYS_REG_BASE + 0x03C)
+#define UFS_SYS_UFS_SYSCTRL_REG (UFS_SYS_REG_BASE + 0x05C)
+#define UFS_SYS_UFS_DEVICE_RESET_CTRL_REG (UFS_SYS_REG_BASE + 0x060)
+#define UFS_SYS_UFS_APB_ADDR_MASK_REG (UFS_SYS_REG_BASE + 0x064)
+
+#define BIT_UFS_PSW_ISO_CTRL (1 << 16)
+#define BIT_UFS_PSW_MTCMOS_EN (1 << 0)
+#define BIT_UFS_REFCLK_ISO_EN (1 << 16)
+#define BIT_UFS_PHY_ISO_CTRL (1 << 0)
+#define BIT_SYSCTRL_LP_ISOL_EN (1 << 16)
+#define BIT_SYSCTRL_PWR_READY (1 << 8)
+#define BIT_SYSCTRL_REF_CLOCK_EN (1 << 24)
+#define MASK_SYSCTRL_REF_CLOCK_SEL (3 << 8)
+#define MASK_SYSCTRL_CFG_CLOCK_FREQ (0xFF)
+#define BIT_SYSCTRL_PSW_CLK_EN (1 << 4)
+#define MASK_UFS_CLK_GATE_BYPASS (0x3F)
+#define BIT_SYSCTRL_LP_RESET_N (1 << 0)
+#define BIT_UFS_REFCLK_SRC_SE1 (1 << 0)
+#define MASK_UFS_SYSCTRL_BYPASS (0x3F << 16)
+#define MASK_UFS_DEVICE_RESET (1 << 16)
+#define BIT_UFS_DEVICE_RESET (1 << 0)
+
+#define IOMG_FIX_REG_BASE 0xFF3B6000
+
+/* GPIO150: LED */
+#define IOMG_FIX_006_REG (IOMG_FIX_REG_BASE + 0x018)
+/* GPIO151: LED */
+#define IOMG_FIX_007_REG (IOMG_FIX_REG_BASE + 0x01C)
+
+#define IOMG_AO_REG_BASE 0xFFF11000
+
+/* GPIO189: LED */
+#define IOMG_AO_011_REG (IOMG_AO_REG_BASE + 0x02C)
+/* GPIO190: LED */
+#define IOMG_AO_012_REG (IOMG_AO_REG_BASE + 0x030)
+/* GPIO202: type C enable. active low */
+#define IOMG_AO_023_REG (IOMG_AO_REG_BASE + 0x05C)
+/* GPIO206: USB switch. active low */
+#define IOMG_AO_026_REG (IOMG_AO_REG_BASE + 0x068)
+/* GPIO219: PD interrupt. pull up */
+#define IOMG_AO_039_REG (IOMG_AO_REG_BASE + 0x09C)
+
+#define IOCG_AO_REG_BASE 0xFFF1187C
+/* GPIO219: PD interrupt. pull up */
+#define IOCG_AO_043_REG (IOCG_AO_REG_BASE + 0x030)
+
+#endif /* __HI3660_H__ */
diff --git a/plat/hisilicon/hikey960/include/hi3660_crg.h b/plat/hisilicon/hikey960/include/hi3660_crg.h
new file mode 100644
index 00000000..db1df9ed
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/hi3660_crg.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef __HI3660_CRG_H__
+#define __HI3660_CRG_H__
+
+#define CRG_REG_BASE 0xFFF35000
+
+#define CRG_PEREN0_REG (CRG_REG_BASE + 0x000)
+#define CRG_PERDIS0_REG (CRG_REG_BASE + 0x004)
+#define CRG_PERSTAT0_REG (CRG_REG_BASE + 0x008)
+#define PEREN0_GT_CLK_AOMM (1 << 31)
+
+#define CRG_PEREN1_REG (CRG_REG_BASE + 0x010)
+#define CRG_PERDIS1_REG (CRG_REG_BASE + 0x014)
+#define CRG_PERSTAT1_REG (CRG_REG_BASE + 0x018)
+#define CRG_PEREN2_REG (CRG_REG_BASE + 0x020)
+#define CRG_PERDIS2_REG (CRG_REG_BASE + 0x024)
+#define CRG_PERSTAT2_REG (CRG_REG_BASE + 0x028)
+#define PEREN2_HKADCSSI (1 << 24)
+
+#define CRG_PEREN3_REG (CRG_REG_BASE + 0x030)
+#define CRG_PERDIS3_REG (CRG_REG_BASE + 0x034)
+
+#define CRG_PEREN4_REG (CRG_REG_BASE + 0x040)
+#define CRG_PERDIS4_REG (CRG_REG_BASE + 0x044)
+#define CRG_PERCLKEN4_REG (CRG_REG_BASE + 0x048)
+#define CRG_PERSTAT4_REG (CRG_REG_BASE + 0x04C)
+#define GT_ACLK_USB3OTG (1 << 1)
+#define GT_CLK_USB3OTG_REF (1 << 0)
+
+#define CRG_PEREN5_REG (CRG_REG_BASE + 0x050)
+#define CRG_PERDIS5_REG (CRG_REG_BASE + 0x054)
+#define CRG_PERSTAT5_REG (CRG_REG_BASE + 0x058)
+#define CRG_PERRSTEN0_REG (CRG_REG_BASE + 0x060)
+#define CRG_PERRSTDIS0_REG (CRG_REG_BASE + 0x064)
+#define CRG_PERRSTSTAT0_REG (CRG_REG_BASE + 0x068)
+#define CRG_PERRSTEN1_REG (CRG_REG_BASE + 0x06C)
+#define CRG_PERRSTDIS1_REG (CRG_REG_BASE + 0x070)
+#define CRG_PERRSTSTAT1_REG (CRG_REG_BASE + 0x074)
+#define CRG_PERRSTEN2_REG (CRG_REG_BASE + 0x078)
+#define CRG_PERRSTDIS2_REG (CRG_REG_BASE + 0x07C)
+#define CRG_PERRSTSTAT2_REG (CRG_REG_BASE + 0x080)
+#define PERRSTEN2_HKADCSSI (1 << 24)
+
+#define CRG_PERRSTEN3_REG (CRG_REG_BASE + 0x084)
+#define CRG_PERRSTDIS3_REG (CRG_REG_BASE + 0x088)
+#define CRG_PERRSTSTAT3_REG (CRG_REG_BASE + 0x08C)
+#define CRG_PERRSTEN4_REG (CRG_REG_BASE + 0x090)
+#define CRG_PERRSTDIS4_REG (CRG_REG_BASE + 0x094)
+#define CRG_PERRSTSTAT4_REG (CRG_REG_BASE + 0x098)
+#define IP_RST_USB3OTG_MUX (1 << 8)
+#define IP_RST_USB3OTG_AHBIF (1 << 7)
+#define IP_RST_USB3OTG_32K (1 << 6)
+#define IP_RST_USB3OTG (1 << 5)
+#define IP_RST_USB3OTGPHY_POR (1 << 3)
+
+#define CRG_PERRSTEN5_REG (CRG_REG_BASE + 0x09C)
+#define CRG_PERRSTDIS5_REG (CRG_REG_BASE + 0x0A0)
+#define CRG_PERRSTSTAT5_REG (CRG_REG_BASE + 0x0A4)
+
+/* bit fields in CRG_PERI */
+#define PERI_PCLK_PCTRL_BIT (1 << 31)
+#define PERI_TIMER12_BIT (1 << 25)
+#define PERI_TIMER11_BIT (1 << 24)
+#define PERI_TIMER10_BIT (1 << 23)
+#define PERI_TIMER9_BIT (1 << 22)
+#define PERI_UART5_BIT (1 << 15)
+#define PERI_UFS_BIT (1 << 12)
+#define PERI_ARST_UFS_BIT (1 << 7)
+#define PERI_PPLL2_EN_CPU (1 << 3)
+#define PERI_PWM_BIT (1 << 0)
+#define PERI_DDRC_BIT (1 << 0)
+#define PERI_DDRC_D_BIT (1 << 4)
+#define PERI_DDRC_C_BIT (1 << 3)
+#define PERI_DDRC_B_BIT (1 << 2)
+#define PERI_DDRC_A_BIT (1 << 1)
+#define PERI_DDRC_DMUX_BIT (1 << 0)
+
+#define CRG_CLKDIV0_REG (CRG_REG_BASE + 0x0A0)
+#define SC_DIV_LPMCU_MASK ((0x1F << 5) << 16)
+#define SC_DIV_LPMCU(x) (((x) & 0x1F) << 5)
+
+#define CRG_CLKDIV1_REG (CRG_REG_BASE + 0x0B0)
+#define SEL_LPMCU_PLL_MASK ((1 << 1) << 16)
+#define SEL_SYSBUS_MASK ((1 << 0) << 16)
+#define SEL_LPMCU_PLL1 (1 << 1)
+#define SEL_LPMCU_PLL0 (0 << 1)
+#define SEL_SYSBUS_PLL0 (1 << 0)
+#define SEL_SYSBUS_PLL1 (0 << 0)
+
+#define CRG_CLKDIV3_REG (CRG_REG_BASE + 0x0B4)
+#define CRG_CLKDIV5_REG (CRG_REG_BASE + 0x0BC)
+#define CRG_CLKDIV8_REG (CRG_REG_BASE + 0x0C8)
+
+#define CRG_CLKDIV12_REG (CRG_REG_BASE + 0x0D8)
+#define SC_DIV_A53HPM_MASK (0x7 << 13)
+#define SC_DIV_A53HPM(x) (((x) & 0x7) << 13)
+
+#define CRG_CLKDIV16_REG (CRG_REG_BASE + 0x0E8)
+#define DDRC_CLK_SW_REQ_CFG_MASK (0x3 << 12)
+#define DDRC_CLK_SW_REQ_CFG(x) (((x) & 0x3) << 12)
+#define SC_DIV_UFSPHY_CFG_MASK (0x3 << 9)
+#define SC_DIV_UFSPHY_CFG(x) (((x) & 0x3) << 9)
+#define DDRCPLL_SW (1 << 8)
+
+#define CRG_CLKDIV17_REG (CRG_REG_BASE + 0x0EC)
+#define SC_DIV_UFS_PERIBUS (1 << 14)
+
+#define CRG_CLKDIV18_REG (CRG_REG_BASE + 0x0F0)
+#define CRG_CLKDIV19_REG (CRG_REG_BASE + 0x0F4)
+#define CRG_CLKDIV20_REG (CRG_REG_BASE + 0x0F8)
+#define CLKDIV20_GT_CLK_AOMM (1 << 3)
+
+#define CRG_CLKDIV22_REG (CRG_REG_BASE + 0x100)
+#define SEL_PLL_320M_MASK (1 << 16)
+#define SEL_PLL2_320M (1 << 0)
+#define SEL_PLL0_320M (0 << 0)
+
+#define CRG_CLKDIV23_REG (CRG_REG_BASE + 0x104)
+#define PERI_DDRC_SW_BIT (1 << 13)
+#define DIV_CLK_DDRSYS_MASK (0x3 << 10)
+#define DIV_CLK_DDRSYS(x) (((x) & 0x3) << 10)
+#define GET_DIV_CLK_DDRSYS(x) (((x) & DIV_CLK_DDRSYS_MASK) >> 10)
+#define DIV_CLK_DDRCFG_MASK (0x6 << 5)
+#define DIV_CLK_DDRCFG(x) (((x) & 0x6) << 5)
+#define GET_DIV_CLK_DDRCFG(x) (((x) & DIV_CLK_DDRCFG_MASK) >> 5)
+#define DIV_CLK_DDRC_MASK 0x1F
+#define DIV_CLK_DDRC(x) ((x) & DIV_CLK_DDRC_MASK)
+#define GET_DIV_CLK_DDRC(x) ((x) & DIV_CLK_DDRC_MASK)
+
+#define CRG_CLKDIV25_REG (CRG_REG_BASE + 0x10C)
+#define DIV_SYSBUS_PLL_MASK (0xF << 16)
+#define DIV_SYSBUS_PLL(x) ((x) & 0xF)
+
+#define CRG_PERI_CTRL2_REG (CRG_REG_BASE + 0x128)
+#define PERI_TIME_STAMP_CLK_MASK (0x7 << 28)
+#define PERI_TIME_STAMP_CLK_DIV(x) (((x) & 0x7) << 22)
+
+#define CRG_ISODIS_REG (CRG_REG_BASE + 0x148)
+#define CRG_PERPWREN_REG (CRG_REG_BASE + 0x150)
+
+#define CRG_PEREN7_REG (CRG_REG_BASE + 0x420)
+#define CRG_PERDIS7_REG (CRG_REG_BASE + 0x424)
+#define CRG_PERSTAT7_REG (CRG_REG_BASE + 0x428)
+#define GT_CLK_UFSPHY_CFG (1 << 14)
+
+#define CRG_PEREN8_REG (CRG_REG_BASE + 0x430)
+#define CRG_PERDIS8_REG (CRG_REG_BASE + 0x434)
+#define CRG_PERSTAT8_REG (CRG_REG_BASE + 0x438)
+#define PERI_DMC_D_BIT (1 << 22)
+#define PERI_DMC_C_BIT (1 << 21)
+#define PERI_DMC_B_BIT (1 << 20)
+#define PERI_DMC_A_BIT (1 << 19)
+#define PERI_DMC_BIT (1 << 18)
+
+#define CRG_PEREN11_REG (CRG_REG_BASE + 0x460)
+#define PPLL1_GATE_CPU (1 << 18)
+
+#define CRG_PERSTAT11_REG (CRG_REG_BASE + 0x46C)
+#define PPLL3_EN_STAT (1 << 21)
+#define PPLL2_EN_STAT (1 << 20)
+#define PPLL1_EN_STAT (1 << 19)
+
+#define CRG_IVP_SEC_RSTDIS_REG (CRG_REG_BASE + 0xC04)
+#define CRG_ISP_SEC_RSTDIS_REG (CRG_REG_BASE + 0xC84)
+
+#define CRG_RVBAR(c, n) (0xE00 + (0x10 * c) + (0x4 * n))
+#define CRG_GENERAL_SEC_RSTEN_REG (CRG_REG_BASE + 0xE20)
+#define CRG_GENERAL_SEC_RSTDIS_REG (CRG_REG_BASE + 0xE24)
+#define IP_RST_GPIO0_SEC (1 << 2)
+
+#define CRG_GENERAL_SEC_CLKDIV0_REG (CRG_REG_BASE + 0xE90)
+#define SC_DIV_AO_HISE_MASK 3
+#define SC_DIV_AO_HISE(x) ((x) & 0x3)
+
+#endif /* __HI3660_CRG_H__ */
diff --git a/plat/hisilicon/hikey960/include/hi3660_hkadc.h b/plat/hisilicon/hikey960/include/hi3660_hkadc.h
new file mode 100644
index 00000000..6e67114e
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/hi3660_hkadc.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef __HI3660_HKADC_H__
+#define __HI3660_HKADC_H__
+
+#define HKADC_SSI_REG_BASE 0xE82B8000
+
+#define HKADC_DSP_START_REG (HKADC_SSI_REG_BASE + 0x000)
+#define HKADC_WR_NUM_REG (HKADC_SSI_REG_BASE + 0x008)
+#define HKADC_DSP_START_CLR_REG (HKADC_SSI_REG_BASE + 0x01C)
+#define HKADC_WR01_DATA_REG (HKADC_SSI_REG_BASE + 0x020)
+
+#define WR1_WRITE_MODE (1 << 31)
+#define WR1_READ_MODE (0 << 31)
+#define WR1_ADDR(x) (((x) & 0x7F) << 24)
+#define WR1_DATA(x) (((x) & 0xFF) << 16)
+#define WR0_WRITE_MODE (1 << 15)
+#define WR0_READ_MODE (0 << 15)
+#define WR0_ADDR(x) (((x) & 0x7F) << 8)
+#define WR0_DATA(x) ((x) & 0xFF)
+
+#define HKADC_WR23_DATA_REG (HKADC_SSI_REG_BASE + 0x024)
+#define HKADC_WR45_DATA_REG (HKADC_SSI_REG_BASE + 0x028)
+#define HKADC_DELAY01_REG (HKADC_SSI_REG_BASE + 0x030)
+#define HKADC_DELAY23_REG (HKADC_SSI_REG_BASE + 0x034)
+#define HKADC_DELAY45_REG (HKADC_SSI_REG_BASE + 0x038)
+#define HKADC_DSP_RD2_DATA_REG (HKADC_SSI_REG_BASE + 0x048)
+#define HKADC_DSP_RD3_DATA_REG (HKADC_SSI_REG_BASE + 0x04C)
+
+/* HKADC Internal Registers */
+#define HKADC_CTRL_ADDR 0x00
+#define HKADC_START_ADDR 0x01
+#define HKADC_DATA1_ADDR 0x03 /* high 8 bits */
+#define HKADC_DATA0_ADDR 0x04 /* low 8 bits */
+#define HKADC_MODE_CFG 0x0A
+
+#define HKADC_VALUE_HIGH 0x0FF0
+#define HKADC_VALUE_LOW 0x000F
+#define HKADC_VALID_VALUE 0x0FFF
+
+#define HKADC_CHANNEL_MAX 15
+#define HKADC_VREF_1V8 1800
+#define HKADC_ACCURACY 0x0FFF
+
+#define HKADC_WR01_VALUE ((HKADC_START_ADDR << 24) | \
+ (0x1 << 16))
+#define HKADC_WR23_VALUE ((0x1 << 31) | \
+ (HKADC_DATA0_ADDR << 24) | \
+ (1 << 15) | \
+ (HKADC_DATA1_ADDR << 8))
+#define HKADC_WR45_VALUE (0x80)
+#define HKADC_CHANNEL0_DELAY01_VALUE ((0x0700 << 16) | 0xFFFF)
+#define HKADC_DELAY01_VALUE ((0x0700 << 16) | 0x0200)
+#define HKADC_DELAY23_VALUE ((0x00C8 << 16) | 0x00C8)
+#define START_DELAY_TIMEOUT 2000
+#define HKADC_WR_NUM_VALUE 4
+
+#endif /* __HI3660_HKADC_H__ */
diff --git a/plat/hisilicon/hikey960/include/hi3660_mem_map.h b/plat/hisilicon/hikey960/include/hi3660_mem_map.h
new file mode 100644
index 00000000..db3efaf0
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/hi3660_mem_map.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __HI3660_MEM_MAP__
+#define __HI3660_MEM_MAP__
+
+#define HISI_DATA_HEAD_BASE (0x89C44400)
+
+#define HISI_RESERVED_MEM_BASE (0x89C80000)
+#define HISI_RESERVED_MEM_SIZE (0x00040000)
+
+#define HISI_DATA0_BASE (0x89C96180)
+#define HISI_DATA0_SIZE (0x000003A0)
+#define HISI_DATA1_BASE (0x89C93480)
+#define HISI_DATA1_SIZE (0x00002D00)
+
+#endif /* __HI3660_MEM_MAP__ */
diff --git a/plat/hisilicon/hikey960/include/plat_macros.S b/plat/hisilicon/hikey960/include/plat_macros.S
new file mode 100644
index 00000000..9f1befdc
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/plat_macros.S
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __PLAT_MACROS_S__
+#define __PLAT_MACROS_S__
+
+#include <cci.h>
+#include <hi3660.h>
+#include <gic_v2.h>
+#include <platform_def.h>
+
+.section .rodata.gic_reg_name, "aS"
+gicc_regs:
+ .asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", ""
+gicd_pend_reg:
+ .asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n" \
+ " Offset:\t\t\tvalue\n"
+newline:
+ .asciz "\n"
+spacer:
+ .asciz ":\t\t0x"
+
+.section .rodata.cci_reg_name, "aS"
+cci_iface_regs:
+ .asciz "cci_snoop_ctrl_cluster0", "cci_snoop_ctrl_cluster1" , ""
+
+/* ---------------------------------------------
+ * The below macro prints out relevant GIC
+ * registers whenever an unhandled exception is
+ * taken in BL31.
+ * ---------------------------------------------
+ */
+.macro plat_crash_print_regs
+ mov_imm x16, GICD_REG_BASE
+ mov_imm x17, GICC_REG_BASE
+
+ /* Load the gicc reg list to x6 */
+ adr x6, gicc_regs
+ /* Load the gicc regs to gp regs used by str_in_crash_buf_print */
+ ldr w8, [x17, #GICC_HPPIR]
+ ldr w9, [x17, #GICC_AHPPIR]
+ ldr w10, [x17, #GICC_CTLR]
+ /* Store to the crash buf and print to cosole */
+ bl str_in_crash_buf_print
+
+ /* Print the GICD_ISPENDR regs */
+ add x7, x16, #GICD_ISPENDR
+ adr x4, gicd_pend_reg
+ bl asm_print_str
+2:
+ sub x4, x7, x16
+ cmp x4, #0x280
+ b.eq 1f
+ bl asm_print_hex
+ adr x4, spacer
+ bl asm_print_str
+ ldr x4, [x7], #8
+ bl asm_print_hex
+ adr x4, newline
+ bl asm_print_str
+ b 2b
+1:
+ adr x6, cci_iface_regs
+ /* Store in x7 the base address of the first interface */
+ mov_imm x7, (CCI400_REG_BASE + SLAVE_IFACE_OFFSET( \
+ CCI400_SL_IFACE3_CLUSTER_IX))
+ ldr w8, [x7, #SNOOP_CTRL_REG]
+ /* Store in x7 the base address of the second interface */
+ mov_imm x7, (CCI400_REG_BASE + SLAVE_IFACE_OFFSET( \
+ CCI400_SL_IFACE4_CLUSTER_IX))
+ ldr w9, [x7, #SNOOP_CTRL_REG]
+ /* Store to the crash buf and print to console */
+ bl str_in_crash_buf_print
+.endm
+
+#endif /* __PLAT_MACROS_S__ */
diff --git a/plat/hisilicon/hikey960/include/platform_def.h b/plat/hisilicon/hikey960/include/platform_def.h
new file mode 100644
index 00000000..369117b8
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/platform_def.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __PLATFORM_DEF_H__
+#define __PLATFORM_DEF_H__
+
+#include <arch.h>
+#include "../hikey960_def.h"
+
+
+/*
+ * Generic platform constants
+ */
+
+/* Size of cacheable stacks */
+#define PLATFORM_STACK_SIZE 0x800
+
+#define FIRMWARE_WELCOME_STR "Booting Trusted Firmware\n"
+
+#define PLATFORM_CACHE_LINE_SIZE 64
+#define PLATFORM_CLUSTER_COUNT 2
+#define PLATFORM_CORE_COUNT_PER_CLUSTER 4
+#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER_COUNT * \
+ PLATFORM_CORE_COUNT_PER_CLUSTER)
+#define PLAT_MAX_PWR_LVL MPIDR_AFFLVL2
+#define PLAT_NUM_PWR_DOMAINS (PLATFORM_CORE_COUNT + \
+ PLATFORM_CLUSTER_COUNT + 1)
+
+#define PLAT_MAX_RET_STATE 1
+#define PLAT_MAX_OFF_STATE 2
+
+#define MAX_IO_DEVICES 3
+#define MAX_IO_HANDLES 4
+/* UFS RPMB and UFS User Data */
+#define MAX_IO_BLOCK_DEVICES 2
+
+
+/*
+ * Platform memory map related constants
+ */
+
+/*
+ * BL1 specific defines.
+ */
+#define BL1_RO_BASE (0x1AC00000)
+#define BL1_RO_LIMIT (BL1_RO_BASE + 0x10000)
+#define BL1_RW_BASE (BL1_RO_LIMIT) /* 1AC1_0000 */
+#define BL1_RW_SIZE (0x00188000)
+#define BL1_RW_LIMIT (0x1B000000)
+
+/*
+ * BL2 specific defines.
+ */
+#define BL2_BASE (BL1_RW_BASE + 0x8000) /* 1AC1_8000 */
+#define BL2_LIMIT (BL2_BASE + 0x40000) /* 1AC5_8000 */
+
+/*
+ * BL31 specific defines.
+ */
+#define BL31_BASE (BL2_LIMIT) /* 1AC5_8000 */
+#define BL31_LIMIT (BL31_BASE + 0x40000) /* 1AC9_8000 */
+
+#define NS_BL1U_BASE (BL31_LIMIT) /* 1AC9_8000 */
+#define NS_BL1U_SIZE (0x00100000)
+#define NS_BL1U_LIMIT (NS_BL1U_BASE + NS_BL1U_SIZE)
+
+#define HIKEY960_NS_IMAGE_OFFSET (0x1AC18000) /* offset in l-loader */
+#define HIKEY960_NS_TMP_OFFSET (0x1AE00000)
+
+#define SCP_BL2_BASE BL31_BASE
+
+#define SCP_MEM_BASE (0x89C80000)
+#define SCP_MEM_SIZE (0x00040000)
+
+/*
+ * Platform specific page table and MMU setup constants
+ */
+#define ADDR_SPACE_SIZE (1ull << 32)
+
+#if IMAGE_BL1 || IMAGE_BL2 || IMAGE_BL31
+#define MAX_XLAT_TABLES 3
+#endif
+
+#define MAX_MMAP_REGIONS 16
+
+/*
+ * Declarations and constants to access the mailboxes safely. Each mailbox is
+ * aligned on the biggest cache line size in the platform. This is known only
+ * to the platform as it might have a combination of integrated and external
+ * caches. Such alignment ensures that two maiboxes do not sit on the same cache
+ * line at any cache level. They could belong to different cpus/clusters &
+ * get written while being protected by different locks causing corruption of
+ * a valid mailbox address.
+ */
+#define CACHE_WRITEBACK_SHIFT 6
+#define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT)
+
+#endif /* __PLATFORM_DEF_H__ */
diff --git a/plat/hisilicon/hikey960/platform.mk b/plat/hisilicon/hikey960/platform.mk
new file mode 100644
index 00000000..b04c5efb
--- /dev/null
+++ b/plat/hisilicon/hikey960/platform.mk
@@ -0,0 +1,43 @@
+#
+# Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+CRASH_CONSOLE_BASE := PL011_UART6_BASE
+COLD_BOOT_SINGLE_CPU := 1
+PROGRAMMABLE_RESET_ADDRESS := 1
+
+# Process flags
+$(eval $(call add_define,CRASH_CONSOLE_BASE))
+
+ENABLE_PLAT_COMPAT := 0
+
+USE_COHERENT_MEM := 1
+
+PLAT_INCLUDES := -Iinclude/common/tbbr \
+ -Iplat/hisilicon/hikey960/include
+
+PLAT_BL_COMMON_SOURCES := drivers/arm/pl011/pl011_console.S \
+ drivers/delay_timer/delay_timer.c \
+ drivers/delay_timer/generic_delay_timer.c \
+ lib/aarch64/xlat_tables.c \
+ plat/hisilicon/hikey960/aarch64/hikey960_common.c \
+ plat/hisilicon/hikey960/hikey960_boardid.c
+
+HIKEY960_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \
+ drivers/arm/gic/v2/gicv2_main.c \
+ drivers/arm/gic/v2/gicv2_helpers.c \
+ plat/common/plat_gicv2.c
+
+BL1_SOURCES += bl1/tbbr/tbbr_img_desc.c \
+ drivers/io/io_block.c \
+ drivers/io/io_fip.c \
+ drivers/io/io_storage.c \
+ drivers/synopsys/ufs/dw_ufs.c \
+ drivers/ufs/ufs.c \
+ lib/cpus/aarch64/cortex_a53.S \
+ plat/hisilicon/hikey960/aarch64/hikey960_helpers.S \
+ plat/hisilicon/hikey960/hikey960_bl1_setup.c \
+ plat/hisilicon/hikey960/hikey960_io_storage.c \
+ ${HIKEY960_GIC_SOURCES}