11da81e55SFilip Kokosinski // SPDX-License-Identifier: GPL-2.0
21da81e55SFilip Kokosinski /*
31da81e55SFilip Kokosinski * LiteUART serial controller (LiteX) Driver
41da81e55SFilip Kokosinski *
51da81e55SFilip Kokosinski * Copyright (C) 2019-2020 Antmicro <www.antmicro.com>
61da81e55SFilip Kokosinski */
71da81e55SFilip Kokosinski
85996b2e3SGabriel Somlo #include <linux/bits.h>
91da81e55SFilip Kokosinski #include <linux/console.h>
105602cf99SGabriel Somlo #include <linux/interrupt.h>
111da81e55SFilip Kokosinski #include <linux/litex.h>
121da81e55SFilip Kokosinski #include <linux/module.h>
131da81e55SFilip Kokosinski #include <linux/of.h>
14*29e5c442SRob Herring #include <linux/platform_device.h>
151da81e55SFilip Kokosinski #include <linux/serial.h>
161da81e55SFilip Kokosinski #include <linux/serial_core.h>
171da81e55SFilip Kokosinski #include <linux/slab.h>
181da81e55SFilip Kokosinski #include <linux/timer.h>
191da81e55SFilip Kokosinski #include <linux/tty_flip.h>
201da81e55SFilip Kokosinski #include <linux/xarray.h>
211da81e55SFilip Kokosinski
221da81e55SFilip Kokosinski /*
231da81e55SFilip Kokosinski * CSRs definitions (base address offsets + width)
241da81e55SFilip Kokosinski *
251da81e55SFilip Kokosinski * The definitions below are true for LiteX SoC configured for 8-bit CSR Bus,
261da81e55SFilip Kokosinski * 32-bit aligned.
271da81e55SFilip Kokosinski *
281da81e55SFilip Kokosinski * Supporting other configurations might require new definitions or a more
291da81e55SFilip Kokosinski * generic way of indexing the LiteX CSRs.
301da81e55SFilip Kokosinski *
311da81e55SFilip Kokosinski * For more details on how CSRs are defined and handled in LiteX, see comments
321da81e55SFilip Kokosinski * in the LiteX SoC Driver: drivers/soc/litex/litex_soc_ctrl.c
331da81e55SFilip Kokosinski */
341da81e55SFilip Kokosinski #define OFF_RXTX 0x00
351da81e55SFilip Kokosinski #define OFF_TXFULL 0x04
361da81e55SFilip Kokosinski #define OFF_RXEMPTY 0x08
371da81e55SFilip Kokosinski #define OFF_EV_STATUS 0x0c
381da81e55SFilip Kokosinski #define OFF_EV_PENDING 0x10
391da81e55SFilip Kokosinski #define OFF_EV_ENABLE 0x14
401da81e55SFilip Kokosinski
411da81e55SFilip Kokosinski /* events */
425996b2e3SGabriel Somlo #define EV_TX BIT(0)
435996b2e3SGabriel Somlo #define EV_RX BIT(1)
441da81e55SFilip Kokosinski
451da81e55SFilip Kokosinski struct liteuart_port {
461da81e55SFilip Kokosinski struct uart_port port;
471da81e55SFilip Kokosinski struct timer_list timer;
485602cf99SGabriel Somlo u8 irq_reg;
491da81e55SFilip Kokosinski };
501da81e55SFilip Kokosinski
511da81e55SFilip Kokosinski #define to_liteuart_port(port) container_of(port, struct liteuart_port, port)
521da81e55SFilip Kokosinski
531da81e55SFilip Kokosinski static DEFINE_XARRAY_FLAGS(liteuart_array, XA_FLAGS_ALLOC);
541da81e55SFilip Kokosinski
551da81e55SFilip Kokosinski #ifdef CONFIG_SERIAL_LITEUART_CONSOLE
561da81e55SFilip Kokosinski static struct console liteuart_console;
571da81e55SFilip Kokosinski #endif
581da81e55SFilip Kokosinski
591da81e55SFilip Kokosinski static struct uart_driver liteuart_driver = {
601da81e55SFilip Kokosinski .owner = THIS_MODULE,
612696216bSGabriel Somlo .driver_name = KBUILD_MODNAME,
621da81e55SFilip Kokosinski .dev_name = "ttyLXU",
631da81e55SFilip Kokosinski .major = 0,
641da81e55SFilip Kokosinski .minor = 0,
651da81e55SFilip Kokosinski .nr = CONFIG_SERIAL_LITEUART_MAX_PORTS,
661da81e55SFilip Kokosinski #ifdef CONFIG_SERIAL_LITEUART_CONSOLE
671da81e55SFilip Kokosinski .cons = &liteuart_console,
681da81e55SFilip Kokosinski #endif
691da81e55SFilip Kokosinski };
701da81e55SFilip Kokosinski
liteuart_update_irq_reg(struct uart_port * port,bool set,u8 mask)715602cf99SGabriel Somlo static void liteuart_update_irq_reg(struct uart_port *port, bool set, u8 mask)
725602cf99SGabriel Somlo {
735602cf99SGabriel Somlo struct liteuart_port *uart = to_liteuart_port(port);
745602cf99SGabriel Somlo
755602cf99SGabriel Somlo if (set)
765602cf99SGabriel Somlo uart->irq_reg |= mask;
775602cf99SGabriel Somlo else
785602cf99SGabriel Somlo uart->irq_reg &= ~mask;
795602cf99SGabriel Somlo
805602cf99SGabriel Somlo if (port->irq)
815602cf99SGabriel Somlo litex_write8(port->membase + OFF_EV_ENABLE, uart->irq_reg);
825602cf99SGabriel Somlo }
835602cf99SGabriel Somlo
liteuart_stop_tx(struct uart_port * port)841da81e55SFilip Kokosinski static void liteuart_stop_tx(struct uart_port *port)
851da81e55SFilip Kokosinski {
8601a305a3SGabriel Somlo liteuart_update_irq_reg(port, false, EV_TX);
871da81e55SFilip Kokosinski }
881da81e55SFilip Kokosinski
liteuart_start_tx(struct uart_port * port)891da81e55SFilip Kokosinski static void liteuart_start_tx(struct uart_port *port)
901da81e55SFilip Kokosinski {
9101a305a3SGabriel Somlo liteuart_update_irq_reg(port, true, EV_TX);
921da81e55SFilip Kokosinski }
931da81e55SFilip Kokosinski
liteuart_stop_rx(struct uart_port * port)941da81e55SFilip Kokosinski static void liteuart_stop_rx(struct uart_port *port)
951da81e55SFilip Kokosinski {
961da81e55SFilip Kokosinski struct liteuart_port *uart = to_liteuart_port(port);
971da81e55SFilip Kokosinski
981da81e55SFilip Kokosinski /* just delete timer */
991da81e55SFilip Kokosinski del_timer(&uart->timer);
1001da81e55SFilip Kokosinski }
1011da81e55SFilip Kokosinski
liteuart_rx_chars(struct uart_port * port)1027121d86eSGabriel Somlo static void liteuart_rx_chars(struct uart_port *port)
1037121d86eSGabriel Somlo {
1047121d86eSGabriel Somlo unsigned char __iomem *membase = port->membase;
1057121d86eSGabriel Somlo u8 ch;
1067121d86eSGabriel Somlo
1077121d86eSGabriel Somlo while (!litex_read8(membase + OFF_RXEMPTY)) {
1087121d86eSGabriel Somlo ch = litex_read8(membase + OFF_RXTX);
1097121d86eSGabriel Somlo port->icount.rx++;
1107121d86eSGabriel Somlo
1117121d86eSGabriel Somlo /* necessary for RXEMPTY to refresh its value */
1127121d86eSGabriel Somlo litex_write8(membase + OFF_EV_PENDING, EV_RX);
1137121d86eSGabriel Somlo
1147121d86eSGabriel Somlo /* no overflow bits in status */
1157121d86eSGabriel Somlo if (!(uart_handle_sysrq_char(port, ch)))
1167121d86eSGabriel Somlo uart_insert_char(port, 1, 0, ch, TTY_NORMAL);
1177121d86eSGabriel Somlo }
1187121d86eSGabriel Somlo
1197121d86eSGabriel Somlo tty_flip_buffer_push(&port->state->port);
1207121d86eSGabriel Somlo }
1217121d86eSGabriel Somlo
liteuart_tx_chars(struct uart_port * port)12201a305a3SGabriel Somlo static void liteuart_tx_chars(struct uart_port *port)
12301a305a3SGabriel Somlo {
12401a305a3SGabriel Somlo u8 ch;
12501a305a3SGabriel Somlo
12601a305a3SGabriel Somlo uart_port_tx(port, ch,
12701a305a3SGabriel Somlo !litex_read8(port->membase + OFF_TXFULL),
12801a305a3SGabriel Somlo litex_write8(port->membase + OFF_RXTX, ch));
12901a305a3SGabriel Somlo }
13001a305a3SGabriel Somlo
liteuart_interrupt(int irq,void * data)1315602cf99SGabriel Somlo static irqreturn_t liteuart_interrupt(int irq, void *data)
1325602cf99SGabriel Somlo {
1335602cf99SGabriel Somlo struct liteuart_port *uart = data;
1345602cf99SGabriel Somlo struct uart_port *port = &uart->port;
1355602cf99SGabriel Somlo unsigned long flags;
1365602cf99SGabriel Somlo u8 isr;
1375602cf99SGabriel Somlo
1385602cf99SGabriel Somlo /*
1395602cf99SGabriel Somlo * if polling, the context would be "in_serving_softirq", so use
1405602cf99SGabriel Somlo * irq[save|restore] spin_lock variants to cover all possibilities
1415602cf99SGabriel Somlo */
1425602cf99SGabriel Somlo spin_lock_irqsave(&port->lock, flags);
1435602cf99SGabriel Somlo isr = litex_read8(port->membase + OFF_EV_PENDING) & uart->irq_reg;
1445602cf99SGabriel Somlo if (isr & EV_RX)
1455602cf99SGabriel Somlo liteuart_rx_chars(port);
14601a305a3SGabriel Somlo if (isr & EV_TX)
14701a305a3SGabriel Somlo liteuart_tx_chars(port);
1485602cf99SGabriel Somlo spin_unlock_irqrestore(&port->lock, flags);
1495602cf99SGabriel Somlo
1505602cf99SGabriel Somlo return IRQ_RETVAL(isr);
1515602cf99SGabriel Somlo }
1525602cf99SGabriel Somlo
liteuart_timer(struct timer_list * t)1537121d86eSGabriel Somlo static void liteuart_timer(struct timer_list *t)
1547121d86eSGabriel Somlo {
1557121d86eSGabriel Somlo struct liteuart_port *uart = from_timer(uart, t, timer);
1567121d86eSGabriel Somlo struct uart_port *port = &uart->port;
1577121d86eSGabriel Somlo
1585602cf99SGabriel Somlo liteuart_interrupt(0, port);
1597121d86eSGabriel Somlo mod_timer(&uart->timer, jiffies + uart_poll_timeout(port));
1607121d86eSGabriel Somlo }
1617121d86eSGabriel Somlo
liteuart_tx_empty(struct uart_port * port)1627121d86eSGabriel Somlo static unsigned int liteuart_tx_empty(struct uart_port *port)
1637121d86eSGabriel Somlo {
1647121d86eSGabriel Somlo /* not really tx empty, just checking if tx is not full */
1657121d86eSGabriel Somlo if (!litex_read8(port->membase + OFF_TXFULL))
1667121d86eSGabriel Somlo return TIOCSER_TEMT;
1677121d86eSGabriel Somlo
1687121d86eSGabriel Somlo return 0;
1697121d86eSGabriel Somlo }
1707121d86eSGabriel Somlo
liteuart_set_mctrl(struct uart_port * port,unsigned int mctrl)1717121d86eSGabriel Somlo static void liteuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
1727121d86eSGabriel Somlo {
1737121d86eSGabriel Somlo /* modem control register is not present in LiteUART */
1747121d86eSGabriel Somlo }
1757121d86eSGabriel Somlo
liteuart_get_mctrl(struct uart_port * port)1767121d86eSGabriel Somlo static unsigned int liteuart_get_mctrl(struct uart_port *port)
1777121d86eSGabriel Somlo {
1787121d86eSGabriel Somlo return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
1797121d86eSGabriel Somlo }
1807121d86eSGabriel Somlo
liteuart_startup(struct uart_port * port)1811da81e55SFilip Kokosinski static int liteuart_startup(struct uart_port *port)
1821da81e55SFilip Kokosinski {
1831da81e55SFilip Kokosinski struct liteuart_port *uart = to_liteuart_port(port);
1845602cf99SGabriel Somlo unsigned long flags;
1855602cf99SGabriel Somlo int ret;
1861da81e55SFilip Kokosinski
1875602cf99SGabriel Somlo if (port->irq) {
1885602cf99SGabriel Somlo ret = request_irq(port->irq, liteuart_interrupt, 0,
1895602cf99SGabriel Somlo KBUILD_MODNAME, uart);
1905602cf99SGabriel Somlo if (ret) {
1915602cf99SGabriel Somlo dev_warn(port->dev,
1925602cf99SGabriel Somlo "line %d irq %d failed: switch to polling\n",
1935602cf99SGabriel Somlo port->line, port->irq);
1945602cf99SGabriel Somlo port->irq = 0;
1955602cf99SGabriel Somlo }
1965602cf99SGabriel Somlo }
1971da81e55SFilip Kokosinski
1985602cf99SGabriel Somlo spin_lock_irqsave(&port->lock, flags);
1995602cf99SGabriel Somlo /* only enabling rx irqs during startup */
2005602cf99SGabriel Somlo liteuart_update_irq_reg(port, true, EV_RX);
2015602cf99SGabriel Somlo spin_unlock_irqrestore(&port->lock, flags);
2025602cf99SGabriel Somlo
2035602cf99SGabriel Somlo if (!port->irq) {
2041da81e55SFilip Kokosinski timer_setup(&uart->timer, liteuart_timer, 0);
2051da81e55SFilip Kokosinski mod_timer(&uart->timer, jiffies + uart_poll_timeout(port));
2065602cf99SGabriel Somlo }
2071da81e55SFilip Kokosinski
2081da81e55SFilip Kokosinski return 0;
2091da81e55SFilip Kokosinski }
2101da81e55SFilip Kokosinski
liteuart_shutdown(struct uart_port * port)2111da81e55SFilip Kokosinski static void liteuart_shutdown(struct uart_port *port)
2121da81e55SFilip Kokosinski {
2135602cf99SGabriel Somlo struct liteuart_port *uart = to_liteuart_port(port);
2145602cf99SGabriel Somlo unsigned long flags;
2155602cf99SGabriel Somlo
2165602cf99SGabriel Somlo spin_lock_irqsave(&port->lock, flags);
2175602cf99SGabriel Somlo liteuart_update_irq_reg(port, false, EV_RX | EV_TX);
2185602cf99SGabriel Somlo spin_unlock_irqrestore(&port->lock, flags);
2195602cf99SGabriel Somlo
2205602cf99SGabriel Somlo if (port->irq)
2215602cf99SGabriel Somlo free_irq(port->irq, port);
2225602cf99SGabriel Somlo else
2235602cf99SGabriel Somlo del_timer_sync(&uart->timer);
2241da81e55SFilip Kokosinski }
2251da81e55SFilip Kokosinski
liteuart_set_termios(struct uart_port * port,struct ktermios * new,const struct ktermios * old)2261da81e55SFilip Kokosinski static void liteuart_set_termios(struct uart_port *port, struct ktermios *new,
227bec5b814SIlpo Järvinen const struct ktermios *old)
2281da81e55SFilip Kokosinski {
2291da81e55SFilip Kokosinski unsigned int baud;
2301da81e55SFilip Kokosinski unsigned long flags;
2311da81e55SFilip Kokosinski
2321da81e55SFilip Kokosinski spin_lock_irqsave(&port->lock, flags);
2331da81e55SFilip Kokosinski
2341da81e55SFilip Kokosinski /* update baudrate */
2351da81e55SFilip Kokosinski baud = uart_get_baud_rate(port, new, old, 0, 460800);
2361da81e55SFilip Kokosinski uart_update_timeout(port, new->c_cflag, baud);
2371da81e55SFilip Kokosinski
2381da81e55SFilip Kokosinski spin_unlock_irqrestore(&port->lock, flags);
2391da81e55SFilip Kokosinski }
2401da81e55SFilip Kokosinski
liteuart_type(struct uart_port * port)2411da81e55SFilip Kokosinski static const char *liteuart_type(struct uart_port *port)
2421da81e55SFilip Kokosinski {
2431da81e55SFilip Kokosinski return "liteuart";
2441da81e55SFilip Kokosinski }
2451da81e55SFilip Kokosinski
liteuart_config_port(struct uart_port * port,int flags)2461da81e55SFilip Kokosinski static void liteuart_config_port(struct uart_port *port, int flags)
2471da81e55SFilip Kokosinski {
2481da81e55SFilip Kokosinski /*
2491da81e55SFilip Kokosinski * Driver core for serial ports forces a non-zero value for port type.
2501da81e55SFilip Kokosinski * Write an arbitrary value here to accommodate the serial core driver,
2511da81e55SFilip Kokosinski * as ID part of UAPI is redundant.
2521da81e55SFilip Kokosinski */
2531da81e55SFilip Kokosinski port->type = 1;
2541da81e55SFilip Kokosinski }
2551da81e55SFilip Kokosinski
liteuart_verify_port(struct uart_port * port,struct serial_struct * ser)2561da81e55SFilip Kokosinski static int liteuart_verify_port(struct uart_port *port,
2571da81e55SFilip Kokosinski struct serial_struct *ser)
2581da81e55SFilip Kokosinski {
2591da81e55SFilip Kokosinski if (port->type != PORT_UNKNOWN && ser->type != 1)
2601da81e55SFilip Kokosinski return -EINVAL;
2611da81e55SFilip Kokosinski
2621da81e55SFilip Kokosinski return 0;
2631da81e55SFilip Kokosinski }
2641da81e55SFilip Kokosinski
2651da81e55SFilip Kokosinski static const struct uart_ops liteuart_ops = {
2661da81e55SFilip Kokosinski .tx_empty = liteuart_tx_empty,
2671da81e55SFilip Kokosinski .set_mctrl = liteuart_set_mctrl,
2681da81e55SFilip Kokosinski .get_mctrl = liteuart_get_mctrl,
2691da81e55SFilip Kokosinski .stop_tx = liteuart_stop_tx,
2701da81e55SFilip Kokosinski .start_tx = liteuart_start_tx,
2711da81e55SFilip Kokosinski .stop_rx = liteuart_stop_rx,
2721da81e55SFilip Kokosinski .startup = liteuart_startup,
2731da81e55SFilip Kokosinski .shutdown = liteuart_shutdown,
2741da81e55SFilip Kokosinski .set_termios = liteuart_set_termios,
2751da81e55SFilip Kokosinski .type = liteuart_type,
2761da81e55SFilip Kokosinski .config_port = liteuart_config_port,
2771da81e55SFilip Kokosinski .verify_port = liteuart_verify_port,
2781da81e55SFilip Kokosinski };
2791da81e55SFilip Kokosinski
liteuart_probe(struct platform_device * pdev)2801da81e55SFilip Kokosinski static int liteuart_probe(struct platform_device *pdev)
2811da81e55SFilip Kokosinski {
2821da81e55SFilip Kokosinski struct liteuart_port *uart;
2831da81e55SFilip Kokosinski struct uart_port *port;
2841da81e55SFilip Kokosinski struct xa_limit limit;
2851da81e55SFilip Kokosinski int dev_id, ret;
2861da81e55SFilip Kokosinski
287297cb3f0SAndy Shevchenko uart = devm_kzalloc(&pdev->dev, sizeof(struct liteuart_port), GFP_KERNEL);
288297cb3f0SAndy Shevchenko if (!uart)
289297cb3f0SAndy Shevchenko return -ENOMEM;
290297cb3f0SAndy Shevchenko
291297cb3f0SAndy Shevchenko port = &uart->port;
292297cb3f0SAndy Shevchenko
293297cb3f0SAndy Shevchenko /* get membase */
294297cb3f0SAndy Shevchenko port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
295297cb3f0SAndy Shevchenko if (IS_ERR(port->membase))
296297cb3f0SAndy Shevchenko return PTR_ERR(port->membase);
297297cb3f0SAndy Shevchenko
298297cb3f0SAndy Shevchenko ret = platform_get_irq_optional(pdev, 0);
299297cb3f0SAndy Shevchenko if (ret < 0 && ret != -ENXIO)
300297cb3f0SAndy Shevchenko return ret;
301297cb3f0SAndy Shevchenko if (ret > 0)
302297cb3f0SAndy Shevchenko port->irq = ret;
303297cb3f0SAndy Shevchenko
3041da81e55SFilip Kokosinski /* look for aliases; auto-enumerate for free index if not found */
3051da81e55SFilip Kokosinski dev_id = of_alias_get_id(pdev->dev.of_node, "serial");
3061da81e55SFilip Kokosinski if (dev_id < 0)
3071da81e55SFilip Kokosinski limit = XA_LIMIT(0, CONFIG_SERIAL_LITEUART_MAX_PORTS);
3081da81e55SFilip Kokosinski else
3091da81e55SFilip Kokosinski limit = XA_LIMIT(dev_id, dev_id);
3101da81e55SFilip Kokosinski
3111da81e55SFilip Kokosinski ret = xa_alloc(&liteuart_array, &dev_id, uart, limit, GFP_KERNEL);
3121da81e55SFilip Kokosinski if (ret)
3131da81e55SFilip Kokosinski return ret;
3141da81e55SFilip Kokosinski
3151da81e55SFilip Kokosinski /* values not from device tree */
3161da81e55SFilip Kokosinski port->dev = &pdev->dev;
3171da81e55SFilip Kokosinski port->iotype = UPIO_MEM;
3181da81e55SFilip Kokosinski port->flags = UPF_BOOT_AUTOCONF;
3191da81e55SFilip Kokosinski port->ops = &liteuart_ops;
3201da81e55SFilip Kokosinski port->fifosize = 16;
3211da81e55SFilip Kokosinski port->type = PORT_UNKNOWN;
3221da81e55SFilip Kokosinski port->line = dev_id;
3231da81e55SFilip Kokosinski spin_lock_init(&port->lock);
3241da81e55SFilip Kokosinski
3250f55f89dSIlia Sergachev platform_set_drvdata(pdev, port);
3260f55f89dSIlia Sergachev
327dd5e90b1SJohan Hovold ret = uart_add_one_port(&liteuart_driver, &uart->port);
328dd5e90b1SJohan Hovold if (ret)
329dd5e90b1SJohan Hovold goto err_erase_id;
330dd5e90b1SJohan Hovold
331dd5e90b1SJohan Hovold return 0;
332dd5e90b1SJohan Hovold
333dd5e90b1SJohan Hovold err_erase_id:
334646b4cd9SAndy Shevchenko xa_erase(&liteuart_array, dev_id);
335dd5e90b1SJohan Hovold
336dd5e90b1SJohan Hovold return ret;
3371da81e55SFilip Kokosinski }
3381da81e55SFilip Kokosinski
liteuart_remove(struct platform_device * pdev)3391da81e55SFilip Kokosinski static int liteuart_remove(struct platform_device *pdev)
3401da81e55SFilip Kokosinski {
3411da81e55SFilip Kokosinski struct uart_port *port = platform_get_drvdata(pdev);
342646b4cd9SAndy Shevchenko unsigned int line = port->line;
3431da81e55SFilip Kokosinski
34405f929b3SJohan Hovold uart_remove_one_port(&liteuart_driver, port);
345646b4cd9SAndy Shevchenko xa_erase(&liteuart_array, line);
3461da81e55SFilip Kokosinski
3471da81e55SFilip Kokosinski return 0;
3481da81e55SFilip Kokosinski }
3491da81e55SFilip Kokosinski
3501da81e55SFilip Kokosinski static const struct of_device_id liteuart_of_match[] = {
3511da81e55SFilip Kokosinski { .compatible = "litex,liteuart" },
3521da81e55SFilip Kokosinski {}
3531da81e55SFilip Kokosinski };
3541da81e55SFilip Kokosinski MODULE_DEVICE_TABLE(of, liteuart_of_match);
3551da81e55SFilip Kokosinski
3561da81e55SFilip Kokosinski static struct platform_driver liteuart_platform_driver = {
3571da81e55SFilip Kokosinski .probe = liteuart_probe,
3581da81e55SFilip Kokosinski .remove = liteuart_remove,
3591da81e55SFilip Kokosinski .driver = {
3602696216bSGabriel Somlo .name = KBUILD_MODNAME,
3611da81e55SFilip Kokosinski .of_match_table = liteuart_of_match,
3621da81e55SFilip Kokosinski },
3631da81e55SFilip Kokosinski };
3641da81e55SFilip Kokosinski
3651da81e55SFilip Kokosinski #ifdef CONFIG_SERIAL_LITEUART_CONSOLE
3661da81e55SFilip Kokosinski
liteuart_putchar(struct uart_port * port,unsigned char ch)367f1c6c8b1SGabriel Somlo static void liteuart_putchar(struct uart_port *port, unsigned char ch)
368f1c6c8b1SGabriel Somlo {
369f1c6c8b1SGabriel Somlo while (litex_read8(port->membase + OFF_TXFULL))
370f1c6c8b1SGabriel Somlo cpu_relax();
371f1c6c8b1SGabriel Somlo
372f1c6c8b1SGabriel Somlo litex_write8(port->membase + OFF_RXTX, ch);
373f1c6c8b1SGabriel Somlo }
374f1c6c8b1SGabriel Somlo
liteuart_console_write(struct console * co,const char * s,unsigned int count)3751da81e55SFilip Kokosinski static void liteuart_console_write(struct console *co, const char *s,
3761da81e55SFilip Kokosinski unsigned int count)
3771da81e55SFilip Kokosinski {
3781da81e55SFilip Kokosinski struct liteuart_port *uart;
3791da81e55SFilip Kokosinski struct uart_port *port;
3801da81e55SFilip Kokosinski unsigned long flags;
3811da81e55SFilip Kokosinski
3821da81e55SFilip Kokosinski uart = (struct liteuart_port *)xa_load(&liteuart_array, co->index);
3831da81e55SFilip Kokosinski port = &uart->port;
3841da81e55SFilip Kokosinski
3851da81e55SFilip Kokosinski spin_lock_irqsave(&port->lock, flags);
3861da81e55SFilip Kokosinski uart_console_write(port, s, count, liteuart_putchar);
3871da81e55SFilip Kokosinski spin_unlock_irqrestore(&port->lock, flags);
3881da81e55SFilip Kokosinski }
3891da81e55SFilip Kokosinski
liteuart_console_setup(struct console * co,char * options)3901da81e55SFilip Kokosinski static int liteuart_console_setup(struct console *co, char *options)
3911da81e55SFilip Kokosinski {
3921da81e55SFilip Kokosinski struct liteuart_port *uart;
3931da81e55SFilip Kokosinski struct uart_port *port;
3941da81e55SFilip Kokosinski int baud = 115200;
3951da81e55SFilip Kokosinski int bits = 8;
3961da81e55SFilip Kokosinski int parity = 'n';
3971da81e55SFilip Kokosinski int flow = 'n';
3981da81e55SFilip Kokosinski
3991da81e55SFilip Kokosinski uart = (struct liteuart_port *)xa_load(&liteuart_array, co->index);
4001da81e55SFilip Kokosinski if (!uart)
4011da81e55SFilip Kokosinski return -ENODEV;
4021da81e55SFilip Kokosinski
4031da81e55SFilip Kokosinski port = &uart->port;
4041da81e55SFilip Kokosinski if (!port->membase)
4051da81e55SFilip Kokosinski return -ENODEV;
4061da81e55SFilip Kokosinski
4071da81e55SFilip Kokosinski if (options)
4081da81e55SFilip Kokosinski uart_parse_options(options, &baud, &parity, &bits, &flow);
4091da81e55SFilip Kokosinski
4101da81e55SFilip Kokosinski return uart_set_options(port, co, baud, parity, bits, flow);
4111da81e55SFilip Kokosinski }
4121da81e55SFilip Kokosinski
4131da81e55SFilip Kokosinski static struct console liteuart_console = {
4142696216bSGabriel Somlo .name = KBUILD_MODNAME,
4151da81e55SFilip Kokosinski .write = liteuart_console_write,
4161da81e55SFilip Kokosinski .device = uart_console_device,
4171da81e55SFilip Kokosinski .setup = liteuart_console_setup,
4181da81e55SFilip Kokosinski .flags = CON_PRINTBUFFER,
4191da81e55SFilip Kokosinski .index = -1,
4201da81e55SFilip Kokosinski .data = &liteuart_driver,
4211da81e55SFilip Kokosinski };
4221da81e55SFilip Kokosinski
liteuart_console_init(void)4231da81e55SFilip Kokosinski static int __init liteuart_console_init(void)
4241da81e55SFilip Kokosinski {
4251da81e55SFilip Kokosinski register_console(&liteuart_console);
4261da81e55SFilip Kokosinski
4271da81e55SFilip Kokosinski return 0;
4281da81e55SFilip Kokosinski }
4291da81e55SFilip Kokosinski console_initcall(liteuart_console_init);
4304bc2bd5aSStafford Horne
early_liteuart_write(struct console * console,const char * s,unsigned int count)4314bc2bd5aSStafford Horne static void early_liteuart_write(struct console *console, const char *s,
4324bc2bd5aSStafford Horne unsigned int count)
4334bc2bd5aSStafford Horne {
4344bc2bd5aSStafford Horne struct earlycon_device *device = console->data;
4354bc2bd5aSStafford Horne struct uart_port *port = &device->port;
4364bc2bd5aSStafford Horne
4374bc2bd5aSStafford Horne uart_console_write(port, s, count, liteuart_putchar);
4384bc2bd5aSStafford Horne }
4394bc2bd5aSStafford Horne
early_liteuart_setup(struct earlycon_device * device,const char * options)4404bc2bd5aSStafford Horne static int __init early_liteuart_setup(struct earlycon_device *device,
4414bc2bd5aSStafford Horne const char *options)
4424bc2bd5aSStafford Horne {
4434bc2bd5aSStafford Horne if (!device->port.membase)
4444bc2bd5aSStafford Horne return -ENODEV;
4454bc2bd5aSStafford Horne
4464bc2bd5aSStafford Horne device->con->write = early_liteuart_write;
4474bc2bd5aSStafford Horne return 0;
4484bc2bd5aSStafford Horne }
4494bc2bd5aSStafford Horne
4504bc2bd5aSStafford Horne OF_EARLYCON_DECLARE(liteuart, "litex,liteuart", early_liteuart_setup);
4511da81e55SFilip Kokosinski #endif /* CONFIG_SERIAL_LITEUART_CONSOLE */
4521da81e55SFilip Kokosinski
liteuart_init(void)4531da81e55SFilip Kokosinski static int __init liteuart_init(void)
4541da81e55SFilip Kokosinski {
4551da81e55SFilip Kokosinski int res;
4561da81e55SFilip Kokosinski
4571da81e55SFilip Kokosinski res = uart_register_driver(&liteuart_driver);
4581da81e55SFilip Kokosinski if (res)
4591da81e55SFilip Kokosinski return res;
4601da81e55SFilip Kokosinski
4611da81e55SFilip Kokosinski res = platform_driver_register(&liteuart_platform_driver);
462b9f5a18aSGabriel Somlo if (res)
4631da81e55SFilip Kokosinski uart_unregister_driver(&liteuart_driver);
4641da81e55SFilip Kokosinski
465b9f5a18aSGabriel Somlo return res;
4661da81e55SFilip Kokosinski }
4671da81e55SFilip Kokosinski
liteuart_exit(void)4681da81e55SFilip Kokosinski static void __exit liteuart_exit(void)
4691da81e55SFilip Kokosinski {
4701da81e55SFilip Kokosinski platform_driver_unregister(&liteuart_platform_driver);
4711da81e55SFilip Kokosinski uart_unregister_driver(&liteuart_driver);
4721da81e55SFilip Kokosinski }
4731da81e55SFilip Kokosinski
4741da81e55SFilip Kokosinski module_init(liteuart_init);
4751da81e55SFilip Kokosinski module_exit(liteuart_exit);
4761da81e55SFilip Kokosinski
4771da81e55SFilip Kokosinski MODULE_AUTHOR("Antmicro <www.antmicro.com>");
4781da81e55SFilip Kokosinski MODULE_DESCRIPTION("LiteUART serial driver");
4791da81e55SFilip Kokosinski MODULE_LICENSE("GPL v2");
4801da81e55SFilip Kokosinski MODULE_ALIAS("platform:liteuart");
481