diff options
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; +} |
