diff options
Diffstat (limited to 'arch/arm/mach-apple')
-rw-r--r-- | arch/arm/mach-apple/Kconfig | 2 | ||||
-rw-r--r-- | arch/arm/mach-apple/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-apple/board.c | 234 | ||||
-rw-r--r-- | arch/arm/mach-apple/rtkit.c | 231 |
4 files changed, 431 insertions, 37 deletions
diff --git a/arch/arm/mach-apple/Kconfig b/arch/arm/mach-apple/Kconfig index 80e8eb23079..75ee21e0f4c 100644 --- a/arch/arm/mach-apple/Kconfig +++ b/arch/arm/mach-apple/Kconfig @@ -7,7 +7,7 @@ config SYS_CONFIG_NAME default "apple" config SYS_SOC - default "m1" + default "apple" config SYS_MALLOC_LEN default 0x4000000 diff --git a/arch/arm/mach-apple/Makefile b/arch/arm/mach-apple/Makefile index e74a8c9df10..52f30a777b2 100644 --- a/arch/arm/mach-apple/Makefile +++ b/arch/arm/mach-apple/Makefile @@ -2,3 +2,4 @@ obj-y += board.o obj-y += lowlevel_init.o +obj-y += rtkit.o diff --git a/arch/arm/mach-apple/board.c b/arch/arm/mach-apple/board.c index b7e8d212f1a..54005f3adf0 100644 --- a/arch/arm/mach-apple/board.c +++ b/arch/arm/mach-apple/board.c @@ -14,12 +14,22 @@ DECLARE_GLOBAL_DATA_PTR; -static struct mm_region apple_mem_map[] = { +/* Apple M1 */ + +static struct mm_region t8103_mem_map[] = { { /* I/O */ .virt = 0x200000000, .phys = 0x200000000, - .size = 8UL * SZ_1G, + .size = 2UL * SZ_1G, + .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | + PTE_BLOCK_NON_SHARE | + PTE_BLOCK_PXN | PTE_BLOCK_UXN + }, { + /* I/O */ + .virt = 0x380000000, + .phys = 0x380000000, + .size = SZ_1G, .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN @@ -27,7 +37,7 @@ static struct mm_region apple_mem_map[] = { /* I/O */ .virt = 0x500000000, .phys = 0x500000000, - .size = 2UL * SZ_1G, + .size = SZ_1G, .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN @@ -63,15 +73,110 @@ static struct mm_region apple_mem_map[] = { .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | PTE_BLOCK_INNER_SHARE }, { - /* Empty entry for framebuffer */ + /* Framebuffer */ + .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL_NC) | + PTE_BLOCK_INNER_SHARE | + PTE_BLOCK_PXN | PTE_BLOCK_UXN + }, { + /* List terminator */ 0, + } +}; + +/* Apple M1 Pro/Max */ + +static struct mm_region t6000_mem_map[] = { + { + /* I/O */ + .virt = 0x280000000, + .phys = 0x280000000, + .size = SZ_1G, + .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | + PTE_BLOCK_NON_SHARE | + PTE_BLOCK_PXN | PTE_BLOCK_UXN + }, { + /* I/O */ + .virt = 0x380000000, + .phys = 0x380000000, + .size = SZ_1G, + .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | + PTE_BLOCK_NON_SHARE | + PTE_BLOCK_PXN | PTE_BLOCK_UXN + }, { + /* I/O */ + .virt = 0x580000000, + .phys = 0x580000000, + .size = SZ_512M, + .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | + PTE_BLOCK_NON_SHARE | + PTE_BLOCK_PXN | PTE_BLOCK_UXN + }, { + /* PCIE */ + .virt = 0x5a0000000, + .phys = 0x5a0000000, + .size = SZ_512M, + .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRE) | + PTE_BLOCK_INNER_SHARE | + PTE_BLOCK_PXN | PTE_BLOCK_UXN + }, { + /* PCIE */ + .virt = 0x5c0000000, + .phys = 0x5c0000000, + .size = SZ_1G, + .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRE) | + PTE_BLOCK_INNER_SHARE | + PTE_BLOCK_PXN | PTE_BLOCK_UXN + }, { + /* I/O */ + .virt = 0x700000000, + .phys = 0x700000000, + .size = SZ_1G, + .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | + PTE_BLOCK_NON_SHARE | + PTE_BLOCK_PXN | PTE_BLOCK_UXN + }, { + /* I/O */ + .virt = 0xb00000000, + .phys = 0xb00000000, + .size = SZ_1G, + .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | + PTE_BLOCK_NON_SHARE | + PTE_BLOCK_PXN | PTE_BLOCK_UXN + }, { + /* I/O */ + .virt = 0xf00000000, + .phys = 0xf00000000, + .size = SZ_1G, + .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | + PTE_BLOCK_NON_SHARE | + PTE_BLOCK_PXN | PTE_BLOCK_UXN + }, { + /* I/O */ + .virt = 0x1300000000, + .phys = 0x1300000000, + .size = SZ_1G, + .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | + PTE_BLOCK_NON_SHARE | + PTE_BLOCK_PXN | PTE_BLOCK_UXN + }, { + /* RAM */ + .virt = 0x10000000000, + .phys = 0x10000000000, + .size = 16UL * SZ_1G, + .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | + PTE_BLOCK_INNER_SHARE + }, { + /* Framebuffer */ + .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL_NC) | + PTE_BLOCK_INNER_SHARE | + PTE_BLOCK_PXN | PTE_BLOCK_UXN }, { /* List terminator */ 0, } }; -struct mm_region *mem_map = apple_mem_map; +struct mm_region *mem_map; int board_init(void) { @@ -80,59 +185,116 @@ int board_init(void) int dram_init(void) { + return fdtdec_setup_mem_size_base(); +} + +int dram_init_banksize(void) +{ + return fdtdec_setup_memory_banksize(); +} + +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; +} + +void build_mem_map(void) +{ ofnode node; - int index, ret; fdt_addr_t base; fdt_size_t size; + int i; + + if (of_machine_is_compatible("apple,t8103")) + mem_map = t8103_mem_map; + else if (of_machine_is_compatible("apple,t6000")) + mem_map = t6000_mem_map; + else if (of_machine_is_compatible("apple,t6001")) + mem_map = t6000_mem_map; + else + panic("Unsupported SoC\n"); - ret = fdtdec_setup_mem_size_base(); - if (ret) - return ret; + /* Find list terminator. */ + for (i = 0; mem_map[i].size || mem_map[i].attrs; i++) + ; + + /* Align RAM mapping to page boundaries */ + base = gd->bd->bi_dram[0].start; + size = gd->bd->bi_dram[0].size; + size += (base - ALIGN_DOWN(base, SZ_4K)); + base = ALIGN_DOWN(base, SZ_4K); + size = ALIGN(size, SZ_4K); /* 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; + mem_map[i - 2].virt = base; + mem_map[i - 2].phys = base; + mem_map[i - 2].size = size; node = ofnode_path("/chosen/framebuffer"); if (!ofnode_valid(node)) - return 0; + return; base = ofnode_get_addr_size(node, "reg", &size); if (base == FDT_ADDR_T_NONE) - return 0; + return; - /* 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; + /* Align framebuffer mapping to page boundaries */ + size += (base - ALIGN_DOWN(base, SZ_4K)); + base = ALIGN_DOWN(base, SZ_4K); + size = ALIGN(size, SZ_4K); - return 0; + /* Add framebuffer mapping */ + mem_map[i - 1].virt = base; + mem_map[i - 1].phys = base; + mem_map[i - 1].size = size; } -int dram_init_banksize(void) +void enable_caches(void) { - return fdtdec_setup_memory_banksize(); -} + build_mem_map(); -extern long fw_dtb_pointer; + icache_enable(); + dcache_enable(); +} -void *board_fdt_blob_setup(int *err) +u64 get_page_table_size(void) { - /* Return DTB pointer passed by m1n1 */ - *err = 0; - return (void *)fw_dtb_pointer; + return SZ_256K; } -ulong board_get_usable_ram_top(ulong total_size) +int board_late_init(void) { - /* - * Top part of RAM is used by firmware for things like the - * framebuffer. This gives us plenty of room to play with. + unsigned long base; + unsigned long top; + u32 status = 0; + + /* Reserve 4M each for scriptaddr and pxefile_addr_r at the top of RAM + * at least 1M below the stack. */ - return 0x980000000; + top = gd->start_addr_sp - CONFIG_STACK_SIZE - SZ_8M - SZ_1M; + top = ALIGN_DOWN(top, SZ_8M); + + status |= env_set_hex("scriptaddr", top + SZ_4M); + status |= env_set_hex("pxefile_addr_r", top); + + /* somewhat based on the Linux Kernel boot requirements: + * align by 2M and maximal FDT size 2M + */ + base = ALIGN(gd->ram_base, SZ_2M); + + status |= env_set_hex("fdt_addr_r", base); + status |= env_set_hex("kernel_addr_r", base + SZ_2M); + status |= env_set_hex("ramdisk_addr_r", base + SZ_128M); + status |= env_set_hex("loadaddr", base + SZ_2G); + status |= env_set_hex("kernel_comp_addr_r", base + SZ_2G - SZ_128M); + status |= env_set_hex("kernel_comp_size", SZ_128M); + + if (status) + log_warning("late_init: Failed to set run time variables\n"); + + return 0; } diff --git a/arch/arm/mach-apple/rtkit.c b/arch/arm/mach-apple/rtkit.c new file mode 100644 index 00000000000..dff475cab7d --- /dev/null +++ b/arch/arm/mach-apple/rtkit.c @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2021 Mark Kettenis <kettenis@openbsd.org> + * (C) Copyright 2021 Copyright The Asahi Linux Contributors + */ + +#include <common.h> +#include <mailbox.h> +#include <malloc.h> + +#include <asm/arch/rtkit.h> +#include <linux/apple-mailbox.h> +#include <linux/bitfield.h> + +#define APPLE_RTKIT_EP_MGMT 0 +#define APPLE_RTKIT_EP_CRASHLOG 1 +#define APPLE_RTKIT_EP_SYSLOG 2 +#define APPLE_RTKIT_EP_DEBUG 3 +#define APPLE_RTKIT_EP_IOREPORT 4 + +/* Messages for management endpoint. */ +#define APPLE_RTKIT_MGMT_TYPE GENMASK(59, 52) + +#define APPLE_RTKIT_MGMT_PWR_STATE GENMASK(15, 0) + +#define APPLE_RTKIT_MGMT_HELLO 1 +#define APPLE_RTKIT_MGMT_HELLO_REPLY 2 +#define APPLE_RTKIT_MGMT_HELLO_MINVER GENMASK(15, 0) +#define APPLE_RTKIT_MGMT_HELLO_MAXVER GENMASK(31, 16) + +#define APPLE_RTKIT_MGMT_STARTEP 5 +#define APPLE_RTKIT_MGMT_STARTEP_EP GENMASK(39, 32) +#define APPLE_RTKIT_MGMT_STARTEP_FLAG BIT(1) + +#define APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE 6 +#define APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE_ACK 7 + +#define APPLE_RTKIT_MGMT_EPMAP 8 +#define APPLE_RTKIT_MGMT_EPMAP_LAST BIT(51) +#define APPLE_RTKIT_MGMT_EPMAP_BASE GENMASK(34, 32) +#define APPLE_RTKIT_MGMT_EPMAP_BITMAP GENMASK(31, 0) + +#define APPLE_RTKIT_MGMT_EPMAP_REPLY 8 +#define APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE BIT(0) + +#define APPLE_RTKIT_MIN_SUPPORTED_VERSION 11 +#define APPLE_RTKIT_MAX_SUPPORTED_VERSION 12 + +/* Messages for internal endpoints. */ +#define APPLE_RTKIT_BUFFER_REQUEST 1 +#define APPLE_RTKIT_BUFFER_REQUEST_SIZE GENMASK(51, 44) +#define APPLE_RTKIT_BUFFER_REQUEST_IOVA GENMASK(41, 0) + +int apple_rtkit_init(struct mbox_chan *chan) +{ + struct apple_mbox_msg msg; + int endpoints[256]; + int nendpoints = 0; + int endpoint; + int min_ver, max_ver, want_ver; + int msgtype, pwrstate; + u64 reply; + u32 bitmap, base; + int i, ret; + + /* Wakup the IOP. */ + msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE) | + FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, APPLE_RTKIT_PWR_STATE_ON); + msg.msg1 = APPLE_RTKIT_EP_MGMT; + ret = mbox_send(chan, &msg); + if (ret < 0) + return ret; + + /* Wait for protocol version negotiation message. */ + ret = mbox_recv(chan, &msg, 10000); + if (ret < 0) + return ret; + + endpoint = msg.msg1; + msgtype = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg.msg0); + if (endpoint != APPLE_RTKIT_EP_MGMT) { + printf("%s: unexpected endpoint %d\n", __func__, endpoint); + return -EINVAL; + } + if (msgtype != APPLE_RTKIT_MGMT_HELLO) { + printf("%s: unexpected message type %d\n", __func__, msgtype); + return -EINVAL; + } + + min_ver = FIELD_GET(APPLE_RTKIT_MGMT_HELLO_MINVER, msg.msg0); + max_ver = FIELD_GET(APPLE_RTKIT_MGMT_HELLO_MAXVER, msg.msg0); + want_ver = min(APPLE_RTKIT_MAX_SUPPORTED_VERSION, max_ver); + + if (min_ver > APPLE_RTKIT_MAX_SUPPORTED_VERSION) { + printf("%s: firmware min version %d is too new\n", + __func__, min_ver); + return -ENOTSUPP; + } + + if (max_ver < APPLE_RTKIT_MIN_SUPPORTED_VERSION) { + printf("%s: firmware max version %d is too old\n", + __func__, max_ver); + return -ENOTSUPP; + } + + /* Ack version. */ + msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_HELLO_REPLY) | + FIELD_PREP(APPLE_RTKIT_MGMT_HELLO_MINVER, want_ver) | + FIELD_PREP(APPLE_RTKIT_MGMT_HELLO_MAXVER, want_ver); + msg.msg1 = APPLE_RTKIT_EP_MGMT; + ret = mbox_send(chan, &msg); + if (ret < 0) + return ret; + +wait_epmap: + /* Wait for endpoint map message. */ + ret = mbox_recv(chan, &msg, 10000); + if (ret < 0) + return ret; + + endpoint = msg.msg1; + msgtype = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg.msg0); + if (endpoint != APPLE_RTKIT_EP_MGMT) { + printf("%s: unexpected endpoint %d\n", __func__, endpoint); + return -EINVAL; + } + if (msgtype != APPLE_RTKIT_MGMT_EPMAP) { + printf("%s: unexpected message type %d\n", __func__, msgtype); + return -EINVAL; + } + + bitmap = FIELD_GET(APPLE_RTKIT_MGMT_EPMAP_BITMAP, msg.msg0); + base = FIELD_GET(APPLE_RTKIT_MGMT_EPMAP_BASE, msg.msg0); + for (i = 0; i < 32; i++) { + if (bitmap & (1U << i)) + endpoints[nendpoints++] = base * 32 + i; + } + + /* Ack endpoint map. */ + reply = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_EPMAP_REPLY) | + FIELD_PREP(APPLE_RTKIT_MGMT_EPMAP_BASE, base); + if (msg.msg0 & APPLE_RTKIT_MGMT_EPMAP_LAST) + reply |= APPLE_RTKIT_MGMT_EPMAP_LAST; + else + reply |= APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE; + msg.msg0 = reply; + msg.msg1 = APPLE_RTKIT_EP_MGMT; + ret = mbox_send(chan, &msg); + if (ret < 0) + return ret; + + if (reply & APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE) + goto wait_epmap; + + for (i = 0; i < nendpoints; i++) { + /* Don't start the syslog endpoint since we can't + easily handle its messages in U-Boot. */ + if (endpoints[i] == APPLE_RTKIT_EP_SYSLOG) + continue; + + /* Request endpoint. */ + msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_STARTEP) | + FIELD_PREP(APPLE_RTKIT_MGMT_STARTEP_EP, endpoints[i]) | + APPLE_RTKIT_MGMT_STARTEP_FLAG; + msg.msg1 = APPLE_RTKIT_EP_MGMT; + ret = mbox_send(chan, &msg); + if (ret < 0) + return ret; + } + + pwrstate = APPLE_RTKIT_PWR_STATE_SLEEP; + while (pwrstate != APPLE_RTKIT_PWR_STATE_ON) { + ret = mbox_recv(chan, &msg, 100000); + if (ret < 0) + return ret; + + endpoint = msg.msg1; + msgtype = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg.msg0); + + if (endpoint == APPLE_RTKIT_EP_CRASHLOG || + endpoint == APPLE_RTKIT_EP_SYSLOG || + endpoint == APPLE_RTKIT_EP_IOREPORT) { + u64 addr = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_IOVA, msg.msg0); + u64 size = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_SIZE, msg.msg0); + + if (msgtype == APPLE_RTKIT_BUFFER_REQUEST && addr != 0) + continue; + + msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_BUFFER_REQUEST) | + FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_SIZE, size) | + FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_IOVA, addr); + msg.msg1 = endpoint; + ret = mbox_send(chan, &msg); + if (ret < 0) + return ret; + continue; + } + + if (endpoint != APPLE_RTKIT_EP_MGMT) { + printf("%s: unexpected endpoint %d\n", __func__, endpoint); + return -EINVAL; + } + if (msgtype != APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE_ACK) { + printf("%s: unexpected message type %d\n", __func__, msgtype); + return -EINVAL; + } + + pwrstate = FIELD_GET(APPLE_RTKIT_MGMT_PWR_STATE, msg.msg0); + } + + return 0; +} + +int apple_rtkit_shutdown(struct mbox_chan *chan, int pwrstate) +{ + struct apple_mbox_msg msg; + int ret; + + msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE) | + FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, pwrstate); + msg.msg1 = APPLE_RTKIT_EP_MGMT; + ret = mbox_send(chan, &msg); + if (ret < 0) + return ret; + + ret = mbox_recv(chan, &msg, 100000); + if (ret < 0) + return ret; + + return 0; +} |