From b15be6bcd7dd15804579fe29552a28db41336895 Mon Sep 17 00:00:00 2001 From: Vincent Duvert Date: Sun, 31 Oct 2021 20:25:36 +0100 Subject: [PATCH] Remove hardcoded UART/WDT addresses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The M1 Pro/Max Macs use a different base address for the UART and the WDT than earlier models. Remove hardcoded base addresses constants and replace them with loads from the ADT. - The base address of the WDT is already retrieved in wdt_disable; also use this address when triggering a reboot. - Retrieve the base address of uart0 in uart_init. If the operation fails, the error will be signaled on the early uart (if not disabled). - The early debug UART can’t use the ADT (or shouldn’t) so it is now disabled by default. To enable it, add -DEARLY_UART -DEARLY_UART_BASE=0xuart_address to the CFLAGS. Signed-off-by: Vincent Duvert --- src/start.S | 23 ++++++++------------ src/startup.c | 22 ++++++++++--------- src/uart.c | 59 +++++++++++++++++++++++++++++++++++++++------------ src/uart.h | 2 +- src/wdt.c | 24 ++++++++++++++++----- src/wdt.h | 1 + 6 files changed, 87 insertions(+), 44 deletions(-) diff --git a/src/start.S b/src/start.S index 38503686..4891d1f3 100644 --- a/src/start.S +++ b/src/start.S @@ -1,14 +1,12 @@ /* SPDX-License-Identifier: MIT */ -#define UART_BASE 0x235200000 +#if defined(EARLY_UART) && !defined(EARLY_UART_BASE) +#error EARLY_UART_BASE must be defined to the UART base address +#endif + #define UTRSTAT 0x010 #define UTXH 0x020 -#define WDT_BASE 0x23d2b0000 -#define WDT_COUNT 0x10 -#define WDT_ALARM 0x14 -#define WDT_CTL 0x1c - .extern _start_c .extern _stack_bot .extern _v_sp0_sync @@ -17,6 +15,7 @@ .extern _v_sp0_serr .extern _reset_stack .extern _cpu_reset_c +.extern wdt_reboot .section .init, "ax" @@ -154,13 +153,15 @@ cpu_reset: .globl debug_putc .type debug_putc, @function debug_putc: - ldr x1, =UART_BASE +#ifdef EARLY_UART + ldr x1, =EARLY_UART_BASE 1: ldr w2, [x1, UTRSTAT] tst w2, #2 beq 1b str w0, [x1, UTXH] +#endif ret .globl reboot @@ -171,13 +172,7 @@ reboot: beq 1f hvc #0 1: - ldr x1, =WDT_BASE - mov w0, #0x100000 - str w0, [x1, #WDT_ALARM] - mov w0, #0 - str w0, [x1, #WDT_COUNT] - mov w0, #4 - str w0, [x1, #WDT_CTL] + bl wdt_reboot b . .pool diff --git a/src/startup.c b/src/startup.c index 292f398b..139ea4bf 100644 --- a/src/startup.c +++ b/src/startup.c @@ -79,25 +79,27 @@ void _start_c(void *boot_args, void *base) msr(TPIDR_EL1, 0); memset64(_bss_start, 0, _bss_end - _bss_start); - uart_putchar('s'); - uart_init(); - uart_putchar('c'); - uart_puts(": Initializing"); + boot_args_addr = (u64)boot_args; + memcpy(&cur_boot_args, boot_args, sizeof(cur_boot_args)); + + adt = + (void *)(((u64)cur_boot_args.devtree) - cur_boot_args.virt_base + cur_boot_args.phys_base); + + int ret = uart_init(); + if (ret < 0) { + debug_putc('!'); + } + + uart_puts("Initializing"); printf("CPU init... "); const char *type = init_cpu(); printf("CPU: %s\n\n", type); printf("boot_args at %p\n", boot_args); - boot_args_addr = (u64)boot_args; - memcpy(&cur_boot_args, boot_args, sizeof(cur_boot_args)); - dump_boot_args(&cur_boot_args); printf("\n"); - adt = - (void *)(((u64)cur_boot_args.devtree) - cur_boot_args.virt_base + cur_boot_args.phys_base); - exception_initialize(); gxf_init(); m1n1_main(); diff --git a/src/uart.c b/src/uart.c index 9a4e3a44..5caf651e 100644 --- a/src/uart.c +++ b/src/uart.c @@ -2,38 +2,56 @@ #include -#include "uart.h" +#include "adt.h" #include "iodev.h" #include "types.h" +#include "uart.h" #include "uart_regs.h" #include "utils.h" #include "vsprintf.h" #define UART_CLOCK 24000000 -#define UART_BASE 0x235200000L +static u64 uart_base = 0; -void *pxx = uart_init; - -void uart_init(void) +int uart_init(void) { - /* keep UART config from iBoot */ + int path[8]; + int node = adt_path_offset_trace(adt, "/arm-io/uart0", path); + + if (node < 0) { + printf("!!! UART node not found!\n"); + return -1; + } + + if (adt_get_reg(adt, path, "reg", 0, &uart_base, NULL)) { + printf("!!! Failed to get UART reg property!\n"); + return -1; + } + + return 0; } void uart_putbyte(u8 c) { - while (!(read32(UART_BASE + UTRSTAT) & UTRSTAT_TXBE)) + if (!uart_base) + return; + + while (!(read32(uart_base + UTRSTAT) & UTRSTAT_TXBE)) ; - write32(UART_BASE + UTXH, c); + write32(uart_base + UTXH, c); } u8 uart_getbyte(void) { - while (!(read32(UART_BASE + UTRSTAT) & UTRSTAT_RXD)) + if (!uart_base) + return 0; + + while (!(read32(uart_base + UTRSTAT) & UTRSTAT_RXD)) ; - return read32(UART_BASE + URXH); + return read32(uart_base + URXH); } void uart_putchar(u8 c) @@ -80,19 +98,28 @@ size_t uart_read(void *buf, size_t count) void uart_setbaud(int baudrate) { + if (!uart_base) + return; + uart_flush(); - write32(UART_BASE + UBRDIV, ((UART_CLOCK / baudrate + 7) / 16) - 1); + write32(uart_base + UBRDIV, ((UART_CLOCK / baudrate + 7) / 16) - 1); } void uart_flush(void) { - while (!(read32(UART_BASE + UTRSTAT) & UTRSTAT_TXE)) + if (!uart_base) + return; + + while (!(read32(uart_base + UTRSTAT) & UTRSTAT_TXE)) ; } void uart_clear_irqs(void) { - write32(UART_BASE + UTRSTAT, UTRSTAT_TXTHRESH | UTRSTAT_RXTHRESH | UTRSTAT_RXTO); + if (!uart_base) + return; + + write32(uart_base + UTRSTAT, UTRSTAT_TXTHRESH | UTRSTAT_RXTHRESH | UTRSTAT_RXTO); } int uart_printf(const char *fmt, ...) @@ -119,7 +146,11 @@ static bool uart_iodev_can_write(void *opaque) static ssize_t uart_iodev_can_read(void *opaque) { UNUSED(opaque); - return (read32(UART_BASE + UTRSTAT) & UTRSTAT_RXD) ? 1 : 0; + + if (!uart_base) + return 0; + + return (read32(uart_base + UTRSTAT) & UTRSTAT_RXD) ? 1 : 0; } static ssize_t uart_iodev_read(void *opaque, void *buf, size_t len) diff --git a/src/uart.h b/src/uart.h index 4f3c4c1d..0b03f2d1 100644 --- a/src/uart.h +++ b/src/uart.h @@ -5,7 +5,7 @@ #include "types.h" -void uart_init(void); +int uart_init(void); void uart_putbyte(u8 c); u8 uart_getbyte(void); diff --git a/src/wdt.c b/src/wdt.c index e7ef66bb..a3ebe3ac 100644 --- a/src/wdt.c +++ b/src/wdt.c @@ -5,6 +5,12 @@ #include "types.h" #include "utils.h" +#define WDT_COUNT 0x10 +#define WDT_ALARM 0x14 +#define WDT_CTL 0x1c + +static u64 wdt_base = 0; + void wdt_disable(void) { int path[8]; @@ -15,16 +21,24 @@ void wdt_disable(void) return; } - u64 wdt_regs; - - if (adt_get_reg(adt, path, "reg", 0, &wdt_regs, NULL)) { + if (adt_get_reg(adt, path, "reg", 0, &wdt_base, NULL)) { printf("Failed to get WDT reg property!\n"); return; } - printf("WDT registers @ 0x%lx\n", wdt_regs); + printf("WDT registers @ 0x%lx\n", wdt_base); - write32(wdt_regs + 0x1c, 0); + write32(wdt_base + WDT_CTL, 0); printf("WDT disabled\n"); } + +void wdt_reboot(void) +{ + if (!wdt_base) + return; + + write32(wdt_base + WDT_ALARM, 0x100000); + write32(wdt_base + WDT_COUNT, 0); + write32(wdt_base + WDT_CTL, 4); +} diff --git a/src/wdt.h b/src/wdt.h index 6c8e76f3..6a48601c 100644 --- a/src/wdt.h +++ b/src/wdt.h @@ -4,5 +4,6 @@ #define __WDT_H__ void wdt_disable(void); +void wdt_reboot(void); #endif