diff options
79 files changed, 2357 insertions, 4743 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 274252f205b7..84960c66c77b 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -713,10 +713,18 @@ bytes respectively. Such letter suffixes can also be entirely omitted. uart[8250],io,<addr>[,options] uart[8250],mmio,<addr>[,options] + uart[8250],mmio32,<addr>[,options] + uart[8250],0x<addr>[,options] Start an early, polled-mode console on the 8250/16550 UART at the specified I/O port or MMIO address, - switching to the matching ttyS device later. The - options are the same as for ttyS, above. + switching to the matching ttyS device later. + MMIO inter-register address stride is either 8-bit + (mmio) or 32-bit (mmio32). + If none of [io|mmio|mmio32], <addr> is assumed to be + equivalent to 'mmio'. 'options' are specified in the + same format described for ttyS above; if unspecified, + the h/w is not re-initialized. + hvc<n> Use the hypervisor console device <n>. This is for both Xen and PowerPC hypervisors. @@ -950,11 +958,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted. uart[8250],io,<addr>[,options] uart[8250],mmio,<addr>[,options] uart[8250],mmio32,<addr>[,options] + uart[8250],0x<addr>[,options] Start an early, polled-mode console on the 8250/16550 UART at the specified I/O port or MMIO address. MMIO inter-register address stride is either 8-bit (mmio) or 32-bit (mmio32). - The options are the same as for ttyS, above. + If none of [io|mmio|mmio32], <addr> is assumed to be + equivalent to 'mmio'. 'options' are specified in the + same format described for "console=ttyS<n>"; if + unspecified, the h/w is not initialized. pl011,<addr> Start an early, polled-mode console on a pl011 serial diff --git a/arch/mips/mti-malta/malta-init.c b/arch/mips/mti-malta/malta-init.c index 6849f533154f..cec3e187c48f 100644 --- a/arch/mips/mti-malta/malta-init.c +++ b/arch/mips/mti-malta/malta-init.c @@ -14,7 +14,7 @@ #include <linux/init.h> #include <linux/string.h> #include <linux/kernel.h> -#include <linux/serial_8250.h> +#include <linux/serial_core.h> #include <asm/cacheflush.h> #include <asm/smp-ops.h> @@ -75,7 +75,7 @@ static void __init console_config(void) if ((strstr(fw_getcmdline(), "earlycon=")) == NULL) { sprintf(console_string, "uart8250,io,0x3f8,%d%c%c", baud, parity, bits); - setup_early_serial8250_console(console_string); + setup_earlycon(console_string); } if ((strstr(fw_getcmdline(), "console=")) == NULL) { diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index 20028da8ae18..72484a645f05 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug @@ -43,10 +43,6 @@ config EARLY_PRINTK with klogd/syslogd or the X server. You should normally N here, unless you want to debug such a crash. -config EARLY_PRINTK_INTEL_MID - bool "Early printk for Intel MID platform support" - depends on EARLY_PRINTK && X86_INTEL_MID - config EARLY_PRINTK_DBGP bool "Early printk via EHCI debug port" depends on EARLY_PRINTK && PCI diff --git a/arch/x86/include/asm/intel-mid.h b/arch/x86/include/asm/intel-mid.h index 705d35708a50..7c5af123bdbd 100644 --- a/arch/x86/include/asm/intel-mid.h +++ b/arch/x86/include/asm/intel-mid.h @@ -136,9 +136,6 @@ extern enum intel_mid_timer_options intel_mid_timer_options; #define SFI_MTMR_MAX_NUM 8 #define SFI_MRTC_MAX 8 -extern struct console early_hsu_console; -extern void hsu_early_console_init(const char *); - extern void intel_scu_devices_create(void); extern void intel_scu_devices_destroy(void); diff --git a/arch/x86/include/asm/serial.h b/arch/x86/include/asm/serial.h index 460b84f64556..8378b8c9109c 100644 --- a/arch/x86/include/asm/serial.h +++ b/arch/x86/include/asm/serial.h @@ -12,11 +12,11 @@ /* Standard COM flags (except for COM4, because of the 8514 problem) */ #ifdef CONFIG_SERIAL_DETECT_IRQ -# define STD_COMX_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ) -# define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | 0 | ASYNC_AUTO_IRQ) +# define STD_COMX_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ) +# define STD_COM4_FLAGS (UPF_BOOT_AUTOCONF | 0 | UPF_AUTO_IRQ) #else -# define STD_COMX_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | 0 ) -# define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | 0 | 0 ) +# define STD_COMX_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | 0 ) +# define STD_COM4_FLAGS (UPF_BOOT_AUTOCONF | 0 | 0 ) #endif #define SERIAL_PORT_DFNS \ diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c index 49ff55ef9b26..89427d8d4fc5 100644 --- a/arch/x86/kernel/early_printk.c +++ b/arch/x86/kernel/early_printk.c @@ -375,12 +375,6 @@ static int __init setup_early_printk(char *buf) if (!strncmp(buf, "xen", 3)) early_console_register(&xenboot_console, keep); #endif -#ifdef CONFIG_EARLY_PRINTK_INTEL_MID - if (!strncmp(buf, "hsu", 3)) { - hsu_early_console_init(buf + 3); - early_console_register(&early_hsu_console, keep); - } -#endif #ifdef CONFIG_EARLY_PRINTK_EFI if (!strncmp(buf, "efi", 3)) early_console_register(&early_efi_console, keep); diff --git a/arch/x86/platform/intel-mid/Makefile b/arch/x86/platform/intel-mid/Makefile index 0a8ee703b9fa..0ce1b1913673 100644 --- a/arch/x86/platform/intel-mid/Makefile +++ b/arch/x86/platform/intel-mid/Makefile @@ -1,5 +1,4 @@ obj-$(CONFIG_X86_INTEL_MID) += intel-mid.o intel_mid_vrtc.o mfld.o mrfl.o -obj-$(CONFIG_EARLY_PRINTK_INTEL_MID) += early_printk_intel_mid.o # SFI specific code ifdef CONFIG_X86_INTEL_MID diff --git a/arch/x86/platform/intel-mid/early_printk_intel_mid.c b/arch/x86/platform/intel-mid/early_printk_intel_mid.c deleted file mode 100644 index 4e720829ab90..000000000000 --- a/arch/x86/platform/intel-mid/early_printk_intel_mid.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * early_printk_intel_mid.c - early consoles for Intel MID platforms - * - * Copyright (c) 2008-2010, Intel Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; version 2 - * of the License. - */ - -/* - * This file implements early console named hsu. - * hsu is based on a High Speed UART device which only exists in the Medfield - * platform - */ - -#include <linux/serial_reg.h> -#include <linux/serial_mfd.h> -#include <linux/console.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/io.h> - -#include <asm/fixmap.h> -#include <asm/pgtable.h> -#include <asm/intel-mid.h> - -/* - * Following is the early console based on Medfield HSU (High - * Speed UART) device. - */ -#define HSU_PORT_BASE 0xffa28080 - -static void __iomem *phsu; - -void hsu_early_console_init(const char *s) -{ - unsigned long paddr, port = 0; - u8 lcr; - - /* - * Select the early HSU console port if specified by user in the - * kernel command line. - */ - if (*s && !kstrtoul(s, 10, &port)) - port = clamp_val(port, 0, 2); - - paddr = HSU_PORT_BASE + port * 0x80; - phsu = (void __iomem *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE, paddr); - - /* Disable FIFO */ - writeb(0x0, phsu + UART_FCR); - - /* Set to default 115200 bps, 8n1 */ - lcr = readb(phsu + UART_LCR); - writeb((0x80 | lcr), phsu + UART_LCR); - writeb(0x18, phsu + UART_DLL); - writeb(lcr, phsu + UART_LCR); - writel(0x3600, phsu + UART_MUL*4); - - writeb(0x8, phsu + UART_MCR); - writeb(0x7, phsu + UART_FCR); - writeb(0x3, phsu + UART_LCR); - - /* Clear IRQ status */ - readb(phsu + UART_LSR); - readb(phsu + UART_RX); - readb(phsu + UART_IIR); - readb(phsu + UART_MSR); - - /* Enable FIFO */ - writeb(0x7, phsu + UART_FCR); -} - -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - -static void early_hsu_putc(char ch) -{ - unsigned int timeout = 10000; /* 10ms */ - u8 status; - - while (--timeout) { - status = readb(phsu + UART_LSR); - if (status & BOTH_EMPTY) - break; - udelay(1); - } - - /* Only write the char when there was no timeout */ - if (timeout) - writeb(ch, phsu + UART_TX); -} - -static void early_hsu_write(struct console *con, const char *str, unsigned n) -{ - int i; - - for (i = 0; i < n && *str; i++) { - if (*str == '\n') - early_hsu_putc('\r'); - early_hsu_putc(*str); - str++; - } -} - -struct console early_hsu_console = { - .name = "earlyhsu", - .write = early_hsu_write, - .flags = CON_PRINTBUFFER, - .index = -1, -}; diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 942ca541dcbd..91eced044321 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -112,6 +112,8 @@ config FSL_DMA EloPlus is on mpc85xx and mpc86xx and Pxxx parts, and the Elo3 is on some Txxx and Bxxx parts. +source "drivers/dma/hsu/Kconfig" + config MPC512X_DMA tristate "Freescale MPC512x built-in DMA engine support" depends on PPC_MPC512x || PPC_MPC831x diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index 539d4825bd76..7e8301cb489d 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_DMATEST) += dmatest.o obj-$(CONFIG_INTEL_IOATDMA) += ioat/ obj-$(CONFIG_INTEL_IOP_ADMA) += iop-adma.o obj-$(CONFIG_FSL_DMA) += fsldma.o +obj-$(CONFIG_HSU_DMA) += hsu/ obj-$(CONFIG_MPC512X_DMA) += mpc512x_dma.o obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/ obj-$(CONFIG_MV_XOR) += mv_xor.o diff --git a/drivers/dma/hsu/Kconfig b/drivers/dma/hsu/Kconfig new file mode 100644 index 000000000000..7e98eff7440e --- /dev/null +++ b/drivers/dma/hsu/Kconfig @@ -0,0 +1,14 @@ +# DMA engine configuration for hsu +config HSU_DMA + tristate "High Speed UART DMA support" + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + +config HSU_DMA_PCI + tristate "High Speed UART DMA PCI driver" + depends on PCI + select HSU_DMA + help + Support the High Speed UART DMA on the platfroms that + enumerate it as a PCI device. For example, Intel Medfield + has integrated this HSU DMA controller. diff --git a/drivers/dma/hsu/Makefile b/drivers/dma/hsu/Makefile new file mode 100644 index 000000000000..b8f9af032ef1 --- /dev/null +++ b/drivers/dma/hsu/Makefile @@ -0,0 +1,5 @@ +obj-$(CONFIG_HSU_DMA) += hsu_dma.o +hsu_dma-objs := hsu.o + +obj-$(CONFIG_HSU_DMA_PCI) += hsu_dma_pci.o +hsu_dma_pci-objs := pci.o diff --git a/drivers/dma/hsu/hsu.c b/drivers/dma/hsu/hsu.c new file mode 100644 index 000000000000..9b84def7a353 --- /dev/null +++ b/drivers/dma/hsu/hsu.c @@ -0,0 +1,495 @@ +/* + * Core driver for the High Speed UART DMA + * + * Copyright (C) 2015 Intel Corporation + * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com> + * + * Partially based on the bits found in drivers/tty/serial/mfd.c. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * DMA channel allocation: + * 1. Even number chans are used for DMA Read (UART TX), odd chans for DMA + * Write (UART RX). + * 2. 0/1 channel are assigned to port 0, 2/3 chan to port 1, 4/5 chan to + * port 3, and so on. + */ + +#include <linux/delay.h> +#include <linux/dmaengine.h> +#include <linux/dma-mapping.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/slab.h> + +#include "hsu.h" + +#define HSU_DMA_BUSWIDTHS \ + BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) | \ + BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \ + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \ + BIT(DMA_SLAVE_BUSWIDTH_3_BYTES) | \ + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \ + BIT(DMA_SLAVE_BUSWIDTH_8_BYTES) | \ + BIT(DMA_SLAVE_BUSWIDTH_16_BYTES) + +static inline void hsu_chan_disable(struct hsu_dma_chan *hsuc) +{ + hsu_chan_writel(hsuc, HSU_CH_CR, 0); +} + +static inline void hsu_chan_enable(struct hsu_dma_chan *hsuc) +{ + u32 cr = HSU_CH_CR_CHA; + + if (hsuc->direction == DMA_MEM_TO_DEV) + cr &= ~HSU_CH_CR_CHD; + else if (hsuc->direction == DMA_DEV_TO_MEM) + cr |= HSU_CH_CR_CHD; + + hsu_chan_writel(hsuc, HSU_CH_CR, cr); +} + +static void hsu_dma_chan_start(struct hsu_dma_chan *hsuc) +{ + struct dma_slave_config *config = &hsuc->config; + struct hsu_dma_desc *desc = hsuc->desc; + u32 bsr = 0, mtsr = 0; /* to shut the compiler up */ + u32 dcr = HSU_CH_DCR_CHSOE | HSU_CH_DCR_CHEI; + unsigned int i, count; + + if (hsuc->direction == DMA_MEM_TO_DEV) { + bsr = config->dst_maxburst; + mtsr = config->dst_addr_width; + } else if (hsuc->direction == DMA_DEV_TO_MEM) { + bsr = config->src_maxburst; + mtsr = config->src_addr_width; + } + + hsu_chan_disable(hsuc); + + hsu_chan_writel(hsuc, HSU_CH_DCR, 0); + hsu_chan_writel(hsuc, HSU_CH_BSR, bsr); + hsu_chan_writel(hsuc, HSU_CH_MTSR, mtsr); + + /* Set descriptors */ + count = (desc->nents - desc->active) % HSU_DMA_CHAN_NR_DESC; + for (i = 0; i < count; i++) { + hsu_chan_writel(hsuc, HSU_CH_DxSAR(i), desc->sg[i].addr); + hsu_chan_writel(hsuc, HSU_CH_DxTSR(i), desc->sg[i].len); + + /* Prepare value for DCR */ + dcr |= HSU_CH_DCR_DESCA(i); + dcr |= HSU_CH_DCR_CHTOI(i); /* timeout bit, see HSU Errata 1 */ + + desc->active++; + } + /* Only for the last descriptor in the chain */ + dcr |= HSU_CH_DCR_CHSOD(count - 1); + dcr |= HSU_CH_DCR_CHDI(count - 1); + + hsu_chan_writel(hsuc, HSU_CH_DCR, dcr); + + hsu_chan_enable(hsuc); +} + +static void hsu_dma_stop_channel(struct hsu_dma_chan *hsuc) +{ + unsigned long flags; + + spin_lock_irqsave(&hsuc->lock, flags); + hsu_chan_disable(hsuc); + hsu_chan_writel(hsuc, HSU_CH_DCR, 0); + spin_unlock_irqrestore(&hsuc->lock, flags); +} + +static void hsu_dma_start_channel(struct hsu_dma_chan *hsuc) +{ + unsigned long flags; + + spin_lock_irqsave(&hsuc->lock, flags); + hsu_dma_chan_start(hsuc); + spin_unlock_irqrestore(&hsuc->lock, flags); +} + +static void hsu_dma_start_transfer(struct hsu_dma_chan *hsuc) +{ + struct virt_dma_desc *vdesc; + + /* Get the next descriptor */ + vdesc = vchan_next_desc(&hsuc->vchan); + if (!vdesc) { + hsuc->desc = NULL; + return; + } + + list_del(&vdesc->node); + hsuc->desc = to_hsu_dma_desc(vdesc); + + /* Start the channel with a new descriptor */ + hsu_dma_start_channel(hsuc); +} + +static u32 hsu_dma_chan_get_sr(struct hsu_dma_chan *hsuc) +{ + unsigned long flags; + u32 sr; + + spin_lock_irqsave(&hsuc->lock, flags); + sr = hsu_chan_readl(hsuc, HSU_CH_SR); + spin_unlock_irqrestore(&hsuc->lock, flags); + + return sr; +} + +irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr) +{ + struct hsu_dma_chan *hsuc; + struct hsu_dma_desc *desc; + unsigned long flags; + u32 sr; + + /* Sanity check */ + if (nr >= chip->pdata->nr_channels) + return IRQ_NONE; + + hsuc = &chip->hsu->chan[nr]; + + /* + * No matter what situation, need read clear the IRQ status + * There is a bug, see Errata 5, HSD 2900918 + */ + sr = hsu_dma_chan_get_sr(hsuc); + if (!sr) + return IRQ_NONE; + + /* Timeout IRQ, need wait some time, see Errata 2 */ + if (hsuc->direction == DMA_DEV_TO_MEM && (sr & HSU_CH_SR_DESCTO_ANY)) + udelay(2); + + sr &= ~HSU_CH_SR_DESCTO_ANY; + if (!sr) + return IRQ_HANDLED; + + spin_lock_irqsave(&hsuc->vchan.lock, flags); + desc = hsuc->desc; + if (desc) { + if (sr & HSU_CH_SR_CHE) { + desc->status = DMA_ERROR; + } else if (desc->active < desc->nents) { + hsu_dma_start_channel(hsuc); + } else { + vchan_cookie_complete(&desc->vdesc); + desc->status = DMA_COMPLETE; + hsu_dma_start_transfer(hsuc); + } + } + spin_unlock_irqrestore(&hsuc->vchan.lock, flags); + + return IRQ_HANDLED; +} +EXPORT_SYMBOL_GPL(hsu_dma_irq); + +static struct hsu_dma_desc *hsu_dma_alloc_desc(unsigned int nents) +{ + struct hsu_dma_desc *desc; + + desc = kzalloc(sizeof(*desc), GFP_NOWAIT); + if (!desc) + return NULL; + + desc->sg = kcalloc(nents, sizeof(*desc->sg), GFP_NOWAIT); + if (!desc->sg) { + kfree(desc); + return NULL; + } + + return desc; +} + +static void hsu_dma_desc_free(struct virt_dma_desc *vdesc) +{ + struct hsu_dma_desc *desc = to_hsu_dma_desc(vdesc); + + kfree(desc->sg); + kfree(desc); +} + +static struct dma_async_tx_descriptor *hsu_dma_prep_slave_sg( + struct dma_chan *chan, struct scatterlist *sgl, + unsigned int sg_len, enum dma_transfer_direction direction, + unsigned long flags, void *context) +{ + struct hsu_dma_chan *hsuc = to_hsu_dma_chan(chan); + struct hsu_dma_desc *desc; + struct scatterlist *sg; + unsigned int i; + + desc = hsu_dma_alloc_desc(sg_len); + if (!desc) + return NULL; + + for_each_sg(sgl, sg, sg_len, i) { + desc->sg[i].addr = sg_dma_address(sg); + desc->sg[i].len = sg_dma_len(sg); + } + + desc->nents = sg_len; + desc->direction = direction; + /* desc->active = 0 by kzalloc */ + desc->status = DMA_IN_PROGRESS; + + return vchan_tx_prep(&hsuc->vchan, &desc->vdesc, flags); +} + +static void hsu_dma_issue_pending(struct dma_chan *chan) +{ + struct hsu_dma_chan *hsuc = to_hsu_dma_chan(chan); + unsigned long flags; + + spin_lock_irqsave(&hsuc->vchan.lock, flags); + if (vchan_issue_pending(&hsuc->vchan) && !hsuc->desc) + hsu_dma_start_transfer(hsuc); + spin_unlock_irqrestore(&hsuc->vchan.lock, flags); +} + +static size_t hsu_dma_desc_size(struct hsu_dma_desc *desc) +{ + size_t bytes = 0; + unsigned int i; + + for (i = desc->active; i < desc->nents; i++) + bytes += desc->sg[i].len; + + return bytes; +} + +static size_t hsu_dma_active_desc_size(struct hsu_dma_chan *hsuc) +{ + struct hsu_dma_desc *desc = hsuc->desc; + size_t bytes = hsu_dma_desc_size(desc); + int i; + unsigned long flags; + + spin_lock_irqsave(&hsuc->lock, flags); + i = desc->active % HSU_DMA_CHAN_NR_DESC; + do { + bytes += hsu_chan_readl(hsuc, HSU_CH_DxTSR(i)); + } while (--i >= 0); + spin_unlock_irqrestore(&hsuc->lock, flags); + + return bytes; +} + +static enum dma_status hsu_dma_tx_status(struct dma_chan *chan, + dma_cookie_t cookie, struct dma_tx_state *state) +{ + struct hsu_dma_chan *hsuc = to_hsu_dma_chan(chan); + struct virt_dma_desc *vdesc; + enum dma_status status; + size_t bytes; + unsigned long flags; + + status = dma_cookie_status(chan, cookie, state); + if (status == DMA_COMPLETE) + return status; + + spin_lock_irqsave(&hsuc->vchan.lock, flags); + vdesc = vchan_find_desc(&hsuc->vchan, cookie); + if (hsuc->desc && cookie == hsuc->desc->vdesc.tx.cookie) { + bytes = hsu_dma_active_desc_size(hsuc); + dma_set_residue(state, bytes); + status = hsuc->desc->status; + } else if (vdesc) { + bytes = hsu_dma_desc_size(to_hsu_dma_desc(vdesc)); + dma_set_residue(state, bytes); + } + spin_unlock_irqrestore(&hsuc->vchan.lock, flags); + + return status; +} + +static int hsu_dma_slave_config(struct dma_chan *chan, + struct dma_slave_config *config) +{ + struct hsu_dma_chan *hsuc = to_hsu_dma_chan(chan); + + /* Check if chan will be configured for slave transfers */ + if (!is_slave_direction(config->direction)) + return -EINVAL; + + memcpy(&hsuc->config, config, sizeof(hsuc->config)); + + return 0; +} + +static void hsu_dma_chan_deactivate(struct hsu_dma_chan *hsuc) +{ + unsigned long flags; + + spin_lock_irqsave(&hsuc->lock, flags); + hsu_chan_disable(hsuc); + spin_unlock_irqrestore(&hsuc->lock, flags); +} + +static void hsu_dma_chan_activate(struct hsu_dma_chan *hsuc) +{ + unsigned long flags; + + spin_lock_irqsave(&hsuc->lock, flags); + hsu_chan_enable(hsuc); + spin_unlock_irqrestore(&hsuc->lock, flags); +} + +static int hsu_dma_pause(struct dma_chan *chan) +{ + struct hsu_dma_chan *hsuc = to_hsu_dma_chan(chan); + unsigned long flags; + + spin_lock_irqsave(&hsuc->vchan.lock, flags); + if (hsuc->desc && hsuc->desc->status == DMA_IN_PROGRESS) { + hsu_dma_chan_deactivate(hsuc); + hsuc->desc->status = DMA_PAUSED; + } + spin_unlock_irqrestore(&hsuc->vchan.lock, flags); + + return 0; +} + +static int hsu_dma_resume(struct dma_chan *chan) +{ + struct hsu_dma_chan *hsuc = to_hsu_dma_chan(chan); + unsigned long flags; + + spin_lock_irqsave(&hsuc->vchan.lock, flags); + if (hsuc->desc && hsuc->desc->status == DMA_PAUSED) { + hsuc->desc->status = DMA_IN_PROGRESS; + hsu_dma_chan_activate(hsuc); + } + spin_unlock_irqrestore(&hsuc->vchan.lock, flags); + + return 0; +} + +static int hsu_dma_terminate_all(struct dma_chan *chan) +{ + struct hsu_dma_chan *hsuc = to_hsu_dma_chan(chan); + unsigned long flags; + LIST_HEAD(head); + + spin_lock_irqsave(&hsuc->vchan.lock, flags); + + hsu_dma_stop_channel(hsuc); + hsuc->desc = NULL; + + vchan_get_all_descriptors(&hsuc->vchan, &head); + spin_unlock_irqrestore(&hsuc->vchan.lock, flags); + vchan_dma_desc_free_list(&hsuc->vchan, &head); + + return 0; +} + +static void hsu_dma_free_chan_resources(struct dma_chan *chan) +{ + vchan_free_chan_resources(to_virt_chan(chan)); +} + +int hsu_dma_probe(struct hsu_dma_chip *chip) +{ + struct hsu_dma *hsu; + struct hsu_dma_platform_data *pdata = chip->pdata; + void __iomem *addr = chip->regs + chip->offset; + unsigned short i; + int ret; + + hsu = devm_kzalloc(chip->dev, sizeof(*hsu), GFP_KERNEL); + if (!hsu) + return -ENOMEM; + + chip->hsu = hsu; + + if (!pdata) { + pdata = devm_kzalloc(chip->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + chip->pdata = pdata; + + /* Guess nr_channels from the IO space length */ + pdata->nr_channels = (chip->length - chip->offset) / + HSU_DMA_CHAN_LENGTH; + } + + hsu->chan = devm_kcalloc(chip->dev, pdata->nr_channels, + sizeof(*hsu->chan), GFP_KERNEL); + if (!hsu->chan) + return -ENOMEM; + + INIT_LIST_HEAD(&hsu->dma.channels); + for (i = 0; i < pdata->nr_channels; i++) { + struct hsu_dma_chan *hsuc = &hsu->chan[i]; + + hsuc->vchan.desc_free = hsu_dma_desc_free; + vchan_init(&hsuc->vchan, &hsu->dma); + + hsuc->direction = (i & 0x1) ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV; + hsuc->reg = addr + i * HSU_DMA_CHAN_LENGTH; + + spin_lock_init(&hsuc->lock); + } + + dma_cap_set(DMA_SLAVE, hsu->dma.cap_mask); + dma_cap_set(DMA_PRIVATE, hsu->dma.cap_mask); + + hsu->dma.device_free_chan_resources = hsu_dma_free_chan_resources; + + hsu->dma.device_prep_slave_sg = hsu_dma_prep_slave_sg; + + hsu->dma.device_issue_pending = hsu_dma_issue_pending; + hsu->dma.device_tx_status = hsu_dma_tx_status; + + hsu->dma.device_config = hsu_dma_slave_config; + hsu->dma.device_pause = hsu_dma_pause; + hsu->dma.device_resume = hsu_dma_resume; + hsu->dma.device_terminate_all = hsu_dma_terminate_all; + + hsu->dma.src_addr_widths = HSU_DMA_BUSWIDTHS; + hsu->dma.dst_addr_widths = HSU_DMA_BUSWIDTHS; + hsu->dma.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); + hsu->dma.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; + + hsu->dma.dev = chip->dev; + + ret = dma_async_device_register(&hsu->dma); + if (ret) + return ret; + + dev_info(chip->dev, "Found HSU DMA, %d channels\n", pdata->nr_channels); + return 0; +} +EXPORT_SYMBOL_GPL(hsu_dma_probe); + +int hsu_dma_remove(struct hsu_dma_chip *chip) +{ + struct hsu_dma *hsu = chip->hsu; + unsigned short i; + + dma_async_device_unregister(&hsu->dma); + + for (i = 0; i < chip->pdata->nr_channels; i++) { + struct hsu_dma_chan *hsuc = &hsu->chan[i]; + + tasklet_kill(&hsuc->vchan.task); + } + + return 0; +} +EXPORT_SYMBOL_GPL(hsu_dma_remove); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("High Speed UART DMA core driver"); +MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>"); diff --git a/drivers/dma/hsu/hsu.h b/drivers/dma/hsu/hsu.h new file mode 100644 index 000000000000..0275233cf550 --- /dev/null +++ b/drivers/dma/hsu/hsu.h @@ -0,0 +1,118 @@ +/* + * Driver for the High Speed UART DMA + * + * Copyright (C) 2015 Intel Corporation + * + * Partially based on the bits found in drivers/tty/serial/mfd.c. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __DMA_HSU_H__ +#define __DMA_HSU_H__ + +#include <linux/spinlock.h> +#include <linux/dma/hsu.h> + +#include "../virt-dma.h" + +#define HSU_CH_SR 0x00 /* channel status */ +#define HSU_CH_CR 0x04 /* channel control */ +#define HSU_CH_DCR 0x08 /* descriptor control */ +#define HSU_CH_BSR 0x10 /* FIFO buffer size */ +#define HSU_CH_MTSR 0x14 /* minimum transfer size */ +#define HSU_CH_DxSAR(x) (0x20 + 8 * (x)) /* desc start addr */ +#define HSU_CH_DxTSR(x) (0x24 + 8 * (x)) /* desc transfer size */ +#define HSU_CH_D0SAR 0x20 /* desc 0 start addr */ +#define HSU_CH_D0TSR 0x24 /* desc 0 transfer size */ +#define HSU_CH_D1SAR 0x28 +#define HSU_CH_D1TSR 0x2c +#define HSU_CH_D2SAR 0x30 +#define HSU_CH_D2TSR 0x34 +#define HSU_CH_D3SAR 0x38 +#define HSU_CH_D3TSR 0x3c + +#define HSU_DMA_CHAN_NR_DESC 4 +#define HSU_DMA_CHAN_LENGTH 0x40 + +/* Bits in HSU_CH_SR */ +#define HSU_CH_SR_DESCTO(x) BIT(8 + (x)) +#define HSU_CH_SR_DESCTO_ANY (BIT(11) | BIT(10) | BIT(9) | BIT(8)) +#define HSU_CH_SR_CHE BIT(15) + +/* Bits in HSU_CH_CR */ +#define HSU_CH_CR_CHA BIT(0) +#define HSU_CH_CR_CHD BIT(1) + +/* Bits in HSU_CH_DCR */ +#define HSU_CH_DCR_DESCA(x) BIT(0 + (x)) +#define HSU_CH_DCR_CHSOD(x) BIT(8 + (x)) +#define HSU_CH_DCR_CHSOTO BIT(14) +#define HSU_CH_DCR_CHSOE BIT(15) +#define HSU_CH_DCR_CHDI(x) BIT(16 + (x)) +#define HSU_CH_DCR_CHEI BIT(23) +#define HSU_CH_DCR_CHTOI(x) BIT(24 + (x)) + +struct hsu_dma_sg { + dma_addr_t addr; + unsigned int len; +}; + +struct hsu_dma_desc { + struct virt_dma_desc vdesc; + enum dma_transfer_direction direction; + struct hsu_dma_sg *sg; + unsigned int nents; + unsigned int active; + enum dma_status status; +}; + +static inline struct hsu_dma_desc *to_hsu_dma_desc(struct virt_dma_desc *vdesc) +{ + return container_of(vdesc, struct hsu_dma_desc, vdesc); +} + +struct hsu_dma_chan { + struct virt_dma_chan vchan; + + void __iomem *reg; + spinlock_t lock; + + /* hardware configuration */ + enum dma_transfer_direction direction; + struct dma_slave_config config; + + struct hsu_dma_desc *desc; +}; + +static inline struct hsu_dma_chan *to_hsu_dma_chan(struct dma_chan *chan) +{ + return container_of(chan, struct hsu_dma_chan, vchan.chan); +} + +static inline u32 hsu_chan_readl(struct hsu_dma_chan *hsuc, int offset) +{ + return readl(hsuc->reg + offset); +} + +static inline void hsu_chan_writel(struct hsu_dma_chan *hsuc, int offset, + u32 value) +{ + writel(value, hsuc->reg + offset); +} + +struct hsu_dma { + struct dma_device dma; + + /* channels */ + struct hsu_dma_chan *chan; +}; + +static inline struct hsu_dma *to_hsu_dma(struct dma_device *ddev) +{ + return container_of(ddev, struct hsu_dma, dma); +} + +#endif /* __DMA_HSU_H__ */ diff --git a/drivers/dma/hsu/pci.c b/drivers/dma/hsu/pci.c new file mode 100644 index 000000000000..77879e6ddc4c --- /dev/null +++ b/drivers/dma/hsu/pci.c @@ -0,0 +1,124 @@ +/* + * PCI driver for the High Speed UART DMA + * + * Copyright (C) 2015 Intel Corporation + * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com> + * + * Partially based on the bits found in drivers/tty/serial/mfd.c. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/bitops.h> +#include <linux/device.h> +#include <linux/module.h> +#include <linux/pci.h> + +#include "hsu.h" + +#define HSU_PCI_DMASR 0x00 +#define HSU_PCI_DMAISR 0x04 + +#define HSU_PCI_CHAN_OFFSET 0x100 + +static irqreturn_t hsu_pci_irq(int irq, void *dev) +{ + struct hsu_dma_chip *chip = dev; + u32 dmaisr; + unsigned short i; + irqreturn_t ret = IRQ_NONE; + + dmaisr = readl(chip->regs + HSU_PCI_DMAISR); + for (i = 0; i < chip->pdata->nr_channels; i++) { + if (dmaisr & 0x1) + ret |= hsu_dma_irq(chip, i); + dmaisr >>= 1; + } + + return ret; +} + +static int hsu_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct hsu_dma_chip *chip; + int ret; + + ret = pcim_enable_device(pdev); + if (ret) + return ret; + + ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); + if (ret) { + dev_err(&pdev->dev, "I/O memory remapping failed\n"); + return ret; + } + + pci_set_master(pdev); + pci_try_set_mwi(pdev); + + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (ret) + return ret; + + ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + if (ret) + return ret; + + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->dev = &pdev->dev; + chip->regs = pcim_iomap_table(pdev)[0]; + chip->length = pci_resource_len(pdev, 0); + chip->offset = HSU_PCI_CHAN_OFFSET; + chip->irq = pdev->irq; + + pci_enable_msi(pdev); + + ret = hsu_dma_probe(chip); + if (ret) + return ret; + + ret = request_irq(chip->irq, hsu_pci_irq, 0, "hsu_dma_pci", chip); + if (ret) + goto err_register_irq; + + pci_set_drvdata(pdev, chip); + + return 0; + +err_register_irq: + hsu_dma_remove(chip); + return ret; +} + +static void hsu_pci_remove(struct pci_dev *pdev) +{ + struct hsu_dma_chip *chip = pci_get_drvdata(pdev); + + free_irq(chip->irq, chip); + hsu_dma_remove(chip); +} + +static const struct pci_device_id hsu_pci_id_table[] = { + { PCI_VDEVICE(INTEL, 0x081e), 0 }, + { PCI_VDEVICE(INTEL, 0x1192), 0 }, + { } +}; +MODULE_DEVICE_TABLE(pci, hsu_pci_id_table); + +static struct pci_driver hsu_pci_driver = { + .name = "hsu_dma_pci", + .id_table = hsu_pci_id_table, + .probe = hsu_pci_probe, + .remove = hsu_pci_remove, +}; + +module_pci_driver(hsu_pci_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("High Speed UART DMA PCI driver"); +MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>"); diff --git a/drivers/firmware/pcdp.c b/drivers/firmware/pcdp.c index a330492e06f9..75273a251603 100644 --- a/drivers/firmware/pcdp.c +++ b/drivers/firmware/pcdp.c @@ -15,7 +15,7 @@ #include <linux/console.h> #include <linux/efi.h> #include <linux/serial.h> -#include <linux/serial_8250.h> +#include <linux/serial_core.h> #include <asm/vga.h> #include "pcdp.h" @@ -43,7 +43,7 @@ setup_serial_console(struct pcdp_uart *uart) } add_preferred_console("uart", 8250, &options[9]); - return setup_early_serial8250_console(options); + return setup_earlycon(options); #else return -ENODEV; #endif diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c index 071551bf3e9a..543b234e70fc 100644 --- a/drivers/tty/hvc/hvc_opal.c +++ b/drivers/tty/hvc/hvc_opal.c @@ -41,7 +41,7 @@ static const char hvc_opal_name[] = "hvc_opal"; -static struct of_device_id hvc_opal_match[] = { +static const struct of_device_id hvc_opal_match[] = { { .name = "serial", .compatible = "ibm,opal-console-raw" }, { .name = "serial", .compatible = "ibm,opal-console-hvsi" }, { }, diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index c4343764cc5b..91abc00aa833 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2669,7 +2669,7 @@ static inline void muxnet_put(struct gsm_mux_net *mux_net) static int gsm_mux_net_start_xmit(struct sk_buff *skb, struct net_device *net) { - struct gsm_mux_net *mux_net = (struct gsm_mux_net *)netdev_priv(net); + struct gsm_mux_net *mux_net = netdev_priv(net); struct gsm_dlci *dlci = mux_net->dlci; muxnet_get(mux_net); @@ -2698,7 +2698,7 @@ static void gsm_mux_rx_netchar(struct gsm_dlci *dlci, { struct net_device *net = dlci->net; struct sk_buff *skb; - struct gsm_mux_net *mux_net = (struct gsm_mux_net *)netdev_priv(net); + struct gsm_mux_net *mux_net = netdev_priv(net); muxnet_get(mux_net); /* Allocate an sk_buff */ @@ -2727,7 +2727,7 @@ static void gsm_mux_rx_netchar(struct gsm_dlci *dlci, static int gsm_change_mtu(struct net_device *net, int new_mtu) { - struct gsm_mux_net *mux_net = (struct gsm_mux_net *)netdev_priv(net); + struct gsm_mux_net *mux_net = netdev_priv(net); if ((new_mtu < 8) || (new_mtu > mux_net->dlci->gsm->mtu)) return -EINVAL; net->mtu = new_mtu; @@ -2763,7 +2763,7 @@ static void gsm_destroy_network(struct gsm_dlci *dlci) pr_debug("destroy network interface"); if (!dlci->net) return; - mux_net = (struct gsm_mux_net *)netdev_priv(dlci->net); + mux_net = netdev_priv(dlci->net); muxnet_put(mux_net); } @@ -2801,7 +2801,7 @@ static int gsm_create_network(struct gsm_dlci *dlci, struct gsm_netconfig *nc) return -ENOMEM; } net->mtu = dlci->gsm->mtu; - mux_net = (struct gsm_mux_net *)netdev_priv(net); + mux_net = netdev_priv(net); mux_net->dlci = dlci; kref_init(&mux_net->ref); strncpy(nc->if_name, net->name, IFNAMSIZ); /* return net name */ @@ -2824,7 +2824,7 @@ static int gsm_create_network(struct gsm_dlci *dlci, struct gsm_netconfig *nc) } /* Line discipline for real tty */ -struct tty_ldisc_ops tty_ldisc_packet = { +static struct tty_ldisc_ops tty_ldisc_packet = { .owner = THIS_MODULE, .magic = TTY_LDISC_MAGIC, .name = "n_gsm", diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index b00836851061..c43f74c53cd9 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -21,7 +21,6 @@ struct uart_8250_dma { /* Filter function */ dma_filter_fn fn; - /* Parameter to the filter function */ void *rx_param; void *tx_param; @@ -53,7 +52,7 @@ struct old_serial_port { unsigned int baud_base; unsigned int port; unsigned int irq; - unsigned int flags; + upf_t flags; unsigned char hub6; unsigned char io_type; unsigned char __iomem *iomem_base; @@ -85,9 +84,6 @@ struct serial8250_config { #define UART_BUG_THRE (1 << 3) /* UART has buggy THRE reassertion */ #define UART_BUG_PARITY (1 << 4) /* UART mishandles parity if FIFO enabled */ -#define PROBE_RSA (1 << 0) -#define PROBE_ANY (~0) - #define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) #ifdef CONFIG_SERIAL_8250_SHARE_IRQ @@ -198,3 +194,20 @@ static inline int serial8250_request_dma(struct uart_8250_port *p) } static inline void serial8250_release_dma(struct uart_8250_port *p) { } #endif + +static inline int ns16550a_goto_highspeed(struct uart_8250_port *up) +{ + unsigned char status; + + status = serial_in(up, 0x04); /* EXCR2 */ +#define PRESL(x) ((x) & 0x30) + if (PRESL(status) == 0x10) { + /* already in high speed mode */ + return 0; + } else { + status &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */ + status |= 0x10; /* 1.625 divisor for baud_base --> 921600 */ + serial_out(up, 0x04, status); + } + return 1; +} diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index deae122c9c4b..422ebea96a64 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -31,7 +31,6 @@ #include <linux/tty.h> #include <linux/ratelimit.h> #include <linux/tty_flip.h> -#include <linux/serial_core.h> #include <linux/serial.h> #include <linux/serial_8250.h> #include <linux/nmi.h> @@ -61,7 +60,7 @@ static struct uart_driver serial8250_reg; static int serial_index(struct uart_port *port) { - return (serial8250_reg.minor - 64) + port->line; + return port->minor - 64; } static unsigned int skip_txen_test; /* force skip of txen test at init time */ @@ -358,34 +357,46 @@ static void default_serial_dl_write(struct uart_8250_port *up, int value) #if defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_SERIAL_8250_RT288X) /* Au1x00/RT288x UART hardware has a weird register layout */ -static const u8 au_io_in_map[] = { - [UART_RX] = 0, - [UART_IER] = 2, - [UART_IIR] = 3, - [UART_LCR] = 5, - [UART_MCR] = 6, - [UART_LSR] = 7, - [UART_MSR] = 8, +static const s8 au_io_in_map[8] = { + 0, /* UART_RX */ + 2, /* UART_IER */ + 3, /* UART_IIR */ + 5, /* UART_LCR */ + 6, /* UART_MCR */ + 7, /* UART_LSR */ + 8, /* UART_MSR */ + -1, /* UART_SCR (unmapped) */ }; -static const u8 au_io_out_map[] = { - [UART_TX] = 1, - [UART_IER] = 2, - [UART_FCR] = 4, - [UART_LCR] = 5, - [UART_MCR] = 6, +static const s8 au_io_out_map[8] = { + 1, /* UART_TX */ + 2, /* UART_IER */ + 4, /* UART_FCR */ + 5, /* UART_LCR */ + 6, /* UART_MCR */ + -1, /* UART_LSR (unmapped) */ + -1, /* UART_MSR (unmapped) */ + -1, /* UART_SCR (unmapped) */ }; static unsigned int au_serial_in(struct uart_port *p, int offset) { - offset = au_io_in_map[offset] << p->regshift; - return __raw_readl(p->membase + offset); + if (offset >= ARRAY_SIZE(au_io_in_map)) + return UINT_MAX; + offset = au_io_in_map[offset]; + if (offset < 0) + return UINT_MAX; + return __raw_readl(p->membase + (offset << p->regshift)); } static void au_serial_out(struct uart_port *p, int offset, int value) { - offset = au_io_out_map[offset] << p->regshift; - __raw_writel(value, p->membase + offset); + if (offset >= ARRAY_SIZE(au_io_out_map)) + return; + offset = au_io_out_map[offset]; + if (offset < 0) + return; + __raw_writel(value, p->membase + (offset << p->regshift)); } /* Au1x00 haven't got a standard divisor latch */ @@ -895,7 +906,7 @@ static int broken_efr(struct uart_8250_port *up) /* * Exar ST16C2550 "A2" devices incorrectly detect as * having an EFR, and report an ID of 0x0201. See - * http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-11/4812.html + * http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-11/4812.html */ if (autoconfig_read_divisor_id(up) == 0x0201 && size_fifo(up) == 16) return 1; @@ -903,23 +914,6 @@ static int broken_efr(struct uart_8250_port *up) return 0; } -static inline int ns16550a_goto_highspeed(struct uart_8250_port *up) -{ - unsigned char status; - - status = serial_in(up, 0x04); /* EXCR2 */ -#define PRESL(x) ((x) & 0x30) - if (PRESL(status) == 0x10) { - /* already in high speed mode */ - return 0; - } else { - status &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */ - status |= 0x10; /* 1.625 divisor for baud_base --> 921600 */ - serial_out(up, 0x04, status); - } - return 1; -} - /* * We know that the chip has FIFOs. Does it have an EFR? The * EFR is located in the same register position as the IIR and @@ -1122,7 +1116,7 @@ static void autoconfig_16550a(struct uart_8250_port *up) * whether or not this UART is a 16550A or not, since this will * determine whether or not we can use its FIFO features or not. */ -static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) +static void autoconfig(struct uart_8250_port *up) { unsigned char status1, scratch, scratch2, scratch3; unsigned char save_lcr, save_mcr; @@ -1245,22 +1239,15 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) /* * Only probe for RSA ports if we got the region. */ - if (port->type == PORT_16550A && probeflags & PROBE_RSA) { - int i; - - for (i = 0 ; i < probe_rsa_count; ++i) { - if (probe_rsa[i] == port->iobase && __enable_rsa(up)) { - port->type = PORT_RSA; - break; - } - } - } + if (port->type == PORT_16550A && up->probe & UART_PROBE_RSA && + __enable_rsa(up)) + port->type = PORT_RSA; #endif serial_out(up, UART_LCR, save_lcr); port->fifosize = uart_config[up->port.type].fifo_size; - old_capabilities = up->capabilities; + old_capabilities = up->capabilities; up->capabilities = uart_config[port->type].flags; up->tx_loadsz = uart_config[port->type].tx_loadsz; @@ -1907,6 +1894,48 @@ static void serial8250_backup_timeout(unsigned long data) jiffies + uart_poll_timeout(&up->port) + HZ / 5); } +static int univ8250_setup_irq(struct uart_8250_port *up) +{ + struct uart_port *port = &up->port; + int retval = 0; + + /* + * The above check will only give an accurate result the first time + * the port is opened so this value needs to be preserved. + */ + if (up->bugs & UART_BUG_THRE) { + pr_debug("ttyS%d - using backup timer\n", serial_index(port)); + + up->timer.function = serial8250_backup_timeout; + up->timer.data = (unsigned long)up; + mod_timer(&up->timer, jiffies + + uart_poll_timeout(port) + HZ / 5); + } + + /* + * If the "interrupt" for this port doesn't correspond with any + * hardware interrupt, we use a timer-based system. The original + * driver used to do this with IRQ0. + */ + if (!port->irq) { + up->timer.data = (unsigned long)up; + mod_timer(&up->timer, jiffies + uart_poll_timeout(port)); + } else + retval = serial_link_irq_chain(up); + + return retval; +} + +static void univ8250_release_irq(struct uart_8250_port *up) +{ + struct uart_port *port = &up->port; + + del_timer_sync(&up->timer); + up->timer.function = serial8250_timeout; + if (port->irq) + serial_unlink_irq_chain(up); +} + static unsigned int serial8250_tx_empty(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); @@ -2211,35 +2240,12 @@ int serial8250_do_startup(struct uart_port *port) if ((!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) || up->port.flags & UPF_BUG_THRE) { up->bugs |= UART_BUG_THRE; - pr_debug("ttyS%d - using backup timer\n", - serial_index(port)); } } - /* - * The above check will only give an accurate result the first time - * the port is opened so this value needs to be preserved. - */ - if (up->bugs & UART_BUG_THRE) { - up->timer.function = serial8250_backup_timeout; - up->timer.data = (unsigned long)up; - mod_timer(&up->timer, jiffies + - uart_poll_timeout(port) + HZ / 5); - } - - /* - * If the "interrupt" for this port doesn't correspond with any - * hardware interrupt, we use a timer-based system. The original - * driver used to do this with IRQ0. - */ - if (!port->irq) { - up->timer.data = (unsigned long)up; - mod_timer(&up->timer, jiffies + uart_poll_timeout(port)); - } else { - retval = serial_link_irq_chain(up); - if (retval) - goto out; - } + retval = up->ops->setup_irq(up); + if (retval) + goto out; /* * Now, initialize the UART @@ -2270,7 +2276,7 @@ int serial8250_do_startup(struct uart_port *port) is variable. So, let's just don't test if we receive TX irq. This way, we'll never enable UART_BUG_TXEN. */ - if (skip_txen_test || up->port.flags & UPF_NO_TXEN_TEST) + if (up->port.flags & UPF_NO_TXEN_TEST) goto dont_test_tx_en; /* @@ -2397,10 +2403,7 @@ void serial8250_do_shutdown(struct uart_port *port) serial_port_in(port, UART_RX); serial8250_rpm_put(up); - del_timer_sync(&up->timer); - up->timer.function = serial8250_timeout; - if (port->irq) - serial_unlink_irq_chain(up); + up->ops->release_irq(up); } EXPORT_SYMBOL_GPL(serial8250_do_shutdown); @@ -2719,6 +2722,8 @@ serial8250_pm(struct uart_port *port, unsigned int state, static unsigned int serial8250_port_size(struct uart_8250_port *pt) { + if (pt->port.mapsize) + return pt->port.mapsize; if (pt->port.iotype == UPIO_AU) { if (pt->port.type == PORT_RT2880) return 0x100; @@ -2798,6 +2803,7 @@ static void serial8250_release_std_resource(struct uart_8250_port *up) } } +#ifdef CONFIG_SERIAL_8250_RSA static int serial8250_request_rsa_resource(struct uart_8250_port *up) { unsigned long start = UART_RSA_BASE << up->port.regshift; @@ -2832,14 +2838,13 @@ static void serial8250_release_rsa_resource(struct uart_8250_port *up) break; } } +#endif static void serial8250_release_port(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); serial8250_release_std_resource(up); - if (port->type == PORT_RSA) - serial8250_release_rsa_resource(up); } static int serial8250_request_port(struct uart_port *port) @@ -2851,11 +2856,6 @@ static int serial8250_request_port(struct uart_port *port) return -ENODEV; ret = serial8250_request_std_resource(up); - if (ret == 0 && port->type == PORT_RSA) { - ret = serial8250_request_rsa_resource(up); - if (ret < 0) - serial8250_release_std_resource(up); - } return ret; } @@ -3003,7 +3003,6 @@ static void register_dev_spec_attr_grp(struct uart_8250_port *up) static void serial8250_config_port(struct uart_port *port, int flags) { struct uart_8250_port *up = up_to_u8250p(port); - int probeflags = PROBE_ANY; int ret; if (port->type == PORT_8250_CIR) @@ -3017,15 +3016,11 @@ static void serial8250_config_port(struct uart_port *port, int flags) if (ret < 0) return; - ret = serial8250_request_rsa_resource(up); - if (ret < 0) - probeflags &= ~PROBE_RSA; - if (port->iotype != up->cur_iotype) set_io_from_upio(port); if (flags & UART_CONFIG_TYPE) - autoconfig(up, probeflags); + autoconfig(up); /* if access method is AU, it is a 16550 with a quirk */ if (port->type == PORT_16550A && port->iotype == UPIO_AU) @@ -3038,8 +3033,6 @@ static void serial8250_config_port(struct uart_port *port, int flags) if (port->type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ) autoconfig_irq(up); - if (port->type != PORT_RSA && probeflags & PROBE_RSA) - serial8250_release_rsa_resource(up); if (port->type == PORT_UNKNOWN) serial8250_release_std_resource(up); @@ -3073,7 +3066,7 @@ serial8250_type(struct uart_port *port) return uart_config[type].name; } -static struct uart_ops serial8250_pops = { +static const struct uart_ops serial8250_pops = { .tx_empty = serial8250_tx_empty, .set_mctrl = serial8250_set_mctrl, .get_mctrl = serial8250_get_mctrl, @@ -3100,6 +3093,14 @@ static struct uart_ops serial8250_pops = { #endif }; +static const struct uart_ops *base_ops; +static struct uart_ops univ8250_port_ops; + +static const struct uart_8250_ops univ8250_driver_ops = { + .setup_irq = univ8250_setup_irq, + .release_irq = univ8250_release_irq, +}; + static struct uart_8250_port serial8250_ports[UART_NR]; /** @@ -3130,6 +3131,105 @@ void serial8250_set_isa_configurator( } EXPORT_SYMBOL(serial8250_set_isa_configurator); +static void serial8250_init_port(struct uart_8250_port *up) +{ + struct uart_port *port = &up->port; + + spin_lock_init(&port->lock); + port->ops = &serial8250_pops; + + up->cur_iotype = 0xFF; +} + +static void serial8250_set_defaults(struct uart_8250_port *up) +{ + struct uart_port *port = &up->port; + + if (up->port.flags & UPF_FIXED_TYPE) { + unsigned int type = up->port.type; + + if (!up->port.fifosize) + up->port.fifosize = uart_config[type].fifo_size; + if (!up->tx_loadsz) + up->tx_loadsz = uart_config[type].tx_loadsz; + if (!up->capabilities) + up->capabilities = uart_config[type].flags; + } + + set_io_from_upio(port); + + /* default dma handlers */ + if (up->dma) { + if (!up->dma->tx_dma) + up->dma->tx_dma = serial8250_tx_dma; + if (!up->dma->rx_dma) + up->dma->rx_dma = serial8250_rx_dma; + } +} + +#ifdef CONFIG_SERIAL_8250_RSA + +static void univ8250_config_port(struct uart_port *port, int flags) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + up->probe &= ~UART_PROBE_RSA; + if (port->type == PORT_RSA) { + if (serial8250_request_rsa_resource(up) == 0) + up->probe |= UART_PROBE_RSA; + } else if (flags & UART_CONFIG_TYPE) { + int i; + + for (i = 0; i < probe_rsa_count; i++) { + if (probe_rsa[i] == up->port.iobase) { + if (serial8250_request_rsa_resource(up) == 0) + up->probe |= UART_PROBE_RSA; + break; + } + } + } + + base_ops->config_port(port, flags); + + if (port->type != PORT_RSA && up->probe & UART_PROBE_RSA) + serial8250_release_rsa_resource(up); +} + +static int univ8250_request_port(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + int ret; + + ret = base_ops->request_port(port); + if (ret == 0 && port->type == PORT_RSA) { + ret = serial8250_request_rsa_resource(up); + if (ret < 0) + base_ops->release_port(port); + } + + return ret; +} + +static void univ8250_release_port(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + if (port->type == PORT_RSA) + serial8250_release_rsa_resource(up); + base_ops->release_port(port); +} + +static void univ8250_rsa_support(struct uart_ops *ops) +{ + ops->config_port = univ8250_config_port; + ops->request_port = univ8250_request_port; + ops->release_port = univ8250_release_port; +} + +#else +#define univ8250_rsa_support(x) do { } while (0) +#endif /* CONFIG_SERIAL_8250_RSA */ + static void __init serial8250_isa_init_ports(void) { struct uart_8250_port *up; @@ -3148,21 +3248,27 @@ static void __init serial8250_isa_init_ports(void) struct uart_port *port = &up->port; port->line = i; - spin_lock_init(&port->lock); + serial8250_init_port(up); + if (!base_ops) + base_ops = port->ops; + port->ops = &univ8250_port_ops; init_timer(&up->timer); up->timer.function = serial8250_timeout; - up->cur_iotype = 0xFF; + + up->ops = &univ8250_driver_ops; /* * ALPHA_KLUDGE_MCR needs to be killed. */ up->mcr_mask = ~ALPHA_KLUDGE_MCR; up->mcr_force = ALPHA_KLUDGE_MCR; - - port->ops = &serial8250_pops; } + /* chain base port ops to support Remote Supervisor Adapter */ + univ8250_port_ops = *base_ops; + univ8250_rsa_support(&univ8250_port_ops); + if (share_irqs) irqflag = IRQF_SHARED; @@ -3180,26 +3286,14 @@ static void __init serial8250_isa_init_ports(void) port->membase = old_serial_port[i].iomem_base; port->iotype = old_serial_port[i].io_type; port->regshift = old_serial_port[i].iomem_reg_shift; - set_io_from_upio(port); + serial8250_set_defaults(up); + port->irqflags |= irqflag; if (serial8250_isa_config != NULL) serial8250_isa_config(i, &up->port, &up->capabilities); - } } -static void -serial8250_init_fixed_type_port(struct uart_8250_port *up, unsigned int type) -{ - up->port.type = type; - if (!up->port.fifosize) - up->port.fifosize = uart_config[type].fifo_size; - if (!up->tx_loadsz) - up->tx_loadsz = uart_config[type].tx_loadsz; - if (!up->capabilities) - up->capabilities = uart_config[type].flags; -} - static void __init serial8250_register_ports(struct uart_driver *drv, struct device *dev) { @@ -3213,8 +3307,8 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev) up->port.dev = dev; - if (up->port.flags & UPF_FIXED_TYPE) - serial8250_init_fixed_type_port(up, up->port.type); + if (skip_txen_test) + up->port.flags |= UPF_NO_TXEN_TEST; uart_add_one_port(drv, &up->port); } @@ -3236,10 +3330,9 @@ static void serial8250_console_putchar(struct uart_port *port, int ch) * * The console_lock must be held when we get here. */ -static void -serial8250_console_write(struct console *co, const char *s, unsigned int count) +static void serial8250_console_write(struct uart_8250_port *up, const char *s, + unsigned int count) { - struct uart_8250_port *up = &serial8250_ports[co->index]; struct uart_port *port = &up->port; unsigned long flags; unsigned int ier; @@ -3311,14 +3404,51 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) serial8250_rpm_put(up); } -static int serial8250_console_setup(struct console *co, char *options) +static void univ8250_console_write(struct console *co, const char *s, + unsigned int count) +{ + struct uart_8250_port *up = &serial8250_ports[co->index]; + + serial8250_console_write(up, s, count); +} + +static unsigned int probe_baud(struct uart_port *port) +{ + unsigned char lcr, dll, dlm; + unsigned int quot; + + lcr = serial_port_in(port, UART_LCR); + serial_port_out(port, UART_LCR, lcr | UART_LCR_DLAB); + dll = serial_port_in(port, UART_DLL); + dlm = serial_port_in(port, UART_DLM); + serial_port_out(port, UART_LCR, lcr); + + quot = (dlm << 8) | dll; + return (port->uartclk / 16) / quot; +} + +static int serial8250_console_setup(struct uart_port *port, char *options, bool probe) { - struct uart_port *port; int baud = 9600; int bits = 8; int parity = 'n'; int flow = 'n'; + if (!port->iobase && !port->membase) + return -ENODEV; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else if (probe) + baud = probe_baud(port); + + return uart_set_options(port, port->cons, baud, parity, bits, flow); +} + +static int univ8250_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + /* * Check whether an invalid uart number has been specified, and * if so, search for the first available port that does have @@ -3327,53 +3457,84 @@ static int serial8250_console_setup(struct console *co, char *options) if (co->index >= nr_uarts) co->index = 0; port = &serial8250_ports[co->index].port; - if (!port->iobase && !port->membase) - return -ENODEV; + /* link port to console */ + port->cons = co; - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - - return uart_set_options(port, co, baud, parity, bits, flow); + return serial8250_console_setup(port, options, false); } -static int serial8250_console_early_setup(void) +/** + * univ8250_console_match - non-standard console matching + * @co: registering console + * @name: name from console command line + * @idx: index from console command line + * @options: ptr to option string from console command line + * + * Only attempts to match console command lines of the form: + * console=uart[8250],io|mmio|mmio32,<addr>[,<options>] + * console=uart[8250],0x<addr>[,<options>] + * This form is used to register an initial earlycon boot console and + * replace it with the serial8250_console at 8250 driver init. + * + * Performs console setup for a match (as required by interface) + * If no <options> are specified, then assume the h/w is already setup. + * + * Returns 0 if console matches; otherwise non-zero to use default matching + */ +static int univ8250_console_match(struct console *co, char *name, int idx, + char *options) { - return serial8250_find_port_for_earlycon(); + char match[] = "uart"; /* 8250-specific earlycon name */ + unsigned char iotype; + unsigned long addr; + int i; + + if (strncmp(name, match, 4) != 0) + return -ENODEV; + + if (uart_parse_earlycon(options, &iotype, &addr, &options)) + return -ENODEV; + + /* try to match the port specified on the command line */ + for (i = 0; i < nr_uarts; i++) { + struct uart_port *port = &serial8250_ports[i].port; + + if (port->iotype != iotype) + continue; + if ((iotype == UPIO_MEM || iotype == UPIO_MEM32) && + (port->mapbase != addr)) + continue; + if (iotype == UPIO_PORT && port->iobase != addr) + continue; + + co->index = i; + port->cons = co; + return serial8250_console_setup(port, options, true); + } + + return -ENODEV; } -static struct console serial8250_console = { +static struct console univ8250_console = { .name = "ttyS", - .write = serial8250_console_write, + .write = univ8250_console_write, .device = uart_console_device, - .setup = serial8250_console_setup, - .early_setup = serial8250_console_early_setup, + .setup = univ8250_console_setup, + .match = univ8250_console_match, .flags = CON_PRINTBUFFER | CON_ANYTIME, .index = -1, .data = &serial8250_reg, }; -static int __init serial8250_console_init(void) +static int __init univ8250_console_init(void) { serial8250_isa_init_ports(); - register_console(&serial8250_console); + register_console(&univ8250_console); return 0; } -console_initcall(serial8250_console_init); - -int serial8250_find_port(struct uart_port *p) -{ - int line; - struct uart_port *port; - - for (line = 0; line < nr_uarts; line++) { - port = &serial8250_ports[line].port; - if (uart_match_port(p, port)) - return line; - } - return -ENODEV; -} +console_initcall(univ8250_console_init); -#define SERIAL8250_CONSOLE &serial8250_console +#define SERIAL8250_CONSOLE &univ8250_console #else #define SERIAL8250_CONSOLE NULL #endif @@ -3412,19 +3573,19 @@ int __init early_serial_setup(struct uart_port *port) p->iotype = port->iotype; p->flags = port->flags; p->mapbase = port->mapbase; + p->mapsize = port->mapsize; p->private_data = port->private_data; p->type = port->type; p->line = port->line; - set_io_from_upio(p); + serial8250_set_defaults(up_to_u8250p(p)); + if (port->serial_in) p->serial_in = port->serial_in; if (port->serial_out) p->serial_out = port->serial_out; if (port->handle_irq) p->handle_irq = port->handle_irq; - else - p->handle_irq = serial8250_default_handle_irq; return 0; } @@ -3444,7 +3605,8 @@ void serial8250_suspend_port(int line) port->type != PORT_8250) { unsigned char canary = 0xa5; serial_out(up, UART_SCR, canary); - up->canary = canary; + if (serial_in(up, UART_SCR) == canary) + up->canary = canary; } uart_suspend_port(&serial8250_reg, port); @@ -3666,6 +3828,7 @@ int serial8250_register_8250_port(struct uart_8250_port *up) uart->port.flags = up->port.flags | UPF_BOOT_AUTOCONF; uart->bugs = up->bugs; uart->port.mapbase = up->port.mapbase; + uart->port.mapsize = up->port.mapsize; uart->port.private_data = up->port.private_data; uart->port.fifosize = up->port.fifosize; uart->tx_loadsz = up->tx_loadsz; @@ -3674,6 +3837,7 @@ int serial8250_register_8250_port(struct uart_8250_port *up) uart->port.unthrottle = up->port.unthrottle; uart->port.rs485_config = up->port.rs485_config; uart->port.rs485 = up->port.rs485; + uart->dma = up->dma; /* Take tx_loadsz from fifosize if it wasn't set separately */ if (uart->port.fifosize && !uart->tx_loadsz) @@ -3682,10 +3846,14 @@ int serial8250_register_8250_port(struct uart_8250_port *up) if (up->port.dev) uart->port.dev = up->port.dev; + if (skip_txen_test) + uart->port.flags |= UPF_NO_TXEN_TEST; + if (up->port.flags & UPF_FIXED_TYPE) - serial8250_init_fixed_type_port(uart, up->port.type); + uart->port.type = up->port.type; + + serial8250_set_defaults(uart); - set_io_from_upio(&uart->port); /* Possibly override default I/O functions. */ if (up->port.serial_in) uart->port.serial_in = up->port.serial_in; @@ -3710,13 +3878,6 @@ int serial8250_register_8250_port(struct uart_8250_port *up) uart->dl_read = up->dl_read; if (up->dl_write) uart->dl_write = up->dl_write; - if (up->dma) { - uart->dma = up->dma; - if (!uart->dma->tx_dma) - uart->dma->tx_dma = serial8250_tx_dma; - if (!uart->dma->rx_dma) - uart->dma->rx_dma = serial8250_rx_dma; - } if (serial8250_isa_config != NULL) serial8250_isa_config(0, &uart->port, @@ -3747,9 +3908,11 @@ void serial8250_unregister_port(int line) uart_remove_one_port(&serial8250_reg, &uart->port); if (serial8250_isa_devs) { uart->port.flags &= ~UPF_BOOT_AUTOCONF; + if (skip_txen_test) + uart->port.flags |= UPF_NO_TXEN_TEST; uart->port.type = PORT_UNKNOWN; uart->port.dev = &serial8250_isa_devs->dev; - uart->capabilities = uart_config[uart->port.type].flags; + uart->capabilities = 0; uart_add_one_port(&serial8250_reg, &uart->port); } else { uart->port.dev = NULL; diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 6ae5b8560e4d..176f18f2e3ab 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -17,7 +17,6 @@ #include <linux/io.h> #include <linux/module.h> #include <linux/serial_8250.h> -#include <linux/serial_core.h> #include <linux/serial_reg.h> #include <linux/of.h> #include <linux/of_irq.h> @@ -364,9 +363,9 @@ static int dw8250_probe_of(struct uart_port *p, } if (of_property_read_bool(np, "cts-override")) { - /* Always report DSR as active */ - data->msr_mask_on |= UART_MSR_DSR; - data->msr_mask_off |= UART_MSR_DDSR; + /* 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")) { @@ -375,37 +374,16 @@ static int dw8250_probe_of(struct uart_port *p, data->msr_mask_off |= UART_MSR_TERI; } - /* clock got configured through clk api, all done */ - if (p->uartclk) - return 0; - - /* try to find out clock frequency from DT as fallback */ - if (of_property_read_u32(np, "clock-frequency", &val)) { - dev_err(p->dev, "clk or clock-frequency not defined\n"); - return -EINVAL; - } - p->uartclk = val; - return 0; } static int dw8250_probe_acpi(struct uart_8250_port *up, struct dw8250_data *data) { - const struct acpi_device_id *id; struct uart_port *p = &up->port; dw8250_setup_port(up); - id = acpi_match_device(p->dev->driver->acpi_match_table, p->dev); - if (!id) - return -ENODEV; - - if (!p->uartclk) - if (device_property_read_u32(p->dev, "clock-frequency", - &p->uartclk)) - return -EINVAL; - p->iotype = UPIO_MEM32; p->serial_in = dw8250_serial_in32; p->serial_out = dw8250_serial_out32; @@ -425,18 +403,24 @@ static int dw8250_probe(struct platform_device *pdev) { struct uart_8250_port uart = {}; struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + int irq = platform_get_irq(pdev, 0); struct dw8250_data *data; int err; - if (!regs || !irq) { - dev_err(&pdev->dev, "no registers/irq defined\n"); + 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->start; + uart.port.irq = irq; uart.port.handle_irq = dw8250_handle_irq; uart.port.pm = dw8250_do_pm; uart.port.type = PORT_8250; @@ -453,12 +437,18 @@ static int dw8250_probe(struct platform_device *pdev) 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); + + /* If there is separate baudclk, get the rate from it. */ data->clk = devm_clk_get(&pdev->dev, "baudclk"); if (IS_ERR(data->clk) && PTR_ERR(data->clk) != -EPROBE_DEFER) data->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER) return -EPROBE_DEFER; - if (!IS_ERR(data->clk)) { + if (!IS_ERR_OR_NULL(data->clk)) { err = clk_prepare_enable(data->clk); if (err) dev_warn(&pdev->dev, "could not enable optional baudclk: %d\n", @@ -467,6 +457,12 @@ static int dw8250_probe(struct platform_device *pdev) uart.port.uartclk = clk_get_rate(data->clk); } + /* If no clock rate is defined, fail. */ + if (!uart.port.uartclk) { + dev_err(&pdev->dev, "clock rate not defined\n"); + return -EINVAL; + } + data->pclk = devm_clk_get(&pdev->dev, "apb_pclk"); if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER) { err = -EPROBE_DEFER; @@ -629,6 +625,7 @@ static const struct acpi_device_id dw8250_acpi_match[] = { { "80860F0A", 0 }, { "8086228A", 0 }, { "APMC0D08", 0}, + { "AMD0020", 0 }, { }, }; MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match); @@ -649,3 +646,4 @@ module_platform_driver(dw8250_platform_driver); MODULE_AUTHOR("Jamie Iles"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Synopsys DesignWare 8250 serial port driver"); +MODULE_ALIAS("platform:dw-apb-uart"); diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c index c31a22b4f845..8e119682266a 100644 --- a/drivers/tty/serial/8250/8250_early.c +++ b/drivers/tty/serial/8250/8250_early.c @@ -29,15 +29,12 @@ #include <linux/tty.h> #include <linux/init.h> #include <linux/console.h> -#include <linux/serial_core.h> #include <linux/serial_reg.h> #include <linux/serial.h> #include <linux/serial_8250.h> #include <asm/io.h> #include <asm/serial.h> -static struct earlycon_device *early_device; - unsigned int __weak __init serial8250_early_in(struct uart_port *port, int offset) { switch (port->iotype) { @@ -90,7 +87,8 @@ static void __init serial_putc(struct uart_port *port, int c) static void __init early_serial8250_write(struct console *console, const char *s, unsigned int count) { - struct uart_port *port = &early_device->port; + struct earlycon_device *device = console->data; + struct uart_port *port = &device->port; unsigned int ier; /* Save the IER and disable interrupts preserving the UUE bit */ @@ -107,21 +105,6 @@ static void __init early_serial8250_write(struct console *console, serial8250_early_out(port, UART_IER, ier); } -static unsigned int __init probe_baud(struct uart_port *port) -{ - unsigned char lcr, dll, dlm; - unsigned int quot; - - lcr = serial8250_early_in(port, UART_LCR); - serial8250_early_out(port, UART_LCR, lcr | UART_LCR_DLAB); - dll = serial8250_early_in(port, UART_DLL); - dlm = serial8250_early_in(port, UART_DLM); - serial8250_early_out(port, UART_LCR, lcr); - - quot = (dlm << 8) | dll; - return (port->uartclk / 16) / quot; -} - static void __init init_port(struct earlycon_device *device) { struct uart_port *port = &device->port; @@ -147,52 +130,20 @@ static int __init early_serial8250_setup(struct earlycon_device *device, const char *options) { if (!(device->port.membase || device->port.iobase)) - return 0; + return -ENODEV; if (!device->baud) { - device->baud = probe_baud(&device->port); - snprintf(device->options, sizeof(device->options), "%u", - device->baud); - } + struct uart_port *port = &device->port; + unsigned int ier; - init_port(device); + /* assume the device was initialized, only mask interrupts */ + ier = serial8250_early_in(port, UART_IER); + serial8250_early_out(port, UART_IER, ier & UART_IER_UUE); + } else + init_port(device); - early_device = device; device->con->write = early_serial8250_write; return 0; } EARLYCON_DECLARE(uart8250, early_serial8250_setup); EARLYCON_DECLARE(uart, early_serial8250_setup); - -int __init setup_early_serial8250_console(char *cmdline) -{ - char match[] = "uart8250"; - - if (cmdline && cmdline[4] == ',') - match[4] = '\0'; - - return setup_earlycon(cmdline, match, early_serial8250_setup); -} - -int serial8250_find_port_for_earlycon(void) -{ - struct earlycon_device *device = early_device; - struct uart_port *port = device ? &device->port : NULL; - int line; - int ret; - - if (!port || (!port->membase && !port->iobase)) - return -ENODEV; - - line = serial8250_find_port(port); - if (line < 0) - return -ENODEV; - - ret = update_console_cmdline("uart", 8250, - "ttyS", line, device->options); - if (ret < 0) - ret = update_console_cmdline("uart", 0, - "ttyS", line, device->options); - - return ret; -} diff --git a/drivers/tty/serial/8250/8250_em.c b/drivers/tty/serial/8250/8250_em.c index ae5eaed6aa85..0b6381214917 100644 --- a/drivers/tty/serial/8250/8250_em.c +++ b/drivers/tty/serial/8250/8250_em.c @@ -21,7 +21,6 @@ #include <linux/io.h> #include <linux/module.h> #include <linux/serial_8250.h> -#include <linux/serial_core.h> #include <linux/serial_reg.h> #include <linux/platform_device.h> #include <linux/clk.h> diff --git a/drivers/tty/serial/8250/8250_hp300.c b/drivers/tty/serial/8250/8250_hp300.c index b4882082b247..2891958cd842 100644 --- a/drivers/tty/serial/8250/8250_hp300.c +++ b/drivers/tty/serial/8250/8250_hp300.c @@ -10,7 +10,6 @@ #include <linux/string.h> #include <linux/kernel.h> #include <linux/serial.h> -#include <linux/serial_core.h> #include <linux/serial_8250.h> #include <linux/delay.h> #include <linux/dio.h> diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index fe6d2e51da09..9289999cb7c6 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -11,7 +11,6 @@ #include <linux/io.h> #include <linux/module.h> #include <linux/serial_8250.h> -#include <linux/serial_core.h> #include <linux/serial_reg.h> #include <linux/tty_flip.h> #include <linux/platform_device.h> diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 892eb32cdef4..08da4d3e2162 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -21,12 +21,14 @@ #include <linux/serial_core.h> #include <linux/8250_pci.h> #include <linux/bitops.h> +#include <linux/rational.h> #include <asm/byteorder.h> #include <asm/io.h> #include <linux/dmaengine.h> #include <linux/platform_data/dma-dw.h> +#include <linux/platform_data/dma-hsu.h> #include "8250.h" @@ -1392,45 +1394,22 @@ byt_set_termios(struct uart_port *p, struct ktermios *termios, struct ktermios *old) { unsigned int baud = tty_termios_baud_rate(termios); - unsigned int m, n; + unsigned long fref = 100000000, fuart = baud * 16; + unsigned long w = BIT(15) - 1; + unsigned long m, n; u32 reg; + /* Get Fuart closer to Fref */ + fuart *= rounddown_pow_of_two(fref / fuart); + /* * For baud rates 0.5M, 1M, 1.5M, 2M, 2.5M, 3M, 3.5M and 4M the * dividers must be adjusted. * * uartclk = (m / n) * 100 MHz, where m <= n */ - switch (baud) { - case 500000: - case 1000000: - case 2000000: - case 4000000: - m = 64; - n = 100; - p->uartclk = 64000000; - break; - case 3500000: - m = 56; - n = 100; - p->uartclk = 56000000; - break; - case 1500000: - case 3000000: - m = 48; - n = 100; - p->uartclk = 48000000; - break; - case 2500000: - m = 40; - n = 100; - p->uartclk = 40000000; - break; - default: - m = 2304; - n = 3125; - p->uartclk = 73728000; - } + rational_best_approximation(fuart, fref, w, w, &m, &n); + p->uartclk = fuart; /* Reset the clock */ reg = (m << BYT_PRV_CLK_M_VAL_SHIFT) | (n << BYT_PRV_CLK_N_VAL_SHIFT); @@ -1525,6 +1504,167 @@ byt_serial_setup(struct serial_private *priv, return ret; } +#define INTEL_MID_UART_PS 0x30 +#define INTEL_MID_UART_MUL 0x34 +#define INTEL_MID_UART_DIV 0x38 + +static void intel_mid_set_termios(struct uart_port *p, + struct ktermios *termios, + struct ktermios *old, + unsigned long fref) +{ + unsigned int baud = tty_termios_baud_rate(termios); + unsigned short ps = 16; + unsigned long fuart = baud * ps; + unsigned long w = BIT(24) - 1; + unsigned long mul, div; + + if (fref < fuart) { + /* Find prescaler value that satisfies Fuart < Fref */ + if (fref > baud) + ps = fref / baud; /* baud rate too high */ + else + ps = 1; /* PLL case */ + fuart = baud * ps; + } else { + /* Get Fuart closer to Fref */ + fuart *= rounddown_pow_of_two(fref / fuart); + } + + rational_best_approximation(fuart, fref, w, w, &mul, &div); + p->uartclk = fuart * 16 / ps; /* core uses ps = 16 always */ + + writel(ps, p->membase + INTEL_MID_UART_PS); /* set PS */ + writel(mul, p->membase + INTEL_MID_UART_MUL); /* set MUL */ + writel(div, p->membase + INTEL_MID_UART_DIV); + + serial8250_do_set_termios(p, termios, old); +} + +static void intel_mid_set_termios_38_4M(struct uart_port *p, + struct ktermios *termios, + struct ktermios *old) +{ + intel_mid_set_termios(p, termios, old, 38400000); +} + +static void intel_mid_set_termios_50M(struct uart_port *p, + struct ktermios *termios, + struct ktermios *old) +{ + /* + * The uart clk is 50Mhz, and the baud rate come from: + * baud = 50M * MUL / (DIV * PS * DLAB) + */ + intel_mid_set_termios(p, termios, old, 50000000); +} + +static bool intel_mid_dma_filter(struct dma_chan *chan, void *param) +{ + struct hsu_dma_slave *s = param; + + if (s->dma_dev != chan->device->dev || s->chan_id != chan->chan_id) + return false; + + chan->private = s; + return true; +} + +static int intel_mid_serial_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx, + int index, struct pci_dev *dma_dev) +{ + struct device *dev = port->port.dev; + struct uart_8250_dma *dma; + struct hsu_dma_slave *tx_param, *rx_param; + + dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL); + if (!dma) + return -ENOMEM; + + tx_param = devm_kzalloc(dev, sizeof(*tx_param), GFP_KERNEL); + if (!tx_param) + return -ENOMEM; + + rx_param = devm_kzalloc(dev, sizeof(*rx_param), GFP_KERNEL); + if (!rx_param) + return -ENOMEM; + + rx_param->chan_id = index * 2 + 1; + tx_param->chan_id = index * 2; + + dma->rxconf.src_maxburst = 64; + dma->txconf.dst_maxburst = 64; + + rx_param->dma_dev = &dma_dev->dev; + tx_param->dma_dev = &dma_dev->dev; + + dma->fn = intel_mid_dma_filter; + dma->rx_param = rx_param; + dma->tx_param = tx_param; + + port->port.type = PORT_16750; + port->port.flags |= UPF_FIXED_PORT | UPF_FIXED_TYPE; + port->dma = dma; + + return pci_default_setup(priv, board, port, idx); +} + +#define PCI_DEVICE_ID_INTEL_PNW_UART1 0x081b +#define PCI_DEVICE_ID_INTEL_PNW_UART2 0x081c +#define PCI_DEVICE_ID_INTEL_PNW_UART3 0x081d + +static int pnw_serial_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) +{ + struct pci_dev *pdev = priv->dev; + struct pci_dev *dma_dev; + int index; + + switch (pdev->device) { + case PCI_DEVICE_ID_INTEL_PNW_UART1: + index = 0; + break; + case PCI_DEVICE_ID_INTEL_PNW_UART2: + index = 1; + break; + case PCI_DEVICE_ID_INTEL_PNW_UART3: + index = 2; + break; + default: + return -EINVAL; + } + + dma_dev = pci_get_slot(pdev->bus, PCI_DEVFN(PCI_SLOT(pdev->devfn), 3)); + + port->port.set_termios = intel_mid_set_termios_50M; + + return intel_mid_serial_setup(priv, board, port, idx, index, dma_dev); +} + +#define PCI_DEVICE_ID_INTEL_TNG_UART 0x1191 + +static int tng_serial_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) +{ + struct pci_dev *pdev = priv->dev; + struct pci_dev *dma_dev; + int index = PCI_FUNC(pdev->devfn); + + /* Currently no support for HSU port0 */ + if (index-- == 0) + return -ENODEV; + + dma_dev = pci_get_slot(pdev->bus, PCI_DEVFN(5, 0)); + + port->port.set_termios = intel_mid_set_termios_38_4M; + + return intel_mid_serial_setup(priv, board, port, idx, index, dma_dev); +} + static int pci_omegapci_setup(struct serial_private *priv, const struct pciserial_board *board, @@ -1550,95 +1690,71 @@ static int pci_fintek_setup(struct serial_private *priv, struct uart_8250_port *port, int idx) { struct pci_dev *pdev = priv->dev; - unsigned long base; - unsigned long iobase; - unsigned long ciobase = 0; u8 config_base; + u16 iobase; + + config_base = 0x40 + 0x08 * idx; + + /* Get the io address from configuration space */ + pci_read_config_word(pdev, config_base + 4, &iobase); + + dev_dbg(&pdev->dev, "%s: idx=%d iobase=0x%x", __func__, idx, iobase); + + port->port.iotype = UPIO_PORT; + port->port.iobase = iobase; + + return 0; +} + +static int pci_fintek_init(struct pci_dev *dev) +{ + unsigned long iobase; + u32 max_port, i; u32 bar_data[3]; + u8 config_base; - /* - * Find each UARTs offset in PCI configuraion space - */ - switch (idx) { - case 0: - config_base = 0x40; + switch (dev->device) { + case 0x1104: /* 4 ports */ + case 0x1108: /* 8 ports */ + max_port = dev->device & 0xff; break; - case 1: - config_base = 0x48; - break; - case 2: - config_base = 0x50; - break; - case 3: - config_base = 0x58; - break; - case 4: - config_base = 0x60; - break; - case 5: - config_base = 0x68; - break; - case 6: - config_base = 0x70; - break; - case 7: - config_base = 0x78; - break; - case 8: - config_base = 0x80; - break; - case 9: - config_base = 0x88; - break; - case 10: - config_base = 0x90; - break; - case 11: - config_base = 0x98; + case 0x1112: /* 12 ports */ + max_port = 12; break; default: - /* Unknown number of ports, get out of here */ return -EINVAL; } - if (idx < 4) { - base = pci_resource_start(priv->dev, 3); - ciobase = (int)(base + (0x8 * idx)); - } - /* Get the io address dispatch from the BIOS */ - pci_read_config_dword(pdev, 0x24, &bar_data[0]); - pci_read_config_dword(pdev, 0x20, &bar_data[1]); - pci_read_config_dword(pdev, 0x1c, &bar_data[2]); - - /* Calculate Real IO Port */ - iobase = (bar_data[idx/4] & 0xffffffe0) + (idx % 4) * 8; + pci_read_config_dword(dev, 0x24, &bar_data[0]); + pci_read_config_dword(dev, 0x20, &bar_data[1]); + pci_read_config_dword(dev, 0x1c, &bar_data[2]); - dev_dbg(&pdev->dev, "%s: idx=%d iobase=0x%lx ciobase=0x%lx config_base=0x%2x\n", - __func__, idx, iobase, ciobase, config_base); + for (i = 0; i < max_port; ++i) { + /* UART0 configuration offset start from 0x40 */ + config_base = 0x40 + 0x08 * i; - /* Enable UART I/O port */ - pci_write_config_byte(pdev, config_base + 0x00, 0x01); + /* Calculate Real IO Port */ + iobase = (bar_data[i / 4] & 0xffffffe0) + (i % 4) * 8; - /* Select 128-byte FIFO and 8x FIFO threshold */ - pci_write_config_byte(pdev, config_base + 0x01, 0x33); + /* Enable UART I/O port */ + pci_write_config_byte(dev, config_base + 0x00, 0x01); - /* LSB UART */ - pci_write_config_byte(pdev, config_base + 0x04, (u8)(iobase & 0xff)); + /* Select 128-byte FIFO and 8x FIFO threshold */ + pci_write_config_byte(dev, config_base + 0x01, 0x33); - /* MSB UART */ - pci_write_config_byte(pdev, config_base + 0x05, (u8)((iobase & 0xff00) >> 8)); + /* LSB UART */ + pci_write_config_byte(dev, config_base + 0x04, + (u8)(iobase & 0xff)); - /* irq number, this usually fails, but the spec says to do it anyway. */ - pci_write_config_byte(pdev, config_base + 0x06, pdev->irq); + /* MSB UART */ + pci_write_config_byte(dev, config_base + 0x05, + (u8)((iobase & 0xff00) >> 8)); - port->port.iotype = UPIO_PORT; - port->port.iobase = iobase; - port->port.mapbase = 0; - port->port.membase = NULL; - port->port.regshift = 0; + pci_write_config_byte(dev, config_base + 0x06, dev->irq); + } - return 0; + return max_port; } static int skip_tx_en_setup(struct serial_private *priv, @@ -1989,6 +2105,34 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { }, { .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_PNW_UART1, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pnw_serial_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_PNW_UART2, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pnw_serial_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_PNW_UART3, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pnw_serial_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_TNG_UART, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = tng_serial_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, .device = PCI_DEVICE_ID_INTEL_BSW_UART1, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, @@ -2653,6 +2797,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .setup = pci_fintek_setup, + .init = pci_fintek_init, }, { .vendor = 0x1c29, @@ -2660,6 +2805,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .setup = pci_fintek_setup, + .init = pci_fintek_init, }, { .vendor = 0x1c29, @@ -2667,6 +2813,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .setup = pci_fintek_setup, + .init = pci_fintek_init, }, /* @@ -2864,6 +3011,8 @@ enum pci_board_num_t { pbn_ADDIDATA_PCIe_8_3906250, pbn_ce4100_1_115200, pbn_byt, + pbn_pnw, + pbn_tng, pbn_qrk, pbn_omegapci, pbn_NETMOS9900_2s_115200, @@ -3630,6 +3779,16 @@ static struct pciserial_board pci_boards[] = { .uart_offset = 0x80, .reg_shift = 2, }, + [pbn_pnw] = { + .flags = FL_BASE0, + .num_ports = 1, + .base_baud = 115200, + }, + [pbn_tng] = { + .flags = FL_BASE0, + .num_ports = 1, + .base_baud = 1843200, + }, [pbn_qrk] = { .flags = FL_BASE0, .num_ports = 1, @@ -4006,41 +4165,41 @@ static void pciserial_remove_one(struct pci_dev *dev) pci_disable_device(dev); } -#ifdef CONFIG_PM -static int pciserial_suspend_one(struct pci_dev *dev, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int pciserial_suspend_one(struct device *dev) { - struct serial_private *priv = pci_get_drvdata(dev); + struct pci_dev *pdev = to_pci_dev(dev); + struct serial_private *priv = pci_get_drvdata(pdev); if (priv) pciserial_suspend_ports(priv); - pci_save_state(dev); - pci_set_power_state(dev, pci_choose_state(dev, state)); return 0; } -static int pciserial_resume_one(struct pci_dev *dev) +static int pciserial_resume_one(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); + struct serial_private *priv = pci_get_drvdata(pdev); int err; - struct serial_private *priv = pci_get_drvdata(dev); - - pci_set_power_state(dev, PCI_D0); - pci_restore_state(dev); if (priv) { /* * The device may have been disabled. Re-enable it. */ - err = pci_enable_device(dev); + err = pci_enable_device(pdev); /* FIXME: We cannot simply error out here */ if (err) - dev_err(&dev->dev, "Unable to re-enable ports, trying to continue.\n"); + dev_err(dev, "Unable to re-enable ports, trying to continue.\n"); pciserial_resume_ports(priv); } return 0; } #endif +static SIMPLE_DEV_PM_OPS(pciserial_pm_ops, pciserial_suspend_one, + pciserial_resume_one); + static struct pci_device_id serial_pci_tbl[] = { /* Advantech use PCI_DEVICE_ID_ADVANTECH_PCI3620 (0x3620) as 'PCI_SUBVENDOR_ID' */ { PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3620, @@ -5363,6 +5522,26 @@ static struct pci_device_id serial_pci_tbl[] = { pbn_byt }, /* + * Intel Penwell + */ + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PNW_UART1, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_pnw}, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PNW_UART2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_pnw}, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PNW_UART3, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_pnw}, + + /* + * Intel Tangier + */ + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TNG_UART, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_tng}, + + /* * Intel Quark x1000 */ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_QRK_UART, @@ -5510,10 +5689,9 @@ static struct pci_driver serial_pci_driver = { .name = "serial", .probe = pciserial_init_one, .remove = pciserial_remove_one, -#ifdef CONFIG_PM - .suspend = pciserial_suspend_one, - .resume = pciserial_resume_one, -#endif + .driver = { + .pm = &pciserial_pm_ops, + }, .id_table = serial_pci_tbl, .err_handler = &serial8250_err_handler, }; diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index 6f7f2d753def..c35070356528 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -108,6 +108,7 @@ config SERIAL_8250_PCI tristate "8250/16550 PCI device support" if EXPERT depends on SERIAL_8250 && PCI default SERIAL_8250 + select RATIONAL help This builds standard PCI serial support. You may be able to disable this feature if you only need legacy serial support. diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index d2501f01cd03..f8120c1bde14 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -20,7 +20,7 @@ comment "Non-8250 serial port support" config SERIAL_AMBA_PL010 tristate "ARM AMBA PL010 serial port support" - depends on ARM_AMBA && (BROKEN || !ARCH_VERSATILE) + depends on ARM_AMBA select SERIAL_CORE help This selects the ARM(R) AMBA(R) PrimeCell PL010 UART. If you have @@ -483,16 +483,6 @@ config SERIAL_SA1100_CONSOLE your boot loader (lilo or loadlin) about how to pass options to the kernel at boot time.) -config SERIAL_MFD_HSU - tristate "Medfield High Speed UART support" - depends on PCI - select SERIAL_CORE - -config SERIAL_MFD_HSU_CONSOLE - bool "Medfile HSU serial console support" - depends on SERIAL_MFD_HSU=y - select SERIAL_CORE_CONSOLE - config SERIAL_BFIN tristate "Blackfin serial port support" depends on BLACKFIN @@ -835,7 +825,7 @@ config SERIAL_MCF_CONSOLE config SERIAL_PMACZILOG tristate "Mac or PowerMac z85c30 ESCC support" - depends on (M68K && MAC) || (PPC_OF && PPC_PMAC) + depends on (M68K && MAC) || PPC_PMAC select SERIAL_CORE help This driver supports the Zilog z85C30 serial ports found on @@ -878,7 +868,7 @@ config SERIAL_PMACZILOG_CONSOLE config SERIAL_CPM tristate "CPM SCC/SMC serial port support" - depends on CPM2 || 8xx + depends on CPM2 || CPM1 select SERIAL_CORE help This driver supports the SCC and SMC serial ports on Motorola @@ -1054,7 +1044,7 @@ config SERIAL_SGI_IOC3 config SERIAL_MSM bool "MSM on-chip serial port support" - depends on ARCH_MSM || ARCH_QCOM + depends on ARCH_QCOM select SERIAL_CORE config SERIAL_MSM_CONSOLE @@ -1063,18 +1053,6 @@ config SERIAL_MSM_CONSOLE select SERIAL_CORE_CONSOLE select SERIAL_EARLYCON -config SERIAL_MSM_HS - tristate "MSM UART High Speed: Serial Driver" - depends on ARCH_MSM7X00A || ARCH_MSM7X30 || ARCH_QSD8X50 - select SERIAL_CORE - help - If you have a machine based on MSM family of SoCs, you - can enable its onboard high speed serial port by enabling - this option. - - Choose M here to compile it as a module. The module will be - called msm_serial_hs. - config SERIAL_VT8500 bool "VIA VT8500 on-chip serial port support" depends on ARCH_VT8500 @@ -1153,7 +1131,7 @@ config SERIAL_OMAP_CONSOLE config SERIAL_OF_PLATFORM_NWPSERIAL tristate "NWP serial port driver" - depends on PPC_OF && PPC_DCR + depends on PPC_DCR select SERIAL_OF_PLATFORM select SERIAL_CORE_CONSOLE select SERIAL_CORE diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 599be4b05a26..c3ac3d930b33 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -62,7 +62,6 @@ obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o obj-$(CONFIG_SERIAL_MSM) += msm_serial.o -obj-$(CONFIG_SERIAL_MSM_HS) += msm_serial_hs.o obj-$(CONFIG_SERIAL_NETX) += netx-serial.o obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o @@ -78,7 +77,6 @@ obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o -obj-$(CONFIG_SERIAL_MFD_HSU) += mfd.o obj-$(CONFIG_SERIAL_IFX6X60) += ifx6x60.o obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o obj-$(CONFIG_SERIAL_MSM_SMD) += msm_smd_tty.o diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 8d94c194f090..5a4e9d579585 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -58,6 +58,7 @@ #include <linux/pinctrl/consumer.h> #include <linux/sizes.h> #include <linux/io.h> +#include <linux/workqueue.h> #define UART_NR 14 @@ -156,7 +157,9 @@ struct uart_amba_port { unsigned int lcrh_tx; /* vendor-specific */ unsigned int lcrh_rx; /* vendor-specific */ unsigned int old_cr; /* state during shutdown */ + struct delayed_work tx_softirq_work; bool autorts; + unsigned int tx_irq_seen; /* 0=none, 1=1, 2=2 or more */ char type[12]; #ifdef CONFIG_DMA_ENGINE /* DMA stuff */ @@ -164,6 +167,7 @@ struct uart_amba_port { bool using_rx_dma; struct pl011_dmarx_data dmarx; struct pl011_dmatx_data dmatx; + bool dma_probed; #endif }; @@ -261,10 +265,11 @@ static void pl011_sgbuf_free(struct dma_chan *chan, struct pl011_sgbuf *sg, } } -static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port *uap) +static void pl011_dma_probe(struct uart_amba_port *uap) { /* DMA is the sole user of the platform data right now */ struct amba_pl011_data *plat = dev_get_platdata(uap->port.dev); + struct device *dev = uap->port.dev; struct dma_slave_config tx_conf = { .dst_addr = uap->port.mapbase + UART01x_DR, .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, @@ -275,9 +280,14 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port * struct dma_chan *chan; dma_cap_mask_t mask; - chan = dma_request_slave_channel(dev, "tx"); + uap->dma_probed = true; + chan = dma_request_slave_channel_reason(dev, "tx"); + if (IS_ERR(chan)) { + if (PTR_ERR(chan) == -EPROBE_DEFER) { + uap->dma_probed = false; + return; + } - if (!chan) { /* We need platform data */ if (!plat || !plat->dma_filter) { dev_info(uap->port.dev, "no DMA platform data\n"); @@ -385,63 +395,17 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port * } } -#ifndef MODULE -/* - * Stack up the UARTs and let the above initcall be done at device - * initcall time, because the serial driver is called as an arch - * initcall, and at this time the DMA subsystem is not yet registered. - * At this point the driver will switch over to using DMA where desired. - */ -struct dma_uap { - struct list_head node; - struct uart_amba_port *uap; - struct device *dev; -}; - -static LIST_HEAD(pl011_dma_uarts); - -static int __init pl011_dma_initcall(void) -{ - struct list_head *node, *tmp; - - list_for_each_safe(node, tmp, &pl011_dma_uarts) { - struct dma_uap *dmau = list_entry(node, struct dma_uap, node); - pl011_dma_probe_initcall(dmau->dev, dmau->uap); - list_del(node); - kfree(dmau); - } - return 0; -} - -device_initcall(pl011_dma_initcall); - -static void pl011_dma_probe(struct device *dev, struct uart_amba_port *uap) -{ - struct dma_uap *dmau = kzalloc(sizeof(struct dma_uap), GFP_KERNEL); - if (dmau) { - dmau->uap = uap; - dmau->dev = dev; - list_add_tail(&dmau->node, &pl011_dma_uarts); - } -} -#else -static void pl011_dma_probe(struct device *dev, struct uart_amba_port *uap) -{ - pl011_dma_probe_initcall(dev, uap); -} -#endif - static void pl011_dma_remove(struct uart_amba_port *uap) { - /* TODO: remove the initcall if it has not yet executed */ if (uap->dmatx.chan) dma_release_channel(uap->dmatx.chan); if (uap->dmarx.chan) dma_release_channel(uap->dmarx.chan); } -/* Forward declare this for the refill routine */ +/* Forward declare these for the refill routine */ static int pl011_dma_tx_refill(struct uart_amba_port *uap); +static void pl011_start_tx_pio(struct uart_amba_port *uap); /* * The current DMA TX buffer has been sent. @@ -479,14 +443,13 @@ static void pl011_dma_tx_callback(void *data) return; } - if (pl011_dma_tx_refill(uap) <= 0) { + if (pl011_dma_tx_refill(uap) <= 0) /* * We didn't queue a DMA buffer for some reason, but we * have data pending to be sent. Re-enable the TX IRQ. */ - uap->im |= UART011_TXIM; - writew(uap->im, uap->port.membase + UART011_IMSC); - } + pl011_start_tx_pio(uap); + spin_unlock_irqrestore(&uap->port.lock, flags); } @@ -664,12 +627,10 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap) if (!uap->dmatx.queued) { if (pl011_dma_tx_refill(uap) > 0) { uap->im &= ~UART011_TXIM; - ret = true; - } else { - uap->im |= UART011_TXIM; + writew(uap->im, uap->port.membase + + UART011_IMSC); + } else ret = false; - } - writew(uap->im, uap->port.membase + UART011_IMSC); } else if (!(uap->dmacr & UART011_TXDMAE)) { uap->dmacr |= UART011_TXDMAE; writew(uap->dmacr, @@ -1021,6 +982,9 @@ static void pl011_dma_startup(struct uart_amba_port *uap) { int ret; + if (!uap->dma_probed) + pl011_dma_probe(uap); + if (!uap->dmatx.chan) return; @@ -1142,7 +1106,7 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap) #else /* Blank functions if the DMA engine is not available */ -static inline void pl011_dma_probe(struct device *dev, struct uart_amba_port *uap) +static inline void pl011_dma_probe(struct uart_amba_port *uap) { } @@ -1208,15 +1172,24 @@ static void pl011_stop_tx(struct uart_port *port) pl011_dma_tx_stop(uap); } +static bool pl011_tx_chars(struct uart_amba_port *uap); + +/* Start TX with programmed I/O only (no DMA) */ +static void pl011_start_tx_pio(struct uart_amba_port *uap) +{ + uap->im |= UART011_TXIM; + writew(uap->im, uap->port.membase + UART011_IMSC); + if (!uap->tx_irq_seen) + pl011_tx_chars(uap); +} + static void pl011_start_tx(struct uart_port *port) { struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); - if (!pl011_dma_tx_start(uap)) { - uap->im |= UART011_TXIM; - writew(uap->im, uap->port.membase + UART011_IMSC); - } + if (!pl011_dma_tx_start(uap)) + pl011_start_tx_pio(uap); } static void pl011_stop_rx(struct uart_port *port) @@ -1274,40 +1247,87 @@ __acquires(&uap->port.lock) spin_lock(&uap->port.lock); } -static void pl011_tx_chars(struct uart_amba_port *uap) +/* + * Transmit a character + * There must be at least one free entry in the TX FIFO to accept the char. + * + * Returns true if the FIFO might have space in it afterwards; + * returns false if the FIFO definitely became full. + */ +static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c) +{ + writew(c, uap->port.membase + UART01x_DR); + uap->port.icount.tx++; + + if (likely(uap->tx_irq_seen > 1)) + return true; + + return !(readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF); +} + +static bool pl011_tx_chars(struct uart_amba_port *uap) { struct circ_buf *xmit = &uap->port.state->xmit; int count; + if (unlikely(uap->tx_irq_seen < 2)) + /* + * Initial FIFO fill level unknown: we must check TXFF + * after each write, so just try to fill up the FIFO. + */ + count = uap->fifosize; + else /* tx_irq_seen >= 2 */ + /* + * FIFO initially at least half-empty, so we can simply + * write half the FIFO without polling TXFF. + + * Note: the *first* TX IRQ can still race with + * pl011_start_tx_pio(), which can result in the FIFO + * being fuller than expected in that case. + */ + count = uap->fifosize >> 1; + + /* + * If the FIFO is full we're guaranteed a TX IRQ at some later point, + * and can't transmit immediately in any case: + */ + if (unlikely(uap->tx_irq_seen < 2 && + readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)) + return false; + if (uap->port.x_char) { - writew(uap->port.x_char, uap->port.membase + UART01x_DR); - uap->port.icount.tx++; + pl011_tx_char(uap, uap->port.x_char); uap->port.x_char = 0; - return; + --count; } if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) { pl011_stop_tx(&uap->port); - return; + goto done; } /* If we are using DMA mode, try to send some characters. */ if (pl011_dma_tx_irq(uap)) - return; + goto done; - count = uap->fifosize >> 1; - do { - writew(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR); + while (count-- > 0 && pl011_tx_char(uap, xmit->buf[xmit->tail])) { xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - uap->port.icount.tx++; if (uart_circ_empty(xmit)) break; - } while (--count > 0); + } if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&uap->port); - if (uart_circ_empty(xmit)) + if (uart_circ_empty(xmit)) { pl011_stop_tx(&uap->port); + goto done; + } + + if (unlikely(!uap->tx_irq_seen)) + schedule_delayed_work(&uap->tx_softirq_work, uap->port.timeout); + +done: + return false; } static void pl011_modem_status(struct uart_amba_port *uap) @@ -1334,6 +1354,28 @@ static void pl011_modem_status(struct uart_amba_port *uap) wake_up_interruptible(&uap->port.state->port.delta_msr_wait); } +static void pl011_tx_softirq(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct uart_amba_port *uap = + container_of(dwork, struct uart_amba_port, tx_softirq_work); + + spin_lock(&uap->port.lock); + while (pl011_tx_chars(uap)) ; + spin_unlock(&uap->port.lock); +} + +static void pl011_tx_irq_seen(struct uart_amba_port *uap) +{ + if (likely(uap->tx_irq_seen > 1)) + return; + + uap->tx_irq_seen++; + if (uap->tx_irq_seen < 2) + /* first TX IRQ */ + cancel_delayed_work(&uap->tx_softirq_work); +} + static irqreturn_t pl011_int(int irq, void *dev_id) { struct uart_amba_port *uap = dev_id; @@ -1372,8 +1414,10 @@ static irqreturn_t pl011_int(int irq, void *dev_id) if (status & (UART011_DSRMIS|UART011_DCDMIS| UART011_CTSMIS|UART011_RIMIS)) pl011_modem_status(uap); - if (status & UART011_TXIS) + if (status & UART011_TXIS) { + pl011_tx_irq_seen(uap); pl011_tx_chars(uap); + } if (pass_counter-- == 0) break; @@ -1577,7 +1621,7 @@ static int pl011_startup(struct uart_port *port) { struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); - unsigned int cr, lcr_h, fbrd, ibrd; + unsigned int cr; int retval; retval = pl011_hwinit(port); @@ -1595,30 +1639,8 @@ static int pl011_startup(struct uart_port *port) writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS); - /* - * Provoke TX FIFO interrupt into asserting. Taking care to preserve - * baud rate and data format specified by FBRD, IBRD and LCRH as the - * UART may already be in use as a console. - */ spin_lock_irq(&uap->port.lock); - fbrd = readw(uap->port.membase + UART011_FBRD); - ibrd = readw(uap->port.membase + UART011_IBRD); - lcr_h = readw(uap->port.membase + uap->lcrh_rx); - - cr = UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_LBE; - writew(cr, uap->port.membase + UART011_CR); - writew(0, uap->port.membase + UART011_FBRD); - writew(1, uap->port.membase + UART011_IBRD); - pl011_write_lcr_h(uap, 0); - writew(0, uap->port.membase + UART01x_DR); - while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY) - barrier(); - - writew(fbrd, uap->port.membase + UART011_FBRD); - writew(ibrd, uap->port.membase + UART011_IBRD); - pl011_write_lcr_h(uap, lcr_h); - /* restore RTS and DTR */ cr = uap->old_cr & (UART011_CR_RTS | UART011_CR_DTR); cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE; @@ -1672,13 +1694,15 @@ static void pl011_shutdown(struct uart_port *port) container_of(port, struct uart_amba_port, port); unsigned int cr; + cancel_delayed_work_sync(&uap->tx_softirq_work); + /* * disable all interrupts */ spin_lock_irq(&uap->port.lock); uap->im = 0; writew(uap->im, uap->port.membase + UART011_IMSC); - writew(0xffff, uap->port.membase + UART011_ICR); + writew(0xffff & ~UART011_TXIS, uap->port.membase + UART011_ICR); spin_unlock_irq(&uap->port.lock); pl011_dma_shutdown(uap); @@ -2218,7 +2242,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) uap->port.ops = &amba_pl011_pops; uap->port.flags = UPF_BOOT_AUTOCONF; uap->port.line = i; - pl011_dma_probe(&dev->dev, uap); + INIT_DELAYED_WORK(&uap->tx_softirq_work, pl011_tx_softirq); /* Ensure interrupts from this UART are masked and cleared */ writew(0, uap->port.membase + UART011_IMSC); @@ -2233,7 +2257,8 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) if (!amba_reg.state) { ret = uart_register_driver(&amba_reg); if (ret < 0) { - pr_err("Failed to register AMBA-PL011 driver\n"); + dev_err(&dev->dev, + "Failed to register AMBA-PL011 driver\n"); return ret; } } @@ -2242,7 +2267,6 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) if (ret) { amba_ports[i] = NULL; uart_unregister_driver(&amba_reg); - pl011_dma_remove(uap); } return ret; diff --git a/drivers/tty/serial/apbuart.c b/drivers/tty/serial/apbuart.c index 4f0f95e358e8..f3af317131ac 100644 --- a/drivers/tty/serial/apbuart.c +++ b/drivers/tty/serial/apbuart.c @@ -572,7 +572,7 @@ static int apbuart_probe(struct platform_device *op) return 0; } -static struct of_device_id apbuart_match[] = { +static const struct of_device_id apbuart_match[] = { { .name = "GAISLER_APBUART", }, diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c index 77fc9faa74a4..1519d2ca7705 100644 --- a/drivers/tty/serial/ar933x_uart.c +++ b/drivers/tty/serial/ar933x_uart.c @@ -649,7 +649,7 @@ static int ar933x_uart_probe(struct platform_device *pdev) id = 0; } - if (id > CONFIG_SERIAL_AR933X_NR_UARTS) + if (id >= CONFIG_SERIAL_AR933X_NR_UARTS) return -EINVAL; irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 4e959c43f680..d58fe4763d9e 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -855,7 +855,7 @@ static int atmel_prepare_tx_dma(struct uart_port *port) spin_lock_init(&atmel_port->lock_tx); sg_init_table(&atmel_port->sg_tx, 1); /* UART circular tx buffer is an aligned page. */ - BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK); + BUG_ON(!PAGE_ALIGNED(port->state->xmit.buf)); sg_set_page(&atmel_port->sg_tx, virt_to_page(port->state->xmit.buf), UART_XMIT_SIZE, @@ -1034,10 +1034,10 @@ static int atmel_prepare_rx_dma(struct uart_port *port) spin_lock_init(&atmel_port->lock_rx); sg_init_table(&atmel_port->sg_rx, 1); /* UART circular rx buffer is an aligned page. */ - BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK); + BUG_ON(!PAGE_ALIGNED(ring->buf)); sg_set_page(&atmel_port->sg_rx, virt_to_page(ring->buf), - ATMEL_SERIAL_RINGSIZE, + sizeof(struct atmel_uart_char) * ATMEL_SERIAL_RINGSIZE, (int)ring->buf & ~PAGE_MASK); nent = dma_map_sg(port->dev, &atmel_port->sg_rx, @@ -1554,7 +1554,7 @@ static void atmel_tasklet_func(unsigned long data) spin_unlock(&port->lock); } -static int atmel_init_property(struct atmel_uart_port *atmel_port, +static void atmel_init_property(struct atmel_uart_port *atmel_port, struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -1595,7 +1595,6 @@ static int atmel_init_property(struct atmel_uart_port *atmel_port, atmel_port->use_dma_tx = false; } - return 0; } static void atmel_init_rs485(struct uart_port *port, @@ -1777,10 +1776,13 @@ static int atmel_startup(struct uart_port *port) if (retval) goto free_irq; + tasklet_enable(&atmel_port->tasklet); + /* * Initialize DMA (if necessary) */ atmel_init_property(atmel_port, pdev); + atmel_set_ops(port); if (atmel_port->prepare_rx) { retval = atmel_port->prepare_rx(port); @@ -1879,6 +1881,7 @@ static void atmel_shutdown(struct uart_port *port) * Clear out any scheduled tasklets before * we destroy the buffers */ + tasklet_disable(&atmel_port->tasklet); tasklet_kill(&atmel_port->tasklet); /* @@ -2256,8 +2259,8 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port, struct uart_port *port = &atmel_port->uart; struct atmel_uart_data *pdata = dev_get_platdata(&pdev->dev); - if (!atmel_init_property(atmel_port, pdev)) - atmel_set_ops(port); + atmel_init_property(atmel_port, pdev); + atmel_set_ops(port); atmel_init_rs485(port, pdev); @@ -2272,6 +2275,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port, tasklet_init(&atmel_port->tasklet, atmel_tasklet_func, (unsigned long)port); + tasklet_disable(&atmel_port->tasklet); memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring)); @@ -2581,8 +2585,8 @@ static int atmel_init_gpios(struct atmel_uart_port *p, struct device *dev) struct gpio_desc *gpiod; p->gpios = mctrl_gpio_init(dev, 0); - if (IS_ERR_OR_NULL(p->gpios)) - return -1; + if (IS_ERR(p->gpios)) + return PTR_ERR(p->gpios); for (i = 0; i < UART_GPIO_MAX; i++) { gpiod = mctrl_gpio_to_gpiod(p->gpios, i); @@ -2635,9 +2639,10 @@ static int atmel_serial_probe(struct platform_device *pdev) spin_lock_init(&port->lock_suspended); ret = atmel_init_gpios(port, &pdev->dev); - if (ret < 0) - dev_err(&pdev->dev, "%s", - "Failed to initialize GPIOs. The serial port may not work as expected"); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to initialize GPIOs."); + goto err; + } ret = atmel_init_port(port, pdev); if (ret) diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c index 01d83df08e3d..681e0f3d5e0e 100644 --- a/drivers/tty/serial/bcm63xx_uart.c +++ b/drivers/tty/serial/bcm63xx_uart.c @@ -854,7 +854,7 @@ static int bcm_uart_probe(struct platform_device *pdev) ret = uart_add_one_port(&bcm_uart_driver, port); if (ret) { - ports[pdev->id].membase = 0; + ports[pdev->id].membase = NULL; return ret; } platform_set_drvdata(pdev, port); @@ -868,7 +868,7 @@ static int bcm_uart_remove(struct platform_device *pdev) port = platform_get_drvdata(pdev); uart_remove_one_port(&bcm_uart_driver, port); /* mark port as free */ - ports[pdev->id].membase = 0; + ports[pdev->id].membase = NULL; return 0; } diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c index 43b3e2c233ff..155781ece050 100644 --- a/drivers/tty/serial/bfin_uart.c +++ b/drivers/tty/serial/bfin_uart.c @@ -464,6 +464,7 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) int x_pos, pos; unsigned long flags; + dma_disable_irq_nosync(uart->rx_dma_channel); spin_lock_irqsave(&uart->rx_lock, flags); /* 2D DMA RX buffer ring is used. Because curr_y_count and @@ -496,6 +497,7 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) } spin_unlock_irqrestore(&uart->rx_lock, flags); + dma_enable_irq(uart->rx_dma_channel); mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES); } diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c index 6e11c275f2ab..d5d2dd7c7917 100644 --- a/drivers/tty/serial/clps711x.c +++ b/drivers/tty/serial/clps711x.c @@ -501,6 +501,8 @@ static int uart_clps711x_probe(struct platform_device *pdev) platform_set_drvdata(pdev, s); s->gpios = mctrl_gpio_init(&pdev->dev, 0); + if (IS_ERR(s->gpios)) + return PTR_ERR(s->gpios); ret = uart_add_one_port(&clps711x_uart, &s->port); if (ret) diff --git a/drivers/tty/serial/cpm_uart/Makefile b/drivers/tty/serial/cpm_uart/Makefile index e072724ea754..896a5d57881c 100644 --- a/drivers/tty/serial/cpm_uart/Makefile +++ b/drivers/tty/serial/cpm_uart/Makefile @@ -6,6 +6,6 @@ obj-$(CONFIG_SERIAL_CPM) += cpm_uart.o # Select the correct platform objects. cpm_uart-objs-$(CONFIG_CPM2) += cpm_uart_cpm2.o -cpm_uart-objs-$(CONFIG_8xx) += cpm_uart_cpm1.o +cpm_uart-objs-$(CONFIG_CPM1) += cpm_uart_cpm1.o cpm_uart-objs := cpm_uart_core.o $(cpm_uart-objs-y) diff --git a/drivers/tty/serial/cpm_uart/cpm_uart.h b/drivers/tty/serial/cpm_uart/cpm_uart.h index cf34d26ff6cd..0ad027b95873 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart.h +++ b/drivers/tty/serial/cpm_uart/cpm_uart.h @@ -19,7 +19,7 @@ #if defined(CONFIG_CPM2) #include "cpm_uart_cpm2.h" -#elif defined(CONFIG_8xx) +#elif defined(CONFIG_CPM1) #include "cpm_uart_cpm1.h" #endif diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c index fddb1fd4d9d3..08431adeacd5 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c @@ -1435,7 +1435,7 @@ static int cpm_uart_remove(struct platform_device *ofdev) return uart_remove_one_port(&cpm_reg, &pinfo->port); } -static struct of_device_id cpm_uart_match[] = { +static const struct of_device_id cpm_uart_match[] = { { .compatible = "fsl,cpm1-smc-uart", }, diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c index 64fe25a4285c..5fdc9f3ecd64 100644 --- a/drivers/tty/serial/earlycon.c +++ b/drivers/tty/serial/earlycon.c @@ -10,6 +10,9 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/console.h> #include <linux/kernel.h> #include <linux/init.h> @@ -34,6 +37,10 @@ static struct earlycon_device early_console_dev = { .con = &early_con, }; +extern struct earlycon_id __earlycon_table[]; +static const struct earlycon_id __earlycon_table_sentinel + __used __section(__earlycon_table_end); + static const struct of_device_id __earlycon_of_table_sentinel __used __section(__earlycon_of_table_end); @@ -54,44 +61,29 @@ static void __iomem * __init earlycon_map(unsigned long paddr, size_t size) return base; } -static int __init parse_options(struct earlycon_device *device, - char *options) +static int __init parse_options(struct earlycon_device *device, char *options) { struct uart_port *port = &device->port; - int mmio, mmio32, length; + int length; unsigned long addr; - if (!options) - return -ENODEV; + if (uart_parse_earlycon(options, &port->iotype, &addr, &options)) + return -EINVAL; - mmio = !strncmp(options, "mmio,", 5); - mmio32 = !strncmp(options, "mmio32,", 7); - if (mmio || mmio32) { - port->iotype = (mmio ? UPIO_MEM : UPIO_MEM32); - options += mmio ? 5 : 7; - addr = simple_strtoul(options, NULL, 0); + switch (port->iotype) { + case UPIO_MEM32: + port->regshift = 2; /* fall-through */ + case UPIO_MEM: port->mapbase = addr; - if (mmio32) - port->regshift = 2; - } else if (!strncmp(options, "io,", 3)) { - port->iotype = UPIO_PORT; - options += 3; - addr = simple_strtoul(options, NULL, 0); + break; + case UPIO_PORT: port->iobase = addr; - mmio = 0; - } else if (!strncmp(options, "0x", 2)) { - port->iotype = UPIO_MEM; - addr = simple_strtoul(options, NULL, 0); - port->mapbase = addr; - } else { + break; + default: return -EINVAL; } - port->uartclk = BASE_BAUD * 16; - - options = strchr(options, ','); if (options) { - options++; device->baud = simple_strtoul(options, NULL, 0); length = min(strcspn(options, " ") + 1, (size_t)(sizeof(device->options))); @@ -100,7 +92,7 @@ static int __init parse_options(struct earlycon_device *device, if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM32) pr_info("Early serial console at MMIO%s 0x%llx (options '%s')\n", - mmio32 ? "32" : "", + (port->iotype == UPIO_MEM32) ? "32" : "", (unsigned long long)port->mapbase, device->options); else @@ -111,34 +103,21 @@ static int __init parse_options(struct earlycon_device *device, return 0; } -int __init setup_earlycon(char *buf, const char *match, - int (*setup)(struct earlycon_device *, const char *)) +static int __init register_earlycon(char *buf, const struct earlycon_id *match) { int err; - size_t len; struct uart_port *port = &early_console_dev.port; - if (!buf || !match || !setup) - return 0; - - len = strlen(match); - if (strncmp(buf, match, len)) - return 0; - if (buf[len] && (buf[len] != ',')) - return 0; - - buf += len + 1; - - err = parse_options(&early_console_dev, buf); /* On parsing error, pass the options buf to the setup function */ - if (!err) + if (buf && !parse_options(&early_console_dev, buf)) buf = NULL; + port->uartclk = BASE_BAUD * 16; if (port->mapbase) port->membase = earlycon_map(port->mapbase, 64); early_console_dev.con->data = &early_console_dev; - err = setup(&early_console_dev, buf); + err = match->setup(&early_console_dev, buf); if (err < 0) return err; if (!early_console_dev.con->write) @@ -148,6 +127,77 @@ int __init setup_earlycon(char *buf, const char *match, return 0; } +/** + * setup_earlycon - match and register earlycon console + * @buf: earlycon param string + * + * Registers the earlycon console matching the earlycon specified + * in the param string @buf. Acceptable param strings are of the form + * <name>,io|mmio|mmio32,<addr>,<options> + * <name>,0x<addr>,<options> + * <name>,<options> + * <name> + * + * Only for the third form does the earlycon setup() method receive the + * <options> string in the 'options' parameter; all other forms set + * the parameter to NULL. + * + * Returns 0 if an attempt to register the earlycon was made, + * otherwise negative error code + */ +int __init setup_earlycon(char *buf) +{ + const struct earlycon_id *match; + + if (!buf || !buf[0]) + return -EINVAL; + + if (early_con.flags & CON_ENABLED) + return -EALREADY; + + for (match = __earlycon_table; match->name[0]; match++) { + size_t len = strlen(match->name); + + if (strncmp(buf, match->name, len)) + continue; + + if (buf[len]) { + if (buf[len] != ',') + continue; + buf += len + 1; + } else + buf = NULL; + + return register_earlycon(buf, match); + } + + return -ENOENT; +} + +/* early_param wrapper for setup_earlycon() */ +static int __init param_setup_earlycon(char *buf) +{ + int err; + + /* + * Just 'earlycon' is a valid param for devicetree earlycons; + * don't generate a warning from parse_early_params() in that case + */ + if (!buf || !buf[0]) + return 0; + + err = setup_earlycon(buf); + if (err == -ENOENT) { + pr_warn("no match for %s\n", buf); + err = 0; + } else if (err == -EALREADY) { + pr_warn("already registered\n"); + err = 0; + } + return err; +} +early_param("earlycon", param_setup_earlycon); + int __init of_setup_earlycon(unsigned long addr, int (*setup)(struct earlycon_device *, const char *)) { diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 3ad1458bfeb0..08ce76f4f261 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -257,7 +257,7 @@ struct lpuart_port { struct timer_list lpuart_timer; }; -static struct of_device_id lpuart_dt_ids[] = { +static const struct of_device_id lpuart_dt_ids[] = { { .compatible = "fsl,vf610-lpuart", }, diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 0eb29b1c47ac..c8cfa0637128 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -1,13 +1,10 @@ /* - * Driver for Motorola IMX serial ports + * Driver for Motorola/Freescale IMX serial ports * - * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. * - * Author: Sascha Hauer <sascha@saschahauer.de> - * Copyright (C) 2004 Pengutronix - * - * Copyright (C) 2009 emlix GmbH - * Author: Fabian Godehardt (added IrDA support for iMX) + * Author: Sascha Hauer <sascha@saschahauer.de> + * Copyright (C) 2004 Pengutronix * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,13 +15,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * [29-Mar-2005] Mike Lee - * Added hardware handshake */ #if defined(CONFIG_SERIAL_IMX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) @@ -189,7 +179,7 @@ #define UART_NR 8 -/* i.mx21 type uart runs on all i.mx except i.mx1 */ +/* i.MX21 type uart runs on all i.mx except i.MX1 and i.MX6q */ enum imx_uart_type { IMX1_UART, IMX21_UART, @@ -206,10 +196,8 @@ struct imx_port { struct uart_port port; struct timer_list timer; unsigned int old_status; - int txirq, rxirq, rtsirq; unsigned int have_rtscts:1; unsigned int dte_mode:1; - unsigned int use_irda:1; unsigned int irda_inv_rx:1; unsigned int irda_inv_tx:1; unsigned short trcv_delay; /* transceiver delay */ @@ -236,12 +224,6 @@ struct imx_port_ucrs { unsigned int ucr3; }; -#ifdef CONFIG_IRDA -#define USE_IRDA(sport) ((sport)->use_irda) -#else -#define USE_IRDA(sport) (0) -#endif - static struct imx_uart_data imx_uart_devdata[] = { [IMX1_UART] = { .uts_reg = IMX1_UTS, @@ -273,7 +255,7 @@ static struct platform_device_id imx_uart_devtype[] = { }; MODULE_DEVICE_TABLE(platform, imx_uart_devtype); -static struct of_device_id imx_uart_dt_ids[] = { +static const struct of_device_id imx_uart_dt_ids[] = { { .compatible = "fsl,imx6q-uart", .data = &imx_uart_devdata[IMX6Q_UART], }, { .compatible = "fsl,imx1-uart", .data = &imx_uart_devdata[IMX1_UART], }, { .compatible = "fsl,imx21-uart", .data = &imx_uart_devdata[IMX21_UART], }, @@ -376,48 +358,6 @@ static void imx_stop_tx(struct uart_port *port) struct imx_port *sport = (struct imx_port *)port; unsigned long temp; - if (USE_IRDA(sport)) { - /* half duplex - wait for end of transmission */ - int n = 256; - while ((--n > 0) && - !(readl(sport->port.membase + USR2) & USR2_TXDC)) { - udelay(5); - barrier(); - } - /* - * irda transceiver - wait a bit more to avoid - * cutoff, hardware dependent - */ - udelay(sport->trcv_delay); - - /* - * half duplex - reactivate receive mode, - * flush receive pipe echo crap - */ - if (readl(sport->port.membase + USR2) & USR2_TXDC) { - temp = readl(sport->port.membase + UCR1); - temp &= ~(UCR1_TXMPTYEN | UCR1_TRDYEN); - writel(temp, sport->port.membase + UCR1); - - temp = readl(sport->port.membase + UCR4); - temp &= ~(UCR4_TCEN); - writel(temp, sport->port.membase + UCR4); - - while (readl(sport->port.membase + URXD0) & - URXD_CHARRDY) - barrier(); - - temp = readl(sport->port.membase + UCR1); - temp |= UCR1_RRDYEN; - writel(temp, sport->port.membase + UCR1); - - temp = readl(sport->port.membase + UCR4); - temp |= UCR4_DREN; - writel(temp, sport->port.membase + UCR4); - } - return; - } - /* * We are maybe in the SMP context, so if the DMA TX thread is running * on other cpu, we have to wait for it to finish. @@ -425,8 +365,23 @@ static void imx_stop_tx(struct uart_port *port) if (sport->dma_is_enabled && sport->dma_is_txing) return; - temp = readl(sport->port.membase + UCR1); - writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1); + temp = readl(port->membase + UCR1); + writel(temp & ~UCR1_TXMPTYEN, port->membase + UCR1); + + /* in rs485 mode disable transmitter if shifter is empty */ + if (port->rs485.flags & SER_RS485_ENABLED && + readl(port->membase + USR2) & USR2_TXDC) { + temp = readl(port->membase + UCR2); + if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND) + temp &= ~UCR2_CTS; + else + temp |= UCR2_CTS; + writel(temp, port->membase + UCR2); + + temp = readl(port->membase + UCR4); + temp &= ~UCR4_TCEN; + writel(temp, port->membase + UCR4); + } } /* @@ -620,15 +575,18 @@ static void imx_start_tx(struct uart_port *port) struct imx_port *sport = (struct imx_port *)port; unsigned long temp; - if (USE_IRDA(sport)) { - /* half duplex in IrDA mode; have to disable receive mode */ - temp = readl(sport->port.membase + UCR4); - temp &= ~(UCR4_DREN); - writel(temp, sport->port.membase + UCR4); + if (port->rs485.flags & SER_RS485_ENABLED) { + /* enable transmitter and shifter empty irq */ + temp = readl(port->membase + UCR2); + if (port->rs485.flags & SER_RS485_RTS_ON_SEND) + temp &= ~UCR2_CTS; + else + temp |= UCR2_CTS; + writel(temp, port->membase + UCR2); - temp = readl(sport->port.membase + UCR1); - temp &= ~(UCR1_RRDYEN); - writel(temp, sport->port.membase + UCR1); + temp = readl(port->membase + UCR4); + temp |= UCR4_TCEN; + writel(temp, port->membase + UCR4); } if (!sport->dma_is_enabled) { @@ -636,16 +594,6 @@ static void imx_start_tx(struct uart_port *port) writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1); } - if (USE_IRDA(sport)) { - temp = readl(sport->port.membase + UCR1); - temp |= UCR1_TRDYEN; - writel(temp, sport->port.membase + UCR1); - - temp = readl(sport->port.membase + UCR4); - temp |= UCR4_TCEN; - writel(temp, sport->port.membase + UCR4); - } - if (sport->dma_is_enabled) { if (sport->port.x_char) { /* We have X-char to send, so enable TX IRQ and @@ -796,6 +744,7 @@ static irqreturn_t imx_int(int irq, void *dev_id) unsigned int sts2; sts = readl(sport->port.membase + USR1); + sts2 = readl(sport->port.membase + USR2); if (sts & USR1_RRDY) { if (sport->dma_is_enabled) @@ -804,8 +753,10 @@ static irqreturn_t imx_int(int irq, void *dev_id) imx_rxint(irq, dev_id); } - if (sts & USR1_TRDY && - readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN) + if ((sts & USR1_TRDY && + readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN) || + (sts2 & USR2_TXDC && + readl(sport->port.membase + UCR4) & UCR4_TCEN)) imx_txint(irq, dev_id); if (sts & USR1_RTSD) @@ -814,11 +765,10 @@ static irqreturn_t imx_int(int irq, void *dev_id) if (sts & USR1_AWAKE) writel(USR1_AWAKE, sport->port.membase + USR1); - sts2 = readl(sport->port.membase + USR2); if (sts2 & USR2_ORE) { dev_err(sport->port.dev, "Rx FIFO overrun\n"); sport->port.icount.overrun++; - writel(sts2 | USR2_ORE, sport->port.membase + USR2); + writel(USR2_ORE, sport->port.membase + USR2); } return IRQ_HANDLED; @@ -866,11 +816,13 @@ static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl) struct imx_port *sport = (struct imx_port *)port; unsigned long temp; - temp = readl(sport->port.membase + UCR2) & ~(UCR2_CTS | UCR2_CTSC); - if (mctrl & TIOCM_RTS) - temp |= UCR2_CTS | UCR2_CTSC; - - writel(temp, sport->port.membase + UCR2); + if (!(port->rs485.flags & SER_RS485_ENABLED)) { + temp = readl(sport->port.membase + UCR2); + temp &= ~(UCR2_CTS | UCR2_CTSC); + if (mctrl & TIOCM_RTS) + temp |= UCR2_CTS | UCR2_CTSC; + writel(temp, sport->port.membase + UCR2); + } temp = readl(sport->port.membase + uts_reg(sport)) & ~UTS_LOOP; if (mctrl & TIOCM_LOOP) @@ -1156,9 +1108,6 @@ static int imx_startup(struct uart_port *port) */ temp = readl(sport->port.membase + UCR4); - if (USE_IRDA(sport)) - temp |= UCR4_IRSC; - /* set the trigger level for CTS */ temp &= ~(UCR4_CTSTL_MASK << UCR4_CTSTL_SHF); temp |= CTSTL << UCR4_CTSTL_SHF; @@ -1181,10 +1130,12 @@ static int imx_startup(struct uart_port *port) imx_uart_dma_init(sport); spin_lock_irqsave(&sport->port.lock, flags); + /* * Finally, clear and enable interrupts */ writel(USR1_RTSD, sport->port.membase + USR1); + writel(USR2_ORE, sport->port.membase + USR2); if (sport->dma_is_inited && !sport->dma_is_enabled) imx_enable_dma(sport); @@ -1192,17 +1143,8 @@ static int imx_startup(struct uart_port *port) temp = readl(sport->port.membase + UCR1); temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN; - if (USE_IRDA(sport)) { - temp |= UCR1_IREN; - temp &= ~(UCR1_RTSDEN); - } - writel(temp, sport->port.membase + UCR1); - /* Clear any pending ORE flag before enabling interrupt */ - temp = readl(sport->port.membase + USR2); - writel(temp | USR2_ORE, sport->port.membase + USR2); - temp = readl(sport->port.membase + UCR4); temp |= UCR4_OREN; writel(temp, sport->port.membase + UCR4); @@ -1219,38 +1161,12 @@ static int imx_startup(struct uart_port *port) writel(temp, sport->port.membase + UCR3); } - if (USE_IRDA(sport)) { - temp = readl(sport->port.membase + UCR4); - if (sport->irda_inv_rx) - temp |= UCR4_INVR; - else - temp &= ~(UCR4_INVR); - writel(temp | UCR4_DREN, sport->port.membase + UCR4); - - temp = readl(sport->port.membase + UCR3); - if (sport->irda_inv_tx) - temp |= UCR3_INVT; - else - temp &= ~(UCR3_INVT); - writel(temp, sport->port.membase + UCR3); - } - /* * Enable modem status interrupts */ imx_enable_ms(&sport->port); spin_unlock_irqrestore(&sport->port.lock, flags); - if (USE_IRDA(sport)) { - struct imxuart_platform_data *pdata; - pdata = dev_get_platdata(sport->port.dev); - sport->irda_inv_rx = pdata->irda_inv_rx; - sport->irda_inv_tx = pdata->irda_inv_tx; - sport->trcv_delay = pdata->transceiver_delay; - if (pdata->irda_enable) - pdata->irda_enable(1); - } - return 0; } @@ -1286,13 +1202,6 @@ static void imx_shutdown(struct uart_port *port) writel(temp, sport->port.membase + UCR2); spin_unlock_irqrestore(&sport->port.lock, flags); - if (USE_IRDA(sport)) { - struct imxuart_platform_data *pdata; - pdata = dev_get_platdata(sport->port.dev); - if (pdata->irda_enable) - pdata->irda_enable(0); - } - /* * Stop our timer. */ @@ -1305,8 +1214,6 @@ static void imx_shutdown(struct uart_port *port) spin_lock_irqsave(&sport->port.lock, flags); temp = readl(sport->port.membase + UCR1); temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN); - if (USE_IRDA(sport)) - temp &= ~(UCR1_IREN); writel(temp, sport->port.membase + UCR1); spin_unlock_irqrestore(&sport->port.lock, flags); @@ -1320,7 +1227,7 @@ static void imx_flush_buffer(struct uart_port *port) struct imx_port *sport = (struct imx_port *)port; struct scatterlist *sgl = &sport->tx_sgl[0]; unsigned long temp; - int i = 100, ubir, ubmr, ubrc, uts; + int i = 100, ubir, ubmr, uts; if (!sport->dma_chan_tx) return; @@ -1345,7 +1252,6 @@ static void imx_flush_buffer(struct uart_port *port) */ ubir = readl(sport->port.membase + UBIR); ubmr = readl(sport->port.membase + UBMR); - ubrc = readl(sport->port.membase + UBRC); uts = readl(sport->port.membase + IMX21_UTS); temp = readl(sport->port.membase + UCR2); @@ -1358,7 +1264,6 @@ static void imx_flush_buffer(struct uart_port *port) /* Restore the registers */ writel(ubir, sport->port.membase + UBIR); writel(ubmr, sport->port.membase + UBMR); - writel(ubrc, sport->port.membase + UBRC); writel(uts, sport->port.membase + IMX21_UTS); } @@ -1375,15 +1280,6 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, uint64_t tdiv64; /* - * If we don't support modem control lines, don't allow - * these to be set. - */ - if (0) { - termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR); - termios->c_cflag |= CLOCAL; - } - - /* * We only support CS7 and CS8. */ while ((termios->c_cflag & CSIZE) != CS7 && @@ -1401,11 +1297,26 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, if (termios->c_cflag & CRTSCTS) { if (sport->have_rtscts) { ucr2 &= ~UCR2_IRTS; - ucr2 |= UCR2_CTSC; + + if (port->rs485.flags & SER_RS485_ENABLED) { + /* + * RTS is mandatory for rs485 operation, so keep + * it under manual control and keep transmitter + * disabled. + */ + if (!(port->rs485.flags & + SER_RS485_RTS_AFTER_SEND)) + ucr2 |= UCR2_CTS; + } else { + ucr2 |= UCR2_CTSC; + } } else { termios->c_cflag &= ~CRTSCTS; } - } + } else if (port->rs485.flags & SER_RS485_ENABLED) + /* disable transmitter */ + if (!(port->rs485.flags & SER_RS485_RTS_AFTER_SEND)) + ucr2 |= UCR2_CTS; if (termios->c_cflag & CSTOPB) ucr2 |= UCR2_STPB; @@ -1471,24 +1382,16 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, sport->port.membase + UCR2); old_txrxen &= (UCR2_TXEN | UCR2_RXEN); - if (USE_IRDA(sport)) { - /* - * use maximum available submodule frequency to - * avoid missing short pulses due to low sampling rate - */ + /* custom-baudrate handling */ + div = sport->port.uartclk / (baud * 16); + if (baud == 38400 && quot != div) + baud = sport->port.uartclk / (quot * 16); + + div = sport->port.uartclk / (baud * 16); + if (div > 7) + div = 7; + if (!div) div = 1; - } else { - /* custom-baudrate handling */ - div = sport->port.uartclk / (baud * 16); - if (baud == 38400 && quot != div) - baud = sport->port.uartclk / (quot * 16); - - div = sport->port.uartclk / (baud * 16); - if (div > 7) - div = 7; - if (!div) - div = 1; - } rational_best_approximation(16 * div * baud, sport->port.uartclk, 1 << 16, 1 << 16, &num, &denom); @@ -1635,6 +1538,38 @@ static void imx_poll_put_char(struct uart_port *port, unsigned char c) } #endif +static int imx_rs485_config(struct uart_port *port, + struct serial_rs485 *rs485conf) +{ + struct imx_port *sport = (struct imx_port *)port; + + /* unimplemented */ + rs485conf->delay_rts_before_send = 0; + rs485conf->delay_rts_after_send = 0; + rs485conf->flags |= SER_RS485_RX_DURING_TX; + + /* RTS is required to control the transmitter */ + if (!sport->have_rtscts) + rs485conf->flags &= ~SER_RS485_ENABLED; + + if (rs485conf->flags & SER_RS485_ENABLED) { + unsigned long temp; + + /* disable transmitter */ + temp = readl(sport->port.membase + UCR2); + temp &= ~UCR2_CTSC; + if (rs485conf->flags & SER_RS485_RTS_AFTER_SEND) + temp &= ~UCR2_CTS; + else + temp |= UCR2_CTS; + writel(temp, sport->port.membase + UCR2); + } + + port->rs485 = *rs485conf; + + return 0; +} + static struct uart_ops imx_pops = { .tx_empty = imx_tx_empty, .set_mctrl = imx_set_mctrl, @@ -1927,9 +1862,6 @@ static int serial_imx_probe_dt(struct imx_port *sport, if (of_get_property(np, "fsl,uart-has-rtscts", NULL)) sport->have_rtscts = 1; - if (of_get_property(np, "fsl,irda-mode", NULL)) - sport->use_irda = 1; - if (of_get_property(np, "fsl,dte-mode", NULL)) sport->dte_mode = 1; @@ -1958,9 +1890,6 @@ static void serial_imx_probe_pdata(struct imx_port *sport, if (pdata->flags & IMXUART_HAVE_RTSCTS) sport->have_rtscts = 1; - - if (pdata->flags & IMXUART_IRDA) - sport->use_irda = 1; } static int serial_imx_probe(struct platform_device *pdev) @@ -1969,6 +1898,7 @@ static int serial_imx_probe(struct platform_device *pdev) void __iomem *base; int ret = 0; struct resource *res; + int txirq, rxirq, rtsirq; sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL); if (!sport) @@ -1985,17 +1915,21 @@ static int serial_imx_probe(struct platform_device *pdev) if (IS_ERR(base)) return PTR_ERR(base); + rxirq = platform_get_irq(pdev, 0); + txirq = platform_get_irq(pdev, 1); + rtsirq = platform_get_irq(pdev, 2); + sport->port.dev = &pdev->dev; sport->port.mapbase = res->start; sport->port.membase = base; sport->port.type = PORT_IMX, sport->port.iotype = UPIO_MEM; - sport->port.irq = platform_get_irq(pdev, 0); - sport->rxirq = platform_get_irq(pdev, 0); - sport->txirq = platform_get_irq(pdev, 1); - sport->rtsirq = platform_get_irq(pdev, 2); + sport->port.irq = rxirq; sport->port.fifosize = 32; sport->port.ops = &imx_pops; + sport->port.rs485_config = imx_rs485_config; + sport->port.rs485.flags = + SER_RS485_RTS_ON_SEND | SER_RS485_RX_DURING_TX; sport->port.flags = UPF_BOOT_AUTOCONF; init_timer(&sport->timer); sport->timer.function = imx_timeout; @@ -2021,27 +1955,18 @@ static int serial_imx_probe(struct platform_device *pdev) * Allocate the IRQ(s) i.MX1 has three interrupts whereas later * chips only have one interrupt. */ - if (sport->txirq > 0) { - ret = devm_request_irq(&pdev->dev, sport->rxirq, imx_rxint, 0, + if (txirq > 0) { + ret = devm_request_irq(&pdev->dev, rxirq, imx_rxint, 0, dev_name(&pdev->dev), sport); if (ret) return ret; - ret = devm_request_irq(&pdev->dev, sport->txirq, imx_txint, 0, + ret = devm_request_irq(&pdev->dev, txirq, imx_txint, 0, dev_name(&pdev->dev), sport); if (ret) return ret; - - /* do not use RTS IRQ on IrDA */ - if (!USE_IRDA(sport)) { - ret = devm_request_irq(&pdev->dev, sport->rtsirq, - imx_rtsint, 0, - dev_name(&pdev->dev), sport); - if (ret) - return ret; - } } else { - ret = devm_request_irq(&pdev->dev, sport->port.irq, imx_int, 0, + ret = devm_request_irq(&pdev->dev, rxirq, imx_int, 0, dev_name(&pdev->dev), sport); if (ret) return ret; diff --git a/drivers/tty/serial/jsm/jsm_cls.c b/drivers/tty/serial/jsm/jsm_cls.c index bfb0681195b6..4eb12a9cae76 100644 --- a/drivers/tty/serial/jsm/jsm_cls.c +++ b/drivers/tty/serial/jsm/jsm_cls.c @@ -570,7 +570,7 @@ static inline void cls_parse_isr(struct jsm_board *brd, uint port) * verified in the interrupt routine. */ - if (port > brd->nasync) + if (port >= brd->nasync) return; ch = brd->channels[port]; diff --git a/drivers/tty/serial/jsm/jsm_neo.c b/drivers/tty/serial/jsm/jsm_neo.c index 7291c2117daa..932b2accd06f 100644 --- a/drivers/tty/serial/jsm/jsm_neo.c +++ b/drivers/tty/serial/jsm/jsm_neo.c @@ -724,7 +724,7 @@ static inline void neo_parse_isr(struct jsm_board *brd, u32 port) if (!brd) return; - if (port > brd->maxports) + if (port >= brd->maxports) return; ch = brd->channels[port]; @@ -840,7 +840,7 @@ static inline void neo_parse_lsr(struct jsm_board *brd, u32 port) if (!brd) return; - if (port > brd->maxports) + if (port >= brd->maxports) return; ch = brd->channels[port]; @@ -1180,7 +1180,7 @@ static irqreturn_t neo_intr(int irq, void *voidbrd) */ /* Verify the port is in range. */ - if (port > brd->nasync) + if (port >= brd->nasync) continue; ch = brd->channels[port]; diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index 79f9a9eff545..077377259a2c 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -782,7 +782,7 @@ static int max3100_probe(struct spi_device *spi) pdata = dev_get_platdata(&spi->dev); max3100s[i]->crystal = pdata->crystal; max3100s[i]->loopback = pdata->loopback; - max3100s[i]->poll_time = pdata->poll_time * HZ / 1000; + max3100s[i]->poll_time = msecs_to_jiffies(pdata->poll_time); if (pdata->poll_time > 0 && max3100s[i]->poll_time == 0) max3100s[i]->poll_time = 1; max3100s[i]->max3100_hw_suspend = pdata->max3100_hw_suspend; diff --git a/drivers/tty/serial/mfd.c b/drivers/tty/serial/mfd.c deleted file mode 100644 index 8fe4501d7565..000000000000 --- a/drivers/tty/serial/mfd.c +++ /dev/null @@ -1,1505 +0,0 @@ -/* - * mfd.c: driver for High Speed UART device of Intel Medfield platform - * - * Refer pxa.c, 8250.c and some other drivers in drivers/serial/ - * - * (C) Copyright 2010 Intel Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; version 2 - * of the License. - */ - -/* Notes: - * 1. DMA channel allocation: 0/1 channel are assigned to port 0, - * 2/3 chan to port 1, 4/5 chan to port 3. Even number chans - * are used for RX, odd chans for TX - * - * 2. The RI/DSR/DCD/DTR are not pinned out, DCD & DSR are always - * asserted, only when the HW is reset the DDCD and DDSR will - * be triggered - */ - -#if defined(CONFIG_SERIAL_MFD_HSU_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/console.h> -#include <linux/sysrq.h> -#include <linux/slab.h> -#include <linux/serial_reg.h> -#include <linux/circ_buf.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/serial_core.h> -#include <linux/serial_mfd.h> -#include <linux/dma-mapping.h> -#include <linux/pci.h> -#include <linux/nmi.h> -#include <linux/io.h> -#include <linux/debugfs.h> -#include <linux/pm_runtime.h> - -#define HSU_DMA_BUF_SIZE 2048 - -#define chan_readl(chan, offset) readl(chan->reg + offset) -#define chan_writel(chan, offset, val) writel(val, chan->reg + offset) - -#define mfd_readl(obj, offset) readl(obj->reg + offset) -#define mfd_writel(obj, offset, val) writel(val, obj->reg + offset) - -static int hsu_dma_enable; -module_param(hsu_dma_enable, int, 0); -MODULE_PARM_DESC(hsu_dma_enable, - "It is a bitmap to set working mode, if bit[x] is 1, then port[x] will work in DMA mode, otherwise in PIO mode."); - -struct hsu_dma_buffer { - u8 *buf; - dma_addr_t dma_addr; - u32 dma_size; - u32 ofs; -}; - -struct hsu_dma_chan { - u32 id; - enum dma_data_direction dirt; - struct uart_hsu_port *uport; - void __iomem *reg; -}; - -struct uart_hsu_port { - struct uart_port port; - unsigned char ier; - unsigned char lcr; - unsigned char mcr; - unsigned int lsr_break_flag; - char name[12]; - int index; - struct device *dev; - - struct hsu_dma_chan *txc; - struct hsu_dma_chan *rxc; - struct hsu_dma_buffer txbuf; - struct hsu_dma_buffer rxbuf; - int use_dma; /* flag for DMA/PIO */ - int running; - int dma_tx_on; -}; - -/* Top level data structure of HSU */ -struct hsu_port { - void __iomem *reg; - unsigned long paddr; - unsigned long iolen; - u32 irq; - - struct uart_hsu_port port[3]; - struct hsu_dma_chan chans[10]; - - struct dentry *debugfs; -}; - -static inline unsigned int serial_in(struct uart_hsu_port *up, int offset) -{ - unsigned int val; - - if (offset > UART_MSR) { - offset <<= 2; - val = readl(up->port.membase + offset); - } else - val = (unsigned int)readb(up->port.membase + offset); - - return val; -} - -static inline void serial_out(struct uart_hsu_port *up, int offset, int value) -{ - if (offset > UART_MSR) { - offset <<= 2; - writel(value, up->port.membase + offset); - } else { - unsigned char val = value & 0xff; - writeb(val, up->port.membase + offset); - } -} - -#ifdef CONFIG_DEBUG_FS - -#define HSU_REGS_BUFSIZE 1024 - - -static ssize_t port_show_regs(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct uart_hsu_port *up = file->private_data; - char *buf; - u32 len = 0; - ssize_t ret; - - buf = kzalloc(HSU_REGS_BUFSIZE, GFP_KERNEL); - if (!buf) - return 0; - - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "MFD HSU port[%d] regs:\n", up->index); - - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "=================================\n"); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "IER: \t\t0x%08x\n", serial_in(up, UART_IER)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "IIR: \t\t0x%08x\n", serial_in(up, UART_IIR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "LCR: \t\t0x%08x\n", serial_in(up, UART_LCR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "MCR: \t\t0x%08x\n", serial_in(up, UART_MCR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "LSR: \t\t0x%08x\n", serial_in(up, UART_LSR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "MSR: \t\t0x%08x\n", serial_in(up, UART_MSR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "FOR: \t\t0x%08x\n", serial_in(up, UART_FOR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "PS: \t\t0x%08x\n", serial_in(up, UART_PS)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "MUL: \t\t0x%08x\n", serial_in(up, UART_MUL)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "DIV: \t\t0x%08x\n", serial_in(up, UART_DIV)); - - if (len > HSU_REGS_BUFSIZE) - len = HSU_REGS_BUFSIZE; - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); - return ret; -} - -static ssize_t dma_show_regs(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct hsu_dma_chan *chan = file->private_data; - char *buf; - u32 len = 0; - ssize_t ret; - - buf = kzalloc(HSU_REGS_BUFSIZE, GFP_KERNEL); - if (!buf) - return 0; - - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "MFD HSU DMA channel [%d] regs:\n", chan->id); - - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "=================================\n"); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "CR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_CR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "DCR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_DCR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "BSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_BSR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "MOTSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_MOTSR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D0SAR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D0TSR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D1SAR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D1TSR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D2SAR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D2TSR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D3SAR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D3TSR)); - - if (len > HSU_REGS_BUFSIZE) - len = HSU_REGS_BUFSIZE; - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); - return ret; -} - -static const struct file_operations port_regs_ops = { - .owner = THIS_MODULE, - .open = simple_open, - .read = port_show_regs, - .llseek = default_llseek, -}; - -static const struct file_operations dma_regs_ops = { - .owner = THIS_MODULE, - .open = simple_open, - .read = dma_show_regs, - .llseek = default_llseek, -}; - -static int hsu_debugfs_init(struct hsu_port *hsu) -{ - int i; - char name[32]; - - hsu->debugfs = debugfs_create_dir("hsu", NULL); - if (!hsu->debugfs) - return -ENOMEM; - - for (i = 0; i < 3; i++) { - snprintf(name, sizeof(name), "port_%d_regs", i); - debugfs_create_file(name, S_IFREG | S_IRUGO, - hsu->debugfs, (void *)(&hsu->port[i]), &port_regs_ops); - } - - for (i = 0; i < 6; i++) { - snprintf(name, sizeof(name), "dma_chan_%d_regs", i); - debugfs_create_file(name, S_IFREG | S_IRUGO, - hsu->debugfs, (void *)&hsu->chans[i], &dma_regs_ops); - } - - return 0; -} - -static void hsu_debugfs_remove(struct hsu_port *hsu) -{ - if (hsu->debugfs) - debugfs_remove_recursive(hsu->debugfs); -} - -#else -static inline int hsu_debugfs_init(struct hsu_port *hsu) -{ - return 0; -} - -static inline void hsu_debugfs_remove(struct hsu_port *hsu) -{ -} -#endif /* CONFIG_DEBUG_FS */ - -static void serial_hsu_enable_ms(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - - up->ier |= UART_IER_MSI; - serial_out(up, UART_IER, up->ier); -} - -static void hsu_dma_tx(struct uart_hsu_port *up) -{ - struct circ_buf *xmit = &up->port.state->xmit; - struct hsu_dma_buffer *dbuf = &up->txbuf; - int count; - - /* test_and_set_bit may be better, but anyway it's in lock protected mode */ - if (up->dma_tx_on) - return; - - /* Update the circ buf info */ - xmit->tail += dbuf->ofs; - xmit->tail &= UART_XMIT_SIZE - 1; - - up->port.icount.tx += dbuf->ofs; - dbuf->ofs = 0; - - /* Disable the channel */ - chan_writel(up->txc, HSU_CH_CR, 0x0); - - if (!uart_circ_empty(xmit) && !uart_tx_stopped(&up->port)) { - dma_sync_single_for_device(up->port.dev, - dbuf->dma_addr, - dbuf->dma_size, - DMA_TO_DEVICE); - - count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); - dbuf->ofs = count; - - /* Reprogram the channel */ - chan_writel(up->txc, HSU_CH_D0SAR, dbuf->dma_addr + xmit->tail); - chan_writel(up->txc, HSU_CH_D0TSR, count); - - /* Reenable the channel */ - chan_writel(up->txc, HSU_CH_DCR, 0x1 - | (0x1 << 8) - | (0x1 << 16) - | (0x1 << 24)); - up->dma_tx_on = 1; - chan_writel(up->txc, HSU_CH_CR, 0x1); - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); -} - -/* The buffer is already cache coherent */ -static void hsu_dma_start_rx_chan(struct hsu_dma_chan *rxc, - struct hsu_dma_buffer *dbuf) -{ - dbuf->ofs = 0; - - chan_writel(rxc, HSU_CH_BSR, 32); - chan_writel(rxc, HSU_CH_MOTSR, 4); - - chan_writel(rxc, HSU_CH_D0SAR, dbuf->dma_addr); - chan_writel(rxc, HSU_CH_D0TSR, dbuf->dma_size); - chan_writel(rxc, HSU_CH_DCR, 0x1 | (0x1 << 8) - | (0x1 << 16) - | (0x1 << 24) /* timeout bit, see HSU Errata 1 */ - ); - chan_writel(rxc, HSU_CH_CR, 0x3); -} - -/* Protected by spin_lock_irqsave(port->lock) */ -static void serial_hsu_start_tx(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - - if (up->use_dma) { - hsu_dma_tx(up); - } else if (!(up->ier & UART_IER_THRI)) { - up->ier |= UART_IER_THRI; - serial_out(up, UART_IER, up->ier); - } -} - -static void serial_hsu_stop_tx(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - struct hsu_dma_chan *txc = up->txc; - - if (up->use_dma) - chan_writel(txc, HSU_CH_CR, 0x0); - else if (up->ier & UART_IER_THRI) { - up->ier &= ~UART_IER_THRI; - serial_out(up, UART_IER, up->ier); - } -} - -/* This is always called in spinlock protected mode, so - * modify timeout timer is safe here */ -static void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts, - unsigned long *flags) -{ - struct hsu_dma_buffer *dbuf = &up->rxbuf; - struct hsu_dma_chan *chan = up->rxc; - struct uart_port *port = &up->port; - struct tty_port *tport = &port->state->port; - int count; - - /* - * First need to know how many is already transferred, - * then check if its a timeout DMA irq, and return - * the trail bytes out, push them up and reenable the - * channel - */ - - /* Timeout IRQ, need wait some time, see Errata 2 */ - if (int_sts & 0xf00) - udelay(2); - - /* Stop the channel */ - chan_writel(chan, HSU_CH_CR, 0x0); - - count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr; - if (!count) { - /* Restart the channel before we leave */ - chan_writel(chan, HSU_CH_CR, 0x3); - return; - } - - dma_sync_single_for_cpu(port->dev, dbuf->dma_addr, - dbuf->dma_size, DMA_FROM_DEVICE); - - /* - * Head will only wrap around when we recycle - * the DMA buffer, and when that happens, we - * explicitly set tail to 0. So head will - * always be greater than tail. - */ - tty_insert_flip_string(tport, dbuf->buf, count); - port->icount.rx += count; - - dma_sync_single_for_device(up->port.dev, dbuf->dma_addr, - dbuf->dma_size, DMA_FROM_DEVICE); - - /* Reprogram the channel */ - chan_writel(chan, HSU_CH_D0SAR, dbuf->dma_addr); - chan_writel(chan, HSU_CH_D0TSR, dbuf->dma_size); - chan_writel(chan, HSU_CH_DCR, 0x1 - | (0x1 << 8) - | (0x1 << 16) - | (0x1 << 24) /* timeout bit, see HSU Errata 1 */ - ); - spin_unlock_irqrestore(&up->port.lock, *flags); - tty_flip_buffer_push(tport); - spin_lock_irqsave(&up->port.lock, *flags); - - chan_writel(chan, HSU_CH_CR, 0x3); - -} - -static void serial_hsu_stop_rx(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - struct hsu_dma_chan *chan = up->rxc; - - if (up->use_dma) - chan_writel(chan, HSU_CH_CR, 0x2); - else { - up->ier &= ~UART_IER_RLSI; - up->port.read_status_mask &= ~UART_LSR_DR; - serial_out(up, UART_IER, up->ier); - } -} - -static inline void receive_chars(struct uart_hsu_port *up, int *status, - unsigned long *flags) -{ - unsigned int ch, flag; - unsigned int max_count = 256; - - do { - ch = serial_in(up, UART_RX); - flag = TTY_NORMAL; - up->port.icount.rx++; - - if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE | - UART_LSR_FE | UART_LSR_OE))) { - - dev_warn(up->dev, "We really rush into ERR/BI case" - "status = 0x%02x", *status); - /* For statistics only */ - if (*status & UART_LSR_BI) { - *status &= ~(UART_LSR_FE | UART_LSR_PE); - up->port.icount.brk++; - /* - * We do the SysRQ and SAK checking - * here because otherwise the break - * may get masked by ignore_status_mask - * or read_status_mask. - */ - if (uart_handle_break(&up->port)) - goto ignore_char; - } else if (*status & UART_LSR_PE) - up->port.icount.parity++; - else if (*status & UART_LSR_FE) - up->port.icount.frame++; - if (*status & UART_LSR_OE) - up->port.icount.overrun++; - - /* Mask off conditions which should be ignored. */ - *status &= up->port.read_status_mask; - -#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE - if (up->port.cons && - up->port.cons->index == up->port.line) { - /* Recover the break flag from console xmit */ - *status |= up->lsr_break_flag; - up->lsr_break_flag = 0; - } -#endif - if (*status & UART_LSR_BI) { - flag = TTY_BREAK; - } else if (*status & UART_LSR_PE) - flag = TTY_PARITY; - else if (*status & UART_LSR_FE) - flag = TTY_FRAME; - } - - if (uart_handle_sysrq_char(&up->port, ch)) - goto ignore_char; - - uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag); - ignore_char: - *status = serial_in(up, UART_LSR); - } while ((*status & UART_LSR_DR) && max_count--); - - spin_unlock_irqrestore(&up->port.lock, *flags); - tty_flip_buffer_push(&up->port.state->port); - spin_lock_irqsave(&up->port.lock, *flags); -} - -static void transmit_chars(struct uart_hsu_port *up) -{ - struct circ_buf *xmit = &up->port.state->xmit; - int count; - - if (up->port.x_char) { - serial_out(up, UART_TX, up->port.x_char); - up->port.icount.tx++; - up->port.x_char = 0; - return; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { - serial_hsu_stop_tx(&up->port); - return; - } - - /* The IRQ is for TX FIFO half-empty */ - count = up->port.fifosize / 2; - - do { - serial_out(up, UART_TX, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - - up->port.icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (--count > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); - - if (uart_circ_empty(xmit)) - serial_hsu_stop_tx(&up->port); -} - -static inline void check_modem_status(struct uart_hsu_port *up) -{ - int status; - - status = serial_in(up, UART_MSR); - - if ((status & UART_MSR_ANY_DELTA) == 0) - return; - - if (status & UART_MSR_TERI) - up->port.icount.rng++; - if (status & UART_MSR_DDSR) - up->port.icount.dsr++; - /* We may only get DDCD when HW init and reset */ - if (status & UART_MSR_DDCD) - uart_handle_dcd_change(&up->port, status & UART_MSR_DCD); - /* Will start/stop_tx accordingly */ - if (status & UART_MSR_DCTS) - uart_handle_cts_change(&up->port, status & UART_MSR_CTS); - - wake_up_interruptible(&up->port.state->port.delta_msr_wait); -} - -/* - * This handles the interrupt from one port. - */ -static irqreturn_t port_irq(int irq, void *dev_id) -{ - struct uart_hsu_port *up = dev_id; - unsigned int iir, lsr; - unsigned long flags; - - if (unlikely(!up->running)) - return IRQ_NONE; - - spin_lock_irqsave(&up->port.lock, flags); - if (up->use_dma) { - lsr = serial_in(up, UART_LSR); - if (unlikely(lsr & (UART_LSR_BI | UART_LSR_PE | - UART_LSR_FE | UART_LSR_OE))) - dev_warn(up->dev, - "Got lsr irq while using DMA, lsr = 0x%2x\n", - lsr); - check_modem_status(up); - spin_unlock_irqrestore(&up->port.lock, flags); - return IRQ_HANDLED; - } - - iir = serial_in(up, UART_IIR); - if (iir & UART_IIR_NO_INT) { - spin_unlock_irqrestore(&up->port.lock, flags); - return IRQ_NONE; - } - - lsr = serial_in(up, UART_LSR); - if (lsr & UART_LSR_DR) - receive_chars(up, &lsr, &flags); - check_modem_status(up); - - /* lsr will be renewed during the receive_chars */ - if (lsr & UART_LSR_THRE) - transmit_chars(up); - - spin_unlock_irqrestore(&up->port.lock, flags); - return IRQ_HANDLED; -} - -static inline void dma_chan_irq(struct hsu_dma_chan *chan) -{ - struct uart_hsu_port *up = chan->uport; - unsigned long flags; - u32 int_sts; - - spin_lock_irqsave(&up->port.lock, flags); - - if (!up->use_dma || !up->running) - goto exit; - - /* - * No matter what situation, need read clear the IRQ status - * There is a bug, see Errata 5, HSD 2900918 - */ - int_sts = chan_readl(chan, HSU_CH_SR); - - /* Rx channel */ - if (chan->dirt == DMA_FROM_DEVICE) - hsu_dma_rx(up, int_sts, &flags); - - /* Tx channel */ - if (chan->dirt == DMA_TO_DEVICE) { - chan_writel(chan, HSU_CH_CR, 0x0); - up->dma_tx_on = 0; - hsu_dma_tx(up); - } - -exit: - spin_unlock_irqrestore(&up->port.lock, flags); - return; -} - -static irqreturn_t dma_irq(int irq, void *dev_id) -{ - struct hsu_port *hsu = dev_id; - u32 int_sts, i; - - int_sts = mfd_readl(hsu, HSU_GBL_DMAISR); - - /* Currently we only have 6 channels may be used */ - for (i = 0; i < 6; i++) { - if (int_sts & 0x1) - dma_chan_irq(&hsu->chans[i]); - int_sts >>= 1; - } - - return IRQ_HANDLED; -} - -static unsigned int serial_hsu_tx_empty(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - unsigned long flags; - unsigned int ret; - - spin_lock_irqsave(&up->port.lock, flags); - ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0; - spin_unlock_irqrestore(&up->port.lock, flags); - - return ret; -} - -static unsigned int serial_hsu_get_mctrl(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - unsigned char status; - unsigned int ret; - - status = serial_in(up, UART_MSR); - - ret = 0; - if (status & UART_MSR_DCD) - ret |= TIOCM_CAR; - if (status & UART_MSR_RI) - ret |= TIOCM_RNG; - if (status & UART_MSR_DSR) - ret |= TIOCM_DSR; - if (status & UART_MSR_CTS) - ret |= TIOCM_CTS; - return ret; -} - -static void serial_hsu_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - unsigned char mcr = 0; - - if (mctrl & TIOCM_RTS) - mcr |= UART_MCR_RTS; - if (mctrl & TIOCM_DTR) - mcr |= UART_MCR_DTR; - if (mctrl & TIOCM_OUT1) - mcr |= UART_MCR_OUT1; - if (mctrl & TIOCM_OUT2) - mcr |= UART_MCR_OUT2; - if (mctrl & TIOCM_LOOP) - mcr |= UART_MCR_LOOP; - - mcr |= up->mcr; - - serial_out(up, UART_MCR, mcr); -} - -static void serial_hsu_break_ctl(struct uart_port *port, int break_state) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - unsigned long flags; - - spin_lock_irqsave(&up->port.lock, flags); - if (break_state == -1) - up->lcr |= UART_LCR_SBC; - else - up->lcr &= ~UART_LCR_SBC; - serial_out(up, UART_LCR, up->lcr); - spin_unlock_irqrestore(&up->port.lock, flags); -} - -/* - * What special to do: - * 1. chose the 64B fifo mode - * 2. start dma or pio depends on configuration - * 3. we only allocate dma memory when needed - */ -static int serial_hsu_startup(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - unsigned long flags; - - pm_runtime_get_sync(up->dev); - - /* - * Clear the FIFO buffers and disable them. - * (they will be reenabled in set_termios()) - */ - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); - serial_out(up, UART_FCR, 0); - - /* Clear the interrupt registers. */ - (void) serial_in(up, UART_LSR); - (void) serial_in(up, UART_RX); - (void) serial_in(up, UART_IIR); - (void) serial_in(up, UART_MSR); - - /* Now, initialize the UART, default is 8n1 */ - serial_out(up, UART_LCR, UART_LCR_WLEN8); - - spin_lock_irqsave(&up->port.lock, flags); - - up->port.mctrl |= TIOCM_OUT2; - serial_hsu_set_mctrl(&up->port, up->port.mctrl); - - /* - * Finally, enable interrupts. Note: Modem status interrupts - * are set via set_termios(), which will be occurring imminently - * anyway, so we don't enable them here. - */ - if (!up->use_dma) - up->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE; - else - up->ier = 0; - serial_out(up, UART_IER, up->ier); - - spin_unlock_irqrestore(&up->port.lock, flags); - - /* DMA init */ - if (up->use_dma) { - struct hsu_dma_buffer *dbuf; - struct circ_buf *xmit = &port->state->xmit; - - up->dma_tx_on = 0; - - /* First allocate the RX buffer */ - dbuf = &up->rxbuf; - dbuf->buf = kzalloc(HSU_DMA_BUF_SIZE, GFP_KERNEL); - if (!dbuf->buf) { - up->use_dma = 0; - goto exit; - } - dbuf->dma_addr = dma_map_single(port->dev, - dbuf->buf, - HSU_DMA_BUF_SIZE, - DMA_FROM_DEVICE); - dbuf->dma_size = HSU_DMA_BUF_SIZE; - - /* Start the RX channel right now */ - hsu_dma_start_rx_chan(up->rxc, dbuf); - - /* Next init the TX DMA */ - dbuf = &up->txbuf; - dbuf->buf = xmit->buf; - dbuf->dma_addr = dma_map_single(port->dev, - dbuf->buf, - UART_XMIT_SIZE, - DMA_TO_DEVICE); - dbuf->dma_size = UART_XMIT_SIZE; - - /* This should not be changed all around */ - chan_writel(up->txc, HSU_CH_BSR, 32); - chan_writel(up->txc, HSU_CH_MOTSR, 4); - dbuf->ofs = 0; - } - -exit: - /* And clear the interrupt registers again for luck. */ - (void) serial_in(up, UART_LSR); - (void) serial_in(up, UART_RX); - (void) serial_in(up, UART_IIR); - (void) serial_in(up, UART_MSR); - - up->running = 1; - return 0; -} - -static void serial_hsu_shutdown(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - unsigned long flags; - - /* Disable interrupts from this port */ - up->ier = 0; - serial_out(up, UART_IER, 0); - up->running = 0; - - spin_lock_irqsave(&up->port.lock, flags); - up->port.mctrl &= ~TIOCM_OUT2; - serial_hsu_set_mctrl(&up->port, up->port.mctrl); - spin_unlock_irqrestore(&up->port.lock, flags); - - /* Disable break condition and FIFOs */ - serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC); - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | - UART_FCR_CLEAR_XMIT); - serial_out(up, UART_FCR, 0); - - pm_runtime_put(up->dev); -} - -static void -serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - unsigned char cval, fcr = 0; - unsigned long flags; - unsigned int baud, quot; - u32 ps, mul; - - switch (termios->c_cflag & CSIZE) { - case CS5: - cval = UART_LCR_WLEN5; - break; - case CS6: - cval = UART_LCR_WLEN6; - break; - case CS7: - cval = UART_LCR_WLEN7; - break; - default: - case CS8: - cval = UART_LCR_WLEN8; - break; - } - - /* CMSPAR isn't supported by this driver */ - termios->c_cflag &= ~CMSPAR; - - if (termios->c_cflag & CSTOPB) - cval |= UART_LCR_STOP; - if (termios->c_cflag & PARENB) - cval |= UART_LCR_PARITY; - if (!(termios->c_cflag & PARODD)) - cval |= UART_LCR_EPAR; - - /* - * The base clk is 50Mhz, and the baud rate come from: - * baud = 50M * MUL / (DIV * PS * DLAB) - * - * For those basic low baud rate we can get the direct - * scalar from 2746800, like 115200 = 2746800/24. For those - * higher baud rate, we handle them case by case, mainly by - * adjusting the MUL/PS registers, and DIV register is kept - * as default value 0x3d09 to make things simple - */ - baud = uart_get_baud_rate(port, termios, old, 0, 4000000); - - quot = 1; - ps = 0x10; - mul = 0x3600; - switch (baud) { - case 3500000: - mul = 0x3345; - ps = 0xC; - break; - case 1843200: - mul = 0x2400; - break; - case 3000000: - case 2500000: - case 2000000: - case 1500000: - case 1000000: - case 500000: - /* mul/ps/quot = 0x9C4/0x10/0x1 will make a 500000 bps */ - mul = baud / 500000 * 0x9C4; - break; - default: - /* Use uart_get_divisor to get quot for other baud rates */ - quot = 0; - } - - if (!quot) - quot = uart_get_divisor(port, baud); - - if ((up->port.uartclk / quot) < (2400 * 16)) - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_1B; - else if ((up->port.uartclk / quot) < (230400 * 16)) - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_16B; - else - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_32B; - - fcr |= UART_FCR_HSU_64B_FIFO; - - /* - * Ok, we're now changing the port state. Do it with - * interrupts disabled. - */ - spin_lock_irqsave(&up->port.lock, flags); - - /* Update the per-port timeout */ - uart_update_timeout(port, termios->c_cflag, baud); - - up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; - if (termios->c_iflag & INPCK) - up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) - up->port.read_status_mask |= UART_LSR_BI; - - /* Characters to ignore */ - up->port.ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; - if (termios->c_iflag & IGNBRK) { - up->port.ignore_status_mask |= UART_LSR_BI; - /* - * If we're ignoring parity and break indicators, - * ignore overruns too (for real raw support). - */ - if (termios->c_iflag & IGNPAR) - up->port.ignore_status_mask |= UART_LSR_OE; - } - - /* Ignore all characters if CREAD is not set */ - if ((termios->c_cflag & CREAD) == 0) - up->port.ignore_status_mask |= UART_LSR_DR; - - /* - * CTS flow control flag and modem status interrupts, disable - * MSI by default - */ - up->ier &= ~UART_IER_MSI; - if (UART_ENABLE_MS(&up->port, termios->c_cflag)) - up->ier |= UART_IER_MSI; - - serial_out(up, UART_IER, up->ier); - - if (termios->c_cflag & CRTSCTS) - up->mcr |= UART_MCR_AFE | UART_MCR_RTS; - else - up->mcr &= ~UART_MCR_AFE; - - serial_out(up, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */ - serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */ - serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */ - serial_out(up, UART_LCR, cval); /* reset DLAB */ - serial_out(up, UART_MUL, mul); /* set MUL */ - serial_out(up, UART_PS, ps); /* set PS */ - up->lcr = cval; /* Save LCR */ - serial_hsu_set_mctrl(&up->port, up->port.mctrl); - serial_out(up, UART_FCR, fcr); - spin_unlock_irqrestore(&up->port.lock, flags); -} - -static void -serial_hsu_pm(struct uart_port *port, unsigned int state, - unsigned int oldstate) -{ -} - -static void serial_hsu_release_port(struct uart_port *port) -{ -} - -static int serial_hsu_request_port(struct uart_port *port) -{ - return 0; -} - -static void serial_hsu_config_port(struct uart_port *port, int flags) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - up->port.type = PORT_MFD; -} - -static int -serial_hsu_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - /* We don't want the core code to modify any port params */ - return -EINVAL; -} - -static const char * -serial_hsu_type(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - return up->name; -} - -/* Mainly for uart console use */ -static struct uart_hsu_port *serial_hsu_ports[3]; -static struct uart_driver serial_hsu_reg; - -#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE - -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - -/* Wait for transmitter & holding register to empty */ -static inline void wait_for_xmitr(struct uart_hsu_port *up) -{ - unsigned int status, tmout = 1000; - - /* Wait up to 1ms for the character to be sent. */ - do { - status = serial_in(up, UART_LSR); - - if (status & UART_LSR_BI) - up->lsr_break_flag = UART_LSR_BI; - - if (--tmout == 0) - break; - udelay(1); - } while (!(status & BOTH_EMPTY)); - - /* Wait up to 1s for flow control if necessary */ - if (up->port.flags & UPF_CONS_FLOW) { - tmout = 1000000; - while (--tmout && - ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0)) - udelay(1); - } -} - -static void serial_hsu_console_putchar(struct uart_port *port, int ch) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - - wait_for_xmitr(up); - serial_out(up, UART_TX, ch); -} - -/* - * Print a string to the serial port trying not to disturb - * any possible real use of the port... - * - * The console_lock must be held when we get here. - */ -static void -serial_hsu_console_write(struct console *co, const char *s, unsigned int count) -{ - struct uart_hsu_port *up = serial_hsu_ports[co->index]; - unsigned long flags; - unsigned int ier; - int locked = 1; - - touch_nmi_watchdog(); - - local_irq_save(flags); - if (up->port.sysrq) - locked = 0; - else if (oops_in_progress) { - locked = spin_trylock(&up->port.lock); - } else - spin_lock(&up->port.lock); - - /* First save the IER then disable the interrupts */ - ier = serial_in(up, UART_IER); - serial_out(up, UART_IER, 0); - - uart_console_write(&up->port, s, count, serial_hsu_console_putchar); - - /* - * Finally, wait for transmitter to become empty - * and restore the IER - */ - wait_for_xmitr(up); - serial_out(up, UART_IER, ier); - - if (locked) - spin_unlock(&up->port.lock); - local_irq_restore(flags); -} - -static struct console serial_hsu_console; - -static int __init -serial_hsu_console_setup(struct console *co, char *options) -{ - struct uart_hsu_port *up; - int baud = 115200; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - if (co->index == -1 || co->index >= serial_hsu_reg.nr) - co->index = 0; - up = serial_hsu_ports[co->index]; - if (!up) - return -ENODEV; - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - - return uart_set_options(&up->port, co, baud, parity, bits, flow); -} - -static struct console serial_hsu_console = { - .name = "ttyMFD", - .write = serial_hsu_console_write, - .device = uart_console_device, - .setup = serial_hsu_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &serial_hsu_reg, -}; - -#define SERIAL_HSU_CONSOLE (&serial_hsu_console) -#else -#define SERIAL_HSU_CONSOLE NULL -#endif - -static struct uart_ops serial_hsu_pops = { - .tx_empty = serial_hsu_tx_empty, - .set_mctrl = serial_hsu_set_mctrl, - .get_mctrl = serial_hsu_get_mctrl, - .stop_tx = serial_hsu_stop_tx, - .start_tx = serial_hsu_start_tx, - .stop_rx = serial_hsu_stop_rx, - .enable_ms = serial_hsu_enable_ms, - .break_ctl = serial_hsu_break_ctl, - .startup = serial_hsu_startup, - .shutdown = serial_hsu_shutdown, - .set_termios = serial_hsu_set_termios, - .pm = serial_hsu_pm, - .type = serial_hsu_type, - .release_port = serial_hsu_release_port, - .request_port = serial_hsu_request_port, - .config_port = serial_hsu_config_port, - .verify_port = serial_hsu_verify_port, -}; - -static struct uart_driver serial_hsu_reg = { - .owner = THIS_MODULE, - .driver_name = "MFD serial", - .dev_name = "ttyMFD", - .major = TTY_MAJOR, - .minor = 128, - .nr = 3, - .cons = SERIAL_HSU_CONSOLE, -}; - -#ifdef CONFIG_PM -static int serial_hsu_suspend(struct pci_dev *pdev, pm_message_t state) -{ - void *priv = pci_get_drvdata(pdev); - struct uart_hsu_port *up; - - /* Make sure this is not the internal dma controller */ - if (priv && (pdev->device != 0x081E)) { - up = priv; - uart_suspend_port(&serial_hsu_reg, &up->port); - } - - pci_save_state(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - return 0; -} - -static int serial_hsu_resume(struct pci_dev *pdev) -{ - void *priv = pci_get_drvdata(pdev); - struct uart_hsu_port *up; - int ret; - - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - - ret = pci_enable_device(pdev); - if (ret) - dev_warn(&pdev->dev, - "HSU: can't re-enable device, try to continue\n"); - - if (priv && (pdev->device != 0x081E)) { - up = priv; - uart_resume_port(&serial_hsu_reg, &up->port); - } - return 0; -} - -static int serial_hsu_runtime_idle(struct device *dev) -{ - pm_schedule_suspend(dev, 500); - return -EBUSY; -} - -static int serial_hsu_runtime_suspend(struct device *dev) -{ - return 0; -} - -static int serial_hsu_runtime_resume(struct device *dev) -{ - return 0; -} -#else -#define serial_hsu_suspend NULL -#define serial_hsu_resume NULL -#define serial_hsu_runtime_idle NULL -#define serial_hsu_runtime_suspend NULL -#define serial_hsu_runtime_resume NULL -#endif - -static const struct dev_pm_ops serial_hsu_pm_ops = { - .runtime_suspend = serial_hsu_runtime_suspend, - .runtime_resume = serial_hsu_runtime_resume, - .runtime_idle = serial_hsu_runtime_idle, -}; - -/* temp global pointer before we settle down on using one or four PCI dev */ -static struct hsu_port *phsu; - -static int serial_hsu_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct uart_hsu_port *uport; - int index, ret; - - printk(KERN_INFO "HSU: found PCI Serial controller(ID: %04x:%04x)\n", - pdev->vendor, pdev->device); - - switch (pdev->device) { - case 0x081B: - index = 0; - break; - case 0x081C: - index = 1; - break; - case 0x081D: - index = 2; - break; - case 0x081E: - /* internal DMA controller */ - index = 3; - break; - default: - dev_err(&pdev->dev, "HSU: out of index!"); - return -ENODEV; - } - - ret = pci_enable_device(pdev); - if (ret) - return ret; - - if (index == 3) { - /* DMA controller */ - ret = request_irq(pdev->irq, dma_irq, 0, "hsu_dma", phsu); - if (ret) { - dev_err(&pdev->dev, "can not get IRQ\n"); - goto err_disable; - } - pci_set_drvdata(pdev, phsu); - } else { - /* UART port 0~2 */ - uport = &phsu->port[index]; - uport->port.irq = pdev->irq; - uport->port.dev = &pdev->dev; - uport->dev = &pdev->dev; - - ret = request_irq(pdev->irq, port_irq, 0, uport->name, uport); - if (ret) { - dev_err(&pdev->dev, "can not get IRQ\n"); - goto err_disable; - } - uart_add_one_port(&serial_hsu_reg, &uport->port); - - pci_set_drvdata(pdev, uport); - } - - pm_runtime_put_noidle(&pdev->dev); - pm_runtime_allow(&pdev->dev); - - return 0; - -err_disable: - pci_disable_device(pdev); - return ret; -} - -static void hsu_global_init(void) -{ - struct hsu_port *hsu; - struct uart_hsu_port *uport; - struct hsu_dma_chan *dchan; - int i, ret; - - hsu = kzalloc(sizeof(struct hsu_port), GFP_KERNEL); - if (!hsu) - return; - - /* Get basic io resource and map it */ - hsu->paddr = 0xffa28000; - hsu->iolen = 0x1000; - - if (!(request_mem_region(hsu->paddr, hsu->iolen, "HSU global"))) - pr_warn("HSU: error in request mem region\n"); - - hsu->reg = ioremap_nocache((unsigned long)hsu->paddr, hsu->iolen); - if (!hsu->reg) { - pr_err("HSU: error in ioremap\n"); - ret = -ENOMEM; - goto err_free_region; - } - - /* Initialise the 3 UART ports */ - uport = hsu->port; - for (i = 0; i < 3; i++) { - uport->port.type = PORT_MFD; - uport->port.iotype = UPIO_MEM; - uport->port.mapbase = (resource_size_t)hsu->paddr - + HSU_PORT_REG_OFFSET - + i * HSU_PORT_REG_LENGTH; - uport->port.membase = hsu->reg + HSU_PORT_REG_OFFSET - + i * HSU_PORT_REG_LENGTH; - - sprintf(uport->name, "hsu_port%d", i); - uport->port.fifosize = 64; - uport->port.ops = &serial_hsu_pops; - uport->port.line = i; - uport->port.flags = UPF_IOREMAP; - /* set the scalable maxim support rate to 2746800 bps */ - uport->port.uartclk = 115200 * 24 * 16; - - uport->running = 0; - uport->txc = &hsu->chans[i * 2]; - uport->rxc = &hsu->chans[i * 2 + 1]; - - serial_hsu_ports[i] = uport; - uport->index = i; - - if (hsu_dma_enable & (1<<i)) - uport->use_dma = 1; - else - uport->use_dma = 0; - - uport++; - } - - /* Initialise 6 dma channels */ - dchan = hsu->chans; - for (i = 0; i < 6; i++) { - dchan->id = i; - dchan->dirt = (i & 0x1) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; - dchan->uport = &hsu->port[i/2]; - dchan->reg = hsu->reg + HSU_DMA_CHANS_REG_OFFSET + - i * HSU_DMA_CHANS_REG_LENGTH; - - dchan++; - } - - phsu = hsu; - hsu_debugfs_init(hsu); - return; - -err_free_region: - release_mem_region(hsu->paddr, hsu->iolen); - kfree(hsu); - return; -} - -static void serial_hsu_remove(struct pci_dev *pdev) -{ - void *priv = pci_get_drvdata(pdev); - struct uart_hsu_port *up; - - if (!priv) - return; - - pm_runtime_forbid(&pdev->dev); - pm_runtime_get_noresume(&pdev->dev); - - /* For port 0/1/2, priv is the address of uart_hsu_port */ - if (pdev->device != 0x081E) { - up = priv; - uart_remove_one_port(&serial_hsu_reg, &up->port); - } - - free_irq(pdev->irq, priv); - pci_disable_device(pdev); -} - -/* First 3 are UART ports, and the 4th is the DMA */ -static const struct pci_device_id pci_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081B) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081C) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081D) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081E) }, - {}, -}; - -static struct pci_driver hsu_pci_driver = { - .name = "HSU serial", - .id_table = pci_ids, - .probe = serial_hsu_probe, - .remove = serial_hsu_remove, - .suspend = serial_hsu_suspend, - .resume = serial_hsu_resume, - .driver = { - .pm = &serial_hsu_pm_ops, - }, -}; - -static int __init hsu_pci_init(void) -{ - int ret; - - hsu_global_init(); - - ret = uart_register_driver(&serial_hsu_reg); - if (ret) - return ret; - - return pci_register_driver(&hsu_pci_driver); -} - -static void __exit hsu_pci_exit(void) -{ - pci_unregister_driver(&hsu_pci_driver); - uart_unregister_driver(&serial_hsu_reg); - - hsu_debugfs_remove(phsu); - - kfree(phsu); -} - -module_init(hsu_pci_init); -module_exit(hsu_pci_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_DEVICE_TABLE(pci, pci_ids); diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c index 3308ef243dc3..1589f17c1fca 100644 --- a/drivers/tty/serial/mpc52xx_uart.c +++ b/drivers/tty/serial/mpc52xx_uart.c @@ -1717,7 +1717,7 @@ static struct uart_driver mpc52xx_uart_driver = { /* OF Platform Driver */ /* ======================================================================== */ -static struct of_device_id mpc52xx_uart_of_match[] = { +static const struct of_device_id mpc52xx_uart_of_match[] = { #ifdef CONFIG_PPC_MPC52xx { .compatible = "fsl,mpc5200b-psc-uart", .data = &mpc5200b_psc_ops, }, { .compatible = "fsl,mpc5200-psc-uart", .data = &mpc52xx_psc_ops, }, diff --git a/drivers/tty/serial/msm_serial.h b/drivers/tty/serial/msm_serial.h index 3e1c7138d8cd..737f69fe7113 100644 --- a/drivers/tty/serial/msm_serial.h +++ b/drivers/tty/serial/msm_serial.h @@ -170,15 +170,6 @@ void msm_serial_set_mnd_regs_from_uartclk(struct uart_port *port) msm_serial_set_mnd_regs_tcxoby4(port); } -/* - * TROUT has a specific defect that makes it report it's uartclk - * as 19.2Mhz (TCXO) when it's actually 4.8Mhz (TCXO/4). This special - * cases TROUT to use the right clock. - */ -#ifdef CONFIG_MACH_TROUT -#define msm_serial_set_mnd_regs msm_serial_set_mnd_regs_tcxoby4 -#else #define msm_serial_set_mnd_regs msm_serial_set_mnd_regs_from_uartclk -#endif #endif /* __DRIVERS_SERIAL_MSM_SERIAL_H */ diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c deleted file mode 100644 index 62da8534ba75..000000000000 --- a/drivers/tty/serial/msm_serial_hs.c +++ /dev/null @@ -1,1874 +0,0 @@ -/* - * MSM 7k/8k High speed uart driver - * - * Copyright (c) 2007-2011, Code Aurora Forum. All rights reserved. - * Copyright (c) 2008 Google Inc. - * Modified: Nick Pelly <npelly@google.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * Has optional support for uart power management independent of linux - * suspend/resume: - * - * RX wakeup. - * UART wakeup can be triggered by RX activity (using a wakeup GPIO on the - * UART RX pin). This should only be used if there is not a wakeup - * GPIO on the UART CTS, and the first RX byte is known (for example, with the - * Bluetooth Texas Instruments HCILL protocol), since the first RX byte will - * always be lost. RTS will be asserted even while the UART is off in this mode - * of operation. See msm_serial_hs_platform_data.rx_wakeup_irq. - */ - -#include <linux/module.h> - -#include <linux/serial.h> -#include <linux/serial_core.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/io.h> -#include <linux/ioport.h> -#include <linux/kernel.h> -#include <linux/timer.h> -#include <linux/clk.h> -#include <linux/platform_device.h> -#include <linux/pm_runtime.h> -#include <linux/dma-mapping.h> -#include <linux/dmapool.h> -#include <linux/wait.h> -#include <linux/workqueue.h> - -#include <linux/atomic.h> -#include <asm/irq.h> - -#include <mach/hardware.h> -#include <mach/dma.h> -#include <linux/platform_data/msm_serial_hs.h> - -/* HSUART Registers */ -#define UARTDM_MR1_ADDR 0x0 -#define UARTDM_MR2_ADDR 0x4 - -/* Data Mover result codes */ -#define RSLT_FIFO_CNTR_BMSK (0xE << 28) -#define RSLT_VLD BIT(1) - -/* write only register */ -#define UARTDM_CSR_ADDR 0x8 -#define UARTDM_CSR_115200 0xFF -#define UARTDM_CSR_57600 0xEE -#define UARTDM_CSR_38400 0xDD -#define UARTDM_CSR_28800 0xCC -#define UARTDM_CSR_19200 0xBB -#define UARTDM_CSR_14400 0xAA -#define UARTDM_CSR_9600 0x99 -#define UARTDM_CSR_7200 0x88 -#define UARTDM_CSR_4800 0x77 -#define UARTDM_CSR_3600 0x66 -#define UARTDM_CSR_2400 0x55 -#define UARTDM_CSR_1200 0x44 -#define UARTDM_CSR_600 0x33 -#define UARTDM_CSR_300 0x22 -#define UARTDM_CSR_150 0x11 -#define UARTDM_CSR_75 0x00 - -/* write only register */ -#define UARTDM_TF_ADDR 0x70 -#define UARTDM_TF2_ADDR 0x74 -#define UARTDM_TF3_ADDR 0x78 -#define UARTDM_TF4_ADDR 0x7C - -/* write only register */ -#define UARTDM_CR_ADDR 0x10 -#define UARTDM_IMR_ADDR 0x14 - -#define UARTDM_IPR_ADDR 0x18 -#define UARTDM_TFWR_ADDR 0x1c -#define UARTDM_RFWR_ADDR 0x20 -#define UARTDM_HCR_ADDR 0x24 -#define UARTDM_DMRX_ADDR 0x34 -#define UARTDM_IRDA_ADDR 0x38 -#define UARTDM_DMEN_ADDR 0x3c - -/* UART_DM_NO_CHARS_FOR_TX */ -#define UARTDM_NCF_TX_ADDR 0x40 - -#define UARTDM_BADR_ADDR 0x44 - -#define UARTDM_SIM_CFG_ADDR 0x80 -/* Read Only register */ -#define UARTDM_SR_ADDR 0x8 - -/* Read Only register */ -#define UARTDM_RF_ADDR 0x70 -#define UARTDM_RF2_ADDR 0x74 -#define UARTDM_RF3_ADDR 0x78 -#define UARTDM_RF4_ADDR 0x7C - -/* Read Only register */ -#define UARTDM_MISR_ADDR 0x10 - -/* Read Only register */ -#define UARTDM_ISR_ADDR 0x14 -#define UARTDM_RX_TOTAL_SNAP_ADDR 0x38 - -#define UARTDM_RXFS_ADDR 0x50 - -/* Register field Mask Mapping */ -#define UARTDM_SR_PAR_FRAME_BMSK BIT(5) -#define UARTDM_SR_OVERRUN_BMSK BIT(4) -#define UARTDM_SR_TXEMT_BMSK BIT(3) -#define UARTDM_SR_TXRDY_BMSK BIT(2) -#define UARTDM_SR_RXRDY_BMSK BIT(0) - -#define UARTDM_CR_TX_DISABLE_BMSK BIT(3) -#define UARTDM_CR_RX_DISABLE_BMSK BIT(1) -#define UARTDM_CR_TX_EN_BMSK BIT(2) -#define UARTDM_CR_RX_EN_BMSK BIT(0) - -/* UARTDM_CR channel_comman bit value (register field is bits 8:4) */ -#define RESET_RX 0x10 -#define RESET_TX 0x20 -#define RESET_ERROR_STATUS 0x30 -#define RESET_BREAK_INT 0x40 -#define START_BREAK 0x50 -#define STOP_BREAK 0x60 -#define RESET_CTS 0x70 -#define RESET_STALE_INT 0x80 -#define RFR_LOW 0xD0 -#define RFR_HIGH 0xE0 -#define CR_PROTECTION_EN 0x100 -#define STALE_EVENT_ENABLE 0x500 -#define STALE_EVENT_DISABLE 0x600 -#define FORCE_STALE_EVENT 0x400 -#define CLEAR_TX_READY 0x300 -#define RESET_TX_ERROR 0x800 -#define RESET_TX_DONE 0x810 - -#define UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK 0xffffff00 -#define UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK 0x3f -#define UARTDM_MR1_CTS_CTL_BMSK 0x40 -#define UARTDM_MR1_RX_RDY_CTL_BMSK 0x80 - -#define UARTDM_MR2_ERROR_MODE_BMSK 0x40 -#define UARTDM_MR2_BITS_PER_CHAR_BMSK 0x30 - -/* bits per character configuration */ -#define FIVE_BPC (0 << 4) -#define SIX_BPC (1 << 4) -#define SEVEN_BPC (2 << 4) -#define EIGHT_BPC (3 << 4) - -#define UARTDM_MR2_STOP_BIT_LEN_BMSK 0xc -#define STOP_BIT_ONE (1 << 2) -#define STOP_BIT_TWO (3 << 2) - -#define UARTDM_MR2_PARITY_MODE_BMSK 0x3 - -/* Parity configuration */ -#define NO_PARITY 0x0 -#define EVEN_PARITY 0x1 -#define ODD_PARITY 0x2 -#define SPACE_PARITY 0x3 - -#define UARTDM_IPR_STALE_TIMEOUT_MSB_BMSK 0xffffff80 -#define UARTDM_IPR_STALE_LSB_BMSK 0x1f - -/* These can be used for both ISR and IMR register */ -#define UARTDM_ISR_TX_READY_BMSK BIT(7) -#define UARTDM_ISR_CURRENT_CTS_BMSK BIT(6) -#define UARTDM_ISR_DELTA_CTS_BMSK BIT(5) -#define UARTDM_ISR_RXLEV_BMSK BIT(4) -#define UARTDM_ISR_RXSTALE_BMSK BIT(3) -#define UARTDM_ISR_RXBREAK_BMSK BIT(2) -#define UARTDM_ISR_RXHUNT_BMSK BIT(1) -#define UARTDM_ISR_TXLEV_BMSK BIT(0) - -/* Field definitions for UART_DM_DMEN*/ -#define UARTDM_TX_DM_EN_BMSK 0x1 -#define UARTDM_RX_DM_EN_BMSK 0x2 - -#define UART_FIFOSIZE 64 -#define UARTCLK 7372800 - -/* Rx DMA request states */ -enum flush_reason { - FLUSH_NONE, - FLUSH_DATA_READY, - FLUSH_DATA_INVALID, /* values after this indicate invalid data */ - FLUSH_IGNORE = FLUSH_DATA_INVALID, - FLUSH_STOP, - FLUSH_SHUTDOWN, -}; - -/* UART clock states */ -enum msm_hs_clk_states_e { - MSM_HS_CLK_PORT_OFF, /* port not in use */ - MSM_HS_CLK_OFF, /* clock disabled */ - MSM_HS_CLK_REQUEST_OFF, /* disable after TX and RX flushed */ - MSM_HS_CLK_ON, /* clock enabled */ -}; - -/* Track the forced RXSTALE flush during clock off sequence. - * These states are only valid during MSM_HS_CLK_REQUEST_OFF */ -enum msm_hs_clk_req_off_state_e { - CLK_REQ_OFF_START, - CLK_REQ_OFF_RXSTALE_ISSUED, - CLK_REQ_OFF_FLUSH_ISSUED, - CLK_REQ_OFF_RXSTALE_FLUSHED, -}; - -/** - * struct msm_hs_tx - * @tx_ready_int_en: ok to dma more tx? - * @dma_in_flight: tx dma in progress - * @xfer: top level DMA command pointer structure - * @command_ptr: third level command struct pointer - * @command_ptr_ptr: second level command list struct pointer - * @mapped_cmd_ptr: DMA view of third level command struct - * @mapped_cmd_ptr_ptr: DMA view of second level command list struct - * @tx_count: number of bytes to transfer in DMA transfer - * @dma_base: DMA view of UART xmit buffer - * - * This structure describes a single Tx DMA transaction. MSM DMA - * commands have two levels of indirection. The top level command - * ptr points to a list of command ptr which in turn points to a - * single DMA 'command'. In our case each Tx transaction consists - * of a single second level pointer pointing to a 'box type' command. - */ -struct msm_hs_tx { - unsigned int tx_ready_int_en; - unsigned int dma_in_flight; - struct msm_dmov_cmd xfer; - dmov_box *command_ptr; - u32 *command_ptr_ptr; - dma_addr_t mapped_cmd_ptr; - dma_addr_t mapped_cmd_ptr_ptr; - int tx_count; - dma_addr_t dma_base; -}; - -/** - * struct msm_hs_rx - * @flush: Rx DMA request state - * @xfer: top level DMA command pointer structure - * @cmdptr_dmaaddr: DMA view of second level command structure - * @command_ptr: third level DMA command pointer structure - * @command_ptr_ptr: second level DMA command list pointer - * @mapped_cmd_ptr: DMA view of the third level command structure - * @wait: wait for DMA completion before shutdown - * @buffer: destination buffer for RX DMA - * @rbuffer: DMA view of buffer - * @pool: dma pool out of which coherent rx buffer is allocated - * @tty_work: private work-queue for tty flip buffer push task - * - * This structure describes a single Rx DMA transaction. Rx DMA - * transactions use box mode DMA commands. - */ -struct msm_hs_rx { - enum flush_reason flush; - struct msm_dmov_cmd xfer; - dma_addr_t cmdptr_dmaaddr; - dmov_box *command_ptr; - u32 *command_ptr_ptr; - dma_addr_t mapped_cmd_ptr; - wait_queue_head_t wait; - dma_addr_t rbuffer; - unsigned char *buffer; - struct dma_pool *pool; - struct work_struct tty_work; -}; - -/** - * struct msm_hs_rx_wakeup - * @irq: IRQ line to be configured as interrupt source on Rx activity - * @ignore: boolean value. 1 = ignore the wakeup interrupt - * @rx_to_inject: extra character to be inserted to Rx tty on wakeup - * @inject_rx: 1 = insert rx_to_inject. 0 = do not insert extra character - * - * This is an optional structure required for UART Rx GPIO IRQ based - * wakeup from low power state. UART wakeup can be triggered by RX activity - * (using a wakeup GPIO on the UART RX pin). This should only be used if - * there is not a wakeup GPIO on the UART CTS, and the first RX byte is - * known (eg., with the Bluetooth Texas Instruments HCILL protocol), - * since the first RX byte will always be lost. RTS will be asserted even - * while the UART is clocked off in this mode of operation. - */ -struct msm_hs_rx_wakeup { - int irq; /* < 0 indicates low power wakeup disabled */ - unsigned char ignore; - unsigned char inject_rx; - char rx_to_inject; -}; - -/** - * struct msm_hs_port - * @uport: embedded uart port structure - * @imr_reg: shadow value of UARTDM_IMR - * @clk: uart input clock handle - * @tx: Tx transaction related data structure - * @rx: Rx transaction related data structure - * @dma_tx_channel: Tx DMA command channel - * @dma_rx_channel Rx DMA command channel - * @dma_tx_crci: Tx channel rate control interface number - * @dma_rx_crci: Rx channel rate control interface number - * @clk_off_timer: Timer to poll DMA event completion before clock off - * @clk_off_delay: clk_off_timer poll interval - * @clk_state: overall clock state - * @clk_req_off_state: post flush clock states - * @rx_wakeup: optional rx_wakeup feature related data - * @exit_lpm_cb: optional callback to exit low power mode - * - * Low level serial port structure. - */ -struct msm_hs_port { - struct uart_port uport; - unsigned long imr_reg; - struct clk *clk; - struct msm_hs_tx tx; - struct msm_hs_rx rx; - - int dma_tx_channel; - int dma_rx_channel; - int dma_tx_crci; - int dma_rx_crci; - - struct hrtimer clk_off_timer; - ktime_t clk_off_delay; - enum msm_hs_clk_states_e clk_state; - enum msm_hs_clk_req_off_state_e clk_req_off_state; - - struct msm_hs_rx_wakeup rx_wakeup; - void (*exit_lpm_cb)(struct uart_port *); -}; - -#define MSM_UARTDM_BURST_SIZE 16 /* DM burst size (in bytes) */ -#define UARTDM_TX_BUF_SIZE UART_XMIT_SIZE -#define UARTDM_RX_BUF_SIZE 512 - -#define UARTDM_NR 2 - -static struct msm_hs_port q_uart_port[UARTDM_NR]; -static struct platform_driver msm_serial_hs_platform_driver; -static struct uart_driver msm_hs_driver; -static struct uart_ops msm_hs_ops; -static struct workqueue_struct *msm_hs_workqueue; - -#define UARTDM_TO_MSM(uart_port) \ - container_of((uart_port), struct msm_hs_port, uport) - -static unsigned int use_low_power_rx_wakeup(struct msm_hs_port - *msm_uport) -{ - return (msm_uport->rx_wakeup.irq >= 0); -} - -static unsigned int msm_hs_read(struct uart_port *uport, - unsigned int offset) -{ - return ioread32(uport->membase + offset); -} - -static void msm_hs_write(struct uart_port *uport, unsigned int offset, - unsigned int value) -{ - iowrite32(value, uport->membase + offset); -} - -static void msm_hs_release_port(struct uart_port *port) -{ - iounmap(port->membase); -} - -static int msm_hs_request_port(struct uart_port *port) -{ - port->membase = ioremap(port->mapbase, PAGE_SIZE); - if (unlikely(!port->membase)) - return -ENOMEM; - - /* configure the CR Protection to Enable */ - msm_hs_write(port, UARTDM_CR_ADDR, CR_PROTECTION_EN); - return 0; -} - -static int msm_hs_remove(struct platform_device *pdev) -{ - - struct msm_hs_port *msm_uport; - struct device *dev; - - if (pdev->id < 0 || pdev->id >= UARTDM_NR) { - printk(KERN_ERR "Invalid plaform device ID = %d\n", pdev->id); - return -EINVAL; - } - - msm_uport = &q_uart_port[pdev->id]; - dev = msm_uport->uport.dev; - - dma_unmap_single(dev, msm_uport->rx.mapped_cmd_ptr, sizeof(dmov_box), - DMA_TO_DEVICE); - dma_pool_free(msm_uport->rx.pool, msm_uport->rx.buffer, - msm_uport->rx.rbuffer); - dma_pool_destroy(msm_uport->rx.pool); - - dma_unmap_single(dev, msm_uport->rx.cmdptr_dmaaddr, sizeof(u32), - DMA_TO_DEVICE); - dma_unmap_single(dev, msm_uport->tx.mapped_cmd_ptr_ptr, sizeof(u32), - DMA_TO_DEVICE); - dma_unmap_single(dev, msm_uport->tx.mapped_cmd_ptr, sizeof(dmov_box), - DMA_TO_DEVICE); - - uart_remove_one_port(&msm_hs_driver, &msm_uport->uport); - clk_put(msm_uport->clk); - - /* Free the tx resources */ - kfree(msm_uport->tx.command_ptr); - kfree(msm_uport->tx.command_ptr_ptr); - - /* Free the rx resources */ - kfree(msm_uport->rx.command_ptr); - kfree(msm_uport->rx.command_ptr_ptr); - - iounmap(msm_uport->uport.membase); - - return 0; -} - -static int msm_hs_init_clk_locked(struct uart_port *uport) -{ - int ret; - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - ret = clk_enable(msm_uport->clk); - if (ret) { - printk(KERN_ERR "Error could not turn on UART clk\n"); - return ret; - } - - /* Set up the MREG/NREG/DREG/MNDREG */ - ret = clk_set_rate(msm_uport->clk, uport->uartclk); - if (ret) { - printk(KERN_WARNING "Error setting clock rate on UART\n"); - clk_disable(msm_uport->clk); - return ret; - } - - msm_uport->clk_state = MSM_HS_CLK_ON; - return 0; -} - -/* Enable and Disable clocks (Used for power management) */ -static void msm_hs_pm(struct uart_port *uport, unsigned int state, - unsigned int oldstate) -{ - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - if (use_low_power_rx_wakeup(msm_uport) || - msm_uport->exit_lpm_cb) - return; /* ignore linux PM states, - use msm_hs_request_clock API */ - - switch (state) { - case 0: - clk_enable(msm_uport->clk); - break; - case 3: - clk_disable(msm_uport->clk); - break; - default: - dev_err(uport->dev, "msm_serial: Unknown PM state %d\n", - state); - } -} - -/* - * programs the UARTDM_CSR register with correct bit rates - * - * Interrupts should be disabled before we are called, as - * we modify Set Baud rate - * Set receive stale interrupt level, dependent on Bit Rate - * Goal is to have around 8 ms before indicate stale. - * roundup (((Bit Rate * .008) / 10) + 1 - */ -static void msm_hs_set_bps_locked(struct uart_port *uport, - unsigned int bps) -{ - unsigned long rxstale; - unsigned long data; - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - switch (bps) { - case 300: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_75); - rxstale = 1; - break; - case 600: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_150); - rxstale = 1; - break; - case 1200: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_300); - rxstale = 1; - break; - case 2400: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_600); - rxstale = 1; - break; - case 4800: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_1200); - rxstale = 1; - break; - case 9600: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_2400); - rxstale = 2; - break; - case 14400: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_3600); - rxstale = 3; - break; - case 19200: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_4800); - rxstale = 4; - break; - case 28800: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_7200); - rxstale = 6; - break; - case 38400: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_9600); - rxstale = 8; - break; - case 57600: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_14400); - rxstale = 16; - break; - case 76800: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_19200); - rxstale = 16; - break; - case 115200: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_28800); - rxstale = 31; - break; - case 230400: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_57600); - rxstale = 31; - break; - case 460800: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_115200); - rxstale = 31; - break; - case 4000000: - case 3686400: - case 3200000: - case 3500000: - case 3000000: - case 2500000: - case 1500000: - case 1152000: - case 1000000: - case 921600: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_115200); - rxstale = 31; - break; - default: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_2400); - /* default to 9600 */ - bps = 9600; - rxstale = 2; - break; - } - if (bps > 460800) - uport->uartclk = bps * 16; - else - uport->uartclk = UARTCLK; - - if (clk_set_rate(msm_uport->clk, uport->uartclk)) { - printk(KERN_WARNING "Error setting clock rate on UART\n"); - return; - } - - data = rxstale & UARTDM_IPR_STALE_LSB_BMSK; - data |= UARTDM_IPR_STALE_TIMEOUT_MSB_BMSK & (rxstale << 2); - - msm_hs_write(uport, UARTDM_IPR_ADDR, data); -} - -/* - * termios : new ktermios - * oldtermios: old ktermios previous setting - * - * Configure the serial port - */ -static void msm_hs_set_termios(struct uart_port *uport, - struct ktermios *termios, - struct ktermios *oldtermios) -{ - unsigned int bps; - unsigned long data; - unsigned long flags; - unsigned int c_cflag = termios->c_cflag; - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - spin_lock_irqsave(&uport->lock, flags); - clk_enable(msm_uport->clk); - - /* 300 is the minimum baud support by the driver */ - bps = uart_get_baud_rate(uport, termios, oldtermios, 200, 4000000); - - /* Temporary remapping 200 BAUD to 3.2 mbps */ - if (bps == 200) - bps = 3200000; - - msm_hs_set_bps_locked(uport, bps); - - data = msm_hs_read(uport, UARTDM_MR2_ADDR); - data &= ~UARTDM_MR2_PARITY_MODE_BMSK; - /* set parity */ - if (PARENB == (c_cflag & PARENB)) { - if (PARODD == (c_cflag & PARODD)) - data |= ODD_PARITY; - else if (CMSPAR == (c_cflag & CMSPAR)) - data |= SPACE_PARITY; - else - data |= EVEN_PARITY; - } - - /* Set bits per char */ - data &= ~UARTDM_MR2_BITS_PER_CHAR_BMSK; - - switch (c_cflag & CSIZE) { - case CS5: - data |= FIVE_BPC; - break; - case CS6: - data |= SIX_BPC; - break; - case CS7: - data |= SEVEN_BPC; - break; - default: - data |= EIGHT_BPC; - break; - } - /* stop bits */ - if (c_cflag & CSTOPB) { - data |= STOP_BIT_TWO; - } else { - /* otherwise 1 stop bit */ - data |= STOP_BIT_ONE; - } - data |= UARTDM_MR2_ERROR_MODE_BMSK; - /* write parity/bits per char/stop bit configuration */ - msm_hs_write(uport, UARTDM_MR2_ADDR, data); - - /* Configure HW flow control */ - data = msm_hs_read(uport, UARTDM_MR1_ADDR); - - data &= ~(UARTDM_MR1_CTS_CTL_BMSK | UARTDM_MR1_RX_RDY_CTL_BMSK); - - if (c_cflag & CRTSCTS) { - data |= UARTDM_MR1_CTS_CTL_BMSK; - data |= UARTDM_MR1_RX_RDY_CTL_BMSK; - } - - msm_hs_write(uport, UARTDM_MR1_ADDR, data); - - uport->ignore_status_mask = termios->c_iflag & INPCK; - uport->ignore_status_mask |= termios->c_iflag & IGNPAR; - uport->read_status_mask = (termios->c_cflag & CREAD); - - msm_hs_write(uport, UARTDM_IMR_ADDR, 0); - - /* Set Transmit software time out */ - uart_update_timeout(uport, c_cflag, bps); - - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_RX); - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX); - - if (msm_uport->rx.flush == FLUSH_NONE) { - msm_uport->rx.flush = FLUSH_IGNORE; - msm_dmov_stop_cmd(msm_uport->dma_rx_channel, NULL, 1); - } - - msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); - - clk_disable(msm_uport->clk); - spin_unlock_irqrestore(&uport->lock, flags); -} - -/* - * Standard API, Transmitter - * Any character in the transmit shift register is sent - */ -static unsigned int msm_hs_tx_empty(struct uart_port *uport) -{ - unsigned int data; - unsigned int ret = 0; - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - clk_enable(msm_uport->clk); - - data = msm_hs_read(uport, UARTDM_SR_ADDR); - if (data & UARTDM_SR_TXEMT_BMSK) - ret = TIOCSER_TEMT; - - clk_disable(msm_uport->clk); - - return ret; -} - -/* - * Standard API, Stop transmitter. - * Any character in the transmit shift register is sent as - * well as the current data mover transfer . - */ -static void msm_hs_stop_tx_locked(struct uart_port *uport) -{ - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - msm_uport->tx.tx_ready_int_en = 0; -} - -/* - * Standard API, Stop receiver as soon as possible. - * - * Function immediately terminates the operation of the - * channel receiver and any incoming characters are lost. None - * of the receiver status bits are affected by this command and - * characters that are already in the receive FIFO there. - */ -static void msm_hs_stop_rx_locked(struct uart_port *uport) -{ - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - unsigned int data; - - clk_enable(msm_uport->clk); - - /* disable dlink */ - data = msm_hs_read(uport, UARTDM_DMEN_ADDR); - data &= ~UARTDM_RX_DM_EN_BMSK; - msm_hs_write(uport, UARTDM_DMEN_ADDR, data); - - /* Disable the receiver */ - if (msm_uport->rx.flush == FLUSH_NONE) - msm_dmov_stop_cmd(msm_uport->dma_rx_channel, NULL, 1); - - if (msm_uport->rx.flush != FLUSH_SHUTDOWN) - msm_uport->rx.flush = FLUSH_STOP; - - clk_disable(msm_uport->clk); -} - -/* Transmit the next chunk of data */ -static void msm_hs_submit_tx_locked(struct uart_port *uport) -{ - int left; - int tx_count; - dma_addr_t src_addr; - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - struct msm_hs_tx *tx = &msm_uport->tx; - struct circ_buf *tx_buf = &msm_uport->uport.state->xmit; - - if (uart_circ_empty(tx_buf) || uport->state->port.tty->stopped) { - msm_hs_stop_tx_locked(uport); - return; - } - - tx->dma_in_flight = 1; - - tx_count = uart_circ_chars_pending(tx_buf); - - if (UARTDM_TX_BUF_SIZE < tx_count) - tx_count = UARTDM_TX_BUF_SIZE; - - left = UART_XMIT_SIZE - tx_buf->tail; - - if (tx_count > left) - tx_count = left; - - src_addr = tx->dma_base + tx_buf->tail; - dma_sync_single_for_device(uport->dev, src_addr, tx_count, - DMA_TO_DEVICE); - - tx->command_ptr->num_rows = (((tx_count + 15) >> 4) << 16) | - ((tx_count + 15) >> 4); - tx->command_ptr->src_row_addr = src_addr; - - dma_sync_single_for_device(uport->dev, tx->mapped_cmd_ptr, - sizeof(dmov_box), DMA_TO_DEVICE); - - *tx->command_ptr_ptr = CMD_PTR_LP | DMOV_CMD_ADDR(tx->mapped_cmd_ptr); - - dma_sync_single_for_device(uport->dev, tx->mapped_cmd_ptr_ptr, - sizeof(u32), DMA_TO_DEVICE); - - /* Save tx_count to use in Callback */ - tx->tx_count = tx_count; - msm_hs_write(uport, UARTDM_NCF_TX_ADDR, tx_count); - - /* Disable the tx_ready interrupt */ - msm_uport->imr_reg &= ~UARTDM_ISR_TX_READY_BMSK; - msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); - msm_dmov_enqueue_cmd(msm_uport->dma_tx_channel, &tx->xfer); -} - -/* Start to receive the next chunk of data */ -static void msm_hs_start_rx_locked(struct uart_port *uport) -{ - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_STALE_INT); - msm_hs_write(uport, UARTDM_DMRX_ADDR, UARTDM_RX_BUF_SIZE); - msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_ENABLE); - msm_uport->imr_reg |= UARTDM_ISR_RXLEV_BMSK; - msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); - - msm_uport->rx.flush = FLUSH_NONE; - msm_dmov_enqueue_cmd(msm_uport->dma_rx_channel, &msm_uport->rx.xfer); - - /* might have finished RX and be ready to clock off */ - hrtimer_start(&msm_uport->clk_off_timer, msm_uport->clk_off_delay, - HRTIMER_MODE_REL); -} - -/* Enable the transmitter Interrupt */ -static void msm_hs_start_tx_locked(struct uart_port *uport) -{ - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - clk_enable(msm_uport->clk); - - if (msm_uport->exit_lpm_cb) - msm_uport->exit_lpm_cb(uport); - - if (msm_uport->tx.tx_ready_int_en == 0) { - msm_uport->tx.tx_ready_int_en = 1; - msm_hs_submit_tx_locked(uport); - } - - clk_disable(msm_uport->clk); -} - -/* - * This routine is called when we are done with a DMA transfer - * - * This routine is registered with Data mover when we set - * up a Data Mover transfer. It is called from Data mover ISR - * when the DMA transfer is done. - */ -static void msm_hs_dmov_tx_callback(struct msm_dmov_cmd *cmd_ptr, - unsigned int result, - struct msm_dmov_errdata *err) -{ - unsigned long flags; - struct msm_hs_port *msm_uport; - - /* DMA did not finish properly */ - WARN_ON((((result & RSLT_FIFO_CNTR_BMSK) >> 28) == 1) && - !(result & RSLT_VLD)); - - msm_uport = container_of(cmd_ptr, struct msm_hs_port, tx.xfer); - - spin_lock_irqsave(&msm_uport->uport.lock, flags); - clk_enable(msm_uport->clk); - - msm_uport->imr_reg |= UARTDM_ISR_TX_READY_BMSK; - msm_hs_write(&msm_uport->uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); - - clk_disable(msm_uport->clk); - spin_unlock_irqrestore(&msm_uport->uport.lock, flags); -} - -/* - * This routine is called when we are done with a DMA transfer or the - * a flush has been sent to the data mover driver. - * - * This routine is registered with Data mover when we set up a Data Mover - * transfer. It is called from Data mover ISR when the DMA transfer is done. - */ -static void msm_hs_dmov_rx_callback(struct msm_dmov_cmd *cmd_ptr, - unsigned int result, - struct msm_dmov_errdata *err) -{ - int retval; - int rx_count; - unsigned long status; - unsigned int error_f = 0; - unsigned long flags; - unsigned int flush; - struct tty_port *port; - struct uart_port *uport; - struct msm_hs_port *msm_uport; - - msm_uport = container_of(cmd_ptr, struct msm_hs_port, rx.xfer); - uport = &msm_uport->uport; - - spin_lock_irqsave(&uport->lock, flags); - clk_enable(msm_uport->clk); - - port = &uport->state->port; - - msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_DISABLE); - - status = msm_hs_read(uport, UARTDM_SR_ADDR); - - /* overflow is not connect to data in a FIFO */ - if (unlikely((status & UARTDM_SR_OVERRUN_BMSK) && - (uport->read_status_mask & CREAD))) { - tty_insert_flip_char(port, 0, TTY_OVERRUN); - uport->icount.buf_overrun++; - error_f = 1; - } - - if (!(uport->ignore_status_mask & INPCK)) - status = status & ~(UARTDM_SR_PAR_FRAME_BMSK); - - if (unlikely(status & UARTDM_SR_PAR_FRAME_BMSK)) { - /* Can not tell difference between parity & frame error */ - uport->icount.parity++; - error_f = 1; - if (uport->ignore_status_mask & IGNPAR) - tty_insert_flip_char(port, 0, TTY_PARITY); - } - - if (error_f) - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_ERROR_STATUS); - - if (msm_uport->clk_req_off_state == CLK_REQ_OFF_FLUSH_ISSUED) - msm_uport->clk_req_off_state = CLK_REQ_OFF_RXSTALE_FLUSHED; - - flush = msm_uport->rx.flush; - if (flush == FLUSH_IGNORE) - msm_hs_start_rx_locked(uport); - if (flush == FLUSH_STOP) - msm_uport->rx.flush = FLUSH_SHUTDOWN; - if (flush >= FLUSH_DATA_INVALID) - goto out; - - rx_count = msm_hs_read(uport, UARTDM_RX_TOTAL_SNAP_ADDR); - - if (0 != (uport->read_status_mask & CREAD)) { - retval = tty_insert_flip_string(port, msm_uport->rx.buffer, - rx_count); - BUG_ON(retval != rx_count); - } - - msm_hs_start_rx_locked(uport); - -out: - clk_disable(msm_uport->clk); - - spin_unlock_irqrestore(&uport->lock, flags); - - if (flush < FLUSH_DATA_INVALID) - queue_work(msm_hs_workqueue, &msm_uport->rx.tty_work); -} - -static void msm_hs_tty_flip_buffer_work(struct work_struct *work) -{ - struct msm_hs_port *msm_uport = - container_of(work, struct msm_hs_port, rx.tty_work); - - tty_flip_buffer_push(&msm_uport->uport.state->port); -} - -/* - * Standard API, Current states of modem control inputs - * - * Since CTS can be handled entirely by HARDWARE we always - * indicate clear to send and count on the TX FIFO to block when - * it fills up. - * - * - TIOCM_DCD - * - TIOCM_CTS - * - TIOCM_DSR - * - TIOCM_RI - * (Unsupported) DCD and DSR will return them high. RI will return low. - */ -static unsigned int msm_hs_get_mctrl_locked(struct uart_port *uport) -{ - return TIOCM_DSR | TIOCM_CAR | TIOCM_CTS; -} - -/* - * True enables UART auto RFR, which indicates we are ready for data if the RX - * buffer is not full. False disables auto RFR, and deasserts RFR to indicate - * we are not ready for data. Must be called with UART clock on. - */ -static void set_rfr_locked(struct uart_port *uport, int auto_rfr) -{ - unsigned int data; - - data = msm_hs_read(uport, UARTDM_MR1_ADDR); - - if (auto_rfr) { - /* enable auto ready-for-receiving */ - data |= UARTDM_MR1_RX_RDY_CTL_BMSK; - msm_hs_write(uport, UARTDM_MR1_ADDR, data); - } else { - /* disable auto ready-for-receiving */ - data &= ~UARTDM_MR1_RX_RDY_CTL_BMSK; - msm_hs_write(uport, UARTDM_MR1_ADDR, data); - /* RFR is active low, set high */ - msm_hs_write(uport, UARTDM_CR_ADDR, RFR_HIGH); - } -} - -/* - * Standard API, used to set or clear RFR - */ -static void msm_hs_set_mctrl_locked(struct uart_port *uport, - unsigned int mctrl) -{ - unsigned int auto_rfr; - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - clk_enable(msm_uport->clk); - - auto_rfr = TIOCM_RTS & mctrl ? 1 : 0; - set_rfr_locked(uport, auto_rfr); - - clk_disable(msm_uport->clk); -} - -/* Standard API, Enable modem status (CTS) interrupt */ -static void msm_hs_enable_ms_locked(struct uart_port *uport) -{ - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - clk_enable(msm_uport->clk); - - /* Enable DELTA_CTS Interrupt */ - msm_uport->imr_reg |= UARTDM_ISR_DELTA_CTS_BMSK; - msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); - - clk_disable(msm_uport->clk); - -} - -/* - * Standard API, Break Signal - * - * Control the transmission of a break signal. ctl eq 0 => break - * signal terminate ctl ne 0 => start break signal - */ -static void msm_hs_break_ctl(struct uart_port *uport, int ctl) -{ - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - clk_enable(msm_uport->clk); - msm_hs_write(uport, UARTDM_CR_ADDR, ctl ? START_BREAK : STOP_BREAK); - clk_disable(msm_uport->clk); -} - -static void msm_hs_config_port(struct uart_port *uport, int cfg_flags) -{ - unsigned long flags; - - spin_lock_irqsave(&uport->lock, flags); - if (cfg_flags & UART_CONFIG_TYPE) { - uport->type = PORT_MSM; - msm_hs_request_port(uport); - } - spin_unlock_irqrestore(&uport->lock, flags); -} - -/* Handle CTS changes (Called from interrupt handler) */ -static void msm_hs_handle_delta_cts_locked(struct uart_port *uport) -{ - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - clk_enable(msm_uport->clk); - - /* clear interrupt */ - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_CTS); - uport->icount.cts++; - - clk_disable(msm_uport->clk); - - /* clear the IOCTL TIOCMIWAIT if called */ - wake_up_interruptible(&uport->state->port.delta_msr_wait); -} - -/* check if the TX path is flushed, and if so clock off - * returns 0 did not clock off, need to retry (still sending final byte) - * -1 did not clock off, do not retry - * 1 if we clocked off - */ -static int msm_hs_check_clock_off_locked(struct uart_port *uport) -{ - unsigned long sr_status; - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - struct circ_buf *tx_buf = &uport->state->xmit; - - /* Cancel if tx tty buffer is not empty, dma is in flight, - * or tx fifo is not empty, or rx fifo is not empty */ - if (msm_uport->clk_state != MSM_HS_CLK_REQUEST_OFF || - !uart_circ_empty(tx_buf) || msm_uport->tx.dma_in_flight || - (msm_uport->imr_reg & UARTDM_ISR_TXLEV_BMSK) || - !(msm_uport->imr_reg & UARTDM_ISR_RXLEV_BMSK)) { - return -1; - } - - /* Make sure the uart is finished with the last byte */ - sr_status = msm_hs_read(uport, UARTDM_SR_ADDR); - if (!(sr_status & UARTDM_SR_TXEMT_BMSK)) - return 0; /* retry */ - - /* Make sure forced RXSTALE flush complete */ - switch (msm_uport->clk_req_off_state) { - case CLK_REQ_OFF_START: - msm_uport->clk_req_off_state = CLK_REQ_OFF_RXSTALE_ISSUED; - msm_hs_write(uport, UARTDM_CR_ADDR, FORCE_STALE_EVENT); - return 0; /* RXSTALE flush not complete - retry */ - case CLK_REQ_OFF_RXSTALE_ISSUED: - case CLK_REQ_OFF_FLUSH_ISSUED: - return 0; /* RXSTALE flush not complete - retry */ - case CLK_REQ_OFF_RXSTALE_FLUSHED: - break; /* continue */ - } - - if (msm_uport->rx.flush != FLUSH_SHUTDOWN) { - if (msm_uport->rx.flush == FLUSH_NONE) - msm_hs_stop_rx_locked(uport); - return 0; /* come back later to really clock off */ - } - - /* we really want to clock off */ - clk_disable(msm_uport->clk); - msm_uport->clk_state = MSM_HS_CLK_OFF; - - if (use_low_power_rx_wakeup(msm_uport)) { - msm_uport->rx_wakeup.ignore = 1; - enable_irq(msm_uport->rx_wakeup.irq); - } - return 1; -} - -static enum hrtimer_restart msm_hs_clk_off_retry(struct hrtimer *timer) -{ - unsigned long flags; - int ret = HRTIMER_NORESTART; - struct msm_hs_port *msm_uport = container_of(timer, struct msm_hs_port, - clk_off_timer); - struct uart_port *uport = &msm_uport->uport; - - spin_lock_irqsave(&uport->lock, flags); - - if (!msm_hs_check_clock_off_locked(uport)) { - hrtimer_forward_now(timer, msm_uport->clk_off_delay); - ret = HRTIMER_RESTART; - } - - spin_unlock_irqrestore(&uport->lock, flags); - - return ret; -} - -static irqreturn_t msm_hs_isr(int irq, void *dev) -{ - unsigned long flags; - unsigned long isr_status; - struct msm_hs_port *msm_uport = dev; - struct uart_port *uport = &msm_uport->uport; - struct circ_buf *tx_buf = &uport->state->xmit; - struct msm_hs_tx *tx = &msm_uport->tx; - struct msm_hs_rx *rx = &msm_uport->rx; - - spin_lock_irqsave(&uport->lock, flags); - - isr_status = msm_hs_read(uport, UARTDM_MISR_ADDR); - - /* Uart RX starting */ - if (isr_status & UARTDM_ISR_RXLEV_BMSK) { - msm_uport->imr_reg &= ~UARTDM_ISR_RXLEV_BMSK; - msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); - } - /* Stale rx interrupt */ - if (isr_status & UARTDM_ISR_RXSTALE_BMSK) { - msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_DISABLE); - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_STALE_INT); - - if (msm_uport->clk_req_off_state == CLK_REQ_OFF_RXSTALE_ISSUED) - msm_uport->clk_req_off_state = - CLK_REQ_OFF_FLUSH_ISSUED; - if (rx->flush == FLUSH_NONE) { - rx->flush = FLUSH_DATA_READY; - msm_dmov_stop_cmd(msm_uport->dma_rx_channel, NULL, 1); - } - } - /* tx ready interrupt */ - if (isr_status & UARTDM_ISR_TX_READY_BMSK) { - /* Clear TX Ready */ - msm_hs_write(uport, UARTDM_CR_ADDR, CLEAR_TX_READY); - - if (msm_uport->clk_state == MSM_HS_CLK_REQUEST_OFF) { - msm_uport->imr_reg |= UARTDM_ISR_TXLEV_BMSK; - msm_hs_write(uport, UARTDM_IMR_ADDR, - msm_uport->imr_reg); - } - - /* Complete DMA TX transactions and submit new transactions */ - tx_buf->tail = (tx_buf->tail + tx->tx_count) & ~UART_XMIT_SIZE; - - tx->dma_in_flight = 0; - - uport->icount.tx += tx->tx_count; - if (tx->tx_ready_int_en) - msm_hs_submit_tx_locked(uport); - - if (uart_circ_chars_pending(tx_buf) < WAKEUP_CHARS) - uart_write_wakeup(uport); - } - if (isr_status & UARTDM_ISR_TXLEV_BMSK) { - /* TX FIFO is empty */ - msm_uport->imr_reg &= ~UARTDM_ISR_TXLEV_BMSK; - msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); - if (!msm_hs_check_clock_off_locked(uport)) - hrtimer_start(&msm_uport->clk_off_timer, - msm_uport->clk_off_delay, - HRTIMER_MODE_REL); - } - - /* Change in CTS interrupt */ - if (isr_status & UARTDM_ISR_DELTA_CTS_BMSK) - msm_hs_handle_delta_cts_locked(uport); - - spin_unlock_irqrestore(&uport->lock, flags); - - return IRQ_HANDLED; -} - -void msm_hs_request_clock_off_locked(struct uart_port *uport) -{ - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - if (msm_uport->clk_state == MSM_HS_CLK_ON) { - msm_uport->clk_state = MSM_HS_CLK_REQUEST_OFF; - msm_uport->clk_req_off_state = CLK_REQ_OFF_START; - if (!use_low_power_rx_wakeup(msm_uport)) - set_rfr_locked(uport, 0); - msm_uport->imr_reg |= UARTDM_ISR_TXLEV_BMSK; - msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); - } -} - -/** - * msm_hs_request_clock_off - request to (i.e. asynchronously) turn off uart - * clock once pending TX is flushed and Rx DMA command is terminated. - * @uport: uart_port structure for the device instance. - * - * This functions puts the device into a partially active low power mode. It - * waits to complete all pending tx transactions, flushes ongoing Rx DMA - * command and terminates UART side Rx transaction, puts UART HW in non DMA - * mode and then clocks off the device. A client calls this when no UART - * data is expected. msm_request_clock_on() must be called before any further - * UART can be sent or received. - */ -void msm_hs_request_clock_off(struct uart_port *uport) -{ - unsigned long flags; - - spin_lock_irqsave(&uport->lock, flags); - msm_hs_request_clock_off_locked(uport); - spin_unlock_irqrestore(&uport->lock, flags); -} - -void msm_hs_request_clock_on_locked(struct uart_port *uport) -{ - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - unsigned int data; - - switch (msm_uport->clk_state) { - case MSM_HS_CLK_OFF: - clk_enable(msm_uport->clk); - disable_irq_nosync(msm_uport->rx_wakeup.irq); - /* fall-through */ - case MSM_HS_CLK_REQUEST_OFF: - if (msm_uport->rx.flush == FLUSH_STOP || - msm_uport->rx.flush == FLUSH_SHUTDOWN) { - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_RX); - data = msm_hs_read(uport, UARTDM_DMEN_ADDR); - data |= UARTDM_RX_DM_EN_BMSK; - msm_hs_write(uport, UARTDM_DMEN_ADDR, data); - } - hrtimer_try_to_cancel(&msm_uport->clk_off_timer); - if (msm_uport->rx.flush == FLUSH_SHUTDOWN) - msm_hs_start_rx_locked(uport); - if (!use_low_power_rx_wakeup(msm_uport)) - set_rfr_locked(uport, 1); - if (msm_uport->rx.flush == FLUSH_STOP) - msm_uport->rx.flush = FLUSH_IGNORE; - msm_uport->clk_state = MSM_HS_CLK_ON; - break; - case MSM_HS_CLK_ON: - break; - case MSM_HS_CLK_PORT_OFF: - break; - } -} - -/** - * msm_hs_request_clock_on - Switch the device from partially active low - * power mode to fully active (i.e. clock on) mode. - * @uport: uart_port structure for the device. - * - * This function switches on the input clock, puts UART HW into DMA mode - * and enqueues an Rx DMA command if the device was in partially active - * mode. It has no effect if called with the device in inactive state. - */ -void msm_hs_request_clock_on(struct uart_port *uport) -{ - unsigned long flags; - - spin_lock_irqsave(&uport->lock, flags); - msm_hs_request_clock_on_locked(uport); - spin_unlock_irqrestore(&uport->lock, flags); -} - -static irqreturn_t msm_hs_rx_wakeup_isr(int irq, void *dev) -{ - unsigned int wakeup = 0; - unsigned long flags; - struct msm_hs_port *msm_uport = dev; - struct uart_port *uport = &msm_uport->uport; - - spin_lock_irqsave(&uport->lock, flags); - if (msm_uport->clk_state == MSM_HS_CLK_OFF) { - /* ignore the first irq - it is a pending irq that occurred - * before enable_irq() */ - if (msm_uport->rx_wakeup.ignore) - msm_uport->rx_wakeup.ignore = 0; - else - wakeup = 1; - } - - if (wakeup) { - /* the uart was clocked off during an rx, wake up and - * optionally inject char into tty rx */ - msm_hs_request_clock_on_locked(uport); - if (msm_uport->rx_wakeup.inject_rx) { - tty_insert_flip_char(&uport->state->port, - msm_uport->rx_wakeup.rx_to_inject, - TTY_NORMAL); - queue_work(msm_hs_workqueue, &msm_uport->rx.tty_work); - } - } - - spin_unlock_irqrestore(&uport->lock, flags); - - return IRQ_HANDLED; -} - -static const char *msm_hs_type(struct uart_port *port) -{ - return (port->type == PORT_MSM) ? "MSM_HS_UART" : NULL; -} - -/* Called when port is opened */ -static int msm_hs_startup(struct uart_port *uport) -{ - int ret; - int rfr_level; - unsigned long flags; - unsigned int data; - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - struct circ_buf *tx_buf = &uport->state->xmit; - struct msm_hs_tx *tx = &msm_uport->tx; - struct msm_hs_rx *rx = &msm_uport->rx; - - rfr_level = uport->fifosize; - if (rfr_level > 16) - rfr_level -= 16; - - tx->dma_base = dma_map_single(uport->dev, tx_buf->buf, UART_XMIT_SIZE, - DMA_TO_DEVICE); - - /* do not let tty layer execute RX in global workqueue, use a - * dedicated workqueue managed by this driver */ - uport->state->port.low_latency = 1; - - /* turn on uart clk */ - ret = msm_hs_init_clk_locked(uport); - if (unlikely(ret)) { - printk(KERN_ERR "Turning uartclk failed!\n"); - goto err_msm_hs_init_clk; - } - - /* Set auto RFR Level */ - data = msm_hs_read(uport, UARTDM_MR1_ADDR); - data &= ~UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK; - data &= ~UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK; - data |= (UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK & (rfr_level << 2)); - data |= (UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK & rfr_level); - msm_hs_write(uport, UARTDM_MR1_ADDR, data); - - /* Make sure RXSTALE count is non-zero */ - data = msm_hs_read(uport, UARTDM_IPR_ADDR); - if (!data) { - data |= 0x1f & UARTDM_IPR_STALE_LSB_BMSK; - msm_hs_write(uport, UARTDM_IPR_ADDR, data); - } - - /* Enable Data Mover Mode */ - data = UARTDM_TX_DM_EN_BMSK | UARTDM_RX_DM_EN_BMSK; - msm_hs_write(uport, UARTDM_DMEN_ADDR, data); - - /* Reset TX */ - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX); - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_RX); - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_ERROR_STATUS); - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_BREAK_INT); - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_STALE_INT); - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_CTS); - msm_hs_write(uport, UARTDM_CR_ADDR, RFR_LOW); - /* Turn on Uart Receiver */ - msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_RX_EN_BMSK); - - /* Turn on Uart Transmitter */ - msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_TX_EN_BMSK); - - /* Initialize the tx */ - tx->tx_ready_int_en = 0; - tx->dma_in_flight = 0; - - tx->xfer.complete_func = msm_hs_dmov_tx_callback; - tx->xfer.execute_func = NULL; - - tx->command_ptr->cmd = CMD_LC | - CMD_DST_CRCI(msm_uport->dma_tx_crci) | CMD_MODE_BOX; - - tx->command_ptr->src_dst_len = (MSM_UARTDM_BURST_SIZE << 16) - | (MSM_UARTDM_BURST_SIZE); - - tx->command_ptr->row_offset = (MSM_UARTDM_BURST_SIZE << 16); - - tx->command_ptr->dst_row_addr = - msm_uport->uport.mapbase + UARTDM_TF_ADDR; - - - /* Turn on Uart Receive */ - rx->xfer.complete_func = msm_hs_dmov_rx_callback; - rx->xfer.execute_func = NULL; - - rx->command_ptr->cmd = CMD_LC | - CMD_SRC_CRCI(msm_uport->dma_rx_crci) | CMD_MODE_BOX; - - rx->command_ptr->src_dst_len = (MSM_UARTDM_BURST_SIZE << 16) - | (MSM_UARTDM_BURST_SIZE); - rx->command_ptr->row_offset = MSM_UARTDM_BURST_SIZE; - rx->command_ptr->src_row_addr = uport->mapbase + UARTDM_RF_ADDR; - - - msm_uport->imr_reg |= UARTDM_ISR_RXSTALE_BMSK; - /* Enable reading the current CTS, no harm even if CTS is ignored */ - msm_uport->imr_reg |= UARTDM_ISR_CURRENT_CTS_BMSK; - - msm_hs_write(uport, UARTDM_TFWR_ADDR, 0); /* TXLEV on empty TX fifo */ - - - ret = request_irq(uport->irq, msm_hs_isr, IRQF_TRIGGER_HIGH, - "msm_hs_uart", msm_uport); - if (unlikely(ret)) { - printk(KERN_ERR "Request msm_hs_uart IRQ failed!\n"); - goto err_request_irq; - } - if (use_low_power_rx_wakeup(msm_uport)) { - ret = request_irq(msm_uport->rx_wakeup.irq, - msm_hs_rx_wakeup_isr, - IRQF_TRIGGER_FALLING, - "msm_hs_rx_wakeup", msm_uport); - if (unlikely(ret)) { - printk(KERN_ERR "Request msm_hs_rx_wakeup IRQ failed!\n"); - free_irq(uport->irq, msm_uport); - goto err_request_irq; - } - disable_irq(msm_uport->rx_wakeup.irq); - } - - spin_lock_irqsave(&uport->lock, flags); - - msm_hs_write(uport, UARTDM_RFWR_ADDR, 0); - msm_hs_start_rx_locked(uport); - - spin_unlock_irqrestore(&uport->lock, flags); - ret = pm_runtime_set_active(uport->dev); - if (ret) - dev_err(uport->dev, "set active error:%d\n", ret); - pm_runtime_enable(uport->dev); - - return 0; - -err_request_irq: -err_msm_hs_init_clk: - dma_unmap_single(uport->dev, tx->dma_base, - UART_XMIT_SIZE, DMA_TO_DEVICE); - return ret; -} - -/* Initialize tx and rx data structures */ -static int uartdm_init_port(struct uart_port *uport) -{ - int ret = 0; - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - struct msm_hs_tx *tx = &msm_uport->tx; - struct msm_hs_rx *rx = &msm_uport->rx; - - /* Allocate the command pointer. Needs to be 64 bit aligned */ - tx->command_ptr = kmalloc(sizeof(dmov_box), GFP_KERNEL | __GFP_DMA); - if (!tx->command_ptr) - return -ENOMEM; - - tx->command_ptr_ptr = kmalloc(sizeof(u32), GFP_KERNEL | __GFP_DMA); - if (!tx->command_ptr_ptr) { - ret = -ENOMEM; - goto err_tx_command_ptr_ptr; - } - - tx->mapped_cmd_ptr = dma_map_single(uport->dev, tx->command_ptr, - sizeof(dmov_box), DMA_TO_DEVICE); - tx->mapped_cmd_ptr_ptr = dma_map_single(uport->dev, - tx->command_ptr_ptr, - sizeof(u32), DMA_TO_DEVICE); - tx->xfer.cmdptr = DMOV_CMD_ADDR(tx->mapped_cmd_ptr_ptr); - - init_waitqueue_head(&rx->wait); - - rx->pool = dma_pool_create("rx_buffer_pool", uport->dev, - UARTDM_RX_BUF_SIZE, 16, 0); - if (!rx->pool) { - pr_err("%s(): cannot allocate rx_buffer_pool", __func__); - ret = -ENOMEM; - goto err_dma_pool_create; - } - - rx->buffer = dma_pool_alloc(rx->pool, GFP_KERNEL, &rx->rbuffer); - if (!rx->buffer) { - pr_err("%s(): cannot allocate rx->buffer", __func__); - ret = -ENOMEM; - goto err_dma_pool_alloc; - } - - /* Allocate the command pointer. Needs to be 64 bit aligned */ - rx->command_ptr = kmalloc(sizeof(dmov_box), GFP_KERNEL | __GFP_DMA); - if (!rx->command_ptr) { - pr_err("%s(): cannot allocate rx->command_ptr", __func__); - ret = -ENOMEM; - goto err_rx_command_ptr; - } - - rx->command_ptr_ptr = kmalloc(sizeof(u32), GFP_KERNEL | __GFP_DMA); - if (!rx->command_ptr_ptr) { - pr_err("%s(): cannot allocate rx->command_ptr_ptr", __func__); - ret = -ENOMEM; - goto err_rx_command_ptr_ptr; - } - - rx->command_ptr->num_rows = ((UARTDM_RX_BUF_SIZE >> 4) << 16) | - (UARTDM_RX_BUF_SIZE >> 4); - - rx->command_ptr->dst_row_addr = rx->rbuffer; - - rx->mapped_cmd_ptr = dma_map_single(uport->dev, rx->command_ptr, - sizeof(dmov_box), DMA_TO_DEVICE); - - *rx->command_ptr_ptr = CMD_PTR_LP | DMOV_CMD_ADDR(rx->mapped_cmd_ptr); - - rx->cmdptr_dmaaddr = dma_map_single(uport->dev, rx->command_ptr_ptr, - sizeof(u32), DMA_TO_DEVICE); - rx->xfer.cmdptr = DMOV_CMD_ADDR(rx->cmdptr_dmaaddr); - - INIT_WORK(&rx->tty_work, msm_hs_tty_flip_buffer_work); - - return ret; - -err_rx_command_ptr_ptr: - kfree(rx->command_ptr); -err_rx_command_ptr: - dma_pool_free(msm_uport->rx.pool, msm_uport->rx.buffer, - msm_uport->rx.rbuffer); -err_dma_pool_alloc: - dma_pool_destroy(msm_uport->rx.pool); -err_dma_pool_create: - dma_unmap_single(uport->dev, msm_uport->tx.mapped_cmd_ptr_ptr, - sizeof(u32), DMA_TO_DEVICE); - dma_unmap_single(uport->dev, msm_uport->tx.mapped_cmd_ptr, - sizeof(dmov_box), DMA_TO_DEVICE); - kfree(msm_uport->tx.command_ptr_ptr); -err_tx_command_ptr_ptr: - kfree(msm_uport->tx.command_ptr); - return ret; -} - -static int msm_hs_probe(struct platform_device *pdev) -{ - int ret; - struct uart_port *uport; - struct msm_hs_port *msm_uport; - struct resource *resource; - const struct msm_serial_hs_platform_data *pdata = - dev_get_platdata(&pdev->dev); - - if (pdev->id < 0 || pdev->id >= UARTDM_NR) { - printk(KERN_ERR "Invalid plaform device ID = %d\n", pdev->id); - return -EINVAL; - } - - msm_uport = &q_uart_port[pdev->id]; - uport = &msm_uport->uport; - - uport->dev = &pdev->dev; - - resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (unlikely(!resource)) - return -ENXIO; - - uport->mapbase = resource->start; - uport->irq = platform_get_irq(pdev, 0); - if (unlikely(uport->irq < 0)) - return -ENXIO; - - if (unlikely(irq_set_irq_wake(uport->irq, 1))) - return -ENXIO; - - if (pdata == NULL || pdata->rx_wakeup_irq < 0) - msm_uport->rx_wakeup.irq = -1; - else { - msm_uport->rx_wakeup.irq = pdata->rx_wakeup_irq; - msm_uport->rx_wakeup.ignore = 1; - msm_uport->rx_wakeup.inject_rx = pdata->inject_rx_on_wakeup; - msm_uport->rx_wakeup.rx_to_inject = pdata->rx_to_inject; - - if (unlikely(msm_uport->rx_wakeup.irq < 0)) - return -ENXIO; - - if (unlikely(irq_set_irq_wake(msm_uport->rx_wakeup.irq, 1))) - return -ENXIO; - } - - if (pdata == NULL) - msm_uport->exit_lpm_cb = NULL; - else - msm_uport->exit_lpm_cb = pdata->exit_lpm_cb; - - resource = platform_get_resource_byname(pdev, IORESOURCE_DMA, - "uartdm_channels"); - if (unlikely(!resource)) - return -ENXIO; - - msm_uport->dma_tx_channel = resource->start; - msm_uport->dma_rx_channel = resource->end; - - resource = platform_get_resource_byname(pdev, IORESOURCE_DMA, - "uartdm_crci"); - if (unlikely(!resource)) - return -ENXIO; - - msm_uport->dma_tx_crci = resource->start; - msm_uport->dma_rx_crci = resource->end; - - uport->iotype = UPIO_MEM; - uport->fifosize = UART_FIFOSIZE; - uport->ops = &msm_hs_ops; - uport->flags = UPF_BOOT_AUTOCONF; - uport->uartclk = UARTCLK; - msm_uport->imr_reg = 0x0; - msm_uport->clk = clk_get(&pdev->dev, "uartdm_clk"); - if (IS_ERR(msm_uport->clk)) - return PTR_ERR(msm_uport->clk); - - ret = uartdm_init_port(uport); - if (unlikely(ret)) - return ret; - - msm_uport->clk_state = MSM_HS_CLK_PORT_OFF; - hrtimer_init(&msm_uport->clk_off_timer, CLOCK_MONOTONIC, - HRTIMER_MODE_REL); - msm_uport->clk_off_timer.function = msm_hs_clk_off_retry; - msm_uport->clk_off_delay = ktime_set(0, 1000000); /* 1ms */ - - uport->line = pdev->id; - return uart_add_one_port(&msm_hs_driver, uport); -} - -static int __init msm_serial_hs_init(void) -{ - int ret, i; - - /* Init all UARTS as non-configured */ - for (i = 0; i < UARTDM_NR; i++) - q_uart_port[i].uport.type = PORT_UNKNOWN; - - msm_hs_workqueue = create_singlethread_workqueue("msm_serial_hs"); - if (unlikely(!msm_hs_workqueue)) - return -ENOMEM; - - ret = uart_register_driver(&msm_hs_driver); - if (unlikely(ret)) { - printk(KERN_ERR "%s failed to load\n", __func__); - goto err_uart_register_driver; - } - - ret = platform_driver_register(&msm_serial_hs_platform_driver); - if (ret) { - printk(KERN_ERR "%s failed to load\n", __func__); - goto err_platform_driver_register; - } - - return ret; - -err_platform_driver_register: - uart_unregister_driver(&msm_hs_driver); -err_uart_register_driver: - destroy_workqueue(msm_hs_workqueue); - return ret; -} -module_init(msm_serial_hs_init); - -/* - * Called by the upper layer when port is closed. - * - Disables the port - * - Unhook the ISR - */ -static void msm_hs_shutdown(struct uart_port *uport) -{ - unsigned long flags; - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - BUG_ON(msm_uport->rx.flush < FLUSH_STOP); - - spin_lock_irqsave(&uport->lock, flags); - clk_enable(msm_uport->clk); - - /* Disable the transmitter */ - msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_TX_DISABLE_BMSK); - /* Disable the receiver */ - msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_RX_DISABLE_BMSK); - - pm_runtime_disable(uport->dev); - pm_runtime_set_suspended(uport->dev); - - /* Free the interrupt */ - free_irq(uport->irq, msm_uport); - if (use_low_power_rx_wakeup(msm_uport)) - free_irq(msm_uport->rx_wakeup.irq, msm_uport); - - msm_uport->imr_reg = 0; - msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); - - wait_event(msm_uport->rx.wait, msm_uport->rx.flush == FLUSH_SHUTDOWN); - - clk_disable(msm_uport->clk); /* to balance local clk_enable() */ - if (msm_uport->clk_state != MSM_HS_CLK_OFF) - clk_disable(msm_uport->clk); /* to balance clk_state */ - msm_uport->clk_state = MSM_HS_CLK_PORT_OFF; - - dma_unmap_single(uport->dev, msm_uport->tx.dma_base, - UART_XMIT_SIZE, DMA_TO_DEVICE); - - spin_unlock_irqrestore(&uport->lock, flags); - - if (cancel_work_sync(&msm_uport->rx.tty_work)) - msm_hs_tty_flip_buffer_work(&msm_uport->rx.tty_work); -} - -static void __exit msm_serial_hs_exit(void) -{ - flush_workqueue(msm_hs_workqueue); - destroy_workqueue(msm_hs_workqueue); - platform_driver_unregister(&msm_serial_hs_platform_driver); - uart_unregister_driver(&msm_hs_driver); -} -module_exit(msm_serial_hs_exit); - -#ifdef CONFIG_PM -static int msm_hs_runtime_idle(struct device *dev) -{ - /* - * returning success from idle results in runtime suspend to be - * called - */ - return 0; -} - -static int msm_hs_runtime_resume(struct device *dev) -{ - struct platform_device *pdev = container_of(dev, struct - platform_device, dev); - struct msm_hs_port *msm_uport = &q_uart_port[pdev->id]; - - msm_hs_request_clock_on(&msm_uport->uport); - return 0; -} - -static int msm_hs_runtime_suspend(struct device *dev) -{ - struct platform_device *pdev = container_of(dev, struct - platform_device, dev); - struct msm_hs_port *msm_uport = &q_uart_port[pdev->id]; - - msm_hs_request_clock_off(&msm_uport->uport); - return 0; -} -#else -#define msm_hs_runtime_idle NULL -#define msm_hs_runtime_resume NULL -#define msm_hs_runtime_suspend NULL -#endif - -static const struct dev_pm_ops msm_hs_dev_pm_ops = { - .runtime_suspend = msm_hs_runtime_suspend, - .runtime_resume = msm_hs_runtime_resume, - .runtime_idle = msm_hs_runtime_idle, -}; - -static struct platform_driver msm_serial_hs_platform_driver = { - .probe = msm_hs_probe, - .remove = msm_hs_remove, - .driver = { - .name = "msm_serial_hs", - .pm = &msm_hs_dev_pm_ops, - }, -}; - -static struct uart_driver msm_hs_driver = { - .owner = THIS_MODULE, - .driver_name = "msm_serial_hs", - .dev_name = "ttyHS", - .nr = UARTDM_NR, - .cons = 0, -}; - -static struct uart_ops msm_hs_ops = { - .tx_empty = msm_hs_tx_empty, - .set_mctrl = msm_hs_set_mctrl_locked, - .get_mctrl = msm_hs_get_mctrl_locked, - .stop_tx = msm_hs_stop_tx_locked, - .start_tx = msm_hs_start_tx_locked, - .stop_rx = msm_hs_stop_rx_locked, - .enable_ms = msm_hs_enable_ms_locked, - .break_ctl = msm_hs_break_ctl, - .startup = msm_hs_startup, - .shutdown = msm_hs_shutdown, - .set_termios = msm_hs_set_termios, - .pm = msm_hs_pm, - .type = msm_hs_type, - .config_port = msm_hs_config_port, - .release_port = msm_hs_release_port, - .request_port = msm_hs_request_port, -}; - -MODULE_DESCRIPTION("High Speed UART Driver for the MSM chipset"); -MODULE_VERSION("1.2"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index d1298b6cc68e..f7e5825b55ab 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -176,7 +176,7 @@ static struct platform_device_id mxs_auart_devtype[] = { }; MODULE_DEVICE_TABLE(platform, mxs_auart_devtype); -static struct of_device_id mxs_auart_dt_ids[] = { +static const struct of_device_id mxs_auart_dt_ids[] = { { .compatible = "fsl,imx28-auart", .data = &mxs_auart_devtype[IMX28_AUART] @@ -1155,14 +1155,14 @@ static int serial_mxs_probe_dt(struct mxs_auart_port *s, return 0; } -static bool mxs_auart_init_gpios(struct mxs_auart_port *s, struct device *dev) +static int mxs_auart_init_gpios(struct mxs_auart_port *s, struct device *dev) { enum mctrl_gpio_idx i; struct gpio_desc *gpiod; s->gpios = mctrl_gpio_init(dev, 0); - if (IS_ERR_OR_NULL(s->gpios)) - return false; + if (IS_ERR(s->gpios)) + return PTR_ERR(s->gpios); /* Block (enabled before) DMA option if RTS or CTS is GPIO line */ if (!RTS_AT_AUART() || !CTS_AT_AUART()) { @@ -1180,7 +1180,7 @@ static bool mxs_auart_init_gpios(struct mxs_auart_port *s, struct device *dev) s->gpio_irq[i] = -EINVAL; } - return true; + return 0; } static void mxs_auart_free_gpio_irq(struct mxs_auart_port *s) @@ -1276,9 +1276,11 @@ static int mxs_auart_probe(struct platform_device *pdev) platform_set_drvdata(pdev, s); - if (!mxs_auart_init_gpios(s, &pdev->dev)) - dev_err(&pdev->dev, - "Failed to initialize GPIOs. The serial port may not work as expected\n"); + ret = mxs_auart_init_gpios(s, &pdev->dev); + if (ret) { + dev_err(&pdev->dev, "Failed to initialize GPIOs.\n"); + return ret; + } /* * Get the GPIO lines IRQ diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c index 33fb94f78967..aa00154c4a6d 100644 --- a/drivers/tty/serial/of_serial.c +++ b/drivers/tty/serial/of_serial.c @@ -89,6 +89,7 @@ static int of_platform_serial_setup(struct platform_device *ofdev, spin_lock_init(&port->lock); port->mapbase = resource.start; + port->mapsize = resource_size(&resource); /* Check for shifted address mapping */ if (of_property_read_u32(np, "reg-offset", &prop) == 0) @@ -155,7 +156,7 @@ out: /* * Try to register a serial port */ -static struct of_device_id of_platform_serial_table[]; +static const struct of_device_id of_platform_serial_table[]; static int of_platform_serial_probe(struct platform_device *ofdev) { const struct of_device_id *match; @@ -320,7 +321,7 @@ static SIMPLE_DEV_PM_OPS(of_serial_pm_ops, of_serial_suspend, of_serial_resume); /* * A few common types, add more as needed. */ -static struct of_device_id of_platform_serial_table[] = { +static const struct of_device_id of_platform_serial_table[] = { { .compatible = "ns8250", .data = (void *)PORT_8250, }, { .compatible = "ns16450", .data = (void *)PORT_16450, }, { .compatible = "ns16550a", .data = (void *)PORT_16550A, }, diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 10256fa04b40..211479aa34bb 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -1654,11 +1654,6 @@ static int serial_omap_probe(struct platform_device *pdev) up->port.type = PORT_OMAP; up->port.iotype = UPIO_MEM; up->port.irq = uartirq; - up->wakeirq = wakeirq; - if (!up->wakeirq) - dev_info(up->port.dev, "no wakeirq for uart%d\n", - up->port.line); - up->port.regshift = 2; up->port.fifosize = 64; up->port.ops = &serial_omap_pops; @@ -1682,6 +1677,11 @@ static int serial_omap_probe(struct platform_device *pdev) goto err_port_line; } + up->wakeirq = wakeirq; + if (!up->wakeirq) + dev_info(up->port.dev, "no wakeirq for uart%d\n", + up->port.line); + ret = serial_omap_probe_rs485(up, pdev->dev.of_node); if (ret < 0) goto err_rs485; diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index 8f515799c9c1..e156e39d620c 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -1846,7 +1846,7 @@ static int __init pmz_register(void) #ifdef CONFIG_PPC_PMAC -static struct of_device_id pmz_match[] = +static const struct of_device_id pmz_match[] = { { .name = "ch-a", diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c index d5d062694bd3..9becba654892 100644 --- a/drivers/tty/serial/pxa.c +++ b/drivers/tty/serial/pxa.c @@ -824,7 +824,7 @@ static const struct dev_pm_ops serial_pxa_pm_ops = { }; #endif -static struct of_device_id serial_pxa_dt_ids[] = { +static const struct of_device_id serial_pxa_dt_ids[] = { { .compatible = "mrvl,pxa-uart", }, { .compatible = "mrvl,mmp-uart", }, {} diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index df9a384dfbda..468354ef7baa 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -829,16 +829,32 @@ static void sc16is7xx_set_termios(struct uart_port *port, } static int sc16is7xx_config_rs485(struct uart_port *port, - struct serial_rs485 *rs485) + struct serial_rs485 *rs485) { - if (port->rs485.flags & SER_RS485_ENABLED) - sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, - SC16IS7XX_EFCR_AUTO_RS485_BIT, - SC16IS7XX_EFCR_AUTO_RS485_BIT); - else - sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, - SC16IS7XX_EFCR_AUTO_RS485_BIT, - 0); + const u32 mask = SC16IS7XX_EFCR_AUTO_RS485_BIT | + SC16IS7XX_EFCR_RTS_INVERT_BIT; + u32 efcr = 0; + + if (rs485->flags & SER_RS485_ENABLED) { + bool rts_during_rx, rts_during_tx; + + rts_during_rx = rs485->flags & SER_RS485_RTS_AFTER_SEND; + rts_during_tx = rs485->flags & SER_RS485_RTS_ON_SEND; + + efcr |= SC16IS7XX_EFCR_AUTO_RS485_BIT; + + if (!rts_during_rx && rts_during_tx) + /* default */; + else if (rts_during_rx && !rts_during_tx) + efcr |= SC16IS7XX_EFCR_RTS_INVERT_BIT; + else + dev_err(port->dev, + "unsupported RTS signalling on_send:%d after_send:%d - exactly one of RS485 RTS flags should be set\n", + rts_during_tx, rts_during_rx); + } + + sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, mask, efcr); + port->rs485 = *rs485; return 0; @@ -903,9 +919,11 @@ static void sc16is7xx_shutdown(struct uart_port *port) /* Disable all interrupts */ sc16is7xx_port_write(port, SC16IS7XX_IER_REG, 0); /* Disable TX/RX */ - sc16is7xx_port_write(port, SC16IS7XX_EFCR_REG, - SC16IS7XX_EFCR_RXDISABLE_BIT | - SC16IS7XX_EFCR_TXDISABLE_BIT); + sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, + SC16IS7XX_EFCR_RXDISABLE_BIT | + SC16IS7XX_EFCR_TXDISABLE_BIT, + SC16IS7XX_EFCR_RXDISABLE_BIT | + SC16IS7XX_EFCR_TXDISABLE_BIT); sc16is7xx_power(port, 0); } @@ -1048,6 +1066,7 @@ static int sc16is7xx_probe(struct device *dev, else return PTR_ERR(s->clk); } else { + clk_prepare_enable(s->clk); freq = clk_get_rate(s->clk); } @@ -1120,6 +1139,9 @@ static int sc16is7xx_probe(struct device *dev, if (!ret) return 0; + for (i = 0; i < s->uart.nr; i++) + uart_remove_one_port(&s->uart, &s->p[i].port); + mutex_destroy(&s->mutex); #ifdef CONFIG_GPIOLIB diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c index 48e6e41636b2..1d5ea3964ee5 100644 --- a/drivers/tty/serial/serial-tegra.c +++ b/drivers/tty/serial/serial-tegra.c @@ -1251,7 +1251,7 @@ static struct tegra_uart_chip_data tegra30_uart_chip_data = { .support_clk_src_div = true, }; -static struct of_device_id tegra_uart_of_match[] = { +static const struct of_device_id tegra_uart_of_match[] = { { .compatible = "nvidia,tegra30-hsuart", .data = &tegra30_uart_chip_data, diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 6a1055ae3437..eb5b03be9dfd 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1118,8 +1118,7 @@ uart_wait_modem_status(struct uart_state *state, unsigned long arg) cprev = cnow; } - - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); remove_wait_queue(&port->delta_msr_wait, &wait); return ret; @@ -1766,7 +1765,7 @@ static const struct file_operations uart_proc_fops = { #endif #if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL) -/* +/** * uart_console_write - write a console message to a serial port * @port: the port to write the message * @s: array of characters @@ -1810,6 +1809,52 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co) } /** + * uart_parse_earlycon - Parse earlycon options + * @p: ptr to 2nd field (ie., just beyond '<name>,') + * @iotype: ptr for decoded iotype (out) + * @addr: ptr for decoded mapbase/iobase (out) + * @options: ptr for <options> field; NULL if not present (out) + * + * Decodes earlycon kernel command line parameters of the form + * earlycon=<name>,io|mmio|mmio32,<addr>,<options> + * console=<name>,io|mmio|mmio32,<addr>,<options> + * + * The optional form + * earlycon=<name>,0x<addr>,<options> + * console=<name>,0x<addr>,<options> + * is also accepted; the returned @iotype will be UPIO_MEM. + * + * Returns 0 on success or -EINVAL on failure + */ +int uart_parse_earlycon(char *p, unsigned char *iotype, unsigned long *addr, + char **options) +{ + if (strncmp(p, "mmio,", 5) == 0) { + *iotype = UPIO_MEM; + p += 5; + } else if (strncmp(p, "mmio32,", 7) == 0) { + *iotype = UPIO_MEM32; + p += 7; + } else if (strncmp(p, "io,", 3) == 0) { + *iotype = UPIO_PORT; + p += 3; + } else if (strncmp(p, "0x", 2) == 0) { + *iotype = UPIO_MEM; + } else { + return -EINVAL; + } + + *addr = simple_strtoul(p, NULL, 0); + p = strchr(p, ','); + if (p) + p++; + + *options = p; + return 0; +} +EXPORT_SYMBOL_GPL(uart_parse_earlycon); + +/** * uart_parse_options - Parse serial port baud/parity/bits/flow control. * @options: pointer to option string * @baud: pointer to an 'int' variable for the baud rate. @@ -2637,6 +2682,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) state->pm_state = UART_PM_STATE_UNDEFINED; uport->cons = drv->cons; + uport->minor = drv->tty_driver->minor_start + uport->line; /* * If this port is a console, then the spinlock is already diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c index a38596c5194e..0ec756c62bcf 100644 --- a/drivers/tty/serial/serial_mctrl_gpio.c +++ b/drivers/tty/serial/serial_mctrl_gpio.c @@ -48,9 +48,6 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl) int value_array[UART_GPIO_MAX]; unsigned int count = 0; - if (IS_ERR_OR_NULL(gpios)) - return; - for (i = 0; i < UART_GPIO_MAX; i++) if (!IS_ERR_OR_NULL(gpios->gpio[i]) && mctrl_gpios_desc[i].dir_out) { @@ -65,10 +62,7 @@ EXPORT_SYMBOL_GPL(mctrl_gpio_set); struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios, enum mctrl_gpio_idx gidx) { - if (!IS_ERR_OR_NULL(gpios) && !IS_ERR_OR_NULL(gpios->gpio[gidx])) - return gpios->gpio[gidx]; - else - return NULL; + return gpios->gpio[gidx]; } EXPORT_SYMBOL_GPL(mctrl_gpio_to_gpiod); @@ -76,15 +70,8 @@ unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl) { enum mctrl_gpio_idx i; - /* - * return it unchanged if the structure is not allocated - */ - if (IS_ERR_OR_NULL(gpios)) - return *mctrl; - for (i = 0; i < UART_GPIO_MAX; i++) { - if (!IS_ERR_OR_NULL(gpios->gpio[i]) && - !mctrl_gpios_desc[i].dir_out) { + if (gpios->gpio[i] && !mctrl_gpios_desc[i].dir_out) { if (gpiod_get_value(gpios->gpio[i])) *mctrl |= mctrl_gpios_desc[i].mctrl; else @@ -100,34 +87,26 @@ struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx) { struct mctrl_gpios *gpios; enum mctrl_gpio_idx i; - int err; gpios = devm_kzalloc(dev, sizeof(*gpios), GFP_KERNEL); if (!gpios) return ERR_PTR(-ENOMEM); for (i = 0; i < UART_GPIO_MAX; i++) { - gpios->gpio[i] = devm_gpiod_get_index(dev, - mctrl_gpios_desc[i].name, - idx); - - /* - * The GPIOs are maybe not all filled, - * this is not an error. - */ - if (IS_ERR_OR_NULL(gpios->gpio[i])) - continue; + enum gpiod_flags flags; if (mctrl_gpios_desc[i].dir_out) - err = gpiod_direction_output(gpios->gpio[i], 0); + flags = GPIOD_OUT_LOW; else - err = gpiod_direction_input(gpios->gpio[i]); - if (err) { - dev_dbg(dev, "Unable to set direction for %s GPIO", - mctrl_gpios_desc[i].name); - devm_gpiod_put(dev, gpios->gpio[i]); - gpios->gpio[i] = NULL; - } + flags = GPIOD_IN; + + gpios->gpio[i] = + devm_gpiod_get_index_optional(dev, + mctrl_gpios_desc[i].name, + idx, flags); + + if (IS_ERR(gpios->gpio[i])) + return ERR_CAST(gpios->gpio[i]); } return gpios; @@ -138,9 +117,6 @@ void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios) { enum mctrl_gpio_idx i; - if (IS_ERR_OR_NULL(gpios)) - return; - for (i = 0; i < UART_GPIO_MAX; i++) if (!IS_ERR_OR_NULL(gpios->gpio[i])) devm_gpiod_put(dev, gpios->gpio[i]); diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 5b50c792ad5f..e7d6566fafaf 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -844,14 +844,32 @@ static int sci_handle_fifo_overrun(struct uart_port *port) struct tty_port *tport = &port->state->port; struct sci_port *s = to_sci_port(port); struct plat_sci_reg *reg; - int copied = 0; + int copied = 0, offset; + u16 status, bit; + + switch (port->type) { + case PORT_SCIF: + case PORT_HSCIF: + offset = SCLSR; + break; + case PORT_SCIFA: + case PORT_SCIFB: + offset = SCxSR; + break; + default: + return 0; + } - reg = sci_getreg(port, SCLSR); + reg = sci_getreg(port, offset); if (!reg->size) return 0; - if ((serial_port_in(port, SCLSR) & (1 << s->overrun_bit))) { - serial_port_out(port, SCLSR, 0); + status = serial_port_in(port, offset); + bit = 1 << s->overrun_bit; + + if (status & bit) { + status &= ~bit; + serial_port_out(port, offset, status); port->icount.overrun++; @@ -996,16 +1014,24 @@ static inline unsigned long port_rx_irq_mask(struct uart_port *port) static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) { - unsigned short ssr_status, scr_status, err_enabled; - unsigned short slr_status = 0; + unsigned short ssr_status, scr_status, err_enabled, orer_status = 0; struct uart_port *port = ptr; struct sci_port *s = to_sci_port(port); irqreturn_t ret = IRQ_NONE; ssr_status = serial_port_in(port, SCxSR); scr_status = serial_port_in(port, SCSCR); - if (port->type == PORT_SCIF || port->type == PORT_HSCIF) - slr_status = serial_port_in(port, SCLSR); + switch (port->type) { + case PORT_SCIF: + case PORT_HSCIF: + orer_status = serial_port_in(port, SCLSR); + break; + case PORT_SCIFA: + case PORT_SCIFB: + orer_status = ssr_status; + break; + } + err_enabled = scr_status & port_rx_irq_mask(port); /* Tx Interrupt */ @@ -1033,10 +1059,8 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) ret = sci_br_interrupt(irq, ptr); /* Overrun Interrupt */ - if (port->type == PORT_SCIF || port->type == PORT_HSCIF) { - if (slr_status & 0x01) - sci_handle_fifo_overrun(port); - } + if (orer_status & (1 << s->overrun_bit)) + sci_handle_fifo_overrun(port); return ret; } @@ -1967,18 +1991,40 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, #ifdef CONFIG_SERIAL_SH_SCI_DMA /* - * Calculate delay for 1.5 DMA buffers: see - * drivers/serial/serial_core.c::uart_update_timeout(). With 10 bits - * (CS8), 250Hz, 115200 baud and 64 bytes FIFO, the above function + * Calculate delay for 2 DMA buffers (4 FIFO). + * See drivers/serial/serial_core.c::uart_update_timeout(). With 10 + * bits (CS8), 250Hz, 115200 baud and 64 bytes FIFO, the above function * calculates 1 jiffie for the data plus 5 jiffies for the "slop(e)." - * Then below we calculate 3 jiffies (12ms) for 1.5 DMA buffers (3 FIFO - * sizes), but it has been found out experimentally, that this is not - * enough: the driver too often needlessly runs on a DMA timeout. 20ms - * as a minimum seem to work perfectly. + * Then below we calculate 5 jiffies (20ms) for 2 DMA buffers (4 FIFO + * sizes), but when performing a faster transfer, value obtained by + * this formula is may not enough. Therefore, if value is smaller than + * 20msec, this sets 20msec as timeout of DMA. */ if (s->chan_rx) { - s->rx_timeout = (port->timeout - HZ / 50) * s->buf_len_rx * 3 / - port->fifosize / 2; + unsigned int bits; + + /* byte size and parity */ + switch (termios->c_cflag & CSIZE) { + case CS5: + bits = 7; + break; + case CS6: + bits = 8; + break; + case CS7: + bits = 9; + break; + default: + bits = 10; + break; + } + + if (termios->c_cflag & CSTOPB) + bits++; + if (termios->c_cflag & PARENB) + bits++; + s->rx_timeout = DIV_ROUND_UP((s->buf_len_rx * 2 * bits * HZ) / + (baud / 10), 10); dev_dbg(port->dev, "DMA Rx t-out %ums, tty t-out %u jiffies\n", s->rx_timeout * 1000 / HZ, port->timeout); if (s->rx_timeout < msecs_to_jiffies(20)) diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c index 27ed0e960880..9de3eabe5737 100644 --- a/drivers/tty/serial/sirfsoc_uart.c +++ b/drivers/tty/serial/sirfsoc_uart.c @@ -1269,7 +1269,7 @@ static struct uart_driver sirfsoc_uart_drv = { #endif }; -static struct of_device_id sirfsoc_uart_ids[] = { +static const struct of_device_id sirfsoc_uart_ids[] = { { .compatible = "sirf,prima2-uart", .data = &sirfsoc_uart,}, { .compatible = "sirf,atlas7-uart", .data = &sirfsoc_uart}, { .compatible = "sirf,prima2-usp-uart", .data = &sirfsoc_usp}, diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c index bca975f5093b..582d2729f700 100644 --- a/drivers/tty/serial/sprd_serial.c +++ b/drivers/tty/serial/sprd_serial.c @@ -493,6 +493,8 @@ static int sprd_verify_port(struct uart_port *port, return -EINVAL; if (port->irq != ser->irq) return -EINVAL; + if (port->iotype != ser->io_type) + return -EINVAL; return 0; } @@ -707,7 +709,7 @@ static int sprd_probe(struct platform_device *pdev) up->dev = &pdev->dev; up->line = index; up->type = PORT_SPRD; - up->iotype = SERIAL_IO_PORT; + up->iotype = UPIO_MEM; up->uartclk = SPRD_DEF_RATE; up->fifosize = SPRD_FIFO_SIZE; up->ops = &serial_sprd_ops; @@ -754,6 +756,7 @@ static int sprd_probe(struct platform_device *pdev) return ret; } +#ifdef CONFIG_PM_SLEEP static int sprd_suspend(struct device *dev) { struct sprd_uart_port *sup = dev_get_drvdata(dev); @@ -771,6 +774,7 @@ static int sprd_resume(struct device *dev) return 0; } +#endif static SIMPLE_DEV_PM_OPS(sprd_pm_ops, sprd_suspend, sprd_resume); diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c index 712b03a076b8..d625664ce1b5 100644 --- a/drivers/tty/serial/st-asc.c +++ b/drivers/tty/serial/st-asc.c @@ -720,7 +720,7 @@ static struct asc_port *asc_of_get_asc_port(struct platform_device *pdev) } #ifdef CONFIG_OF -static struct of_device_id asc_match[] = { +static const struct of_device_id asc_match[] = { { .compatible = "st,asc", }, {}, }; diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c index 189f52e3111f..708eead850b0 100644 --- a/drivers/tty/serial/uartlite.c +++ b/drivers/tty/serial/uartlite.c @@ -622,7 +622,7 @@ static int ulite_release(struct device *dev) #if defined(CONFIG_OF) /* Match table for of_platform binding */ -static struct of_device_id ulite_of_match[] = { +static const struct of_device_id ulite_of_match[] = { { .compatible = "xlnx,opb-uartlite-1.00.b", }, { .compatible = "xlnx,xps-uartlite-1.00.a", }, {} diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c index 14d10fcfd210..7d2532b23969 100644 --- a/drivers/tty/serial/ucc_uart.c +++ b/drivers/tty/serial/ucc_uart.c @@ -1473,7 +1473,7 @@ static int ucc_uart_remove(struct platform_device *ofdev) return 0; } -static struct of_device_id ucc_uart_match[] = { +static const struct of_device_id ucc_uart_match[] = { { .type = "serial", .compatible = "ucc_uart", diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index cff531a51a78..f218ec658f5d 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -37,10 +37,7 @@ #define CDNS_UART_MINOR 0 /* works best with devtmpfs */ #define CDNS_UART_NR_PORTS 2 #define CDNS_UART_FIFO_SIZE 64 /* FIFO size */ -#define CDNS_UART_REGISTER_SPACE 0xFFF - -#define cdns_uart_readl(offset) ioread32(port->membase + offset) -#define cdns_uart_writel(val, offset) iowrite32(val, port->membase + offset) +#define CDNS_UART_REGISTER_SPACE 0x1000 /* Rx Trigger level */ static int rx_trigger_level = 56; @@ -195,7 +192,7 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id) /* Read the interrupt status register to determine which * interrupt(s) is/are active. */ - isrstatus = cdns_uart_readl(CDNS_UART_ISR_OFFSET); + isrstatus = readl(port->membase + CDNS_UART_ISR_OFFSET); /* * There is no hardware break detection, so we interpret framing @@ -203,14 +200,15 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id) * there's another non-zero byte at the end of the sequence. */ if (isrstatus & CDNS_UART_IXR_FRAMING) { - while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) & + while (!(readl(port->membase + CDNS_UART_SR_OFFSET) & CDNS_UART_SR_RXEMPTY)) { - if (!cdns_uart_readl(CDNS_UART_FIFO_OFFSET)) { + if (!readl(port->membase + CDNS_UART_FIFO_OFFSET)) { port->read_status_mask |= CDNS_UART_IXR_BRK; isrstatus &= ~CDNS_UART_IXR_FRAMING; } } - cdns_uart_writel(CDNS_UART_IXR_FRAMING, CDNS_UART_ISR_OFFSET); + writel(CDNS_UART_IXR_FRAMING, + port->membase + CDNS_UART_ISR_OFFSET); } /* drop byte with parity error if IGNPAR specified */ @@ -223,9 +221,9 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id) if ((isrstatus & CDNS_UART_IXR_TOUT) || (isrstatus & CDNS_UART_IXR_RXTRIG)) { /* Receive Timeout Interrupt */ - while ((cdns_uart_readl(CDNS_UART_SR_OFFSET) & - CDNS_UART_SR_RXEMPTY) != CDNS_UART_SR_RXEMPTY) { - data = cdns_uart_readl(CDNS_UART_FIFO_OFFSET); + while (!(readl(port->membase + CDNS_UART_SR_OFFSET) & + CDNS_UART_SR_RXEMPTY)) { + data = readl(port->membase + CDNS_UART_FIFO_OFFSET); /* Non-NULL byte after BREAK is garbage (99%) */ if (data && (port->read_status_mask & @@ -275,8 +273,8 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id) /* Dispatch an appropriate handler */ if ((isrstatus & CDNS_UART_IXR_TXEMPTY) == CDNS_UART_IXR_TXEMPTY) { if (uart_circ_empty(&port->state->xmit)) { - cdns_uart_writel(CDNS_UART_IXR_TXEMPTY, - CDNS_UART_IDR_OFFSET); + writel(CDNS_UART_IXR_TXEMPTY, + port->membase + CDNS_UART_IDR_OFFSET); } else { numbytes = port->fifosize; /* Break if no more data available in the UART buffer */ @@ -287,9 +285,9 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id) * and write it to the cdns_uart's TX_FIFO * register. */ - cdns_uart_writel( - port->state->xmit.buf[port->state->xmit. - tail], CDNS_UART_FIFO_OFFSET); + writel(port->state->xmit.buf[ + port->state->xmit.tail], + port->membase + CDNS_UART_FIFO_OFFSET); port->icount.tx++; @@ -307,7 +305,7 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id) } } - cdns_uart_writel(isrstatus, CDNS_UART_ISR_OFFSET); + writel(isrstatus, port->membase + CDNS_UART_ISR_OFFSET); /* be sure to release the lock and tty before leaving */ spin_unlock_irqrestore(&port->lock, flags); @@ -397,14 +395,14 @@ static unsigned int cdns_uart_set_baud_rate(struct uart_port *port, &div8); /* Write new divisors to hardware */ - mreg = cdns_uart_readl(CDNS_UART_MR_OFFSET); + mreg = readl(port->membase + CDNS_UART_MR_OFFSET); if (div8) mreg |= CDNS_UART_MR_CLKSEL; else mreg &= ~CDNS_UART_MR_CLKSEL; - cdns_uart_writel(mreg, CDNS_UART_MR_OFFSET); - cdns_uart_writel(cd, CDNS_UART_BAUDGEN_OFFSET); - cdns_uart_writel(bdiv, CDNS_UART_BAUDDIV_OFFSET); + writel(mreg, port->membase + CDNS_UART_MR_OFFSET); + writel(cd, port->membase + CDNS_UART_BAUDGEN_OFFSET); + writel(bdiv, port->membase + CDNS_UART_BAUDDIV_OFFSET); cdns_uart->baud = baud; return calc_baud; @@ -451,9 +449,9 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb, spin_lock_irqsave(&cdns_uart->port->lock, flags); /* Disable the TX and RX to set baud rate */ - ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); + ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET); ctrl_reg |= CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS; - cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); + writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET); spin_unlock_irqrestore(&cdns_uart->port->lock, flags); @@ -478,11 +476,11 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb, spin_lock_irqsave(&cdns_uart->port->lock, flags); /* Set TX/RX Reset */ - ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); + ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET); ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST; - cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); + writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET); - while (cdns_uart_readl(CDNS_UART_CR_OFFSET) & + while (readl(port->membase + CDNS_UART_CR_OFFSET) & (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST)) cpu_relax(); @@ -491,11 +489,11 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb, * enable bit and RX enable bit to enable the transmitter and * receiver. */ - cdns_uart_writel(rx_timeout, CDNS_UART_RXTOUT_OFFSET); - ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); + writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET); + ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET); ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS); ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN; - cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); + writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET); spin_unlock_irqrestore(&cdns_uart->port->lock, flags); @@ -517,14 +515,14 @@ static void cdns_uart_start_tx(struct uart_port *port) if (uart_circ_empty(&port->state->xmit) || uart_tx_stopped(port)) return; - status = cdns_uart_readl(CDNS_UART_CR_OFFSET); + status = readl(port->membase + CDNS_UART_CR_OFFSET); /* Set the TX enable bit and clear the TX disable bit to enable the * transmitter. */ - cdns_uart_writel((status & ~CDNS_UART_CR_TX_DIS) | CDNS_UART_CR_TX_EN, - CDNS_UART_CR_OFFSET); + writel((status & ~CDNS_UART_CR_TX_DIS) | CDNS_UART_CR_TX_EN, + port->membase + CDNS_UART_CR_OFFSET); - while (numbytes-- && ((cdns_uart_readl(CDNS_UART_SR_OFFSET) & + while (numbytes-- && ((readl(port->membase + CDNS_UART_SR_OFFSET) & CDNS_UART_SR_TXFULL)) != CDNS_UART_SR_TXFULL) { /* Break if no more data available in the UART buffer */ if (uart_circ_empty(&port->state->xmit)) @@ -533,9 +531,8 @@ static void cdns_uart_start_tx(struct uart_port *port) /* Get the data from the UART circular buffer and * write it to the cdns_uart's TX_FIFO register. */ - cdns_uart_writel( - port->state->xmit.buf[port->state->xmit.tail], - CDNS_UART_FIFO_OFFSET); + writel(port->state->xmit.buf[port->state->xmit.tail], + port->membase + CDNS_UART_FIFO_OFFSET); port->icount.tx++; /* Adjust the tail of the UART buffer and wrap @@ -544,9 +541,9 @@ static void cdns_uart_start_tx(struct uart_port *port) port->state->xmit.tail = (port->state->xmit.tail + 1) & (UART_XMIT_SIZE - 1); } - cdns_uart_writel(CDNS_UART_IXR_TXEMPTY, CDNS_UART_ISR_OFFSET); + writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_ISR_OFFSET); /* Enable the TX Empty interrupt */ - cdns_uart_writel(CDNS_UART_IXR_TXEMPTY, CDNS_UART_IER_OFFSET); + writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IER_OFFSET); if (uart_circ_chars_pending(&port->state->xmit) < WAKEUP_CHARS) uart_write_wakeup(port); @@ -560,10 +557,10 @@ static void cdns_uart_stop_tx(struct uart_port *port) { unsigned int regval; - regval = cdns_uart_readl(CDNS_UART_CR_OFFSET); + regval = readl(port->membase + CDNS_UART_CR_OFFSET); regval |= CDNS_UART_CR_TX_DIS; /* Disable the transmitter */ - cdns_uart_writel(regval, CDNS_UART_CR_OFFSET); + writel(regval, port->membase + CDNS_UART_CR_OFFSET); } /** @@ -574,10 +571,10 @@ static void cdns_uart_stop_rx(struct uart_port *port) { unsigned int regval; - regval = cdns_uart_readl(CDNS_UART_CR_OFFSET); + regval = readl(port->membase + CDNS_UART_CR_OFFSET); regval |= CDNS_UART_CR_RX_DIS; /* Disable the receiver */ - cdns_uart_writel(regval, CDNS_UART_CR_OFFSET); + writel(regval, port->membase + CDNS_UART_CR_OFFSET); } /** @@ -590,7 +587,8 @@ static unsigned int cdns_uart_tx_empty(struct uart_port *port) { unsigned int status; - status = cdns_uart_readl(CDNS_UART_SR_OFFSET) & CDNS_UART_SR_TXEMPTY; + status = readl(port->membase + CDNS_UART_SR_OFFSET) & + CDNS_UART_SR_TXEMPTY; return status ? TIOCSER_TEMT : 0; } @@ -607,15 +605,15 @@ static void cdns_uart_break_ctl(struct uart_port *port, int ctl) spin_lock_irqsave(&port->lock, flags); - status = cdns_uart_readl(CDNS_UART_CR_OFFSET); + status = readl(port->membase + CDNS_UART_CR_OFFSET); if (ctl == -1) - cdns_uart_writel(CDNS_UART_CR_STARTBRK | status, - CDNS_UART_CR_OFFSET); + writel(CDNS_UART_CR_STARTBRK | status, + port->membase + CDNS_UART_CR_OFFSET); else { if ((status & CDNS_UART_CR_STOPBRK) == 0) - cdns_uart_writel(CDNS_UART_CR_STOPBRK | status, - CDNS_UART_CR_OFFSET); + writel(CDNS_UART_CR_STOPBRK | status, + port->membase + CDNS_UART_CR_OFFSET); } spin_unlock_irqrestore(&port->lock, flags); } @@ -638,17 +636,18 @@ static void cdns_uart_set_termios(struct uart_port *port, spin_lock_irqsave(&port->lock, flags); /* Wait for the transmit FIFO to empty before making changes */ - if (!(cdns_uart_readl(CDNS_UART_CR_OFFSET) & CDNS_UART_CR_TX_DIS)) { - while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) & + if (!(readl(port->membase + CDNS_UART_CR_OFFSET) & + CDNS_UART_CR_TX_DIS)) { + while (!(readl(port->membase + CDNS_UART_SR_OFFSET) & CDNS_UART_SR_TXEMPTY)) { cpu_relax(); } } /* Disable the TX and RX to set baud rate */ - ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); + ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET); ctrl_reg |= CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS; - cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); + writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET); /* * Min baud rate = 6bps and Max Baud Rate is 10Mbps for 100Mhz clk @@ -667,20 +666,20 @@ static void cdns_uart_set_termios(struct uart_port *port, uart_update_timeout(port, termios->c_cflag, baud); /* Set TX/RX Reset */ - ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); + ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET); ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST; - cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); + writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET); /* * Clear the RX disable and TX disable bits and then set the TX enable * bit and RX enable bit to enable the transmitter and receiver. */ - ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); + ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET); ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS); ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN; - cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); + writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET); - cdns_uart_writel(rx_timeout, CDNS_UART_RXTOUT_OFFSET); + writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET); port->read_status_mask = CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_RXTRIG | CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_TOUT; @@ -700,7 +699,7 @@ static void cdns_uart_set_termios(struct uart_port *port, CDNS_UART_IXR_TOUT | CDNS_UART_IXR_PARITY | CDNS_UART_IXR_FRAMING | CDNS_UART_IXR_OVERRUN; - mode_reg = cdns_uart_readl(CDNS_UART_MR_OFFSET); + mode_reg = readl(port->membase + CDNS_UART_MR_OFFSET); /* Handling Data Size */ switch (termios->c_cflag & CSIZE) { @@ -741,7 +740,7 @@ static void cdns_uart_set_termios(struct uart_port *port, cval |= CDNS_UART_MR_PARITY_NONE; } cval |= mode_reg & 1; - cdns_uart_writel(cval, CDNS_UART_MR_OFFSET); + writel(cval, port->membase + CDNS_UART_MR_OFFSET); spin_unlock_irqrestore(&port->lock, flags); } @@ -762,52 +761,53 @@ static int cdns_uart_startup(struct uart_port *port) return retval; /* Disable the TX and RX */ - cdns_uart_writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS, - CDNS_UART_CR_OFFSET); + writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS, + port->membase + CDNS_UART_CR_OFFSET); /* Set the Control Register with TX/RX Enable, TX/RX Reset, * no break chars. */ - cdns_uart_writel(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST, - CDNS_UART_CR_OFFSET); + writel(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST, + port->membase + CDNS_UART_CR_OFFSET); - status = cdns_uart_readl(CDNS_UART_CR_OFFSET); + status = readl(port->membase + CDNS_UART_CR_OFFSET); /* Clear the RX disable and TX disable bits and then set the TX enable * bit and RX enable bit to enable the transmitter and receiver. */ - cdns_uart_writel((status & ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS)) + writel((status & ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS)) | (CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN | - CDNS_UART_CR_STOPBRK), CDNS_UART_CR_OFFSET); + CDNS_UART_CR_STOPBRK), + port->membase + CDNS_UART_CR_OFFSET); /* Set the Mode Register with normal mode,8 data bits,1 stop bit, * no parity. */ - cdns_uart_writel(CDNS_UART_MR_CHMODE_NORM | CDNS_UART_MR_STOPMODE_1_BIT + writel(CDNS_UART_MR_CHMODE_NORM | CDNS_UART_MR_STOPMODE_1_BIT | CDNS_UART_MR_PARITY_NONE | CDNS_UART_MR_CHARLEN_8_BIT, - CDNS_UART_MR_OFFSET); + port->membase + CDNS_UART_MR_OFFSET); /* * Set the RX FIFO Trigger level to use most of the FIFO, but it * can be tuned with a module parameter */ - cdns_uart_writel(rx_trigger_level, CDNS_UART_RXWM_OFFSET); + writel(rx_trigger_level, port->membase + CDNS_UART_RXWM_OFFSET); /* * Receive Timeout register is enabled but it * can be tuned with a module parameter */ - cdns_uart_writel(rx_timeout, CDNS_UART_RXTOUT_OFFSET); + writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET); /* Clear out any pending interrupts before enabling them */ - cdns_uart_writel(cdns_uart_readl(CDNS_UART_ISR_OFFSET), - CDNS_UART_ISR_OFFSET); + writel(readl(port->membase + CDNS_UART_ISR_OFFSET), + port->membase + CDNS_UART_ISR_OFFSET); /* Set the Interrupt Registers with desired interrupts */ - cdns_uart_writel(CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_PARITY | + writel(CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_PARITY | CDNS_UART_IXR_FRAMING | CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_RXTRIG | CDNS_UART_IXR_TOUT, - CDNS_UART_IER_OFFSET); + port->membase + CDNS_UART_IER_OFFSET); return retval; } @@ -821,12 +821,12 @@ static void cdns_uart_shutdown(struct uart_port *port) int status; /* Disable interrupts */ - status = cdns_uart_readl(CDNS_UART_IMR_OFFSET); - cdns_uart_writel(status, CDNS_UART_IDR_OFFSET); + status = readl(port->membase + CDNS_UART_IMR_OFFSET); + writel(status, port->membase + CDNS_UART_IDR_OFFSET); /* Disable the TX and RX */ - cdns_uart_writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS, - CDNS_UART_CR_OFFSET); + writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS, + port->membase + CDNS_UART_CR_OFFSET); free_irq(port->irq, port); } @@ -928,7 +928,7 @@ static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) { u32 val; - val = cdns_uart_readl(CDNS_UART_MODEMCR_OFFSET); + val = readl(port->membase + CDNS_UART_MODEMCR_OFFSET); val &= ~(CDNS_UART_MODEMCR_RTS | CDNS_UART_MODEMCR_DTR); @@ -937,7 +937,7 @@ static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) if (mctrl & TIOCM_DTR) val |= CDNS_UART_MODEMCR_DTR; - cdns_uart_writel(val, CDNS_UART_MODEMCR_OFFSET); + writel(val, port->membase + CDNS_UART_MODEMCR_OFFSET); } #ifdef CONFIG_CONSOLE_POLL @@ -947,17 +947,18 @@ static int cdns_uart_poll_get_char(struct uart_port *port) int c; /* Disable all interrupts */ - imr = cdns_uart_readl(CDNS_UART_IMR_OFFSET); - cdns_uart_writel(imr, CDNS_UART_IDR_OFFSET); + imr = readl(port->membase + CDNS_UART_IMR_OFFSET); + writel(imr, port->membase + CDNS_UART_IDR_OFFSET); /* Check if FIFO is empty */ - if (cdns_uart_readl(CDNS_UART_SR_OFFSET) & CDNS_UART_SR_RXEMPTY) + if (readl(port->membase + CDNS_UART_SR_OFFSET) & CDNS_UART_SR_RXEMPTY) c = NO_POLL_CHAR; else /* Read a character */ - c = (unsigned char) cdns_uart_readl(CDNS_UART_FIFO_OFFSET); + c = (unsigned char) readl( + port->membase + CDNS_UART_FIFO_OFFSET); /* Enable interrupts */ - cdns_uart_writel(imr, CDNS_UART_IER_OFFSET); + writel(imr, port->membase + CDNS_UART_IER_OFFSET); return c; } @@ -967,22 +968,24 @@ static void cdns_uart_poll_put_char(struct uart_port *port, unsigned char c) u32 imr; /* Disable all interrupts */ - imr = cdns_uart_readl(CDNS_UART_IMR_OFFSET); - cdns_uart_writel(imr, CDNS_UART_IDR_OFFSET); + imr = readl(port->membase + CDNS_UART_IMR_OFFSET); + writel(imr, port->membase + CDNS_UART_IDR_OFFSET); /* Wait until FIFO is empty */ - while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) & CDNS_UART_SR_TXEMPTY)) + while (!(readl(port->membase + CDNS_UART_SR_OFFSET) & + CDNS_UART_SR_TXEMPTY)) cpu_relax(); /* Write a character */ - cdns_uart_writel(c, CDNS_UART_FIFO_OFFSET); + writel(c, port->membase + CDNS_UART_FIFO_OFFSET); /* Wait until FIFO is empty */ - while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) & CDNS_UART_SR_TXEMPTY)) + while (!(readl(port->membase + CDNS_UART_SR_OFFSET) & + CDNS_UART_SR_TXEMPTY)) cpu_relax(); /* Enable interrupts */ - cdns_uart_writel(imr, CDNS_UART_IER_OFFSET); + writel(imr, port->membase + CDNS_UART_IER_OFFSET); return; } @@ -1010,7 +1013,7 @@ static struct uart_ops cdns_uart_ops = { #endif }; -static struct uart_port cdns_uart_port[2]; +static struct uart_port cdns_uart_port[CDNS_UART_NR_PORTS]; /** * cdns_uart_get_port - Configure the port from platform device resource info @@ -1038,7 +1041,6 @@ static struct uart_port *cdns_uart_get_port(int id) /* At this point, we've got an empty uart_port struct, initialize it */ spin_lock_init(&port->lock); port->membase = NULL; - port->iobase = 1; /* mark port in use */ port->irq = 0; port->type = PORT_UNKNOWN; port->iotype = UPIO_MEM32; @@ -1057,8 +1059,8 @@ static struct uart_port *cdns_uart_get_port(int id) */ static void cdns_uart_console_wait_tx(struct uart_port *port) { - while ((cdns_uart_readl(CDNS_UART_SR_OFFSET) & CDNS_UART_SR_TXEMPTY) - != CDNS_UART_SR_TXEMPTY) + while (!(readl(port->membase + CDNS_UART_SR_OFFSET) & + CDNS_UART_SR_TXEMPTY)) barrier(); } @@ -1070,7 +1072,7 @@ static void cdns_uart_console_wait_tx(struct uart_port *port) static void cdns_uart_console_putchar(struct uart_port *port, int ch) { cdns_uart_console_wait_tx(port); - cdns_uart_writel(ch, CDNS_UART_FIFO_OFFSET); + writel(ch, port->membase + CDNS_UART_FIFO_OFFSET); } static void cdns_early_write(struct console *con, const char *s, unsigned n) @@ -1112,24 +1114,24 @@ static void cdns_uart_console_write(struct console *co, const char *s, spin_lock_irqsave(&port->lock, flags); /* save and disable interrupt */ - imr = cdns_uart_readl(CDNS_UART_IMR_OFFSET); - cdns_uart_writel(imr, CDNS_UART_IDR_OFFSET); + imr = readl(port->membase + CDNS_UART_IMR_OFFSET); + writel(imr, port->membase + CDNS_UART_IDR_OFFSET); /* * Make sure that the tx part is enabled. Set the TX enable bit and * clear the TX disable bit to enable the transmitter. */ - ctrl = cdns_uart_readl(CDNS_UART_CR_OFFSET); - cdns_uart_writel((ctrl & ~CDNS_UART_CR_TX_DIS) | CDNS_UART_CR_TX_EN, - CDNS_UART_CR_OFFSET); + ctrl = readl(port->membase + CDNS_UART_CR_OFFSET); + writel((ctrl & ~CDNS_UART_CR_TX_DIS) | CDNS_UART_CR_TX_EN, + port->membase + CDNS_UART_CR_OFFSET); uart_console_write(port, s, count, cdns_uart_console_putchar); cdns_uart_console_wait_tx(port); - cdns_uart_writel(ctrl, CDNS_UART_CR_OFFSET); + writel(ctrl, port->membase + CDNS_UART_CR_OFFSET); /* restore interrupt state */ - cdns_uart_writel(imr, CDNS_UART_IER_OFFSET); + writel(imr, port->membase + CDNS_UART_IER_OFFSET); if (locked) spin_unlock_irqrestore(&port->lock, flags); @@ -1153,8 +1155,9 @@ static int __init cdns_uart_console_setup(struct console *co, char *options) if (co->index < 0 || co->index >= CDNS_UART_NR_PORTS) return -EINVAL; - if (!port->mapbase) { - pr_debug("console on ttyPS%i not present\n", co->index); + if (!port->membase) { + pr_debug("console on " CDNS_UART_TTY_NAME "%i not present\n", + co->index); return -ENODEV; } @@ -1240,13 +1243,14 @@ static int cdns_uart_suspend(struct device *device) spin_lock_irqsave(&port->lock, flags); /* Empty the receive FIFO 1st before making changes */ - while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) & + while (!(readl(port->membase + CDNS_UART_SR_OFFSET) & CDNS_UART_SR_RXEMPTY)) - cdns_uart_readl(CDNS_UART_FIFO_OFFSET); + readl(port->membase + CDNS_UART_FIFO_OFFSET); /* set RX trigger level to 1 */ - cdns_uart_writel(1, CDNS_UART_RXWM_OFFSET); + writel(1, port->membase + CDNS_UART_RXWM_OFFSET); /* disable RX timeout interrups */ - cdns_uart_writel(CDNS_UART_IXR_TOUT, CDNS_UART_IDR_OFFSET); + writel(CDNS_UART_IXR_TOUT, + port->membase + CDNS_UART_IDR_OFFSET); spin_unlock_irqrestore(&port->lock, flags); } @@ -1285,28 +1289,30 @@ static int cdns_uart_resume(struct device *device) spin_lock_irqsave(&port->lock, flags); /* Set TX/RX Reset */ - ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); + ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET); ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST; - cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); - while (cdns_uart_readl(CDNS_UART_CR_OFFSET) & + writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET); + while (readl(port->membase + CDNS_UART_CR_OFFSET) & (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST)) cpu_relax(); /* restore rx timeout value */ - cdns_uart_writel(rx_timeout, CDNS_UART_RXTOUT_OFFSET); + writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET); /* Enable Tx/Rx */ - ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); + ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET); ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS); ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN; - cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); + writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET); spin_unlock_irqrestore(&port->lock, flags); } else { spin_lock_irqsave(&port->lock, flags); /* restore original rx trigger level */ - cdns_uart_writel(rx_trigger_level, CDNS_UART_RXWM_OFFSET); + writel(rx_trigger_level, + port->membase + CDNS_UART_RXWM_OFFSET); /* enable RX timeout interrupt */ - cdns_uart_writel(CDNS_UART_IXR_TOUT, CDNS_UART_IER_OFFSET); + writel(CDNS_UART_IXR_TOUT, + port->membase + CDNS_UART_IER_OFFSET); spin_unlock_irqrestore(&port->lock, flags); } @@ -1458,7 +1464,7 @@ static int cdns_uart_remove(struct platform_device *pdev) } /* Match table for of_platform binding */ -static struct of_device_id cdns_uart_of_match[] = { +static const struct of_device_id cdns_uart_of_match[] = { { .compatible = "xlnx,xuartps", }, { .compatible = "cdns,uart-r1p8", }, {} diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 2bb4dfc02873..e5695467598f 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1025,11 +1025,17 @@ void start_tty(struct tty_struct *tty) } EXPORT_SYMBOL(start_tty); -/* We limit tty time update visibility to every 8 seconds or so. */ static void tty_update_time(struct timespec *time) { unsigned long sec = get_seconds(); - if (abs(sec - time->tv_sec) & ~7) + + /* + * We only care if the two values differ in anything other than the + * lower three bits (i.e every 8 seconds). If so, then we can update + * the time of the tty device, otherwise it could be construded as a + * security leak to let userspace know the exact timing of the tty. + */ + if ((sec ^ time->tv_sec) & ~7) time->tv_sec = sec; } @@ -3593,6 +3599,13 @@ static ssize_t show_cons_active(struct device *dev, } static DEVICE_ATTR(active, S_IRUGO, show_cons_active, NULL); +static struct attribute *cons_dev_attrs[] = { + &dev_attr_active.attr, + NULL +}; + +ATTRIBUTE_GROUPS(cons_dev); + static struct device *consdev; void console_sysfs_notify(void) @@ -3617,12 +3630,11 @@ int __init tty_init(void) if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0) panic("Couldn't register /dev/console driver\n"); - consdev = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL, - "console"); + consdev = device_create_with_groups(tty_class, NULL, + MKDEV(TTYAUX_MAJOR, 1), NULL, + cons_dev_groups, "console"); if (IS_ERR(consdev)) consdev = NULL; - else - WARN_ON(device_create_file(consdev, &dev_attr_active) < 0); #ifdef CONFIG_VT vty_init(&console_fops); diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 6e00572cbeb9..4a24eb2b0ede 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1237,7 +1237,7 @@ static void default_attr(struct vc_data *vc) struct rgb { u8 r; u8 g; u8 b; }; -struct rgb rgb_from_256(int i) +static struct rgb rgb_from_256(int i) { struct rgb c; if (i < 8) { /* Standard colours. */ @@ -1573,7 +1573,7 @@ static void setterm_command(struct vc_data *vc) case 11: /* set bell duration in msec */ if (vc->vc_npar >= 1) vc->vc_bell_duration = (vc->vc_par[1] < 2000) ? - vc->vc_par[1] * HZ / 1000 : 0; + msecs_to_jiffies(vc->vc_par[1]) : 0; else vc->vc_bell_duration = DEFAULT_BELL_DURATION; break; @@ -3041,17 +3041,24 @@ static ssize_t show_tty_active(struct device *dev, } static DEVICE_ATTR(active, S_IRUGO, show_tty_active, NULL); +static struct attribute *vt_dev_attrs[] = { + &dev_attr_active.attr, + NULL +}; + +ATTRIBUTE_GROUPS(vt_dev); + int __init vty_init(const struct file_operations *console_fops) { cdev_init(&vc0_cdev, console_fops); if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) || register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0) panic("Couldn't register /dev/tty0 driver\n"); - tty0dev = device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0"); + tty0dev = device_create_with_groups(tty_class, NULL, + MKDEV(TTY_MAJOR, 0), NULL, + vt_dev_groups, "tty0"); if (IS_ERR(tty0dev)) tty0dev = NULL; - else - WARN_ON(device_create_file(tty0dev, &dev_attr_active) < 0); vcs_init(); @@ -3423,42 +3430,26 @@ static ssize_t show_name(struct device *dev, struct device_attribute *attr, } -static struct device_attribute device_attrs[] = { - __ATTR(bind, S_IRUGO|S_IWUSR, show_bind, store_bind), - __ATTR(name, S_IRUGO, show_name, NULL), +static DEVICE_ATTR(bind, S_IRUGO|S_IWUSR, show_bind, store_bind); +static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); + +static struct attribute *con_dev_attrs[] = { + &dev_attr_bind.attr, + &dev_attr_name.attr, + NULL }; +ATTRIBUTE_GROUPS(con_dev); + static int vtconsole_init_device(struct con_driver *con) { - int i; - int error = 0; - con->flag |= CON_DRIVER_FLAG_ATTR; - dev_set_drvdata(con->dev, con); - for (i = 0; i < ARRAY_SIZE(device_attrs); i++) { - error = device_create_file(con->dev, &device_attrs[i]); - if (error) - break; - } - - if (error) { - while (--i >= 0) - device_remove_file(con->dev, &device_attrs[i]); - con->flag &= ~CON_DRIVER_FLAG_ATTR; - } - - return error; + return 0; } static void vtconsole_deinit_device(struct con_driver *con) { - int i; - - if (con->flag & CON_DRIVER_FLAG_ATTR) { - for (i = 0; i < ARRAY_SIZE(device_attrs); i++) - device_remove_file(con->dev, &device_attrs[i]); - con->flag &= ~CON_DRIVER_FLAG_ATTR; - } + con->flag &= ~CON_DRIVER_FLAG_ATTR; } /** @@ -3621,11 +3612,11 @@ static int do_register_con_driver(const struct consw *csw, int first, int last) if (retval) goto err; - con_driver->dev = device_create(vtconsole_class, NULL, - MKDEV(0, con_driver->node), - NULL, "vtcon%i", - con_driver->node); - + con_driver->dev = + device_create_with_groups(vtconsole_class, NULL, + MKDEV(0, con_driver->node), + con_driver, con_dev_groups, + "vtcon%i", con_driver->node); if (IS_ERR(con_driver->dev)) { printk(KERN_WARNING "Unable to create device for %s; " "errno = %ld\n", con_driver->desc, @@ -3739,10 +3730,11 @@ static int __init vtconsole_class_init(void) struct con_driver *con = ®istered_con_driver[i]; if (con->con && !con->dev) { - con->dev = device_create(vtconsole_class, NULL, - MKDEV(0, con->node), - NULL, "vtcon%i", - con->node); + con->dev = + device_create_with_groups(vtconsole_class, NULL, + MKDEV(0, con->node), + con, con_dev_groups, + "vtcon%i", con->node); if (IS_ERR(con->dev)) { printk(KERN_WARNING "Unable to create " diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 2bd78e2ac8ec..97d5a74558a3 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -388,7 +388,7 @@ int vt_ioctl(struct tty_struct *tty, * Generate the tone for the appropriate number of ticks. * If the time is zero, turn off sound ourselves. */ - ticks = HZ * ((arg >> 16) & 0xffff) / 1000; + ticks = msecs_to_jiffies((arg >> 16) & 0xffff); count = ticks ? (arg & 0xffff) : 0; if (count) count = PIT_TICK_RATE / count; diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 5c48c58514e5..8bd374d3cf21 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -153,6 +153,14 @@ #define TRACE_SYSCALLS() #endif +#ifdef CONFIG_SERIAL_EARLYCON +#define EARLYCON_TABLE() STRUCT_ALIGN(); \ + VMLINUX_SYMBOL(__earlycon_table) = .; \ + *(__earlycon_table) \ + *(__earlycon_table_end) +#else +#define EARLYCON_TABLE() +#endif #define ___OF_TABLE(cfg, name) _OF_TABLE_##cfg(name) #define __OF_TABLE(cfg, name) ___OF_TABLE(cfg, name) @@ -508,6 +516,7 @@ CPUIDLE_METHOD_OF_TABLES() \ KERNEL_DTB() \ IRQCHIP_OF_MATCH_TABLE() \ + EARLYCON_TABLE() \ EARLYCON_OF_TABLES() #define INIT_TEXT \ diff --git a/include/linux/console.h b/include/linux/console.h index 7571a16bd653..9f50fb413c11 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -123,7 +123,7 @@ struct console { struct tty_driver *(*device)(struct console *, int *); void (*unblank)(void); int (*setup)(struct console *, char *); - int (*early_setup)(void); + int (*match)(struct console *, char *name, int idx, char *options); short flags; short index; int cflag; @@ -141,7 +141,6 @@ extern int console_set_on_cmdline; extern struct console *early_console; extern int add_preferred_console(char *name, int idx, char *options); -extern int update_console_cmdline(char *name, int idx, char *name_new, int idx_new, char *options); extern void register_console(struct console *); extern int unregister_console(struct console *); extern struct console *console_drivers; diff --git a/include/linux/dma/hsu.h b/include/linux/dma/hsu.h new file mode 100644 index 000000000000..234393a6997b --- /dev/null +++ b/include/linux/dma/hsu.h @@ -0,0 +1,48 @@ +/* + * Driver for the High Speed UART DMA + * + * Copyright (C) 2015 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _DMA_HSU_H +#define _DMA_HSU_H + +#include <linux/device.h> +#include <linux/interrupt.h> + +#include <linux/platform_data/dma-hsu.h> + +struct hsu_dma; + +/** + * struct hsu_dma_chip - representation of HSU DMA hardware + * @dev: struct device of the DMA controller + * @irq: irq line + * @regs: memory mapped I/O space + * @length: I/O space length + * @offset: offset of the I/O space where registers are located + * @hsu: struct hsu_dma that is filed by ->probe() + * @pdata: platform data for the DMA controller if provided + */ +struct hsu_dma_chip { + struct device *dev; + int irq; + void __iomem *regs; + unsigned int length; + unsigned int offset; + struct hsu_dma *hsu; + struct hsu_dma_platform_data *pdata; +}; + +/* Export to the internal users */ +irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr); + +/* Export to the platform drivers */ +int hsu_dma_probe(struct hsu_dma_chip *chip); +int hsu_dma_remove(struct hsu_dma_chip *chip); + +#endif /* _DMA_HSU_H */ diff --git a/include/linux/platform_data/dma-hsu.h b/include/linux/platform_data/dma-hsu.h new file mode 100644 index 000000000000..8a1f6a4920b2 --- /dev/null +++ b/include/linux/platform_data/dma-hsu.h @@ -0,0 +1,25 @@ +/* + * Driver for the High Speed UART DMA + * + * Copyright (C) 2015 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _PLATFORM_DATA_DMA_HSU_H +#define _PLATFORM_DATA_DMA_HSU_H + +#include <linux/device.h> + +struct hsu_dma_slave { + struct device *dma_dev; + int chan_id; +}; + +struct hsu_dma_platform_data { + unsigned short nr_channels; +}; + +#endif /* _PLATFORM_DATA_DMA_HSU_H */ diff --git a/include/linux/platform_data/msm_serial_hs.h b/include/linux/platform_data/msm_serial_hs.h deleted file mode 100644 index 98a2046f8b31..000000000000 --- a/include/linux/platform_data/msm_serial_hs.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2008 Google, Inc. - * Author: Nick Pelly <npelly@google.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef __ASM_ARCH_MSM_SERIAL_HS_H -#define __ASM_ARCH_MSM_SERIAL_HS_H - -#include <linux/serial_core.h> - -/* API to request the uart clock off or on for low power management - * Clients should call request_clock_off() when no uart data is expected, - * and must call request_clock_on() before any further uart data can be - * received. */ -extern void msm_hs_request_clock_off(struct uart_port *uport); -extern void msm_hs_request_clock_on(struct uart_port *uport); - -/** - * struct msm_serial_hs_platform_data - * @rx_wakeup_irq: Rx activity irq - * @rx_to_inject: extra character to be inserted to Rx tty on wakeup - * @inject_rx: 1 = insert rx_to_inject. 0 = do not insert extra character - * @exit_lpm_cb: function called before every Tx transaction - * - * This is an optional structure required for UART Rx GPIO IRQ based - * wakeup from low power state. UART wakeup can be triggered by RX activity - * (using a wakeup GPIO on the UART RX pin). This should only be used if - * there is not a wakeup GPIO on the UART CTS, and the first RX byte is - * known (eg., with the Bluetooth Texas Instruments HCILL protocol), - * since the first RX byte will always be lost. RTS will be asserted even - * while the UART is clocked off in this mode of operation. - */ -struct msm_serial_hs_platform_data { - int rx_wakeup_irq; - unsigned char inject_rx_on_wakeup; - char rx_to_inject; - void (*exit_lpm_cb)(struct uart_port *); -}; - -#endif diff --git a/include/linux/platform_data/serial-imx.h b/include/linux/platform_data/serial-imx.h index 3cc2e3c40914..a938eba2f18e 100644 --- a/include/linux/platform_data/serial-imx.h +++ b/include/linux/platform_data/serial-imx.h @@ -20,14 +20,9 @@ #define ASMARM_ARCH_UART_H #define IMXUART_HAVE_RTSCTS (1<<0) -#define IMXUART_IRDA (1<<1) struct imxuart_platform_data { unsigned int flags; - void (*irda_enable)(int enable); - unsigned int irda_inv_rx:1; - unsigned int irda_inv_tx:1; - unsigned short transceiver_delay; }; #endif diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index a8efa235b7c1..78097e7a330a 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -60,6 +60,20 @@ enum { }; struct uart_8250_dma; +struct uart_8250_port; + +/** + * 8250 core driver operations + * + * @setup_irq() Setup irq handling. The universal 8250 driver links this + * port to the irq chain. Other drivers may @request_irq(). + * @release_irq() Undo irq handling. The universal 8250 driver unlinks + * the port from the irq chain. + */ +struct uart_8250_ops { + int (*setup_irq)(struct uart_8250_port *); + void (*release_irq)(struct uart_8250_port *); +}; /* * This should be used by drivers which want to register @@ -88,6 +102,8 @@ struct uart_8250_port { unsigned char canary; /* non-zero during system sleep * if no_console_suspend */ + unsigned char probe; +#define UART_PROBE_RSA (1 << 0) /* * Some bits in registers are cleared on a read, so they must @@ -100,6 +116,7 @@ struct uart_8250_port { unsigned char msr_saved_flags; struct uart_8250_dma *dma; + const struct uart_8250_ops *ops; /* 8250 specific callbacks */ int (*dl_read)(struct uart_8250_port *); @@ -118,11 +135,8 @@ void serial8250_resume_port(int line); extern int early_serial_setup(struct uart_port *port); -extern int serial8250_find_port(struct uart_port *p); -extern int serial8250_find_port_for_earlycon(void); extern unsigned int serial8250_early_in(struct uart_port *port, int offset); extern void serial8250_early_out(struct uart_port *port, int offset, int value); -extern int setup_early_serial8250_console(char *cmdline); extern void serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old); extern int serial8250_do_startup(struct uart_port *port); diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index d10965f0d8a4..025dad9dcde4 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -235,7 +235,9 @@ struct uart_port { const struct uart_ops *ops; unsigned int custom_divisor; unsigned int line; /* port index */ + unsigned int minor; resource_size_t mapbase; /* for ioremap */ + resource_size_t mapsize; struct device *dev; /* parent device */ unsigned char hub6; /* this should be in the 8250 driver */ unsigned char suspended; @@ -336,24 +338,29 @@ struct earlycon_device { char options[16]; /* e.g., 115200n8 */ unsigned int baud; }; -int setup_earlycon(char *buf, const char *match, - int (*setup)(struct earlycon_device *, const char *)); +struct earlycon_id { + char name[16]; + int (*setup)(struct earlycon_device *, const char *options); +} __aligned(32); + +extern int setup_earlycon(char *buf); extern int of_setup_earlycon(unsigned long addr, int (*setup)(struct earlycon_device *, const char *)); -#define EARLYCON_DECLARE(name, func) \ -static int __init name ## _setup_earlycon(char *buf) \ -{ \ - return setup_earlycon(buf, __stringify(name), func); \ -} \ -early_param("earlycon", name ## _setup_earlycon); +#define EARLYCON_DECLARE(_name, func) \ + static const struct earlycon_id __earlycon_##_name \ + __used __section(__earlycon_table) \ + = { .name = __stringify(_name), \ + .setup = func } #define OF_EARLYCON_DECLARE(name, compat, fn) \ _OF_DECLARE(earlycon, name, compat, fn, void *) struct uart_port *uart_get_console(struct uart_port *ports, int nr, struct console *c); +int uart_parse_earlycon(char *p, unsigned char *iotype, unsigned long *addr, + char **options); void uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow); int uart_set_options(struct uart_port *port, struct console *co, int baud, diff --git a/include/linux/serial_mfd.h b/include/linux/serial_mfd.h deleted file mode 100644 index 2b071e0b034d..000000000000 --- a/include/linux/serial_mfd.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef _SERIAL_MFD_H_ -#define _SERIAL_MFD_H_ - -/* HW register offset definition */ -#define UART_FOR 0x08 -#define UART_PS 0x0C -#define UART_MUL 0x0D -#define UART_DIV 0x0E - -#define HSU_GBL_IEN 0x0 -#define HSU_GBL_IST 0x4 - -#define HSU_GBL_INT_BIT_PORT0 0x0 -#define HSU_GBL_INT_BIT_PORT1 0x1 -#define HSU_GBL_INT_BIT_PORT2 0x2 -#define HSU_GBL_INT_BIT_IRI 0x3 -#define HSU_GBL_INT_BIT_HDLC 0x4 -#define HSU_GBL_INT_BIT_DMA 0x5 - -#define HSU_GBL_ISR 0x8 -#define HSU_GBL_DMASR 0x400 -#define HSU_GBL_DMAISR 0x404 - -#define HSU_PORT_REG_OFFSET 0x80 -#define HSU_PORT0_REG_OFFSET 0x80 -#define HSU_PORT1_REG_OFFSET 0x100 -#define HSU_PORT2_REG_OFFSET 0x180 -#define HSU_PORT_REG_LENGTH 0x80 - -#define HSU_DMA_CHANS_REG_OFFSET 0x500 -#define HSU_DMA_CHANS_REG_LENGTH 0x40 - -#define HSU_CH_SR 0x0 /* channel status reg */ -#define HSU_CH_CR 0x4 /* control reg */ -#define HSU_CH_DCR 0x8 /* descriptor control reg */ -#define HSU_CH_BSR 0x10 /* max fifo buffer size reg */ -#define HSU_CH_MOTSR 0x14 /* minimum ocp transfer size */ -#define HSU_CH_D0SAR 0x20 /* desc 0 start addr */ -#define HSU_CH_D0TSR 0x24 /* desc 0 transfer size */ -#define HSU_CH_D1SAR 0x28 -#define HSU_CH_D1TSR 0x2C -#define HSU_CH_D2SAR 0x30 -#define HSU_CH_D2TSR 0x34 -#define HSU_CH_D3SAR 0x38 -#define HSU_CH_D3TSR 0x3C - -#endif diff --git a/include/uapi/linux/serial_reg.h b/include/uapi/linux/serial_reg.h index 00adb01fa5f3..e9b4cb0cd7ed 100644 --- a/include/uapi/linux/serial_reg.h +++ b/include/uapi/linux/serial_reg.h @@ -242,25 +242,6 @@ #define UART_FCR_PXAR32 0xc0 /* receive FIFO threshold = 32 */ /* - * Intel MID on-chip HSU (High Speed UART) defined bits - */ -#define UART_FCR_HSU_64_1B 0x00 /* receive FIFO treshold = 1 */ -#define UART_FCR_HSU_64_16B 0x40 /* receive FIFO treshold = 16 */ -#define UART_FCR_HSU_64_32B 0x80 /* receive FIFO treshold = 32 */ -#define UART_FCR_HSU_64_56B 0xc0 /* receive FIFO treshold = 56 */ - -#define UART_FCR_HSU_16_1B 0x00 /* receive FIFO treshold = 1 */ -#define UART_FCR_HSU_16_4B 0x40 /* receive FIFO treshold = 4 */ -#define UART_FCR_HSU_16_8B 0x80 /* receive FIFO treshold = 8 */ -#define UART_FCR_HSU_16_14B 0xc0 /* receive FIFO treshold = 14 */ - -#define UART_FCR_HSU_64B_FIFO 0x20 /* chose 64 bytes FIFO */ -#define UART_FCR_HSU_16B_FIFO 0x00 /* chose 16 bytes FIFO */ - -#define UART_FCR_HALF_EMPT_TXI 0x00 /* trigger TX_EMPT IRQ for half empty */ -#define UART_FCR_FULL_EMPT_TXI 0x08 /* trigger TX_EMPT IRQ for full empty */ - -/* * These register definitions are for the 16C950 */ #define UART_ASR 0x01 /* Additional Status Register */ diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 879edfc5ee52..c099b082cd02 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -2017,24 +2017,6 @@ int add_preferred_console(char *name, int idx, char *options) return __add_preferred_console(name, idx, options, NULL); } -int update_console_cmdline(char *name, int idx, char *name_new, int idx_new, char *options) -{ - struct console_cmdline *c; - int i; - - for (i = 0, c = console_cmdline; - i < MAX_CMDLINECONSOLES && c->name[0]; - i++, c++) - if (strcmp(c->name, name) == 0 && c->index == idx) { - strlcpy(c->name, name_new, sizeof(c->name)); - c->options = options; - c->index = idx_new; - return i; - } - /* not found */ - return -1; -} - bool console_suspend_enabled = true; EXPORT_SYMBOL(console_suspend_enabled); @@ -2436,9 +2418,6 @@ void register_console(struct console *newcon) if (preferred_console < 0 || bcon || !console_drivers) preferred_console = selected_console; - if (newcon->early_setup) - newcon->early_setup(); - /* * See if we want to use this console driver. If we * didn't select a console we take the first one @@ -2464,23 +2443,27 @@ void register_console(struct console *newcon) for (i = 0, c = console_cmdline; i < MAX_CMDLINECONSOLES && c->name[0]; i++, c++) { - BUILD_BUG_ON(sizeof(c->name) != sizeof(newcon->name)); - if (strcmp(c->name, newcon->name) != 0) - continue; - if (newcon->index >= 0 && - newcon->index != c->index) - continue; - if (newcon->index < 0) - newcon->index = c->index; + if (!newcon->match || + newcon->match(newcon, c->name, c->index, c->options) != 0) { + /* default matching */ + BUILD_BUG_ON(sizeof(c->name) != sizeof(newcon->name)); + if (strcmp(c->name, newcon->name) != 0) + continue; + if (newcon->index >= 0 && + newcon->index != c->index) + continue; + if (newcon->index < 0) + newcon->index = c->index; - if (_braille_register_console(newcon, c)) - return; + if (_braille_register_console(newcon, c)) + return; + + if (newcon->setup && + newcon->setup(newcon, c->options) != 0) + break; + } - if (newcon->setup && - newcon->setup(newcon, console_cmdline[i].options) != 0) - break; newcon->flags |= CON_ENABLED; - newcon->index = c->index; if (i == selected_console) { newcon->flags |= CON_CONSDEV; preferred_console = selected_console; |