mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-17 10:18:38 +00:00
e53237aa53
Apple's M2 SoC very similar to the M1 and can use the same memory map. The keyboard/trackpad on the MacBook Pro (13-inch, M2, 2022) uses "dockchannel" as transport instead of SPI and needs a new driver. USB, NVMe, uart, framebuffer and watchdog are working with the existing drivers. Signed-off-by: Janne Grunau <j@jannau.net> Reviewed-by: Mark Kettenis <kettenis@openbsd.org>
504 lines
11 KiB
C
504 lines
11 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* (C) Copyright 2021 Mark Kettenis <kettenis@openbsd.org>
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <dm.h>
|
|
#include <dm/uclass-internal.h>
|
|
#include <efi_loader.h>
|
|
#include <lmb.h>
|
|
|
|
#include <asm/armv8/mmu.h>
|
|
#include <asm/global_data.h>
|
|
#include <asm/io.h>
|
|
#include <asm/system.h>
|
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
/* Apple M1/M2 */
|
|
|
|
static struct mm_region t8103_mem_map[] = {
|
|
{
|
|
/* I/O */
|
|
.virt = 0x200000000,
|
|
.phys = 0x200000000,
|
|
.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
|
|
}, {
|
|
/* I/O */
|
|
.virt = 0x500000000,
|
|
.phys = 0x500000000,
|
|
.size = 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
|
|
}, {
|
|
/* 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,
|
|
}
|
|
};
|
|
|
|
/* Apple M1 Ultra */
|
|
|
|
static struct mm_region t6002_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
|
|
}, {
|
|
/* I/O */
|
|
.virt = 0x2280000000,
|
|
.phys = 0x2280000000,
|
|
.size = SZ_1G,
|
|
.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
|
|
PTE_BLOCK_NON_SHARE |
|
|
PTE_BLOCK_PXN | PTE_BLOCK_UXN
|
|
}, {
|
|
/* I/O */
|
|
.virt = 0x2380000000,
|
|
.phys = 0x2380000000,
|
|
.size = SZ_1G,
|
|
.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
|
|
PTE_BLOCK_NON_SHARE |
|
|
PTE_BLOCK_PXN | PTE_BLOCK_UXN
|
|
}, {
|
|
/* I/O */
|
|
.virt = 0x2580000000,
|
|
.phys = 0x2580000000,
|
|
.size = SZ_512M,
|
|
.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
|
|
PTE_BLOCK_NON_SHARE |
|
|
PTE_BLOCK_PXN | PTE_BLOCK_UXN
|
|
}, {
|
|
/* PCIE */
|
|
.virt = 0x25a0000000,
|
|
.phys = 0x25a0000000,
|
|
.size = SZ_512M,
|
|
.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRE) |
|
|
PTE_BLOCK_INNER_SHARE |
|
|
PTE_BLOCK_PXN | PTE_BLOCK_UXN
|
|
}, {
|
|
/* PCIE */
|
|
.virt = 0x25c0000000,
|
|
.phys = 0x25c0000000,
|
|
.size = SZ_1G,
|
|
.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRE) |
|
|
PTE_BLOCK_INNER_SHARE |
|
|
PTE_BLOCK_PXN | PTE_BLOCK_UXN
|
|
}, {
|
|
/* I/O */
|
|
.virt = 0x2700000000,
|
|
.phys = 0x2700000000,
|
|
.size = SZ_1G,
|
|
.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
|
|
PTE_BLOCK_NON_SHARE |
|
|
PTE_BLOCK_PXN | PTE_BLOCK_UXN
|
|
}, {
|
|
/* I/O */
|
|
.virt = 0x2b00000000,
|
|
.phys = 0x2b00000000,
|
|
.size = SZ_1G,
|
|
.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
|
|
PTE_BLOCK_NON_SHARE |
|
|
PTE_BLOCK_PXN | PTE_BLOCK_UXN
|
|
}, {
|
|
/* I/O */
|
|
.virt = 0x2f00000000,
|
|
.phys = 0x2f00000000,
|
|
.size = SZ_1G,
|
|
.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
|
|
PTE_BLOCK_NON_SHARE |
|
|
PTE_BLOCK_PXN | PTE_BLOCK_UXN
|
|
}, {
|
|
/* I/O */
|
|
.virt = 0x3300000000,
|
|
.phys = 0x3300000000,
|
|
.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;
|
|
|
|
int board_init(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
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;
|
|
fdt_addr_t base;
|
|
fdt_size_t size;
|
|
int i;
|
|
|
|
if (of_machine_is_compatible("apple,t8103") ||
|
|
of_machine_is_compatible("apple,t8112"))
|
|
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 if (of_machine_is_compatible("apple,t6002"))
|
|
mem_map = t6002_mem_map;
|
|
else
|
|
panic("Unsupported SoC\n");
|
|
|
|
/* 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 */
|
|
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;
|
|
|
|
base = ofnode_get_addr_size(node, "reg", &size);
|
|
if (base == FDT_ADDR_T_NONE)
|
|
return;
|
|
|
|
/* Align framebuffer mapping to page boundaries */
|
|
size += (base - ALIGN_DOWN(base, SZ_4K));
|
|
base = ALIGN_DOWN(base, SZ_4K);
|
|
size = ALIGN(size, SZ_4K);
|
|
|
|
/* Add framebuffer mapping */
|
|
mem_map[i - 1].virt = base;
|
|
mem_map[i - 1].phys = base;
|
|
mem_map[i - 1].size = size;
|
|
}
|
|
|
|
void enable_caches(void)
|
|
{
|
|
build_mem_map();
|
|
|
|
icache_enable();
|
|
dcache_enable();
|
|
}
|
|
|
|
u64 get_page_table_size(void)
|
|
{
|
|
return SZ_256K;
|
|
}
|
|
|
|
#define KERNEL_COMP_SIZE SZ_128M
|
|
|
|
int board_late_init(void)
|
|
{
|
|
struct lmb lmb;
|
|
u32 status = 0;
|
|
|
|
lmb_init_and_reserve(&lmb, gd->bd, (void *)gd->fdt_blob);
|
|
|
|
/* somewhat based on the Linux Kernel boot requirements:
|
|
* align by 2M and maximal FDT size 2M
|
|
*/
|
|
status |= env_set_hex("loadaddr", lmb_alloc(&lmb, SZ_1G, SZ_2M));
|
|
status |= env_set_hex("fdt_addr_r", lmb_alloc(&lmb, SZ_2M, SZ_2M));
|
|
status |= env_set_hex("kernel_addr_r", lmb_alloc(&lmb, SZ_128M, SZ_2M));
|
|
status |= env_set_hex("ramdisk_addr_r", lmb_alloc(&lmb, SZ_1G, SZ_2M));
|
|
status |= env_set_hex("kernel_comp_addr_r",
|
|
lmb_alloc(&lmb, KERNEL_COMP_SIZE, SZ_2M));
|
|
status |= env_set_hex("kernel_comp_size", KERNEL_COMP_SIZE);
|
|
status |= env_set_hex("scriptaddr", lmb_alloc(&lmb, SZ_4M, SZ_2M));
|
|
status |= env_set_hex("pxefile_addr_r", lmb_alloc(&lmb, SZ_4M, SZ_2M));
|
|
|
|
if (status)
|
|
log_warning("late_init: Failed to set run time variables\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ft_board_setup(void *blob, struct bd_info *bd)
|
|
{
|
|
struct udevice *dev;
|
|
const char *stdoutname;
|
|
int node, ret;
|
|
|
|
/*
|
|
* Modify the "stdout-path" property under "/chosen" to point
|
|
* at "/chosen/framebuffer if a keyboard is available and
|
|
* we're not running under the m1n1 hypervisor.
|
|
* Developers can override this behaviour by dropping
|
|
* "vidconsole" from the "stdout" environment variable.
|
|
*/
|
|
|
|
/* EL1 means we're running under the m1n1 hypervisor. */
|
|
if (current_el() == 1)
|
|
return 0;
|
|
|
|
ret = uclass_find_device(UCLASS_KEYBOARD, 0, &dev);
|
|
if (ret < 0)
|
|
return 0;
|
|
|
|
stdoutname = env_get("stdout");
|
|
if (!stdoutname || !strstr(stdoutname, "vidconsole"))
|
|
return 0;
|
|
|
|
/* Make sure we actually have a framebuffer. */
|
|
node = fdt_path_offset(blob, "/chosen/framebuffer");
|
|
if (node < 0 || !fdtdec_get_is_enabled(blob, node))
|
|
return 0;
|
|
|
|
node = fdt_path_offset(blob, "/chosen");
|
|
if (node < 0)
|
|
return 0;
|
|
fdt_setprop_string(blob, node, "stdout-path", "/chosen/framebuffer");
|
|
|
|
return 0;
|
|
}
|