mirror of
https://github.com/torvalds/linux.git
synced 2024-11-26 14:12:06 +00:00
TTY/Serial patches for 4.1-rc1
Here's the big tty/serial driver update for 4.1-rc1. It was delayed for a bit due to some questions surrounding some of the console command line parsing changes that are in here. There's still one tiny regression for people who were previously putting multiple console command lines and expecting them all to be ignored for some odd reason, but Peter is working on fixing that. If not, I'll send a revert for the offending patch, but I have faith that Peter can address it. Other than the console work here, there's the usual serial driver updates and changes, and a buch of 8250 reworks to try to make that driver easier to maintain over time, and have it support more devices in the future. All of these have been in linux-next for a while. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iEYEABECAAYFAlU2IcUACgkQMUfUDdst+ylFqACcC8LPhFEZg9aHn0hNUoqGK3rE 5dUAnR4b8r/NYqjVoE9FJZgZfB/TqVi1 =lyN/ -----END PGP SIGNATURE----- Merge tag 'tty-4.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty Pull tty/serial updates from Greg KH: "Here's the big tty/serial driver update for 4.1-rc1. It was delayed for a bit due to some questions surrounding some of the console command line parsing changes that are in here. There's still one tiny regression for people who were previously putting multiple console command lines and expecting them all to be ignored for some odd reason, but Peter is working on fixing that. If not, I'll send a revert for the offending patch, but I have faith that Peter can address it. Other than the console work here, there's the usual serial driver updates and changes, and a buch of 8250 reworks to try to make that driver easier to maintain over time, and have it support more devices in the future. All of these have been in linux-next for a while" * tag 'tty-4.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (119 commits) n_gsm: Drop unneeded cast on netdev_priv sc16is7xx: expose RTS inversion in RS-485 mode serial: 8250_pci: port failed after wakeup from S3 earlycon: 8250: Document kernel command line options earlycon: 8250: Fix command line regression earlycon: Fix __earlycon_table stride tty: clean up the tty time logic a bit serial: 8250_dw: only get the clock rate in one place serial: 8250_dw: remove useless ACPI ID check dmaengine: hsu: move memory allocation to GFP_NOWAIT dmaengine: hsu: remove redundant pieces of code serial: 8250_pci: add Intel Tangier support dmaengine: hsu: add Intel Tangier PCI ID serial: 8250_pci: replace switch-case by formula for Intel MID serial: 8250_pci: replace switch-case by formula tty: cpm_uart: replace CONFIG_8xx by CONFIG_CPM1 serial: jsm: some off by one bugs serial: xuartps: Fix check in console_setup(). serial: xuartps: Get rid of register access macros. serial: xuartps: Fix iobase use. ...
This commit is contained in:
commit
41d5e08ea8
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 \
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
};
|
@ -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
|
||||
|
@ -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
|
||||
|
14
drivers/dma/hsu/Kconfig
Normal file
14
drivers/dma/hsu/Kconfig
Normal file
@ -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.
|
5
drivers/dma/hsu/Makefile
Normal file
5
drivers/dma/hsu/Makefile
Normal file
@ -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
|
495
drivers/dma/hsu/hsu.c
Normal file
495
drivers/dma/hsu/hsu.c
Normal file
@ -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>");
|
118
drivers/dma/hsu/hsu.h
Normal file
118
drivers/dma/hsu/hsu.h
Normal file
@ -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__ */
|
124
drivers/dma/hsu/pci.c
Normal file
124
drivers/dma/hsu/pci.c
Normal file
@ -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>");
|
@ -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
|
||||
|
@ -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" },
|
||||
{ },
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
/* link port to console */
|
||||
port->cons = co;
|
||||
|
||||
return serial8250_console_setup(port, options, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
char match[] = "uart"; /* 8250-specific earlycon name */
|
||||
unsigned char iotype;
|
||||
unsigned long addr;
|
||||
int i;
|
||||
|
||||
if (strncmp(name, match, 4) != 0)
|
||||
return -ENODEV;
|
||||
|
||||
if (options)
|
||||
uart_parse_options(options, &baud, &parity, &bits, &flow);
|
||||
if (uart_parse_earlycon(options, &iotype, &addr, &options))
|
||||
return -ENODEV;
|
||||
|
||||
return uart_set_options(port, co, baud, parity, bits, flow);
|
||||
/* 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 int serial8250_console_early_setup(void)
|
||||
{
|
||||
return serial8250_find_port_for_earlycon();
|
||||
}
|
||||
|
||||
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);
|
||||
console_initcall(univ8250_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;
|
||||
}
|
||||
|
||||
#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 (up->port.flags & UPF_FIXED_TYPE)
|
||||
serial8250_init_fixed_type_port(uart, up->port.type);
|
||||
if (skip_txen_test)
|
||||
uart->port.flags |= UPF_NO_TXEN_TEST;
|
||||
|
||||
if (up->port.flags & UPF_FIXED_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;
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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,97 +1690,73 @@ 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;
|
||||
u32 bar_data[3];
|
||||
u16 iobase;
|
||||
|
||||
/*
|
||||
* Find each UARTs offset in PCI configuraion space
|
||||
*/
|
||||
switch (idx) {
|
||||
case 0:
|
||||
config_base = 0x40;
|
||||
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;
|
||||
break;
|
||||
default:
|
||||
/* Unknown number of ports, get out of here */
|
||||
return -EINVAL;
|
||||
}
|
||||
config_base = 0x40 + 0x08 * idx;
|
||||
|
||||
if (idx < 4) {
|
||||
base = pci_resource_start(priv->dev, 3);
|
||||
ciobase = (int)(base + (0x8 * idx));
|
||||
}
|
||||
/* Get the io address from configuration space */
|
||||
pci_read_config_word(pdev, config_base + 4, &iobase);
|
||||
|
||||
/* 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;
|
||||
|
||||
dev_dbg(&pdev->dev, "%s: idx=%d iobase=0x%lx ciobase=0x%lx config_base=0x%2x\n",
|
||||
__func__, idx, iobase, ciobase, config_base);
|
||||
|
||||
/* Enable UART I/O port */
|
||||
pci_write_config_byte(pdev, config_base + 0x00, 0x01);
|
||||
|
||||
/* Select 128-byte FIFO and 8x FIFO threshold */
|
||||
pci_write_config_byte(pdev, config_base + 0x01, 0x33);
|
||||
|
||||
/* LSB UART */
|
||||
pci_write_config_byte(pdev, config_base + 0x04, (u8)(iobase & 0xff));
|
||||
|
||||
/* MSB UART */
|
||||
pci_write_config_byte(pdev, config_base + 0x05, (u8)((iobase & 0xff00) >> 8));
|
||||
|
||||
/* irq number, this usually fails, but the spec says to do it anyway. */
|
||||
pci_write_config_byte(pdev, config_base + 0x06, pdev->irq);
|
||||
dev_dbg(&pdev->dev, "%s: idx=%d iobase=0x%x", __func__, idx, iobase);
|
||||
|
||||
port->port.iotype = UPIO_PORT;
|
||||
port->port.iobase = iobase;
|
||||
port->port.mapbase = 0;
|
||||
port->port.membase = NULL;
|
||||
port->port.regshift = 0;
|
||||
|
||||
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;
|
||||
|
||||
switch (dev->device) {
|
||||
case 0x1104: /* 4 ports */
|
||||
case 0x1108: /* 8 ports */
|
||||
max_port = dev->device & 0xff;
|
||||
break;
|
||||
case 0x1112: /* 12 ports */
|
||||
max_port = 12;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Get the io address dispatch from the BIOS */
|
||||
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]);
|
||||
|
||||
for (i = 0; i < max_port; ++i) {
|
||||
/* UART0 configuration offset start from 0x40 */
|
||||
config_base = 0x40 + 0x08 * i;
|
||||
|
||||
/* Calculate Real IO Port */
|
||||
iobase = (bar_data[i / 4] & 0xffffffe0) + (i % 4) * 8;
|
||||
|
||||
/* Enable UART I/O port */
|
||||
pci_write_config_byte(dev, config_base + 0x00, 0x01);
|
||||
|
||||
/* Select 128-byte FIFO and 8x FIFO threshold */
|
||||
pci_write_config_byte(dev, config_base + 0x01, 0x33);
|
||||
|
||||
/* LSB UART */
|
||||
pci_write_config_byte(dev, config_base + 0x04,
|
||||
(u8)(iobase & 0xff));
|
||||
|
||||
/* MSB UART */
|
||||
pci_write_config_byte(dev, config_base + 0x05,
|
||||
(u8)((iobase & 0xff00) >> 8));
|
||||
|
||||
pci_write_config_byte(dev, config_base + 0x06, dev->irq);
|
||||
}
|
||||
|
||||
return max_port;
|
||||
}
|
||||
|
||||
static int skip_tx_en_setup(struct serial_private *priv,
|
||||
const struct pciserial_board *board,
|
||||
struct uart_8250_port *port, int idx)
|
||||
@ -1987,6 +2103,34 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = byt_serial_setup,
|
||||
},
|
||||
{
|
||||
.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,
|
||||
@ -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,
|
||||
@ -5362,6 +5521,26 @@ static struct pci_device_id serial_pci_tbl[] = {
|
||||
PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000,
|
||||
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
|
||||
*/
|
||||
@ -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,
|
||||
};
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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",
|
||||
},
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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",
|
||||
},
|
||||
|
@ -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 *))
|
||||
{
|
||||
|
@ -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",
|
||||
},
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
@ -1374,15 +1279,6 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
unsigned long num, denom;
|
||||
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.
|
||||
*/
|
||||
@ -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
|
||||
*/
|
||||
div = 1;
|
||||
} else {
|
||||
/* custom-baudrate handling */
|
||||
div = sport->port.uartclk / (baud * 16);
|
||||
if (baud == 38400 && quot != div)
|
||||
baud = sport->port.uartclk / (quot * 16);
|
||||
/* 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;
|
||||
}
|
||||
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;
|
||||
|
@ -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];
|
||||
|
@ -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];
|
||||
|
@ -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;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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, },
|
||||
|
@ -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 */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
@ -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, },
|
||||
|
@ -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;
|
||||
|
@ -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",
|
||||
|
@ -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", },
|
||||
{}
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
@ -1809,6 +1808,52 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co)
|
||||
return ports + idx;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@ -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
|
||||
|
@ -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]);
|
||||
|
@ -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;
|
||||
|
||||
reg = sci_getreg(port, SCLSR);
|
||||
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, 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))
|
||||
|
@ -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},
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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", },
|
||||
{},
|
||||
};
|
||||
|
@ -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", },
|
||||
{}
|
||||
|
@ -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",
|
||||
|
@ -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", },
|
||||
{}
|
||||
|
@ -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);
|
||||
|
@ -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 "
|
||||
|
@ -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;
|
||||
|
@ -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 \
|
||||
|
@ -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;
|
||||
|
48
include/linux/dma/hsu.h
Normal file
48
include/linux/dma/hsu.h
Normal file
@ -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 */
|
25
include/linux/platform_data/dma-hsu.h
Normal file
25
include/linux/platform_data/dma-hsu.h
Normal file
@ -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 */
|
@ -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
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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
|
@ -241,25 +241,6 @@
|
||||
#define UART_FCR_PXAR16 0x80 /* receive FIFO threshold = 16 */
|
||||
#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
|
||||
*/
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user