diff options
Diffstat (limited to 'drivers/tty/serial/8250/8250_dw.c')
-rw-r--r-- | drivers/tty/serial/8250/8250_dw.c | 288 |
1 files changed, 132 insertions, 156 deletions
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 06324f17a0cb..a0cdbf35dcb1 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -63,6 +63,9 @@ struct dw8250_data { struct clk *pclk; struct reset_control *rst; struct uart_8250_dma dma; + + unsigned int skip_autocfg:1; + unsigned int uart_16550_compatible:1; }; #define BYT_PRV_CLK 0x800 @@ -244,24 +247,77 @@ out: serial8250_do_set_termios(p, termios, old); } -static bool dw8250_dma_filter(struct dma_chan *chan, void *param) +/* + * dw8250_fallback_dma_filter will prevent the UART from getting just any free + * channel on platforms that have DMA engines, but don't have any channels + * assigned to the UART. + * + * REVISIT: This is a work around for limitation in the DMA Engine API. Once the + * core problem is fixed, this function is no longer needed. + */ +static bool dw8250_fallback_dma_filter(struct dma_chan *chan, void *param) { return false; } -static void dw8250_setup_port(struct uart_8250_port *up) +static bool dw8250_idma_filter(struct dma_chan *chan, void *param) +{ + return param == chan->device->dev->parent; +} + +static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data) { - struct uart_port *p = &up->port; - u32 reg = readl(p->membase + DW_UART_UCV); + if (p->dev->of_node) { + struct device_node *np = p->dev->of_node; + int id; + + /* get index of serial line, if found in DT aliases */ + id = of_alias_get_id(np, "serial"); + if (id >= 0) + p->line = id; +#ifdef CONFIG_64BIT + if (of_device_is_compatible(np, "cavium,octeon-3860-uart")) { + p->serial_in = dw8250_serial_inq; + p->serial_out = dw8250_serial_outq; + p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE; + p->type = PORT_OCTEON; + data->usr_reg = 0x27; + data->skip_autocfg = true; + } +#endif + } else if (has_acpi_companion(p->dev)) { + p->iotype = UPIO_MEM32; + p->regshift = 2; + p->serial_in = dw8250_serial_in32; + p->set_termios = dw8250_set_termios; + /* So far none of there implement the Busy Functionality */ + data->uart_16550_compatible = true; + } + + /* Platforms with iDMA */ + if (platform_get_resource_byname(to_platform_device(p->dev), + IORESOURCE_MEM, "lpss_priv")) { + p->set_termios = dw8250_set_termios; + 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 = readl(p->membase + DW_UART_UCV); if (!reg) return; - dev_dbg_ratelimited(p->dev, "Designware UART version %c.%c%c\n", + dev_dbg(p->dev, "Designware UART version %c.%c%c\n", (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff); reg = readl(p->membase + DW_UART_CPR); @@ -273,7 +329,6 @@ static void dw8250_setup_port(struct uart_8250_port *up) p->type = PORT_16550A; p->flags |= UPF_FIXED_TYPE; p->fifosize = DW_UART_CPR_FIFO_SIZE(reg); - up->tx_loadsz = p->fifosize; up->capabilities = UART_CAP_FIFO; } @@ -281,166 +336,91 @@ static void dw8250_setup_port(struct uart_8250_port *up) up->capabilities |= UART_CAP_AFE; } -static int dw8250_probe_of(struct uart_port *p, - struct dw8250_data *data) +static int dw8250_probe(struct platform_device *pdev) { - struct device_node *np = p->dev->of_node; - struct uart_8250_port *up = up_to_u8250p(p); - u32 val; - bool has_ucv = true; - int id; + struct uart_8250_port 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 dw8250_data *data; + int err; + u32 val; -#ifdef CONFIG_64BIT - if (of_device_is_compatible(np, "cavium,octeon-3860-uart")) { - p->serial_in = dw8250_serial_inq; - p->serial_out = dw8250_serial_outq; - p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE; - p->type = PORT_OCTEON; - data->usr_reg = 0x27; - has_ucv = false; - } else -#endif - if (!of_property_read_u32(np, "reg-io-width", &val)) { - switch (val) { - case 1: - break; - case 4: - p->iotype = UPIO_MEM32; - p->serial_in = dw8250_serial_in32; - p->serial_out = dw8250_serial_out32; - break; - default: - dev_err(p->dev, "unsupported reg-io-width (%u)\n", val); - return -EINVAL; - } + if (!regs) { + dev_err(&pdev->dev, "no registers defined\n"); + return -EINVAL; } - if (has_ucv) - dw8250_setup_port(up); - /* if we have a valid fifosize, try hooking up DMA here */ - if (p->fifosize) { - up->dma = &data->dma; - - up->dma->rxconf.src_maxburst = p->fifosize / 4; - up->dma->txconf.dst_maxburst = p->fifosize / 4; + if (irq < 0) { + if (irq != -EPROBE_DEFER) + dev_err(&pdev->dev, "cannot get irq\n"); + return irq; } - if (!of_property_read_u32(np, "reg-shift", &val)) + spin_lock_init(&p->lock); + p->mapbase = regs->start; + p->irq = irq; + p->handle_irq = dw8250_handle_irq; + p->pm = dw8250_do_pm; + p->type = PORT_8250; + p->flags = UPF_SHARE_IRQ | UPF_FIXED_PORT; + p->dev = &pdev->dev; + p->iotype = UPIO_MEM; + p->serial_in = dw8250_serial_in; + p->serial_out = dw8250_serial_out; + + p->membase = devm_ioremap(&pdev->dev, regs->start, resource_size(regs)); + if (!p->membase) + return -ENOMEM; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->dma.fn = dw8250_fallback_dma_filter; + data->usr_reg = DW_UART_USR; + p->private_data = data; + + data->uart_16550_compatible = device_property_read_bool(p->dev, + "snps,uart-16550-compatible"); + + err = device_property_read_u32(p->dev, "reg-shift", &val); + if (!err) p->regshift = val; - /* get index of serial line, if found in DT aliases */ - id = of_alias_get_id(np, "serial"); - if (id >= 0) - p->line = id; + err = device_property_read_u32(p->dev, "reg-io-width", &val); + if (!err && val == 4) { + p->iotype = UPIO_MEM32; + p->serial_in = dw8250_serial_in32; + p->serial_out = dw8250_serial_out32; + } - if (of_property_read_bool(np, "dcd-override")) { + if (device_property_read_bool(p->dev, "dcd-override")) { /* Always report DCD as active */ data->msr_mask_on |= UART_MSR_DCD; data->msr_mask_off |= UART_MSR_DDCD; } - if (of_property_read_bool(np, "dsr-override")) { + if (device_property_read_bool(p->dev, "dsr-override")) { /* Always report DSR as active */ data->msr_mask_on |= UART_MSR_DSR; data->msr_mask_off |= UART_MSR_DDSR; } - if (of_property_read_bool(np, "cts-override")) { + if (device_property_read_bool(p->dev, "cts-override")) { /* Always report CTS as active */ data->msr_mask_on |= UART_MSR_CTS; data->msr_mask_off |= UART_MSR_DCTS; } - if (of_property_read_bool(np, "ri-override")) { + if (device_property_read_bool(p->dev, "ri-override")) { /* Always report Ring indicator as inactive */ data->msr_mask_off |= UART_MSR_RI; data->msr_mask_off |= UART_MSR_TERI; } - return 0; -} - -static bool dw8250_idma_filter(struct dma_chan *chan, void *param) -{ - struct device *dev = param; - - if (dev != chan->device->dev->parent) - return false; - - return true; -} - -static int dw8250_probe_acpi(struct uart_8250_port *up, - struct dw8250_data *data) -{ - struct uart_port *p = &up->port; - - dw8250_setup_port(up); - - p->iotype = UPIO_MEM32; - p->serial_in = dw8250_serial_in32; - p->serial_out = dw8250_serial_out32; - p->regshift = 2; - - /* Platforms with iDMA */ - if (platform_get_resource_byname(to_platform_device(up->port.dev), - IORESOURCE_MEM, "lpss_priv")) { - data->dma.rx_param = up->port.dev->parent; - data->dma.tx_param = up->port.dev->parent; - data->dma.fn = dw8250_idma_filter; - } - - up->dma = &data->dma; - up->dma->rxconf.src_maxburst = p->fifosize / 4; - up->dma->txconf.dst_maxburst = p->fifosize / 4; - - up->port.set_termios = dw8250_set_termios; - - return 0; -} - -static int dw8250_probe(struct platform_device *pdev) -{ - struct uart_8250_port uart = {}; - struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - int irq = platform_get_irq(pdev, 0); - struct dw8250_data *data; - int err; - - if (!regs) { - dev_err(&pdev->dev, "no registers defined\n"); - return -EINVAL; - } - - if (irq < 0) { - if (irq != -EPROBE_DEFER) - dev_err(&pdev->dev, "cannot get irq\n"); - return irq; - } - - spin_lock_init(&uart.port.lock); - uart.port.mapbase = regs->start; - uart.port.irq = irq; - uart.port.handle_irq = dw8250_handle_irq; - uart.port.pm = dw8250_do_pm; - uart.port.type = PORT_8250; - uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT; - uart.port.dev = &pdev->dev; - - uart.port.membase = devm_ioremap(&pdev->dev, regs->start, - resource_size(regs)); - if (!uart.port.membase) - return -ENOMEM; - - data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; - - data->usr_reg = DW_UART_USR; - /* Always ask for fixed clock rate from a property. */ - device_property_read_u32(&pdev->dev, "clock-frequency", - &uart.port.uartclk); + device_property_read_u32(p->dev, "clock-frequency", &p->uartclk); /* If there is separate baudclk, get the rate from it. */ data->clk = devm_clk_get(&pdev->dev, "baudclk"); @@ -454,11 +434,11 @@ static int dw8250_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "could not enable optional baudclk: %d\n", err); else - uart.port.uartclk = clk_get_rate(data->clk); + p->uartclk = clk_get_rate(data->clk); } /* If no clock rate is defined, fail. */ - if (!uart.port.uartclk) { + if (!p->uartclk) { dev_err(&pdev->dev, "clock rate not defined\n"); return -EINVAL; } @@ -484,26 +464,22 @@ static int dw8250_probe(struct platform_device *pdev) if (!IS_ERR(data->rst)) reset_control_deassert(data->rst); - data->dma.rx_param = data; - data->dma.tx_param = data; - data->dma.fn = dw8250_dma_filter; + dw8250_quirks(p, data); - uart.port.iotype = UPIO_MEM; - uart.port.serial_in = dw8250_serial_in; - uart.port.serial_out = dw8250_serial_out; - uart.port.private_data = data; + /* If the Busy Functionality is not implemented, don't handle it */ + if (data->uart_16550_compatible) { + p->serial_out = NULL; + p->handle_irq = NULL; + } - if (pdev->dev.of_node) { - err = dw8250_probe_of(&uart.port, data); - if (err) - goto err_reset; - } else if (ACPI_HANDLE(&pdev->dev)) { - err = dw8250_probe_acpi(&uart, data); - if (err) - goto err_reset; - } else { - err = -ENODEV; - goto err_reset; + if (!data->skip_autocfg) + dw8250_setup_port(p); + + /* 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->line = serial8250_register_8250_port(&uart); |