// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2024, Raspberry Pi Ltd. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #define RPI_FW_UART_RX_FIFO_RD 0xb0 #define RPI_FW_UART_RX_FIFO_WR 0xb4 #define RPI_FW_UART_TX_FIFO_RD 0xb8 #define RPI_FW_UART_TX_FIFO_WR 0xbc #define RPI_FW_UART_FIFO_SIZE 32 #define RPI_FW_UART_FIFO_SIZE_MASK (RPI_FW_UART_FIFO_SIZE - 1) #define RPI_FW_UART_MIN_VERSION 3 struct rpi_fw_uart_params { u32 start; u32 baud; u32 data_bits; u32 stop_bits; u32 gpio_rx; u32 gpio_tx; u32 flags; u32 fifosize; u32 rx_buffer; u32 tx_buffer; u32 version; u32 fifo_reg_base; }; struct rpi_fw_uart { struct uart_driver driver; struct uart_port port; struct rpi_firmware *firmware; struct gpio_desc *rx_gpiod; struct gpio_desc *tx_gpiod; unsigned int rx_gpio; unsigned int tx_gpio; unsigned int baud; unsigned int data_bits; unsigned int stop_bits; unsigned char __iomem *base; size_t dma_buffer_size; struct hrtimer trigger_start_rx; ktime_t rx_poll_delay; void *rx_buffer; dma_addr_t rx_buffer_dma_addr; int rx_stop; void *tx_buffer; dma_addr_t tx_buffer_dma_addr; }; static unsigned int rpi_fw_uart_tx_is_full(struct uart_port *port) { struct rpi_fw_uart *rfu = container_of(port, struct rpi_fw_uart, port); u32 rd, wr; rd = readl(rfu->base + RPI_FW_UART_TX_FIFO_RD); wr = readl(rfu->base + RPI_FW_UART_TX_FIFO_WR); return ((wr + 1) & RPI_FW_UART_FIFO_SIZE_MASK) == rd; } static unsigned int rpi_fw_uart_tx_is_empty(struct uart_port *port) { struct rpi_fw_uart *rfu = container_of(port, struct rpi_fw_uart, port); u32 rd, wr; if (!rfu->tx_buffer) return 1; rd = readl(rfu->base + RPI_FW_UART_TX_FIFO_RD); wr = readl(rfu->base + RPI_FW_UART_TX_FIFO_WR); return rd == wr; } static unsigned int rpi_fw_uart_rx_is_empty(struct uart_port *port) { struct rpi_fw_uart *rfu = container_of(port, struct rpi_fw_uart, port); u32 rd, wr; if (!rfu->rx_buffer) return 1; rd = readl(rfu->base + RPI_FW_UART_RX_FIFO_RD); wr = readl(rfu->base + RPI_FW_UART_RX_FIFO_WR); return rd == wr; } static unsigned int rpi_fw_uart_tx_empty(struct uart_port *port) { return rpi_fw_uart_tx_is_empty(port) ? TIOCSER_TEMT : 0; } static void rpi_fw_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) { /* * No hardware flow control, firmware automatically configures * TX to output high and RX to input low. */ dev_dbg(port->dev, "%s mctrl %u\n", __func__, mctrl); } static unsigned int rpi_fw_uart_get_mctrl(struct uart_port *port) { /* No hardware flow control */ return TIOCM_CTS; } static void rpi_fw_uart_stop(struct uart_port *port) { struct rpi_fw_uart_params msg = {.start = 0}; struct rpi_fw_uart *rfu = container_of(port, struct rpi_fw_uart, port); hrtimer_cancel(&rfu->trigger_start_rx); if (rpi_firmware_property(rfu->firmware, RPI_FIRMWARE_SET_SW_UART, &msg, sizeof(msg))) dev_warn(port->dev, "Failed to shutdown rpi-fw uart. Firmware not configured?"); } static void rpi_fw_uart_stop_tx(struct uart_port *port) { /* No supported by the current firmware APIs. */ } static void rpi_fw_uart_stop_rx(struct uart_port *port) { struct rpi_fw_uart *rfu = container_of(port, struct rpi_fw_uart, port); rfu->rx_stop = 1; } static unsigned int rpi_fw_write(struct uart_port *port, const char *s, unsigned int count) { struct rpi_fw_uart *rfu = container_of(port, struct rpi_fw_uart, port); u8 *out = rfu->tx_buffer; unsigned int consumed = 0; while (consumed < count && !rpi_fw_uart_tx_is_full(port)) { u32 wp = readl(rfu->base + RPI_FW_UART_TX_FIFO_WR) & RPI_FW_UART_FIFO_SIZE_MASK; out[wp] = s[consumed++]; wp = (wp + 1) & RPI_FW_UART_FIFO_SIZE_MASK; writel(wp, rfu->base + RPI_FW_UART_TX_FIFO_WR); } return consumed; } /* Called with port.lock taken */ static void rpi_fw_uart_start_tx(struct uart_port *port) { struct tty_port *tport = &port->state->port; for (;;) { unsigned int consumed; unsigned char *tail; unsigned int count; count = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail, port->fifosize); if (!count) break; consumed = rpi_fw_write(port, tail, count); uart_xmit_advance(port, consumed); } uart_write_wakeup(port); } /* Called with port.lock taken */ static void rpi_fw_uart_start_rx(struct uart_port *port) { struct tty_port *tty_port = &port->state->port; struct rpi_fw_uart *rfu = container_of(port, struct rpi_fw_uart, port); int count = 0; /* * RX is polled, read up to a full buffer of data before trying again * so that this can be interrupted if the firmware is filling the * buffer too fast */ while (!rpi_fw_uart_rx_is_empty(port) && count < port->fifosize) { const u8 *in = rfu->rx_buffer; u32 rp = readl(rfu->base + RPI_FW_UART_RX_FIFO_RD) & RPI_FW_UART_FIFO_SIZE_MASK; tty_insert_flip_char(tty_port, in[rp], TTY_NORMAL); rp = (rp + 1) & RPI_FW_UART_FIFO_SIZE_MASK; writel(rp, rfu->base + RPI_FW_UART_RX_FIFO_RD); count++; } if (count) tty_flip_buffer_push(tty_port); } static enum hrtimer_restart rpi_fw_uart_trigger_rx(struct hrtimer *t) { unsigned long flags; struct rpi_fw_uart *rfu = container_of(t, struct rpi_fw_uart, trigger_start_rx); spin_lock_irqsave(&rfu->port.lock, flags); if (rfu->rx_stop) { spin_unlock_irqrestore(&rfu->port.lock, flags); return HRTIMER_NORESTART; } rpi_fw_uart_start_rx(&rfu->port); spin_unlock_irqrestore(&rfu->port.lock, flags); hrtimer_forward_now(t, rfu->rx_poll_delay); return HRTIMER_RESTART; } static void rpi_fw_uart_break_ctl(struct uart_port *port, int ctl) { dev_dbg(port->dev, "%s ctl %d\n", __func__, ctl); } static int rpi_fw_uart_configure(struct uart_port *port) { struct rpi_fw_uart *rfu = container_of(port, struct rpi_fw_uart, port); struct rpi_fw_uart_params msg; unsigned long flags; int rc; rpi_fw_uart_stop(port); memset(&msg, 0, sizeof(msg)); msg.start = 1; msg.gpio_rx = rfu->rx_gpio; msg.gpio_tx = rfu->tx_gpio; msg.data_bits = rfu->data_bits; msg.stop_bits = rfu->stop_bits; msg.baud = rfu->baud; msg.fifosize = RPI_FW_UART_FIFO_SIZE; msg.rx_buffer = (u32) rfu->rx_buffer_dma_addr; msg.tx_buffer = (u32) rfu->tx_buffer_dma_addr; rfu->rx_poll_delay = ms_to_ktime(50); /* * Reconfigures the firmware UART with the new settings. On the first * call retrieve the addresses of the FIFO buffers. The buffers are * allocated at startup and are not de-allocated. * NB rpi_firmware_property can block */ rc = rpi_firmware_property(rfu->firmware, RPI_FIRMWARE_SET_SW_UART, &msg, sizeof(msg)); if (rc) goto fail; rc = rpi_firmware_property(rfu->firmware, RPI_FIRMWARE_GET_SW_UART, &msg, sizeof(msg)); if (rc) goto fail; dev_dbg(port->dev, "version %08x, reg addr %x\n", msg.version, msg.fifo_reg_base); dev_dbg(port->dev, "started %d baud %u data %u stop %u rx %u tx %u flags %u fifosize %u\n", msg.start, msg.baud, msg.data_bits, msg.stop_bits, msg.gpio_rx, msg.gpio_tx, msg.flags, msg.fifosize); if (msg.fifosize != port->fifosize) { dev_err(port->dev, "Expected fifo size %u actual %u", port->fifosize, msg.fifosize); rc = -EINVAL; goto fail; } if (!msg.start) { dev_err(port->dev, "Firmware service not running\n"); rc = -EINVAL; } spin_lock_irqsave(&rfu->port.lock, flags); rfu->rx_stop = 0; hrtimer_start(&rfu->trigger_start_rx, rfu->rx_poll_delay, HRTIMER_MODE_REL); spin_unlock_irqrestore(&rfu->port.lock, flags); return 0; fail: dev_err(port->dev, "Failed to configure rpi-fw uart. Firmware not configured?"); return rc; } static void rpi_fw_uart_free_buffers(struct uart_port *port) { struct rpi_fw_uart *rfu = container_of(port, struct rpi_fw_uart, port); if (rfu->rx_buffer) dma_free_coherent(port->dev, rfu->dma_buffer_size, rfu->rx_buffer, GFP_ATOMIC); if (rfu->tx_buffer) dma_free_coherent(port->dev, rfu->dma_buffer_size, rfu->tx_buffer, GFP_ATOMIC); rfu->rx_buffer = NULL; rfu->tx_buffer = NULL; rfu->rx_buffer_dma_addr = 0; rfu->tx_buffer_dma_addr = 0; } static int rpi_fw_uart_alloc_buffers(struct uart_port *port) { struct rpi_fw_uart *rfu = container_of(port, struct rpi_fw_uart, port); if (rfu->tx_buffer) return 0; rfu->dma_buffer_size = PAGE_ALIGN(RPI_FW_UART_FIFO_SIZE); rfu->rx_buffer = dma_alloc_coherent(port->dev, rfu->dma_buffer_size, &rfu->rx_buffer_dma_addr, GFP_ATOMIC); if (!rfu->rx_buffer) goto alloc_fail; rfu->tx_buffer = dma_alloc_coherent(port->dev, rfu->dma_buffer_size, &rfu->tx_buffer_dma_addr, GFP_ATOMIC); if (!rfu->tx_buffer) goto alloc_fail; dev_dbg(port->dev, "alloc-buffers %p %x %p %x\n", rfu->rx_buffer, (u32) rfu->rx_buffer_dma_addr, rfu->tx_buffer, (u32) rfu->tx_buffer_dma_addr); return 0; alloc_fail: dev_err(port->dev, "%s uart buffer allocation failed\n", __func__); rpi_fw_uart_free_buffers(port); return -ENOMEM; } static int rpi_fw_uart_startup(struct uart_port *port) { int rc; rc = rpi_fw_uart_alloc_buffers(port); if (rc) dev_err(port->dev, "Failed to start\n"); return rc; } static void rpi_fw_uart_shutdown(struct uart_port *port) { rpi_fw_uart_stop(port); rpi_fw_uart_free_buffers(port); } static void rpi_fw_uart_set_termios(struct uart_port *port, struct ktermios *new, const struct ktermios *old) { struct rpi_fw_uart *rfu = container_of(port, struct rpi_fw_uart, port); rfu->baud = uart_get_baud_rate(port, new, old, 50, 115200); rfu->stop_bits = (new->c_cflag & CSTOPB) ? 2 : 1; rpi_fw_uart_configure(port); } static const struct uart_ops rpi_fw_uart_ops = { .tx_empty = rpi_fw_uart_tx_empty, .set_mctrl = rpi_fw_uart_set_mctrl, .get_mctrl = rpi_fw_uart_get_mctrl, .stop_rx = rpi_fw_uart_stop_rx, .stop_tx = rpi_fw_uart_stop_tx, .start_tx = rpi_fw_uart_start_tx, .break_ctl = rpi_fw_uart_break_ctl, .startup = rpi_fw_uart_startup, .shutdown = rpi_fw_uart_shutdown, .set_termios = rpi_fw_uart_set_termios, }; static int rpi_fw_uart_get_gpio_offset(struct device *dev, const char *name) { struct of_phandle_args of_args = { 0 }; bool is_bcm28xx; /* This really shouldn't fail, given that we have a gpiod */ if (of_parse_phandle_with_args(dev->of_node, name, "#gpio-cells", 0, &of_args)) return dev_err_probe(dev, -EINVAL, "can't find gpio declaration\n"); is_bcm28xx = of_device_is_compatible(of_args.np, "brcm,bcm2835-gpio") || of_device_is_compatible(of_args.np, "brcm,bcm2711-gpio"); of_node_put(of_args.np); if (!is_bcm28xx || of_args.args_count != 2) return dev_err_probe(dev, -EINVAL, "not a BCM28xx gpio\n"); return of_args.args[0]; } static int rpi_fw_uart_probe(struct platform_device *pdev) { struct device_node *firmware_node; struct device *dev = &pdev->dev; struct rpi_firmware *firmware; struct uart_port *port; struct rpi_fw_uart *rfu; struct rpi_fw_uart_params msg; int version_major; int err; dev_dbg(dev, "%s of_node %p\n", __func__, dev->of_node); /* * We can be probed either through the an old-fashioned * platform device registration or through a DT node that is a * child of the firmware node. Handle both cases. */ if (dev->of_node) firmware_node = of_parse_phandle(dev->of_node, "firmware", 0); else firmware_node = of_find_compatible_node(NULL, NULL, "raspberrypi,bcm2835-firmware"); if (!firmware_node) { dev_err(dev, "Missing firmware node\n"); return -ENOENT; } firmware = devm_rpi_firmware_get(dev, firmware_node); of_node_put(firmware_node); if (!firmware) return -EPROBE_DEFER; rfu = devm_kzalloc(dev, sizeof(*rfu), GFP_KERNEL); if (!rfu) return -ENOMEM; rfu->firmware = firmware; err = rpi_firmware_property(rfu->firmware, RPI_FIRMWARE_GET_SW_UART, &msg, sizeof(msg)); if (err) { dev_err(dev, "VC firmware does not support rpi-fw-uart\n"); return err; } version_major = msg.version >> 16; if (msg.version < RPI_FW_UART_MIN_VERSION) { dev_err(dev, "rpi-fw-uart fw version %d is too old min version %d\n", version_major, RPI_FW_UART_MIN_VERSION); return -EINVAL; } rfu->rx_gpiod = devm_gpiod_get(dev, "rx", GPIOD_IN); if (IS_ERR(rfu->rx_gpiod)) return PTR_ERR(rfu->rx_gpiod); rfu->tx_gpiod = devm_gpiod_get(dev, "tx", GPIOD_OUT_HIGH); if (IS_ERR(rfu->tx_gpiod)) return PTR_ERR(rfu->tx_gpiod); rfu->rx_gpio = rpi_fw_uart_get_gpio_offset(dev, "rx-gpios"); if (rfu->rx_gpio < 0) return rfu->rx_gpio; rfu->tx_gpio = rpi_fw_uart_get_gpio_offset(dev, "tx-gpios"); if (rfu->tx_gpio < 0) return rfu->tx_gpio; rfu->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(rfu->base)) return PTR_ERR(rfu->base); /* setup the driver */ rfu->driver.owner = THIS_MODULE; rfu->driver.driver_name = "ttyRFU"; rfu->driver.dev_name = "ttyRFU"; rfu->driver.nr = 1; rfu->data_bits = 8; /* RX is polled */ hrtimer_setup(&rfu->trigger_start_rx, rpi_fw_uart_trigger_rx, CLOCK_MONOTONIC, HRTIMER_MODE_REL); err = uart_register_driver(&rfu->driver); if (err) { dev_err(dev, "failed to register UART driver: %d\n", err); return err; } /* setup the port */ port = &rfu->port; spin_lock_init(&port->lock); port->dev = &pdev->dev; port->type = PORT_RPI_FW; port->ops = &rpi_fw_uart_ops; port->fifosize = RPI_FW_UART_FIFO_SIZE; port->iotype = UPIO_MEM; port->flags = UPF_BOOT_AUTOCONF; port->private_data = rfu; err = uart_add_one_port(&rfu->driver, port); if (err) { dev_err(dev, "failed to add UART port: %d\n", err); goto unregister_uart; } platform_set_drvdata(pdev, rfu); dev_info(dev, "version %d.%d gpios tx %u rx %u\n", msg.version >> 16, msg.version & 0xffff, rfu->tx_gpio, rfu->rx_gpio); return 0; unregister_uart: uart_unregister_driver(&rfu->driver); return err; } static void rpi_fw_uart_remove(struct platform_device *pdev) { struct rpi_fw_uart *rfu = platform_get_drvdata(pdev); uart_remove_one_port(&rfu->driver, &rfu->port); uart_unregister_driver(&rfu->driver); } static const struct of_device_id rpi_fw_match[] = { { .compatible = "raspberrypi,firmware-uart" }, { } }; MODULE_DEVICE_TABLE(of, rpi_fw_match); static struct platform_driver rpi_fw_driver = { .driver = { .name = "rpi_fw-uart", .of_match_table = rpi_fw_match, }, .probe = rpi_fw_uart_probe, .remove = rpi_fw_uart_remove, }; module_platform_driver(rpi_fw_driver); MODULE_AUTHOR("Tim Gover "); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Raspberry Pi Firmware Software UART driver");