Remove hardcoded UART/WDT addresses

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 <vincent@duvert.net>
This commit is contained in:
Vincent Duvert 2021-10-31 20:25:36 +01:00 committed by Hector Martin
parent 73180e29fa
commit b15be6bcd7
6 changed files with 87 additions and 44 deletions

View file

@ -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

View file

@ -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();

View file

@ -2,38 +2,56 @@
#include <stdarg.h>
#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)

View file

@ -5,7 +5,7 @@
#include "types.h"
void uart_init(void);
int uart_init(void);
void uart_putbyte(u8 c);
u8 uart_getbyte(void);

View file

@ -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);
}

View file

@ -4,5 +4,6 @@
#define __WDT_H__
void wdt_disable(void);
void wdt_reboot(void);
#endif