I2C
M: Heiko Schocher <[email protected]>
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..278d0cf3e0d
--- /dev/null
+++ b/drivers/serial/serial_goldfish.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2025, Kuan-Wei Chiu <[email protected]>
+ * Goldfish TTY driver for U-Boot
+ */
+
+#include <asm/io.h>
+#include <dm.h>
+#include <goldfish_tty.h>
+#include <linux/types.h>
+#include <mapmem.h>
+#include <serial.h>
+
+/* 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_probe(struct udevice *dev)
+{
+ struct goldfish_tty_priv *priv = dev_get_priv(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) {
+ priv->base = map_sysmem(addr, 0x1000);
+ } else {
+ plat = dev_get_plat(dev);
+ if (!plat)
+ return -EINVAL;
+ priv->base = plat->base;
+ }
+
+ 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,
+ .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..8777da4942d
--- /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 <[email protected]>
+ */
+
+#ifndef _GOLDFISH_TTY_H_
+#define _GOLDFISH_TTY_H_
+
+#include <linux/types.h>
+
+/* Platform data for the Goldfish TTY driver
+ * Used to pass hardware base address from Board to Driver
+ */
+struct goldfish_tty_plat {
+ void __iomem *base;
+};
+
+#endif /* _GOLDFISH_TTY_H_ */