arm: apple: Add initial support for Apple's M1 SoC

Add support for Apple's M1 SoC that is used in "Apple Silicon"
Macs.  This builds a basic U-Boot that can be used as a payload
for the m1n1 boot loader being developed by the Asahi Linux
project.

Signed-off-by: Mark Kettenis <kettenis@openbsd.org>
Reviewed-by: Simon Glass <sjg@chromium.org>
[trini: Add MAINTAINERS entry]
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 86c1ebd..48188aa 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -920,6 +920,25 @@
 	select DM
 	select GPIO_EXTRA_HEADER
 
+config ARCH_APPLE
+	bool "Apple SoCs"
+	select ARM64
+	select BLK
+	select CMD_USB
+	select DM
+	select DM_KEYBOARD
+	select DM_SERIAL
+	select DM_USB
+	select DM_VIDEO
+	select LINUX_KERNEL_IMAGE_HEADER
+	select OF_CONTROL
+	select OF_BOARD
+	select POSITION_INDEPENDENT
+	select USB
+	imply CMD_DM
+	imply CMD_GPT
+	imply DISTRO_DEFAULTS
+
 config ARCH_OWL
 	bool "Actions Semi OWL SoCs"
 	select DM
@@ -2016,6 +2035,8 @@
 	  image headers.
 endif
 
+source "arch/arm/mach-apple/Kconfig"
+
 source "arch/arm/mach-aspeed/Kconfig"
 
 source "arch/arm/mach-at91/Kconfig"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 6c9a00c..ad757e9 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -55,6 +55,7 @@
 
 # Machine directory name.  This list is sorted alphanumerically
 # by CONFIG_* macro name.
+machine-$(CONFIG_ARCH_APPLE)		+= apple
 machine-$(CONFIG_ARCH_ASPEED)		+= aspeed
 machine-$(CONFIG_ARCH_AT91)		+= at91
 machine-$(CONFIG_ARCH_BCM283X)		+= bcm283x
