Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drivers: PL011: add support for the ARM SBSA generic UART

The ARM Server Base System Architecture[1] document describes a
generic UART which is a subset of the PL011 UART.
It lacks DMA support, baud rate control and modem status line
control, among other things.
The idea is to move the UART initialization and setup into the
firmware (which does this job today already) and let the kernel just
use the UART for sending and receiving characters.

We use the recent refactoring to build a new struct uart_ops
variable which points to some new functions avoiding access to the
missing registers. We reuse as much existing PL011 code as possible.

In contrast to the PL011 the SBSA UART does not define any AMBA or
PrimeCell relations, so we go with a pretty generic probe function
which only uses platform device functions.
A DT binding is provided with this patch, ACPI support is added in a
separate one.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Tested-by: Mark Langsdorf <mlangsdo@redhat.com>
Tested-by: Naresh Bhat <nbhat@cavium.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Andre Przywara and committed by
Greg Kroah-Hartman
0dd1e247 cefc2d1d

+181
+10
Documentation/devicetree/bindings/serial/arm_sbsa_uart.txt
··· 1 + * ARM SBSA defined generic UART 2 + This UART uses a subset of the PL011 registers and consequently lives 3 + in the PL011 driver. It's baudrate and other communication parameters 4 + cannot be adjusted at runtime, so it lacks a clock specifier here. 5 + 6 + Required properties: 7 + - compatible: must be "arm,sbsa-uart" 8 + - reg: exactly one register range 9 + - interrupts: exactly one interrupt specifier 10 + - current-speed: the (fixed) baud rate set by the firmware
+171
drivers/tty/serial/amba-pl011.c
··· 101 101 .get_fifosize = get_fifosize_arm, 102 102 }; 103 103 104 + static struct vendor_data vendor_sbsa = { 105 + .oversampling = false, 106 + .dma_threshold = false, 107 + .cts_event_workaround = false, 108 + .always_enabled = true, 109 + .fixed_options = true, 110 + }; 111 + 104 112 static unsigned int get_fifosize_st(struct amba_device *dev) 105 113 { 106 114 return 64; ··· 1649 1641 return retval; 1650 1642 } 1651 1643 1644 + static int sbsa_uart_startup(struct uart_port *port) 1645 + { 1646 + struct uart_amba_port *uap = 1647 + container_of(port, struct uart_amba_port, port); 1648 + int retval; 1649 + 1650 + retval = pl011_hwinit(port); 1651 + if (retval) 1652 + return retval; 1653 + 1654 + retval = pl011_allocate_irq(uap); 1655 + if (retval) 1656 + return retval; 1657 + 1658 + /* The SBSA UART does not support any modem status lines. */ 1659 + uap->old_status = 0; 1660 + 1661 + pl011_enable_interrupts(uap); 1662 + 1663 + return 0; 1664 + } 1665 + 1652 1666 static void pl011_shutdown_channel(struct uart_amba_port *uap, 1653 1667 unsigned int lcrh) 1654 1668 { ··· 1746 1716 if (plat->exit) 1747 1717 plat->exit(); 1748 1718 } 1719 + 1720 + if (uap->port.ops->flush_buffer) 1721 + uap->port.ops->flush_buffer(port); 1722 + } 1723 + 1724 + static void sbsa_uart_shutdown(struct uart_port *port) 1725 + { 1726 + struct uart_amba_port *uap = 1727 + container_of(port, struct uart_amba_port, port); 1728 + 1729 + pl011_disable_interrupts(uap); 1730 + 1731 + free_irq(uap->port.irq, uap); 1749 1732 1750 1733 if (uap->port.ops->flush_buffer) 1751 1734 uap->port.ops->flush_buffer(port); ··· 1915 1872 spin_unlock_irqrestore(&port->lock, flags); 1916 1873 } 1917 1874 1875 + static void 1876 + sbsa_uart_set_termios(struct uart_port *port, struct ktermios *termios, 1877 + struct ktermios *old) 1878 + { 1879 + struct uart_amba_port *uap = 1880 + container_of(port, struct uart_amba_port, port); 1881 + unsigned long flags; 1882 + 1883 + tty_termios_encode_baud_rate(termios, uap->fixed_baud, uap->fixed_baud); 1884 + 1885 + /* The SBSA UART only supports 8n1 without hardware flow control. */ 1886 + termios->c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD); 1887 + termios->c_cflag &= ~(CMSPAR | CRTSCTS); 1888 + termios->c_cflag |= CS8 | CLOCAL; 1889 + 1890 + spin_lock_irqsave(&port->lock, flags); 1891 + uart_update_timeout(port, CS8, uap->fixed_baud); 1892 + pl011_setup_status_masks(port, termios); 1893 + spin_unlock_irqrestore(&port->lock, flags); 1894 + } 1895 + 1918 1896 static const char *pl011_type(struct uart_port *port) 1919 1897 { 1920 1898 struct uart_amba_port *uap = ··· 1999 1935 .shutdown = pl011_shutdown, 2000 1936 .flush_buffer = pl011_dma_flush_buffer, 2001 1937 .set_termios = pl011_set_termios, 1938 + .type = pl011_type, 1939 + .release_port = pl011_release_port, 1940 + .request_port = pl011_request_port, 1941 + .config_port = pl011_config_port, 1942 + .verify_port = pl011_verify_port, 1943 + #ifdef CONFIG_CONSOLE_POLL 1944 + .poll_init = pl011_hwinit, 1945 + .poll_get_char = pl011_get_poll_char, 1946 + .poll_put_char = pl011_put_poll_char, 1947 + #endif 1948 + }; 1949 + 1950 + static void sbsa_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) 1951 + { 1952 + } 1953 + 1954 + static unsigned int sbsa_uart_get_mctrl(struct uart_port *port) 1955 + { 1956 + return 0; 1957 + } 1958 + 1959 + static const struct uart_ops sbsa_uart_pops = { 1960 + .tx_empty = pl011_tx_empty, 1961 + .set_mctrl = sbsa_uart_set_mctrl, 1962 + .get_mctrl = sbsa_uart_get_mctrl, 1963 + .stop_tx = pl011_stop_tx, 1964 + .start_tx = pl011_start_tx, 1965 + .stop_rx = pl011_stop_rx, 1966 + .startup = sbsa_uart_startup, 1967 + .shutdown = sbsa_uart_shutdown, 1968 + .set_termios = sbsa_uart_set_termios, 2002 1969 .type = pl011_type, 2003 1970 .release_port = pl011_release_port, 2004 1971 .request_port = pl011_request_port, ··· 2422 2327 2423 2328 static SIMPLE_DEV_PM_OPS(pl011_dev_pm_ops, pl011_suspend, pl011_resume); 2424 2329 2330 + static int sbsa_uart_probe(struct platform_device *pdev) 2331 + { 2332 + struct uart_amba_port *uap; 2333 + struct resource *r; 2334 + int portnr, ret; 2335 + int baudrate; 2336 + 2337 + /* 2338 + * Check the mandatory baud rate parameter in the DT node early 2339 + * so that we can easily exit with the error. 2340 + */ 2341 + if (pdev->dev.of_node) { 2342 + struct device_node *np = pdev->dev.of_node; 2343 + 2344 + ret = of_property_read_u32(np, "current-speed", &baudrate); 2345 + if (ret) 2346 + return ret; 2347 + } else { 2348 + baudrate = 115200; 2349 + } 2350 + 2351 + portnr = pl011_find_free_port(); 2352 + if (portnr < 0) 2353 + return portnr; 2354 + 2355 + uap = devm_kzalloc(&pdev->dev, sizeof(struct uart_amba_port), 2356 + GFP_KERNEL); 2357 + if (!uap) 2358 + return -ENOMEM; 2359 + 2360 + uap->vendor = &vendor_sbsa; 2361 + uap->fifosize = 32; 2362 + uap->port.irq = platform_get_irq(pdev, 0); 2363 + uap->port.ops = &sbsa_uart_pops; 2364 + uap->fixed_baud = baudrate; 2365 + 2366 + snprintf(uap->type, sizeof(uap->type), "SBSA"); 2367 + 2368 + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 2369 + 2370 + ret = pl011_setup_port(&pdev->dev, uap, r, portnr); 2371 + if (ret) 2372 + return ret; 2373 + 2374 + platform_set_drvdata(pdev, uap); 2375 + 2376 + return pl011_register_port(uap); 2377 + } 2378 + 2379 + static int sbsa_uart_remove(struct platform_device *pdev) 2380 + { 2381 + struct uart_amba_port *uap = platform_get_drvdata(pdev); 2382 + 2383 + uart_remove_one_port(&amba_reg, &uap->port); 2384 + pl011_unregister_port(uap); 2385 + return 0; 2386 + } 2387 + 2388 + static const struct of_device_id sbsa_uart_of_match[] = { 2389 + { .compatible = "arm,sbsa-uart", }, 2390 + {}, 2391 + }; 2392 + MODULE_DEVICE_TABLE(of, sbsa_uart_of_match); 2393 + 2394 + static struct platform_driver arm_sbsa_uart_platform_driver = { 2395 + .probe = sbsa_uart_probe, 2396 + .remove = sbsa_uart_remove, 2397 + .driver = { 2398 + .name = "sbsa-uart", 2399 + .of_match_table = of_match_ptr(sbsa_uart_of_match), 2400 + }, 2401 + }; 2402 + 2425 2403 static struct amba_id pl011_ids[] = { 2426 2404 { 2427 2405 .id = 0x00041011, ··· 2525 2357 { 2526 2358 printk(KERN_INFO "Serial: AMBA PL011 UART driver\n"); 2527 2359 2360 + if (platform_driver_register(&arm_sbsa_uart_platform_driver)) 2361 + pr_warn("could not register SBSA UART platform driver\n"); 2528 2362 return amba_driver_register(&pl011_driver); 2529 2363 } 2530 2364 2531 2365 static void __exit pl011_exit(void) 2532 2366 { 2367 + platform_driver_unregister(&arm_sbsa_uart_platform_driver); 2533 2368 amba_driver_unregister(&pl011_driver); 2534 2369 } 2535 2370