aspeed: Add AST2600 platform support

Add low level platform initialization for the AST2600 SoC.
The 2-stage booting with U-Boot SPL are leveraged to support
different booting mode.

However, currently the patch supports only the booting from
memory-mapped SPI flash.

Signed-off-by: Chia-Wei, Wang <chiawei_wang@aspeedtech.com>
Reviewed-by: Ryan Chen <ryan_chen@aspeedtech.com>
diff --git a/arch/arm/include/asm/arch-aspeed/boot0.h b/arch/arm/include/asm/arch-aspeed/boot0.h
new file mode 100644
index 0000000..368becc
--- /dev/null
+++ b/arch/arm/include/asm/arch-aspeed/boot0.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) Aspeed Technology Inc.
+ */
+
+#ifndef _ASM_ARCH_BOOT0_H
+#define _ASM_ARCH_BOOT0_H
+
+_start:
+	ARM_VECTORS
+
+	.word	0x0	/* key location */
+	.word	0x0	/* start address of image */
+	.word	0xfc00  /* maximum image size: 63KB */
+	.word	0x0	/* signature address */
+	.word	0x0	/* header revision ID low */
+	.word	0x0	/* header revision ID high */
+	.word	0x0	/* reserved */
+	.word	0x0	/* checksum */
+	.word	0x0	/* BL2 secure header */
+	.word	0x0	/* public key or digest offset for BL2 */
+
+#endif
diff --git a/arch/arm/include/asm/arch-aspeed/platform.h b/arch/arm/include/asm/arch-aspeed/platform.h
index 6cee036..d50ec5f 100644
--- a/arch/arm/include/asm/arch-aspeed/platform.h
+++ b/arch/arm/include/asm/arch-aspeed/platform.h
@@ -13,6 +13,11 @@
 #define ASPEED_DRAM_BASE	0x80000000
 #define ASPEED_SRAM_BASE	0x1e720000
 #define ASPEED_SRAM_SIZE	0x9000
+#elif defined(CONFIG_ASPEED_AST2600)
+#define ASPEED_MAC_COUNT	4
+#define ASPEED_DRAM_BASE	0x80000000
+#define ASPEED_SRAM_BASE	0x10000000
+#define ASPEED_SRAM_SIZE	0x10000
 #else
 #err "Unrecognized Aspeed platform."
 #endif
diff --git a/arch/arm/mach-aspeed/Kconfig b/arch/arm/mach-aspeed/Kconfig
index 4f021ba..9a725f1 100644
--- a/arch/arm/mach-aspeed/Kconfig
+++ b/arch/arm/mach-aspeed/Kconfig
@@ -9,6 +9,11 @@
 config SYS_TEXT_BASE
 	default 0x00000000
 
+choice
+	prompt "Aspeed SoC select"
+	depends on ARCH_ASPEED
+	default ASPEED_AST2500
+
 config ASPEED_AST2500
 	bool "Support Aspeed AST2500 SoC"
 	depends on DM_RESET
@@ -18,6 +23,21 @@
 	  It is used as Board Management Controller on many server boards,
 	  which is enabled by support of LPC and eSPI peripherals.
 
+config ASPEED_AST2600
+	bool "Support Aspeed AST2600 SoC"
+	select CPU_V7A
+	select CPU_V7_HAS_NONSEC
+	select SYS_ARCH_TIMER
+	select SUPPORT_SPL
+	select ENABLE_ARM_SOC_BOOT0_HOOK
+	help
+	  The Aspeed AST2600 is a ARM-based SoC with Cortex-A7 CPU.
+	  It is used as Board Management Controller on many server boards,
+	  which is enabled by support of LPC and eSPI peripherals.
+
+endchoice
+
 source "arch/arm/mach-aspeed/ast2500/Kconfig"
+source "arch/arm/mach-aspeed/ast2600/Kconfig"
 
 endif