diff --git a/arch/arm/mach-apple/Kconfig b/arch/arm/mach-apple/Kconfig
new file mode 100644
index 0000000..66cab91
--- /dev/null
+++ b/arch/arm/mach-apple/Kconfig
@@ -0,0 +1,18 @@
+if ARCH_APPLE
+
+config SYS_TEXT_BASE
+	default 0x00000000
+
+config SYS_CONFIG_NAME
+	default "apple"
+
+config SYS_SOC
+	default "m1"
+
+config SYS_MALLOC_LEN
+	default 0x4000000
+
+config SYS_MALLOC_F_LEN
+	default 0x4000
+
+endif
diff --git a/arch/arm/mach-apple/Makefile b/arch/arm/mach-apple/Makefile
new file mode 100644
index 0000000..e74a8c9
--- /dev/null
+++ b/arch/arm/mach-apple/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+obj-y += board.o
+obj-y += lowlevel_init.o
diff --git a/arch/arm/mach-apple/board.c b/arch/arm/mach-apple/board.c
new file mode 100644
index 0000000..0bfbc47
--- /dev/null
+++ b/arch/arm/mach-apple/board.c
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2021 Mark Kettenis <kettenis@openbsd.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <efi_loader.h>
+
+#include <asm/armv8/mmu.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct mm_region apple_mem_map[] = {
+	{
+		/* I/O */
+		.virt = 0x200000000,
+		.phys = 0x200000000,
+		.size = 8UL * SZ_1G,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+			 PTE_BLOCK_NON_SHARE |
+			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		/* I/O */
+		.virt = 0x500000000,
+		.phys = 0x500000000,
+		.size = 2UL * SZ_1G,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+			 PTE_BLOCK_NON_SHARE |
+			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		/* I/O */
+		.virt = 0x680000000,
+		.phys = 0x680000000,
+		.size = SZ_512M,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+			 PTE_BLOCK_NON_SHARE |
+			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		/* PCIE */
+		.virt = 0x6a0000000,
+		.phys = 0x6a0000000,
+		.size = SZ_512M,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRE) |
+			 PTE_BLOCK_INNER_SHARE |
+			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		/* PCIE */
+		.virt = 0x6c0000000,
+		.phys = 0x6c0000000,
+		.size = SZ_1G,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRE) |
+			 PTE_BLOCK_INNER_SHARE |
+			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		/* RAM */
+		.virt = 0x800000000,
+		.phys = 0x800000000,
+		.size = 8UL * SZ_1G,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
+			 PTE_BLOCK_INNER_SHARE
+	}, {
+		/* Empty entry for framebuffer */
+		0,
+	}, {
+		/* List terminator */
+		0,
+	}
+};
+
+struct mm_region *mem_map = apple_mem_map;
+
+int board_init(void)
+{
+	return 0;
+}
+
+int dram_init(void)
+{
+	ofnode node;
+	int index, ret;
+	fdt_addr_t base;
+	fdt_size_t size;
+
+	ret = fdtdec_setup_mem_size_base();
+	if (ret)
+		return ret;
+
+	/* Update RAM mapping */
+	index = ARRAY_SIZE(apple_mem_map) - 3;
+	apple_mem_map[index].virt = gd->ram_base;
+	apple_mem_map[index].phys = gd->ram_base;
+	apple_mem_map[index].size = gd->ram_size;
+
+	node = ofnode_path("/chosen/framebuffer");
+	if (!ofnode_valid(node))
+		return 0;
+
+	base = ofnode_get_addr_size(node, "reg", &size);
+	if (base == FDT_ADDR_T_NONE)
+		return 0;
+
+	/* Add framebuffer mapping */
+	index = ARRAY_SIZE(apple_mem_map) - 2;
+	apple_mem_map[index].virt = base;
+	apple_mem_map[index].phys = base;
+	apple_mem_map[index].size = size;
+	apple_mem_map[index].attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL_NC) |
+		PTE_BLOCK_INNER_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN;
+
+	return 0;
+}
+
+int dram_init_banksize(void)
+{
+	return fdtdec_setup_memory_banksize();
+}
+
+#define APPLE_WDT_BASE		0x23d2b0000ULL
+
+#define APPLE_WDT_SYS_CTL_ENABLE	BIT(2)
+
+typedef struct apple_wdt {
+	u32	reserved0[3];
+	u32	chip_ctl;
+	u32	sys_tmr;
+	u32	sys_cmp;
+	u32	reserved1;
+	u32	sys_ctl;
+} apple_wdt_t;
+
+void reset_cpu(void)
+{
+	apple_wdt_t *wdt = (apple_wdt_t *)APPLE_WDT_BASE;
+
+	writel(0, &wdt->sys_cmp);
+	writel(APPLE_WDT_SYS_CTL_ENABLE, &wdt->sys_ctl);
+
+	while(1)
+		wfi();
+}
+
+extern long fw_dtb_pointer;
+
+void *board_fdt_blob_setup(int *err)
+{
+	/* Return DTB pointer passed by m1n1 */
+	*err = 0;
+	return (void *)fw_dtb_pointer;
+}
+
+ulong board_get_usable_ram_top(ulong total_size)
+{
+	/*
+	 * Top part of RAM is used by firmware for things like the
+	 * framebuffer.  This gives us plenty of room to play with.
+	 */
+	return 0x980000000;
+}
diff --git a/arch/arm/mach-apple/lowlevel_init.S b/arch/arm/mach-apple/lowlevel_init.S
new file mode 100644
index 0000000..e1c0d91
--- /dev/null
+++ b/arch/arm/mach-apple/lowlevel_init.S
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2021 Mark Kettenis <kettenis@openbsd.org>
+ */
+
+.align 8
+.global fw_dtb_pointer
+fw_dtb_pointer:
+	.quad	0
+
+.global save_boot_params
+save_boot_params:
+	/* Stash DTB pointer passed by m1n1 */
+	adr	x1, fw_dtb_pointer
+	str	x0, [x1]
+
+	b	save_boot_params_ret