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

serial: qcom-geni: Enable Serial on SA8255p Qualcomm platforms

The Qualcomm automotive SA8255p SoC relies on firmware to configure
platform resources, including clocks, interconnects and TLMM.
The driver requests resources operations over SCMI using power
and performance protocols.

The SCMI power protocol enables or disables resources like clocks,
interconnect paths, and TLMM (GPIOs) using runtime PM framework APIs,
such as resume/suspend, to control power states(on/off).

The SCMI performance protocol manages UART baud rates, with each baud
rate represented by a performance level. The driver uses the
dev_pm_opp_set_level() API to request the desired baud rate by
specifying the performance level.

Reviewed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Signed-off-by: Praveen Talari <quic_ptalari@quicinc.com>
Link: https://lore.kernel.org/r/20250721174532.14022-9-quic_ptalari@quicinc.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Praveen Talari and committed by
Greg Kroah-Hartman
86fa39dd 1afa7063

+140 -16
+140 -16
drivers/tty/serial/qcom_geni_serial.c
··· 11 11 #include <linux/irq.h> 12 12 #include <linux/module.h> 13 13 #include <linux/of.h> 14 + #include <linux/pm_domain.h> 14 15 #include <linux/pm_opp.h> 15 16 #include <linux/platform_device.h> 16 17 #include <linux/pm_runtime.h> ··· 100 99 #define DMA_RX_BUF_SIZE 2048 101 100 102 101 static DEFINE_IDA(port_ida); 102 + #define DOMAIN_IDX_POWER 0 103 + #define DOMAIN_IDX_PERF 1 103 104 104 105 struct qcom_geni_device_data { 105 106 bool console; 106 107 enum geni_se_xfer_mode mode; 108 + struct dev_pm_domain_attach_data pd_data; 109 + int (*resources_init)(struct uart_port *uport); 110 + int (*set_rate)(struct uart_port *uport, unsigned int baud); 111 + int (*power_state)(struct uart_port *uport, bool state); 107 112 }; 108 113 109 114 struct qcom_geni_private_data { ··· 147 140 148 141 struct qcom_geni_private_data private_data; 149 142 const struct qcom_geni_device_data *dev_data; 143 + struct dev_pm_domain_list *pd_list; 150 144 }; 151 145 152 146 static const struct uart_ops qcom_geni_console_pops; ··· 1370 1362 return 0; 1371 1363 } 1372 1364 1365 + static int geni_serial_set_level(struct uart_port *uport, unsigned int baud) 1366 + { 1367 + struct qcom_geni_serial_port *port = to_dev_port(uport); 1368 + struct device *perf_dev = port->pd_list->pd_devs[DOMAIN_IDX_PERF]; 1369 + 1370 + /* 1371 + * The performance protocol sets UART communication 1372 + * speeds by selecting different performance levels 1373 + * through the OPP framework. 1374 + * 1375 + * Supported perf levels for baudrates in firmware are below 1376 + * +---------------------+--------------------+ 1377 + * | Perf level value | Baudrate values | 1378 + * +---------------------+--------------------+ 1379 + * | 300 | 300 | 1380 + * | 1200 | 1200 | 1381 + * | 2400 | 2400 | 1382 + * | 4800 | 4800 | 1383 + * | 9600 | 9600 | 1384 + * | 19200 | 19200 | 1385 + * | 38400 | 38400 | 1386 + * | 57600 | 57600 | 1387 + * | 115200 | 115200 | 1388 + * | 230400 | 230400 | 1389 + * | 460800 | 460800 | 1390 + * | 921600 | 921600 | 1391 + * | 2000000 | 2000000 | 1392 + * | 3000000 | 3000000 | 1393 + * | 3200000 | 3200000 | 1394 + * | 4000000 | 4000000 | 1395 + * +---------------------+--------------------+ 1396 + */ 1397 + 1398 + return dev_pm_opp_set_level(perf_dev, baud); 1399 + } 1400 + 1373 1401 static void qcom_geni_serial_set_termios(struct uart_port *uport, 1374 1402 struct ktermios *termios, 1375 1403 const struct ktermios *old) ··· 1424 1380 /* baud rate */ 1425 1381 baud = uart_get_baud_rate(uport, termios, old, 300, 8000000); 1426 1382 1427 - ret = geni_serial_set_rate(uport, baud); 1383 + ret = port->dev_data->set_rate(uport, baud); 1428 1384 if (ret) 1429 1385 return; 1430 1386 ··· 1711 1667 return 0; 1712 1668 } 1713 1669 1714 - static int geni_serial_resource_init(struct qcom_geni_serial_port *port) 1670 + static int geni_serial_resource_state(struct uart_port *uport, bool power_on) 1715 1671 { 1672 + return power_on ? geni_serial_resources_on(uport) : geni_serial_resources_off(uport); 1673 + } 1674 + 1675 + static int geni_serial_pwr_init(struct uart_port *uport) 1676 + { 1677 + struct qcom_geni_serial_port *port = to_dev_port(uport); 1678 + int ret; 1679 + 1680 + ret = dev_pm_domain_attach_list(port->se.dev, 1681 + &port->dev_data->pd_data, &port->pd_list); 1682 + if (ret <= 0) 1683 + return -EINVAL; 1684 + 1685 + return 0; 1686 + } 1687 + 1688 + static int geni_serial_resource_init(struct uart_port *uport) 1689 + { 1690 + struct qcom_geni_serial_port *port = to_dev_port(uport); 1716 1691 int ret; 1717 1692 1718 1693 port->se.clk = devm_clk_get(port->se.dev, "se"); ··· 1882 1819 port->se.dev = &pdev->dev; 1883 1820 port->se.wrapper = dev_get_drvdata(pdev->dev.parent); 1884 1821 1885 - ret = geni_serial_resource_init(port); 1822 + ret = port->dev_data->resources_init(uport); 1886 1823 if (ret) 1887 1824 return ret; 1888 1825 1889 1826 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1890 - if (!res) 1891 - return -EINVAL; 1827 + if (!res) { 1828 + ret = -EINVAL; 1829 + goto error; 1830 + } 1831 + 1892 1832 uport->mapbase = res->start; 1893 1833 1894 1834 uport->rs485_config = qcom_geni_rs485_config; ··· 1903 1837 if (!data->console) { 1904 1838 port->rx_buf = devm_kzalloc(uport->dev, 1905 1839 DMA_RX_BUF_SIZE, GFP_KERNEL); 1906 - if (!port->rx_buf) 1907 - return -ENOMEM; 1840 + if (!port->rx_buf) { 1841 + ret = -ENOMEM; 1842 + goto error; 1843 + } 1908 1844 } 1909 1845 1910 1846 port->name = devm_kasprintf(uport->dev, GFP_KERNEL, 1911 1847 "qcom_geni_serial_%s%d", 1912 1848 uart_console(uport) ? "console" : "uart", uport->line); 1913 - if (!port->name) 1914 - return -ENOMEM; 1849 + if (!port->name) { 1850 + ret = -ENOMEM; 1851 + goto error; 1852 + } 1915 1853 1916 1854 irq = platform_get_irq(pdev, 0); 1917 - if (irq < 0) 1918 - return irq; 1855 + if (irq < 0) { 1856 + ret = irq; 1857 + goto error; 1858 + } 1859 + 1919 1860 uport->irq = irq; 1920 1861 uport->has_sysrq = IS_ENABLED(CONFIG_SERIAL_QCOM_GENI_CONSOLE); 1921 1862 ··· 1944 1871 IRQF_TRIGGER_HIGH, port->name, uport); 1945 1872 if (ret) { 1946 1873 dev_err(uport->dev, "Failed to get IRQ ret %d\n", ret); 1947 - return ret; 1874 + goto error; 1948 1875 } 1949 1876 1950 1877 ret = uart_get_rs485_mode(uport); ··· 1955 1882 1956 1883 ret = uart_add_one_port(drv, uport); 1957 1884 if (ret) 1958 - return ret; 1885 + goto error; 1959 1886 1960 1887 if (port->wakeup_irq > 0) { 1961 1888 device_init_wakeup(&pdev->dev, true); ··· 1965 1892 device_init_wakeup(&pdev->dev, false); 1966 1893 ida_free(&port_ida, uport->line); 1967 1894 uart_remove_one_port(drv, uport); 1968 - return ret; 1895 + goto error; 1969 1896 } 1970 1897 } 1971 1898 1972 1899 return 0; 1900 + 1901 + error: 1902 + dev_pm_domain_detach_list(port->pd_list); 1903 + return ret; 1973 1904 } 1974 1905 1975 1906 static void qcom_geni_serial_remove(struct platform_device *pdev) ··· 1986 1909 device_init_wakeup(&pdev->dev, false); 1987 1910 ida_free(&port_ida, uport->line); 1988 1911 uart_remove_one_port(drv, &port->uport); 1912 + dev_pm_domain_detach_list(port->pd_list); 1989 1913 } 1990 1914 1991 1915 static int __maybe_unused qcom_geni_serial_runtime_suspend(struct device *dev) 1992 1916 { 1993 1917 struct qcom_geni_serial_port *port = dev_get_drvdata(dev); 1994 1918 struct uart_port *uport = &port->uport; 1919 + int ret = 0; 1995 1920 1996 - return geni_serial_resources_off(uport); 1921 + if (port->dev_data->power_state) 1922 + ret = port->dev_data->power_state(uport, false); 1923 + 1924 + return ret; 1997 1925 } 1998 1926 1999 1927 static int __maybe_unused qcom_geni_serial_runtime_resume(struct device *dev) 2000 1928 { 2001 1929 struct qcom_geni_serial_port *port = dev_get_drvdata(dev); 2002 1930 struct uart_port *uport = &port->uport; 1931 + int ret = 0; 2003 1932 2004 - return geni_serial_resources_on(uport); 1933 + if (port->dev_data->power_state) 1934 + ret = port->dev_data->power_state(uport, true); 1935 + 1936 + return ret; 2005 1937 } 2006 1938 2007 1939 static int qcom_geni_serial_suspend(struct device *dev) ··· 2048 1962 static const struct qcom_geni_device_data qcom_geni_console_data = { 2049 1963 .console = true, 2050 1964 .mode = GENI_SE_FIFO, 1965 + .resources_init = geni_serial_resource_init, 1966 + .set_rate = geni_serial_set_rate, 1967 + .power_state = geni_serial_resource_state, 2051 1968 }; 2052 1969 2053 1970 static const struct qcom_geni_device_data qcom_geni_uart_data = { 2054 1971 .console = false, 2055 1972 .mode = GENI_SE_DMA, 1973 + .resources_init = geni_serial_resource_init, 1974 + .set_rate = geni_serial_set_rate, 1975 + .power_state = geni_serial_resource_state, 1976 + }; 1977 + 1978 + static const struct qcom_geni_device_data sa8255p_qcom_geni_console_data = { 1979 + .console = true, 1980 + .mode = GENI_SE_FIFO, 1981 + .pd_data = { 1982 + .pd_flags = PD_FLAG_DEV_LINK_ON, 1983 + .pd_names = (const char*[]) { "power", "perf" }, 1984 + .num_pd_names = 2, 1985 + }, 1986 + .resources_init = geni_serial_pwr_init, 1987 + .set_rate = geni_serial_set_level, 1988 + }; 1989 + 1990 + static const struct qcom_geni_device_data sa8255p_qcom_geni_uart_data = { 1991 + .console = false, 1992 + .mode = GENI_SE_DMA, 1993 + .pd_data = { 1994 + .pd_flags = PD_FLAG_DEV_LINK_ON, 1995 + .pd_names = (const char*[]) { "power", "perf" }, 1996 + .num_pd_names = 2, 1997 + }, 1998 + .resources_init = geni_serial_pwr_init, 1999 + .set_rate = geni_serial_set_level, 2056 2000 }; 2057 2001 2058 2002 static const struct dev_pm_ops qcom_geni_serial_pm_ops = { ··· 2097 1981 .data = &qcom_geni_console_data, 2098 1982 }, 2099 1983 { 1984 + .compatible = "qcom,sa8255p-geni-debug-uart", 1985 + .data = &sa8255p_qcom_geni_console_data, 1986 + }, 1987 + { 2100 1988 .compatible = "qcom,geni-uart", 2101 1989 .data = &qcom_geni_uart_data, 1990 + }, 1991 + { 1992 + .compatible = "qcom,sa8255p-geni-uart", 1993 + .data = &sa8255p_qcom_geni_uart_data, 2102 1994 }, 2103 1995 {} 2104 1996 };