diff --git a/arch/arm/mach-aspeed/Makefile b/arch/arm/mach-aspeed/Makefile
index 33f65b5..42599c1 100644
--- a/arch/arm/mach-aspeed/Makefile
+++ b/arch/arm/mach-aspeed/Makefile
@@ -4,3 +4,4 @@
 
 obj-$(CONFIG_ARCH_ASPEED) += ast_wdt.o
 obj-$(CONFIG_ASPEED_AST2500) += ast2500/
+obj-$(CONFIG_ASPEED_AST2600) += ast2600/
diff --git a/arch/arm/mach-aspeed/ast2600/Kconfig b/arch/arm/mach-aspeed/ast2600/Kconfig
new file mode 100644
index 0000000..f3a5338
--- /dev/null
+++ b/arch/arm/mach-aspeed/ast2600/Kconfig
@@ -0,0 +1,17 @@
+if ASPEED_AST2600
+
+config SYS_CPU
+	default "armv7"
+
+config TARGET_EVB_AST2600
+	bool "EVB-AST2600"
+	depends on ASPEED_AST2600
+	help
+	  EVB-AST2600 is Aspeed evaluation board for AST2600A0 chip.
+	  It has 512M of RAM, 32M of SPI flash, two Ethernet ports,
+	  4 Serial ports, 4 USB ports, VGA port, PCIe, SD card slot,
+	  20 pin JTAG, pinouts for 14 I2Cs, 3 SPIs and eSPI, 8 PWMs.
+
+source "board/aspeed/evb_ast2600/Kconfig"
+
+endif
diff --git a/arch/arm/mach-aspeed/ast2600/Makefile b/arch/arm/mach-aspeed/ast2600/Makefile
new file mode 100644
index 0000000..448d320
--- /dev/null
+++ b/arch/arm/mach-aspeed/ast2600/Makefile
@@ -0,0 +1,2 @@
+obj-y   += lowlevel_init.o board_common.o
+obj-$(CONFIG_SPL_BUILD) += spl.o
diff --git a/arch/arm/mach-aspeed/ast2600/board_common.c b/arch/arm/mach-aspeed/ast2600/board_common.c
new file mode 100644
index 0000000..a53e163
--- /dev/null
+++ b/arch/arm/mach-aspeed/ast2600/board_common.c
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) Aspeed Technology Inc.
+ */
+#include <common.h>
+#include <dm.h>
+#include <ram.h>
+#include <timer.h>
+#include <asm/io.h>
+#include <asm/arch/timer.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <dm/uclass.h>
+#include <asm/arch/scu_ast2600.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Memory Control registers */
+#define MCR_BASE			0x1e6e0000
+#define MCR_CONF			(MCR_BASE + 0x004)
+
+/* bit fields of MCR_CONF */
+#define MCR_CONF_ECC_EN			BIT(7)
+#define MCR_CONF_VGA_MEMSZ_MASK		GENMASK(3, 2)
+#define MCR_CONF_VGA_MEMSZ_SHIFT	2
+#define MCR_CONF_MEMSZ_MASK		GENMASK(1, 0)
+#define MCR_CONF_MEMSZ_SHIFT		0
+
+int dram_init(void)
+{
+	int ret;
+	struct udevice *dev;
+	struct ram_info ram;
+
+	ret = uclass_get_device(UCLASS_RAM, 0, &dev);
+	if (ret) {
+		debug("cannot get DRAM driver\n");
+		return ret;
+	}
+
+	ret = ram_get_info(dev, &ram);
+	if (ret) {
+		debug("cannot get DRAM information\n");
+		return ret;
+	}
+
+	gd->ram_size = ram.size;
+	return 0;
+}
+
+int board_init(void)
+{
+	int i = 0, rc;
+	struct udevice *dev;
+
+	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
+
+	while (1) {
+		rc = uclass_get_device(UCLASS_MISC, i++, &dev);
+		if (rc)
+			break;
+	}
+
+	return 0;
+}
+
+void board_add_ram_info(int use_default)
+{
+	int rc;
+	uint32_t conf;
+	uint32_t ecc, act_size, vga_rsvd;
+	struct udevice *scu_dev;
+	struct ast2600_scu *scu;
+
+	rc = uclass_get_device_by_driver(UCLASS_CLK,
+					 DM_DRIVER_GET(aspeed_ast2600_scu), &scu_dev);
+	if (rc) {
+		debug("%s: cannot find SCU device, rc=%d\n", __func__, rc);
+		return;
+	}
+
+	scu = devfdt_get_addr_ptr(scu_dev);
+	if (IS_ERR_OR_NULL(scu)) {
+		debug("%s: cannot get SCU address pointer\n", __func__);
+		return;
+	}
+
+	conf = readl(MCR_CONF);
+
+	ecc = conf & MCR_CONF_ECC_EN;
+	act_size = 0x100 << ((conf & MCR_CONF_MEMSZ_MASK) >> MCR_CONF_MEMSZ_SHIFT);
+	vga_rsvd = 0x8 << ((conf & MCR_CONF_VGA_MEMSZ_MASK) >> MCR_CONF_VGA_MEMSZ_SHIFT);
+
+	/* no VGA reservation if efuse VGA disable bit is set */
+	if (readl(scu->efuse) & SCU_EFUSE_DIS_VGA)
+		vga_rsvd = 0;
+
+	printf(" (capacity:%d MiB, VGA:%d MiB), ECC %s", act_size,
+	       vga_rsvd, (ecc) ? "on" : "off");
+}
+
+void enable_caches(void)
+{
+	/* get rid of the warning message */
+}
diff --git a/arch/arm/mach-aspeed/ast2600/lowlevel_init.S b/arch/arm/mach-aspeed/ast2600/lowlevel_init.S
new file mode 100644
index 0000000..594963d
--- /dev/null
+++ b/arch/arm/mach-aspeed/ast2600/lowlevel_init.S
@@ -0,0 +1,233 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) ASPEED Technology Inc.
+ */
+#include <config.h>
+#include <asm/armv7.h>
+#include <linux/linkage.h>
+#include <asm/arch/scu_ast2600.h>
+
+/* SCU register offsets */
+#define SCU_BASE		0x1e6e2000
+#define SCU_PROT_KEY1		(SCU_BASE + 0x000)
+#define SCU_PROT_KEY2		(SCU_BASE + 0x010)
+#define SCU_SMP_BOOT		(SCU_BASE + 0x180)
+#define SCU_HWSTRAP1		(SCU_BASE + 0x510)
+#define SCU_CA7_PARITY_CHK	(SCU_BASE + 0x820)
+#define SCU_CA7_PARITY_CLR	(SCU_BASE + 0x824)
+#define SCU_MMIO_DEC		(SCU_BASE + 0xc24)
+
+/* FMC SPI register offsets */
+#define FMC_BASE		0x1e620000
+#define FMC_CE0_CTRL		(FMC_BASE + 0x010)
+#define FMC_SW_RST_CTRL		(FMC_BASE + 0x050)
+#define FMC_WDT1_CTRL_MODE	(FMC_BASE + 0x060)
+#define FMC_WDT2_CTRL_MODE	(FMC_BASE + 0x064)
+
+/*
+ * The SMP mailbox provides a space with few instructions in it
+ * for secondary cores to execute on and wait for the signal of
+ * SMP core bring up.
+ *
+ *       SMP mailbox
+ * +----------------------+
+ * |                      |
+ * | mailbox insn. for    |
+ * | cpuN polling SMP go  |
+ * |                      |
+ * +----------------------+ 0xC
+ * | mailbox ready signal |
+ * +----------------------+ 0x8
+ * | cpuN GO signal       |
+ * +----------------------+ 0x4
+ * | cpuN entrypoint      |
+ * +----------------------+ SMP_MAILBOX_BASE
+ */
+#define SMP_MBOX_BASE		(SCU_SMP_BOOT)
+#define SMP_MBOX_FIELD_ENTRY	(SMP_MBOX_BASE + 0x0)
+#define SMP_MBOX_FIELD_GOSIGN	(SMP_MBOX_BASE + 0x4)
+#define SMP_MBOX_FIELD_READY	(SMP_MBOX_BASE + 0x8)
+#define SMP_MBOX_FIELD_POLLINSN	(SMP_MBOX_BASE + 0xc)
+
+.macro scu_unlock
+	movw	r0, #(SCU_UNLOCK_KEY & 0xffff)
+	movt	r0, #(SCU_UNLOCK_KEY >> 16)
+
+	ldr	r1, =SCU_PROT_KEY1
+	str	r0, [r1]
+	ldr	r1, =SCU_PROT_KEY2
+	str	r0, [r1]
+.endm
+
+.macro timer_init
+	ldr	r1, =SCU_HWSTRAP1
+	ldr	r1, [r1]
+	and	r1, #0x700
+	lsr	r1, #0x8
+
+	/* 1.2GHz */
+	cmp	r1, #0x0
+	movweq	r0, #0x8c00
+	movteq	r0, #0x4786
+
+	/* 1.6GHz */
+	cmp	r1, #0x1
+	movweq	r0, #0x1000
+	movteq	r0, #0x5f5e
+
+	/* 1.2GHz */
+	cmp	r1, #0x2
+	movweq	r0, #0x8c00
+	movteq	r0, #0x4786
+
+	/* 1.6GHz */
+	cmp	r1, #0x3
+	movweq	r0, #0x1000
+	movteq	r0, #0x5f5e
+
+	/* 800MHz */
+	cmp	r1, #0x4
+	movwge	r0, #0x0800
+	movtge	r0, #0x2faf
+
+	mcr	p15, 0, r0, c14, c0, 0	@; update CNTFRQ
+.endm
+
+
+.globl lowlevel_init
+
+lowlevel_init:
+#if defined(CONFIG_SPL) && !defined(CONFIG_SPL_BUILD)
+	mov	pc, lr
+#else
+	/* setup ARM arch timer frequency */
+	timer_init
+
+	/* reset SMP mailbox as early as possible */
+	mov	r0, #0x0
+	ldr	r1, =SMP_MBOX_FIELD_READY
+	str	r0, [r1]
+
+	/* set ACTLR.SMP to enable cache use */
+	mrc	p15, 0, r0, c1, c0, 1
+	orr	r0, #0x40
+	mcr	p15, 0, r0, c1, c0, 1
+
+	/*
+	 * we treat cpu0 as the primary core and
+	 * put secondary core (cpuN) to sleep
+	 */
+	mrc   p15, 0, r0, c0, c0, 5	@; Read CPU ID register
+	ands  r0, #0xff			@; Mask off, leaving the CPU ID field
+	movw  r2, #0xab00
+	movt  r2, #0xabba
+	orr   r2, r0
+
+	beq   do_primary_core_setup
+
+	/* hold cpuN until mailbox is ready */
+poll_mailbox_ready:
+	wfe
+	ldr	r0, =SMP_MBOX_FIELD_READY
+	ldr	r0, [r0]
+	movw	r1, #0xcafe
+	movt	r1, #0xbabe
+	cmp	r1, r0
+	bne	poll_mailbox_ready
+
+	/* parameters for relocated SMP go polling insn. */
+	ldr	r0, =SMP_MBOX_FIELD_GOSIGN
+	ldr	r1, =SMP_MBOX_FIELD_ENTRY
+
+	/* no return */
+	ldr	pc, =SMP_MBOX_FIELD_POLLINSN
+
+do_primary_core_setup:
+	scu_unlock
+
+	/* MMIO decode setting */
+	ldr	r0, =SCU_MMIO_DEC
+	mov	r1, #0x2000
+	str	r1, [r0]
+
+	/* enable CA7 cache parity check */
+	mov	r0, #0
+	ldr	r1, =SCU_CA7_PARITY_CLR
+	str	r0, [r1]
+
+	mov	r0, #0x1
+	ldr	r1, =SCU_CA7_PARITY_CHK
+	str	r0, [r1]
+
+	/* do not fill FMC50[1] if boot from eMMC */
+	ldr	r0, =SCU_HWSTRAP1
+	ldr	r1, [r0]
+	ands	r1, #0x04
+	bne	skip_fill_wip_bit
+
+	/* fill FMC50[1] for waiting WIP idle */
+	mov	r0, #0x02
+	ldr	r1, =FMC_SW_RST_CTRL
+	str	r0, [r1]
+
+skip_fill_wip_bit:
+	/* disable FMC WDT for SPI address mode detection */
+	mov	r0, #0
+	ldr	r1, =FMC_WDT1_CTRL_MODE
+	str	r0, [r1]
+
+	/* relocate mailbox insn. for cpuN polling SMP go signal */
+	adrl	r0, mailbox_insn
+	adrl	r1, mailbox_insn_end
+
+	ldr	r2, =#SMP_MBOX_FIELD_POLLINSN
+
+relocate_mailbox_insn:
+	ldr	r3, [r0], #0x4
+	str	r3, [r2], #0x4
+	cmp	r0, r1
+	bne	relocate_mailbox_insn
+
+	/* reset SMP go sign */
+	mov	r0, #0
+	ldr	r1, =SMP_MBOX_FIELD_GOSIGN
+	str	r0, [r1]
+
+	/* notify cpuN mailbox is ready */
+	movw	r0, #0xCAFE
+	movt	r0, #0xBABE
+	ldr	r1, =SMP_MBOX_FIELD_READY
+	str	r0, [r1]
+	sev
+
+	/* back to arch calling code */
+	mov	pc, lr
+
+/*
+ * insn. inside mailbox to poll SMP go signal.
+ *
+ * Note that as this code will be relocated, any
+ * pc-relative assembly should NOT be used.
+ */
+mailbox_insn:
+	/*
+	 * r0 ~ r3 are parameters:
+	 *  r0 = SMP_MBOX_FIELD_GOSIGN
+	 *  r1 = SMP_MBOX_FIELD_ENTRY
+	 *  r2 = per-cpu go sign value
+	 *  r3 = no used now
+	 */
+poll_mailbox_smp_go:
+	wfe
+	ldr	r4, [r0]
+	cmp	r2, r4
+	bne	poll_mailbox_smp_go
+
+	/* SMP GO signal confirmed, release cpuN */
+	ldr	pc, [r1]
+
+mailbox_insn_end:
+	/* should never reach */
+	b	.
+
+#endif
diff --git a/arch/arm/mach-aspeed/ast2600/spl.c b/arch/arm/mach-aspeed/ast2600/spl.c
new file mode 100644
index 0000000..9201d4a
--- /dev/null
+++ b/arch/arm/mach-aspeed/ast2600/spl.c
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) Aspeed Technology Inc.
+ */
+#include <common.h>
+#include <debug_uart.h>
+#include <dm.h>
+#include <spl.h>
+#include <init.h>
+#include <asm/io.h>
+#include <asm/arch/scu_ast2600.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void board_init_f(ulong dummy)
+{
+	spl_early_init();
+	preloader_console_init();
+	timer_init();
+	dram_init();
+}
+
+u32 spl_boot_device(void)
+{
+	return BOOT_DEVICE_RAM;
+}
+
+struct image_header *spl_get_load_buffer(ssize_t offset, size_t size)
+{
+	/*
+	 * When boot from SPI, AST2600 already remap 0x00000000 ~ 0x0fffffff
+	 * to BMC SPI memory space 0x20000000 ~ 0x2fffffff. The next stage BL
+	 * has been located in SPI for XIP. In this case, the load buffer for
+	 * SPL image loading will be set to the remapped address of the next
+	 * BL instead of the DRAM space CONFIG_SYS_LOAD_ADDR
+	 */
+	return (struct image_header *)(CONFIG_SYS_TEXT_BASE);
+}
+
+#ifdef CONFIG_SPL_OS_BOOT
+int spl_start_uboot(void)
+{
+	/* boot linux */
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_SPL_LOAD_FIT
+int board_fit_config_name_match(const char *name)
+{
+	/* just empty function now - can't decide what to choose */
+	debug("%s: %s\n", __func__, name);
+	return 0;
+}
+#endif