From 00fc82f17cff9295387d516384ecdc443acb1b22 Mon Sep 17 00:00:00 2001 From: Bradley Morgan Date: Sat, 3 Oct 2026 18:57:38 +0000 Subject: tashaboot: arm64 bringup, semihosting payload loader consoles on the pl011 the dtb points at, walks the memory node and chosen, loads an arm64 kernel Image over semihosting and jumps to it with the documented register state. string functions, printf and libfdt are vendored from lk (lk2nd) and u-boot so the libc surface is the one those projects already proved. built and booted on qemu virt, payload exits clean through semihosting. --- drivers/serial/pl011.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 drivers/serial/pl011.c (limited to 'drivers/serial') diff --git a/drivers/serial/pl011.c b/drivers/serial/pl011.c new file mode 100644 index 0000000..d11aa00 --- /dev/null +++ b/drivers/serial/pl011.c @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * pl011.c - ARM PrimeCell PL011 serial, polled io + * + * the register layout is shared with the PL010 so we use the combined + * struct like u-boot does. base comes from the dtb, never hardcoded. + * + * Copyright (C) 2026 Bradley Morgan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +void pl011_init(uintptr_t base, uint32 clock, uint32 baud) +{ + struct pl01x_regs *regs = (struct pl01x_regs *)base; + uint32 divisor; + uint32 remainder; + uint32 fraction; + + /* baud divisor, same math as the PL011 TRM section 3.3.3 */ + divisor = clock / (16 * baud); + remainder = clock % (16 * baud); + fraction = (8 * remainder + baud / 2) / baud; + + writel(0, ®s->pl011_cr); + writel(0x7ff, ®s->pl011_icr); + writel(divisor, ®s->pl011_ibrd); + writel(fraction, ®s->pl011_fbrd); + writel((3 << 5) | (1 << 4), ®s->pl011_lcrh); + writel((1 << 0) | (1 << 8) | (1 << 9), ®s->pl011_cr); +} + +void pl011_putc(uintptr_t base, char c) +{ + struct pl01x_regs *regs = (struct pl01x_regs *)base; + + while (readl(®s->fr) & UART_PL01x_FR_TXFF) + ; + writel(c, ®s->dr); +} + +int pl011_getc(uintptr_t base) +{ + struct pl01x_regs *regs = (struct pl01x_regs *)base; + + if (readl(®s->fr) & UART_PL01x_FR_RXFE) + return -1; + return readl(®s->dr) & 0xff; +} -- cgit v1.2.3