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

serial: 8250_pci1xxxx: Add driver for quad-uart support

pci1xxxx is a PCIe switch with a multi-function endpoint on one of
its downstream ports. Quad-uart is one of the functions in the
multi-function endpoint. This driver loads for the quad-uart and
enumerates single or multiple instances of uart based on the PCIe
subsystem device ID.

Co-developed-by: Tharun Kumar P <tharunkumar.pasumarthi@microchip.com>
Signed-off-by: Tharun Kumar P <tharunkumar.pasumarthi@microchip.com>
Signed-off-by: Kumaravel Thiagarajan <kumaravel.thiagarajan@microchip.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Link: https://lore.kernel.org/r/20230207164814.3104605-3-kumaravel.thiagarajan@microchip.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Kumaravel Thiagarajan and committed by
Greg Kroah-Hartman
32bb477f 0348386d

+359
+7
MAINTAINERS
··· 13799 13799 S: Maintained 13800 13800 F: drivers/i2c/busses/i2c-mchp-pci1xxxx.c 13801 13801 13802 + MICROCHIP PCIe UART DRIVER 13803 + M: Kumaravel Thiagarajan <kumaravel.thiagarajan@microchip.com> 13804 + M: Tharun Kumar P <tharunkumar.pasumarthi@microchip.com> 13805 + L: linux-serial@vger.kernel.org 13806 + S: Maintained 13807 + F: drivers/tty/serial/8250/8250_pci1xxxx.c 13808 + 13802 13809 MICROCHIP PWM DRIVER 13803 13810 M: Claudiu Beznea <claudiu.beznea@microchip.com> 13804 13811 L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+329
drivers/tty/serial/8250/8250_pci1xxxx.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Probe module for 8250/16550-type MCHP PCI serial ports. 4 + * 5 + * Based on drivers/tty/serial/8250/8250_pci.c, 6 + * 7 + * Copyright (C) 2022 Microchip Technology Inc., All Rights Reserved. 8 + */ 9 + 10 + #include <linux/bitfield.h> 11 + #include <linux/bitops.h> 12 + #include <linux/io.h> 13 + #include <linux/kernel.h> 14 + #include <linux/module.h> 15 + #include <linux/pci.h> 16 + #include <linux/serial_core.h> 17 + #include <linux/slab.h> 18 + #include <linux/string.h> 19 + #include <linux/units.h> 20 + #include <linux/tty.h> 21 + 22 + #include <asm/byteorder.h> 23 + 24 + #include "8250.h" 25 + #include "8250_pcilib.h" 26 + 27 + #define PCI_DEVICE_ID_EFAR_PCI12000 0xa002 28 + #define PCI_DEVICE_ID_EFAR_PCI11010 0xa012 29 + #define PCI_DEVICE_ID_EFAR_PCI11101 0xa022 30 + #define PCI_DEVICE_ID_EFAR_PCI11400 0xa032 31 + #define PCI_DEVICE_ID_EFAR_PCI11414 0xa042 32 + 33 + #define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_4p 0x0001 34 + #define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p012 0x0002 35 + #define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p013 0x0003 36 + #define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p023 0x0004 37 + #define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p123 0x0005 38 + #define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p01 0x0006 39 + #define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p02 0x0007 40 + #define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p03 0x0008 41 + #define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p12 0x0009 42 + #define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p13 0x000a 43 + #define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p23 0x000b 44 + #define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p0 0x000c 45 + #define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p1 0x000d 46 + #define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p2 0x000e 47 + #define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p3 0x000f 48 + 49 + #define PCI_SUBDEVICE_ID_EFAR_PCI12000 PCI_DEVICE_ID_EFAR_PCI12000 50 + #define PCI_SUBDEVICE_ID_EFAR_PCI11010 PCI_DEVICE_ID_EFAR_PCI11010 51 + #define PCI_SUBDEVICE_ID_EFAR_PCI11101 PCI_DEVICE_ID_EFAR_PCI11101 52 + #define PCI_SUBDEVICE_ID_EFAR_PCI11400 PCI_DEVICE_ID_EFAR_PCI11400 53 + #define PCI_SUBDEVICE_ID_EFAR_PCI11414 PCI_DEVICE_ID_EFAR_PCI11414 54 + 55 + #define UART_ACTV_REG 0x11 56 + #define UART_BLOCK_SET_ACTIVE BIT(0) 57 + 58 + #define UART_PCI_CTRL_REG 0x80 59 + #define UART_PCI_CTRL_SET_MULTIPLE_MSI BIT(4) 60 + #define UART_PCI_CTRL_D3_CLK_ENABLE BIT(0) 61 + 62 + #define ADCL_CFG_REG 0x40 63 + #define ADCL_CFG_POL_SEL BIT(2) 64 + #define ADCL_CFG_PIN_SEL BIT(1) 65 + #define ADCL_CFG_EN BIT(0) 66 + 67 + #define UART_BIT_SAMPLE_CNT 16 68 + #define BAUD_CLOCK_DIV_INT_MSK GENMASK(31, 8) 69 + #define ADCL_CFG_RTS_DELAY_MASK GENMASK(11, 8) 70 + #define UART_CLOCK_DEFAULT (62500 * HZ_PER_KHZ) 71 + 72 + #define UART_WAKE_REG 0x8C 73 + #define UART_WAKE_MASK_REG 0x90 74 + #define UART_WAKE_N_PIN BIT(2) 75 + #define UART_WAKE_NCTS BIT(1) 76 + #define UART_WAKE_INT BIT(0) 77 + #define UART_WAKE_SRCS \ 78 + (UART_WAKE_N_PIN | UART_WAKE_NCTS | UART_WAKE_INT) 79 + 80 + #define UART_BAUD_CLK_DIVISOR_REG 0x54 81 + 82 + #define UART_RESET_REG 0x94 83 + #define UART_RESET_D3_RESET_DISABLE BIT(16) 84 + 85 + #define MAX_PORTS 4 86 + #define PORT_OFFSET 0x100 87 + 88 + static const int logical_to_physical_port_idx[][MAX_PORTS] = { 89 + {0, 1, 2, 3}, /* PCI12000, PCI11010, PCI11101, PCI11400, PCI11414 */ 90 + {0, 1, 2, 3}, /* PCI4p */ 91 + {0, 1, 2, -1}, /* PCI3p012 */ 92 + {0, 1, 3, -1}, /* PCI3p013 */ 93 + {0, 2, 3, -1}, /* PCI3p023 */ 94 + {1, 2, 3, -1}, /* PCI3p123 */ 95 + {0, 1, -1, -1}, /* PCI2p01 */ 96 + {0, 2, -1, -1}, /* PCI2p02 */ 97 + {0, 3, -1, -1}, /* PCI2p03 */ 98 + {1, 2, -1, -1}, /* PCI2p12 */ 99 + {1, 3, -1, -1}, /* PCI2p13 */ 100 + {2, 3, -1, -1}, /* PCI2p23 */ 101 + {0, -1, -1, -1}, /* PCI1p0 */ 102 + {1, -1, -1, -1}, /* PCI1p1 */ 103 + {2, -1, -1, -1}, /* PCI1p2 */ 104 + {3, -1, -1, -1}, /* PCI1p3 */ 105 + }; 106 + 107 + struct pci1xxxx_8250 { 108 + unsigned int nr; 109 + void __iomem *membase; 110 + int line[]; 111 + }; 112 + 113 + static int pci1xxxx_get_num_ports(struct pci_dev *dev) 114 + { 115 + switch (dev->subsystem_device) { 116 + case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p0: 117 + case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p1: 118 + case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p2: 119 + case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p3: 120 + case PCI_SUBDEVICE_ID_EFAR_PCI12000: 121 + case PCI_SUBDEVICE_ID_EFAR_PCI11010: 122 + case PCI_SUBDEVICE_ID_EFAR_PCI11101: 123 + case PCI_SUBDEVICE_ID_EFAR_PCI11400: 124 + default: 125 + return 1; 126 + case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p01: 127 + case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p02: 128 + case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p03: 129 + case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p12: 130 + case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p13: 131 + case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p23: 132 + return 2; 133 + case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p012: 134 + case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p123: 135 + case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p013: 136 + case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p023: 137 + return 3; 138 + case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_4p: 139 + case PCI_SUBDEVICE_ID_EFAR_PCI11414: 140 + return 4; 141 + } 142 + } 143 + 144 + static unsigned int pci1xxxx_get_divisor(struct uart_port *port, 145 + unsigned int baud, unsigned int *frac) 146 + { 147 + unsigned int quot; 148 + 149 + /* 150 + * Calculate baud rate sampling period in nanoseconds. 151 + * Fractional part x denotes x/255 parts of a nanosecond. 152 + */ 153 + quot = NSEC_PER_SEC / (baud * UART_BIT_SAMPLE_CNT); 154 + *frac = (NSEC_PER_SEC - quot * baud * UART_BIT_SAMPLE_CNT) * 155 + 255 / UART_BIT_SAMPLE_CNT / baud; 156 + 157 + return quot; 158 + } 159 + 160 + static void pci1xxxx_set_divisor(struct uart_port *port, unsigned int baud, 161 + unsigned int quot, unsigned int frac) 162 + { 163 + writel(FIELD_PREP(BAUD_CLOCK_DIV_INT_MSK, quot) | frac, 164 + port->membase + UART_BAUD_CLK_DIVISOR_REG); 165 + } 166 + 167 + static int pci1xxxx_setup(struct pci_dev *pdev, 168 + struct uart_8250_port *port, int port_idx) 169 + { 170 + int ret; 171 + 172 + port->port.flags |= UPF_FIXED_TYPE | UPF_SKIP_TEST; 173 + port->port.type = PORT_MCHP16550A; 174 + port->port.set_termios = serial8250_do_set_termios; 175 + port->port.get_divisor = pci1xxxx_get_divisor; 176 + port->port.set_divisor = pci1xxxx_set_divisor; 177 + 178 + ret = serial8250_pci_setup_port(pdev, port, 0, PORT_OFFSET * port_idx, 0); 179 + if (ret < 0) 180 + return ret; 181 + 182 + writeb(UART_BLOCK_SET_ACTIVE, port->port.membase + UART_ACTV_REG); 183 + writeb(UART_WAKE_SRCS, port->port.membase + UART_WAKE_REG); 184 + writeb(UART_WAKE_N_PIN, port->port.membase + UART_WAKE_MASK_REG); 185 + 186 + return 0; 187 + } 188 + 189 + static unsigned int pci1xxxx_get_max_port(int subsys_dev) 190 + { 191 + unsigned int i = MAX_PORTS; 192 + 193 + if (subsys_dev < ARRAY_SIZE(logical_to_physical_port_idx)) 194 + while (i--) { 195 + if (logical_to_physical_port_idx[subsys_dev][i] != -1) 196 + return logical_to_physical_port_idx[subsys_dev][i] + 1; 197 + } 198 + 199 + if (subsys_dev == PCI_SUBDEVICE_ID_EFAR_PCI11414) 200 + return 4; 201 + 202 + return 1; 203 + } 204 + 205 + static int pci1xxxx_logical_to_physical_port_translate(int subsys_dev, int port) 206 + { 207 + if (subsys_dev < ARRAY_SIZE(logical_to_physical_port_idx)) 208 + return logical_to_physical_port_idx[subsys_dev][port]; 209 + 210 + return logical_to_physical_port_idx[0][port]; 211 + } 212 + 213 + static int pci1xxxx_serial_probe(struct pci_dev *pdev, 214 + const struct pci_device_id *id) 215 + { 216 + struct device *dev = &pdev->dev; 217 + struct pci1xxxx_8250 *priv; 218 + struct uart_8250_port uart; 219 + unsigned int max_vec_reqd; 220 + unsigned int nr_ports, i; 221 + int num_vectors; 222 + int subsys_dev; 223 + int port_idx; 224 + int rc; 225 + 226 + rc = pcim_enable_device(pdev); 227 + if (rc) 228 + return rc; 229 + 230 + nr_ports = pci1xxxx_get_num_ports(pdev); 231 + 232 + priv = devm_kzalloc(dev, struct_size(priv, line, nr_ports), GFP_KERNEL); 233 + if (!priv) 234 + return -ENOMEM; 235 + 236 + priv->membase = pci_ioremap_bar(pdev, 0); 237 + if (!priv->membase) 238 + return -ENOMEM; 239 + 240 + pci_set_master(pdev); 241 + 242 + priv->nr = nr_ports; 243 + 244 + subsys_dev = pdev->subsystem_device; 245 + max_vec_reqd = pci1xxxx_get_max_port(subsys_dev); 246 + 247 + num_vectors = pci_alloc_irq_vectors(pdev, 1, max_vec_reqd, PCI_IRQ_ALL_TYPES); 248 + if (num_vectors < 0) { 249 + pci_iounmap(pdev, priv->membase); 250 + return num_vectors; 251 + } 252 + 253 + memset(&uart, 0, sizeof(uart)); 254 + uart.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT; 255 + uart.port.uartclk = UART_CLOCK_DEFAULT; 256 + uart.port.dev = dev; 257 + 258 + if (num_vectors == max_vec_reqd) 259 + writeb(UART_PCI_CTRL_SET_MULTIPLE_MSI, priv->membase + UART_PCI_CTRL_REG); 260 + 261 + for (i = 0; i < nr_ports; i++) { 262 + priv->line[i] = -ENODEV; 263 + 264 + port_idx = pci1xxxx_logical_to_physical_port_translate(subsys_dev, i); 265 + 266 + if (num_vectors == max_vec_reqd) 267 + uart.port.irq = pci_irq_vector(pdev, port_idx); 268 + else 269 + uart.port.irq = pci_irq_vector(pdev, 0); 270 + 271 + rc = pci1xxxx_setup(pdev, &uart, port_idx); 272 + if (rc) { 273 + dev_warn(dev, "Failed to setup port %u\n", i); 274 + continue; 275 + } 276 + 277 + priv->line[i] = serial8250_register_8250_port(&uart); 278 + if (priv->line[i] < 0) { 279 + dev_warn(dev, 280 + "Couldn't register serial port %lx, irq %d, type %d, error %d\n", 281 + uart.port.iobase, uart.port.irq, uart.port.iotype, 282 + priv->line[i]); 283 + } 284 + } 285 + 286 + pci_set_drvdata(pdev, priv); 287 + 288 + return 0; 289 + } 290 + 291 + static void pci1xxxx_serial_remove(struct pci_dev *dev) 292 + { 293 + struct pci1xxxx_8250 *priv = pci_get_drvdata(dev); 294 + unsigned int i; 295 + 296 + for (i = 0; i < priv->nr; i++) { 297 + if (priv->line[i] >= 0) 298 + serial8250_unregister_port(priv->line[i]); 299 + } 300 + 301 + pci_free_irq_vectors(dev); 302 + pci_iounmap(dev, priv->membase); 303 + } 304 + 305 + static const struct pci_device_id pci1xxxx_pci_tbl[] = { 306 + { PCI_VDEVICE(EFAR, PCI_DEVICE_ID_EFAR_PCI11010) }, 307 + { PCI_VDEVICE(EFAR, PCI_DEVICE_ID_EFAR_PCI11101) }, 308 + { PCI_VDEVICE(EFAR, PCI_DEVICE_ID_EFAR_PCI11400) }, 309 + { PCI_VDEVICE(EFAR, PCI_DEVICE_ID_EFAR_PCI11414) }, 310 + { PCI_VDEVICE(EFAR, PCI_DEVICE_ID_EFAR_PCI12000) }, 311 + {} 312 + }; 313 + MODULE_DEVICE_TABLE(pci, pci1xxxx_pci_tbl); 314 + 315 + static struct pci_driver pci1xxxx_pci_driver = { 316 + .name = "pci1xxxx serial", 317 + .probe = pci1xxxx_serial_probe, 318 + .remove = pci1xxxx_serial_remove, 319 + .id_table = pci1xxxx_pci_tbl, 320 + }; 321 + module_pci_driver(pci1xxxx_pci_driver); 322 + 323 + static_assert((ARRAY_SIZE(logical_to_physical_port_idx) == PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p3 + 1)); 324 + 325 + MODULE_IMPORT_NS(SERIAL_8250_PCI); 326 + MODULE_DESCRIPTION("Microchip Technology Inc. PCIe to UART module"); 327 + MODULE_AUTHOR("Kumaravel Thiagarajan <kumaravel.thiagarajan@microchip.com>"); 328 + MODULE_AUTHOR("Tharun Kumar P <tharunkumar.pasumarthi@microchip.com>"); 329 + MODULE_LICENSE("GPL");
+8
drivers/tty/serial/8250/8250_port.c
··· 313 313 .rxtrig_bytes = {1, 4, 8, 14}, 314 314 .flags = UART_CAP_FIFO, 315 315 }, 316 + [PORT_MCHP16550A] = { 317 + .name = "MCHP16550A", 318 + .fifo_size = 256, 319 + .tx_loadsz = 256, 320 + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01, 321 + .rxtrig_bytes = {2, 66, 130, 194}, 322 + .flags = UART_CAP_FIFO, 323 + }, 316 324 }; 317 325 318 326 /* Uart divisor latch read */
+11
drivers/tty/serial/8250/Kconfig
··· 295 295 To compile this driver as a module, choose M here: the module 296 296 will be called 8250_hub6. 297 297 298 + config SERIAL_8250_PCI1XXXX 299 + tristate "Microchip 8250 based serial port" 300 + depends on SERIAL_8250 && PCI 301 + select SERIAL_8250_PCILIB 302 + default SERIAL_8250 303 + help 304 + Select this option if you have a setup with Microchip PCIe 305 + Switch with serial port enabled and wish to enable 8250 306 + serial driver for the serial interface. This driver support 307 + will ensure to support baud rates upto 1.5Mpbs. 308 + 298 309 # 299 310 # Misc. options/drivers. 300 311 #
+1
drivers/tty/serial/8250/Makefile
··· 27 27 obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o 28 28 obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o 29 29 obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o 30 + obj-$(CONFIG_SERIAL_8250_PCI1XXXX) += 8250_pci1xxxx.o 30 31 obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o 31 32 obj-$(CONFIG_SERIAL_8250_MEN_MCB) += 8250_men_mcb.o 32 33 obj-$(CONFIG_SERIAL_8250_DFL) += 8250_dfl.o
+3
include/uapi/linux/serial_core.h
··· 207 207 /* Atheros AR933X SoC */ 208 208 #define PORT_AR933X 99 209 209 210 + /* MCHP 16550A UART with 256 byte FIFOs */ 211 + #define PORT_MCHP16550A 100 212 + 210 213 /* ARC (Synopsys) on-chip UART */ 211 214 #define PORT_ARC 101 212 215