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>
diff --git a/plat/hisilicon/hikey960/hikey960_boardid.c b/plat/hisilicon/hikey960/hikey960_boardid.c
new file mode 100644
index 0000000..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;
+}