diff --git a/MAINTAINERS b/MAINTAINERS index 27ce73d83f4..8f884ff495a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1260,6 +1260,12 @@ S: Maintained F: drivers/misc/gsc.c F: include/gsc.h +GOLDFISH SERIAL DRIVER +M: Kuan-Wei Chiu +S: Maintained +F: drivers/serial/serial_goldfish.c +F: include/goldfish_tty.h + INTERCONNECT: M: Neil Armstrong S: Maintained diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 371d7aa5bba..b84cb9ec781 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -1193,4 +1193,12 @@ config SYS_SDMR depends on MPC8XX_CONS default 0x0 +config SERIAL_GOLDFISH + bool "Goldfish TTY support" + depends on DM_SERIAL + help + Select this to enable support for the Goldfish TTY serial port. + This virtual device is commonly used by QEMU virtual machines + (e.g. m68k virt) for console output. + endif diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 8eaae62b0fc..fe8d23be512 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -63,3 +63,4 @@ obj-$(CONFIG_XTENSA_SEMIHOSTING_SERIAL) += serial_xtensa_semihosting.o obj-$(CONFIG_S5P4418_PL011_SERIAL) += serial_s5p4418_pl011.o obj-$(CONFIG_UART4_SERIAL) += serial_adi_uart4.o +obj-$(CONFIG_SERIAL_GOLDFISH) += serial_goldfish.o diff --git a/drivers/serial/serial_goldfish.c b/drivers/serial/serial_goldfish.c new file mode 100644 index 00000000000..4ac2cfb6231 --- /dev/null +++ b/drivers/serial/serial_goldfish.c @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2025, Kuan-Wei Chiu + * Goldfish TTY driver for U-Boot + */ + +#include +#include +#include +#include +#include +#include + +/* Goldfish TTY Register Offsets */ +#define GOLDFISH_TTY_PUT_CHAR 0x00 +#define GOLDFISH_TTY_BYTES_READY 0x04 +#define GOLDFISH_TTY_CMD 0x08 +#define GOLDFISH_TTY_DATA_PTR 0x10 +#define GOLDFISH_TTY_DATA_LEN 0x14 +#define GOLDFISH_TTY_DATA_PTR_HIGH 0x18 +#define GOLDFISH_TTY_VERSION 0x20 + +/* Commands */ +#define CMD_WRITE_BUFFER 2 +#define CMD_READ_BUFFER 3 + +struct goldfish_tty_priv { + void __iomem *base; + u8 rx_buf; +}; + +static int goldfish_serial_getc(struct udevice *dev) +{ + struct goldfish_tty_priv *priv = dev_get_priv(dev); + unsigned long paddr; + u32 count; + + count = __raw_readl(priv->base + GOLDFISH_TTY_BYTES_READY); + if (count == 0) + return -EAGAIN; + + paddr = virt_to_phys((void *)&priv->rx_buf); + + __raw_writel(0, priv->base + GOLDFISH_TTY_DATA_PTR_HIGH); + __raw_writel(paddr, priv->base + GOLDFISH_TTY_DATA_PTR); + __raw_writel(1, priv->base + GOLDFISH_TTY_DATA_LEN); + __raw_writel(CMD_READ_BUFFER, priv->base + GOLDFISH_TTY_CMD); + + return priv->rx_buf; +} + +static int goldfish_serial_putc(struct udevice *dev, const char ch) +{ + struct goldfish_tty_priv *priv = dev_get_priv(dev); + + __raw_writel(ch, priv->base + GOLDFISH_TTY_PUT_CHAR); + + return 0; +} + +static int goldfish_serial_pending(struct udevice *dev, bool input) +{ + struct goldfish_tty_priv *priv = dev_get_priv(dev); + + if (input) + return __raw_readl(priv->base + GOLDFISH_TTY_BYTES_READY); + + return 0; +} + +static int goldfish_serial_of_to_plat(struct udevice *dev) +{ + struct goldfish_tty_plat *plat = dev_get_plat(dev); + fdt_addr_t addr; + + addr = dev_read_addr(dev); + if (addr != FDT_ADDR_T_NONE) + plat->reg = addr; + + return 0; +} + +static int goldfish_serial_probe(struct udevice *dev) +{ + struct goldfish_tty_plat *plat = dev_get_plat(dev); + struct goldfish_tty_priv *priv = dev_get_priv(dev); + + if (!plat->reg) + return -EINVAL; + + priv->base = map_sysmem(plat->reg, 0x1000); + + return 0; +} + +static const struct dm_serial_ops goldfish_serial_ops = { + .putc = goldfish_serial_putc, + .pending = goldfish_serial_pending, + .getc = goldfish_serial_getc, +}; + +static const struct udevice_id goldfish_serial_ids[] = { + { .compatible = "google,goldfish-tty" }, + { } +}; + +U_BOOT_DRIVER(serial_goldfish) = { + .name = "serial_goldfish", + .id = UCLASS_SERIAL, + .of_match = goldfish_serial_ids, + .of_to_plat = goldfish_serial_of_to_plat, + .plat_auto = sizeof(struct goldfish_tty_plat), + .probe = goldfish_serial_probe, + .ops = &goldfish_serial_ops, + .priv_auto = sizeof(struct goldfish_tty_priv), + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/include/goldfish_tty.h b/include/goldfish_tty.h new file mode 100644 index 00000000000..db49c8d6344 --- /dev/null +++ b/include/goldfish_tty.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2025, Kuan-Wei Chiu + */ + +#ifndef _GOLDFISH_TTY_H_ +#define _GOLDFISH_TTY_H_ + +#include + +/* Platform data for the Goldfish TTY driver + * Used to pass hardware base address from Board to Driver + */ +struct goldfish_tty_plat { + phys_addr_t reg; +}; + +#endif /* _GOLDFISH_TTY_H_ */