diff options
| author | Bradley Morgan <brads@mainlining.org> | 2026-10-03 18:57:38 +0000 |
|---|---|---|
| committer | Bradley Morgan <brads@mainlining.org> | 2026-10-03 18:57:38 +0000 |
| commit | 00fc82f17cff9295387d516384ecdc443acb1b22 (patch) | |
| tree | 798bef0185878286028fe0eaf7594616a66903e4 /drivers/serial/pl011.c | |
| parent | 7e8514efb64774b6a635b87ae945e519a7c38551 (diff) | |
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.
Diffstat (limited to 'drivers/serial/pl011.c')
| -rw-r--r-- | drivers/serial/pl011.c | 56 |
1 files changed, 56 insertions, 0 deletions
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 <brads@mainlining.org> + * + * 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 <sys/types.h> +#include <stdint.h> +#include <reg.h> +#include <drivers/serial/pl011.h> + +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; +} |
