diff options
Diffstat (limited to 'drivers/tty/serial/8250')
23 files changed, 1042 insertions, 621 deletions
diff --git a/drivers/tty/serial/8250/8250_aspeed_vuart.c b/drivers/tty/serial/8250/8250_aspeed_vuart.c index 0438d9a905ce..d657aa14c3e4 100644 --- a/drivers/tty/serial/8250/8250_aspeed_vuart.c +++ b/drivers/tty/serial/8250/8250_aspeed_vuart.c @@ -5,15 +5,13 @@ * Copyright (C) 2016 Jeremy Kerr <jk@ozlabs.org>, IBM Corp. * Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de>, IBM Corp. */ -#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - #include <linux/device.h> #include <linux/module.h> #include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/of_platform.h> +#include <linux/regmap.h> +#include <linux/mfd/syscon.h> #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/clk.h> @@ -22,6 +20,7 @@ #define ASPEED_VUART_GCRA 0x20 #define ASPEED_VUART_GCRA_VUART_EN BIT(0) +#define ASPEED_VUART_GCRA_HOST_SIRQ_POLARITY BIT(1) #define ASPEED_VUART_GCRA_DISABLE_HOST_TX_DISCARD BIT(5) #define ASPEED_VUART_GCRB 0x24 #define ASPEED_VUART_GCRB_HOST_SIRQ_MASK GENMASK(7, 4) @@ -131,8 +130,53 @@ static ssize_t sirq_store(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR_RW(sirq); +static ssize_t sirq_polarity_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aspeed_vuart *vuart = dev_get_drvdata(dev); + u8 reg; + + reg = readb(vuart->regs + ASPEED_VUART_GCRA); + reg &= ASPEED_VUART_GCRA_HOST_SIRQ_POLARITY; + + return snprintf(buf, PAGE_SIZE - 1, "%u\n", reg ? 1 : 0); +} + +static void aspeed_vuart_set_sirq_polarity(struct aspeed_vuart *vuart, + bool polarity) +{ + u8 reg = readb(vuart->regs + ASPEED_VUART_GCRA); + + if (polarity) + reg |= ASPEED_VUART_GCRA_HOST_SIRQ_POLARITY; + else + reg &= ~ASPEED_VUART_GCRA_HOST_SIRQ_POLARITY; + + writeb(reg, vuart->regs + ASPEED_VUART_GCRA); +} + +static ssize_t sirq_polarity_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct aspeed_vuart *vuart = dev_get_drvdata(dev); + unsigned long val; + int err; + + err = kstrtoul(buf, 0, &val); + if (err) + return err; + + aspeed_vuart_set_sirq_polarity(vuart, val != 0); + + return count; +} + +static DEVICE_ATTR_RW(sirq_polarity); + static struct attribute *aspeed_vuart_attrs[] = { &dev_attr_sirq.attr, + &dev_attr_sirq_polarity.attr, &dev_attr_lpc_address.attr, NULL, }; @@ -302,8 +346,30 @@ static int aspeed_vuart_handle_irq(struct uart_port *port) return 1; } +static void aspeed_vuart_auto_configure_sirq_polarity( + struct aspeed_vuart *vuart, struct device_node *syscon_np, + u32 reg_offset, u32 reg_mask) +{ + struct regmap *regmap; + u32 value; + + regmap = syscon_node_to_regmap(syscon_np); + if (IS_ERR(regmap)) { + dev_warn(vuart->dev, + "could not get regmap for aspeed,sirq-polarity-sense\n"); + return; + } + if (regmap_read(regmap, reg_offset, &value)) { + dev_warn(vuart->dev, "could not read hw strap table\n"); + return; + } + + aspeed_vuart_set_sirq_polarity(vuart, (value & reg_mask) == 0); +} + static int aspeed_vuart_probe(struct platform_device *pdev) { + struct of_phandle_args sirq_polarity_sense_args; struct uart_8250_port port; struct aspeed_vuart *vuart; struct device_node *np; @@ -336,6 +402,7 @@ static int aspeed_vuart_probe(struct platform_device *pdev) port.port.unthrottle = aspeed_vuart_unthrottle; port.port.status = UPSTAT_SYNC_FIFO; port.port.dev = &pdev->dev; + port.port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE); rc = sysfs_create_group(&vuart->dev->kobj, &aspeed_vuart_attr_group); if (rc < 0) @@ -402,6 +469,20 @@ static int aspeed_vuart_probe(struct platform_device *pdev) vuart->line = rc; + rc = of_parse_phandle_with_fixed_args( + np, "aspeed,sirq-polarity-sense", 2, 0, + &sirq_polarity_sense_args); + if (rc < 0) { + dev_dbg(&pdev->dev, + "aspeed,sirq-polarity-sense property not found\n"); + } else { + aspeed_vuart_auto_configure_sirq_polarity( + vuart, sirq_polarity_sense_args.np, + sirq_polarity_sense_args.args[0], + BIT(sirq_polarity_sense_args.args[1])); + of_node_put(sirq_polarity_sense_args.np); + } + aspeed_vuart_set_enabled(vuart, true); aspeed_vuart_set_host_tx_discard(vuart, true); platform_set_drvdata(pdev, vuart); diff --git a/drivers/tty/serial/8250/8250_bcm2835aux.c b/drivers/tty/serial/8250/8250_bcm2835aux.c index bd53661103eb..e70e3cc30050 100644 --- a/drivers/tty/serial/8250/8250_bcm2835aux.c +++ b/drivers/tty/serial/8250/8250_bcm2835aux.c @@ -16,14 +16,19 @@ #include "8250.h" +/** + * struct bcm2835aux_data - driver private data of BCM2835 auxiliary UART + * @clk: clock producer of the port's uartclk + * @line: index of the port's serial8250_ports[] entry + */ struct bcm2835aux_data { - struct uart_8250_port uart; struct clk *clk; int line; }; static int bcm2835aux_serial_probe(struct platform_device *pdev) { + struct uart_8250_port up = { }; struct bcm2835aux_data *data; struct resource *res; int ret; @@ -34,33 +39,29 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev) return -ENOMEM; /* initialize data */ - spin_lock_init(&data->uart.port.lock); - data->uart.capabilities = UART_CAP_FIFO | UART_CAP_MINI; - data->uart.port.dev = &pdev->dev; - data->uart.port.regshift = 2; - data->uart.port.type = PORT_16550; - data->uart.port.iotype = UPIO_MEM; - data->uart.port.fifosize = 8; - data->uart.port.flags = UPF_SHARE_IRQ | - UPF_FIXED_PORT | - UPF_FIXED_TYPE | - UPF_SKIP_TEST; + up.capabilities = UART_CAP_FIFO | UART_CAP_MINI; + up.port.dev = &pdev->dev; + up.port.regshift = 2; + up.port.type = PORT_16550; + up.port.iotype = UPIO_MEM; + up.port.fifosize = 8; + up.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE | + UPF_SKIP_TEST | UPF_IOREMAP; /* get the clock - this also enables the HW */ data->clk = devm_clk_get(&pdev->dev, NULL); ret = PTR_ERR_OR_ZERO(data->clk); if (ret) { - dev_err(&pdev->dev, "could not get clk: %d\n", ret); + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "could not get clk: %d\n", ret); return ret; } /* get the interrupt */ ret = platform_get_irq(pdev, 0); - if (ret < 0) { - dev_err(&pdev->dev, "irq not found - %i", ret); + if (ret < 0) return ret; - } - data->uart.port.irq = ret; + up.port.irq = ret; /* map the main registers */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -68,15 +69,13 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev) dev_err(&pdev->dev, "memory resource not found"); return -EINVAL; } - data->uart.port.membase = devm_ioremap_resource(&pdev->dev, res); - ret = PTR_ERR_OR_ZERO(data->uart.port.membase); - if (ret) - return ret; + up.port.mapbase = res->start; + up.port.mapsize = resource_size(res); /* Check for a fixed line number */ ret = of_alias_get_id(pdev->dev.of_node, "serial"); if (ret >= 0) - data->uart.port.line = ret; + up.port.line = ret; /* enable the clock as a last step */ ret = clk_prepare_enable(data->clk); @@ -91,13 +90,14 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev) * so we have to multiply the actual clock by 2 * to get identical baudrates. */ - data->uart.port.uartclk = clk_get_rate(data->clk) * 2; + up.port.uartclk = clk_get_rate(data->clk) * 2; /* register the port */ - ret = serial8250_register_8250_port(&data->uart); + ret = serial8250_register_8250_port(&up); if (ret < 0) { - dev_err(&pdev->dev, "unable to register 8250 port - %d\n", - ret); + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, + "unable to register 8250 port - %d\n", ret); goto dis_clk; } data->line = ret; @@ -115,7 +115,7 @@ static int bcm2835aux_serial_remove(struct platform_device *pdev) { struct bcm2835aux_data *data = platform_get_drvdata(pdev); - serial8250_unregister_port(data->uart.port.line); + serial8250_unregister_port(data->line); clk_disable_unprepare(data->clk); return 0; diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index df3bcc0b2d74..0894a22fd702 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -816,6 +816,7 @@ static int serial8250_probe(struct platform_device *dev) uart.port.flags = p->flags; uart.port.mapbase = p->mapbase; uart.port.hub6 = p->hub6; + uart.port.has_sysrq = p->has_sysrq; uart.port.private_data = p->private_data; uart.port.type = p->type; uart.port.serial_in = p->serial_in; @@ -1026,10 +1027,8 @@ int serial8250_register_8250_port(struct uart_8250_port *up) if (!has_acpi_companion(uart->port.dev)) { gpios = mctrl_gpio_init(&uart->port, 0); if (IS_ERR(gpios)) { - if (PTR_ERR(gpios) != -ENOSYS) { - ret = PTR_ERR(gpios); - goto out_unlock; - } + ret = PTR_ERR(gpios); + goto out_unlock; } else { uart->gpios = gpios; } diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 284e8d052fc3..aab3cccc6789 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -27,66 +27,36 @@ #include <asm/byteorder.h> -#include "8250.h" +#include "8250_dwlib.h" /* Offsets for the DesignWare specific registers */ #define DW_UART_USR 0x1f /* UART Status Register */ -#define DW_UART_DLF 0xc0 /* Divisor Latch Fraction Register */ -#define DW_UART_CPR 0xf4 /* Component Parameter Register */ -#define DW_UART_UCV 0xf8 /* UART Component Version */ - -/* Component Parameter Register bits */ -#define DW_UART_CPR_ABP_DATA_WIDTH (3 << 0) -#define DW_UART_CPR_AFCE_MODE (1 << 4) -#define DW_UART_CPR_THRE_MODE (1 << 5) -#define DW_UART_CPR_SIR_MODE (1 << 6) -#define DW_UART_CPR_SIR_LP_MODE (1 << 7) -#define DW_UART_CPR_ADDITIONAL_FEATURES (1 << 8) -#define DW_UART_CPR_FIFO_ACCESS (1 << 9) -#define DW_UART_CPR_FIFO_STAT (1 << 10) -#define DW_UART_CPR_SHADOW (1 << 11) -#define DW_UART_CPR_ENCODED_PARMS (1 << 12) -#define DW_UART_CPR_DMA_EXTRA (1 << 13) -#define DW_UART_CPR_FIFO_MODE (0xff << 16) -/* Helper for fifo size calculation */ -#define DW_UART_CPR_FIFO_SIZE(a) (((a >> 16) & 0xff) * 16) /* DesignWare specific register fields */ #define DW_UART_MCR_SIRE BIT(6) struct dw8250_data { + struct dw8250_port_data data; + u8 usr_reg; - u8 dlf_size; - int line; int msr_mask_on; int msr_mask_off; struct clk *clk; struct clk *pclk; struct reset_control *rst; - struct uart_8250_dma dma; unsigned int skip_autocfg:1; unsigned int uart_16550_compatible:1; }; -static inline u32 dw8250_readl_ext(struct uart_port *p, int offset) -{ - if (p->iotype == UPIO_MEM32BE) - return ioread32be(p->membase + offset); - return readl(p->membase + offset); -} - -static inline void dw8250_writel_ext(struct uart_port *p, int offset, u32 reg) +static inline struct dw8250_data *to_dw8250_data(struct dw8250_port_data *data) { - if (p->iotype == UPIO_MEM32BE) - iowrite32be(reg, p->membase + offset); - else - writel(reg, p->membase + offset); + return container_of(data, struct dw8250_data, data); } static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value) { - struct dw8250_data *d = p->private_data; + struct dw8250_data *d = to_dw8250_data(p->private_data); /* Override any modem control signals if needed */ if (offset == UART_MSR) { @@ -160,7 +130,7 @@ static void dw8250_tx_wait_empty(struct uart_port *p) static void dw8250_serial_out38x(struct uart_port *p, int offset, int value) { - struct dw8250_data *d = p->private_data; + struct dw8250_data *d = to_dw8250_data(p->private_data); /* Allow the TX to drain before we reconfigure */ if (offset == UART_LCR) @@ -175,7 +145,7 @@ static void dw8250_serial_out38x(struct uart_port *p, int offset, int value) static void dw8250_serial_out(struct uart_port *p, int offset, int value) { - struct dw8250_data *d = p->private_data; + struct dw8250_data *d = to_dw8250_data(p->private_data); writeb(value, p->membase + (offset << p->regshift)); @@ -202,7 +172,7 @@ static unsigned int dw8250_serial_inq(struct uart_port *p, int offset) static void dw8250_serial_outq(struct uart_port *p, int offset, int value) { - struct dw8250_data *d = p->private_data; + struct dw8250_data *d = to_dw8250_data(p->private_data); value &= 0xff; __raw_writeq(value, p->membase + (offset << p->regshift)); @@ -216,7 +186,7 @@ static void dw8250_serial_outq(struct uart_port *p, int offset, int value) static void dw8250_serial_out32(struct uart_port *p, int offset, int value) { - struct dw8250_data *d = p->private_data; + struct dw8250_data *d = to_dw8250_data(p->private_data); writel(value, p->membase + (offset << p->regshift)); @@ -233,7 +203,7 @@ static unsigned int dw8250_serial_in32(struct uart_port *p, int offset) static void dw8250_serial_out32be(struct uart_port *p, int offset, int value) { - struct dw8250_data *d = p->private_data; + struct dw8250_data *d = to_dw8250_data(p->private_data); iowrite32be(value, p->membase + (offset << p->regshift)); @@ -252,7 +222,7 @@ static unsigned int dw8250_serial_in32be(struct uart_port *p, int offset) static int dw8250_handle_irq(struct uart_port *p) { struct uart_8250_port *up = up_to_u8250p(p); - struct dw8250_data *d = p->private_data; + struct dw8250_data *d = to_dw8250_data(p->private_data); unsigned int iir = p->serial_in(p, UART_IIR); unsigned int status; unsigned long flags; @@ -306,13 +276,10 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios, struct ktermios *old) { unsigned int baud = tty_termios_baud_rate(termios); - struct dw8250_data *d = p->private_data; + struct dw8250_data *d = to_dw8250_data(p->private_data); long rate; int ret; - if (IS_ERR(d->clk)) - goto out; - clk_disable_unprepare(d->clk); rate = clk_round_rate(d->clk, baud * 16); if (rate < 0) @@ -323,8 +290,10 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios, ret = clk_set_rate(d->clk, rate); clk_prepare_enable(d->clk); - if (!ret) - p->uartclk = rate; + if (ret) + goto out; + + p->uartclk = rate; out: p->status &= ~UPSTAT_AUTOCTS; @@ -368,37 +337,6 @@ static bool dw8250_idma_filter(struct dma_chan *chan, void *param) return param == chan->device->dev; } -/* - * divisor = div(I) + div(F) - * "I" means integer, "F" means fractional - * quot = div(I) = clk / (16 * baud) - * frac = div(F) * 2^dlf_size - * - * let rem = clk % (16 * baud) - * we have: div(F) * (16 * baud) = rem - * so frac = 2^dlf_size * rem / (16 * baud) = (rem << dlf_size) / (16 * baud) - */ -static unsigned int dw8250_get_divisor(struct uart_port *p, - unsigned int baud, - unsigned int *frac) -{ - unsigned int quot, rem, base_baud = baud * 16; - struct dw8250_data *d = p->private_data; - - quot = p->uartclk / base_baud; - rem = p->uartclk % base_baud; - *frac = DIV_ROUND_CLOSEST(rem << d->dlf_size, base_baud); - - return quot; -} - -static void dw8250_set_divisor(struct uart_port *p, unsigned int baud, - unsigned int quot, unsigned int quot_frac) -{ - dw8250_writel_ext(p, DW_UART_DLF, quot_frac); - serial8250_do_set_divisor(p, baud, quot, quot_frac); -} - static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data) { if (p->dev->of_node) { @@ -437,67 +375,20 @@ static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data) /* Platforms with iDMA 64-bit */ if (platform_get_resource_byname(to_platform_device(p->dev), IORESOURCE_MEM, "lpss_priv")) { - data->dma.rx_param = p->dev->parent; - data->dma.tx_param = p->dev->parent; - data->dma.fn = dw8250_idma_filter; - } -} - -static void dw8250_setup_port(struct uart_port *p) -{ - struct uart_8250_port *up = up_to_u8250p(p); - u32 reg; - - /* - * If the Component Version Register returns zero, we know that - * ADDITIONAL_FEATURES are not enabled. No need to go any further. - */ - reg = dw8250_readl_ext(p, DW_UART_UCV); - if (!reg) - return; - - dev_dbg(p->dev, "Designware UART version %c.%c%c\n", - (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff); - - dw8250_writel_ext(p, DW_UART_DLF, ~0U); - reg = dw8250_readl_ext(p, DW_UART_DLF); - dw8250_writel_ext(p, DW_UART_DLF, 0); - - if (reg) { - struct dw8250_data *d = p->private_data; - - d->dlf_size = fls(reg); - p->get_divisor = dw8250_get_divisor; - p->set_divisor = dw8250_set_divisor; - } - - reg = dw8250_readl_ext(p, DW_UART_CPR); - if (!reg) - return; - - /* Select the type based on fifo */ - if (reg & DW_UART_CPR_FIFO_MODE) { - p->type = PORT_16550A; - p->flags |= UPF_FIXED_TYPE; - p->fifosize = DW_UART_CPR_FIFO_SIZE(reg); - up->capabilities = UART_CAP_FIFO; + data->data.dma.rx_param = p->dev->parent; + data->data.dma.tx_param = p->dev->parent; + data->data.dma.fn = dw8250_idma_filter; } - - if (reg & DW_UART_CPR_AFCE_MODE) - up->capabilities |= UART_CAP_AFE; - - if (reg & DW_UART_CPR_SIR_MODE) - up->capabilities |= UART_CAP_IRDA; } static int dw8250_probe(struct platform_device *pdev) { - struct uart_8250_port uart = {}; + struct uart_8250_port uart = {}, *up = &uart; struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - int irq = platform_get_irq(pdev, 0); - struct uart_port *p = &uart.port; + struct uart_port *p = &up->port; struct device *dev = &pdev->dev; struct dw8250_data *data; + int irq; int err; u32 val; @@ -506,11 +397,9 @@ static int dw8250_probe(struct platform_device *pdev) return -EINVAL; } - if (irq < 0) { - if (irq != -EPROBE_DEFER) - dev_err(dev, "cannot get irq\n"); + irq = platform_get_irq(pdev, 0); + if (irq < 0) return irq; - } spin_lock_init(&p->lock); p->mapbase = regs->start; @@ -534,9 +423,9 @@ static int dw8250_probe(struct platform_device *pdev) if (!data) return -ENOMEM; - data->dma.fn = dw8250_fallback_dma_filter; + data->data.dma.fn = dw8250_fallback_dma_filter; data->usr_reg = DW_UART_USR; - p->private_data = data; + p->private_data = &data->data; data->uart_16550_compatible = device_property_read_bool(dev, "snps,uart-16550-compatible"); @@ -580,19 +469,18 @@ static int dw8250_probe(struct platform_device *pdev) device_property_read_u32(dev, "clock-frequency", &p->uartclk); /* If there is separate baudclk, get the rate from it. */ - data->clk = devm_clk_get(dev, "baudclk"); - if (IS_ERR(data->clk) && PTR_ERR(data->clk) != -EPROBE_DEFER) - data->clk = devm_clk_get(dev, NULL); - if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER) - return -EPROBE_DEFER; - if (!IS_ERR_OR_NULL(data->clk)) { - err = clk_prepare_enable(data->clk); - if (err) - dev_warn(dev, "could not enable optional baudclk: %d\n", - err); - else - p->uartclk = clk_get_rate(data->clk); - } + data->clk = devm_clk_get_optional(dev, "baudclk"); + if (data->clk == NULL) + data->clk = devm_clk_get_optional(dev, NULL); + if (IS_ERR(data->clk)) + return PTR_ERR(data->clk); + + err = clk_prepare_enable(data->clk); + if (err) + dev_warn(dev, "could not enable optional baudclk: %d\n", err); + + if (data->clk) + p->uartclk = clk_get_rate(data->clk); /* If no clock rate is defined, fail. */ if (!p->uartclk) { @@ -601,17 +489,16 @@ static int dw8250_probe(struct platform_device *pdev) goto err_clk; } - data->pclk = devm_clk_get(dev, "apb_pclk"); - if (IS_ERR(data->pclk) && PTR_ERR(data->pclk) == -EPROBE_DEFER) { - err = -EPROBE_DEFER; + data->pclk = devm_clk_get_optional(dev, "apb_pclk"); + if (IS_ERR(data->pclk)) { + err = PTR_ERR(data->pclk); goto err_clk; } - if (!IS_ERR(data->pclk)) { - err = clk_prepare_enable(data->pclk); - if (err) { - dev_err(dev, "could not enable apb_pclk\n"); - goto err_clk; - } + + err = clk_prepare_enable(data->pclk); + if (err) { + dev_err(dev, "could not enable apb_pclk\n"); + goto err_clk; } data->rst = devm_reset_control_get_optional_exclusive(dev, NULL); @@ -632,14 +519,14 @@ static int dw8250_probe(struct platform_device *pdev) /* If we have a valid fifosize, try hooking up DMA */ if (p->fifosize) { - data->dma.rxconf.src_maxburst = p->fifosize / 4; - data->dma.txconf.dst_maxburst = p->fifosize / 4; - uart.dma = &data->dma; + data->data.dma.rxconf.src_maxburst = p->fifosize / 4; + data->data.dma.txconf.dst_maxburst = p->fifosize / 4; + up->dma = &data->data.dma; } - data->line = serial8250_register_8250_port(&uart); - if (data->line < 0) { - err = data->line; + data->data.line = serial8250_register_8250_port(up); + if (data->data.line < 0) { + err = data->data.line; goto err_reset; } @@ -654,12 +541,10 @@ err_reset: reset_control_assert(data->rst); err_pclk: - if (!IS_ERR(data->pclk)) - clk_disable_unprepare(data->pclk); + clk_disable_unprepare(data->pclk); err_clk: - if (!IS_ERR(data->clk)) - clk_disable_unprepare(data->clk); + clk_disable_unprepare(data->clk); return err; } @@ -667,21 +552,20 @@ err_clk: static int dw8250_remove(struct platform_device *pdev) { struct dw8250_data *data = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; - pm_runtime_get_sync(&pdev->dev); + pm_runtime_get_sync(dev); - serial8250_unregister_port(data->line); + serial8250_unregister_port(data->data.line); reset_control_assert(data->rst); - if (!IS_ERR(data->pclk)) - clk_disable_unprepare(data->pclk); + clk_disable_unprepare(data->pclk); - if (!IS_ERR(data->clk)) - clk_disable_unprepare(data->clk); + clk_disable_unprepare(data->clk); - pm_runtime_disable(&pdev->dev); - pm_runtime_put_noidle(&pdev->dev); + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); return 0; } @@ -691,7 +575,7 @@ static int dw8250_suspend(struct device *dev) { struct dw8250_data *data = dev_get_drvdata(dev); - serial8250_suspend_port(data->line); + serial8250_suspend_port(data->data.line); return 0; } @@ -700,7 +584,7 @@ static int dw8250_resume(struct device *dev) { struct dw8250_data *data = dev_get_drvdata(dev); - serial8250_resume_port(data->line); + serial8250_resume_port(data->data.line); return 0; } @@ -711,11 +595,9 @@ static int dw8250_runtime_suspend(struct device *dev) { struct dw8250_data *data = dev_get_drvdata(dev); - if (!IS_ERR(data->clk)) - clk_disable_unprepare(data->clk); + clk_disable_unprepare(data->clk); - if (!IS_ERR(data->pclk)) - clk_disable_unprepare(data->pclk); + clk_disable_unprepare(data->pclk); return 0; } @@ -724,11 +606,9 @@ static int dw8250_runtime_resume(struct device *dev) { struct dw8250_data *data = dev_get_drvdata(dev); - if (!IS_ERR(data->pclk)) - clk_prepare_enable(data->pclk); + clk_prepare_enable(data->pclk); - if (!IS_ERR(data->clk)) - clk_prepare_enable(data->clk); + clk_prepare_enable(data->clk); return 0; } diff --git a/drivers/tty/serial/8250/8250_dwlib.c b/drivers/tty/serial/8250/8250_dwlib.c new file mode 100644 index 000000000000..6d6a78eead3e --- /dev/null +++ b/drivers/tty/serial/8250/8250_dwlib.c @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Synopsys DesignWare 8250 library. */ + +#include <linux/bitops.h> +#include <linux/device.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/serial_8250.h> +#include <linux/serial_core.h> + +#include "8250_dwlib.h" + +/* Offsets for the DesignWare specific registers */ +#define DW_UART_DLF 0xc0 /* Divisor Latch Fraction Register */ +#define DW_UART_CPR 0xf4 /* Component Parameter Register */ +#define DW_UART_UCV 0xf8 /* UART Component Version */ + +/* Component Parameter Register bits */ +#define DW_UART_CPR_ABP_DATA_WIDTH (3 << 0) +#define DW_UART_CPR_AFCE_MODE (1 << 4) +#define DW_UART_CPR_THRE_MODE (1 << 5) +#define DW_UART_CPR_SIR_MODE (1 << 6) +#define DW_UART_CPR_SIR_LP_MODE (1 << 7) +#define DW_UART_CPR_ADDITIONAL_FEATURES (1 << 8) +#define DW_UART_CPR_FIFO_ACCESS (1 << 9) +#define DW_UART_CPR_FIFO_STAT (1 << 10) +#define DW_UART_CPR_SHADOW (1 << 11) +#define DW_UART_CPR_ENCODED_PARMS (1 << 12) +#define DW_UART_CPR_DMA_EXTRA (1 << 13) +#define DW_UART_CPR_FIFO_MODE (0xff << 16) + +/* Helper for FIFO size calculation */ +#define DW_UART_CPR_FIFO_SIZE(a) (((a >> 16) & 0xff) * 16) + +static inline u32 dw8250_readl_ext(struct uart_port *p, int offset) +{ + if (p->iotype == UPIO_MEM32BE) + return ioread32be(p->membase + offset); + return readl(p->membase + offset); +} + +static inline void dw8250_writel_ext(struct uart_port *p, int offset, u32 reg) +{ + if (p->iotype == UPIO_MEM32BE) + iowrite32be(reg, p->membase + offset); + else + writel(reg, p->membase + offset); +} + +/* + * divisor = div(I) + div(F) + * "I" means integer, "F" means fractional + * quot = div(I) = clk / (16 * baud) + * frac = div(F) * 2^dlf_size + * + * let rem = clk % (16 * baud) + * we have: div(F) * (16 * baud) = rem + * so frac = 2^dlf_size * rem / (16 * baud) = (rem << dlf_size) / (16 * baud) + */ +static unsigned int dw8250_get_divisor(struct uart_port *p, unsigned int baud, + unsigned int *frac) +{ + unsigned int quot, rem, base_baud = baud * 16; + struct dw8250_port_data *d = p->private_data; + + quot = p->uartclk / base_baud; + rem = p->uartclk % base_baud; + *frac = DIV_ROUND_CLOSEST(rem << d->dlf_size, base_baud); + + return quot; +} + +static void dw8250_set_divisor(struct uart_port *p, unsigned int baud, + unsigned int quot, unsigned int quot_frac) +{ + dw8250_writel_ext(p, DW_UART_DLF, quot_frac); + serial8250_do_set_divisor(p, baud, quot, quot_frac); +} + +void dw8250_setup_port(struct uart_port *p) +{ + struct uart_8250_port *up = up_to_u8250p(p); + u32 reg; + + /* + * If the Component Version Register returns zero, we know that + * ADDITIONAL_FEATURES are not enabled. No need to go any further. + */ + reg = dw8250_readl_ext(p, DW_UART_UCV); + if (!reg) + return; + + dev_dbg(p->dev, "Designware UART version %c.%c%c\n", + (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff); + + dw8250_writel_ext(p, DW_UART_DLF, ~0U); + reg = dw8250_readl_ext(p, DW_UART_DLF); + dw8250_writel_ext(p, DW_UART_DLF, 0); + + if (reg) { + struct dw8250_port_data *d = p->private_data; + + d->dlf_size = fls(reg); + p->get_divisor = dw8250_get_divisor; + p->set_divisor = dw8250_set_divisor; + } + + reg = dw8250_readl_ext(p, DW_UART_CPR); + if (!reg) + return; + + /* Select the type based on FIFO */ + if (reg & DW_UART_CPR_FIFO_MODE) { + p->type = PORT_16550A; + p->flags |= UPF_FIXED_TYPE; + p->fifosize = DW_UART_CPR_FIFO_SIZE(reg); + up->capabilities = UART_CAP_FIFO; + } + + if (reg & DW_UART_CPR_AFCE_MODE) + up->capabilities |= UART_CAP_AFE; + + if (reg & DW_UART_CPR_SIR_MODE) + up->capabilities |= UART_CAP_IRDA; +} +EXPORT_SYMBOL_GPL(dw8250_setup_port); diff --git a/drivers/tty/serial/8250/8250_dwlib.h b/drivers/tty/serial/8250/8250_dwlib.h new file mode 100644 index 000000000000..87a4db2a8aba --- /dev/null +++ b/drivers/tty/serial/8250/8250_dwlib.h @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Synopsys DesignWare 8250 library header file. */ + +#include <linux/types.h> + +#include "8250.h" + +struct dw8250_port_data { + /* Port properties */ + int line; + + /* DMA operations */ + struct uart_8250_dma dma; + + /* Hardware configuration */ + u8 dlf_size; +}; + +void dw8250_setup_port(struct uart_port *p); diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index edd6dfe055bf..91e9b070d36d 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -19,6 +19,7 @@ #include <linux/string.h> #include <linux/tty.h> #include <linux/8250_pci.h> +#include <linux/delay.h> #include <asm/byteorder.h> @@ -36,6 +37,8 @@ #define UART_EXAR_INT0 0x80 #define UART_EXAR_8XMODE 0x88 /* 8X sampling rate select */ +#define UART_EXAR_SLEEP 0x8b /* Sleep mode */ +#define UART_EXAR_DVID 0x8d /* Device identification */ #define UART_EXAR_FCTR 0x08 /* Feature Control Register */ #define UART_FCTR_EXAR_IRDA 0x10 /* IrDa data encode select */ @@ -127,18 +130,114 @@ struct exar8250 { int line[0]; }; +static void exar_pm(struct uart_port *port, unsigned int state, unsigned int old) +{ + /* + * Exar UARTs have a SLEEP register that enables or disables each UART + * to enter sleep mode separately. On the XR17V35x the register + * is accessible to each UART at the UART_EXAR_SLEEP offset, but + * the UART channel may only write to the corresponding bit. + */ + serial_port_out(port, UART_EXAR_SLEEP, state ? 0xff : 0); +} + +/* + * XR17V35x UARTs have an extra fractional divisor register (DLD) + * Calculate divisor with extra 4-bit fractional portion + */ +static unsigned int xr17v35x_get_divisor(struct uart_port *p, unsigned int baud, + unsigned int *frac) +{ + unsigned int quot_16; + + quot_16 = DIV_ROUND_CLOSEST(p->uartclk, baud); + *frac = quot_16 & 0x0f; + + return quot_16 >> 4; +} + +static void xr17v35x_set_divisor(struct uart_port *p, unsigned int baud, + unsigned int quot, unsigned int quot_frac) +{ + serial8250_do_set_divisor(p, baud, quot, quot_frac); + + /* Preserve bits not related to baudrate; DLD[7:4]. */ + quot_frac |= serial_port_in(p, 0x2) & 0xf0; + serial_port_out(p, 0x2, quot_frac); +} + +static int xr17v35x_startup(struct uart_port *port) +{ + /* + * First enable access to IER [7:5], ISR [5:4], FCR [5:4], + * MCR [7:5] and MSR [7:0] + */ + serial_port_out(port, UART_XR_EFR, UART_EFR_ECB); + + /* + * Make sure all interrups are masked until initialization is + * complete and the FIFOs are cleared + */ + serial_port_out(port, UART_IER, 0); + + return serial8250_do_startup(port); +} + +static void exar_shutdown(struct uart_port *port) +{ + unsigned char lsr; + bool tx_complete = false; + struct uart_8250_port *up = up_to_u8250p(port); + struct circ_buf *xmit = &port->state->xmit; + int i = 0; + + do { + lsr = serial_in(up, UART_LSR); + if (lsr & (UART_LSR_TEMT | UART_LSR_THRE)) + tx_complete = true; + else + tx_complete = false; + usleep_range(1000, 1100); + } while (!uart_circ_empty(xmit) && !tx_complete && i++ < 1000); + + serial8250_do_shutdown(port); +} + static int default_setup(struct exar8250 *priv, struct pci_dev *pcidev, int idx, unsigned int offset, struct uart_8250_port *port) { const struct exar8250_board *board = priv->board; unsigned int bar = 0; + unsigned char status; port->port.iotype = UPIO_MEM; port->port.mapbase = pci_resource_start(pcidev, bar) + offset; port->port.membase = priv->virt + offset; port->port.regshift = board->reg_shift; + /* + * XR17V35x UARTs have an extra divisor register, DLD that gets enabled + * with when DLAB is set which will cause the device to incorrectly match + * and assign port type to PORT_16650. The EFR for this UART is found + * at offset 0x09. Instead check the Deice ID (DVID) register + * for a 2, 4 or 8 port UART. + */ + status = readb(port->port.membase + UART_EXAR_DVID); + if (status == 0x82 || status == 0x84 || status == 0x88) { + port->port.type = PORT_XR17V35X; + + port->port.get_divisor = xr17v35x_get_divisor; + port->port.set_divisor = xr17v35x_set_divisor; + + port->port.startup = xr17v35x_startup; + } else { + port->port.type = PORT_XR17D15X; + } + + port->port.pm = exar_pm; + port->port.shutdown = exar_shutdown; + return 0; } @@ -434,6 +533,16 @@ static void pci_xr17v35x_exit(struct pci_dev *pcidev) port->port.private_data = NULL; } +static inline void exar_misc_clear(struct exar8250 *priv) +{ + /* Clear all PCI interrupts by reading INT0. No effect on IIR */ + readb(priv->virt + UART_EXAR_INT0); + + /* Clear INT0 for Expansion Interface slave ports, too */ + if (priv->board->num_ports > 8) + readb(priv->virt + 0x2000 + UART_EXAR_INT0); +} + /* * These Exar UARTs have an extra interrupt indicator that could fire for a * few interrupts that are not presented/cleared through IIR. One of which is @@ -445,14 +554,7 @@ static void pci_xr17v35x_exit(struct pci_dev *pcidev) */ static irqreturn_t exar_misc_handler(int irq, void *data) { - struct exar8250 *priv = data; - - /* Clear all PCI interrupts by reading INT0. No effect on IIR */ - readb(priv->virt + UART_EXAR_INT0); - - /* Clear INT0 for Expansion Interface slave ports, too */ - if (priv->board->num_ports > 8) - readb(priv->virt + 0x2000 + UART_EXAR_INT0); + exar_misc_clear(data); return IRQ_HANDLED; } @@ -478,9 +580,7 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) nr_ports = board->num_ports ? board->num_ports : pcidev->device & 0x0f; - priv = devm_kzalloc(&pcidev->dev, sizeof(*priv) + - sizeof(unsigned int) * nr_ports, - GFP_KERNEL); + priv = devm_kzalloc(&pcidev->dev, struct_size(priv, line, nr_ports), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -496,8 +596,7 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) return rc; memset(&uart, 0, sizeof(uart)); - uart.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ - | UPF_EXAR_EFR; + uart.port.flags = UPF_SHARE_IRQ | UPF_EXAR_EFR | UPF_FIXED_TYPE | UPF_FIXED_PORT; uart.port.irq = pci_irq_vector(pcidev, 0); uart.port.dev = &pcidev->dev; @@ -506,6 +605,9 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) if (rc) return rc; + /* Clear interrupts */ + exar_misc_clear(priv); + for (i = 0; i < nr_ports && i < maxnr; i++) { rc = board->setup(priv, pcidev, &uart, i); if (rc) { @@ -561,10 +663,11 @@ static int __maybe_unused exar_suspend(struct device *dev) static int __maybe_unused exar_resume(struct device *dev) { - struct pci_dev *pcidev = to_pci_dev(dev); - struct exar8250 *priv = pci_get_drvdata(pcidev); + struct exar8250 *priv = dev_get_drvdata(dev); unsigned int i; + exar_misc_clear(priv); + for (i = 0; i < priv->nr; i++) if (priv->line[i] >= 0) serial8250_resume_port(priv->line[i]); diff --git a/drivers/tty/serial/8250/8250_fsl.c b/drivers/tty/serial/8250/8250_fsl.c index aa0e216d5ead..0d0c80905c58 100644 --- a/drivers/tty/serial/8250/8250_fsl.c +++ b/drivers/tty/serial/8250/8250_fsl.c @@ -1,8 +1,4 @@ // SPDX-License-Identifier: GPL-2.0 -#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - #include <linux/serial_reg.h> #include <linux/serial_8250.h> diff --git a/drivers/tty/serial/8250/8250_gsc.c b/drivers/tty/serial/8250/8250_gsc.c index 0809ae2aa9b1..673cda3d011d 100644 --- a/drivers/tty/serial/8250/8250_gsc.c +++ b/drivers/tty/serial/8250/8250_gsc.c @@ -55,7 +55,7 @@ static int __init serial_init_chip(struct parisc_device *dev) uart.port.uartclk = (dev->id.sversion != 0xad) ? 7272727 : 1843200; uart.port.mapbase = address; - uart.port.membase = ioremap_nocache(address, 16); + uart.port.membase = ioremap(address, 16); if (!uart.port.membase) { dev_warn(&dev->dev, "Failed to map memory\n"); return -ENOMEM; diff --git a/drivers/tty/serial/8250/8250_ioc3.c b/drivers/tty/serial/8250/8250_ioc3.c new file mode 100644 index 000000000000..d5a39e105a76 --- /dev/null +++ b/drivers/tty/serial/8250/8250_ioc3.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * SGI IOC3 8250 UART driver + * + * Copyright (C) 2019 Thomas Bogendoerfer <tbogendoerfer@suse.de> + * + * based on code Copyright (C) 2005 Stanislaw Skowronek <skylark@unaligned.org> + * Copyright (C) 2014 Joshua Kinard <kumba@gentoo.org> + */ + +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/io.h> +#include <linux/platform_device.h> + +#include "8250.h" + +#define IOC3_UARTCLK (22000000 / 3) + +struct ioc3_8250_data { + int line; +}; + +static unsigned int ioc3_serial_in(struct uart_port *p, int offset) +{ + return readb(p->membase + (offset ^ 3)); +} + +static void ioc3_serial_out(struct uart_port *p, int offset, int value) +{ + writeb(value, p->membase + (offset ^ 3)); +} + +static int serial8250_ioc3_probe(struct platform_device *pdev) +{ + struct ioc3_8250_data *data; + struct uart_8250_port up; + struct resource *r; + void __iomem *membase; + int irq, line; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) + return -ENODEV; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + membase = devm_ioremap(&pdev->dev, r->start, resource_size(r)); + if (!membase) + return -ENOMEM; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + irq = 0; /* no interrupt -> use polling */ + + /* Register serial ports with 8250.c */ + memset(&up, 0, sizeof(struct uart_8250_port)); + up.port.iotype = UPIO_MEM; + up.port.uartclk = IOC3_UARTCLK; + up.port.type = PORT_16550A; + up.port.irq = irq; + up.port.flags = (UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ); + up.port.dev = &pdev->dev; + up.port.membase = membase; + up.port.mapbase = r->start; + up.port.serial_in = ioc3_serial_in; + up.port.serial_out = ioc3_serial_out; + line = serial8250_register_8250_port(&up); + if (line < 0) + return line; + + platform_set_drvdata(pdev, data); + return 0; +} + +static int serial8250_ioc3_remove(struct platform_device *pdev) +{ + struct ioc3_8250_data *data = platform_get_drvdata(pdev); + + serial8250_unregister_port(data->line); + return 0; +} + +static struct platform_driver serial8250_ioc3_driver = { + .probe = serial8250_ioc3_probe, + .remove = serial8250_ioc3_remove, + .driver = { + .name = "ioc3-serial8250", + } +}; + +module_platform_driver(serial8250_ioc3_driver); + +MODULE_AUTHOR("Thomas Bogendoerfer <tbogendoerfer@suse.de>"); +MODULE_DESCRIPTION("SGI IOC3 8250 UART driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/8250/8250_lpc18xx.c b/drivers/tty/serial/8250/8250_lpc18xx.c index eddf119374e1..570e25d6f37e 100644 --- a/drivers/tty/serial/8250/8250_lpc18xx.c +++ b/drivers/tty/serial/8250/8250_lpc18xx.c @@ -106,10 +106,8 @@ static int lpc18xx_serial_probe(struct platform_device *pdev) int irq, ret; irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "irq not found"); + if (irq < 0) return irq; - } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { diff --git a/drivers/tty/serial/8250/8250_lpss.c b/drivers/tty/serial/8250/8250_lpss.c index 53ca9ba6ab4b..60eff3240c8a 100644 --- a/drivers/tty/serial/8250/8250_lpss.c +++ b/drivers/tty/serial/8250/8250_lpss.c @@ -14,7 +14,7 @@ #include <linux/dmaengine.h> #include <linux/dma/dw.h> -#include "8250.h" +#include "8250_dwlib.h" #define PCI_DEVICE_ID_INTEL_QRK_UARTx 0x0936 @@ -24,6 +24,13 @@ #define PCI_DEVICE_ID_INTEL_BSW_UART1 0x228a #define PCI_DEVICE_ID_INTEL_BSW_UART2 0x228c +#define PCI_DEVICE_ID_INTEL_EHL_UART0 0x4b96 +#define PCI_DEVICE_ID_INTEL_EHL_UART1 0x4b97 +#define PCI_DEVICE_ID_INTEL_EHL_UART2 0x4b98 +#define PCI_DEVICE_ID_INTEL_EHL_UART3 0x4b99 +#define PCI_DEVICE_ID_INTEL_EHL_UART4 0x4b9a +#define PCI_DEVICE_ID_INTEL_EHL_UART5 0x4b9b + #define PCI_DEVICE_ID_INTEL_BDW_UART1 0x9ce3 #define PCI_DEVICE_ID_INTEL_BDW_UART2 0x9ce4 @@ -48,21 +55,25 @@ struct lpss8250_board { }; struct lpss8250 { - int line; + struct dw8250_port_data data; struct lpss8250_board *board; /* DMA parameters */ - struct uart_8250_dma dma; struct dw_dma_chip dma_chip; struct dw_dma_slave dma_param; u8 dma_maxburst; }; +static inline struct lpss8250 *to_lpss8250(struct dw8250_port_data *data) +{ + return container_of(data, struct lpss8250, data); +} + static void byt_set_termios(struct uart_port *p, struct ktermios *termios, struct ktermios *old) { unsigned int baud = tty_termios_baud_rate(termios); - struct lpss8250 *lpss = p->private_data; + struct lpss8250 *lpss = to_lpss8250(p->private_data); unsigned long fref = lpss->board->freq, fuart = baud * 16; unsigned long w = BIT(15) - 1; unsigned long m, n; @@ -109,7 +120,6 @@ static unsigned int byt_get_mctrl(struct uart_port *port) static int byt_serial_setup(struct lpss8250 *lpss, struct uart_port *port) { struct dw_dma_slave *param = &lpss->dma_param; - struct uart_8250_port *up = up_to_u8250p(port); struct pci_dev *pdev = to_pci_dev(port->dev); unsigned int dma_devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0); struct pci_dev *dma_dev = pci_get_slot(pdev->bus, dma_devfn); @@ -135,10 +145,6 @@ static int byt_serial_setup(struct lpss8250 *lpss, struct uart_port *port) param->m_master = 0; param->p_master = 1; - /* TODO: Detect FIFO size automaticaly for DesignWare 8250 */ - port->fifosize = 64; - up->tx_loadsz = 64; - lpss->dma_maxburst = 16; port->set_termios = byt_set_termios; @@ -163,16 +169,19 @@ static const struct dw_dma_platform_data qrk_serial_dma_pdata = { static void qrk_serial_setup_dma(struct lpss8250 *lpss, struct uart_port *port) { - struct uart_8250_dma *dma = &lpss->dma; + struct uart_8250_dma *dma = &lpss->data.dma; struct dw_dma_chip *chip = &lpss->dma_chip; struct dw_dma_slave *param = &lpss->dma_param; struct pci_dev *pdev = to_pci_dev(port->dev); int ret; + chip->pdata = &qrk_serial_dma_pdata; chip->dev = &pdev->dev; + chip->id = pdev->devfn; chip->irq = pci_irq_vector(pdev, 0); chip->regs = pci_ioremap_bar(pdev, 1); - chip->pdata = &qrk_serial_dma_pdata; + if (!chip->regs) + return; /* Falling back to PIO mode if DMA probing fails */ ret = dw_dma_probe(chip); @@ -195,11 +204,15 @@ static void qrk_serial_setup_dma(struct lpss8250 *lpss, struct uart_port *port) static void qrk_serial_exit_dma(struct lpss8250 *lpss) { + struct dw_dma_chip *chip = &lpss->dma_chip; struct dw_dma_slave *param = &lpss->dma_param; if (!param->dma_dev) return; - dw_dma_remove(&lpss->dma_chip); + + dw_dma_remove(chip); + + pci_iounmap(to_pci_dev(chip->dev), chip->regs); } #else /* CONFIG_SERIAL_8250_DMA */ static void qrk_serial_setup_dma(struct lpss8250 *lpss, struct uart_port *port) {} @@ -208,17 +221,6 @@ static void qrk_serial_exit_dma(struct lpss8250 *lpss) {} static int qrk_serial_setup(struct lpss8250 *lpss, struct uart_port *port) { - struct pci_dev *pdev = to_pci_dev(port->dev); - int ret; - - pci_set_master(pdev); - - ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); - if (ret < 0) - return ret; - - port->irq = pci_irq_vector(pdev, 0); - qrk_serial_setup_dma(lpss, port); return 0; } @@ -241,7 +243,7 @@ static bool lpss8250_dma_filter(struct dma_chan *chan, void *param) static int lpss8250_dma_setup(struct lpss8250 *lpss, struct uart_8250_port *port) { - struct uart_8250_dma *dma = &lpss->dma; + struct uart_8250_dma *dma = &lpss->data.dma; struct dw_dma_slave *rx_param, *tx_param; struct device *dev = port->port.dev; @@ -280,17 +282,23 @@ static int lpss8250_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) return ret; + pci_set_master(pdev); + lpss = devm_kzalloc(&pdev->dev, sizeof(*lpss), GFP_KERNEL); if (!lpss) return -ENOMEM; + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); + if (ret < 0) + return ret; + lpss->board = (struct lpss8250_board *)id->driver_data; memset(&uart, 0, sizeof(struct uart_8250_port)); uart.port.dev = &pdev->dev; - uart.port.irq = pdev->irq; - uart.port.private_data = lpss; + uart.port.irq = pci_irq_vector(pdev, 0); + uart.port.private_data = &lpss->data; uart.port.type = PORT_16550A; uart.port.iotype = UPIO_MEM; uart.port.regshift = 2; @@ -306,6 +314,8 @@ static int lpss8250_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) return ret; + dw8250_setup_port(&uart.port); + ret = lpss8250_dma_setup(lpss, &uart); if (ret) goto err_exit; @@ -314,7 +324,7 @@ static int lpss8250_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret < 0) goto err_exit; - lpss->line = ret; + lpss->data.line = ret; pci_set_drvdata(pdev, lpss); return 0; @@ -322,6 +332,7 @@ static int lpss8250_probe(struct pci_dev *pdev, const struct pci_device_id *id) err_exit: if (lpss->board->exit) lpss->board->exit(lpss); + pci_free_irq_vectors(pdev); return ret; } @@ -329,10 +340,11 @@ static void lpss8250_remove(struct pci_dev *pdev) { struct lpss8250 *lpss = pci_get_drvdata(pdev); - serial8250_unregister_port(lpss->line); + serial8250_unregister_port(lpss->data.line); if (lpss->board->exit) lpss->board->exit(lpss); + pci_free_irq_vectors(pdev); } static const struct lpss8250_board byt_board = { @@ -341,6 +353,11 @@ static const struct lpss8250_board byt_board = { .setup = byt_serial_setup, }; +static const struct lpss8250_board ehl_board = { + .freq = 200000000, + .base_baud = 12500000, +}; + static const struct lpss8250_board qrk_board = { .freq = 44236800, .base_baud = 2764800, @@ -348,17 +365,21 @@ static const struct lpss8250_board qrk_board = { .exit = qrk_serial_exit, }; -#define LPSS_DEVICE(id, board) { PCI_VDEVICE(INTEL, id), (kernel_ulong_t)&board } - static const struct pci_device_id pci_ids[] = { - LPSS_DEVICE(PCI_DEVICE_ID_INTEL_QRK_UARTx, qrk_board), - LPSS_DEVICE(PCI_DEVICE_ID_INTEL_BYT_UART1, byt_board), - LPSS_DEVICE(PCI_DEVICE_ID_INTEL_BYT_UART2, byt_board), - LPSS_DEVICE(PCI_DEVICE_ID_INTEL_BSW_UART1, byt_board), - LPSS_DEVICE(PCI_DEVICE_ID_INTEL_BSW_UART2, byt_board), - LPSS_DEVICE(PCI_DEVICE_ID_INTEL_BDW_UART1, byt_board), - LPSS_DEVICE(PCI_DEVICE_ID_INTEL_BDW_UART2, byt_board), - { }, + { PCI_DEVICE_DATA(INTEL, QRK_UARTx, &qrk_board) }, + { PCI_DEVICE_DATA(INTEL, EHL_UART0, &ehl_board) }, + { PCI_DEVICE_DATA(INTEL, EHL_UART1, &ehl_board) }, + { PCI_DEVICE_DATA(INTEL, EHL_UART2, &ehl_board) }, + { PCI_DEVICE_DATA(INTEL, EHL_UART3, &ehl_board) }, + { PCI_DEVICE_DATA(INTEL, EHL_UART4, &ehl_board) }, + { PCI_DEVICE_DATA(INTEL, EHL_UART5, &ehl_board) }, + { PCI_DEVICE_DATA(INTEL, BYT_UART1, &byt_board) }, + { PCI_DEVICE_DATA(INTEL, BYT_UART2, &byt_board) }, + { PCI_DEVICE_DATA(INTEL, BSW_UART1, &byt_board) }, + { PCI_DEVICE_DATA(INTEL, BSW_UART2, &byt_board) }, + { PCI_DEVICE_DATA(INTEL, BDW_UART1, &byt_board) }, + { PCI_DEVICE_DATA(INTEL, BDW_UART2, &byt_board) }, + { } }; MODULE_DEVICE_TABLE(pci, pci_ids); diff --git a/drivers/tty/serial/8250/8250_men_mcb.c b/drivers/tty/serial/8250/8250_men_mcb.c index 02c5aff58a74..e985f344b2dd 100644 --- a/drivers/tty/serial/8250/8250_men_mcb.c +++ b/drivers/tty/serial/8250/8250_men_mcb.c @@ -72,8 +72,8 @@ static int serial_8250_men_mcb_probe(struct mcb_device *mdev, { struct serial_8250_men_mcb_data *data; struct resource *mem; - unsigned int num_ports; - unsigned int i; + int num_ports; + int i; void __iomem *membase; mem = mcb_get_resource(mdev, IORESOURCE_MEM); @@ -88,7 +88,7 @@ static int serial_8250_men_mcb_probe(struct mcb_device *mdev, dev_dbg(&mdev->dev, "found a 16z%03u with %u ports\n", mdev->id, num_ports); - if (num_ports == 0 || num_ports > 4) { + if (num_ports <= 0 || num_ports > 4) { dev_err(&mdev->dev, "unexpected number of ports: %u\n", num_ports); return -ENODEV; @@ -133,7 +133,7 @@ static int serial_8250_men_mcb_probe(struct mcb_device *mdev, static void serial_8250_men_mcb_remove(struct mcb_device *mdev) { - unsigned int num_ports, i; + int num_ports, i; struct serial_8250_men_mcb_data *data = mcb_get_drvdata(mdev); if (!data) @@ -174,3 +174,4 @@ MODULE_AUTHOR("Michael Moese <michael.moese@men.de"); MODULE_ALIAS("mcb:16z125"); MODULE_ALIAS("mcb:16z025"); MODULE_ALIAS("mcb:16z057"); +MODULE_IMPORT_NS(MCB); diff --git a/drivers/tty/serial/8250/8250_moxa.c b/drivers/tty/serial/8250/8250_moxa.c deleted file mode 100644 index 1ee4cd94d4fa..000000000000 --- a/drivers/tty/serial/8250/8250_moxa.c +++ /dev/null @@ -1,155 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * 8250_moxa.c - MOXA Smartio/Industio MUE multiport serial driver. - * - * Author: Mathieu OTHACEHE <m.othacehe@gmail.com> - */ - -#include <linux/module.h> -#include <linux/pci.h> - -#include "8250.h" - -#define PCI_DEVICE_ID_MOXA_CP102E 0x1024 -#define PCI_DEVICE_ID_MOXA_CP102EL 0x1025 -#define PCI_DEVICE_ID_MOXA_CP104EL_A 0x1045 -#define PCI_DEVICE_ID_MOXA_CP114EL 0x1144 -#define PCI_DEVICE_ID_MOXA_CP116E_A_A 0x1160 -#define PCI_DEVICE_ID_MOXA_CP116E_A_B 0x1161 -#define PCI_DEVICE_ID_MOXA_CP118EL_A 0x1182 -#define PCI_DEVICE_ID_MOXA_CP118E_A_I 0x1183 -#define PCI_DEVICE_ID_MOXA_CP132EL 0x1322 -#define PCI_DEVICE_ID_MOXA_CP134EL_A 0x1342 -#define PCI_DEVICE_ID_MOXA_CP138E_A 0x1381 -#define PCI_DEVICE_ID_MOXA_CP168EL_A 0x1683 - -#define MOXA_BASE_BAUD 921600 -#define MOXA_UART_OFFSET 0x200 -#define MOXA_BASE_BAR 1 - -struct moxa8250_board { - unsigned int num_ports; - int line[0]; -}; - -enum { - moxa8250_2p = 0, - moxa8250_4p, - moxa8250_8p -}; - -static struct moxa8250_board moxa8250_boards[] = { - [moxa8250_2p] = { .num_ports = 2}, - [moxa8250_4p] = { .num_ports = 4}, - [moxa8250_8p] = { .num_ports = 8}, -}; - -static int moxa8250_probe(struct pci_dev *pdev, const struct pci_device_id *id) -{ - struct uart_8250_port uart; - struct moxa8250_board *brd; - void __iomem *ioaddr; - resource_size_t baseaddr; - unsigned int i, nr_ports; - unsigned int offset; - int ret; - - brd = &moxa8250_boards[id->driver_data]; - nr_ports = brd->num_ports; - - ret = pcim_enable_device(pdev); - if (ret) - return ret; - - brd = devm_kzalloc(&pdev->dev, sizeof(struct moxa8250_board) + - sizeof(unsigned int) * nr_ports, GFP_KERNEL); - if (!brd) - return -ENOMEM; - brd->num_ports = nr_ports; - - memset(&uart, 0, sizeof(struct uart_8250_port)); - - uart.port.dev = &pdev->dev; - uart.port.irq = pdev->irq; - uart.port.uartclk = MOXA_BASE_BAUD * 16; - uart.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ; - - baseaddr = pci_resource_start(pdev, MOXA_BASE_BAR); - ioaddr = pcim_iomap(pdev, MOXA_BASE_BAR, 0); - if (!ioaddr) - return -ENOMEM; - - for (i = 0; i < nr_ports; i++) { - - /* - * MOXA Smartio MUE boards with 4 ports have - * a different offset for port #3 - */ - if (nr_ports == 4 && i == 3) - offset = 7 * MOXA_UART_OFFSET; - else - offset = i * MOXA_UART_OFFSET; - - uart.port.iotype = UPIO_MEM; - uart.port.iobase = 0; - uart.port.mapbase = baseaddr + offset; - uart.port.membase = ioaddr + offset; - uart.port.regshift = 0; - - dev_dbg(&pdev->dev, "Setup PCI port: port %lx, irq %d, type %d\n", - uart.port.iobase, uart.port.irq, uart.port.iotype); - - brd->line[i] = serial8250_register_8250_port(&uart); - if (brd->line[i] < 0) { - dev_err(&pdev->dev, - "Couldn't register serial port %lx, irq %d, type %d, error %d\n", - uart.port.iobase, uart.port.irq, - uart.port.iotype, brd->line[i]); - break; - } - } - - pci_set_drvdata(pdev, brd); - return 0; -} - -static void moxa8250_remove(struct pci_dev *pdev) -{ - struct moxa8250_board *brd = pci_get_drvdata(pdev); - unsigned int i; - - for (i = 0; i < brd->num_ports; i++) - serial8250_unregister_port(brd->line[i]); -} - -#define MOXA_DEVICE(id, data) { PCI_VDEVICE(MOXA, id), (kernel_ulong_t)data } - -static const struct pci_device_id pci_ids[] = { - MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP102E, moxa8250_2p), - MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP102EL, moxa8250_2p), - MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP104EL_A, moxa8250_4p), - MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP114EL, moxa8250_4p), - MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP116E_A_A, moxa8250_8p), - MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP116E_A_B, moxa8250_8p), - MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP118EL_A, moxa8250_8p), - MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP118E_A_I, moxa8250_8p), - MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP132EL, moxa8250_2p), - MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP134EL_A, moxa8250_4p), - MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP138E_A, moxa8250_8p), - MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP168EL_A, moxa8250_8p), - {0} -}; -MODULE_DEVICE_TABLE(pci, pci_ids); - -static struct pci_driver moxa8250_pci_driver = { - .name = "8250_moxa", - .id_table = pci_ids, - .probe = moxa8250_probe, - .remove = moxa8250_remove, -}; - -module_pci_driver(moxa8250_pci_driver); - -MODULE_AUTHOR("Mathieu OTHACEHE"); -MODULE_DESCRIPTION("MOXA SmartIO MUE driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c index b411ba4eb5e9..4d067f515f74 100644 --- a/drivers/tty/serial/8250/8250_mtk.c +++ b/drivers/tty/serial/8250/8250_mtk.c @@ -544,7 +544,7 @@ static int mtk8250_probe(struct platform_device *pdev) pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); - data->rx_wakeup_irq = platform_get_irq(pdev, 1); + data->rx_wakeup_irq = platform_get_irq_optional(pdev, 1); return 0; } diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c index 0826cfdbd406..531ad67395e0 100644 --- a/drivers/tty/serial/8250/8250_of.c +++ b/drivers/tty/serial/8250/8250_of.c @@ -48,6 +48,36 @@ static inline void tegra_serial_handle_break(struct uart_port *port) } #endif +static int of_8250_rs485_config(struct uart_port *port, + struct serial_rs485 *rs485) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + /* Clamp the delays to [0, 100ms] */ + rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U); + rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U); + + port->rs485 = *rs485; + + /* + * Both serial8250_em485_init and serial8250_em485_destroy + * are idempotent + */ + if (rs485->flags & SER_RS485_ENABLED) { + int ret = serial8250_em485_init(up); + + if (ret) { + rs485->flags &= ~SER_RS485_ENABLED; + port->rs485.flags &= ~SER_RS485_ENABLED; + } + return ret; + } + + serial8250_em485_destroy(up); + + return 0; +} + /* * Fill a struct uart_port for a given device node */ @@ -178,6 +208,7 @@ static int of_platform_serial_setup(struct platform_device *ofdev, port->flags |= UPF_SKIP_TEST; port->dev = &ofdev->dev; + port->rs485_config = of_8250_rs485_config; switch (type) { case PORT_TEGRA: @@ -191,8 +222,10 @@ static int of_platform_serial_setup(struct platform_device *ofdev, if (IS_ENABLED(CONFIG_SERIAL_8250_FSL) && (of_device_is_compatible(np, "fsl,ns16550") || - of_device_is_compatible(np, "fsl,16550-FIFO64"))) + of_device_is_compatible(np, "fsl,16550-FIFO64"))) { port->handle_irq = fsl8250_handle_irq; + port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE); + } return 0; err_unprepare: diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 3ef65cbd2478..6f343ca08440 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -8,10 +8,6 @@ * */ -#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - #include <linux/clk.h> #include <linux/device.h> #include <linux/io.h> @@ -141,7 +137,7 @@ static void omap8250_set_mctrl(struct uart_port *port, unsigned int mctrl) serial8250_do_set_mctrl(port, mctrl); - if (!up->gpios) { + if (!mctrl_gpio_to_gpiod(up->gpios, UART_GPIO_RTS)) { /* * Turn off autoRTS if RTS is lowered and restore autoRTS * setting if RTS is raised @@ -456,7 +452,8 @@ static void omap_8250_set_termios(struct uart_port *port, up->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF); if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW && - !up->gpios) { + !mctrl_gpio_to_gpiod(up->gpios, UART_GPIO_RTS) && + !mctrl_gpio_to_gpiod(up->gpios, UART_GPIO_CTS)) { /* Enable AUTOCTS (autoRTS is enabled when RTS is raised) */ up->port.status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS; priv->efr |= UART_EFR_CTS; @@ -1146,7 +1143,7 @@ static int omap8250_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - membase = devm_ioremap_nocache(&pdev->dev, regs->start, + membase = devm_ioremap(&pdev->dev, regs->start, resource_size(regs)); if (!membase) return -ENODEV; @@ -1191,6 +1188,7 @@ static int omap8250_probe(struct platform_device *pdev) up.port.throttle = omap_8250_throttle; up.port.unthrottle = omap_8250_unthrottle; up.port.rs485_config = omap_8250_rs485_config; + up.port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE); ret = of_alias_get_id(np, "serial"); if (ret < 0) { @@ -1234,7 +1232,16 @@ static int omap8250_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, true); pm_runtime_use_autosuspend(&pdev->dev); - pm_runtime_set_autosuspend_delay(&pdev->dev, -1); + + /* + * Disable runtime PM until autosuspend delay unless specifically + * enabled by the user via sysfs. This is the historic way to + * prevent an unsafe default policy with lossy characters on wake-up. + * For serdev devices this is not needed, the policy can be managed by + * the serdev driver. + */ + if (!of_get_available_child_count(pdev->dev.of_node)) + pm_runtime_set_autosuspend_delay(&pdev->dev, -1); pm_runtime_irq_safe(&pdev->dev); pm_runtime_enable(&pdev->dev); diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 7f740b37700b..939685fed396 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -43,7 +43,10 @@ struct pci_serial_quirk { void (*exit)(struct pci_dev *dev); }; -#define PCI_NUM_BAR_RESOURCES 6 +struct f815xxa_data { + spinlock_t lock; + int idx; +}; struct serial_private { struct pci_dev *dev; @@ -53,6 +56,16 @@ struct serial_private { int line[0]; }; +static const struct pci_device_id pci_use_msi[] = { + { PCI_DEVICE_SUB(PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900, + 0xA000, 0x1000) }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9912, + 0xA000, 0x1000) }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9922, + 0xA000, 0x1000) }, + { } +}; + static int pci_default_setup(struct serial_private*, const struct pciserial_board*, struct uart_8250_port *, int); @@ -74,7 +87,7 @@ setup_port(struct serial_private *priv, struct uart_8250_port *port, { struct pci_dev *dev = priv->dev; - if (bar >= PCI_NUM_BAR_RESOURCES) + if (bar >= PCI_STD_NUM_BARS) return -EINVAL; if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) { @@ -262,7 +275,7 @@ static int pci_plx9050_init(struct pci_dev *dev) /* * enable/disable interrupts */ - p = ioremap_nocache(pci_resource_start(dev, 0), 0x80); + p = ioremap(pci_resource_start(dev, 0), 0x80); if (p == NULL) return -ENOMEM; writel(irq_config, p + 0x4c); @@ -286,7 +299,7 @@ static void pci_plx9050_exit(struct pci_dev *dev) /* * disable interrupts */ - p = ioremap_nocache(pci_resource_start(dev, 0), 0x80); + p = ioremap(pci_resource_start(dev, 0), 0x80); if (p != NULL) { writel(0, p + 0x4c); @@ -462,7 +475,7 @@ static int pci_siig10x_init(struct pci_dev *dev) break; } - p = ioremap_nocache(pci_resource_start(dev, 0), 0x80); + p = ioremap(pci_resource_start(dev, 0), 0x80); if (p == NULL) return -ENOMEM; @@ -1596,6 +1609,77 @@ static int pci_fintek_init(struct pci_dev *dev) return max_port; } +static void f815xxa_mem_serial_out(struct uart_port *p, int offset, int value) +{ + struct f815xxa_data *data = p->private_data; + unsigned long flags; + + spin_lock_irqsave(&data->lock, flags); + writeb(value, p->membase + offset); + readb(p->membase + UART_SCR); /* Dummy read for flush pcie tx queue */ + spin_unlock_irqrestore(&data->lock, flags); +} + +static int pci_fintek_f815xxa_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) +{ + struct pci_dev *pdev = priv->dev; + struct f815xxa_data *data; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->idx = idx; + spin_lock_init(&data->lock); + + port->port.private_data = data; + port->port.iotype = UPIO_MEM; + port->port.flags |= UPF_IOREMAP; + port->port.mapbase = pci_resource_start(pdev, 0) + 8 * idx; + port->port.serial_out = f815xxa_mem_serial_out; + + return 0; +} + +static int pci_fintek_f815xxa_init(struct pci_dev *dev) +{ + u32 max_port, i; + int config_base; + + if (!(pci_resource_flags(dev, 0) & IORESOURCE_MEM)) + return -ENODEV; + + switch (dev->device) { + case 0x1204: /* 4 ports */ + case 0x1208: /* 8 ports */ + max_port = dev->device & 0xff; + break; + case 0x1212: /* 12 ports */ + max_port = 12; + break; + default: + return -EINVAL; + } + + /* Set to mmio decode */ + pci_write_config_byte(dev, 0x209, 0x40); + + for (i = 0; i < max_port; ++i) { + /* UART0 configuration offset start from 0x2A0 */ + config_base = 0x2A0 + 0x08 * i; + + /* Select 128-byte FIFO and 8x FIFO threshold */ + pci_write_config_byte(dev, config_base + 0x01, 0x33); + + /* Enable UART I/O port */ + pci_write_config_byte(dev, config_base + 0, 0x01); + } + + return max_port; +} + static int skip_tx_en_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) @@ -1692,6 +1776,46 @@ pci_wch_ch38x_setup(struct serial_private *priv, return pci_default_setup(priv, board, port, idx); } +static int +pci_sunix_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) +{ + int bar; + int offset; + + port->port.flags |= UPF_FIXED_TYPE; + port->port.type = PORT_SUNIX; + + if (idx < 4) { + bar = 0; + offset = idx * board->uart_offset; + } else { + bar = 1; + idx -= 4; + idx = div_s64_rem(idx, 4, &offset); + offset = idx * 64 + offset * board->uart_offset; + } + + return setup_port(priv, port, bar, offset, 0); +} + +static int +pci_moxa_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) +{ + unsigned int bar = FL_GET_BASE(board->flags); + int offset; + + if (board->num_ports == 4 && idx == 3) + offset = 7 * board->uart_offset; + else + offset = idx * board->uart_offset; + + return setup_port(priv, port, bar, offset, 0); +} + #define PCI_VENDOR_ID_SBSMODULARIO 0x124B #define PCI_SUBVENDOR_ID_SBSMODULARIO 0x124B #define PCI_DEVICE_ID_OCTPRO 0x0001 @@ -1787,6 +1911,18 @@ pci_wch_ch38x_setup(struct serial_private *priv, #define PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM 0x11D8 +#define PCI_DEVICE_ID_MOXA_CP102E 0x1024 +#define PCI_DEVICE_ID_MOXA_CP102EL 0x1025 +#define PCI_DEVICE_ID_MOXA_CP104EL_A 0x1045 +#define PCI_DEVICE_ID_MOXA_CP114EL 0x1144 +#define PCI_DEVICE_ID_MOXA_CP116E_A_A 0x1160 +#define PCI_DEVICE_ID_MOXA_CP116E_A_B 0x1161 +#define PCI_DEVICE_ID_MOXA_CP118EL_A 0x1182 +#define PCI_DEVICE_ID_MOXA_CP118E_A_I 0x1183 +#define PCI_DEVICE_ID_MOXA_CP132EL 0x1322 +#define PCI_DEVICE_ID_MOXA_CP134EL_A 0x1342 +#define PCI_DEVICE_ID_MOXA_CP138E_A 0x1381 +#define PCI_DEVICE_ID_MOXA_CP168EL_A 0x1683 /* Unknown vendors/cards - this should not be in linux/pci_ids.h */ #define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584 @@ -2289,21 +2425,14 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .setup = pci_timedia_setup, }, /* - * SUNIX (Timedia) cards - * Do not "probe" for these cards as there is at least one combination - * card that should be handled by parport_pc that doesn't match the - * rule in pci_timedia_probe. - * It is part number is MIO5079A but its subdevice ID is 0x0102. - * There are some boards with part number SER5037AL that report - * subdevice ID 0x0002. + * Sunix PCI serial boards */ { .vendor = PCI_VENDOR_ID_SUNIX, .device = PCI_DEVICE_ID_SUNIX_1999, .subvendor = PCI_VENDOR_ID_SUNIX, .subdevice = PCI_ANY_ID, - .init = pci_timedia_init, - .setup = pci_timedia_setup, + .setup = pci_sunix_setup, }, /* * Xircom cards @@ -2563,6 +2692,40 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .setup = pci_fintek_setup, .init = pci_fintek_init, }, + /* + * MOXA + */ + { + .vendor = PCI_VENDOR_ID_MOXA, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_moxa_setup, + }, + { + .vendor = 0x1c29, + .device = 0x1204, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_fintek_f815xxa_setup, + .init = pci_fintek_f815xxa_init, + }, + { + .vendor = 0x1c29, + .device = 0x1208, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_fintek_f815xxa_setup, + .init = pci_fintek_f815xxa_init, + }, + { + .vendor = 0x1c29, + .device = 0x1212, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_fintek_f815xxa_setup, + .init = pci_fintek_f815xxa_init, + }, /* * Default "match everything" terminator entry @@ -2751,12 +2914,23 @@ enum pci_board_num_t { pbn_fintek_4, pbn_fintek_8, pbn_fintek_12, + pbn_fintek_F81504A, + pbn_fintek_F81508A, + pbn_fintek_F81512A, pbn_wch382_2, pbn_wch384_4, pbn_pericom_PI7C9X7951, pbn_pericom_PI7C9X7952, pbn_pericom_PI7C9X7954, pbn_pericom_PI7C9X7958, + pbn_sunix_pci_1s, + pbn_sunix_pci_2s, + pbn_sunix_pci_4s, + pbn_sunix_pci_8s, + pbn_sunix_pci_16s, + pbn_moxa8250_2p, + pbn_moxa8250_4p, + pbn_moxa8250_8p, }; /* @@ -3453,6 +3627,21 @@ static struct pciserial_board pci_boards[] = { .base_baud = 115200, .first_offset = 0x40, }, + [pbn_fintek_F81504A] = { + .num_ports = 4, + .uart_offset = 8, + .base_baud = 115200, + }, + [pbn_fintek_F81508A] = { + .num_ports = 8, + .uart_offset = 8, + .base_baud = 115200, + }, + [pbn_fintek_F81512A] = { + .num_ports = 12, + .uart_offset = 8, + .base_baud = 115200, + }, [pbn_wch382_2] = { .flags = FL_BASE0, .num_ports = 2, @@ -3494,6 +3683,49 @@ static struct pciserial_board pci_boards[] = { .base_baud = 921600, .uart_offset = 0x8, }, + [pbn_sunix_pci_1s] = { + .num_ports = 1, + .base_baud = 921600, + .uart_offset = 0x8, + }, + [pbn_sunix_pci_2s] = { + .num_ports = 2, + .base_baud = 921600, + .uart_offset = 0x8, + }, + [pbn_sunix_pci_4s] = { + .num_ports = 4, + .base_baud = 921600, + .uart_offset = 0x8, + }, + [pbn_sunix_pci_8s] = { + .num_ports = 8, + .base_baud = 921600, + .uart_offset = 0x8, + }, + [pbn_sunix_pci_16s] = { + .num_ports = 16, + .base_baud = 921600, + .uart_offset = 0x8, + }, + [pbn_moxa8250_2p] = { + .flags = FL_BASE1, + .num_ports = 2, + .base_baud = 921600, + .uart_offset = 0x200, + }, + [pbn_moxa8250_4p] = { + .flags = FL_BASE1, + .num_ports = 4, + .base_baud = 921600, + .uart_offset = 0x200, + }, + [pbn_moxa8250_8p] = { + .flags = FL_BASE1, + .num_ports = 8, + .base_baud = 921600, + .uart_offset = 0x200, + }, }; static const struct pci_device_id blacklist[] = { @@ -3507,20 +3739,6 @@ static const struct pci_device_id blacklist[] = { { PCI_DEVICE(0x4348, 0x5053), }, /* WCH CH353 1S1P */ { PCI_DEVICE(0x1c00, 0x3250), }, /* WCH CH382 2S1P */ - /* Moxa Smartio MUE boards handled by 8250_moxa */ - { PCI_VDEVICE(MOXA, 0x1024), }, - { PCI_VDEVICE(MOXA, 0x1025), }, - { PCI_VDEVICE(MOXA, 0x1045), }, - { PCI_VDEVICE(MOXA, 0x1144), }, - { PCI_VDEVICE(MOXA, 0x1160), }, - { PCI_VDEVICE(MOXA, 0x1161), }, - { PCI_VDEVICE(MOXA, 0x1182), }, - { PCI_VDEVICE(MOXA, 0x1183), }, - { PCI_VDEVICE(MOXA, 0x1322), }, - { PCI_VDEVICE(MOXA, 0x1342), }, - { PCI_VDEVICE(MOXA, 0x1381), }, - { PCI_VDEVICE(MOXA, 0x1683), }, - /* Intel platforms with MID UART */ { PCI_VDEVICE(INTEL, 0x081b), }, { PCI_VDEVICE(INTEL, 0x081c), }, @@ -3583,7 +3801,7 @@ serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board) return -ENODEV; num_iomem = num_port = 0; - for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) { + for (i = 0; i < PCI_STD_NUM_BARS; i++) { if (pci_resource_flags(dev, i) & IORESOURCE_IO) { num_port++; if (first_port == -1) @@ -3611,7 +3829,7 @@ serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board) */ first_port = -1; num_port = 0; - for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) { + for (i = 0; i < PCI_STD_NUM_BARS; i++) { if (pci_resource_flags(dev, i) & IORESOURCE_IO && pci_resource_len(dev, i) == 8 && (first_port == -1 || (first_port + num_port) == i)) { @@ -3688,7 +3906,22 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board) memset(&uart, 0, sizeof(uart)); uart.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ; uart.port.uartclk = board->base_baud * 16; - uart.port.irq = get_pci_irq(dev, board); + + if (pci_match_id(pci_use_msi, dev)) { + dev_dbg(&dev->dev, "Using MSI(-X) interrupts\n"); + pci_set_master(dev); + rc = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_ALL_TYPES); + } else { + dev_dbg(&dev->dev, "Using legacy interrupts\n"); + rc = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_LEGACY); + } + if (rc < 0) { + kfree(priv); + priv = ERR_PTR(rc); + goto err_deinit; + } + + uart.port.irq = pci_irq_vector(dev, 0); uart.port.dev = &dev->dev; for (i = 0; i < nr_ports; i++) { @@ -3859,8 +4092,7 @@ static void pciserial_remove_one(struct pci_dev *dev) #ifdef CONFIG_PM_SLEEP static int pciserial_suspend_one(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct serial_private *priv = pci_get_drvdata(pdev); + struct serial_private *priv = dev_get_drvdata(dev); if (priv) pciserial_suspend_ports(priv); @@ -4532,17 +4764,29 @@ static const struct pci_device_id serial_pci_tbl[] = { pbn_b0_bt_1_921600 }, /* - * SUNIX (TIMEDIA) + * Sunix PCI serial boards */ { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, - PCI_VENDOR_ID_SUNIX, PCI_ANY_ID, - PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xffff00, - pbn_b0_bt_1_921600 }, - + PCI_VENDOR_ID_SUNIX, 0x0001, 0, 0, + pbn_sunix_pci_1s }, { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, - PCI_VENDOR_ID_SUNIX, PCI_ANY_ID, - PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00, - pbn_b0_bt_1_921600 }, + PCI_VENDOR_ID_SUNIX, 0x0002, 0, 0, + pbn_sunix_pci_2s }, + { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, + PCI_VENDOR_ID_SUNIX, 0x0004, 0, 0, + pbn_sunix_pci_4s }, + { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, + PCI_VENDOR_ID_SUNIX, 0x0084, 0, 0, + pbn_sunix_pci_4s }, + { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, + PCI_VENDOR_ID_SUNIX, 0x0008, 0, 0, + pbn_sunix_pci_8s }, + { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, + PCI_VENDOR_ID_SUNIX, 0x0088, 0, 0, + pbn_sunix_pci_8s }, + { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, + PCI_VENDOR_ID_SUNIX, 0x0010, 0, 0, + pbn_sunix_pci_16s }, /* * AFAVLAB serial card, from Harald Welte <laforge@gnumonks.org> @@ -5066,6 +5310,46 @@ static const struct pci_device_id serial_pci_tbl[] = { pbn_ni8430_4 }, /* + * MOXA + */ + { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102E, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_moxa8250_2p }, + { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102EL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_moxa8250_2p }, + { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104EL_A, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_moxa8250_4p }, + { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP114EL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_moxa8250_4p }, + { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP116E_A_A, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_moxa8250_8p }, + { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP116E_A_B, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_moxa8250_8p }, + { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP118EL_A, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_moxa8250_8p }, + { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP118E_A_I, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_moxa8250_8p }, + { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP132EL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_moxa8250_2p }, + { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP134EL_A, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_moxa8250_4p }, + { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP138E_A, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_moxa8250_8p }, + { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP168EL_A, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_moxa8250_8p }, + + /* * ADDI-DATA GmbH communication cards <info@addi-data.com> */ { PCI_VENDOR_ID_ADDIDATA, @@ -5292,6 +5576,9 @@ static const struct pci_device_id serial_pci_tbl[] = { { PCI_DEVICE(0x1c29, 0x1104), .driver_data = pbn_fintek_4 }, { PCI_DEVICE(0x1c29, 0x1108), .driver_data = pbn_fintek_8 }, { PCI_DEVICE(0x1c29, 0x1112), .driver_data = pbn_fintek_12 }, + { PCI_DEVICE(0x1c29, 0x1204), .driver_data = pbn_fintek_F81504A }, + { PCI_DEVICE(0x1c29, 0x1208), .driver_data = pbn_fintek_F81508A }, + { PCI_DEVICE(0x1c29, 0x1212), .driver_data = pbn_fintek_F81512A }, /* MKS Tenta SCOM-080x serial cards */ { PCI_DEVICE(0x1601, 0x0800), .driver_data = pbn_b0_4_1250000 }, diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c index dfca33141fcc..de90d681b64c 100644 --- a/drivers/tty/serial/8250/8250_pnp.c +++ b/drivers/tty/serial/8250/8250_pnp.c @@ -498,10 +498,9 @@ static void serial_pnp_remove(struct pnp_dev *dev) serial8250_unregister_port(line - 1); } -#ifdef CONFIG_PM -static int serial_pnp_suspend(struct pnp_dev *dev, pm_message_t state) +static int __maybe_unused serial_pnp_suspend(struct device *dev) { - long line = (long)pnp_get_drvdata(dev); + long line = (long)dev_get_drvdata(dev); if (!line) return -ENODEV; @@ -509,26 +508,25 @@ static int serial_pnp_suspend(struct pnp_dev *dev, pm_message_t state) return 0; } -static int serial_pnp_resume(struct pnp_dev *dev) +static int __maybe_unused serial_pnp_resume(struct device *dev) { - long line = (long)pnp_get_drvdata(dev); + long line = (long)dev_get_drvdata(dev); if (!line) return -ENODEV; serial8250_resume_port(line - 1); return 0; } -#else -#define serial_pnp_suspend NULL -#define serial_pnp_resume NULL -#endif /* CONFIG_PM */ + +static SIMPLE_DEV_PM_OPS(serial_pnp_pm_ops, serial_pnp_suspend, serial_pnp_resume); static struct pnp_driver serial_pnp_driver = { .name = "serial", .probe = serial_pnp_probe, .remove = serial_pnp_remove, - .suspend = serial_pnp_suspend, - .resume = serial_pnp_resume, + .driver = { + .pm = &serial_pnp_pm_ops, + }, .id_table = pnp_dev_table, }; diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index c1cec808571b..430e3467aff7 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -11,10 +11,6 @@ * membase is an 'ioremapped' cookie. */ -#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/ioport.h> @@ -40,13 +36,6 @@ #include "8250.h" -/* - * These are definitions for the Exar XR17V35X and XR17(C|D)15X - */ -#define UART_EXAR_INT0 0x80 -#define UART_EXAR_SLEEP 0x8b /* Sleep mode */ -#define UART_EXAR_DVID 0x8d /* Device identification */ - /* Nuvoton NPCM timeout register */ #define UART_NPCM_TOR 7 #define UART_NPCM_TOIE BIT(7) /* Timeout Interrupt Enable */ @@ -308,6 +297,14 @@ static const struct serial8250_config uart_config[] = { .rxtrig_bytes = {1, 4, 8, 14}, .flags = UART_CAP_FIFO, }, + [PORT_SUNIX] = { + .name = "Sunix", + .fifo_size = 128, + .tx_loadsz = 128, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .rxtrig_bytes = {1, 32, 64, 112}, + .flags = UART_CAP_FIFO | UART_CAP_SLEEP, + }, }; /* Uart divisor latch read */ @@ -709,19 +706,8 @@ EXPORT_SYMBOL_GPL(serial8250_rpm_put_tx); static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) { unsigned char lcr = 0, efr = 0; - /* - * Exar UARTs have a SLEEP register that enables or disables - * each UART to enter sleep mode separately. On the XR17V35x the - * register is accessible to each UART at the UART_EXAR_SLEEP - * offset but the UART channel may only write to the corresponding - * bit. - */ + serial8250_rpm_get(p); - if ((p->port.type == PORT_XR17V35X) || - (p->port.type == PORT_XR17D15X)) { - serial_out(p, UART_EXAR_SLEEP, sleep ? 0xff : 0); - goto out; - } if (p->capabilities & UART_CAP_SLEEP) { if (p->capabilities & UART_CAP_EFR) { @@ -738,7 +724,7 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) serial_out(p, UART_LCR, lcr); } } -out: + serial8250_rpm_put(p); } @@ -1011,26 +997,8 @@ static void autoconfig_16550a(struct uart_8250_port *up) up->port.type = PORT_16550A; up->capabilities |= UART_CAP_FIFO; - /* - * XR17V35x UARTs have an extra divisor register, DLD - * that gets enabled with when DLAB is set which will - * cause the device to incorrectly match and assign - * port type to PORT_16650. The EFR for this UART is - * found at offset 0x09. Instead check the Deice ID (DVID) - * register for a 2, 4 or 8 port UART. - */ - if (up->port.flags & UPF_EXAR_EFR) { - status1 = serial_in(up, UART_EXAR_DVID); - if (status1 == 0x82 || status1 == 0x84 || status1 == 0x88) { - DEBUG_AUTOCONF("Exar XR17V35x "); - up->port.type = PORT_XR17V35X; - up->capabilities |= UART_CAP_AFE | UART_CAP_EFR | - UART_CAP_SLEEP; - - return; - } - - } + if (!IS_ENABLED(CONFIG_SERIAL_8250_16550A_VARIANTS)) + return; /* * Check for presence of the EFR when DLAB is set. @@ -1171,18 +1139,6 @@ static void autoconfig_16550a(struct uart_8250_port *up) serial_out(up, UART_IER, iersave); /* - * Exar uarts have EFR in a weird location - */ - if (up->port.flags & UPF_EXAR_EFR) { - DEBUG_AUTOCONF("Exar XR17D15x "); - up->port.type = PORT_XR17D15X; - up->capabilities |= UART_CAP_AFE | UART_CAP_EFR | - UART_CAP_SLEEP; - - return; - } - - /* * We distinguish between 16550A and U6 16550A by counting * how many bytes are in the FIFO. */ @@ -2157,20 +2113,6 @@ int serial8250_do_startup(struct uart_port *port) enable_rsa(up); #endif - if (port->type == PORT_XR17V35X) { - /* - * First enable access to IER [7:5], ISR [5:4], FCR [5:4], - * MCR [7:5] and MSR [7:0] - */ - serial_port_out(port, UART_XR_EFR, UART_EFR_ECB); - - /* - * Make sure all interrups are masked until initialization is - * complete and the FIFOs are cleared - */ - serial_port_out(port, UART_IER, 0); - } - /* * Clear the FIFO buffers and disable them. * (they will be reenabled in set_termios()) @@ -2184,8 +2126,6 @@ int serial8250_do_startup(struct uart_port *port) serial_port_in(port, UART_RX); serial_port_in(port, UART_IIR); serial_port_in(port, UART_MSR); - if ((port->type == PORT_XR17V35X) || (port->type == PORT_XR17D15X)) - serial_port_in(port, UART_EXAR_INT0); /* * At this point, there's no way the LSR could still be 0xff; @@ -2343,8 +2283,6 @@ dont_test_tx_en: serial_port_in(port, UART_RX); serial_port_in(port, UART_IIR); serial_port_in(port, UART_MSR); - if ((port->type == PORT_XR17V35X) || (port->type == PORT_XR17D15X)) - serial_port_in(port, UART_EXAR_INT0); up->lsr_saved_flags = 0; up->msr_saved_flags = 0; @@ -2453,23 +2391,6 @@ static void serial8250_shutdown(struct uart_port *port) serial8250_do_shutdown(port); } -/* - * XR17V35x UARTs have an extra fractional divisor register (DLD) - * Calculate divisor with extra 4-bit fractional portion - */ -static unsigned int xr17v35x_get_divisor(struct uart_8250_port *up, - unsigned int baud, - unsigned int *frac) -{ - struct uart_port *port = &up->port; - unsigned int quot_16; - - quot_16 = DIV_ROUND_CLOSEST(port->uartclk, baud); - *frac = quot_16 & 0x0f; - - return quot_16 >> 4; -} - /* Nuvoton NPCM UARTs have a custom divisor calculation */ static unsigned int npcm_get_divisor(struct uart_8250_port *up, unsigned int baud) @@ -2497,8 +2418,6 @@ static unsigned int serial8250_do_get_divisor(struct uart_port *port, else if ((port->flags & UPF_MAGIC_MULTIPLIER) && baud == (port->uartclk/8)) quot = 0x8002; - else if (up->port.type == PORT_XR17V35X) - quot = xr17v35x_get_divisor(up, baud, frac); else if (up->port.type == PORT_NPCM) quot = npcm_get_divisor(up, baud); else @@ -2585,13 +2504,6 @@ void serial8250_do_set_divisor(struct uart_port *port, unsigned int baud, serial_port_out(port, UART_LCR, up->lcr | UART_LCR_DLAB); serial_dl_write(up, quot); - - /* XR17V35x UARTs have an extra fractional divisor register (DLD) */ - if (up->port.type == PORT_XR17V35X) { - /* Preserve bits not related to baudrate; DLD[7:4]. */ - quot_frac |= serial_port_in(port, 0x2) & 0xf0; - serial_port_out(port, 0x2, quot_frac); - } } EXPORT_SYMBOL_GPL(serial8250_do_set_divisor); @@ -2853,7 +2765,7 @@ static int serial8250_request_std_resource(struct uart_8250_port *up) } if (port->flags & UPF_IOREMAP) { - port->membase = ioremap_nocache(port->mapbase, size); + port->membase = ioremap(port->mapbase, size); if (!port->membase) { release_mem_region(port->mapbase, size); ret = -ENOMEM; @@ -3142,6 +3054,7 @@ void serial8250_init_port(struct uart_8250_port *up) spin_lock_init(&port->lock); port->ops = &serial8250_pops; + port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE); up->cur_iotype = 0xFF; } diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c index 164ba133437a..e0b73a5402db 100644 --- a/drivers/tty/serial/8250/8250_uniphier.c +++ b/drivers/tty/serial/8250/8250_uniphier.c @@ -176,10 +176,8 @@ static int uniphier_uart_probe(struct platform_device *pdev) return -ENOMEM; irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(dev, "failed to get IRQ number\n"); + if (irq < 0) return irq; - } priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index 509f6a3bb9ff..f16824bbb573 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -60,6 +60,16 @@ config SERIAL_8250_PNP This builds standard PNP serial support. You may be able to disable this feature if you only need legacy serial support. +config SERIAL_8250_16550A_VARIANTS + bool "Support for variants of the 16550A serial port" + depends on SERIAL_8250 + help + The 8250 driver can probe for many variants of the venerable 16550A + serial port. Doing so takes additional time at boot. + + On modern systems, especially those using serial only for a simple + console, you can say N here. + config SERIAL_8250_FINTEK bool "Support for Fintek F81216A LPC to 4 UART RS485 API" depends on SERIAL_8250 @@ -243,6 +253,7 @@ config SERIAL_8250_ASPEED_VUART tristate "Aspeed Virtual UART" depends on SERIAL_8250 depends on OF + depends on REGMAP && MFD_SYSCON help If you want to use the virtual UART (VUART) device on Aspeed BMC platforms, enable this option. This enables the 16550A- @@ -314,6 +325,9 @@ config SERIAL_8250_RSA If you don't have such card, or if unsure, say N. +config SERIAL_8250_DWLIB + bool + config SERIAL_8250_ACORN tristate "Acorn expansion card serial port support" depends on ARCH_ACORN && SERIAL_8250 @@ -331,7 +345,7 @@ config SERIAL_8250_BCM2835AUX Features and limitations of the UART are Registers are similar to 16650 registers, - set bits in the control registers that are unsupported + set bits in the control registers that are unsupported are ignored and read back as 0 7/8 bit operation with 1 start and 1 stop bit 8 symbols deep fifo for rx and tx @@ -354,6 +368,7 @@ config SERIAL_8250_FSL config SERIAL_8250_DW tristate "Support for Synopsys DesignWare 8250 quirks" depends on SERIAL_8250 + select SERIAL_8250_DWLIB help Selecting this option will enable handling of the extra features present in the Synopsys DesignWare APB UART. @@ -366,6 +381,17 @@ config SERIAL_8250_EM port hardware found on the Emma Mobile line of processors. If unsure, say N. +config SERIAL_8250_IOC3 + tristate "SGI IOC3 8250 UART support" + depends on SGI_MFD_IOC3 && SERIAL_8250 + select SERIAL_8250_EXTENDED + select SERIAL_8250_SHARE_IRQ + help + Enable this if you have a SGI Origin or Octane machine. This module + provides basic serial support by directly driving the UART chip + behind the IOC3 device on those systems. Maximum baud speed is + 38400bps using this driver. + config SERIAL_8250_RT288X bool "Ralink RT288x/RT305x/RT3662/RT3883 serial port support" depends on SERIAL_8250 @@ -440,6 +466,7 @@ config SERIAL_8250_LPSS default SERIAL_8250 depends on SERIAL_8250 && PCI depends on X86 || COMPILE_TEST + select SERIAL_8250_DWLIB select DW_DMAC_CORE if SERIAL_8250_DMA select DW_DMAC_PCI if (SERIAL_8250_DMA && X86_INTEL_LPSS) select RATIONAL @@ -463,16 +490,6 @@ config SERIAL_8250_MID present on the UART found on Intel Medfield SOC and various other Intel platforms. -config SERIAL_8250_MOXA - tristate "MOXA SmartIO MUE support" - depends on SERIAL_8250 && PCI - help - Say Y here if you have a Moxa SmartIO MUE multiport serial card. - If unsure, say N. - - This driver can also be built as a module. The module will be called - 8250_moxa. If you want to do that, say M here. - config SERIAL_8250_PXA tristate "PXA serial port support" depends on SERIAL_8250 diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile index 18751bc63a84..51a6079d3f1f 100644 --- a/drivers/tty/serial/8250/Makefile +++ b/drivers/tty/serial/8250/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_SERIAL_8250) += 8250.o 8250_base.o 8250-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o 8250_base-y := 8250_port.o 8250_base-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o +8250_base-$(CONFIG_SERIAL_8250_DWLIB) += 8250_dwlib.o 8250_base-$(CONFIG_SERIAL_8250_FINTEK) += 8250_fintek.o obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o @@ -27,6 +28,7 @@ obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o obj-$(CONFIG_SERIAL_8250_MEN_MCB) += 8250_men_mcb.o obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o +obj-$(CONFIG_SERIAL_8250_IOC3) += 8250_ioc3.o obj-$(CONFIG_SERIAL_8250_OMAP) += 8250_omap.o obj-$(CONFIG_SERIAL_8250_LPC18XX) += 8250_lpc18xx.o obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o @@ -34,7 +36,6 @@ obj-$(CONFIG_SERIAL_8250_UNIPHIER) += 8250_uniphier.o obj-$(CONFIG_SERIAL_8250_INGENIC) += 8250_ingenic.o obj-$(CONFIG_SERIAL_8250_LPSS) += 8250_lpss.o obj-$(CONFIG_SERIAL_8250_MID) += 8250_mid.o -obj-$(CONFIG_SERIAL_8250_MOXA) += 8250_moxa.o obj-$(CONFIG_SERIAL_8250_PXA) += 8250_pxa.o obj-$(CONFIG_SERIAL_OF_PLATFORM) += 8250_of.o |