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

tty: serial: 8250: add DFL bus driver for Altera 16550.

Add a Device Feature List (DFL) bus driver for the Altera
16550 implementation of UART.

Signed-off-by: Matthew Gerlach <matthew.gerlach@linux.intel.com>
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Marco Pagani <marpagan@redhat.com>
Link: https://lore.kernel.org/r/20230115151447.1353428-5-matthew.gerlach@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Matthew Gerlach and committed by
Greg Kroah-Hartman
e34a79d0 4747ab89

+180
+167
drivers/tty/serial/8250/8250_dfl.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Driver for FPGA UART 4 + * 5 + * Copyright (C) 2022 Intel Corporation. 6 + * 7 + * Authors: 8 + * Ananda Ravuri <ananda.ravuri@intel.com> 9 + * Matthew Gerlach <matthew.gerlach@linux.intel.com> 10 + */ 11 + 12 + #include <linux/bitfield.h> 13 + #include <linux/device.h> 14 + #include <linux/dfl.h> 15 + #include <linux/errno.h> 16 + #include <linux/ioport.h> 17 + #include <linux/module.h> 18 + #include <linux/mod_devicetable.h> 19 + #include <linux/types.h> 20 + 21 + #include <linux/serial.h> 22 + #include <linux/serial_8250.h> 23 + 24 + #define DFHv1_PARAM_ID_CLK_FRQ 0x2 25 + #define DFHv1_PARAM_ID_FIFO_LEN 0x3 26 + 27 + #define DFHv1_PARAM_ID_REG_LAYOUT 0x4 28 + #define DFHv1_PARAM_REG_LAYOUT_WIDTH GENMASK_ULL(63, 32) 29 + #define DFHv1_PARAM_REG_LAYOUT_SHIFT GENMASK_ULL(31, 0) 30 + 31 + struct dfl_uart { 32 + int line; 33 + }; 34 + 35 + static int dfh_get_u64_param_val(struct dfl_device *dfl_dev, int param_id, u64 *pval) 36 + { 37 + size_t psize; 38 + u64 *p; 39 + 40 + p = dfh_find_param(dfl_dev, param_id, &psize); 41 + if (IS_ERR(p)) 42 + return PTR_ERR(p); 43 + 44 + if (psize != sizeof(*pval)) 45 + return -EINVAL; 46 + 47 + *pval = *p; 48 + 49 + return 0; 50 + } 51 + 52 + static int dfl_uart_get_params(struct dfl_device *dfl_dev, struct uart_8250_port *uart) 53 + { 54 + struct device *dev = &dfl_dev->dev; 55 + u64 fifo_len, clk_freq, reg_layout; 56 + u32 reg_width; 57 + int ret; 58 + 59 + ret = dfh_get_u64_param_val(dfl_dev, DFHv1_PARAM_ID_CLK_FRQ, &clk_freq); 60 + if (ret) 61 + return dev_err_probe(dev, ret, "missing CLK_FRQ param\n"); 62 + 63 + uart->port.uartclk = clk_freq; 64 + 65 + ret = dfh_get_u64_param_val(dfl_dev, DFHv1_PARAM_ID_FIFO_LEN, &fifo_len); 66 + if (ret) 67 + return dev_err_probe(dev, ret, "missing FIFO_LEN param\n"); 68 + 69 + switch (fifo_len) { 70 + case 32: 71 + uart->port.type = PORT_ALTR_16550_F32; 72 + break; 73 + 74 + case 64: 75 + uart->port.type = PORT_ALTR_16550_F64; 76 + break; 77 + 78 + case 128: 79 + uart->port.type = PORT_ALTR_16550_F128; 80 + break; 81 + 82 + default: 83 + return dev_err_probe(dev, -EINVAL, "unsupported FIFO_LEN %llu\n", fifo_len); 84 + } 85 + 86 + ret = dfh_get_u64_param_val(dfl_dev, DFHv1_PARAM_ID_REG_LAYOUT, &reg_layout); 87 + if (ret) 88 + return dev_err_probe(dev, ret, "missing REG_LAYOUT param\n"); 89 + 90 + uart->port.regshift = FIELD_GET(DFHv1_PARAM_REG_LAYOUT_SHIFT, reg_layout); 91 + reg_width = FIELD_GET(DFHv1_PARAM_REG_LAYOUT_WIDTH, reg_layout); 92 + switch (reg_width) { 93 + case 4: 94 + uart->port.iotype = UPIO_MEM32; 95 + break; 96 + 97 + case 2: 98 + uart->port.iotype = UPIO_MEM16; 99 + break; 100 + 101 + default: 102 + return dev_err_probe(dev, -EINVAL, "unsupported reg-width %u\n", reg_width); 103 + 104 + } 105 + 106 + return 0; 107 + } 108 + 109 + static int dfl_uart_probe(struct dfl_device *dfl_dev) 110 + { 111 + struct device *dev = &dfl_dev->dev; 112 + struct uart_8250_port uart = { }; 113 + struct dfl_uart *dfluart; 114 + int ret; 115 + 116 + uart.port.flags = UPF_IOREMAP; 117 + uart.port.mapbase = dfl_dev->mmio_res.start; 118 + uart.port.mapsize = resource_size(&dfl_dev->mmio_res); 119 + 120 + ret = dfl_uart_get_params(dfl_dev, &uart); 121 + if (ret < 0) 122 + return dev_err_probe(dev, ret, "failed uart feature walk\n"); 123 + 124 + if (dfl_dev->num_irqs == 1) 125 + uart.port.irq = dfl_dev->irqs[0]; 126 + 127 + dfluart = devm_kzalloc(dev, sizeof(*dfluart), GFP_KERNEL); 128 + if (!dfluart) 129 + return -ENOMEM; 130 + 131 + dfluart->line = serial8250_register_8250_port(&uart); 132 + if (dfluart->line < 0) 133 + return dev_err_probe(dev, dfluart->line, "unable to register 8250 port.\n"); 134 + 135 + dev_set_drvdata(dev, dfluart); 136 + 137 + return 0; 138 + } 139 + 140 + static void dfl_uart_remove(struct dfl_device *dfl_dev) 141 + { 142 + struct dfl_uart *dfluart = dev_get_drvdata(&dfl_dev->dev); 143 + 144 + serial8250_unregister_port(dfluart->line); 145 + } 146 + 147 + #define FME_FEATURE_ID_UART 0x24 148 + 149 + static const struct dfl_device_id dfl_uart_ids[] = { 150 + { FME_ID, FME_FEATURE_ID_UART }, 151 + { } 152 + }; 153 + MODULE_DEVICE_TABLE(dfl, dfl_uart_ids); 154 + 155 + static struct dfl_driver dfl_uart_driver = { 156 + .drv = { 157 + .name = "dfl-uart", 158 + }, 159 + .id_table = dfl_uart_ids, 160 + .probe = dfl_uart_probe, 161 + .remove = dfl_uart_remove, 162 + }; 163 + module_dfl_driver(dfl_uart_driver); 164 + 165 + MODULE_DESCRIPTION("DFL Intel UART driver"); 166 + MODULE_AUTHOR("Intel Corporation"); 167 + MODULE_LICENSE("GPL");
+12
drivers/tty/serial/8250/Kconfig
··· 370 370 erratum for Freescale 16550 UARTs in the 8250 driver. It also 371 371 enables support for ACPI enumeration. 372 372 373 + config SERIAL_8250_DFL 374 + tristate "DFL bus driver for Altera 16550 UART" 375 + depends on SERIAL_8250 && FPGA_DFL 376 + help 377 + This option enables support for a Device Feature List (DFL) bus 378 + driver for the Altera 16550 UART. One or more Altera 16550 UARTs 379 + can be instantiated in a FPGA and then be discovered during 380 + enumeration of the DFL bus. 381 + 382 + To compile this driver as a module, chose M here: the 383 + module will be called 8250_dfl. 384 + 373 385 config SERIAL_8250_DW 374 386 tristate "Support for Synopsys DesignWare 8250 quirks" 375 387 depends on SERIAL_8250
+1
drivers/tty/serial/8250/Makefile
··· 28 28 obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o 29 29 obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o 30 30 obj-$(CONFIG_SERIAL_8250_MEN_MCB) += 8250_men_mcb.o 31 + obj-$(CONFIG_SERIAL_8250_DFL) += 8250_dfl.o 31 32 obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o 32 33 obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o 33 34 obj-$(CONFIG_SERIAL_8250_IOC3) += 8250_ioc3.o