arm: add initial support for the Phytium Pomelo Board

This adds platform code and the device tree for the Phytium Pomelo Board.
The initial support comprises the UART and the PCIE.

Signed-off-by: weichangzheng <nicholas_zheng@outlook.com>
diff --git a/board/phytium/pomelo/Kconfig b/board/phytium/pomelo/Kconfig
new file mode 100644
index 0000000..281aa8f
--- /dev/null
+++ b/board/phytium/pomelo/Kconfig
@@ -0,0 +1,12 @@
+if TARGET_POMELO
+
+config SYS_BOARD
+	default "pomelo"
+
+config SYS_VENDOR
+	default "phytium"
+
+config SYS_CONFIG_NAME
+	default "pomelo"
+
+endif
diff --git a/board/phytium/pomelo/MAINTAINERS b/board/phytium/pomelo/MAINTAINERS
new file mode 100644
index 0000000..d76a4a0
--- /dev/null
+++ b/board/phytium/pomelo/MAINTAINERS
@@ -0,0 +1,8 @@
+POMELO BOARD
+M:	lixinde <lixinde@phytium.com.cn>
+M:	weichangzheng <weichangzheng@phytium.com.cn>
+S:	Maintained
+F:	board/phytium/pomelo/*
+F:	include/configs/pomelo.h
+F:	configs/pomelo_defconfig
+F:	arch/arm/dts/phytium-pomelo.dts
diff --git a/board/phytium/pomelo/Makefile b/board/phytium/pomelo/Makefile
new file mode 100644
index 0000000..b9cb360
--- /dev/null
+++ b/board/phytium/pomelo/Makefile
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2021
+# lixinde         <lixinde@phytium.com.cn>
+# weichangzheng   <weichangzheng@phytium.com.cn>
+#
+
+obj-y += pomelo.o
+obj-y += pll.o
+obj-y += pcie.o
+obj-y += ddr.o
+obj-y += sec.o
+
+
diff --git a/board/phytium/pomelo/cpu.h b/board/phytium/pomelo/cpu.h
new file mode 100644
index 0000000..005ea59
--- /dev/null
+++ b/board/phytium/pomelo/cpu.h
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2021
+ * Phytium Technology Ltd <www.phytium.com>
+ * lixinde         <lixinde@phytium.com.cn>
+ * weichangzheng   <weichangzheng@phytium.com.cn>
+ */
+
+#ifndef _FT_POMELO_H
+#define _FT_POMELO_H
+
+/* SMCCC ID */
+#define CPU_SVC_VERSION			0xC2000F00
+#define CPU_GET_RST_SOURCE		0xC2000F01
+#define CPU_INIT_PLL			0xC2000F02
+#define CPU_INIT_PCIE			0xC2000F03
+#define CPU_INIT_MEM			0xC2000F04
+#define CPU_INIT_SEC_SVC		0xC2000F05
+
+/*CPU RESET*/
+#define CPU_RESET_POWER_ON		0x1
+#define CPU_RESET_PLL			0x4
+#define CPU_RESET_WATCH_DOG		0x8
+
+/* PLL */
+#define PARAMETER_PLL_MAGIC		0x54460010
+
+/* PCIE */
+#define PARAMETER_PCIE_MAGIC		0x54460011
+#define CFG_INDEPENDENT_TREE		0x0
+#define PCI_PEU0			0x1
+#define PCI_PEU1			0x1
+#define PEU1_OFFSET			16
+#define PEU_C_OFFSET_MODE		16
+#define PEU_C_OFFSET_SPEED		0
+#define RC_MODE				0x1
+#define X8X8				0x1
+#define GEN3				3
+
+/* DDR */
+#define PARAMETER_MCU_MAGIC		0x54460014
+#define PARAM_MCU_VERSION		0x1
+#define PARAM_MCU_SIZE			0x100
+#define PARAM_CH_ENABLE			0x3
+#define PARAM_ECC_ENABLE		0x3
+#define PARAM_FORCE_SPD_DISABLE		0x0
+#define PARAM_MCU_MISC_ENABLE		0x0
+
+#define UDIMM_TYPE			0x2
+#define DIMM_X8				0x1
+#define NO_MIRROR			0x0
+#define NO_ECC_TYPE			0
+#define DDR4_TYPE			0xC
+
+/* SEC */
+#define PARAMETER_COMMON_MAGIC		0x54460013
+
+/* FLUSH L3 CASHE */
+#define HNF_COUNT			0x8
+#define HNF_PSTATE_REQ			(HNF_BASE + 0x10)
+#define HNF_PSTATE_STAT			(HNF_BASE + 0x18)
+#define HNF_PSTATE_OFF			0x0
+#define HNF_PSTATE_SFONLY		0x1
+#define HNF_PSTATE_HALF			0x2
+#define HNF_PSTATE_FULL			0x3
+#define HNF_STRIDE			0x10000
+#define HNF_BASE			(unsigned long)(0x3A200000)
+void ddr_init(void);
+void sec_init(void);
+void check_reset(void);
+void pcie_init(void);
+
+#endif /* _FT_POMELO_H */
diff --git a/board/phytium/pomelo/ddr.c b/board/phytium/pomelo/ddr.c
new file mode 100644
index 0000000..c6dbed9
--- /dev/null
+++ b/board/phytium/pomelo/ddr.c
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2021
+ * lixinde         <lixinde@phytium.com.cn>
+ * weichangzheng   <weichangzheng@phytium.com.cn>
+ */
+
+#include <stdio.h>
+#include <linux/arm-smccc.h>
+#include <init.h>
+#include "cpu.h"
+
+struct ddr_spd {
+	/******************* read from spd *****************/
+	u8  dimm_type;	/* 1: RDIMM;2: UDIMM;3: SODIMM;4: LRDIMM */
+	u8  data_width;	/* 0: x4; 1: x8; 2: x16 */
+	u8  mirror_type;/* 0: stardard; 1: mirror */
+	u8  ecc_type;	/* 0: no-ecc; 1:ecc */
+	u8  dram_type;	/* 0xB: DDR3; 0xC: DDR4 */
+	u8  rank_num;
+	u8  row_num;
+	u8  col_num;
+
+	u8  bg_num;	/*only DDR4*/
+	u8  bank_num;
+	u16 module_manufacturer_id;
+	u16 taamin;
+	u16 trcdmin;
+
+	u16 trpmin;
+	u16 trasmin;
+	u16 trcmin;
+	u16 tfawmin;
+
+	u16 trrd_smin;	/*only DDR4*/
+	u16 trrd_lmin;	/*only DDR4*/
+	u16 tccd_lmin;	/*only DDR4*/
+	u16 twrmin;
+
+	u16 twtr_smin;	/*only DDR4*/
+	u16 twtr_lmin;	/*only DDR4*/
+	u16 twtrmin;	/*only DDR3*/
+	u16 trrdmin;	/*only DDR3*/
+
+	/******************* RCD control words *****************/
+	u8  f0rc03; /*bit[3:2]:CS		bit[1:0]:CA  */
+	u8  f0rc04; /*bit[3:2]:ODT		bit[1:0]:CKE */
+	u8  f0rc05; /*bit[3:2]:CLK-A side	bit[1:0]:CLK-B side */
+	u8  bc00;
+	u8  bc01;
+	u8  bc02;
+	u8  bc03;
+	u8  bc04;
+
+	u8  bc05;
+	u8  f5bc5x;
+	u8  f5bc6x;
+	/******************* LRDIMM special *****************/
+	u8  vrefdq_pr0;
+	u8  vrefdq_mdram;
+	u8  rtt_mdram_1866;
+	u8  rtt_mdram_2400;
+	u8  rtt_mdram_3200;
+
+	u8  drive_dram;
+	u8  odt_dram_1866;
+	u8  odt_dram_2400;
+	u8  odt_dram_3200;
+	u8  park_dram_1866;
+	u8  park_dram_2400;
+	u8  park_dram_3200;
+	u8  rcd_num;
+} __attribute((aligned(4)));
+
+struct mcu_config {
+	u32 magic;
+	u32 version;
+	u32 size;
+	u8 rev1[4];
+
+	u8 ch_enable;
+	u8 misc1_enable;
+	u8 misc2_enable;
+	u8 force_spd_enable;
+	u8 misc3_enable;
+	u8 train_debug;
+	u8 train_recover;
+	u8 rev2[9];
+
+	struct ddr_spd ddr_spd_info[2];
+} __attribute((aligned(4)));
+
+static void get_mcu_up_info_default(struct mcu_config *pm)
+{
+	pm->magic		= PARAMETER_MCU_MAGIC;
+	pm->version		= PARAM_MCU_VERSION;
+	pm->size		= PARAM_MCU_SIZE;
+	pm->ch_enable		= PARAM_CH_ENABLE;
+	pm->misc1_enable	= PARAM_ECC_ENABLE;
+	pm->force_spd_enable	= PARAM_FORCE_SPD_DISABLE;
+	pm->misc3_enable	= PARAM_MCU_MISC_ENABLE;
+	pm->train_recover	= 0x0;
+}
+
+static u8 init_dimm_param(u8 ch, struct mcu_config *pm)
+{
+	debug("manual config dimm info...\n");
+	pm->ddr_spd_info[ch].dimm_type = UDIMM_TYPE;
+	pm->ddr_spd_info[ch].data_width = DIMM_X8;
+	pm->ddr_spd_info[ch].mirror_type = NO_MIRROR;
+	pm->ddr_spd_info[ch].ecc_type = NO_ECC_TYPE;
+	pm->ddr_spd_info[ch].dram_type = DDR4_TYPE;
+	pm->ddr_spd_info[ch].rank_num = 1;
+	pm->ddr_spd_info[ch].row_num  = 16;
+	pm->ddr_spd_info[ch].col_num = 10;
+	pm->ddr_spd_info[ch].bg_num = 4;
+	pm->ddr_spd_info[ch].bank_num = 4;
+	pm->ddr_spd_info[ch].taamin = 13750;
+	pm->ddr_spd_info[ch].trcdmin = 13750;
+
+	pm->ddr_spd_info[ch].trpmin = 13750;
+	pm->ddr_spd_info[ch].trasmin = 32000;
+	pm->ddr_spd_info[ch].trcmin =  45750;
+	pm->ddr_spd_info[ch].tfawmin = 21000;
+
+	pm->ddr_spd_info[ch].trrd_smin = 3000;
+	pm->ddr_spd_info[ch].trrd_lmin = 4900;
+	pm->ddr_spd_info[ch].tccd_lmin = 5000;
+	pm->ddr_spd_info[ch].twrmin = 15000;
+
+	pm->ddr_spd_info[ch].twtr_smin = 2500;
+	pm->ddr_spd_info[ch].twtr_lmin = 7500;
+
+	return 0;
+}
+
+void get_default_mcu_info(u8 *data)
+{
+	get_mcu_up_info_default((struct mcu_config *)data);
+}
+
+void fix_mcu_info(u8 *data)
+{
+	struct mcu_config *mcu_info = (struct mcu_config *)data;
+
+	for (int ch = 0; ch < 2; ch++)
+		init_dimm_param(ch, mcu_info);
+}
+
+void ddr_init(void)
+{
+	u8 buffer[0x100];
+	struct arm_smccc_res res;
+
+	get_default_mcu_info(buffer);
+	fix_mcu_info(buffer);
+
+	arm_smccc_smc(CPU_INIT_MEM, 0, (u64)buffer, 0, 0, 0, 0, 0, &res);
+	if (res.a0 != 0)
+		panic("DRAM init failed :0x%lx\n", res.a0);
+}
diff --git a/board/phytium/pomelo/pcie.c b/board/phytium/pomelo/pcie.c
new file mode 100644
index 0000000..698d82f
--- /dev/null
+++ b/board/phytium/pomelo/pcie.c
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2021
+ * lixinde         <lixinde@phytium.com.cn>
+ * weichangzheng   <weichangzheng@phytium.com.cn>
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <linux/arm-smccc.h>
+#include <init.h>
+#include "cpu.h"
+
+struct pcu_ctr {
+	u32 base_config[3];
+	u32 equalization[3];
+	u8 rev[80];
+} __attribute((aligned(4)));
+
+struct pcu_config {
+	u32 magic;
+	u32 version;
+	u32 size;
+	u8 rev1[4];
+	u32 independent_tree;
+	u32 base_cfg;
+	u8 rev2[16];
+	struct pcu_ctr ctr_cfg[2];
+} __attribute((aligned(4)));
+
+struct pcu_config const peu_base_info = {
+	.magic = PARAMETER_PCIE_MAGIC,
+	.version = 0x2,
+	.size = 0x100,
+	.independent_tree = CFG_INDEPENDENT_TREE,
+	.base_cfg = ((PCI_PEU1 | (X8X8 << 1)) << PEU1_OFFSET | (PCI_PEU0 | (X8X8 << 1))),
+	.ctr_cfg[0].base_config[0] = (RC_MODE << PEU_C_OFFSET_MODE) | (GEN3 << PEU_C_OFFSET_SPEED),
+	.ctr_cfg[0].base_config[1] = (RC_MODE << PEU_C_OFFSET_MODE) | (GEN3 << PEU_C_OFFSET_SPEED),
+	.ctr_cfg[0].base_config[2] = (RC_MODE << PEU_C_OFFSET_MODE) | (GEN3 << PEU_C_OFFSET_SPEED),
+	.ctr_cfg[1].base_config[0] = (RC_MODE << PEU_C_OFFSET_MODE) | (GEN3 << PEU_C_OFFSET_SPEED),
+	.ctr_cfg[1].base_config[1] = (RC_MODE << PEU_C_OFFSET_MODE) | (GEN3 << PEU_C_OFFSET_SPEED),
+	.ctr_cfg[1].base_config[2] = (RC_MODE << PEU_C_OFFSET_MODE) | (GEN3 << PEU_C_OFFSET_SPEED),
+	.ctr_cfg[0].equalization[0] = 0x7,
+	.ctr_cfg[0].equalization[1] = 0x7,
+	.ctr_cfg[0].equalization[2] = 0x7,
+	.ctr_cfg[1].equalization[0] = 0x7,
+	.ctr_cfg[1].equalization[1] = 0x7,
+	.ctr_cfg[1].equalization[2] = 0x7,
+};
+
+void pcie_init(void)
+{
+	u8 buffer[0x100];
+	struct arm_smccc_res res;
+
+	memcpy(buffer, &peu_base_info, sizeof(peu_base_info));
+	arm_smccc_smc(CPU_INIT_PCIE, 0, (u64)buffer, 0, 0, 0, 0, 0, &res);
+	if (res.a0 != 0)
+		panic("PCIE init failed :0x%lx\n", res.a0);
+}
diff --git a/board/phytium/pomelo/pll.c b/board/phytium/pomelo/pll.c
new file mode 100644
index 0000000..a66ffdd
--- /dev/null
+++ b/board/phytium/pomelo/pll.c
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2021
+ * lixinde         <lixinde@phytium.com.cn>
+ * weichangzheng   <weichangzheng@phytium.com.cn>
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <asm/io.h>
+#include <linux/arm-smccc.h>
+#include <init.h>
+#include "cpu.h"
+
+struct pll_config {
+	u32 magic;
+	u32 version;
+	u32 size;
+	u8 rev1[4];
+	u32 core_pll;
+	u32 res1;
+	u32 lmu_pll;
+	u32 res2;
+	u32 res3;
+	u32 res4;
+	u32 res5;
+} __attribute((aligned(4)));
+
+struct pll_config const pll_base_info = {
+	.magic = PARAMETER_PLL_MAGIC,
+	.version = 0x1,
+	.size = 0x30,
+	.core_pll = 2300,	/*MHz*/
+	.lmu_pll = 667,		/*MHz*/
+};
+
+u32 get_reset_source(void)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_smc(CPU_GET_RST_SOURCE, 0, 0, 0, 0, 0, 0, 0, &res);
+	return res.a0;
+}
+
+void pll_init(void)
+{
+	u8 buffer[0x100];
+	struct arm_smccc_res res;
+
+	memcpy(buffer, &pll_base_info, sizeof(pll_base_info));
+	arm_smccc_smc(CPU_INIT_PLL, 0, (u64)buffer, 0, 0, 0, 0, 0, &res);
+	if (res.a0 != 0)
+		panic("PLL init failed :0x%lx\n", res.a0);
+}
+
+void check_reset(void)
+{
+	u32 rst;
+
+	rst = get_reset_source();
+
+	switch (rst) {
+	case CPU_RESET_POWER_ON:
+		pll_init();
+		break;
+	case CPU_RESET_PLL:
+		break;
+	case CPU_RESET_WATCH_DOG:
+		break;
+	default:
+		panic("other reset source\n");
+	}
+}
diff --git a/board/phytium/pomelo/pomelo.c b/board/phytium/pomelo/pomelo.c
new file mode 100644
index 0000000..4fbe1e5
--- /dev/null
+++ b/board/phytium/pomelo/pomelo.c
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2021
+ * lixinde         <lixinde@phytium.com.cn>
+ * weichangzheng   <weichangzheng@phytium.com.cn>
+ */
+
+#include <stdio.h>
+#include <command.h>
+#include <init.h>
+#include <asm/armv8/mmu.h>
+#include <asm/io.h>
+#include <linux/arm-smccc.h>
+#include <scsi.h>
+#include <init.h>
+#include <asm/u-boot.h>
+#include "cpu.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int dram_init(void)
+{
+	debug("Phytium ddr init\n");
+	ddr_init();
+
+	gd->mem_clk = 0;
+	gd->ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE, 0x7b000000);
+
+	sec_init();
+	debug("PBF relocate done\n");
+
+	return 0;
+}
+
+int board_init(void)
+{
+	return 0;
+}
+
+void reset_cpu(void)
+{
+	struct arm_smccc_res res;
+
+	debug("run in reset cpu\n");
+	arm_smccc_smc(0x84000009, 0, 0, 0, 0, 0, 0, 0, &res);
+	if (res.a0 != 0)
+		panic("reset cpu error, %lx\n", res.a0);
+}
+
+int mach_cpu_init(void)
+{
+	check_reset();
+	return 0;
+}
+
+int board_early_init_f(void)
+{
+	pcie_init();
+	return 0;
+}
+
+static struct mm_region pomelo_mem_map[] = {
+	{
+		.virt = 0x0UL,
+		.phys = 0x0UL,
+		.size = 0x80000000UL,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+				 PTE_BLOCK_NON_SHARE |
+				 PTE_BLOCK_PXN |
+				 PTE_BLOCK_UXN
+	},
+	{
+		.virt = 0x80000000UL,
+		.phys = 0x80000000UL,
+		.size = 0x7b000000UL,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
+				 PTE_BLOCK_NS |
+				 PTE_BLOCK_INNER_SHARE
+	},
+	{
+		0,
+	}
+};
+
+struct mm_region *mem_map = pomelo_mem_map;
+
+int __asm_flush_l3_dcache(void)
+{
+	int i, pstate;
+
+	for (i = 0; i < HNF_COUNT; i++)
+		writeq(HNF_PSTATE_SFONLY, HNF_PSTATE_REQ + i * HNF_STRIDE);
+	for (i = 0; i < HNF_COUNT; i++) {
+		do {
+			pstate = readq(HNF_PSTATE_STAT + i * HNF_STRIDE);
+		} while ((pstate & 0xf) != (HNF_PSTATE_SFONLY << 2));
+	}
+
+	for (i = 0; i < HNF_COUNT; i++)
+		writeq(HNF_PSTATE_FULL, HNF_PSTATE_REQ + i * HNF_STRIDE);
+
+	return 0;
+}
+
+int last_stage_init(void)
+{
+	int ret;
+
+	/* pci e */
+	pci_init();
+	/* scsi scan */
+	ret = scsi_scan(true);
+	if (ret) {
+		printf("scsi scan failed\n");
+		return CMD_RET_FAILURE;
+	}
+	return ret;
+}
diff --git a/board/phytium/pomelo/sec.c b/board/phytium/pomelo/sec.c
new file mode 100644
index 0000000..aeb3983f
--- /dev/null
+++ b/board/phytium/pomelo/sec.c
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2021
+ * lixinde         <lixinde@phytium.com.cn>
+ * weichangzheng   <weichangzheng@phytium.com.cn>
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <linux/arm-smccc.h>
+#include <init.h>
+#include "cpu.h"
+
+struct common_config {
+	u32 magic;
+	u32 version;
+	u32 size;
+	u8 rev1[4];
+	u64  core_bit_map;
+} __attribute((aligned(4)));
+
+struct common_config const common_base_info = {
+	.magic = PARAMETER_COMMON_MAGIC,
+	.version = 0x1,
+	.core_bit_map = 0x3333,
+};
+
+void sec_init(void)
+{
+	u8 buffer[0x100];
+	struct arm_smccc_res res;
+
+	memcpy(buffer, &common_base_info, sizeof(common_base_info));
+	arm_smccc_smc(CPU_INIT_SEC_SVC, 0, (u64)buffer, 0, 0, 0, 0, 0, &res);
+	if (res.a0 != 0)
+		panic("SEC init failed :0x%lx\n", res.a0);
+}