mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-18 02:38:56 +00:00
a609353e82
Unless you have a spare Apple Silicon machine, getting access to the serial port on Apple Silicon machines requires special hardware. Given that most machines come with a built-in screen the framebuffer is likely to be the most convenient output device for most users. While U-Boot will output to both serial and framebuffer, OSes might not. Therefore set stdout-path to point at /chosen/framebuffer when a keyboard is connected to the machine. This behaviour can be overridden by setting the "stdout" variable in the U-Boot environment. I addition to that keep the serial console as the default when running under the m1n1 hypervisor. The m1n1 hypervisor virtualizes the serial port such that it can be easily accessed from any other machine with a USB port. Signed-off-by: Mark Kettenis <kettenis@openbsd.org> Reviewed-by: Janne Grunau <j@jannau.net> Tested-by: Janne Grunau <j@jannau.net>
503 lines
11 KiB
C
503 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 */
|
|
|
|
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"))
|
|
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;
|
|
}
|