1
0
Fork 0

TTY/Serial driver patches for 3.20-rc1

Here's the big tty/serial driver update for 3.20-rc1.  Nothing huge
 here, just lots of driver updates and some core tty layer fixes as well.
 All have been in linux-next with no reported issues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iEYEABECAAYFAlTgtgkACgkQMUfUDdst+ykXbACg14oFAmeYjO9RsdIHPXBvKseO
 47QAn0foy91bpNQ5UFOxWS5L6Fzj2ZND
 =syx2
 -----END PGP SIGNATURE-----

Merge tag 'tty-3.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty

Pull tty/serial driver patches from Greg KH:
 "Here's the big tty/serial driver update for 3.20-rc1.  Nothing huge
  here, just lots of driver updates and some core tty layer fixes as
  well.  All have been in linux-next with no reported issues"

* tag 'tty-3.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (119 commits)
  serial: 8250: Fix UART_BUG_TXEN workaround
  serial: driver for ETRAX FS UART
  tty: remove unused variable sprop
  serial: of-serial: fetch line number from DT
  serial: samsung: earlycon support depends on CONFIG_SERIAL_SAMSUNG_CONSOLE
  tty/serial: serial8250_set_divisor() can be static
  tty/serial: Add Spreadtrum sc9836-uart driver support
  Documentation: DT: Add bindings for Spreadtrum SoC Platform
  serial: samsung: remove redundant interrupt enabling
  tty: Remove external interface for tty_set_termios()
  serial: omap: Fix RTS handling
  serial: 8250_omap: Use UPSTAT_AUTORTS for RTS handling
  serial: core: Rework hw-assisted flow control support
  tty/serial: 8250_early: Add support for PXA UARTs
  tty/serial: of_serial: add support for PXA/MMP uarts
  tty/serial: of_serial: add DT alias ID handling
  serial: 8250: Prevent concurrent updates to shadow registers
  serial: 8250: Use canary to restart console after suspend
  serial: 8250: Refactor XR17V35X divisor calculation
  serial: 8250: Refactor divisor programming
  ...
hifive-unleashed-5.1
Linus Torvalds 2015-02-15 11:37:02 -08:00
commit a9724125ad
73 changed files with 4523 additions and 1910 deletions

View File

@ -0,0 +1,11 @@
Spreadtrum SoC Platforms Device Tree Bindings
----------------------------------------------------
Sharkl64 is a Spreadtrum's SoC Platform which is based
on ARM 64-bit processor.
SC9836 openphone board with SC9836 SoC based on the
Sharkl64 Platform shall have the following properties.
Required root node properties:
- compatible = "sprd,sc9836-openphone", "sprd,sc9836";

View File

@ -0,0 +1,27 @@
Binding for Conexant Digicolor USART
Note: this binding is only applicable for using the USART peripheral as
UART. USART also support synchronous serial protocols like SPI and I2S. Use
the binding that matches the wiring of your system.
Required properties:
- compatible : should be "cnxt,cx92755-usart".
- reg: Should contain USART controller registers location and length.
- interrupts: Should contain a single USART controller interrupt.
- clocks: Must contain phandles to the USART clock
See ../clocks/clock-bindings.txt for details.
Note: Each UART port should have an alias correctly numbered
in "aliases" node.
Example:
aliases {
serial0 = &uart0;
};
uart0: uart@f0000740 {
compatible = "cnxt,cx92755-usart";
reg = <0xf0000740 0x20>;
clocks = <&main_clk>;
interrupts = <44>;
};

View File

@ -2,7 +2,7 @@
Required properties:
- compatible : Should be "sirf,prima2-uart", "sirf, prima2-usp-uart",
"sirf,marco-uart" or "sirf,marco-bt-uart" which means
"sirf,atlas7-uart" or "sirf,atlas7-bt-uart" which means
uart located in BT module and used for BT.
- reg : Offset and length of the register set for the device
- interrupts : Should contain uart interrupt
@ -37,7 +37,7 @@ usp@b0090000 {
for uart use in BT module,
uart6: uart@11000000 {
cell-index = <6>;
compatible = "sirf,marco-bt-uart", "sirf,marco-uart";
compatible = "sirf,atlas7-bt-uart", "sirf,atlas7-uart";
reg = <0x11000000 0x1000>;
interrupts = <0 100 0>;
clocks = <&clks 138>, <&clks 140>, <&clks 141>;

View File

@ -0,0 +1,7 @@
* Spreadtrum serial UART
Required properties:
- compatible: must be "sprd,sc9836-uart"
- reg: offset and length of the register set for the device
- interrupts: exactly one interrupt specifier
- clocks: phandles to input clocks.

View File

@ -37,6 +37,7 @@ chrp Common Hardware Reference Platform
chunghwa Chunghwa Picture Tubes Ltd.
cirrus Cirrus Logic, Inc.
cnm Chips&Media, Inc.
cnxt Conexant Systems, Inc.
cortina Cortina Systems, Inc.
cosmic Cosmic Circuits
crystalfontz Crystalfontz America, Inc.
@ -162,6 +163,7 @@ snps Synopsys, Inc.
solidrun SolidRun
sony Sony Corporation
spansion Spansion Inc.
sprd Spreadtrum Communications Inc.
st STMicroelectronics
ste ST-Ericsson
stericsson ST-Ericsson

View File

@ -970,6 +970,18 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
smh Use ARM semihosting calls for early console.
s3c2410,<addr>
s3c2412,<addr>
s3c2440,<addr>
s3c6400,<addr>
s5pv210,<addr>
exynos4210,<addr>
Use early console provided by serial driver available
on Samsung SoCs, requires selecting proper type and
a correct base address of the selected UART port. The
serial port must already be setup and configured.
Options are not yet supported.
earlyprintk= [X86,SH,BLACKFIN,ARM,M68k]
earlyprintk=vga
earlyprintk=efi

View File

@ -31,6 +31,7 @@
chosen {
bootargs ="root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC2,115200 init=/linuxrc";
stdout-path = &serial_2;
};
regulators {

View File

@ -27,6 +27,7 @@
chosen {
bootargs = "root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC1,115200 init=/linuxrc";
stdout-path = &serial_1;
};
sdhci@12530000 {

View File

@ -28,6 +28,7 @@
chosen {
bootargs = "console=ttySAC2,115200N8 root=/dev/mmcblk0p5 rootwait earlyprintk panic=5";
stdout-path = &serial_2;
};
regulators {

View File

@ -26,6 +26,7 @@
chosen {
bootargs = "console=ttySAC2,115200N8 root=/dev/mmcblk0p5 rw rootwait earlyprintk panic=5 maxcpus=1";
stdout-path = &serial_2;
};
sysram@02020000 {

View File

@ -12,6 +12,10 @@
#include "exynos4412.dtsi"
/ {
chosen {
stdout-path = &serial_1;
};
firmware@0204F000 {
compatible = "samsung,secure-firmware";
reg = <0x0204F000 0x1000>;

View File

@ -26,6 +26,7 @@
chosen {
bootargs ="console=ttySAC2,115200";
stdout-path = &serial_2;
};
firmware@0203F000 {

View File

@ -25,6 +25,7 @@
chosen {
bootargs ="root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC1,115200 init=/linuxrc";
stdout-path = &serial_1;
};
g2d@10800000 {

View File

@ -18,6 +18,10 @@
model = "FriendlyARM TINY4412 board based on Exynos4412";
compatible = "friendlyarm,tiny4412", "samsung,exynos4412", "samsung,exynos4";
chosen {
stdout-path = &serial_0;
};
memory {
reg = <0x40000000 0x40000000>;
};

View File

@ -32,6 +32,7 @@
chosen {
bootargs = "console=ttySAC2,115200N8 root=/dev/mmcblk0p5 rootwait earlyprintk panic=5";
stdout-path = &serial_2;
};
firmware@0204F000 {

View File

@ -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_mrst_console;
extern void mrst_early_console_init(void);
extern struct console early_hsu_console;
extern void hsu_early_console_init(const char *);

View File

@ -19,6 +19,7 @@
#include <linux/usb/ehci_def.h>
#include <linux/efi.h>
#include <asm/efi.h>
#include <asm/pci_x86.h>
/* Simple VGA output */
#define VGABASE (__ISA_IO_base + 0xb8000)
@ -76,7 +77,7 @@ static struct console early_vga_console = {
/* Serial functions loosely based on a similar package from Klaus P. Gerlicher */
static int early_serial_base = 0x3f8; /* ttyS0 */
static unsigned long early_serial_base = 0x3f8; /* ttyS0 */
#define XMTRDY 0x20
@ -94,13 +95,40 @@ static int early_serial_base = 0x3f8; /* ttyS0 */
#define DLL 0 /* Divisor Latch Low */
#define DLH 1 /* Divisor latch High */
static void mem32_serial_out(unsigned long addr, int offset, int value)
{
uint32_t *vaddr = (uint32_t *)addr;
/* shift implied by pointer type */
writel(value, vaddr + offset);
}
static unsigned int mem32_serial_in(unsigned long addr, int offset)
{
uint32_t *vaddr = (uint32_t *)addr;
/* shift implied by pointer type */
return readl(vaddr + offset);
}
static unsigned int io_serial_in(unsigned long addr, int offset)
{
return inb(addr + offset);
}
static void io_serial_out(unsigned long addr, int offset, int value)
{
outb(value, addr + offset);
}
static unsigned int (*serial_in)(unsigned long addr, int offset) = io_serial_in;
static void (*serial_out)(unsigned long addr, int offset, int value) = io_serial_out;
static int early_serial_putc(unsigned char ch)
{
unsigned timeout = 0xffff;
while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout)
while ((serial_in(early_serial_base, LSR) & XMTRDY) == 0 && --timeout)
cpu_relax();
outb(ch, early_serial_base + TXR);
serial_out(early_serial_base, TXR, ch);
return timeout ? 0 : -1;
}
@ -114,13 +142,28 @@ static void early_serial_write(struct console *con, const char *s, unsigned n)
}
}
static __init void early_serial_hw_init(unsigned divisor)
{
unsigned char c;
serial_out(early_serial_base, LCR, 0x3); /* 8n1 */
serial_out(early_serial_base, IER, 0); /* no interrupt */
serial_out(early_serial_base, FCR, 0); /* no fifo */
serial_out(early_serial_base, MCR, 0x3); /* DTR + RTS */
c = serial_in(early_serial_base, LCR);
serial_out(early_serial_base, LCR, c | DLAB);
serial_out(early_serial_base, DLL, divisor & 0xff);
serial_out(early_serial_base, DLH, (divisor >> 8) & 0xff);
serial_out(early_serial_base, LCR, c & ~DLAB);
}
#define DEFAULT_BAUD 9600
static __init void early_serial_init(char *s)
{
unsigned char c;
unsigned divisor;
unsigned baud = DEFAULT_BAUD;
unsigned long baud = DEFAULT_BAUD;
char *e;
if (*s == ',')
@ -145,25 +188,125 @@ static __init void early_serial_init(char *s)
s++;
}
outb(0x3, early_serial_base + LCR); /* 8n1 */
outb(0, early_serial_base + IER); /* no interrupt */
outb(0, early_serial_base + FCR); /* no fifo */
outb(0x3, early_serial_base + MCR); /* DTR + RTS */
if (*s) {
baud = simple_strtoul(s, &e, 0);
if (baud == 0 || s == e)
if (kstrtoul(s, 0, &baud) < 0 || baud == 0)
baud = DEFAULT_BAUD;
}
/* Convert from baud to divisor value */
divisor = 115200 / baud;
c = inb(early_serial_base + LCR);
outb(c | DLAB, early_serial_base + LCR);
outb(divisor & 0xff, early_serial_base + DLL);
outb((divisor >> 8) & 0xff, early_serial_base + DLH);
outb(c & ~DLAB, early_serial_base + LCR);
/* These will always be IO based ports */
serial_in = io_serial_in;
serial_out = io_serial_out;
/* Set up the HW */
early_serial_hw_init(divisor);
}
#ifdef CONFIG_PCI
/*
* early_pci_serial_init()
*
* This function is invoked when the early_printk param starts with "pciserial"
* The rest of the param should be ",B:D.F,baud" where B, D & F describe the
* location of a PCI device that must be a UART device.
*/
static __init void early_pci_serial_init(char *s)
{
unsigned divisor;
unsigned long baud = DEFAULT_BAUD;
u8 bus, slot, func;
uint32_t classcode, bar0;
uint16_t cmdreg;
char *e;
/*
* First, part the param to get the BDF values
*/
if (*s == ',')
++s;
if (*s == 0)
return;
bus = (u8)simple_strtoul(s, &e, 16);
s = e;
if (*s != ':')
return;
++s;
slot = (u8)simple_strtoul(s, &e, 16);
s = e;
if (*s != '.')
return;
++s;
func = (u8)simple_strtoul(s, &e, 16);
s = e;
/* A baud might be following */
if (*s == ',')
s++;
/*
* Second, find the device from the BDF
*/
cmdreg = read_pci_config(bus, slot, func, PCI_COMMAND);
classcode = read_pci_config(bus, slot, func, PCI_CLASS_REVISION);
bar0 = read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_0);
/*
* Verify it is a UART type device
*/
if (((classcode >> 16 != PCI_CLASS_COMMUNICATION_MODEM) &&
(classcode >> 16 != PCI_CLASS_COMMUNICATION_SERIAL)) ||
(((classcode >> 8) & 0xff) != 0x02)) /* 16550 I/F at BAR0 */
return;
/*
* Determine if it is IO or memory mapped
*/
if (bar0 & 0x01) {
/* it is IO mapped */
serial_in = io_serial_in;
serial_out = io_serial_out;
early_serial_base = bar0&0xfffffffc;
write_pci_config(bus, slot, func, PCI_COMMAND,
cmdreg|PCI_COMMAND_IO);
} else {
/* It is memory mapped - assume 32-bit alignment */
serial_in = mem32_serial_in;
serial_out = mem32_serial_out;
/* WARNING! assuming the address is always in the first 4G */
early_serial_base =
(unsigned long)early_ioremap(bar0 & 0xfffffff0, 0x10);
write_pci_config(bus, slot, func, PCI_COMMAND,
cmdreg|PCI_COMMAND_MEMORY);
}
/*
* Lastly, initalize the hardware
*/
if (*s) {
if (strcmp(s, "nocfg") == 0)
/* Sometimes, we want to leave the UART alone
* and assume the BIOS has set it up correctly.
* "nocfg" tells us this is the case, and we
* should do no more setup.
*/
return;
if (kstrtoul(s, 0, &baud) < 0 || baud == 0)
baud = DEFAULT_BAUD;
}
/* Convert from baud to divisor value */
divisor = 115200 / baud;
/* Set up the HW */
early_serial_hw_init(divisor);
}
#endif
static struct console early_serial_console = {
.name = "earlyser",
.write = early_serial_write,
@ -210,6 +353,13 @@ static int __init setup_early_printk(char *buf)
early_serial_init(buf + 4);
early_console_register(&early_serial_console, keep);
}
#ifdef CONFIG_PCI
if (!strncmp(buf, "pciserial", 9)) {
early_pci_serial_init(buf + 9);
early_console_register(&early_serial_console, keep);
buf += 9; /* Keep from match the above "serial" */
}
#endif
if (!strncmp(buf, "vga", 3) &&
boot_params.screen_info.orig_video_isVGA == 1) {
max_xpos = boot_params.screen_info.orig_video_cols;
@ -226,11 +376,6 @@ static int __init setup_early_printk(char *buf)
early_console_register(&xenboot_console, keep);
#endif
#ifdef CONFIG_EARLY_PRINTK_INTEL_MID
if (!strncmp(buf, "mrst", 4)) {
mrst_early_console_init();
early_console_register(&early_mrst_console, keep);
}
if (!strncmp(buf, "hsu", 3)) {
hsu_early_console_init(buf + 3);
early_console_register(&early_hsu_console, keep);

View File

@ -16,8 +16,6 @@ obj-$(subst m,y,$(CONFIG_INPUT_MPU3050)) += platform_mpu3050.o
obj-$(subst m,y,$(CONFIG_INPUT_BMA150)) += platform_bma023.o
obj-$(subst m,y,$(CONFIG_GPIO_PCA953X)) += platform_tca6416.o
obj-$(subst m,y,$(CONFIG_DRM_MEDFIELD)) += platform_tc35876x.o
# SPI Devices
obj-$(subst m,y,$(CONFIG_SERIAL_MRST_MAX3110)) += platform_max3111.o
# MISC Devices
obj-$(subst m,y,$(CONFIG_KEYBOARD_GPIO)) += platform_gpio_keys.o
obj-$(subst m,y,$(CONFIG_INTEL_MID_WATCHDOG)) += platform_wdt.o

View File

@ -1,35 +0,0 @@
/*
* platform_max3111.c: max3111 platform data initilization file
*
* (C) Copyright 2013 Intel Corporation
* Author: Sathyanarayanan Kuppuswamy <sathyanarayanan.kuppuswamy@intel.com>
*
* 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.
*/
#include <linux/gpio.h>
#include <linux/spi/spi.h>
#include <asm/intel-mid.h>
static void __init *max3111_platform_data(void *info)
{
struct spi_board_info *spi_info = info;
int intr = get_gpio_by_name("max3111_int");
spi_info->mode = SPI_MODE_0;
if (intr == -1)
return NULL;
spi_info->irq = intr + INTEL_MID_IRQ_OFFSET;
return NULL;
}
static const struct devs_id max3111_dev_id __initconst = {
.name = "spi_max3111",
.type = SFI_DEV_TYPE_SPI,
.get_platform_data = &max3111_platform_data,
};
sfi_device(max3111_dev_id);

View File

@ -10,15 +10,13 @@
*/
/*
* This file implements two early consoles named mrst and hsu.
* mrst is based on Maxim3110 spi-uart device, it exists in both
* Moorestown and Medfield platforms, while hsu is based on a High
* Speed UART device which only exists in the Medfield platform
* 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/kmsg_dump.h>
#include <linux/console.h>
#include <linux/kernel.h>
#include <linux/delay.h>
@ -28,216 +26,6 @@
#include <asm/pgtable.h>
#include <asm/intel-mid.h>
#define MRST_SPI_TIMEOUT 0x200000
#define MRST_REGBASE_SPI0 0xff128000
#define MRST_REGBASE_SPI1 0xff128400
#define MRST_CLK_SPI0_REG 0xff11d86c
/* Bit fields in CTRLR0 */
#define SPI_DFS_OFFSET 0
#define SPI_FRF_OFFSET 4
#define SPI_FRF_SPI 0x0
#define SPI_FRF_SSP 0x1
#define SPI_FRF_MICROWIRE 0x2
#define SPI_FRF_RESV 0x3
#define SPI_MODE_OFFSET 6
#define SPI_SCPH_OFFSET 6
#define SPI_SCOL_OFFSET 7
#define SPI_TMOD_OFFSET 8
#define SPI_TMOD_TR 0x0 /* xmit & recv */
#define SPI_TMOD_TO 0x1 /* xmit only */
#define SPI_TMOD_RO 0x2 /* recv only */
#define SPI_TMOD_EPROMREAD 0x3 /* eeprom read mode */
#define SPI_SLVOE_OFFSET 10
#define SPI_SRL_OFFSET 11
#define SPI_CFS_OFFSET 12
/* Bit fields in SR, 7 bits */
#define SR_MASK 0x7f /* cover 7 bits */
#define SR_BUSY (1 << 0)
#define SR_TF_NOT_FULL (1 << 1)
#define SR_TF_EMPT (1 << 2)
#define SR_RF_NOT_EMPT (1 << 3)
#define SR_RF_FULL (1 << 4)
#define SR_TX_ERR (1 << 5)
#define SR_DCOL (1 << 6)
struct dw_spi_reg {
u32 ctrl0;
u32 ctrl1;
u32 ssienr;
u32 mwcr;
u32 ser;
u32 baudr;
u32 txfltr;
u32 rxfltr;
u32 txflr;
u32 rxflr;
u32 sr;
u32 imr;
u32 isr;
u32 risr;
u32 txoicr;
u32 rxoicr;
u32 rxuicr;
u32 msticr;
u32 icr;
u32 dmacr;
u32 dmatdlr;
u32 dmardlr;
u32 idr;
u32 version;
/* Currently operates as 32 bits, though only the low 16 bits matter */
u32 dr;
} __packed;
#define dw_readl(dw, name) __raw_readl(&(dw)->name)
#define dw_writel(dw, name, val) __raw_writel((val), &(dw)->name)
/* Default use SPI0 register for mrst, we will detect Penwell and use SPI1 */
static unsigned long mrst_spi_paddr = MRST_REGBASE_SPI0;
static u32 *pclk_spi0;
/* Always contains an accessible address, start with 0 */
static struct dw_spi_reg *pspi;
static struct kmsg_dumper dw_dumper;
static int dumper_registered;
static void dw_kmsg_dump(struct kmsg_dumper *dumper,
enum kmsg_dump_reason reason)
{
static char line[1024];
size_t len;
/* When run to this, we'd better re-init the HW */
mrst_early_console_init();
while (kmsg_dump_get_line(dumper, true, line, sizeof(line), &len))
early_mrst_console.write(&early_mrst_console, line, len);
}
/* Set the ratio rate to 115200, 8n1, IRQ disabled */
static void max3110_write_config(void)
{
u16 config;
config = 0xc001;
dw_writel(pspi, dr, config);
}
/* Translate char to a eligible word and send to max3110 */
static void max3110_write_data(char c)
{
u16 data;
data = 0x8000 | c;
dw_writel(pspi, dr, data);
}
void mrst_early_console_init(void)
{
u32 ctrlr0 = 0;
u32 spi0_cdiv;
u32 freq; /* Freqency info only need be searched once */
/* Base clk is 100 MHz, the actual clk = 100M / (clk_divider + 1) */
pclk_spi0 = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE,
MRST_CLK_SPI0_REG);
spi0_cdiv = ((*pclk_spi0) & 0xe00) >> 9;
freq = 100000000 / (spi0_cdiv + 1);
if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_PENWELL)
mrst_spi_paddr = MRST_REGBASE_SPI1;
pspi = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE,
mrst_spi_paddr);
/* Disable SPI controller */
dw_writel(pspi, ssienr, 0);
/* Set control param, 8 bits, transmit only mode */
ctrlr0 = dw_readl(pspi, ctrl0);
ctrlr0 &= 0xfcc0;
ctrlr0 |= 0xf | (SPI_FRF_SPI << SPI_FRF_OFFSET)
| (SPI_TMOD_TO << SPI_TMOD_OFFSET);
dw_writel(pspi, ctrl0, ctrlr0);
/*
* Change the spi0 clk to comply with 115200 bps, use 100000 to
* calculate the clk dividor to make the clock a little slower
* than real baud rate.
*/
dw_writel(pspi, baudr, freq/100000);
/* Disable all INT for early phase */
dw_writel(pspi, imr, 0x0);
/* Set the cs to spi-uart */
dw_writel(pspi, ser, 0x2);
/* Enable the HW, the last step for HW init */
dw_writel(pspi, ssienr, 0x1);
/* Set the default configuration */
max3110_write_config();
/* Register the kmsg dumper */
if (!dumper_registered) {
dw_dumper.dump = dw_kmsg_dump;
kmsg_dump_register(&dw_dumper);
dumper_registered = 1;
}
}
/* Slave select should be called in the read/write function */
static void early_mrst_spi_putc(char c)
{
unsigned int timeout;
u32 sr;
timeout = MRST_SPI_TIMEOUT;
/* Early putc needs to make sure the TX FIFO is not full */
while (--timeout) {
sr = dw_readl(pspi, sr);
if (!(sr & SR_TF_NOT_FULL))
cpu_relax();
else
break;
}
if (!timeout)
pr_warn("MRST earlycon: timed out\n");
else
max3110_write_data(c);
}
/* Early SPI only uses polling mode */
static void early_mrst_spi_write(struct console *con, const char *str,
unsigned n)
{
int i;
for (i = 0; i < n && *str; i++) {
if (*str == '\n')
early_mrst_spi_putc('\r');
early_mrst_spi_putc(*str);
str++;
}
}
struct console early_mrst_console = {
.name = "earlymrst",
.write = early_mrst_spi_write,
.flags = CON_PRINTBUFFER,
.index = -1,
};
/*
* Following is the early console based on Medfield HSU (High
* Speed UART) device.
@ -259,7 +47,7 @@ void hsu_early_console_init(const char *s)
port = clamp_val(port, 0, 2);
paddr = HSU_PORT_BASE + port * 0x80;
phsu = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE, paddr);
phsu = (void __iomem *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE, paddr);
/* Disable FIFO */
writeb(0x0, phsu + UART_FCR);

View File

@ -51,33 +51,22 @@ struct ath_struct {
static int ath_wakeup_ar3k(struct tty_struct *tty)
{
struct ktermios ktermios;
int status = tty->driver->ops->tiocmget(tty);
if (status & TIOCM_CTS)
return status;
/* Disable Automatic RTSCTS */
ktermios = tty->termios;
ktermios.c_cflag &= ~CRTSCTS;
tty_set_termios(tty, &ktermios);
/* Clear RTS first */
status = tty->driver->ops->tiocmget(tty);
tty->driver->ops->tiocmget(tty);
tty->driver->ops->tiocmset(tty, 0x00, TIOCM_RTS);
mdelay(20);
/* Set RTS, wake up board */
status = tty->driver->ops->tiocmget(tty);
tty->driver->ops->tiocmget(tty);
tty->driver->ops->tiocmset(tty, TIOCM_RTS, 0x00);
mdelay(20);
status = tty->driver->ops->tiocmget(tty);
/* Enable Automatic RTSCTS */
ktermios.c_cflag |= CRTSCTS;
status = tty_set_termios(tty, &ktermios);
return status;
}

View File

@ -182,7 +182,7 @@ static int __pnp_bus_suspend(struct device *dev, pm_message_t state)
return error;
}
if (pnp_dev->protocol->suspend)
if (pnp_can_suspend(pnp_dev))
pnp_dev->protocol->suspend(pnp_dev, state);
return 0;
}

View File

@ -931,7 +931,7 @@ static void rs_send_xchar(struct tty_struct *tty, char ch)
struct serial_state *info = tty->driver_data;
unsigned long flags;
if (serial_paranoia_check(info, tty->name, "rs_send_char"))
if (serial_paranoia_check(info, tty->name, "rs_send_xchar"))
return;
info->x_char = ch;

View File

@ -112,7 +112,6 @@ static void disable_tx_interrupt(struct ehv_bc_data *bc)
static int find_console_handle(void)
{
struct device_node *np = of_stdout;
const char *sprop = NULL;
const uint32_t *iprop;
/* We don't care what the aliased node is actually called. We only

View File

@ -1055,7 +1055,7 @@ static int isicom_send_break(struct tty_struct *tty, int length)
outw(0x8000 | ((port->channel) << (card->shift_count)) | 0x3, base);
outw((length & 0xff) << 8 | 0x00, base);
outw((length & 0xff00), base);
outw((length & 0xff00u), base);
InterruptTheCard(base);
unlock_card(card);

View File

@ -90,6 +90,7 @@
struct n_tty_data {
/* producer-published */
size_t read_head;
size_t commit_head;
size_t canon_head;
size_t echo_head;
size_t echo_commit;
@ -161,36 +162,11 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
return put_user(x, ptr);
}
static int receive_room(struct tty_struct *tty)
{
struct n_tty_data *ldata = tty->disc_data;
int left;
if (I_PARMRK(tty)) {
/* Multiply read_cnt by 3, since each byte might take up to
* three times as many spaces when PARMRK is set (depending on
* its flags, e.g. parity error). */
left = N_TTY_BUF_SIZE - read_cnt(ldata) * 3 - 1;
} else
left = N_TTY_BUF_SIZE - read_cnt(ldata) - 1;
/*
* If we are doing input canonicalization, and there are no
* pending newlines, let characters through without limit, so
* that erase characters will be handled. Other excess
* characters will be beeped.
*/
if (left <= 0)
left = ldata->icanon && ldata->canon_head == ldata->read_tail;
return left;
}
/**
* n_tty_set_room - receive space
* n_tty_kick_worker - start input worker (if required)
* @tty: terminal
*
* Re-schedules the flip buffer work if space just became available.
* Re-schedules the flip buffer work if it may have stopped
*
* Caller holds exclusive termios_rwsem
* or
@ -198,12 +174,12 @@ static int receive_room(struct tty_struct *tty)
* holds non-exclusive termios_rwsem
*/
static void n_tty_set_room(struct tty_struct *tty)
static void n_tty_kick_worker(struct tty_struct *tty)
{
struct n_tty_data *ldata = tty->disc_data;
/* Did this open up the receive buffer? We may need to flip */
if (unlikely(ldata->no_room) && receive_room(tty)) {
/* Did the input worker stop? Restart it */
if (unlikely(ldata->no_room)) {
ldata->no_room = 0;
WARN_RATELIMIT(tty->port->itty == NULL,
@ -224,7 +200,7 @@ static ssize_t chars_in_buffer(struct tty_struct *tty)
ssize_t n = 0;
if (!ldata->icanon)
n = read_cnt(ldata);
n = ldata->commit_head - ldata->read_tail;
else
n = ldata->canon_head - ldata->read_tail;
return n;
@ -247,17 +223,20 @@ static void n_tty_write_wakeup(struct tty_struct *tty)
static void n_tty_check_throttle(struct tty_struct *tty)
{
if (tty->driver->type == TTY_DRIVER_TYPE_PTY)
return;
struct n_tty_data *ldata = tty->disc_data;
/*
* Check the remaining room for the input canonicalization
* mode. We don't want to throttle the driver if we're in
* canonical mode and don't have a newline yet!
*/
if (ldata->icanon && ldata->canon_head == ldata->read_tail)
return;
while (1) {
int throttled;
tty_set_flow_change(tty, TTY_THROTTLE_SAFE);
if (receive_room(tty) >= TTY_THRESHOLD_THROTTLE)
if (N_TTY_BUF_SIZE - read_cnt(ldata) >= TTY_THRESHOLD_THROTTLE)
break;
throttled = tty_throttle_safe(tty);
if (!throttled)
@ -274,7 +253,7 @@ static void n_tty_check_unthrottle(struct tty_struct *tty)
return;
if (!tty->count)
return;
n_tty_set_room(tty);
n_tty_kick_worker(tty);
n_tty_write_wakeup(tty->link);
if (waitqueue_active(&tty->link->write_wait))
wake_up_interruptible_poll(&tty->link->write_wait, POLLOUT);
@ -296,7 +275,7 @@ static void n_tty_check_unthrottle(struct tty_struct *tty)
break;
if (!tty->count)
break;
n_tty_set_room(tty);
n_tty_kick_worker(tty);
unthrottled = tty_unthrottle_safe(tty);
if (!unthrottled)
break;
@ -313,10 +292,6 @@ static void n_tty_check_unthrottle(struct tty_struct *tty)
*
* n_tty_receive_buf()/producer path:
* caller holds non-exclusive termios_rwsem
* modifies read_head
*
* read_head is only considered 'published' if canonical mode is
* not active.
*/
static inline void put_tty_queue(unsigned char c, struct n_tty_data *ldata)
@ -340,6 +315,7 @@ static void reset_buffer_flags(struct n_tty_data *ldata)
{
ldata->read_head = ldata->canon_head = ldata->read_tail = 0;
ldata->echo_head = ldata->echo_tail = ldata->echo_commit = 0;
ldata->commit_head = 0;
ldata->echo_mark = 0;
ldata->line_start = 0;
@ -379,7 +355,7 @@ static void n_tty_flush_buffer(struct tty_struct *tty)
{
down_write(&tty->termios_rwsem);
reset_buffer_flags(tty->disc_data);
n_tty_set_room(tty);
n_tty_kick_worker(tty);
if (tty->link)
n_tty_packet_mode_flush(tty);
@ -987,10 +963,6 @@ static inline void finish_erasing(struct n_tty_data *ldata)
*
* n_tty_receive_buf()/producer path:
* caller holds non-exclusive termios_rwsem
* modifies read_head
*
* Modifying the read_head is not considered a publish in this context
* because canonical mode is active -- only canon_head publishes
*/
static void eraser(unsigned char c, struct tty_struct *tty)
@ -1118,16 +1090,45 @@ static void eraser(unsigned char c, struct tty_struct *tty)
* Called when a signal is being sent due to terminal input.
* Called from the driver receive_buf path so serialized.
*
* Performs input and output flush if !NOFLSH. In this context, the echo
* buffer is 'output'. The signal is processed first to alert any current
* readers or writers to discontinue and exit their i/o loops.
*
* Locking: ctrl_lock
*/
static void isig(int sig, struct tty_struct *tty)
{
struct n_tty_data *ldata = tty->disc_data;
struct pid *tty_pgrp = tty_get_pgrp(tty);
if (tty_pgrp) {
kill_pgrp(tty_pgrp, sig, 1);
put_pid(tty_pgrp);
}
if (!L_NOFLSH(tty)) {
up_read(&tty->termios_rwsem);
down_write(&tty->termios_rwsem);
/* clear echo buffer */
mutex_lock(&ldata->output_lock);
ldata->echo_head = ldata->echo_tail = 0;
ldata->echo_mark = ldata->echo_commit = 0;
mutex_unlock(&ldata->output_lock);
/* clear output buffer */
tty_driver_flush_buffer(tty);
/* clear input buffer */
reset_buffer_flags(tty->disc_data);
/* notify pty master of flush */
if (tty->link)
n_tty_packet_mode_flush(tty);
up_write(&tty->termios_rwsem);
down_read(&tty->termios_rwsem);
}
}
/**
@ -1139,7 +1140,6 @@ static void isig(int sig, struct tty_struct *tty)
*
* n_tty_receive_buf()/producer path:
* caller holds non-exclusive termios_rwsem
* publishes read_head via put_tty_queue()
*
* Note: may get exclusive termios_rwsem if flushing input buffer
*/
@ -1152,13 +1152,6 @@ static void n_tty_receive_break(struct tty_struct *tty)
return;
if (I_BRKINT(tty)) {
isig(SIGINT, tty);
if (!L_NOFLSH(tty)) {
/* flushing needs exclusive termios_rwsem */
up_read(&tty->termios_rwsem);
n_tty_flush_buffer(tty);
tty_driver_flush_buffer(tty);
down_read(&tty->termios_rwsem);
}
return;
}
if (I_PARMRK(tty)) {
@ -1209,7 +1202,6 @@ static void n_tty_receive_overrun(struct tty_struct *tty)
*
* n_tty_receive_buf()/producer path:
* caller holds non-exclusive termios_rwsem
* publishes read_head via put_tty_queue()
*/
static void n_tty_receive_parity_error(struct tty_struct *tty, unsigned char c)
{
@ -1233,13 +1225,7 @@ static void n_tty_receive_parity_error(struct tty_struct *tty, unsigned char c)
static void
n_tty_receive_signal_char(struct tty_struct *tty, int signal, unsigned char c)
{
if (!L_NOFLSH(tty)) {
/* flushing needs exclusive termios_rwsem */
up_read(&tty->termios_rwsem);
n_tty_flush_buffer(tty);
tty_driver_flush_buffer(tty);
down_read(&tty->termios_rwsem);
}
isig(signal, tty);
if (I_IXON(tty))
start_tty(tty);
if (L_ECHO(tty)) {
@ -1247,7 +1233,6 @@ n_tty_receive_signal_char(struct tty_struct *tty, int signal, unsigned char c)
commit_echoes(tty);
} else
process_echoes(tty);
isig(signal, tty);
return;
}
@ -1263,7 +1248,6 @@ n_tty_receive_signal_char(struct tty_struct *tty, int signal, unsigned char c)
* n_tty_receive_buf()/producer path:
* caller holds non-exclusive termios_rwsem
* publishes canon_head if canonical mode is active
* otherwise, publishes read_head via put_tty_queue()
*
* Returns 1 if LNEXT was received, else returns 0
*/
@ -1376,7 +1360,7 @@ n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
handle_newline:
set_bit(ldata->read_head & (N_TTY_BUF_SIZE - 1), ldata->read_flags);
put_tty_queue(c, ldata);
ldata->canon_head = ldata->read_head;
smp_store_release(&ldata->canon_head, ldata->read_head);
kill_fasync(&tty->fasync, SIGIO, POLL_IN);
if (waitqueue_active(&tty->read_wait))
wake_up_interruptible_poll(&tty->read_wait, POLLIN);
@ -1512,23 +1496,6 @@ n_tty_receive_char_lnext(struct tty_struct *tty, unsigned char c, char flag)
n_tty_receive_char_flagged(tty, c, flag);
}
/**
* n_tty_receive_buf - data receive
* @tty: terminal device
* @cp: buffer
* @fp: flag buffer
* @count: characters
*
* Called by the terminal driver when a block of characters has
* been received. This function must be called from soft contexts
* not from interrupt context. The driver is responsible for making
* calls one at a time and in order (or using flush_to_ldisc)
*
* n_tty_receive_buf()/producer path:
* claims non-exclusive termios_rwsem
* publishes read_head and canon_head
*/
static void
n_tty_receive_buf_real_raw(struct tty_struct *tty, const unsigned char *cp,
char *fp, int count)
@ -1537,16 +1504,14 @@ n_tty_receive_buf_real_raw(struct tty_struct *tty, const unsigned char *cp,
size_t n, head;
head = ldata->read_head & (N_TTY_BUF_SIZE - 1);
n = N_TTY_BUF_SIZE - max(read_cnt(ldata), head);
n = min_t(size_t, count, n);
n = min_t(size_t, count, N_TTY_BUF_SIZE - head);
memcpy(read_buf_addr(ldata, head), cp, n);
ldata->read_head += n;
cp += n;
count -= n;
head = ldata->read_head & (N_TTY_BUF_SIZE - 1);
n = N_TTY_BUF_SIZE - max(read_cnt(ldata), head);
n = min_t(size_t, count, n);
n = min_t(size_t, count, N_TTY_BUF_SIZE - head);
memcpy(read_buf_addr(ldata, head), cp, n);
ldata->read_head += n;
}
@ -1676,32 +1641,98 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
tty->ops->flush_chars(tty);
}
if ((!ldata->icanon && (read_cnt(ldata) >= ldata->minimum_to_wake)) ||
L_EXTPROC(tty)) {
if (ldata->icanon && !L_EXTPROC(tty))
return;
/* publish read_head to consumer */
smp_store_release(&ldata->commit_head, ldata->read_head);
if ((read_cnt(ldata) >= ldata->minimum_to_wake) || L_EXTPROC(tty)) {
kill_fasync(&tty->fasync, SIGIO, POLL_IN);
if (waitqueue_active(&tty->read_wait))
wake_up_interruptible_poll(&tty->read_wait, POLLIN);
}
}
/**
* n_tty_receive_buf_common - process input
* @tty: device to receive input
* @cp: input chars
* @fp: flags for each char (if NULL, all chars are TTY_NORMAL)
* @count: number of input chars in @cp
*
* Called by the terminal driver when a block of characters has
* been received. This function must be called from soft contexts
* not from interrupt context. The driver is responsible for making
* calls one at a time and in order (or using flush_to_ldisc)
*
* Returns the # of input chars from @cp which were processed.
*
* In canonical mode, the maximum line length is 4096 chars (including
* the line termination char); lines longer than 4096 chars are
* truncated. After 4095 chars, input data is still processed but
* not stored. Overflow processing ensures the tty can always
* receive more input until at least one line can be read.
*
* In non-canonical mode, the read buffer will only accept 4095 chars;
* this provides the necessary space for a newline char if the input
* mode is switched to canonical.
*
* Note it is possible for the read buffer to _contain_ 4096 chars
* in non-canonical mode: the read buffer could already contain the
* maximum canon line of 4096 chars when the mode is switched to
* non-canonical.
*
* n_tty_receive_buf()/producer path:
* claims non-exclusive termios_rwsem
* publishes commit_head or canon_head
*/
static int
n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp,
char *fp, int count, int flow)
{
struct n_tty_data *ldata = tty->disc_data;
int room, n, rcvd = 0;
int room, n, rcvd = 0, overflow;
down_read(&tty->termios_rwsem);
while (1) {
room = receive_room(tty);
/*
* When PARMRK is set, each input char may take up to 3 chars
* in the read buf; reduce the buffer space avail by 3x
*
* If we are doing input canonicalization, and there are no
* pending newlines, let characters through without limit, so
* that erase characters will be handled. Other excess
* characters will be beeped.
*
* paired with store in *_copy_from_read_buf() -- guarantees
* the consumer has loaded the data in read_buf up to the new
* read_tail (so this producer will not overwrite unread data)
*/
size_t tail = smp_load_acquire(&ldata->read_tail);
room = N_TTY_BUF_SIZE - (ldata->read_head - tail);
if (I_PARMRK(tty))
room = (room + 2) / 3;
room--;
if (room <= 0) {
overflow = ldata->icanon && ldata->canon_head == tail;
if (overflow && room < 0)
ldata->read_head--;
room = overflow;
ldata->no_room = flow && !room;
} else
overflow = 0;
n = min(count, room);
if (!n) {
if (flow && !room)
ldata->no_room = 1;
if (!n)
break;
}
__receive_buf(tty, cp, fp, n);
/* ignore parity errors if handling overflow */
if (!overflow || !fp || *fp != TTY_PARITY)
__receive_buf(tty, cp, fp, n);
cp += n;
if (fp)
fp += n;
@ -1710,7 +1741,17 @@ n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp,
}
tty->receive_room = room;
n_tty_check_throttle(tty);
/* Unthrottle if handling overflow on pty */
if (tty->driver->type == TTY_DRIVER_TYPE_PTY) {
if (overflow) {
tty_set_flow_change(tty, TTY_UNTHROTTLE_SAFE);
tty_unthrottle_safe(tty);
__tty_set_flow_change(tty, 0);
}
} else
n_tty_check_throttle(tty);
up_read(&tty->termios_rwsem);
return rcvd;
@ -1764,6 +1805,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
ldata->canon_head = ldata->read_head;
ldata->push = 1;
}
ldata->commit_head = ldata->read_head;
ldata->erasing = 0;
ldata->lnext = 0;
}
@ -1817,7 +1859,6 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
else
ldata->real_raw = 0;
}
n_tty_set_room(tty);
/*
* Fix tty hang when I_IXON(tty) is cleared, but the tty
* been stopped by STOP_CHAR(tty) before it.
@ -1905,7 +1946,7 @@ static inline int input_available_p(struct tty_struct *tty, int poll)
if (ldata->icanon && !L_EXTPROC(tty))
return ldata->canon_head != ldata->read_tail;
else
return read_cnt(ldata) >= amt;
return ldata->commit_head - ldata->read_tail >= amt;
}
/**
@ -1937,10 +1978,11 @@ static int copy_from_read_buf(struct tty_struct *tty,
int retval;
size_t n;
bool is_eof;
size_t head = smp_load_acquire(&ldata->commit_head);
size_t tail = ldata->read_tail & (N_TTY_BUF_SIZE - 1);
retval = 0;
n = min(read_cnt(ldata), N_TTY_BUF_SIZE - tail);
n = min(head - ldata->read_tail, N_TTY_BUF_SIZE - tail);
n = min(*nr, n);
if (n) {
retval = copy_to_user(*b, read_buf_addr(ldata, tail), n);
@ -1948,9 +1990,10 @@ static int copy_from_read_buf(struct tty_struct *tty,
is_eof = n == 1 && read_buf(ldata, tail) == EOF_CHAR(tty);
tty_audit_add_data(tty, read_buf_addr(ldata, tail), n,
ldata->icanon);
ldata->read_tail += n;
smp_store_release(&ldata->read_tail, ldata->read_tail + n);
/* Turn single EOF into zero-length read */
if (L_EXTPROC(tty) && ldata->icanon && is_eof && !read_cnt(ldata))
if (L_EXTPROC(tty) && ldata->icanon && is_eof &&
(head == ldata->read_tail))
n = 0;
*b += n;
*nr -= n;
@ -1993,7 +2036,7 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
bool eof_push = 0;
/* N.B. avoid overrun if nr == 0 */
n = min(*nr, read_cnt(ldata));
n = min(*nr, smp_load_acquire(&ldata->canon_head) - ldata->read_tail);
if (!n)
return 0;
@ -2043,8 +2086,7 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
if (found)
clear_bit(eol, ldata->read_flags);
smp_mb__after_atomic();
ldata->read_tail += c;
smp_store_release(&ldata->read_tail, ldata->read_tail + c);
if (found) {
if (!ldata->push)
@ -2130,6 +2172,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
ssize_t retval = 0;
long timeout;
int packet;
size_t tail;
c = job_control(tty, file);
if (c < 0)
@ -2166,6 +2209,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
}
packet = tty->packet;
tail = ldata->read_tail;
add_wait_queue(&tty->read_wait, &wait);
while (nr) {
@ -2208,7 +2252,6 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
retval = -ERESTARTSYS;
break;
}
n_tty_set_room(tty);
up_read(&tty->termios_rwsem);
timeout = wait_woken(&wait, TASK_INTERRUPTIBLE,
@ -2253,7 +2296,8 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
if (time)
timeout = time;
}
n_tty_set_room(tty);
if (tail != ldata->read_tail)
n_tty_kick_worker(tty);
up_read(&tty->termios_rwsem);
remove_wait_queue(&tty->read_wait, &wait);

View File

@ -87,19 +87,6 @@ static void pty_unthrottle(struct tty_struct *tty)
set_bit(TTY_THROTTLED, &tty->flags);
}
/**
* pty_space - report space left for writing
* @to: tty we are writing into
*
* Limit the buffer space used by ptys to 8k.
*/
static int pty_space(struct tty_struct *to)
{
int n = tty_buffer_space_avail(to->port);
return min(n, 8192);
}
/**
* pty_write - write to a pty
* @tty: the tty we write from
@ -141,7 +128,7 @@ static int pty_write_room(struct tty_struct *tty)
{
if (tty->stopped)
return 0;
return pty_space(tty->link);
return tty_buffer_space_avail(tty->link->port);
}
/**
@ -210,6 +197,9 @@ static int pty_signal(struct tty_struct *tty, int sig)
{
struct pid *pgrp;
if (sig != SIGINT && sig != SIGQUIT && sig != SIGTSTP)
return -EINVAL;
if (tty->link) {
pgrp = tty_get_pgrp(tty->link);
if (pgrp)
@ -222,10 +212,16 @@ static int pty_signal(struct tty_struct *tty, int sig)
static void pty_flush_buffer(struct tty_struct *tty)
{
struct tty_struct *to = tty->link;
struct tty_ldisc *ld;
if (!to)
return;
/* tty_buffer_flush(to); FIXME */
ld = tty_ldisc_ref(to);
tty_buffer_flush(to, ld);
if (ld)
tty_ldisc_deref(ld);
if (to->packet) {
spin_lock_irq(&tty->ctrl_lock);
tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
@ -399,6 +395,7 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
goto err_put_module;
tty_set_lock_subclass(o_tty);
lockdep_set_subclass(&o_tty->termios_rwsem, TTY_LOCK_SLAVE);
if (legacy) {
/* We always use new tty termios data so we can do this
@ -429,10 +426,14 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
o_tty->link = tty;
tty_port_init(ports[0]);
tty_port_init(ports[1]);
tty_buffer_set_limit(ports[0], 8192);
tty_buffer_set_limit(ports[1], 8192);
o_tty->port = ports[0];
tty->port = ports[1];
o_tty->port->itty = o_tty;
tty_buffer_set_lock_subclass(o_tty->port);
tty_driver_kref_get(driver);
tty->count++;
o_tty->count++;

View File

@ -1390,7 +1390,7 @@ static void rp_unthrottle(struct tty_struct *tty)
tty->ldisc.chars_in_buffer(tty));
#endif
if (rocket_paranoia_check(info, "rp_throttle"))
if (rocket_paranoia_check(info, "rp_unthrottle"))
return;
if (I_IXOFF(tty))
@ -1458,7 +1458,7 @@ static void rp_wait_until_sent(struct tty_struct *tty, int timeout)
orig_jiffies = jiffies;
#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
printk(KERN_INFO "In RP_wait_until_sent(%d) (jiff=%lu)...\n", timeout,
printk(KERN_INFO "In %s(%d) (jiff=%lu)...\n", __func__, timeout,
jiffies);
printk(KERN_INFO "cps=%d...\n", info->cps);
#endif

View File

@ -329,6 +329,17 @@ static const struct serial8250_config uart_config[] = {
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
.flags = UART_CAP_FIFO | UART_CAP_AFE,
},
/* tx_loadsz is set to 63-bytes instead of 64-bytes to implement
workaround of errata A-008006 which states that tx_loadsz should be
configured less than Maximum supported fifo bytes */
[PORT_16550A_FSL64] = {
.name = "16550A_FSL64",
.fifo_size = 64,
.tx_loadsz = 63,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 |
UART_FCR7_64BYTE,
.flags = UART_CAP_FIFO,
},
};
/* Uart divisor latch read */
@ -956,7 +967,17 @@ static void autoconfig_16550a(struct uart_8250_port *up)
up->port.type = PORT_16650;
up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP;
} else {
DEBUG_AUTOCONF("Motorola 8xxx DUART ");
serial_out(up, UART_LCR, 0);
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
UART_FCR7_64BYTE);
status1 = serial_in(up, UART_IIR) >> 5;
serial_out(up, UART_FCR, 0);
serial_out(up, UART_LCR, 0);
if (status1 == 7)
up->port.type = PORT_16550A_FSL64;
else
DEBUG_AUTOCONF("Motorola 8xxx DUART ");
}
serial_out(up, UART_EFR, 0);
return;
@ -1355,9 +1376,11 @@ static void serial8250_start_tx(struct uart_port *port)
struct uart_8250_port *up = up_to_u8250p(port);
serial8250_rpm_get_tx(up);
if (up->dma && !up->dma->tx_dma(up)) {
if (up->dma && !up->dma->tx_dma(up))
return;
} else if (!(up->ier & UART_IER_THRI)) {
if (!(up->ier & UART_IER_THRI)) {
up->ier |= UART_IER_THRI;
serial_port_out(port, UART_IER, up->ier);
@ -1365,7 +1388,7 @@ static void serial8250_start_tx(struct uart_port *port)
unsigned char lsr;
lsr = serial_in(up, UART_LSR);
up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
if (lsr & UART_LSR_TEMT)
if (lsr & UART_LSR_THRE)
serial8250_tx_chars(up);
}
}
@ -1924,7 +1947,7 @@ static unsigned int serial8250_get_mctrl(struct uart_port *port)
return ret;
}
static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct uart_8250_port *up = up_to_u8250p(port);
unsigned char mcr = 0;
@ -1944,6 +1967,14 @@ static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
serial_port_out(port, UART_MCR, mcr);
}
EXPORT_SYMBOL_GPL(serial8250_do_set_mctrl);
static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
if (port->set_mctrl)
return port->set_mctrl(port, mctrl);
return serial8250_do_set_mctrl(port, mctrl);
}
static void serial8250_break_ctl(struct uart_port *port, int break_state)
{
@ -2382,13 +2413,34 @@ static void serial8250_shutdown(struct uart_port *port)
serial8250_do_shutdown(port);
}
static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int baud)
/*
* XR17V35x UARTs have an extra fractional divisor register (DLD)
* Calculate divisor with extra 4-bit fractional portion
*/
static unsigned int xr17v35x_get_divisor(struct uart_8250_port *up,
unsigned int baud,
unsigned int *frac)
{
struct uart_port *port = &up->port;
unsigned int quot_16;
quot_16 = DIV_ROUND_CLOSEST(port->uartclk, baud);
*frac = quot_16 & 0x0f;
return quot_16 >> 4;
}
static unsigned int serial8250_get_divisor(struct uart_8250_port *up,
unsigned int baud,
unsigned int *frac)
{
struct uart_port *port = &up->port;
unsigned int quot;
/*
* Handle magic divisors for baud rates above baud_base on
* SMSC SuperIO chips.
*
*/
if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
baud == (port->uartclk/4))
@ -2396,22 +2448,26 @@ static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int
else if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
baud == (port->uartclk/8))
quot = 0x8002;
else if (up->port.type == PORT_XR17V35X)
quot = xr17v35x_get_divisor(up, baud, frac);
else
quot = uart_get_divisor(port, baud);
/*
* Oxford Semi 952 rev B workaround
*/
if (up->bugs & UART_BUG_QUOT && (quot & 0xff) == 0)
quot++;
return quot;
}
void
serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
static unsigned char serial8250_compute_lcr(struct uart_8250_port *up,
tcflag_t c_cflag)
{
struct uart_8250_port *up = up_to_u8250p(port);
unsigned char cval;
unsigned long flags;
unsigned int baud, quot;
switch (termios->c_cflag & CSIZE) {
switch (c_cflag & CSIZE) {
case CS5:
cval = UART_LCR_WLEN5;
break;
@ -2427,33 +2483,80 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
break;
}
if (termios->c_cflag & CSTOPB)
if (c_cflag & CSTOPB)
cval |= UART_LCR_STOP;
if (termios->c_cflag & PARENB) {
if (c_cflag & PARENB) {
cval |= UART_LCR_PARITY;
if (up->bugs & UART_BUG_PARITY)
up->fifo_bug = true;
}
if (!(termios->c_cflag & PARODD))
if (!(c_cflag & PARODD))
cval |= UART_LCR_EPAR;
#ifdef CMSPAR
if (termios->c_cflag & CMSPAR)
if (c_cflag & CMSPAR)
cval |= UART_LCR_SPAR;
#endif
return cval;
}
static void serial8250_set_divisor(struct uart_port *port, unsigned int baud,
unsigned int quot, unsigned int quot_frac)
{
struct uart_8250_port *up = up_to_u8250p(port);
/* Workaround to enable 115200 baud on OMAP1510 internal ports */
if (is_omap1510_8250(up)) {
if (baud == 115200) {
quot = 1;
serial_port_out(port, UART_OMAP_OSC_12M_SEL, 1);
} else
serial_port_out(port, UART_OMAP_OSC_12M_SEL, 0);
}
/*
* For NatSemi, switch to bank 2 not bank 1, to avoid resetting EXCR2,
* otherwise just set DLAB
*/
if (up->capabilities & UART_NATSEMI)
serial_port_out(port, UART_LCR, 0xe0);
else
serial_port_out(port, UART_LCR, up->lcr | UART_LCR_DLAB);
serial_dl_write(up, quot);
/* XR17V35x UARTs have an extra fractional divisor register (DLD) */
if (up->port.type == PORT_XR17V35X)
serial_port_out(port, 0x2, quot_frac);
}
void
serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
struct uart_8250_port *up = up_to_u8250p(port);
unsigned char cval;
unsigned long flags;
unsigned int baud, quot, frac = 0;
cval = serial8250_compute_lcr(up, termios->c_cflag);
/*
* Ask the core to calculate the divisor for us.
*/
baud = uart_get_baud_rate(port, termios, old,
port->uartclk / 16 / 0xffff,
port->uartclk / 16);
quot = serial8250_get_divisor(port, baud);
quot = serial8250_get_divisor(up, baud, &frac);
/*
* Oxford Semi 952 rev B workaround
* Ok, we're now changing the port state. Do it with
* interrupts disabled.
*/
if (up->bugs & UART_BUG_QUOT && (quot & 0xff) == 0)
quot++;
serial8250_rpm_get(up);
spin_lock_irqsave(&port->lock, flags);
up->lcr = cval; /* Save computed LCR */
if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) {
/* NOTE: If fifo_bug is not set, a user can set RX_trigger. */
@ -2477,13 +2580,6 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
up->mcr |= UART_MCR_AFE;
}
/*
* Ok, we're now changing the port state. Do it with
* interrupts disabled.
*/
serial8250_rpm_get(up);
spin_lock_irqsave(&port->lock, flags);
/*
* Update the per-port timeout.
*/
@ -2548,43 +2644,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
serial_port_out(port, UART_EFR, efr);
}
/* Workaround to enable 115200 baud on OMAP1510 internal ports */
if (is_omap1510_8250(up)) {
if (baud == 115200) {
quot = 1;
serial_port_out(port, UART_OMAP_OSC_12M_SEL, 1);
} else
serial_port_out(port, UART_OMAP_OSC_12M_SEL, 0);
}
/*
* For NatSemi, switch to bank 2 not bank 1, to avoid resetting EXCR2,
* otherwise just set DLAB
*/
if (up->capabilities & UART_NATSEMI)
serial_port_out(port, UART_LCR, 0xe0);
else
serial_port_out(port, UART_LCR, cval | UART_LCR_DLAB);
serial_dl_write(up, quot);
/*
* XR17V35x UARTs have an extra fractional divisor register (DLD)
*
* We need to recalculate all of the registers, because DLM and DLL
* are already rounded to a whole integer.
*
* When recalculating we use a 32x clock instead of a 16x clock to
* allow 1-bit for rounding in the fractional part.
*/
if (up->port.type == PORT_XR17V35X) {
unsigned int baud_x32 = (port->uartclk * 2) / baud;
u16 quot = baud_x32 / 32;
u8 quot_frac = DIV_ROUND_CLOSEST(baud_x32 % 32, 2);
serial_dl_write(up, quot);
serial_port_out(port, 0x2, quot_frac & 0xf);
}
serial8250_set_divisor(port, baud, quot, frac);
/*
* LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR
@ -2593,8 +2653,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
if (port->type == PORT_16750)
serial_port_out(port, UART_FCR, up->fcr);
serial_port_out(port, UART_LCR, cval); /* reset DLAB */
up->lcr = cval; /* Save LCR */
serial_port_out(port, UART_LCR, up->lcr); /* reset DLAB */
if (port->type != PORT_16750) {
/* emulated UARTs (Lucent Venus 167x) need two steps */
if (up->fcr & UART_FCR_ENABLE_FIFO)
@ -3208,6 +3267,27 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
else
serial_port_out(port, UART_IER, 0);
/* check scratch reg to see if port powered off during system sleep */
if (up->canary && (up->canary != serial_port_in(port, UART_SCR))) {
struct ktermios termios;
unsigned int baud, quot, frac = 0;
termios.c_cflag = port->cons->cflag;
if (port->state->port.tty && termios.c_cflag == 0)
termios.c_cflag = port->state->port.tty->termios.c_cflag;
baud = uart_get_baud_rate(port, &termios, NULL,
port->uartclk / 16 / 0xffff,
port->uartclk / 16);
quot = serial8250_get_divisor(up, baud, &frac);
serial8250_set_divisor(port, baud, quot, frac);
serial_port_out(port, UART_LCR, up->lcr);
serial_port_out(port, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
up->canary = 0;
}
uart_console_write(port, s, count, serial8250_console_putchar);
/*
@ -3358,7 +3438,17 @@ int __init early_serial_setup(struct uart_port *port)
*/
void serial8250_suspend_port(int line)
{
uart_suspend_port(&serial8250_reg, &serial8250_ports[line].port);
struct uart_8250_port *up = &serial8250_ports[line];
struct uart_port *port = &up->port;
if (!console_suspend_enabled && uart_console(port) &&
port->type != PORT_8250) {
unsigned char canary = 0xa5;
serial_out(up, UART_SCR, canary);
up->canary = canary;
}
uart_suspend_port(&serial8250_reg, port);
}
/**
@ -3372,6 +3462,8 @@ void serial8250_resume_port(int line)
struct uart_8250_port *up = &serial8250_ports[line];
struct uart_port *port = &up->port;
up->canary = 0;
if (up->capabilities & UART_NATSEMI) {
/* Ensure it's still in high speed mode */
serial_port_out(port, UART_LCR, 0xE0);
@ -3605,6 +3697,8 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
/* Possibly override set_termios call */
if (up->port.set_termios)
uart->port.set_termios = up->port.set_termios;
if (up->port.set_mctrl)
uart->port.set_mctrl = up->port.set_mctrl;
if (up->port.startup)
uart->port.startup = up->port.startup;
if (up->port.shutdown)

View File

@ -59,7 +59,6 @@ static void __dma_rx_complete(void *param)
dma->rx_running = 0;
dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
dmaengine_terminate_all(dma->rxchan);
count = dma->rx_size - state.residue;
@ -81,6 +80,10 @@ int serial8250_tx_dma(struct uart_8250_port *p)
return 0;
dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
if (dma->tx_size < p->port.fifosize) {
ret = -EINVAL;
goto err;
}
desc = dmaengine_prep_slave_single(dma->txchan,
dma->tx_addr + xmit->tail,
@ -131,6 +134,7 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
if (dma->rx_running) {
dmaengine_pause(dma->rxchan);
__dma_rx_complete(p);
dmaengine_terminate_all(dma->rxchan);
}
return -ETIMEDOUT;
default:

View File

@ -351,10 +351,20 @@ static int dw8250_probe_of(struct uart_port *p,
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;
@ -577,6 +587,7 @@ static const struct acpi_device_id dw8250_acpi_match[] = {
{ "INT3435", 0 },
{ "80860F0A", 0 },
{ "8086228A", 0 },
{ "APMC0D08", 0},
{ },
};
MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);

View File

@ -93,15 +93,18 @@ static void __init early_serial8250_write(struct console *console,
struct uart_port *port = &early_device->port;
unsigned int ier;
/* Save the IER and disable interrupts */
/* Save the IER and disable interrupts preserving the UUE bit */
ier = serial8250_early_in(port, UART_IER);
serial8250_early_out(port, UART_IER, 0);
if (ier)
serial8250_early_out(port, UART_IER, ier & UART_IER_UUE);
uart_console_write(port, s, count, serial_putc);
/* Wait for transmitter to become empty and restore the IER */
wait_for_xmitr(port);
serial8250_early_out(port, UART_IER, ier);
if (ier)
serial8250_early_out(port, UART_IER, ier);
}
static unsigned int __init probe_baud(struct uart_port *port)
@ -124,9 +127,11 @@ static void __init init_port(struct earlycon_device *device)
struct uart_port *port = &device->port;
unsigned int divisor;
unsigned char c;
unsigned int ier;
serial8250_early_out(port, UART_LCR, 0x3); /* 8n1 */
serial8250_early_out(port, UART_IER, 0); /* no interrupt */
ier = serial8250_early_in(port, UART_IER);
serial8250_early_out(port, UART_IER, ier & UART_IER_UUE); /* no interrupt */
serial8250_early_out(port, UART_FCR, 0); /* no fifo */
serial8250_early_out(port, UART_MCR, 0x3); /* DTR + RTS */

View File

@ -106,6 +106,28 @@ static u32 uart_read(struct uart_8250_port *up, u32 reg)
return readl(up->port.membase + (reg << up->port.regshift));
}
static void omap8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct uart_8250_port *up = up_to_u8250p(port);
struct omap8250_priv *priv = up->port.private_data;
u8 lcr;
serial8250_do_set_mctrl(port, mctrl);
/*
* Turn off autoRTS if RTS is lowered and restore autoRTS setting
* if RTS is raised
*/
lcr = serial_in(up, UART_LCR);
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
priv->efr |= UART_EFR_RTS;
else
priv->efr &= ~UART_EFR_RTS;
serial_out(up, UART_EFR, priv->efr);
serial_out(up, UART_LCR, lcr);
}
/*
* Work Around for Errata i202 (2430, 3430, 3630, 4430 and 4460)
* The access to uart register after MDR1 Access
@ -397,12 +419,12 @@ static void omap_8250_set_termios(struct uart_port *port,
priv->efr = 0;
up->mcr &= ~(UART_MCR_RTS | UART_MCR_XONANY);
if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) {
/* Enable AUTORTS and AUTOCTS */
priv->efr |= UART_EFR_CTS | UART_EFR_RTS;
up->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF);
/* Ensure MCR RTS is asserted */
up->mcr |= UART_MCR_RTS;
if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) {
/* Enable AUTOCTS (autoRTS is enabled when RTS is raised) */
up->port.status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
priv->efr |= UART_EFR_CTS;
} else if (up->port.flags & UPF_SOFT_FLOW) {
/*
* IXON Flag:
@ -417,8 +439,10 @@ static void omap_8250_set_termios(struct uart_port *port,
* Enable XON/XOFF flow control on output.
* Transmit XON1, XOFF1
*/
if (termios->c_iflag & IXOFF)
if (termios->c_iflag & IXOFF) {
up->port.status |= UPSTAT_AUTOXOFF;
priv->efr |= OMAP_UART_SW_TX;
}
/*
* IXANY Flag:
@ -450,18 +474,18 @@ static void omap_8250_set_termios(struct uart_port *port,
static void omap_8250_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate)
{
struct uart_8250_port *up =
container_of(port, struct uart_8250_port, port);
struct omap8250_priv *priv = up->port.private_data;
struct uart_8250_port *up = up_to_u8250p(port);
u8 efr;
pm_runtime_get_sync(port->dev);
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
serial_out(up, UART_EFR, priv->efr | UART_EFR_ECB);
efr = serial_in(up, UART_EFR);
serial_out(up, UART_EFR, efr | UART_EFR_ECB);
serial_out(up, UART_LCR, 0);
serial_out(up, UART_IER, (state != 0) ? UART_IERX_SLEEP : 0);
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
serial_out(up, UART_EFR, priv->efr);
serial_out(up, UART_EFR, efr);
serial_out(up, UART_LCR, 0);
pm_runtime_mark_last_busy(port->dev);
@ -1007,6 +1031,7 @@ static int omap8250_probe(struct platform_device *pdev)
up.capabilities |= UART_CAP_RPM;
#endif
up.port.set_termios = omap_8250_set_termios;
up.port.set_mctrl = omap8250_set_mctrl;
up.port.pm = omap_8250_pm;
up.port.startup = omap_8250_startup;
up.port.shutdown = omap_8250_shutdown;
@ -1248,6 +1273,46 @@ static int omap8250_runtime_resume(struct device *dev)
}
#endif
#ifdef CONFIG_SERIAL_8250_OMAP_TTYO_FIXUP
static int __init omap8250_console_fixup(void)
{
char *omap_str;
char *options;
u8 idx;
if (strstr(boot_command_line, "console=ttyS"))
/* user set a ttyS based name for the console */
return 0;
omap_str = strstr(boot_command_line, "console=ttyO");
if (!omap_str)
/* user did not set ttyO based console, so we don't care */
return 0;
omap_str += 12;
if ('0' <= *omap_str && *omap_str <= '9')
idx = *omap_str - '0';
else
return 0;
omap_str++;
if (omap_str[0] == ',') {
omap_str++;
options = omap_str;
} else {
options = NULL;
}
add_preferred_console("ttyS", idx, options);
pr_err("WARNING: Your 'console=ttyO%d' has been replaced by 'ttyS%d'\n",
idx, idx);
pr_err("This ensures that you still see kernel messages. Please\n");
pr_err("update your kernel commandline.\n");
return 0;
}
console_initcall(omap8250_console_fixup);
#endif
static const struct dev_pm_ops omap8250_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(omap8250_suspend, omap8250_resume)
SET_RUNTIME_PM_OPS(omap8250_runtime_suspend,
@ -1269,7 +1334,6 @@ static struct platform_driver omap8250_platform_driver = {
.name = "omap8250",
.pm = &omap8250_dev_pm_ops,
.of_match_table = omap8250_dt_ids,
.owner = THIS_MODULE,
},
.probe = omap8250_probe,
.remove = omap8250_remove,

View File

@ -221,13 +221,13 @@ pci_hp_diva_setup(struct serial_private *priv,
*/
static int pci_inteli960ni_init(struct pci_dev *dev)
{
unsigned long oldval;
u32 oldval;
if (!(dev->subsystem_device & 0x1000))
return -ENODEV;
/* is firmware started? */
pci_read_config_dword(dev, 0x44, (void *)&oldval);
pci_read_config_dword(dev, 0x44, &oldval);
if (oldval == 0x00001000L) { /* RESET value */
dev_dbg(&dev->dev, "Local i960 firmware missing\n");
return -ENODEV;

View File

@ -426,7 +426,7 @@ static int serial_pnp_guess_board(struct pnp_dev *dev)
static int
serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
{
struct uart_8250_port uart;
struct uart_8250_port uart, *port;
int ret, line, flags = dev_id->driver_data;
if (flags & UNKNOWN_DEV) {
@ -471,6 +471,10 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
if (line < 0 || (flags & CIR_PORT))
return -ENODEV;
port = serial8250_get_port(line);
if (uart_console(&port->port))
dev->capabilities |= PNP_CONSOLE;
pnp_set_drvdata(dev, (void *)((long)line + 1));
return 0;
}
@ -478,6 +482,8 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
static void serial_pnp_remove(struct pnp_dev *dev)
{
long line = (long)pnp_get_drvdata(dev);
dev->capabilities &= ~PNP_CONSOLE;
if (line)
serial8250_unregister_port(line - 1);
}

View File

@ -308,6 +308,25 @@ config SERIAL_8250_OMAP
This driver uses ttyS instead of ttyO.
config SERIAL_8250_OMAP_TTYO_FIXUP
bool "Replace ttyO with ttyS"
depends on SERIAL_8250_OMAP=y && SERIAL_8250_CONSOLE
default y
help
This option replaces the "console=ttyO" argument with the matching
ttyS argument if the user did not specified it on the command line.
This ensures that the user can see the kernel output during boot
which he wouldn't see otherwise. The getty has still to be configured
for ttyS instead of ttyO regardless of this option.
This option is intended for people who "automatically" enable this
driver without knowing that this driver requires a different console=
argument. If you read this, please keep this option disabled and
instead update your kernel command line. If you prepare a kernel for a
distribution or other kind of larger user base then you probably want
to keep this option enabled. Otherwise people might complain about a
not booting kernel because the serial console remains silent in case
they forgot to update the command line.
config SERIAL_8250_FINTEK
tristate "Support for Fintek F81216A LPC to 4 UART"
depends on SERIAL_8250 && PNP

View File

@ -241,6 +241,7 @@ config SERIAL_SAMSUNG
tristate "Samsung SoC serial support"
depends on PLAT_SAMSUNG || ARCH_EXYNOS
select SERIAL_CORE
select SERIAL_EARLYCON
help
Support for the on-chip UARTs on the Samsung S3C24XX series CPUs,
providing /dev/ttySAC0, 1 and 2 (note, some machines may not
@ -482,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_MRST_MAX3110
tristate "SPI UART driver for Max3110"
depends on SPI_DW_PCI
select SERIAL_CORE
select SERIAL_CORE_CONSOLE
help
This is the UART protocol driver for the MAX3110 device on
the Intel Moorestown platform. On other systems use the max3100
driver.
config SERIAL_MFD_HSU
tristate "Medfield High Speed UART support"
depends on PCI
@ -1094,6 +1085,16 @@ config SERIAL_VT8500_CONSOLE
depends on SERIAL_VT8500=y
select SERIAL_CORE_CONSOLE
config SERIAL_ETRAXFS
bool "ETRAX FS serial port support"
depends on ETRAX_ARCH_V32 && OF
select SERIAL_CORE
config SERIAL_ETRAXFS_CONSOLE
bool "ETRAX FS serial console support"
depends on SERIAL_ETRAXFS
select SERIAL_CORE_CONSOLE
config SERIAL_NETX
tristate "NetX serial port support"
depends on ARCH_NETX
@ -1549,6 +1550,21 @@ config SERIAL_FSL_LPUART_CONSOLE
If you have enabled the lpuart serial port on the Freescale SoCs,
you can make it the console by answering Y to this option.
config SERIAL_CONEXANT_DIGICOLOR
tristate "Conexant Digicolor CX92xxx USART serial port support"
depends on OF
select SERIAL_CORE
help
Support for the on-chip USART on Conexant Digicolor SoCs.
config SERIAL_CONEXANT_DIGICOLOR_CONSOLE
bool "Console on Conexant Digicolor serial port"
depends on SERIAL_CONEXANT_DIGICOLOR=y
select SERIAL_CORE_CONSOLE
help
If you have enabled the USART serial port on Conexant Digicolor
SoCs, you can make it the console by answering Y to this option.
config SERIAL_ST_ASC
tristate "ST ASC serial port support"
select SERIAL_CORE
@ -1577,6 +1593,24 @@ config SERIAL_MEN_Z135
This driver can also be build as a module. If so, the module will be called
men_z135_uart.ko
config SERIAL_SPRD
tristate "Support for Spreadtrum serial"
depends on ARCH_SPRD
select SERIAL_CORE
help
This enables the driver for the Spreadtrum's serial.
config SERIAL_SPRD_CONSOLE
bool "Spreadtrum UART console support"
depends on SERIAL_SPRD=y
select SERIAL_CORE_CONSOLE
select SERIAL_EARLYCON
help
Support for early debug console using Spreadtrum's serial. This enables
the console before standard serial driver is probed. This is enabled
with "earlycon" on the kernel command line. The console is
enabled when early_param is processed.
endmenu
config SERIAL_MCTRL_GPIO

View File

@ -51,6 +51,7 @@ obj-$(CONFIG_SERIAL_MPSC) += mpsc.o
obj-$(CONFIG_SERIAL_MESON) += meson_uart.o
obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o
obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o
obj-$(CONFIG_SERIAL_ETRAXFS) += etraxfs-uart.o
obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o
obj-$(CONFIG_SERIAL_SC16IS7XX) += sc16is7xx.o
obj-$(CONFIG_SERIAL_JSM) += jsm/
@ -77,7 +78,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_MRST_MAX3110) += mrst_max3110.o
obj-$(CONFIG_SERIAL_MFD_HSU) += mfd.o
obj-$(CONFIG_SERIAL_IFX6X60) += ifx6x60.o
obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o
@ -92,7 +92,9 @@ obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o
obj-$(CONFIG_SERIAL_ARC) += arc_uart.o
obj-$(CONFIG_SERIAL_RP2) += rp2.o
obj-$(CONFIG_SERIAL_FSL_LPUART) += fsl_lpuart.o
obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR) += digicolor-usart.o
obj-$(CONFIG_SERIAL_MEN_Z135) += men_z135_uart.o
obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
# GPIOLIB helpers for modem control lines
obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o

View File

@ -441,6 +441,7 @@ static int altera_jtaguart_probe(struct platform_device *pdev)
port->iotype = SERIAL_IO_MEM;
port->ops = &altera_jtaguart_ops;
port->flags = UPF_BOOT_AUTOCONF;
port->dev = &pdev->dev;
uart_add_one_port(&altera_jtaguart_driver, port);

View File

@ -589,6 +589,7 @@ static int altera_uart_probe(struct platform_device *pdev)
port->iotype = SERIAL_IO_MEM;
port->ops = &altera_uart_ops;
port->flags = UPF_BOOT_AUTOCONF;
port->dev = &pdev->dev;
platform_set_drvdata(pdev, port);

View File

@ -341,13 +341,37 @@ static u_int atmel_tx_empty(struct uart_port *port)
static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
{
unsigned int control = 0;
unsigned int mode;
unsigned int mode = UART_GET_MR(port);
unsigned int rts_paused, rts_ready;
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
/* override mode to RS485 if needed, otherwise keep the current mode */
if (port->rs485.flags & SER_RS485_ENABLED) {
if ((port->rs485.delay_rts_after_send) > 0)
UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
mode &= ~ATMEL_US_USMODE;
mode |= ATMEL_US_USMODE_RS485;
}
/* set the RTS line state according to the mode */
if ((mode & ATMEL_US_USMODE) == ATMEL_US_USMODE_HWHS) {
/* force RTS line to high level */
rts_paused = ATMEL_US_RTSEN;
/* give the control of the RTS line back to the hardware */
rts_ready = ATMEL_US_RTSDIS;
} else {
/* force RTS line to high level */
rts_paused = ATMEL_US_RTSDIS;
/* force RTS line to low level */
rts_ready = ATMEL_US_RTSEN;
}
if (mctrl & TIOCM_RTS)
control |= ATMEL_US_RTSEN;
control |= rts_ready;
else
control |= ATMEL_US_RTSDIS;
control |= rts_paused;
if (mctrl & TIOCM_DTR)
control |= ATMEL_US_DTREN;
@ -359,23 +383,12 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
mctrl_gpio_set(atmel_port->gpios, mctrl);
/* Local loopback mode? */
mode = UART_GET_MR(port) & ~ATMEL_US_CHMODE;
mode &= ~ATMEL_US_CHMODE;
if (mctrl & TIOCM_LOOP)
mode |= ATMEL_US_CHMODE_LOC_LOOP;
else
mode |= ATMEL_US_CHMODE_NORMAL;
/* Resetting serial mode to RS232 (0x0) */
mode &= ~ATMEL_US_USMODE;
if (port->rs485.flags & SER_RS485_ENABLED) {
dev_dbg(port->dev, "Setting UART to RS485\n");
if ((port->rs485.delay_rts_after_send) > 0)
UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
mode |= ATMEL_US_USMODE_RS485;
} else {
dev_dbg(port->dev, "Setting UART to RS232\n");
}
UART_PUT_MR(port, mode);
}
@ -725,7 +738,11 @@ static void atmel_complete_tx_dma(void *arg)
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
/* Do we really need this? */
/*
* xmit is a circular buffer so, if we have just send data from
* xmit->tail to the end of xmit->buf, now we have to transmit the
* remaining data from the beginning of xmit->buf to xmit->head.
*/
if (!uart_circ_empty(xmit))
tasklet_schedule(&atmel_port->tasklet);
@ -784,17 +801,17 @@ static void atmel_tx_dma(struct uart_port *port)
BUG_ON(!sg_dma_len(sg));
desc = dmaengine_prep_slave_sg(chan,
sg,
1,
DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT |
DMA_CTRL_ACK);
sg,
1,
DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT |
DMA_CTRL_ACK);
if (!desc) {
dev_err(port->dev, "Failed to send via dma!\n");
return;
}
dma_sync_sg_for_device(port->dev, sg, 1, DMA_MEM_TO_DEV);
dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE);
atmel_port->desc_tx = desc;
desc->callback = atmel_complete_tx_dma;
@ -927,7 +944,7 @@ static void atmel_rx_from_dma(struct uart_port *port)
dma_sync_sg_for_cpu(port->dev,
&atmel_port->sg_rx,
1,
DMA_DEV_TO_MEM);
DMA_FROM_DEVICE);
/*
* ring->head points to the end of data already written by the DMA.
@ -974,7 +991,7 @@ static void atmel_rx_from_dma(struct uart_port *port)
dma_sync_sg_for_device(port->dev,
&atmel_port->sg_rx,
1,
DMA_DEV_TO_MEM);
DMA_FROM_DEVICE);
/*
* Drop the lock here since it might end up calling
@ -1012,13 +1029,13 @@ static int atmel_prepare_rx_dma(struct uart_port *port)
/* UART circular rx buffer is an aligned page. */
BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK);
sg_set_page(&atmel_port->sg_rx,
virt_to_page(ring->buf),
ATMEL_SERIAL_RINGSIZE,
(int)ring->buf & ~PAGE_MASK);
nent = dma_map_sg(port->dev,
&atmel_port->sg_rx,
1,
DMA_FROM_DEVICE);
virt_to_page(ring->buf),
ATMEL_SERIAL_RINGSIZE,
(int)ring->buf & ~PAGE_MASK);
nent = dma_map_sg(port->dev,
&atmel_port->sg_rx,
1,
DMA_FROM_DEVICE);
if (!nent) {
dev_dbg(port->dev, "need to release resource of dma\n");
@ -1047,11 +1064,11 @@ static int atmel_prepare_rx_dma(struct uart_port *port)
* each one is half ring buffer size
*/
desc = dmaengine_prep_dma_cyclic(atmel_port->chan_rx,
sg_dma_address(&atmel_port->sg_rx),
sg_dma_len(&atmel_port->sg_rx),
sg_dma_len(&atmel_port->sg_rx)/2,
DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT);
sg_dma_address(&atmel_port->sg_rx),
sg_dma_len(&atmel_port->sg_rx),
sg_dma_len(&atmel_port->sg_rx)/2,
DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT);
desc->callback = atmel_complete_rx_dma;
desc->callback_param = port;
atmel_port->desc_rx = desc;
@ -1921,12 +1938,14 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
unsigned long flags;
unsigned int mode, imr, quot, baud;
unsigned int old_mode, mode, imr, quot, baud;
/* Get current mode register */
mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL
| ATMEL_US_NBSTOP | ATMEL_US_PAR
| ATMEL_US_USMODE);
/* save the current mode register */
mode = old_mode = UART_GET_MR(port);
/* reset the mode, clock divisor, parity, stop bits and data size */
mode &= ~(ATMEL_US_USCLKS | ATMEL_US_CHRL | ATMEL_US_NBSTOP |
ATMEL_US_PAR | ATMEL_US_USMODE);
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
quot = uart_get_divisor(port, baud);
@ -1971,12 +1990,6 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
} else
mode |= ATMEL_US_PAR_NONE;
/* hardware handshake (RTS/CTS) */
if (termios->c_cflag & CRTSCTS)
mode |= ATMEL_US_USMODE_HWHS;
else
mode |= ATMEL_US_USMODE_NORMAL;
spin_lock_irqsave(&port->lock, flags);
port->read_status_mask = ATMEL_US_OVRE;
@ -2020,18 +2033,40 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
/* disable receiver and transmitter */
UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS);
/* Resetting serial mode to RS232 (0x0) */
mode &= ~ATMEL_US_USMODE;
/* mode */
if (port->rs485.flags & SER_RS485_ENABLED) {
if ((port->rs485.delay_rts_after_send) > 0)
UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
mode |= ATMEL_US_USMODE_RS485;
} else if (termios->c_cflag & CRTSCTS) {
/* RS232 with hardware handshake (RTS/CTS) */
mode |= ATMEL_US_USMODE_HWHS;
} else {
/* RS232 without hadware handshake */
mode |= ATMEL_US_USMODE_NORMAL;
}
/* set the parity, stop bits and data size */
/* set the mode, clock divisor, parity, stop bits and data size */
UART_PUT_MR(port, mode);
/*
* when switching the mode, set the RTS line state according to the
* new mode, otherwise keep the former state
*/
if ((old_mode & ATMEL_US_USMODE) != (mode & ATMEL_US_USMODE)) {
unsigned int rts_state;
if ((mode & ATMEL_US_USMODE) == ATMEL_US_USMODE_HWHS) {
/* let the hardware control the RTS line */
rts_state = ATMEL_US_RTSDIS;
} else {
/* force RTS line to low level */
rts_state = ATMEL_US_RTSEN;
}
UART_PUT_CR(port, rts_state);
}
/* set the baud rate */
UART_PUT_BRGR(port, quot);
UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
@ -2565,7 +2600,7 @@ static int atmel_serial_probe(struct platform_device *pdev)
ret = atmel_init_port(port, pdev);
if (ret)
goto err;
goto err_clear_bit;
if (!atmel_use_pdc_rx(&port->uart)) {
ret = -ENOMEM;
@ -2596,6 +2631,12 @@ static int atmel_serial_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 1);
platform_set_drvdata(pdev, port);
/*
* The peripheral clock has been disabled by atmel_init_port():
* enable it before accessing I/O registers
*/
clk_prepare_enable(port->clk);
if (rs485_enabled) {
UART_PUT_MR(&port->uart, ATMEL_US_USMODE_NORMAL);
UART_PUT_CR(&port->uart, ATMEL_US_RTSEN);
@ -2606,6 +2647,12 @@ static int atmel_serial_probe(struct platform_device *pdev)
*/
atmel_get_ip_name(&port->uart);
/*
* The peripheral clock can now safely be disabled till the port
* is used
*/
clk_disable_unprepare(port->clk);
return 0;
err_add_port:
@ -2616,6 +2663,8 @@ err_alloc_ring:
clk_put(port->clk);
port->clk = NULL;
}
err_clear_bit:
clear_bit(port->uart.line, atmel_ports_in_use);
err:
return ret;
}

View File

@ -0,0 +1,560 @@
/*
* Driver for Conexant Digicolor serial ports (USART)
*
* Author: Baruch Siach <baruch@tkos.co.il>
*
* Copyright (C) 2014 Paradox Innovation Ltd.
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/module.h>
#include <linux/console.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/workqueue.h>
#define UA_ENABLE 0x00
#define UA_ENABLE_ENABLE BIT(0)
#define UA_CONTROL 0x01
#define UA_CONTROL_RX_ENABLE BIT(0)
#define UA_CONTROL_TX_ENABLE BIT(1)
#define UA_CONTROL_SOFT_RESET BIT(2)
#define UA_STATUS 0x02
#define UA_STATUS_PARITY_ERR BIT(0)
#define UA_STATUS_FRAME_ERR BIT(1)
#define UA_STATUS_OVERRUN_ERR BIT(2)
#define UA_STATUS_TX_READY BIT(6)
#define UA_CONFIG 0x03
#define UA_CONFIG_CHAR_LEN BIT(0)
#define UA_CONFIG_STOP_BITS BIT(1)
#define UA_CONFIG_PARITY BIT(2)
#define UA_CONFIG_ODD_PARITY BIT(4)
#define UA_EMI_REC 0x04
#define UA_HBAUD_LO 0x08
#define UA_HBAUD_HI 0x09
#define UA_STATUS_FIFO 0x0a
#define UA_STATUS_FIFO_RX_EMPTY BIT(2)
#define UA_STATUS_FIFO_RX_INT_ALMOST BIT(3)
#define UA_STATUS_FIFO_TX_FULL BIT(4)
#define UA_STATUS_FIFO_TX_INT_ALMOST BIT(7)
#define UA_CONFIG_FIFO 0x0b
#define UA_CONFIG_FIFO_RX_THRESH 7
#define UA_CONFIG_FIFO_RX_FIFO_MODE BIT(3)
#define UA_CONFIG_FIFO_TX_FIFO_MODE BIT(7)
#define UA_INTFLAG_CLEAR 0x1c
#define UA_INTFLAG_SET 0x1d
#define UA_INT_ENABLE 0x1e
#define UA_INT_STATUS 0x1f
#define UA_INT_TX BIT(0)
#define UA_INT_RX BIT(1)
#define DIGICOLOR_USART_NR 3
/*
* We use the 16 bytes hardware FIFO to buffer Rx traffic. Rx interrupt is
* only produced when the FIFO is filled more than a certain configurable
* threshold. Unfortunately, there is no way to set this threshold below half
* FIFO. This means that we must periodically poll the FIFO status register to
* see whether there are waiting Rx bytes.
*/
struct digicolor_port {
struct uart_port port;
struct delayed_work rx_poll_work;
};
static struct uart_port *digicolor_ports[DIGICOLOR_USART_NR];
static bool digicolor_uart_tx_full(struct uart_port *port)
{
return !!(readb_relaxed(port->membase + UA_STATUS_FIFO) &
UA_STATUS_FIFO_TX_FULL);
}
static bool digicolor_uart_rx_empty(struct uart_port *port)
{
return !!(readb_relaxed(port->membase + UA_STATUS_FIFO) &
UA_STATUS_FIFO_RX_EMPTY);
}
static void digicolor_uart_stop_tx(struct uart_port *port)
{
u8 int_enable = readb_relaxed(port->membase + UA_INT_ENABLE);
int_enable &= ~UA_INT_TX;
writeb_relaxed(int_enable, port->membase + UA_INT_ENABLE);
}
static void digicolor_uart_start_tx(struct uart_port *port)
{
u8 int_enable = readb_relaxed(port->membase + UA_INT_ENABLE);
int_enable |= UA_INT_TX;
writeb_relaxed(int_enable, port->membase + UA_INT_ENABLE);
}
static void digicolor_uart_stop_rx(struct uart_port *port)
{
u8 int_enable = readb_relaxed(port->membase + UA_INT_ENABLE);
int_enable &= ~UA_INT_RX;
writeb_relaxed(int_enable, port->membase + UA_INT_ENABLE);
}
static void digicolor_rx_poll(struct work_struct *work)
{
struct digicolor_port *dp =
container_of(to_delayed_work(work),
struct digicolor_port, rx_poll_work);
if (!digicolor_uart_rx_empty(&dp->port))
/* force RX interrupt */
writeb_relaxed(UA_INT_RX, dp->port.membase + UA_INTFLAG_SET);
schedule_delayed_work(&dp->rx_poll_work, msecs_to_jiffies(100));
}
static void digicolor_uart_rx(struct uart_port *port)
{
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
while (1) {
u8 status, ch;
unsigned int ch_flag;
if (digicolor_uart_rx_empty(port))
break;
ch = readb_relaxed(port->membase + UA_EMI_REC);
status = readb_relaxed(port->membase + UA_STATUS);
port->icount.rx++;
ch_flag = TTY_NORMAL;
if (status) {
if (status & UA_STATUS_PARITY_ERR)
port->icount.parity++;
else if (status & UA_STATUS_FRAME_ERR)
port->icount.frame++;
else if (status & UA_STATUS_OVERRUN_ERR)
port->icount.overrun++;
status &= port->read_status_mask;
if (status & UA_STATUS_PARITY_ERR)
ch_flag = TTY_PARITY;
else if (status & UA_STATUS_FRAME_ERR)
ch_flag = TTY_FRAME;
else if (status & UA_STATUS_OVERRUN_ERR)
ch_flag = TTY_OVERRUN;
}
if (status & port->ignore_status_mask)
continue;
uart_insert_char(port, status, UA_STATUS_OVERRUN_ERR, ch,
ch_flag);
}
spin_unlock_irqrestore(&port->lock, flags);
tty_flip_buffer_push(&port->state->port);
}
static void digicolor_uart_tx(struct uart_port *port)
{
struct circ_buf *xmit = &port->state->xmit;
unsigned long flags;
if (digicolor_uart_tx_full(port))
return;
spin_lock_irqsave(&port->lock, flags);
if (port->x_char) {
writeb_relaxed(port->x_char, port->membase + UA_EMI_REC);
port->icount.tx++;
port->x_char = 0;
goto out;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
digicolor_uart_stop_tx(port);
goto out;
}
while (!uart_circ_empty(xmit)) {
writeb(xmit->buf[xmit->tail], port->membase + UA_EMI_REC);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
if (digicolor_uart_tx_full(port))
break;
}
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
out:
spin_unlock_irqrestore(&port->lock, flags);
}
static irqreturn_t digicolor_uart_int(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
u8 int_status = readb_relaxed(port->membase + UA_INT_STATUS);
writeb_relaxed(UA_INT_RX | UA_INT_TX,
port->membase + UA_INTFLAG_CLEAR);
if (int_status & UA_INT_RX)
digicolor_uart_rx(port);
if (int_status & UA_INT_TX)
digicolor_uart_tx(port);
return IRQ_HANDLED;
}
static unsigned int digicolor_uart_tx_empty(struct uart_port *port)
{
u8 status = readb_relaxed(port->membase + UA_STATUS);
return (status & UA_STATUS_TX_READY) ? TIOCSER_TEMT : 0;
}
static unsigned int digicolor_uart_get_mctrl(struct uart_port *port)
{
return TIOCM_CTS;
}
static void digicolor_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
}
static void digicolor_uart_break_ctl(struct uart_port *port, int state)
{
}
static int digicolor_uart_startup(struct uart_port *port)
{
struct digicolor_port *dp =
container_of(port, struct digicolor_port, port);
writeb_relaxed(UA_ENABLE_ENABLE, port->membase + UA_ENABLE);
writeb_relaxed(UA_CONTROL_SOFT_RESET, port->membase + UA_CONTROL);
writeb_relaxed(0, port->membase + UA_CONTROL);
writeb_relaxed(UA_CONFIG_FIFO_RX_FIFO_MODE
| UA_CONFIG_FIFO_TX_FIFO_MODE | UA_CONFIG_FIFO_RX_THRESH,
port->membase + UA_CONFIG_FIFO);
writeb_relaxed(UA_STATUS_FIFO_RX_INT_ALMOST,
port->membase + UA_STATUS_FIFO);
writeb_relaxed(UA_CONTROL_RX_ENABLE | UA_CONTROL_TX_ENABLE,
port->membase + UA_CONTROL);
writeb_relaxed(UA_INT_TX | UA_INT_RX,
port->membase + UA_INT_ENABLE);
schedule_delayed_work(&dp->rx_poll_work, msecs_to_jiffies(100));
return 0;
}
static void digicolor_uart_shutdown(struct uart_port *port)
{
struct digicolor_port *dp =
container_of(port, struct digicolor_port, port);
writeb_relaxed(0, port->membase + UA_ENABLE);
cancel_delayed_work_sync(&dp->rx_poll_work);
}
static void digicolor_uart_set_termios(struct uart_port *port,
struct ktermios *termios,
struct ktermios *old)
{
unsigned int baud, divisor;
u8 config = 0;
unsigned long flags;
/* Mask termios capabilities we don't support */
termios->c_cflag &= ~CMSPAR;
termios->c_iflag &= ~(BRKINT | IGNBRK);
/* Limit baud rates so that we don't need the fractional divider */
baud = uart_get_baud_rate(port, termios, old,
port->uartclk / (0x10000*16),
port->uartclk / 256);
divisor = uart_get_divisor(port, baud) - 1;
switch (termios->c_cflag & CSIZE) {
case CS7:
break;
case CS8:
default:
config |= UA_CONFIG_CHAR_LEN;
break;
}
if (termios->c_cflag & CSTOPB)
config |= UA_CONFIG_STOP_BITS;
if (termios->c_cflag & PARENB) {
config |= UA_CONFIG_PARITY;
if (termios->c_cflag & PARODD)
config |= UA_CONFIG_ODD_PARITY;
}
/* Set read status mask */
port->read_status_mask = UA_STATUS_OVERRUN_ERR;
if (termios->c_iflag & INPCK)
port->read_status_mask |= UA_STATUS_PARITY_ERR
| UA_STATUS_FRAME_ERR;
/* Set status ignore mask */
port->ignore_status_mask = 0;
if (!(termios->c_cflag & CREAD))
port->ignore_status_mask |= UA_STATUS_OVERRUN_ERR
| UA_STATUS_PARITY_ERR | UA_STATUS_FRAME_ERR;
spin_lock_irqsave(&port->lock, flags);
uart_update_timeout(port, termios->c_cflag, baud);
writeb_relaxed(config, port->membase + UA_CONFIG);
writeb_relaxed(divisor & 0xff, port->membase + UA_HBAUD_LO);
writeb_relaxed(divisor >> 8, port->membase + UA_HBAUD_HI);
spin_unlock_irqrestore(&port->lock, flags);
}
static const char *digicolor_uart_type(struct uart_port *port)
{
return (port->type == PORT_DIGICOLOR) ? "DIGICOLOR USART" : NULL;
}
static void digicolor_uart_config_port(struct uart_port *port, int flags)
{
if (flags & UART_CONFIG_TYPE)
port->type = PORT_DIGICOLOR;
}
static void digicolor_uart_release_port(struct uart_port *port)
{
}
static int digicolor_uart_request_port(struct uart_port *port)
{
return 0;
}
static const struct uart_ops digicolor_uart_ops = {
.tx_empty = digicolor_uart_tx_empty,
.set_mctrl = digicolor_uart_set_mctrl,
.get_mctrl = digicolor_uart_get_mctrl,
.stop_tx = digicolor_uart_stop_tx,
.start_tx = digicolor_uart_start_tx,
.stop_rx = digicolor_uart_stop_rx,
.break_ctl = digicolor_uart_break_ctl,
.startup = digicolor_uart_startup,
.shutdown = digicolor_uart_shutdown,
.set_termios = digicolor_uart_set_termios,
.type = digicolor_uart_type,
.config_port = digicolor_uart_config_port,
.release_port = digicolor_uart_release_port,
.request_port = digicolor_uart_request_port,
};
static void digicolor_uart_console_putchar(struct uart_port *port, int ch)
{
while (digicolor_uart_tx_full(port))
cpu_relax();
writeb_relaxed(ch, port->membase + UA_EMI_REC);
}
static void digicolor_uart_console_write(struct console *co, const char *c,
unsigned n)
{
struct uart_port *port = digicolor_ports[co->index];
u8 status;
unsigned long flags;
int locked = 1;
if (oops_in_progress)
locked = spin_trylock_irqsave(&port->lock, flags);
else
spin_lock_irqsave(&port->lock, flags);
uart_console_write(port, c, n, digicolor_uart_console_putchar);
if (locked)
spin_unlock_irqrestore(&port->lock, flags);
/* Wait for transmitter to become empty */
do {
status = readb_relaxed(port->membase + UA_STATUS);
} while ((status & UA_STATUS_TX_READY) == 0);
}
static int digicolor_uart_console_setup(struct console *co, char *options)
{
int baud = 115200, bits = 8, parity = 'n', flow = 'n';
struct uart_port *port;
if (co->index < 0 || co->index >= DIGICOLOR_USART_NR)
return -EINVAL;
port = digicolor_ports[co->index];
if (!port)
return -ENODEV;
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
return uart_set_options(port, co, baud, parity, bits, flow);
}
static struct console digicolor_console = {
.name = "ttyS",
.device = uart_console_device,
.write = digicolor_uart_console_write,
.setup = digicolor_uart_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
};
static struct uart_driver digicolor_uart = {
.driver_name = "digicolor-usart",
.dev_name = "ttyS",
.nr = DIGICOLOR_USART_NR,
};
static int digicolor_uart_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
int ret, index;
struct digicolor_port *dp;
struct resource *res;
struct clk *uart_clk;
if (!np) {
dev_err(&pdev->dev, "Missing device tree node\n");
return -ENXIO;
}
index = of_alias_get_id(np, "serial");
if (index < 0 || index >= DIGICOLOR_USART_NR)
return -EINVAL;
dp = devm_kzalloc(&pdev->dev, sizeof(*dp), GFP_KERNEL);
if (!dp)
return -ENOMEM;
uart_clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(uart_clk))
return PTR_ERR(uart_clk);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dp->port.mapbase = res->start;
dp->port.membase = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(dp->port.membase))
return PTR_ERR(dp->port.membase);
dp->port.irq = platform_get_irq(pdev, 0);
if (IS_ERR_VALUE(dp->port.irq))
return dp->port.irq;
dp->port.iotype = UPIO_MEM;
dp->port.uartclk = clk_get_rate(uart_clk);
dp->port.fifosize = 16;
dp->port.dev = &pdev->dev;
dp->port.ops = &digicolor_uart_ops;
dp->port.line = index;
dp->port.type = PORT_DIGICOLOR;
spin_lock_init(&dp->port.lock);
digicolor_ports[index] = &dp->port;
platform_set_drvdata(pdev, &dp->port);
INIT_DELAYED_WORK(&dp->rx_poll_work, digicolor_rx_poll);
ret = devm_request_irq(&pdev->dev, dp->port.irq, digicolor_uart_int, 0,
dev_name(&pdev->dev), &dp->port);
if (ret)
return ret;
return uart_add_one_port(&digicolor_uart, &dp->port);
}
static int digicolor_uart_remove(struct platform_device *pdev)
{
struct uart_port *port = platform_get_drvdata(pdev);
uart_remove_one_port(&digicolor_uart, port);
return 0;
}
static const struct of_device_id digicolor_uart_dt_ids[] = {
{ .compatible = "cnxt,cx92755-usart", },
{ }
};
MODULE_DEVICE_TABLE(of, digicolor_uart_dt_ids);
static struct platform_driver digicolor_uart_platform = {
.driver = {
.name = "digicolor-usart",
.of_match_table = of_match_ptr(digicolor_uart_dt_ids),
},
.probe = digicolor_uart_probe,
.remove = digicolor_uart_remove,
};
static int __init digicolor_uart_init(void)
{
int ret;
if (IS_ENABLED(CONFIG_SERIAL_CONEXANT_DIGICOLOR_CONSOLE)) {
digicolor_uart.cons = &digicolor_console;
digicolor_console.data = &digicolor_uart;
}
ret = uart_register_driver(&digicolor_uart);
if (ret)
return ret;
return platform_driver_register(&digicolor_uart_platform);
}
module_init(digicolor_uart_init);
static void __exit digicolor_uart_exit(void)
{
platform_driver_unregister(&digicolor_uart_platform);
uart_unregister_driver(&digicolor_uart);
}
module_exit(digicolor_uart_exit);
MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
MODULE_DESCRIPTION("Conexant Digicolor USART serial driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,996 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/platform_device.h>
#include <linux/serial_core.h>
#include <linux/tty_flip.h>
#include <linux/of.h>
#include <linux/gpio.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <hwregs/ser_defs.h>
#define DRV_NAME "etraxfs-uart"
#define UART_NR CONFIG_ETRAX_SERIAL_PORTS
#define MODIFY_REG(instance, reg, var) \
do { \
if (REG_RD_INT(ser, instance, reg) != \
REG_TYPE_CONV(int, reg_ser_##reg, var)) \
REG_WR(ser, instance, reg, var); \
} while (0)
struct uart_cris_port {
struct uart_port port;
int initialized;
int irq;
void __iomem *regi_ser;
struct gpio_desc *dtr_pin;
struct gpio_desc *dsr_pin;
struct gpio_desc *ri_pin;
struct gpio_desc *cd_pin;
int write_ongoing;
};
static struct uart_driver etraxfs_uart_driver;
static struct uart_port *console_port;
static int console_baud = 115200;
static struct uart_cris_port *etraxfs_uart_ports[UART_NR];
static void cris_serial_port_init(struct uart_port *port, int line);
static void etraxfs_uart_stop_rx(struct uart_port *port);
static inline void etraxfs_uart_start_tx_bottom(struct uart_port *port);
#ifdef CONFIG_SERIAL_ETRAXFS_CONSOLE
static void
cris_console_write(struct console *co, const char *s, unsigned int count)
{
struct uart_cris_port *up;
int i;
reg_ser_r_stat_din stat;
reg_ser_rw_tr_dma_en tr_dma_en, old;
up = etraxfs_uart_ports[co->index];
if (!up)
return;
/* Switch to manual mode. */
tr_dma_en = old = REG_RD(ser, up->regi_ser, rw_tr_dma_en);
if (tr_dma_en.en == regk_ser_yes) {
tr_dma_en.en = regk_ser_no;
REG_WR(ser, up->regi_ser, rw_tr_dma_en, tr_dma_en);
}
/* Send data. */
for (i = 0; i < count; i++) {
/* LF -> CRLF */
if (s[i] == '\n') {
do {
stat = REG_RD(ser, up->regi_ser, r_stat_din);
} while (!stat.tr_rdy);
REG_WR_INT(ser, up->regi_ser, rw_dout, '\r');
}
/* Wait until transmitter is ready and send. */
do {
stat = REG_RD(ser, up->regi_ser, r_stat_din);
} while (!stat.tr_rdy);
REG_WR_INT(ser, up->regi_ser, rw_dout, s[i]);
}
/* Restore mode. */
if (tr_dma_en.en != old.en)
REG_WR(ser, up->regi_ser, rw_tr_dma_en, old);
}
static int __init
cris_console_setup(struct console *co, char *options)
{
struct uart_port *port;
int baud = 115200;
int bits = 8;
int parity = 'n';
int flow = 'n';
if (co->index < 0 || co->index >= UART_NR)
co->index = 0;
port = &etraxfs_uart_ports[co->index]->port;
console_port = port;
co->flags |= CON_CONSDEV;
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
console_baud = baud;
cris_serial_port_init(port, co->index);
uart_set_options(port, co, baud, parity, bits, flow);
return 0;
}
static struct tty_driver *cris_console_device(struct console *co, int *index)
{
struct uart_driver *p = co->data;
*index = co->index;
return p->tty_driver;
}
static struct console cris_console = {
.name = "ttyS",
.write = cris_console_write,
.device = cris_console_device,
.setup = cris_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &etraxfs_uart_driver,
};
#endif /* CONFIG_SERIAL_ETRAXFS_CONSOLE */
static struct uart_driver etraxfs_uart_driver = {
.owner = THIS_MODULE,
.driver_name = "serial",
.dev_name = "ttyS",
.major = TTY_MAJOR,
.minor = 64,
.nr = UART_NR,
#ifdef CONFIG_SERIAL_ETRAXFS_CONSOLE
.cons = &cris_console,
#endif /* CONFIG_SERIAL_ETRAXFS_CONSOLE */
};
static inline int crisv32_serial_get_rts(struct uart_cris_port *up)
{
void __iomem *regi_ser = up->regi_ser;
/*
* Return what the user has controlled rts to or
* what the pin is? (if auto_rts is used it differs during tx)
*/
reg_ser_r_stat_din rstat = REG_RD(ser, regi_ser, r_stat_din);
return !(rstat.rts_n == regk_ser_active);
}
/*
* A set = 0 means 3.3V on the pin, bitvalue: 0=active, 1=inactive
* 0=0V , 1=3.3V
*/
static inline void crisv32_serial_set_rts(struct uart_cris_port *up,
int set, int force)
{
void __iomem *regi_ser = up->regi_ser;
unsigned long flags;
reg_ser_rw_rec_ctrl rec_ctrl;
local_irq_save(flags);
rec_ctrl = REG_RD(ser, regi_ser, rw_rec_ctrl);
if (set)
rec_ctrl.rts_n = regk_ser_active;
else
rec_ctrl.rts_n = regk_ser_inactive;
REG_WR(ser, regi_ser, rw_rec_ctrl, rec_ctrl);
local_irq_restore(flags);
}
static inline int crisv32_serial_get_cts(struct uart_cris_port *up)
{
void __iomem *regi_ser = up->regi_ser;
reg_ser_r_stat_din rstat = REG_RD(ser, regi_ser, r_stat_din);
return (rstat.cts_n == regk_ser_active);
}
/*
* Send a single character for XON/XOFF purposes. We do it in this separate
* function instead of the alternative support port.x_char, in the ...start_tx
* function, so we don't mix up this case with possibly enabling transmission
* of queued-up data (in case that's disabled after *receiving* an XOFF or
* negative CTS). This function is used for both DMA and non-DMA case; see HW
* docs specifically blessing sending characters manually when DMA for
* transmission is enabled and running. We may be asked to transmit despite
* the transmitter being disabled by a ..._stop_tx call so we need to enable
* it temporarily but restore the state afterwards.
*/
static void etraxfs_uart_send_xchar(struct uart_port *port, char ch)
{
struct uart_cris_port *up = (struct uart_cris_port *)port;
reg_ser_rw_dout dout = { .data = ch };
reg_ser_rw_ack_intr ack_intr = { .tr_rdy = regk_ser_yes };
reg_ser_r_stat_din rstat;
reg_ser_rw_tr_ctrl prev_tr_ctrl, tr_ctrl;
void __iomem *regi_ser = up->regi_ser;
unsigned long flags;
/*
* Wait for tr_rdy in case a character is already being output. Make
* sure we have integrity between the register reads and the writes
* below, but don't busy-wait with interrupts off and the port lock
* taken.
*/
spin_lock_irqsave(&port->lock, flags);
do {
spin_unlock_irqrestore(&port->lock, flags);
spin_lock_irqsave(&port->lock, flags);
prev_tr_ctrl = tr_ctrl = REG_RD(ser, regi_ser, rw_tr_ctrl);
rstat = REG_RD(ser, regi_ser, r_stat_din);
} while (!rstat.tr_rdy);
/*
* Ack an interrupt if one was just issued for the previous character
* that was output. This is required for non-DMA as the interrupt is
* used as the only indicator that the transmitter is ready and it
* isn't while this x_char is being transmitted.
*/
REG_WR(ser, regi_ser, rw_ack_intr, ack_intr);
/* Enable the transmitter in case it was disabled. */
tr_ctrl.stop = 0;
REG_WR(ser, regi_ser, rw_tr_ctrl, tr_ctrl);
/*
* Finally, send the blessed character; nothing should stop it now,
* except for an xoff-detected state, which we'll handle below.
*/
REG_WR(ser, regi_ser, rw_dout, dout);
up->port.icount.tx++;
/* There might be an xoff state to clear. */
rstat = REG_RD(ser, up->regi_ser, r_stat_din);
/*
* Clear any xoff state that *may* have been there to
* inhibit transmission of the character.
*/
if (rstat.xoff_detect) {
reg_ser_rw_xoff_clr xoff_clr = { .clr = 1 };
reg_ser_rw_tr_dma_en tr_dma_en;
REG_WR(ser, regi_ser, rw_xoff_clr, xoff_clr);
tr_dma_en = REG_RD(ser, regi_ser, rw_tr_dma_en);
/*
* If we had an xoff state but cleared it, instead sneak in a
* disabled state for the transmitter, after the character we
* sent. Thus we keep the port disabled, just as if the xoff
* state was still in effect (or actually, as if stop_tx had
* been called, as we stop DMA too).
*/
prev_tr_ctrl.stop = 1;
tr_dma_en.en = 0;
REG_WR(ser, regi_ser, rw_tr_dma_en, tr_dma_en);
}
/* Restore "previous" enabled/disabled state of the transmitter. */
REG_WR(ser, regi_ser, rw_tr_ctrl, prev_tr_ctrl);
spin_unlock_irqrestore(&port->lock, flags);
}
/*
* Do not spin_lock_irqsave or disable interrupts by other means here; it's
* already done by the caller.
*/
static void etraxfs_uart_start_tx(struct uart_port *port)
{
struct uart_cris_port *up = (struct uart_cris_port *)port;
/* we have already done below if a write is ongoing */
if (up->write_ongoing)
return;
/* Signal that write is ongoing */
up->write_ongoing = 1;
etraxfs_uart_start_tx_bottom(port);
}
static inline void etraxfs_uart_start_tx_bottom(struct uart_port *port)
{
struct uart_cris_port *up = (struct uart_cris_port *)port;
void __iomem *regi_ser = up->regi_ser;
reg_ser_rw_tr_ctrl tr_ctrl;
reg_ser_rw_intr_mask intr_mask;
tr_ctrl = REG_RD(ser, regi_ser, rw_tr_ctrl);
tr_ctrl.stop = regk_ser_no;
REG_WR(ser, regi_ser, rw_tr_ctrl, tr_ctrl);
intr_mask = REG_RD(ser, regi_ser, rw_intr_mask);
intr_mask.tr_rdy = regk_ser_yes;
REG_WR(ser, regi_ser, rw_intr_mask, intr_mask);
}
/*
* This function handles both the DMA and non-DMA case by ordering the
* transmitter to stop of after the current character. We don't need to wait
* for any such character to be completely transmitted; we do that where it
* matters, like in etraxfs_uart_set_termios. Don't busy-wait here; see
* Documentation/serial/driver: this function is called within
* spin_lock_irq{,save} and thus separate ones would be disastrous (when SMP).
* There's no documented need to set the txd pin to any particular value;
* break setting is controlled solely by etraxfs_uart_break_ctl.
*/
static void etraxfs_uart_stop_tx(struct uart_port *port)
{
struct uart_cris_port *up = (struct uart_cris_port *)port;
void __iomem *regi_ser = up->regi_ser;
reg_ser_rw_tr_ctrl tr_ctrl;
reg_ser_rw_intr_mask intr_mask;
reg_ser_rw_tr_dma_en tr_dma_en = {0};
reg_ser_rw_xoff_clr xoff_clr = {0};
/*
* For the non-DMA case, we'd get a tr_rdy interrupt that we're not
* interested in as we're not transmitting any characters. For the
* DMA case, that interrupt is already turned off, but no reason to
* waste code on conditionals here.
*/
intr_mask = REG_RD(ser, regi_ser, rw_intr_mask);
intr_mask.tr_rdy = regk_ser_no;
REG_WR(ser, regi_ser, rw_intr_mask, intr_mask);
tr_ctrl = REG_RD(ser, regi_ser, rw_tr_ctrl);
tr_ctrl.stop = 1;
REG_WR(ser, regi_ser, rw_tr_ctrl, tr_ctrl);
/*
* Always clear possible hardware xoff-detected state here, no need to
* unnecessary consider mctrl settings and when they change. We clear
* it here rather than in start_tx: both functions are called as the
* effect of XOFF processing, but start_tx is also called when upper
* levels tell the driver that there are more characters to send, so
* avoid adding code there.
*/
xoff_clr.clr = 1;
REG_WR(ser, regi_ser, rw_xoff_clr, xoff_clr);
/*
* Disable transmitter DMA, so that if we're in XON/XOFF, we can send
* those single characters without also giving go-ahead for queued up
* DMA data.
*/
tr_dma_en.en = 0;
REG_WR(ser, regi_ser, rw_tr_dma_en, tr_dma_en);
/*
* Make sure that write_ongoing is reset when stopping tx.
*/
up->write_ongoing = 0;
}
static void etraxfs_uart_stop_rx(struct uart_port *port)
{
struct uart_cris_port *up = (struct uart_cris_port *)port;
void __iomem *regi_ser = up->regi_ser;
reg_ser_rw_rec_ctrl rec_ctrl = REG_RD(ser, regi_ser, rw_rec_ctrl);
rec_ctrl.en = regk_ser_no;
REG_WR(ser, regi_ser, rw_rec_ctrl, rec_ctrl);
}
static void etraxfs_uart_enable_ms(struct uart_port *port)
{
}
static void check_modem_status(struct uart_cris_port *up)
{
}
static unsigned int etraxfs_uart_tx_empty(struct uart_port *port)
{
struct uart_cris_port *up = (struct uart_cris_port *)port;
unsigned long flags;
unsigned int ret;
reg_ser_r_stat_din rstat = {0};
spin_lock_irqsave(&up->port.lock, flags);
rstat = REG_RD(ser, up->regi_ser, r_stat_din);
ret = rstat.tr_empty ? TIOCSER_TEMT : 0;
spin_unlock_irqrestore(&up->port.lock, flags);
return ret;
}
static unsigned int etraxfs_uart_get_mctrl(struct uart_port *port)
{
struct uart_cris_port *up = (struct uart_cris_port *)port;
unsigned int ret;
ret = 0;
if (crisv32_serial_get_rts(up))
ret |= TIOCM_RTS;
/* DTR is active low */
if (up->dtr_pin && !gpiod_get_raw_value(up->dtr_pin))
ret |= TIOCM_DTR;
/* CD is active low */
if (up->cd_pin && !gpiod_get_raw_value(up->cd_pin))
ret |= TIOCM_CD;
/* RI is active low */
if (up->ri_pin && !gpiod_get_raw_value(up->ri_pin))
ret |= TIOCM_RI;
/* DSR is active low */
if (up->dsr_pin && !gpiod_get_raw_value(up->dsr_pin))
ret |= TIOCM_DSR;
if (crisv32_serial_get_cts(up))
ret |= TIOCM_CTS;
return ret;
}
static void etraxfs_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct uart_cris_port *up = (struct uart_cris_port *)port;
crisv32_serial_set_rts(up, mctrl & TIOCM_RTS ? 1 : 0, 0);
/* DTR is active low */
if (up->dtr_pin)
gpiod_set_raw_value(up->dtr_pin, mctrl & TIOCM_DTR ? 0 : 1);
/* RI is active low */
if (up->ri_pin)
gpiod_set_raw_value(up->ri_pin, mctrl & TIOCM_RNG ? 0 : 1);
/* CD is active low */
if (up->cd_pin)
gpiod_set_raw_value(up->cd_pin, mctrl & TIOCM_CD ? 0 : 1);
}
static void etraxfs_uart_break_ctl(struct uart_port *port, int break_state)
{
struct uart_cris_port *up = (struct uart_cris_port *)port;
unsigned long flags;
reg_ser_rw_tr_ctrl tr_ctrl;
reg_ser_rw_tr_dma_en tr_dma_en;
reg_ser_rw_intr_mask intr_mask;
spin_lock_irqsave(&up->port.lock, flags);
tr_ctrl = REG_RD(ser, up->regi_ser, rw_tr_ctrl);
tr_dma_en = REG_RD(ser, up->regi_ser, rw_tr_dma_en);
intr_mask = REG_RD(ser, up->regi_ser, rw_intr_mask);
if (break_state != 0) { /* Send break */
/*
* We need to disable DMA (if used) or tr_rdy interrupts if no
* DMA. No need to make this conditional on use of DMA;
* disabling will be a no-op for the other mode.
*/
intr_mask.tr_rdy = regk_ser_no;
tr_dma_en.en = 0;
/*
* Stop transmission and set the txd pin to 0 after the
* current character. The txd setting will take effect after
* any current transmission has completed.
*/
tr_ctrl.stop = 1;
tr_ctrl.txd = 0;
} else {
/* Re-enable the serial interrupt. */
intr_mask.tr_rdy = regk_ser_yes;
tr_ctrl.stop = 0;
tr_ctrl.txd = 1;
}
REG_WR(ser, up->regi_ser, rw_tr_ctrl, tr_ctrl);
REG_WR(ser, up->regi_ser, rw_tr_dma_en, tr_dma_en);
REG_WR(ser, up->regi_ser, rw_intr_mask, intr_mask);
spin_unlock_irqrestore(&up->port.lock, flags);
}
static void
transmit_chars_no_dma(struct uart_cris_port *up)
{
int max_count;
struct circ_buf *xmit = &up->port.state->xmit;
void __iomem *regi_ser = up->regi_ser;
reg_ser_r_stat_din rstat;
reg_ser_rw_ack_intr ack_intr = { .tr_rdy = regk_ser_yes };
if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
/* No more to send, so disable the interrupt. */
reg_ser_rw_intr_mask intr_mask;
intr_mask = REG_RD(ser, regi_ser, rw_intr_mask);
intr_mask.tr_rdy = 0;
intr_mask.tr_empty = 0;
REG_WR(ser, regi_ser, rw_intr_mask, intr_mask);
up->write_ongoing = 0;
return;
}
/* If the serport is fast, we send up to max_count bytes before
exiting the loop. */
max_count = 64;
do {
reg_ser_rw_dout dout = { .data = xmit->buf[xmit->tail] };
REG_WR(ser, regi_ser, rw_dout, dout);
REG_WR(ser, regi_ser, rw_ack_intr, ack_intr);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
up->port.icount.tx++;
if (xmit->head == xmit->tail)
break;
rstat = REG_RD(ser, regi_ser, r_stat_din);
} while ((--max_count > 0) && rstat.tr_rdy);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&up->port);
}
static void receive_chars_no_dma(struct uart_cris_port *up)
{
reg_ser_rs_stat_din stat_din;
reg_ser_r_stat_din rstat;
struct tty_port *port;
struct uart_icount *icount;
int max_count = 16;
char flag;
reg_ser_rw_ack_intr ack_intr = { 0 };
rstat = REG_RD(ser, up->regi_ser, r_stat_din);
icount = &up->port.icount;
port = &up->port.state->port;
do {
stat_din = REG_RD(ser, up->regi_ser, rs_stat_din);
flag = TTY_NORMAL;
ack_intr.dav = 1;
REG_WR(ser, up->regi_ser, rw_ack_intr, ack_intr);
icount->rx++;
if (stat_din.framing_err | stat_din.par_err | stat_din.orun) {
if (stat_din.data == 0x00 &&
stat_din.framing_err) {
/* Most likely a break. */
flag = TTY_BREAK;
icount->brk++;
} else if (stat_din.par_err) {
flag = TTY_PARITY;
icount->parity++;
} else if (stat_din.orun) {
flag = TTY_OVERRUN;
icount->overrun++;
} else if (stat_din.framing_err) {
flag = TTY_FRAME;
icount->frame++;
}
}
/*
* If this becomes important, we probably *could* handle this
* gracefully by keeping track of the unhandled character.
*/
if (!tty_insert_flip_char(port, stat_din.data, flag))
panic("%s: No tty buffer space", __func__);
rstat = REG_RD(ser, up->regi_ser, r_stat_din);
} while (rstat.dav && (max_count-- > 0));
spin_unlock(&up->port.lock);
tty_flip_buffer_push(port);
spin_lock(&up->port.lock);
}
static irqreturn_t
ser_interrupt(int irq, void *dev_id)
{
struct uart_cris_port *up = (struct uart_cris_port *)dev_id;
void __iomem *regi_ser;
int handled = 0;
spin_lock(&up->port.lock);
regi_ser = up->regi_ser;
if (regi_ser) {
reg_ser_r_masked_intr masked_intr;
masked_intr = REG_RD(ser, regi_ser, r_masked_intr);
/*
* Check what interrupts are active before taking
* actions. If DMA is used the interrupt shouldn't
* be enabled.
*/
if (masked_intr.dav) {
receive_chars_no_dma(up);
handled = 1;
}
check_modem_status(up);
if (masked_intr.tr_rdy) {
transmit_chars_no_dma(up);
handled = 1;
}
}
spin_unlock(&up->port.lock);
return IRQ_RETVAL(handled);
}
#ifdef CONFIG_CONSOLE_POLL
static int etraxfs_uart_get_poll_char(struct uart_port *port)
{
reg_ser_rs_stat_din stat;
reg_ser_rw_ack_intr ack_intr = { 0 };
struct uart_cris_port *up = (struct uart_cris_port *)port;
do {
stat = REG_RD(ser, up->regi_ser, rs_stat_din);
} while (!stat.dav);
/* Ack the data_avail interrupt. */
ack_intr.dav = 1;
REG_WR(ser, up->regi_ser, rw_ack_intr, ack_intr);
return stat.data;
}
static void etraxfs_uart_put_poll_char(struct uart_port *port,
unsigned char c)
{
reg_ser_r_stat_din stat;
struct uart_cris_port *up = (struct uart_cris_port *)port;
do {
stat = REG_RD(ser, up->regi_ser, r_stat_din);
} while (!stat.tr_rdy);
REG_WR_INT(ser, up->regi_ser, rw_dout, c);
}
#endif /* CONFIG_CONSOLE_POLL */
static int etraxfs_uart_startup(struct uart_port *port)
{
struct uart_cris_port *up = (struct uart_cris_port *)port;
unsigned long flags;
reg_ser_rw_intr_mask ser_intr_mask = {0};
ser_intr_mask.dav = regk_ser_yes;
if (request_irq(etraxfs_uart_ports[port->line]->irq, ser_interrupt,
0, DRV_NAME, etraxfs_uart_ports[port->line]))
panic("irq ser%d", port->line);
spin_lock_irqsave(&up->port.lock, flags);
REG_WR(ser, up->regi_ser, rw_intr_mask, ser_intr_mask);
etraxfs_uart_set_mctrl(&up->port, up->port.mctrl);
spin_unlock_irqrestore(&up->port.lock, flags);
return 0;
}
static void etraxfs_uart_shutdown(struct uart_port *port)
{
struct uart_cris_port *up = (struct uart_cris_port *)port;
unsigned long flags;
spin_lock_irqsave(&up->port.lock, flags);
etraxfs_uart_stop_tx(port);
etraxfs_uart_stop_rx(port);
free_irq(etraxfs_uart_ports[port->line]->irq,
etraxfs_uart_ports[port->line]);
etraxfs_uart_set_mctrl(&up->port, up->port.mctrl);
spin_unlock_irqrestore(&up->port.lock, flags);
}
static void
etraxfs_uart_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
struct uart_cris_port *up = (struct uart_cris_port *)port;
unsigned long flags;
reg_ser_rw_xoff xoff;
reg_ser_rw_xoff_clr xoff_clr = {0};
reg_ser_rw_tr_ctrl tx_ctrl = {0};
reg_ser_rw_tr_dma_en tx_dma_en = {0};
reg_ser_rw_rec_ctrl rx_ctrl = {0};
reg_ser_rw_tr_baud_div tx_baud_div = {0};
reg_ser_rw_rec_baud_div rx_baud_div = {0};
int baud;
if (old &&
termios->c_cflag == old->c_cflag &&
termios->c_iflag == old->c_iflag)
return;
/* Tx: 8 bit, no/even parity, 1 stop bit, no cts. */
tx_ctrl.base_freq = regk_ser_f29_493;
tx_ctrl.en = 0;
tx_ctrl.stop = 0;
tx_ctrl.auto_rts = regk_ser_no;
tx_ctrl.txd = 1;
tx_ctrl.auto_cts = 0;
/* Rx: 8 bit, no/even parity. */
rx_ctrl.dma_err = regk_ser_stop;
rx_ctrl.sampling = regk_ser_majority;
rx_ctrl.timeout = 1;
rx_ctrl.rts_n = regk_ser_inactive;
/* Common for tx and rx: 8N1. */
tx_ctrl.data_bits = regk_ser_bits8;
rx_ctrl.data_bits = regk_ser_bits8;
tx_ctrl.par = regk_ser_even;
rx_ctrl.par = regk_ser_even;
tx_ctrl.par_en = regk_ser_no;
rx_ctrl.par_en = regk_ser_no;
tx_ctrl.stop_bits = regk_ser_bits1;
/*
* Change baud-rate and write it to the hardware.
*
* baud_clock = base_freq / (divisor*8)
* divisor = base_freq / (baud_clock * 8)
* base_freq is either:
* off, ext, 29.493MHz, 32.000 MHz, 32.768 MHz or 100 MHz
* 20.493MHz is used for standard baudrates
*/
/*
* For the console port we keep the original baudrate here. Not very
* beautiful.
*/
if ((port != console_port) || old)
baud = uart_get_baud_rate(port, termios, old, 0,
port->uartclk / 8);
else
baud = console_baud;
tx_baud_div.div = 29493000 / (8 * baud);
/* Rx uses same as tx. */
rx_baud_div.div = tx_baud_div.div;
rx_ctrl.base_freq = tx_ctrl.base_freq;
if ((termios->c_cflag & CSIZE) == CS7) {
/* Set 7 bit mode. */
tx_ctrl.data_bits = regk_ser_bits7;
rx_ctrl.data_bits = regk_ser_bits7;
}
if (termios->c_cflag & CSTOPB) {
/* Set 2 stop bit mode. */
tx_ctrl.stop_bits = regk_ser_bits2;
}
if (termios->c_cflag & PARENB) {
/* Enable parity. */
tx_ctrl.par_en = regk_ser_yes;
rx_ctrl.par_en = regk_ser_yes;
}
if (termios->c_cflag & CMSPAR) {
if (termios->c_cflag & PARODD) {
/* Set mark parity if PARODD and CMSPAR. */
tx_ctrl.par = regk_ser_mark;
rx_ctrl.par = regk_ser_mark;
} else {
tx_ctrl.par = regk_ser_space;
rx_ctrl.par = regk_ser_space;
}
} else {
if (termios->c_cflag & PARODD) {
/* Set odd parity. */
tx_ctrl.par = regk_ser_odd;
rx_ctrl.par = regk_ser_odd;
}
}
if (termios->c_cflag & CRTSCTS) {
/* Enable automatic CTS handling. */
tx_ctrl.auto_cts = regk_ser_yes;
}
/* Make sure the tx and rx are enabled. */
tx_ctrl.en = regk_ser_yes;
rx_ctrl.en = regk_ser_yes;
spin_lock_irqsave(&port->lock, flags);
tx_dma_en.en = 0;
REG_WR(ser, up->regi_ser, rw_tr_dma_en, tx_dma_en);
/* Actually write the control regs (if modified) to the hardware. */
uart_update_timeout(port, termios->c_cflag, port->uartclk/8);
MODIFY_REG(up->regi_ser, rw_rec_baud_div, rx_baud_div);
MODIFY_REG(up->regi_ser, rw_rec_ctrl, rx_ctrl);
MODIFY_REG(up->regi_ser, rw_tr_baud_div, tx_baud_div);
MODIFY_REG(up->regi_ser, rw_tr_ctrl, tx_ctrl);
tx_dma_en.en = 0;
REG_WR(ser, up->regi_ser, rw_tr_dma_en, tx_dma_en);
xoff = REG_RD(ser, up->regi_ser, rw_xoff);
if (up->port.state && up->port.state->port.tty &&
(up->port.state->port.tty->termios.c_iflag & IXON)) {
xoff.chr = STOP_CHAR(up->port.state->port.tty);
xoff.automatic = regk_ser_yes;
} else
xoff.automatic = regk_ser_no;
MODIFY_REG(up->regi_ser, rw_xoff, xoff);
/*
* Make sure we don't start in an automatically shut-off state due to
* a previous early exit.
*/
xoff_clr.clr = 1;
REG_WR(ser, up->regi_ser, rw_xoff_clr, xoff_clr);
etraxfs_uart_set_mctrl(&up->port, up->port.mctrl);
spin_unlock_irqrestore(&up->port.lock, flags);
}
static const char *
etraxfs_uart_type(struct uart_port *port)
{
return "CRISv32";
}
static void etraxfs_uart_release_port(struct uart_port *port)
{
}
static int etraxfs_uart_request_port(struct uart_port *port)
{
return 0;
}
static void etraxfs_uart_config_port(struct uart_port *port, int flags)
{
struct uart_cris_port *up = (struct uart_cris_port *)port;
up->port.type = PORT_CRIS;
}
static const struct uart_ops etraxfs_uart_pops = {
.tx_empty = etraxfs_uart_tx_empty,
.set_mctrl = etraxfs_uart_set_mctrl,
.get_mctrl = etraxfs_uart_get_mctrl,
.stop_tx = etraxfs_uart_stop_tx,
.start_tx = etraxfs_uart_start_tx,
.send_xchar = etraxfs_uart_send_xchar,
.stop_rx = etraxfs_uart_stop_rx,
.enable_ms = etraxfs_uart_enable_ms,
.break_ctl = etraxfs_uart_break_ctl,
.startup = etraxfs_uart_startup,
.shutdown = etraxfs_uart_shutdown,
.set_termios = etraxfs_uart_set_termios,
.type = etraxfs_uart_type,
.release_port = etraxfs_uart_release_port,
.request_port = etraxfs_uart_request_port,
.config_port = etraxfs_uart_config_port,
#ifdef CONFIG_CONSOLE_POLL
.poll_get_char = etraxfs_uart_get_poll_char,
.poll_put_char = etraxfs_uart_put_poll_char,
#endif
};
static void cris_serial_port_init(struct uart_port *port, int line)
{
struct uart_cris_port *up = (struct uart_cris_port *)port;
if (up->initialized)
return;
up->initialized = 1;
port->line = line;
spin_lock_init(&port->lock);
port->ops = &etraxfs_uart_pops;
port->irq = up->irq;
port->iobase = (unsigned long) up->regi_ser;
port->uartclk = 29493000;
/*
* We can't fit any more than 255 here (unsigned char), though
* actually UART_XMIT_SIZE characters could be pending output.
* At time of this writing, the definition of "fifosize" is here the
* amount of characters that can be pending output after a start_tx call
* until tx_empty returns 1: see serial_core.c:uart_wait_until_sent.
* This matters for timeout calculations unfortunately, but keeping
* larger amounts at the DMA wouldn't win much so let's just play nice.
*/
port->fifosize = 255;
port->flags = UPF_BOOT_AUTOCONF;
}
static int etraxfs_uart_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct uart_cris_port *up;
int dev_id;
if (!np)
return -ENODEV;
dev_id = of_alias_get_id(np, "serial");
if (dev_id < 0)
dev_id = 0;
if (dev_id >= UART_NR)
return -EINVAL;
if (etraxfs_uart_ports[dev_id])
return -EBUSY;
up = devm_kzalloc(&pdev->dev, sizeof(struct uart_cris_port),
GFP_KERNEL);
if (!up)
return -ENOMEM;
up->irq = irq_of_parse_and_map(np, 0);
up->regi_ser = of_iomap(np, 0);
up->dtr_pin = devm_gpiod_get_optional(&pdev->dev, "dtr");
up->dsr_pin = devm_gpiod_get_optional(&pdev->dev, "dsr");
up->ri_pin = devm_gpiod_get_optional(&pdev->dev, "ri");
up->cd_pin = devm_gpiod_get_optional(&pdev->dev, "cd");
up->port.dev = &pdev->dev;
cris_serial_port_init(&up->port, dev_id);
etraxfs_uart_ports[dev_id] = up;
platform_set_drvdata(pdev, &up->port);
uart_add_one_port(&etraxfs_uart_driver, &up->port);
return 0;
}
static int etraxfs_uart_remove(struct platform_device *pdev)
{
struct uart_port *port;
port = platform_get_drvdata(pdev);
uart_remove_one_port(&etraxfs_uart_driver, port);
etraxfs_uart_ports[pdev->id] = NULL;
return 0;
}
static const struct of_device_id etraxfs_uart_dt_ids[] = {
{ .compatible = "axis,etraxfs-uart" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, etraxfs_uart_dt_ids);
static struct platform_driver etraxfs_uart_platform_driver = {
.driver = {
.name = DRV_NAME,
.of_match_table = of_match_ptr(etraxfs_uart_dt_ids),
},
.probe = etraxfs_uart_probe,
.remove = etraxfs_uart_remove,
};
static int __init etraxfs_uart_init(void)
{
int ret;
ret = uart_register_driver(&etraxfs_uart_driver);
if (ret)
return ret;
ret = platform_driver_register(&etraxfs_uart_platform_driver);
if (ret)
uart_unregister_driver(&etraxfs_uart_driver);
return ret;
}
static void __exit etraxfs_uart_exit(void)
{
platform_driver_unregister(&etraxfs_uart_platform_driver);
uart_unregister_driver(&etraxfs_uart_driver);
}
module_init(etraxfs_uart_init);
module_exit(etraxfs_uart_exit);

View File

@ -237,7 +237,8 @@ struct lpuart_port {
unsigned int rxfifo_size;
bool lpuart32;
bool lpuart_dma_use;
bool lpuart_dma_tx_use;
bool lpuart_dma_rx_use;
struct dma_chan *dma_tx_chan;
struct dma_chan *dma_rx_chan;
struct dma_async_tx_descriptor *dma_tx_desc;
@ -454,6 +455,15 @@ static int lpuart_dma_rx(struct lpuart_port *sport)
return 0;
}
static void lpuart_flush_buffer(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
if (sport->lpuart_dma_tx_use) {
dmaengine_terminate_all(sport->dma_tx_chan);
sport->dma_tx_in_progress = 0;
}
}
static void lpuart_dma_rx_complete(void *arg)
{
struct lpuart_port *sport = arg;
@ -461,6 +471,7 @@ static void lpuart_dma_rx_complete(void *arg)
unsigned long flags;
async_tx_ack(sport->dma_rx_desc);
mod_timer(&sport->lpuart_timer, jiffies + sport->dma_rx_timeout);
spin_lock_irqsave(&sport->port.lock, flags);
@ -506,9 +517,6 @@ static inline void lpuart_prepare_rx(struct lpuart_port *sport)
spin_lock_irqsave(&sport->port.lock, flags);
init_timer(&sport->lpuart_timer);
sport->lpuart_timer.function = lpuart_timer_func;
sport->lpuart_timer.data = (unsigned long)sport;
sport->lpuart_timer.expires = jiffies + sport->dma_rx_timeout;
add_timer(&sport->lpuart_timer);
@ -571,7 +579,7 @@ static void lpuart_start_tx(struct uart_port *port)
temp = readb(port->membase + UARTCR2);
writeb(temp | UARTCR2_TIE, port->membase + UARTCR2);
if (sport->lpuart_dma_use) {
if (sport->lpuart_dma_tx_use) {
if (!uart_circ_empty(xmit) && !sport->dma_tx_in_progress)
lpuart_prepare_tx(sport);
} else {
@ -758,19 +766,19 @@ out:
static irqreturn_t lpuart_int(int irq, void *dev_id)
{
struct lpuart_port *sport = dev_id;
unsigned char sts;
unsigned char sts, crdma;
sts = readb(sport->port.membase + UARTSR1);
crdma = readb(sport->port.membase + UARTCR5);
if (sts & UARTSR1_RDRF) {
if (sport->lpuart_dma_use)
if (sts & UARTSR1_RDRF && !(crdma & UARTCR5_RDMAS)) {
if (sport->lpuart_dma_rx_use)
lpuart_prepare_rx(sport);
else
lpuart_rxint(irq, dev_id);
}
if (sts & UARTSR1_TDRE &&
!(readb(sport->port.membase + UARTCR5) & UARTCR5_TDMAS)) {
if (sport->lpuart_dma_use)
if (sts & UARTSR1_TDRE && !(crdma & UARTCR5_TDMAS)) {
if (sport->lpuart_dma_tx_use)
lpuart_pio_tx(sport);
else
lpuart_txint(irq, dev_id);
@ -953,26 +961,17 @@ static int lpuart_dma_tx_request(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port,
struct lpuart_port, port);
struct dma_chan *tx_chan;
struct dma_slave_config dma_tx_sconfig;
dma_addr_t dma_bus;
unsigned char *dma_buf;
int ret;
tx_chan = dma_request_slave_channel(sport->port.dev, "tx");
if (!tx_chan) {
dev_err(sport->port.dev, "Dma tx channel request failed!\n");
return -ENODEV;
}
dma_bus = dma_map_single(tx_chan->device->dev,
dma_bus = dma_map_single(sport->dma_tx_chan->device->dev,
sport->port.state->xmit.buf,
UART_XMIT_SIZE, DMA_TO_DEVICE);
if (dma_mapping_error(tx_chan->device->dev, dma_bus)) {
if (dma_mapping_error(sport->dma_tx_chan->device->dev, dma_bus)) {
dev_err(sport->port.dev, "dma_map_single tx failed\n");
dma_release_channel(tx_chan);
return -ENOMEM;
}
@ -981,16 +980,14 @@ static int lpuart_dma_tx_request(struct uart_port *port)
dma_tx_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
dma_tx_sconfig.dst_maxburst = sport->txfifo_size;
dma_tx_sconfig.direction = DMA_MEM_TO_DEV;
ret = dmaengine_slave_config(tx_chan, &dma_tx_sconfig);
ret = dmaengine_slave_config(sport->dma_tx_chan, &dma_tx_sconfig);
if (ret < 0) {
dev_err(sport->port.dev,
"Dma slave config failed, err = %d\n", ret);
dma_release_channel(tx_chan);
return ret;
}
sport->dma_tx_chan = tx_chan;
sport->dma_tx_buf_virt = dma_buf;
sport->dma_tx_buf_bus = dma_bus;
sport->dma_tx_in_progress = 0;
@ -1002,34 +999,24 @@ static int lpuart_dma_rx_request(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port,
struct lpuart_port, port);
struct dma_chan *rx_chan;
struct dma_slave_config dma_rx_sconfig;
dma_addr_t dma_bus;
unsigned char *dma_buf;
int ret;
rx_chan = dma_request_slave_channel(sport->port.dev, "rx");
if (!rx_chan) {
dev_err(sport->port.dev, "Dma rx channel request failed!\n");
return -ENODEV;
}
dma_buf = devm_kzalloc(sport->port.dev,
FSL_UART_RX_DMA_BUFFER_SIZE, GFP_KERNEL);
if (!dma_buf) {
dev_err(sport->port.dev, "Dma rx alloc failed\n");
dma_release_channel(rx_chan);
return -ENOMEM;
}
dma_bus = dma_map_single(rx_chan->device->dev, dma_buf,
dma_bus = dma_map_single(sport->dma_rx_chan->device->dev, dma_buf,
FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
if (dma_mapping_error(rx_chan->device->dev, dma_bus)) {
if (dma_mapping_error(sport->dma_rx_chan->device->dev, dma_bus)) {
dev_err(sport->port.dev, "dma_map_single rx failed\n");
dma_release_channel(rx_chan);
return -ENOMEM;
}
@ -1037,16 +1024,14 @@ static int lpuart_dma_rx_request(struct uart_port *port)
dma_rx_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
dma_rx_sconfig.src_maxburst = 1;
dma_rx_sconfig.direction = DMA_DEV_TO_MEM;
ret = dmaengine_slave_config(rx_chan, &dma_rx_sconfig);
ret = dmaengine_slave_config(sport->dma_rx_chan, &dma_rx_sconfig);
if (ret < 0) {
dev_err(sport->port.dev,
"Dma slave config failed, err = %d\n", ret);
dma_release_channel(rx_chan);
return ret;
}
sport->dma_rx_chan = rx_chan;
sport->dma_rx_buf_virt = dma_buf;
sport->dma_rx_buf_bus = dma_bus;
sport->dma_rx_in_progress = 0;
@ -1058,31 +1043,24 @@ static void lpuart_dma_tx_free(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port,
struct lpuart_port, port);
struct dma_chan *dma_chan;
dma_unmap_single(sport->port.dev, sport->dma_tx_buf_bus,
UART_XMIT_SIZE, DMA_TO_DEVICE);
dma_chan = sport->dma_tx_chan;
sport->dma_tx_chan = NULL;
sport->dma_tx_buf_bus = 0;
sport->dma_tx_buf_virt = NULL;
dma_release_channel(dma_chan);
}
static void lpuart_dma_rx_free(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port,
struct lpuart_port, port);
struct dma_chan *dma_chan;
dma_unmap_single(sport->port.dev, sport->dma_rx_buf_bus,
FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
dma_chan = sport->dma_rx_chan;
sport->dma_rx_chan = NULL;
sport->dma_rx_buf_bus = 0;
sport->dma_rx_buf_virt = NULL;
dma_release_channel(dma_chan);
}
static int lpuart_startup(struct uart_port *port)
@ -1101,14 +1079,21 @@ static int lpuart_startup(struct uart_port *port)
sport->rxfifo_size = 0x1 << (((temp >> UARTPFIFO_RXSIZE_OFF) &
UARTPFIFO_FIFOSIZE_MASK) + 1);
/* Whether use dma support by dma request results */
if (lpuart_dma_tx_request(port) || lpuart_dma_rx_request(port)) {
sport->lpuart_dma_use = false;
} else {
sport->lpuart_dma_use = true;
if (sport->dma_rx_chan && !lpuart_dma_rx_request(port)) {
sport->lpuart_dma_rx_use = true;
setup_timer(&sport->lpuart_timer, lpuart_timer_func,
(unsigned long)sport);
} else
sport->lpuart_dma_rx_use = false;
if (sport->dma_tx_chan && !lpuart_dma_tx_request(port)) {
sport->lpuart_dma_tx_use = true;
temp = readb(port->membase + UARTCR5);
temp &= ~UARTCR5_RDMAS;
writeb(temp | UARTCR5_TDMAS, port->membase + UARTCR5);
}
} else
sport->lpuart_dma_tx_use = false;
ret = devm_request_irq(port->dev, port->irq, lpuart_int, 0,
DRIVER_NAME, sport);
@ -1179,10 +1164,13 @@ static void lpuart_shutdown(struct uart_port *port)
devm_free_irq(port->dev, port->irq, sport);
if (sport->lpuart_dma_use) {
lpuart_dma_tx_free(port);
lpuart_dma_rx_free(port);
if (sport->lpuart_dma_rx_use) {
lpuart_dma_rx_free(&sport->port);
del_timer_sync(&sport->lpuart_timer);
}
if (sport->lpuart_dma_tx_use)
lpuart_dma_tx_free(&sport->port);
}
static void lpuart32_shutdown(struct uart_port *port)
@ -1304,7 +1292,7 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
/* update the per-port timeout */
uart_update_timeout(port, termios->c_cflag, baud);
if (sport->lpuart_dma_use) {
if (sport->lpuart_dma_rx_use) {
/* Calculate delay for 1.5 DMA buffers */
sport->dma_rx_timeout = (sport->port.timeout - HZ / 50) *
FSL_UART_RX_DMA_BUFFER_SIZE * 3 /
@ -1517,6 +1505,7 @@ static struct uart_ops lpuart_pops = {
.release_port = lpuart_release_port,
.config_port = lpuart_config_port,
.verify_port = lpuart_verify_port,
.flush_buffer = lpuart_flush_buffer,
};
static struct uart_ops lpuart32_pops = {
@ -1535,6 +1524,7 @@ static struct uart_ops lpuart32_pops = {
.release_port = lpuart_release_port,
.config_port = lpuart_config_port,
.verify_port = lpuart_verify_port,
.flush_buffer = lpuart_flush_buffer,
};
static struct lpuart_port *lpuart_ports[UART_NR];
@ -1833,6 +1823,16 @@ static int lpuart_probe(struct platform_device *pdev)
return ret;
}
sport->dma_tx_chan = dma_request_slave_channel(sport->port.dev, "tx");
if (!sport->dma_tx_chan)
dev_info(sport->port.dev, "DMA tx channel request failed, "
"operating without tx DMA\n");
sport->dma_rx_chan = dma_request_slave_channel(sport->port.dev, "rx");
if (!sport->dma_rx_chan)
dev_info(sport->port.dev, "DMA rx channel request failed, "
"operating without rx DMA\n");
return 0;
}
@ -1844,6 +1844,12 @@ static int lpuart_remove(struct platform_device *pdev)
clk_disable_unprepare(sport->clk);
if (sport->dma_tx_chan)
dma_release_channel(sport->dma_tx_chan);
if (sport->dma_rx_chan)
dma_release_channel(sport->dma_rx_chan);
return 0;
}
@ -1851,6 +1857,19 @@ static int lpuart_remove(struct platform_device *pdev)
static int lpuart_suspend(struct device *dev)
{
struct lpuart_port *sport = dev_get_drvdata(dev);
unsigned long temp;
if (sport->lpuart32) {
/* disable Rx/Tx and interrupts */
temp = lpuart32_read(sport->port.membase + UARTCTRL);
temp &= ~(UARTCTRL_TE | UARTCTRL_TIE | UARTCTRL_TCIE);
lpuart32_write(temp, sport->port.membase + UARTCTRL);
} else {
/* disable Rx/Tx and interrupts */
temp = readb(sport->port.membase + UARTCR2);
temp &= ~(UARTCR2_TE | UARTCR2_TIE | UARTCR2_TCIE);
writeb(temp, sport->port.membase + UARTCR2);
}
uart_suspend_port(&lpuart_reg, &sport->port);

View File

@ -74,6 +74,7 @@
#define IMX21_UTS 0xb4 /* UART Test Register on all other i.mx*/
/* UART Control Register Bit Fields.*/
#define URXD_DUMMY_READ (1<<16)
#define URXD_CHARRDY (1<<15)
#define URXD_ERR (1<<14)
#define URXD_OVRRUN (1<<13)
@ -463,13 +464,17 @@ static void imx_enable_ms(struct uart_port *port)
mod_timer(&sport->timer, jiffies);
}
static void imx_dma_tx(struct imx_port *sport);
static inline void imx_transmit_buffer(struct imx_port *sport)
{
struct circ_buf *xmit = &sport->port.state->xmit;
unsigned long temp;
if (sport->port.x_char) {
/* Send next char */
writel(sport->port.x_char, sport->port.membase + URTX0);
sport->port.icount.tx++;
sport->port.x_char = 0;
return;
}
@ -478,6 +483,22 @@ static inline void imx_transmit_buffer(struct imx_port *sport)
return;
}
if (sport->dma_is_enabled) {
/*
* We've just sent a X-char Ensure the TX DMA is enabled
* and the TX IRQ is disabled.
**/
temp = readl(sport->port.membase + UCR1);
temp &= ~UCR1_TXMPTYEN;
if (sport->dma_is_txing) {
temp |= UCR1_TDMAEN;
writel(temp, sport->port.membase + UCR1);
} else {
writel(temp, sport->port.membase + UCR1);
imx_dma_tx(sport);
}
}
while (!uart_circ_empty(xmit) &&
!(readl(sport->port.membase + uts_reg(sport)) & UTS_TXFULL)) {
/* send xmit->buf[xmit->tail]
@ -500,26 +521,39 @@ static void dma_tx_callback(void *data)
struct scatterlist *sgl = &sport->tx_sgl[0];
struct circ_buf *xmit = &sport->port.state->xmit;
unsigned long flags;
unsigned long temp;
spin_lock_irqsave(&sport->port.lock, flags);
dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
sport->dma_is_txing = 0;
temp = readl(sport->port.membase + UCR1);
temp &= ~UCR1_TDMAEN;
writel(temp, sport->port.membase + UCR1);
/* update the stat */
spin_lock_irqsave(&sport->port.lock, flags);
xmit->tail = (xmit->tail + sport->tx_bytes) & (UART_XMIT_SIZE - 1);
sport->port.icount.tx += sport->tx_bytes;
spin_unlock_irqrestore(&sport->port.lock, flags);
dev_dbg(sport->port.dev, "we finish the TX DMA.\n");
uart_write_wakeup(&sport->port);
sport->dma_is_txing = 0;
spin_unlock_irqrestore(&sport->port.lock, flags);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&sport->port);
if (waitqueue_active(&sport->dma_wait)) {
wake_up(&sport->dma_wait);
dev_dbg(sport->port.dev, "exit in %s.\n", __func__);
return;
}
spin_lock_irqsave(&sport->port.lock, flags);
if (!uart_circ_empty(xmit) && !uart_tx_stopped(&sport->port))
imx_dma_tx(sport);
spin_unlock_irqrestore(&sport->port.lock, flags);
}
static void imx_dma_tx(struct imx_port *sport)
@ -529,24 +563,23 @@ static void imx_dma_tx(struct imx_port *sport)
struct dma_async_tx_descriptor *desc;
struct dma_chan *chan = sport->dma_chan_tx;
struct device *dev = sport->port.dev;
enum dma_status status;
unsigned long temp;
int ret;
status = dmaengine_tx_status(chan, (dma_cookie_t)0, NULL);
if (DMA_IN_PROGRESS == status)
if (sport->dma_is_txing)
return;
sport->tx_bytes = uart_circ_chars_pending(xmit);
if (xmit->tail > xmit->head && xmit->head > 0) {
if (xmit->tail < xmit->head) {
sport->dma_tx_nents = 1;
sg_init_one(sgl, xmit->buf + xmit->tail, sport->tx_bytes);
} else {
sport->dma_tx_nents = 2;
sg_init_table(sgl, 2);
sg_set_buf(sgl, xmit->buf + xmit->tail,
UART_XMIT_SIZE - xmit->tail);
sg_set_buf(sgl + 1, xmit->buf, xmit->head);
} else {
sport->dma_tx_nents = 1;
sg_init_one(sgl, xmit->buf + xmit->tail, sport->tx_bytes);
}
ret = dma_map_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
@ -557,6 +590,8 @@ static void imx_dma_tx(struct imx_port *sport)
desc = dmaengine_prep_slave_sg(chan, sgl, sport->dma_tx_nents,
DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
if (!desc) {
dma_unmap_sg(dev, sgl, sport->dma_tx_nents,
DMA_TO_DEVICE);
dev_err(dev, "We cannot prepare for the TX slave dma!\n");
return;
}
@ -565,6 +600,11 @@ static void imx_dma_tx(struct imx_port *sport)
dev_dbg(dev, "TX: prepare to send %lu bytes by DMA.\n",
uart_circ_chars_pending(xmit));
temp = readl(sport->port.membase + UCR1);
temp |= UCR1_TDMAEN;
writel(temp, sport->port.membase + UCR1);
/* fire it */
sport->dma_is_txing = 1;
dmaengine_submit(desc);
@ -590,13 +630,6 @@ static void imx_start_tx(struct uart_port *port)
temp &= ~(UCR1_RRDYEN);
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);
if (!sport->dma_is_enabled) {
temp = readl(sport->port.membase + UCR1);
@ -614,15 +647,21 @@ static void imx_start_tx(struct uart_port *port)
}
if (sport->dma_is_enabled) {
/* FIXME: port->x_char must be transmitted if != 0 */
if (sport->port.x_char) {
/* We have X-char to send, so enable TX IRQ and
* disable TX DMA to let TX interrupt to send X-char */
temp = readl(sport->port.membase + UCR1);
temp &= ~UCR1_TDMAEN;
temp |= UCR1_TXMPTYEN;
writel(temp, sport->port.membase + UCR1);
return;
}
if (!uart_circ_empty(&port->state->xmit) &&
!uart_tx_stopped(port))
imx_dma_tx(sport);
return;
}
if (readl(sport->port.membase + uts_reg(sport)) & UTS_TXEMPTY)
imx_transmit_buffer(sport);
}
static irqreturn_t imx_rtsint(int irq, void *dev_id)
@ -694,7 +733,7 @@ static irqreturn_t imx_rxint(int irq, void *dev_id)
continue;
}
rx &= sport->port.read_status_mask;
rx &= (sport->port.read_status_mask | 0xFF);
if (rx & URXD_BRK)
flg = TTY_BREAK;
@ -710,6 +749,9 @@ static irqreturn_t imx_rxint(int irq, void *dev_id)
#endif
}
if (sport->port.ignore_status_mask & URXD_DUMMY_READ)
goto out;
tty_insert_flip_char(port, rx, flg);
}
@ -727,6 +769,9 @@ static int start_rx_dma(struct imx_port *sport);
static void imx_dma_rxint(struct imx_port *sport)
{
unsigned long temp;
unsigned long flags;
spin_lock_irqsave(&sport->port.lock, flags);
temp = readl(sport->port.membase + USR2);
if ((temp & USR2_RDR) && !sport->dma_is_rxing) {
@ -740,6 +785,8 @@ static void imx_dma_rxint(struct imx_port *sport)
/* tell the DMA to receive the data. */
start_rx_dma(sport);
}
spin_unlock_irqrestore(&sport->port.lock, flags);
}
static irqreturn_t imx_int(int irq, void *dev_id)
@ -869,6 +916,9 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
static void imx_rx_dma_done(struct imx_port *sport)
{
unsigned long temp;
unsigned long flags;
spin_lock_irqsave(&sport->port.lock, flags);
/* Enable this interrupt when the RXFIFO is empty. */
temp = readl(sport->port.membase + UCR1);
@ -880,6 +930,8 @@ static void imx_rx_dma_done(struct imx_port *sport)
/* Is the shutdown waiting for us? */
if (waitqueue_active(&sport->dma_wait))
wake_up(&sport->dma_wait);
spin_unlock_irqrestore(&sport->port.lock, flags);
}
/*
@ -910,12 +962,26 @@ static void dma_rx_callback(void *data)
dev_dbg(sport->port.dev, "We get %d bytes.\n", count);
if (count) {
tty_insert_flip_string(port, sport->rx_buf, count);
if (!(sport->port.ignore_status_mask & URXD_DUMMY_READ))
tty_insert_flip_string(port, sport->rx_buf, count);
tty_flip_buffer_push(port);
start_rx_dma(sport);
} else
} else if (readl(sport->port.membase + USR2) & USR2_RDR) {
/*
* start rx_dma directly once data in RXFIFO, more efficient
* than before:
* 1. call imx_rx_dma_done to stop dma if no data received
* 2. wait next RDR interrupt to start dma transfer.
*/
start_rx_dma(sport);
} else {
/*
* stop dma to prevent too many IDLE event trigged if no data
* in RXFIFO
*/
imx_rx_dma_done(sport);
}
}
static int start_rx_dma(struct imx_port *sport)
@ -935,6 +1001,7 @@ static int start_rx_dma(struct imx_port *sport)
desc = dmaengine_prep_slave_sg(chan, sgl, 1, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT);
if (!desc) {
dma_unmap_sg(dev, sgl, 1, DMA_FROM_DEVICE);
dev_err(dev, "We cannot prepare for the RX slave dma!\n");
return -EINVAL;
}
@ -1108,12 +1175,20 @@ static int imx_startup(struct uart_port *port)
while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0))
udelay(1);
/* Can we enable the DMA support? */
if (is_imx6q_uart(sport) && !uart_console(port) &&
!sport->dma_is_inited)
imx_uart_dma_init(sport);
spin_lock_irqsave(&sport->port.lock, flags);
/*
* Finally, clear and enable interrupts
*/
writel(USR1_RTSD, sport->port.membase + USR1);
if (sport->dma_is_inited && !sport->dma_is_enabled)
imx_enable_dma(sport);
temp = readl(sport->port.membase + UCR1);
temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN;
@ -1124,6 +1199,14 @@ static int imx_startup(struct uart_port *port)
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);
temp = readl(sport->port.membase + UCR2);
temp |= (UCR2_RXEN | UCR2_TXEN);
if (!sport->have_rtscts)
@ -1189,9 +1272,11 @@ static void imx_shutdown(struct uart_port *port)
dmaengine_terminate_all(sport->dma_chan_tx);
dmaengine_terminate_all(sport->dma_chan_rx);
}
spin_lock_irqsave(&sport->port.lock, flags);
imx_stop_tx(port);
imx_stop_rx(port);
imx_disable_dma(sport);
spin_unlock_irqrestore(&sport->port.lock, flags);
imx_uart_dma_exit(sport);
}
@ -1233,11 +1318,48 @@ static void imx_shutdown(struct uart_port *port)
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;
if (sport->dma_is_enabled) {
sport->tx_bytes = 0;
dmaengine_terminate_all(sport->dma_chan_tx);
if (!sport->dma_chan_tx)
return;
sport->tx_bytes = 0;
dmaengine_terminate_all(sport->dma_chan_tx);
if (sport->dma_is_txing) {
dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents,
DMA_TO_DEVICE);
temp = readl(sport->port.membase + UCR1);
temp &= ~UCR1_TDMAEN;
writel(temp, sport->port.membase + UCR1);
sport->dma_is_txing = false;
}
/*
* According to the Reference Manual description of the UART SRST bit:
* "Reset the transmit and receive state machines,
* all FIFOs and register USR1, USR2, UBIR, UBMR, UBRC, URXD, UTXD
* and UTS[6-3]". As we don't need to restore the old values from
* USR1, USR2, URXD, UTXD, only save/restore the other four registers
*/
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);
temp &= ~UCR2_SRST;
writel(temp, sport->port.membase + UCR2);
while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0))
udelay(1);
/* 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);
}
static void
@ -1280,11 +1402,6 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
if (sport->have_rtscts) {
ucr2 &= ~UCR2_IRTS;
ucr2 |= UCR2_CTSC;
/* Can we enable the DMA support? */
if (is_imx6q_uart(sport) && !uart_console(port)
&& !sport->dma_is_inited)
imx_uart_dma_init(sport);
} else {
termios->c_cflag &= ~CRTSCTS;
}
@ -1319,7 +1436,7 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
*/
sport->port.ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
sport->port.ignore_status_mask |= URXD_PRERR;
sport->port.ignore_status_mask |= URXD_PRERR | URXD_FRMERR;
if (termios->c_iflag & IGNBRK) {
sport->port.ignore_status_mask |= URXD_BRK;
/*
@ -1330,6 +1447,9 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
sport->port.ignore_status_mask |= URXD_OVRRUN;
}
if ((termios->c_cflag & CREAD) == 0)
sport->port.ignore_status_mask |= URXD_DUMMY_READ;
/*
* Update the per-port timeout.
*/
@ -1403,8 +1523,6 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
imx_enable_ms(&sport->port);
if (sport->dma_is_inited && !sport->dma_is_enabled)
imx_enable_dma(sport);
spin_unlock_irqrestore(&sport->port.lock, flags);
}

View File

@ -3,7 +3,7 @@
/*
* mcf.c -- Freescale ColdFire UART driver
*
* (C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
* (C) Copyright 2003-2007, Greg Ungerer <gerg@uclinux.org>
*
* 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
@ -198,7 +198,6 @@ static void mcf_shutdown(struct uart_port *port)
static void mcf_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
unsigned long flags;
unsigned int baud, baudclk;
#if defined(CONFIG_M5272)
@ -441,7 +440,6 @@ static int mcf_verify_port(struct uart_port *port, struct serial_struct *ser)
/* Enable or disable the RS485 support */
static int mcf_config_rs485(struct uart_port *port, struct serial_rs485 *rs485)
{
struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
unsigned char mr1, mr2;
/* Get mode registers */
@ -631,6 +629,7 @@ static int mcf_probe(struct platform_device *pdev)
port->mapbase = platp[i].mapbase;
port->membase = (platp[i].membase) ? platp[i].membase :
(unsigned char __iomem *) platp[i].mapbase;
port->dev = &pdev->dev;
port->iotype = SERIAL_IO_MEM;
port->irq = platp[i].irq;
port->uartclk = MCF_BUSCLK;
@ -702,7 +701,7 @@ static void __exit mcf_exit(void)
module_init(mcf_init);
module_exit(mcf_exit);
MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>");
MODULE_AUTHOR("Greg Ungerer <gerg@uclinux.org>");
MODULE_DESCRIPTION("Freescale ColdFire UART driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:mcfuart");

View File

@ -23,7 +23,6 @@
#define MEN_Z135_MAX_PORTS 12
#define MEN_Z135_BASECLK 29491200
#define MEN_Z135_FIFO_SIZE 1024
#define MEN_Z135_NUM_MSI_VECTORS 2
#define MEN_Z135_FIFO_WATERMARK 1020
#define MEN_Z135_STAT_REG 0x0
@ -34,12 +33,11 @@
#define MEN_Z135_CONF_REG 0x808
#define MEN_Z135_UART_FREQ 0x80c
#define MEN_Z135_BAUD_REG 0x810
#define MENZ135_TIMEOUT 0x814
#define MEN_Z135_TIMEOUT 0x814
#define MEN_Z135_MEM_SIZE 0x818
#define IS_IRQ(x) ((x) & 1)
#define IRQ_ID(x) (((x) >> 1) & 7)
#define IRQ_ID(x) ((x) & 0x1f)
#define MEN_Z135_IER_RXCIEN BIT(0) /* RX Space IRQ */
#define MEN_Z135_IER_TXCIEN BIT(1) /* TX Space IRQ */
@ -94,11 +92,11 @@
#define MEN_Z135_LSR_TEXP BIT(6)
#define MEN_Z135_LSR_RXFIFOERR BIT(7)
#define MEN_Z135_IRQ_ID_MST 0
#define MEN_Z135_IRQ_ID_TSA 1
#define MEN_Z135_IRQ_ID_RDA 2
#define MEN_Z135_IRQ_ID_RLS 3
#define MEN_Z135_IRQ_ID_CTI 6
#define MEN_Z135_IRQ_ID_RLS BIT(0)
#define MEN_Z135_IRQ_ID_RDA BIT(1)
#define MEN_Z135_IRQ_ID_CTI BIT(2)
#define MEN_Z135_IRQ_ID_TSA BIT(3)
#define MEN_Z135_IRQ_ID_MST BIT(4)
#define LCR(x) (((x) >> MEN_Z135_LCR_SHIFT) & 0xff)
@ -118,12 +116,18 @@ static int align;
module_param(align, int, S_IRUGO);
MODULE_PARM_DESC(align, "Keep hardware FIFO write pointer aligned, default 0");
static uint rx_timeout;
module_param(rx_timeout, uint, S_IRUGO);
MODULE_PARM_DESC(rx_timeout, "RX timeout. "
"Timeout in seconds = (timeout_reg * baud_reg * 4) / freq_reg");
struct men_z135_port {
struct uart_port port;
struct mcb_device *mdev;
unsigned char *rxbuf;
u32 stat_reg;
spinlock_t lock;
bool automode;
};
#define to_men_z135(port) container_of((port), struct men_z135_port, port)
@ -180,12 +184,16 @@ static inline void men_z135_reg_clr(struct men_z135_port *uart,
*/
static void men_z135_handle_modem_status(struct men_z135_port *uart)
{
if (uart->stat_reg & MEN_Z135_MSR_DDCD)
u8 msr;
msr = (uart->stat_reg >> 8) & 0xff;
if (msr & MEN_Z135_MSR_DDCD)
uart_handle_dcd_change(&uart->port,
uart->stat_reg & ~MEN_Z135_MSR_DCD);
if (uart->stat_reg & MEN_Z135_MSR_DCTS)
msr & MEN_Z135_MSR_DCD);
if (msr & MEN_Z135_MSR_DCTS)
uart_handle_cts_change(&uart->port,
uart->stat_reg & ~MEN_Z135_MSR_CTS);
msr & MEN_Z135_MSR_CTS);
}
static void men_z135_handle_lsr(struct men_z135_port *uart)
@ -322,7 +330,8 @@ static void men_z135_handle_tx(struct men_z135_port *uart)
txfree = MEN_Z135_FIFO_WATERMARK - txc;
if (txfree <= 0) {
pr_err("Not enough room in TX FIFO have %d, need %d\n",
dev_err(&uart->mdev->dev,
"Not enough room in TX FIFO have %d, need %d\n",
txfree, qlen);
goto irq_en;
}
@ -373,43 +382,54 @@ out:
* @irq: The IRQ number
* @data: Pointer to UART port
*
* Check IIR register to see which tasklet to start.
* Check IIR register to find the cause of the interrupt and handle it.
* It is possible that multiple interrupts reason bits are set and reading
* the IIR is a destructive read, so we always need to check for all possible
* interrupts and handle them.
*/
static irqreturn_t men_z135_intr(int irq, void *data)
{
struct men_z135_port *uart = (struct men_z135_port *)data;
struct uart_port *port = &uart->port;
bool handled = false;
unsigned long flags;
int irq_id;
uart->stat_reg = ioread32(port->membase + MEN_Z135_STAT_REG);
/* IRQ pending is low active */
if (IS_IRQ(uart->stat_reg))
return IRQ_NONE;
irq_id = IRQ_ID(uart->stat_reg);
switch (irq_id) {
case MEN_Z135_IRQ_ID_MST:
men_z135_handle_modem_status(uart);
break;
case MEN_Z135_IRQ_ID_TSA:
men_z135_handle_tx(uart);
break;
case MEN_Z135_IRQ_ID_CTI:
dev_dbg(&uart->mdev->dev, "Character Timeout Indication\n");
/* Fallthrough */
case MEN_Z135_IRQ_ID_RDA:
/* Reading data clears RX IRQ */
men_z135_handle_rx(uart);
break;
case MEN_Z135_IRQ_ID_RLS:
if (!irq_id)
goto out;
spin_lock_irqsave(&port->lock, flags);
/* It's save to write to IIR[7:6] RXC[9:8] */
iowrite8(irq_id, port->membase + MEN_Z135_STAT_REG);
if (irq_id & MEN_Z135_IRQ_ID_RLS) {
men_z135_handle_lsr(uart);
break;
default:
dev_warn(&uart->mdev->dev, "Unknown IRQ id %d\n", irq_id);
return IRQ_NONE;
handled = true;
}
return IRQ_HANDLED;
if (irq_id & (MEN_Z135_IRQ_ID_RDA | MEN_Z135_IRQ_ID_CTI)) {
if (irq_id & MEN_Z135_IRQ_ID_CTI)
dev_dbg(&uart->mdev->dev, "Character Timeout Indication\n");
men_z135_handle_rx(uart);
handled = true;
}
if (irq_id & MEN_Z135_IRQ_ID_TSA) {
men_z135_handle_tx(uart);
handled = true;
}
if (irq_id & MEN_Z135_IRQ_ID_MST) {
men_z135_handle_modem_status(uart);
handled = true;
}
spin_unlock_irqrestore(&port->lock, flags);
out:
return IRQ_RETVAL(handled);
}
/**
@ -464,21 +484,37 @@ static unsigned int men_z135_tx_empty(struct uart_port *port)
*/
static void men_z135_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct men_z135_port *uart = to_men_z135(port);
u32 conf_reg = 0;
u32 old;
u32 conf_reg;
conf_reg = old = ioread32(port->membase + MEN_Z135_CONF_REG);
if (mctrl & TIOCM_RTS)
conf_reg |= MEN_Z135_MCR_RTS;
else
conf_reg &= ~MEN_Z135_MCR_RTS;
if (mctrl & TIOCM_DTR)
conf_reg |= MEN_Z135_MCR_DTR;
else
conf_reg &= ~MEN_Z135_MCR_DTR;
if (mctrl & TIOCM_OUT1)
conf_reg |= MEN_Z135_MCR_OUT1;
else
conf_reg &= ~MEN_Z135_MCR_OUT1;
if (mctrl & TIOCM_OUT2)
conf_reg |= MEN_Z135_MCR_OUT2;
else
conf_reg &= ~MEN_Z135_MCR_OUT2;
if (mctrl & TIOCM_LOOP)
conf_reg |= MEN_Z135_MCR_LOOP;
else
conf_reg &= ~MEN_Z135_MCR_LOOP;
men_z135_reg_set(uart, MEN_Z135_CONF_REG, conf_reg);
if (conf_reg != old)
iowrite32(conf_reg, port->membase + MEN_Z135_CONF_REG);
}
/**
@ -490,12 +526,9 @@ static void men_z135_set_mctrl(struct uart_port *port, unsigned int mctrl)
static unsigned int men_z135_get_mctrl(struct uart_port *port)
{
unsigned int mctrl = 0;
u32 stat_reg;
u8 msr;
stat_reg = ioread32(port->membase + MEN_Z135_STAT_REG);
msr = ~((stat_reg >> 8) & 0xff);
msr = ioread8(port->membase + MEN_Z135_STAT_REG + 1);
if (msr & MEN_Z135_MSR_CTS)
mctrl |= TIOCM_CTS;
@ -524,6 +557,19 @@ static void men_z135_stop_tx(struct uart_port *port)
men_z135_reg_clr(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN);
}
/*
* men_z135_disable_ms() - Disable Modem Status
* port: The UART port
*
* Enable Modem Status IRQ.
*/
static void men_z135_disable_ms(struct uart_port *port)
{
struct men_z135_port *uart = to_men_z135(port);
men_z135_reg_clr(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_MSIEN);
}
/**
* men_z135_start_tx() - Start transmitting characters
* @port: The UART port
@ -535,6 +581,9 @@ static void men_z135_start_tx(struct uart_port *port)
{
struct men_z135_port *uart = to_men_z135(port);
if (uart->automode)
men_z135_disable_ms(port);
men_z135_handle_tx(uart);
}
@ -584,6 +633,9 @@ static int men_z135_startup(struct uart_port *port)
iowrite32(conf_reg, port->membase + MEN_Z135_CONF_REG);
if (rx_timeout)
iowrite32(rx_timeout, port->membase + MEN_Z135_TIMEOUT);
return 0;
}
@ -603,6 +655,7 @@ static void men_z135_set_termios(struct uart_port *port,
struct ktermios *termios,
struct ktermios *old)
{
struct men_z135_port *uart = to_men_z135(port);
unsigned int baud;
u32 conf_reg;
u32 bd_reg;
@ -643,6 +696,16 @@ static void men_z135_set_termios(struct uart_port *port,
} else
lcr |= MEN_Z135_PAR_DIS << MEN_Z135_PEN_SHIFT;
conf_reg |= MEN_Z135_IER_MSIEN;
if (termios->c_cflag & CRTSCTS) {
conf_reg |= MEN_Z135_MCR_RCFC;
uart->automode = true;
termios->c_cflag &= ~CLOCAL;
} else {
conf_reg &= ~MEN_Z135_MCR_RCFC;
uart->automode = false;
}
termios->c_cflag &= ~CMSPAR; /* Mark/Space parity is not supported */
conf_reg |= lcr << MEN_Z135_LCR_SHIFT;

View File

@ -1,909 +0,0 @@
/*
* mrst_max3110.c - spi uart protocol driver for Maxim 3110
*
* Copyright (c) 2008-2010, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* 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.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
* Note:
* 1. From Max3110 spec, the Rx FIFO has 8 words, while the Tx FIFO only has
* 1 word. If SPI master controller doesn't support sclk frequency change,
* then the char need be sent out one by one with some delay
*
* 2. Currently only RX available interrupt is used, no need for waiting TXE
* interrupt for a low speed UART device
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#ifdef CONFIG_MAGIC_SYSRQ
#define SUPPORT_SYSRQ
#endif
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/irq.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
#include <linux/serial_reg.h>
#include <linux/kthread.h>
#include <linux/spi/spi.h>
#include <linux/pm.h>
#include "mrst_max3110.h"
#define UART_TX_NEEDED 1
#define CON_TX_NEEDED 2
#define BIT_IRQ_PENDING 3
struct uart_max3110 {
struct uart_port port;
struct spi_device *spi;
char name[SPI_NAME_SIZE];
wait_queue_head_t wq;
struct task_struct *main_thread;
struct task_struct *read_thread;
struct mutex thread_mutex;
struct mutex io_mutex;
u32 baud;
u16 cur_conf;
u8 clock;
u8 parity, word_7bits;
u16 irq;
unsigned long uart_flags;
/* console related */
struct circ_buf con_xmit;
};
/* global data structure, may need be removed */
static struct uart_max3110 *pmax;
static int receive_chars(struct uart_max3110 *max,
unsigned short *str, int len);
static int max3110_read_multi(struct uart_max3110 *max);
static void max3110_con_receive(struct uart_max3110 *max);
static int max3110_write_then_read(struct uart_max3110 *max,
const void *txbuf, void *rxbuf, unsigned len, int always_fast)
{
struct spi_device *spi = max->spi;
struct spi_message message;
struct spi_transfer x;
int ret;
mutex_lock(&max->io_mutex);
spi_message_init(&message);
memset(&x, 0, sizeof x);
x.len = len;
x.tx_buf = txbuf;
x.rx_buf = rxbuf;
spi_message_add_tail(&x, &message);
if (always_fast)
x.speed_hz = spi->max_speed_hz;
else if (max->baud)
x.speed_hz = max->baud;
/* Do the i/o */
ret = spi_sync(spi, &message);
mutex_unlock(&max->io_mutex);
return ret;
}
/* Write a 16b word to the device */
static int max3110_out(struct uart_max3110 *max, const u16 out)
{
void *buf;
u16 *obuf, *ibuf;
int ret;
buf = kzalloc(8, GFP_KERNEL | GFP_DMA);
if (!buf)
return -ENOMEM;
obuf = buf;
ibuf = buf + 4;
*obuf = out;
ret = max3110_write_then_read(max, obuf, ibuf, 2, 1);
if (ret) {
pr_warn("%s: get err msg %d when sending 0x%x\n",
__func__, ret, out);
goto exit;
}
receive_chars(max, ibuf, 1);
exit:
kfree(buf);
return ret;
}
/*
* This is usually used to read data from SPIC RX FIFO, which doesn't
* need any delay like flushing character out.
*
* Return how many valide bytes are read back
*/
static int max3110_read_multi(struct uart_max3110 *max)
{
void *buf;
u16 *obuf, *ibuf;
int ret, blen;
blen = M3110_RX_FIFO_DEPTH * sizeof(u16);
buf = kzalloc(blen * 2, GFP_KERNEL | GFP_DMA);
if (!buf)
return 0;
/* tx/rx always have the same length */
obuf = buf;
ibuf = buf + blen;
if (max3110_write_then_read(max, obuf, ibuf, blen, 1)) {
kfree(buf);
return 0;
}
ret = receive_chars(max, ibuf, M3110_RX_FIFO_DEPTH);
kfree(buf);
return ret;
}
static void serial_m3110_con_putchar(struct uart_port *port, int ch)
{
struct uart_max3110 *max =
container_of(port, struct uart_max3110, port);
struct circ_buf *xmit = &max->con_xmit;
if (uart_circ_chars_free(xmit)) {
xmit->buf[xmit->head] = (char)ch;
xmit->head = (xmit->head + 1) & (PAGE_SIZE - 1);
}
}
/*
* Print a string to the serial port trying not to disturb
* any possible real use of the port...
*
* The console_lock must be held when we get here.
*/
static void serial_m3110_con_write(struct console *co,
const char *s, unsigned int count)
{
if (!pmax)
return;
uart_console_write(&pmax->port, s, count, serial_m3110_con_putchar);
if (!test_and_set_bit(CON_TX_NEEDED, &pmax->uart_flags))
wake_up(&pmax->wq);
}
static int __init
serial_m3110_con_setup(struct console *co, char *options)
{
struct uart_max3110 *max = pmax;
int baud = 115200;
int bits = 8;
int parity = 'n';
int flow = 'n';
pr_info("setting up console\n");
if (co->index == -1)
co->index = 0;
if (!max) {
pr_err("pmax is NULL, return\n");
return -ENODEV;
}
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
return uart_set_options(&max->port, co, baud, parity, bits, flow);
}
static struct tty_driver *serial_m3110_con_device(struct console *co,
int *index)
{
struct uart_driver *p = co->data;
*index = co->index;
return p->tty_driver;
}
static struct uart_driver serial_m3110_reg;
static struct console serial_m3110_console = {
.name = "ttyS",
.write = serial_m3110_con_write,
.device = serial_m3110_con_device,
.setup = serial_m3110_con_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &serial_m3110_reg,
};
static unsigned int serial_m3110_tx_empty(struct uart_port *port)
{
return 1;
}
static void serial_m3110_stop_tx(struct uart_port *port)
{
return;
}
/* stop_rx will be called in spin_lock env */
static void serial_m3110_stop_rx(struct uart_port *port)
{
return;
}
#define WORDS_PER_XFER 128
static void send_circ_buf(struct uart_max3110 *max,
struct circ_buf *xmit)
{
void *buf;
u16 *obuf, *ibuf;
int i, len, blen, dma_size, left, ret = 0;
dma_size = WORDS_PER_XFER * sizeof(u16) * 2;
buf = kzalloc(dma_size, GFP_KERNEL | GFP_DMA);
if (!buf)
return;
obuf = buf;
ibuf = buf + dma_size/2;
while (!uart_circ_empty(xmit)) {
left = uart_circ_chars_pending(xmit);
while (left) {
len = min(left, WORDS_PER_XFER);
blen = len * sizeof(u16);
memset(ibuf, 0, blen);
for (i = 0; i < len; i++) {
obuf[i] = (u8)xmit->buf[xmit->tail] | WD_TAG;
xmit->tail = (xmit->tail + 1) &
(UART_XMIT_SIZE - 1);
}
/* Fail to send msg to console is not very critical */
ret = max3110_write_then_read(max, obuf, ibuf, blen, 0);
if (ret)
pr_warn("%s: get err msg %d\n", __func__, ret);
receive_chars(max, ibuf, len);
max->port.icount.tx += len;
left -= len;
}
}
kfree(buf);
}
static void transmit_char(struct uart_max3110 *max)
{
struct uart_port *port = &max->port;
struct circ_buf *xmit = &port->state->xmit;
if (uart_circ_empty(xmit) || uart_tx_stopped(port))
return;
send_circ_buf(max, xmit);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
if (uart_circ_empty(xmit))
serial_m3110_stop_tx(port);
}
/*
* This will be called by uart_write() and tty_write, can't
* go to sleep
*/
static void serial_m3110_start_tx(struct uart_port *port)
{
struct uart_max3110 *max =
container_of(port, struct uart_max3110, port);
if (!test_and_set_bit(UART_TX_NEEDED, &max->uart_flags))
wake_up(&max->wq);
}
static int
receive_chars(struct uart_max3110 *max, unsigned short *str, int len)
{
struct uart_port *port = &max->port;
struct tty_port *tport;
char buf[M3110_RX_FIFO_DEPTH];
int r, w, usable;
/* If uart is not opened, just return */
if (!port->state)
return 0;
tport = &port->state->port;
for (r = 0, w = 0; r < len; r++) {
if (str[r] & MAX3110_BREAK &&
uart_handle_break(port))
continue;
if (str[r] & MAX3110_READ_DATA_AVAILABLE) {
if (uart_handle_sysrq_char(port, str[r] & 0xff))
continue;
buf[w++] = str[r] & 0xff;
}
}
if (!w)
return 0;
for (r = 0; w; r += usable, w -= usable) {
usable = tty_buffer_request_room(tport, w);
if (usable) {
tty_insert_flip_string(tport, buf + r, usable);
port->icount.rx += usable;
}
}
tty_flip_buffer_push(tport);
return r;
}
/*
* This routine will be used in read_thread or RX IRQ handling,
* it will first do one round buffer read(8 words), if there is some
* valid RX data, will try to read 5 more rounds till all data
* is read out.
*
* Use stack space as data buffer to save some system load, and chose
* 504 Btyes as a threadhold to do a bulk push to upper tty layer when
* receiving bulk data, a much bigger buffer may cause stack overflow
*/
static void max3110_con_receive(struct uart_max3110 *max)
{
int loop = 1, num;
do {
num = max3110_read_multi(max);
if (num) {
loop = 5;
}
} while (--loop);
}
static int max3110_main_thread(void *_max)
{
struct uart_max3110 *max = _max;
wait_queue_head_t *wq = &max->wq;
int ret = 0;
struct circ_buf *xmit = &max->con_xmit;
pr_info("start main thread\n");
do {
wait_event_interruptible(*wq,
max->uart_flags || kthread_should_stop());
mutex_lock(&max->thread_mutex);
if (test_and_clear_bit(BIT_IRQ_PENDING, &max->uart_flags))
max3110_con_receive(max);
/* first handle console output */
if (test_and_clear_bit(CON_TX_NEEDED, &max->uart_flags))
send_circ_buf(max, xmit);
/* handle uart output */
if (test_and_clear_bit(UART_TX_NEEDED, &max->uart_flags))
transmit_char(max);
mutex_unlock(&max->thread_mutex);
} while (!kthread_should_stop());
return ret;
}
static irqreturn_t serial_m3110_irq(int irq, void *dev_id)
{
struct uart_max3110 *max = dev_id;
/* max3110's irq is a falling edge, not level triggered,
* so no need to disable the irq */
if (!test_and_set_bit(BIT_IRQ_PENDING, &max->uart_flags))
wake_up(&max->wq);
return IRQ_HANDLED;
}
/* if don't use RX IRQ, then need a thread to polling read */
static int max3110_read_thread(void *_max)
{
struct uart_max3110 *max = _max;
pr_info("start read thread\n");
do {
/*
* If can't acquire the mutex, it means the main thread
* is running which will also perform the rx job
*/
if (mutex_trylock(&max->thread_mutex)) {
max3110_con_receive(max);
mutex_unlock(&max->thread_mutex);
}
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ / 20);
} while (!kthread_should_stop());
return 0;
}
static int serial_m3110_startup(struct uart_port *port)
{
struct uart_max3110 *max =
container_of(port, struct uart_max3110, port);
u16 config = 0;
int ret = 0;
if (port->line != 0) {
pr_err("uart port startup failed\n");
return -1;
}
/* Disable all IRQ and config it to 115200, 8n1 */
config = WC_TAG | WC_FIFO_ENABLE
| WC_1_STOPBITS
| WC_8BIT_WORD
| WC_BAUD_DR2;
/* as we use thread to handle tx/rx, need set low latency */
port->state->port.low_latency = 1;
if (max->irq) {
/* Enable RX IRQ only */
config |= WC_RXA_IRQ_ENABLE;
} else {
/* If IRQ is disabled, start a read thread for input data */
max->read_thread =
kthread_run(max3110_read_thread, max, "max3110_read");
if (IS_ERR(max->read_thread)) {
ret = PTR_ERR(max->read_thread);
max->read_thread = NULL;
pr_err("Can't create read thread!\n");
return ret;
}
}
ret = max3110_out(max, config);
if (ret) {
if (max->read_thread)
kthread_stop(max->read_thread);
max->read_thread = NULL;
return ret;
}
max->cur_conf = config;
return 0;
}
static void serial_m3110_shutdown(struct uart_port *port)
{
struct uart_max3110 *max =
container_of(port, struct uart_max3110, port);
u16 config;
if (max->read_thread) {
kthread_stop(max->read_thread);
max->read_thread = NULL;
}
/* Disable interrupts from this port */
config = WC_TAG | WC_SW_SHDI;
max3110_out(max, config);
}
static void serial_m3110_release_port(struct uart_port *port)
{
}
static int serial_m3110_request_port(struct uart_port *port)
{
return 0;
}
static void serial_m3110_config_port(struct uart_port *port, int flags)
{
port->type = PORT_MAX3100;
}
static int
serial_m3110_verify_port(struct uart_port *port, struct serial_struct *ser)
{
/* we don't want the core code to modify any port params */
return -EINVAL;
}
static const char *serial_m3110_type(struct uart_port *port)
{
struct uart_max3110 *max =
container_of(port, struct uart_max3110, port);
return max->name;
}
static void
serial_m3110_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
struct uart_max3110 *max =
container_of(port, struct uart_max3110, port);
unsigned char cval;
unsigned int baud, parity = 0;
int clk_div = -1;
u16 new_conf = max->cur_conf;
switch (termios->c_cflag & CSIZE) {
case CS7:
cval = UART_LCR_WLEN7;
new_conf |= WC_7BIT_WORD;
break;
default:
/* We only support CS7 & CS8 */
termios->c_cflag &= ~CSIZE;
termios->c_cflag |= CS8;
case CS8:
cval = UART_LCR_WLEN8;
new_conf |= WC_8BIT_WORD;
break;
}
baud = uart_get_baud_rate(port, termios, old, 0, 230400);
/* First calc the div for 1.8MHZ clock case */
switch (baud) {
case 300:
clk_div = WC_BAUD_DR384;
break;
case 600:
clk_div = WC_BAUD_DR192;
break;
case 1200:
clk_div = WC_BAUD_DR96;
break;
case 2400:
clk_div = WC_BAUD_DR48;
break;
case 4800:
clk_div = WC_BAUD_DR24;
break;
case 9600:
clk_div = WC_BAUD_DR12;
break;
case 19200:
clk_div = WC_BAUD_DR6;
break;
case 38400:
clk_div = WC_BAUD_DR3;
break;
case 57600:
clk_div = WC_BAUD_DR2;
break;
case 115200:
clk_div = WC_BAUD_DR1;
break;
case 230400:
if (max->clock & MAX3110_HIGH_CLK)
break;
default:
/* Pick the previous baud rate */
baud = max->baud;
clk_div = max->cur_conf & WC_BAUD_DIV_MASK;
tty_termios_encode_baud_rate(termios, baud, baud);
}
if (max->clock & MAX3110_HIGH_CLK) {
clk_div += 1;
/* High clk version max3110 doesn't support B300 */
if (baud == 300) {
baud = 600;
clk_div = WC_BAUD_DR384;
}
if (baud == 230400)
clk_div = WC_BAUD_DR1;
tty_termios_encode_baud_rate(termios, baud, baud);
}
new_conf = (new_conf & ~WC_BAUD_DIV_MASK) | clk_div;
if (unlikely(termios->c_cflag & CMSPAR))
termios->c_cflag &= ~CMSPAR;
if (termios->c_cflag & CSTOPB)
new_conf |= WC_2_STOPBITS;
else
new_conf &= ~WC_2_STOPBITS;
if (termios->c_cflag & PARENB) {
new_conf |= WC_PARITY_ENABLE;
parity |= UART_LCR_PARITY;
} else
new_conf &= ~WC_PARITY_ENABLE;
if (!(termios->c_cflag & PARODD))
parity |= UART_LCR_EPAR;
max->parity = parity;
uart_update_timeout(port, termios->c_cflag, baud);
new_conf |= WC_TAG;
if (new_conf != max->cur_conf) {
if (!max3110_out(max, new_conf)) {
max->cur_conf = new_conf;
max->baud = baud;
}
}
}
/* Don't handle hw handshaking */
static unsigned int serial_m3110_get_mctrl(struct uart_port *port)
{
return TIOCM_DSR | TIOCM_CAR | TIOCM_DSR;
}
static void serial_m3110_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
}
static void serial_m3110_break_ctl(struct uart_port *port, int break_state)
{
}
static void serial_m3110_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate)
{
}
static struct uart_ops serial_m3110_ops = {
.tx_empty = serial_m3110_tx_empty,
.set_mctrl = serial_m3110_set_mctrl,
.get_mctrl = serial_m3110_get_mctrl,
.stop_tx = serial_m3110_stop_tx,
.start_tx = serial_m3110_start_tx,
.stop_rx = serial_m3110_stop_rx,
.break_ctl = serial_m3110_break_ctl,
.startup = serial_m3110_startup,
.shutdown = serial_m3110_shutdown,
.set_termios = serial_m3110_set_termios,
.pm = serial_m3110_pm,
.type = serial_m3110_type,
.release_port = serial_m3110_release_port,
.request_port = serial_m3110_request_port,
.config_port = serial_m3110_config_port,
.verify_port = serial_m3110_verify_port,
};
static struct uart_driver serial_m3110_reg = {
.owner = THIS_MODULE,
.driver_name = "MRST serial",
.dev_name = "ttyS",
.major = TTY_MAJOR,
.minor = 64,
.nr = 1,
.cons = &serial_m3110_console,
};
#ifdef CONFIG_PM_SLEEP
static int serial_m3110_suspend(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
struct uart_max3110 *max = spi_get_drvdata(spi);
if (max->irq > 0)
disable_irq(max->irq);
uart_suspend_port(&serial_m3110_reg, &max->port);
max3110_out(max, max->cur_conf | WC_SW_SHDI);
return 0;
}
static int serial_m3110_resume(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
struct uart_max3110 *max = spi_get_drvdata(spi);
max3110_out(max, max->cur_conf);
uart_resume_port(&serial_m3110_reg, &max->port);
if (max->irq > 0)
enable_irq(max->irq);
return 0;
}
static SIMPLE_DEV_PM_OPS(serial_m3110_pm_ops, serial_m3110_suspend,
serial_m3110_resume);
#define SERIAL_M3110_PM_OPS (&serial_m3110_pm_ops)
#else
#define SERIAL_M3110_PM_OPS NULL
#endif
static int serial_m3110_probe(struct spi_device *spi)
{
struct uart_max3110 *max;
void *buffer;
u16 res;
int ret = 0;
max = kzalloc(sizeof(*max), GFP_KERNEL);
if (!max)
return -ENOMEM;
/* Set spi info */
spi->bits_per_word = 16;
max->clock = MAX3110_HIGH_CLK;
spi_setup(spi);
max->port.type = PORT_MAX3100;
max->port.fifosize = 2; /* Only have 16b buffer */
max->port.ops = &serial_m3110_ops;
max->port.line = 0;
max->port.dev = &spi->dev;
max->port.uartclk = 115200;
max->spi = spi;
strcpy(max->name, spi->modalias);
max->irq = (u16)spi->irq;
mutex_init(&max->thread_mutex);
mutex_init(&max->io_mutex);
max->word_7bits = 0;
max->parity = 0;
max->baud = 0;
max->cur_conf = 0;
max->uart_flags = 0;
/* Check if reading configuration register returns something sane */
res = RC_TAG;
ret = max3110_write_then_read(max, (u8 *)&res, (u8 *)&res, 2, 0);
if (ret < 0 || res == 0 || res == 0xffff) {
dev_dbg(&spi->dev, "MAX3111 deemed not present (conf reg %04x)",
res);
ret = -ENODEV;
goto err_get_page;
}
buffer = (void *)__get_free_page(GFP_KERNEL);
if (!buffer) {
ret = -ENOMEM;
goto err_get_page;
}
max->con_xmit.buf = buffer;
max->con_xmit.head = 0;
max->con_xmit.tail = 0;
init_waitqueue_head(&max->wq);
max->main_thread = kthread_run(max3110_main_thread,
max, "max3110_main");
if (IS_ERR(max->main_thread)) {
ret = PTR_ERR(max->main_thread);
goto err_kthread;
}
if (max->irq) {
ret = request_irq(max->irq, serial_m3110_irq,
IRQ_TYPE_EDGE_FALLING, "max3110", max);
if (ret) {
max->irq = 0;
dev_warn(&spi->dev,
"unable to allocate IRQ, will use polling method\n");
}
}
spi_set_drvdata(spi, max);
pmax = max;
/* Give membase a psudo value to pass serial_core's check */
max->port.membase = (unsigned char __iomem *)0xff110000;
uart_add_one_port(&serial_m3110_reg, &max->port);
return 0;
err_kthread:
free_page((unsigned long)buffer);
err_get_page:
kfree(max);
return ret;
}
static int serial_m3110_remove(struct spi_device *dev)
{
struct uart_max3110 *max = spi_get_drvdata(dev);
if (!max)
return 0;
uart_remove_one_port(&serial_m3110_reg, &max->port);
free_page((unsigned long)max->con_xmit.buf);
if (max->irq)
free_irq(max->irq, max);
if (max->main_thread)
kthread_stop(max->main_thread);
kfree(max);
return 0;
}
static struct spi_driver uart_max3110_driver = {
.driver = {
.name = "spi_max3111",
.owner = THIS_MODULE,
.pm = SERIAL_M3110_PM_OPS,
},
.probe = serial_m3110_probe,
.remove = serial_m3110_remove,
};
static int __init serial_m3110_init(void)
{
int ret = 0;
ret = uart_register_driver(&serial_m3110_reg);
if (ret)
return ret;
ret = spi_register_driver(&uart_max3110_driver);
if (ret)
uart_unregister_driver(&serial_m3110_reg);
return ret;
}
static void __exit serial_m3110_exit(void)
{
spi_unregister_driver(&uart_max3110_driver);
uart_unregister_driver(&serial_m3110_reg);
}
module_init(serial_m3110_init);
module_exit(serial_m3110_exit);
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("spi:max3110-uart");

View File

@ -1,61 +0,0 @@
#ifndef _MRST_MAX3110_H
#define _MRST_MAX3110_H
#define MAX3110_HIGH_CLK 0x1 /* 3.6864 MHZ */
#define MAX3110_LOW_CLK 0x0 /* 1.8432 MHZ */
/* status bits for all 4 MAX3110 operate modes */
#define MAX3110_READ_DATA_AVAILABLE (1 << 15)
#define MAX3110_WRITE_BUF_EMPTY (1 << 14)
#define MAX3110_BREAK (1 << 10)
#define WC_TAG (3 << 14)
#define RC_TAG (1 << 14)
#define WD_TAG (2 << 14)
#define RD_TAG (0 << 14)
/* bits def for write configuration */
#define WC_FIFO_ENABLE_MASK (1 << 13)
#define WC_FIFO_ENABLE (0 << 13)
#define WC_SW_SHDI (1 << 12)
#define WC_IRQ_MASK (0xF << 8)
#define WC_TXE_IRQ_ENABLE (1 << 11) /* TX empty irq */
#define WC_RXA_IRQ_ENABLE (1 << 10) /* RX available irq */
#define WC_PAR_HIGH_IRQ_ENABLE (1 << 9)
#define WC_REC_ACT_IRQ_ENABLE (1 << 8)
#define WC_IRDA_ENABLE (1 << 7)
#define WC_STOPBITS_MASK (1 << 6)
#define WC_2_STOPBITS (1 << 6)
#define WC_1_STOPBITS (0 << 6)
#define WC_PARITY_ENABLE_MASK (1 << 5)
#define WC_PARITY_ENABLE (1 << 5)
#define WC_WORDLEN_MASK (1 << 4)
#define WC_7BIT_WORD (1 << 4)
#define WC_8BIT_WORD (0 << 4)
#define WC_BAUD_DIV_MASK (0xF)
#define WC_BAUD_DR1 (0x0)
#define WC_BAUD_DR2 (0x1)
#define WC_BAUD_DR4 (0x2)
#define WC_BAUD_DR8 (0x3)
#define WC_BAUD_DR16 (0x4)
#define WC_BAUD_DR32 (0x5)
#define WC_BAUD_DR64 (0x6)
#define WC_BAUD_DR128 (0x7)
#define WC_BAUD_DR3 (0x8)
#define WC_BAUD_DR6 (0x9)
#define WC_BAUD_DR12 (0xA)
#define WC_BAUD_DR24 (0xB)
#define WC_BAUD_DR48 (0xC)
#define WC_BAUD_DR96 (0xD)
#define WC_BAUD_DR192 (0xE)
#define WC_BAUD_DR384 (0xF)
#define M3110_RX_FIFO_DEPTH 8
#endif

View File

@ -920,14 +920,15 @@ static void msm_console_write(struct console *co, const char *s,
static int __init msm_console_setup(struct console *co, char *options)
{
struct uart_port *port;
struct msm_port *msm_port;
int baud = 0, flow, bits, parity;
int baud = 115200;
int bits = 8;
int parity = 'n';
int flow = 'n';
if (unlikely(co->index >= UART_NR || co->index < 0))
return -ENXIO;
port = get_port_from_line(co->index);
msm_port = UART_TO_MSM(port);
if (unlikely(!port->membase))
return -ENXIO;
@ -937,23 +938,6 @@ static int __init msm_console_setup(struct console *co, char *options)
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
bits = 8;
parity = 'n';
flow = 'n';
msm_write(port, UART_MR2_BITS_PER_CHAR_8 | UART_MR2_STOP_BIT_LEN_ONE,
UART_MR2); /* 8N1 */
if (baud < 300 || baud > 115200)
baud = 115200;
msm_set_baud_rate(port, baud);
msm_reset(port);
if (msm_port->is_uartdm) {
msm_write(port, UART_CR_CMD_PROTECTION_EN, UART_CR);
msm_write(port, UART_CR_TX_ENABLE, UART_CR);
}
pr_info("msm_serial: console setup on port #%d\n", port->line);
return uart_set_options(port, co, baud, parity, bits, flow);
@ -1142,9 +1126,6 @@ static int __init msm_serial_init(void)
static void __exit msm_serial_exit(void)
{
#ifdef CONFIG_SERIAL_MSM_CONSOLE
unregister_console(&msm_console);
#endif
platform_driver_unregister(&msm_platform_driver);
uart_unregister_driver(&msm_uart_driver);
}

View File

@ -152,8 +152,6 @@ struct mxs_auart_port {
unsigned int mctrl_prev;
enum mxs_auart_type devtype;
unsigned int irq;
struct clk *clk;
struct device *dev;
@ -1228,37 +1226,32 @@ static int mxs_auart_probe(struct platform_device *pdev)
of_match_device(mxs_auart_dt_ids, &pdev->dev);
struct mxs_auart_port *s;
u32 version;
int ret = 0;
int ret, irq;
struct resource *r;
s = kzalloc(sizeof(struct mxs_auart_port), GFP_KERNEL);
if (!s) {
ret = -ENOMEM;
goto out;
}
s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL);
if (!s)
return -ENOMEM;
ret = serial_mxs_probe_dt(s, pdev);
if (ret > 0)
s->port.line = pdev->id < 0 ? 0 : pdev->id;
else if (ret < 0)
goto out_free;
return ret;
if (of_id) {
pdev->id_entry = of_id->data;
s->devtype = pdev->id_entry->driver_data;
}
s->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(s->clk)) {
ret = PTR_ERR(s->clk);
goto out_free;
}
s->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(s->clk))
return PTR_ERR(s->clk);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) {
ret = -ENXIO;
goto out_free_clk;
}
if (!r)
return -ENXIO;
s->port.mapbase = r->start;
s->port.membase = ioremap(r->start, resource_size(r));
@ -1271,11 +1264,15 @@ static int mxs_auart_probe(struct platform_device *pdev)
s->mctrl_prev = 0;
s->irq = platform_get_irq(pdev, 0);
s->port.irq = s->irq;
ret = request_irq(s->irq, mxs_auart_irq_handle, 0, dev_name(&pdev->dev), s);
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
s->port.irq = irq;
ret = devm_request_irq(&pdev->dev, irq, mxs_auart_irq_handle, 0,
dev_name(&pdev->dev), s);
if (ret)
goto out_free_clk;
return ret;
platform_set_drvdata(pdev, s);
@ -1288,7 +1285,7 @@ static int mxs_auart_probe(struct platform_device *pdev)
*/
ret = mxs_auart_request_gpio_irq(s);
if (ret)
goto out_free_irq;
return ret;
auart_port[s->port.line] = s;
@ -1307,14 +1304,7 @@ static int mxs_auart_probe(struct platform_device *pdev)
out_free_gpio_irq:
mxs_auart_free_gpio_irq(s);
out_free_irq:
auart_port[pdev->id] = NULL;
free_irq(s->irq, s);
out_free_clk:
clk_put(s->clk);
out_free:
kfree(s);
out:
return ret;
}
@ -1323,13 +1313,8 @@ static int mxs_auart_remove(struct platform_device *pdev)
struct mxs_auart_port *s = platform_get_drvdata(pdev);
uart_remove_one_port(&auart_driver, &s->port);
auart_port[pdev->id] = NULL;
mxs_auart_free_gpio_irq(s);
clk_put(s->clk);
free_irq(s->irq, s);
kfree(s);
return 0;
}

View File

@ -102,6 +102,11 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
if (of_property_read_u32(np, "fifo-size", &prop) == 0)
port->fifosize = prop;
/* Check for a fixed line number */
ret = of_alias_get_id(np, "serial");
if (ret >= 0)
port->line = ret;
port->irq = irq_of_parse_and_map(np, 0);
port->iotype = UPIO_MEM;
if (of_property_read_u32(np, "reg-io-width", &prop) == 0) {
@ -128,6 +133,10 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
if (of_find_property(np, "no-loopback-test", NULL))
port->flags |= UPF_SKIP_TEST;
ret = of_alias_get_id(np, "serial");
if (ret >= 0)
port->line = ret;
port->dev = &ofdev->dev;
switch (type) {
@ -331,6 +340,10 @@ static struct of_device_id of_platform_serial_table[] = {
.data = (void *)PORT_ALTR_16550_F64, },
{ .compatible = "altr,16550-FIFO128",
.data = (void *)PORT_ALTR_16550_F128, },
{ .compatible = "mrvl,mmp-uart",
.data = (void *)PORT_XSCALE, },
{ .compatible = "mrvl,pxa-uart",
.data = (void *)PORT_XSCALE, },
#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
{ .compatible = "ibm,qpace-nwp-serial",
.data = (void *)PORT_NWPSERIAL, },

View File

@ -63,7 +63,7 @@
#define UART_ERRATA_i202_MDR1_ACCESS BIT(0)
#define UART_ERRATA_i291_DMA_FORCEIDLE BIT(1)
#define DEFAULT_CLK_SPEED 48000000 /* 48Mhz*/
#define DEFAULT_CLK_SPEED 48000000 /* 48Mhz */
/* SCR register bitmasks */
#define OMAP_UART_SCR_RX_TRIG_GRANU1_MASK (1 << 7)
@ -93,7 +93,7 @@
/* WER = 0x7F
* Enable module level wakeup in WER reg
*/
#define OMAP_UART_WER_MOD_WKUP 0X7F
#define OMAP_UART_WER_MOD_WKUP 0x7F
/* Enable XON/XOFF flow control on output */
#define OMAP_UART_SW_TX 0x08
@ -114,7 +114,7 @@ struct uart_omap_dma {
dma_addr_t tx_buf_dma_phys;
unsigned int uart_base;
/*
* Buffer for rx dma.It is not required for tx because the buffer
* Buffer for rx dma. It is not required for tx because the buffer
* comes from port structure.
*/
unsigned char *rx_buf;
@ -151,7 +151,7 @@ struct uart_omap_port {
int use_dma;
/*
* Some bits in registers are cleared on a read, so they must
* be saved whenever the register is read but the bits will not
* be saved whenever the register is read, but the bits will not
* be immediately processed.
*/
unsigned int lsr_break_flag;
@ -681,7 +681,7 @@ static unsigned int serial_omap_get_mctrl(struct uart_port *port)
static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct uart_omap_port *up = to_uart_omap_port(port);
unsigned char mcr = 0, old_mcr;
unsigned char mcr = 0, old_mcr, lcr;
dev_dbg(up->port.dev, "serial_omap_set_mctrl+%d\n", up->port.line);
if (mctrl & TIOCM_RTS)
@ -701,6 +701,17 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
UART_MCR_DTR | UART_MCR_RTS);
up->mcr = old_mcr | mcr;
serial_out(up, UART_MCR, up->mcr);
/* Turn off autoRTS if RTS is lowered; restore autoRTS if RTS raised */
lcr = serial_in(up, UART_LCR);
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
up->efr |= UART_EFR_RTS;
else
up->efr &= UART_EFR_RTS;
serial_out(up, UART_EFR, up->efr);
serial_out(up, UART_LCR, lcr);
pm_runtime_mark_last_busy(up->dev);
pm_runtime_put_autosuspend(up->dev);
}
@ -756,8 +767,6 @@ static int serial_omap_startup(struct uart_port *port)
* (they will be reenabled in set_termios())
*/
serial_omap_clear_fifos(up);
/* For Hardware flow control */
serial_out(up, UART_MCR, UART_MCR_RTS);
/*
* Clear the interrupt registers.
@ -1053,12 +1062,12 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);
if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) {
/* Enable AUTORTS and AUTOCTS */
up->efr |= UART_EFR_CTS | UART_EFR_RTS;
up->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF);
/* Ensure MCR RTS is asserted */
up->mcr |= UART_MCR_RTS;
if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) {
/* Enable AUTOCTS (autoRTS is enabled when RTS is raised) */
up->port.status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
up->efr |= UART_EFR_CTS;
} else {
/* Disable AUTORTS and AUTOCTS */
up->efr &= ~(UART_EFR_CTS | UART_EFR_RTS);
@ -1081,8 +1090,10 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
* Enable XON/XOFF flow control on output.
* Transmit XON1, XOFF1
*/
if (termios->c_iflag & IXOFF)
if (termios->c_iflag & IXOFF) {
up->port.status |= UPSTAT_AUTOXOFF;
up->efr |= OMAP_UART_SW_TX;
}
/*
* IXANY Flag:

View File

@ -28,6 +28,9 @@
#define SUPPORT_SYSRQ
#endif
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/io.h>
@ -78,6 +81,10 @@ static void dbg(const char *fmt, ...)
#define S3C24XX_SERIAL_MAJOR 204
#define S3C24XX_SERIAL_MINOR 64
#define S3C24XX_TX_PIO 1
#define S3C24XX_TX_DMA 2
#define S3C24XX_RX_PIO 1
#define S3C24XX_RX_DMA 2
/* macros to change one thing to another */
#define tx_enabled(port) ((port)->unused[0])
@ -154,39 +161,272 @@ static void s3c24xx_serial_rx_disable(struct uart_port *port)
static void s3c24xx_serial_stop_tx(struct uart_port *port)
{
struct s3c24xx_uart_port *ourport = to_ourport(port);
struct s3c24xx_uart_dma *dma = ourport->dma;
struct circ_buf *xmit = &port->state->xmit;
struct dma_tx_state state;
int count;
if (tx_enabled(port)) {
if (s3c24xx_serial_has_interrupt_mask(port))
__set_bit(S3C64XX_UINTM_TXD,
portaddrl(port, S3C64XX_UINTM));
else
disable_irq_nosync(ourport->tx_irq);
tx_enabled(port) = 0;
if (port->flags & UPF_CONS_FLOW)
s3c24xx_serial_rx_enable(port);
if (!tx_enabled(port))
return;
if (s3c24xx_serial_has_interrupt_mask(port))
__set_bit(S3C64XX_UINTM_TXD,
portaddrl(port, S3C64XX_UINTM));
else
disable_irq_nosync(ourport->tx_irq);
if (dma && dma->tx_chan && ourport->tx_in_progress == S3C24XX_TX_DMA) {
dmaengine_pause(dma->tx_chan);
dmaengine_tx_status(dma->tx_chan, dma->tx_cookie, &state);
dmaengine_terminate_all(dma->tx_chan);
dma_sync_single_for_cpu(ourport->port.dev,
dma->tx_transfer_addr, dma->tx_size, DMA_TO_DEVICE);
async_tx_ack(dma->tx_desc);
count = dma->tx_bytes_requested - state.residue;
xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
port->icount.tx += count;
}
tx_enabled(port) = 0;
ourport->tx_in_progress = 0;
if (port->flags & UPF_CONS_FLOW)
s3c24xx_serial_rx_enable(port);
ourport->tx_mode = 0;
}
static void s3c24xx_serial_start_tx(struct uart_port *port)
static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport);
static void s3c24xx_serial_tx_dma_complete(void *args)
{
struct s3c24xx_uart_port *ourport = args;
struct uart_port *port = &ourport->port;
struct circ_buf *xmit = &port->state->xmit;
struct s3c24xx_uart_dma *dma = ourport->dma;
struct dma_tx_state state;
unsigned long flags;
int count;
dmaengine_tx_status(dma->tx_chan, dma->tx_cookie, &state);
count = dma->tx_bytes_requested - state.residue;
async_tx_ack(dma->tx_desc);
dma_sync_single_for_cpu(ourport->port.dev, dma->tx_transfer_addr,
dma->tx_size, DMA_TO_DEVICE);
spin_lock_irqsave(&port->lock, flags);
xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
port->icount.tx += count;
ourport->tx_in_progress = 0;
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
s3c24xx_serial_start_next_tx(ourport);
spin_unlock_irqrestore(&port->lock, flags);
}
static void enable_tx_dma(struct s3c24xx_uart_port *ourport)
{
struct uart_port *port = &ourport->port;
u32 ucon;
/* Mask Tx interrupt */
if (s3c24xx_serial_has_interrupt_mask(port))
__set_bit(S3C64XX_UINTM_TXD,
portaddrl(port, S3C64XX_UINTM));
else
disable_irq_nosync(ourport->tx_irq);
/* Enable tx dma mode */
ucon = rd_regl(port, S3C2410_UCON);
ucon &= ~(S3C64XX_UCON_TXBURST_MASK | S3C64XX_UCON_TXMODE_MASK);
ucon |= (dma_get_cache_alignment() >= 16) ?
S3C64XX_UCON_TXBURST_16 : S3C64XX_UCON_TXBURST_1;
ucon |= S3C64XX_UCON_TXMODE_DMA;
wr_regl(port, S3C2410_UCON, ucon);
ourport->tx_mode = S3C24XX_TX_DMA;
}
static void enable_tx_pio(struct s3c24xx_uart_port *ourport)
{
struct uart_port *port = &ourport->port;
u32 ucon, ufcon;
/* Set ufcon txtrig */
ourport->tx_in_progress = S3C24XX_TX_PIO;
ufcon = rd_regl(port, S3C2410_UFCON);
wr_regl(port, S3C2410_UFCON, ufcon);
/* Enable tx pio mode */
ucon = rd_regl(port, S3C2410_UCON);
ucon &= ~(S3C64XX_UCON_TXMODE_MASK);
ucon |= S3C64XX_UCON_TXMODE_CPU;
wr_regl(port, S3C2410_UCON, ucon);
/* Unmask Tx interrupt */
if (s3c24xx_serial_has_interrupt_mask(port))
__clear_bit(S3C64XX_UINTM_TXD,
portaddrl(port, S3C64XX_UINTM));
else
enable_irq(ourport->tx_irq);
ourport->tx_mode = S3C24XX_TX_PIO;
}
static void s3c24xx_serial_start_tx_pio(struct s3c24xx_uart_port *ourport)
{
if (ourport->tx_mode != S3C24XX_TX_PIO)
enable_tx_pio(ourport);
}
static int s3c24xx_serial_start_tx_dma(struct s3c24xx_uart_port *ourport,
unsigned int count)
{
struct uart_port *port = &ourport->port;
struct circ_buf *xmit = &port->state->xmit;
struct s3c24xx_uart_dma *dma = ourport->dma;
if (ourport->tx_mode != S3C24XX_TX_DMA)
enable_tx_dma(ourport);
while (xmit->tail & (dma_get_cache_alignment() - 1)) {
if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)
return 0;
wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
count--;
}
dma->tx_size = count & ~(dma_get_cache_alignment() - 1);
dma->tx_transfer_addr = dma->tx_addr + xmit->tail;
dma_sync_single_for_device(ourport->port.dev, dma->tx_transfer_addr,
dma->tx_size, DMA_TO_DEVICE);
dma->tx_desc = dmaengine_prep_slave_single(dma->tx_chan,
dma->tx_transfer_addr, dma->tx_size,
DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
if (!dma->tx_desc) {
dev_err(ourport->port.dev, "Unable to get desc for Tx\n");
return -EIO;
}
dma->tx_desc->callback = s3c24xx_serial_tx_dma_complete;
dma->tx_desc->callback_param = ourport;
dma->tx_bytes_requested = dma->tx_size;
ourport->tx_in_progress = S3C24XX_TX_DMA;
dma->tx_cookie = dmaengine_submit(dma->tx_desc);
dma_async_issue_pending(dma->tx_chan);
return 0;
}
static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport)
{
struct uart_port *port = &ourport->port;
struct circ_buf *xmit = &port->state->xmit;
unsigned long count;
/* Get data size up to the end of buffer */
count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
if (!count) {
s3c24xx_serial_stop_tx(port);
return;
}
if (!ourport->dma || !ourport->dma->tx_chan || count < port->fifosize)
s3c24xx_serial_start_tx_pio(ourport);
else
s3c24xx_serial_start_tx_dma(ourport, count);
}
void s3c24xx_serial_start_tx(struct uart_port *port)
{
struct s3c24xx_uart_port *ourport = to_ourport(port);
struct circ_buf *xmit = &port->state->xmit;
if (!tx_enabled(port)) {
if (port->flags & UPF_CONS_FLOW)
s3c24xx_serial_rx_disable(port);
if (s3c24xx_serial_has_interrupt_mask(port))
__clear_bit(S3C64XX_UINTM_TXD,
portaddrl(port, S3C64XX_UINTM));
else
enable_irq(ourport->tx_irq);
tx_enabled(port) = 1;
if (!ourport->dma || !ourport->dma->tx_chan)
s3c24xx_serial_start_tx_pio(ourport);
}
if (ourport->dma && ourport->dma->tx_chan) {
if (!uart_circ_empty(xmit) && !ourport->tx_in_progress)
s3c24xx_serial_start_next_tx(ourport);
}
}
static void s3c24xx_uart_copy_rx_to_tty(struct s3c24xx_uart_port *ourport,
struct tty_port *tty, int count)
{
struct s3c24xx_uart_dma *dma = ourport->dma;
int copied;
if (!count)
return;
dma_sync_single_for_cpu(ourport->port.dev, dma->rx_addr,
dma->rx_size, DMA_FROM_DEVICE);
ourport->port.icount.rx += count;
if (!tty) {
dev_err(ourport->port.dev, "No tty port\n");
return;
}
copied = tty_insert_flip_string(tty,
((unsigned char *)(ourport->dma->rx_buf)), count);
if (copied != count) {
WARN_ON(1);
dev_err(ourport->port.dev, "RxData copy to tty layer failed\n");
}
}
static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport,
unsigned long ufstat);
static void uart_rx_drain_fifo(struct s3c24xx_uart_port *ourport)
{
struct uart_port *port = &ourport->port;
struct tty_port *tty = &port->state->port;
unsigned int ch, ufstat;
unsigned int count;
ufstat = rd_regl(port, S3C2410_UFSTAT);
count = s3c24xx_serial_rx_fifocnt(ourport, ufstat);
if (!count)
return;
while (count-- > 0) {
ch = rd_regb(port, S3C2410_URXH);
ourport->port.icount.rx++;
tty_insert_flip_char(tty, ch, TTY_NORMAL);
}
tty_flip_buffer_push(tty);
}
static void s3c24xx_serial_stop_rx(struct uart_port *port)
{
struct s3c24xx_uart_port *ourport = to_ourport(port);
struct s3c24xx_uart_dma *dma = ourport->dma;
struct tty_port *t = &port->state->port;
struct dma_tx_state state;
enum dma_status dma_status;
unsigned int received;
if (rx_enabled(port)) {
dbg("s3c24xx_serial_stop_rx: port=%p\n", port);
@ -197,6 +437,17 @@ static void s3c24xx_serial_stop_rx(struct uart_port *port)
disable_irq_nosync(ourport->rx_irq);
rx_enabled(port) = 0;
}
if (dma && dma->rx_chan) {
dmaengine_pause(dma->tx_chan);
dma_status = dmaengine_tx_status(dma->rx_chan,
dma->rx_cookie, &state);
if (dma_status == DMA_IN_PROGRESS ||
dma_status == DMA_PAUSED) {
received = dma->rx_bytes_requested - state.residue;
dmaengine_terminate_all(dma->rx_chan);
s3c24xx_uart_copy_rx_to_tty(ourport, t, received);
}
}
}
static inline struct s3c24xx_uart_info
@ -228,12 +479,157 @@ static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport,
return (ufstat & info->rx_fifomask) >> info->rx_fifoshift;
}
static void s3c64xx_start_rx_dma(struct s3c24xx_uart_port *ourport);
static void s3c24xx_serial_rx_dma_complete(void *args)
{
struct s3c24xx_uart_port *ourport = args;
struct uart_port *port = &ourport->port;
struct s3c24xx_uart_dma *dma = ourport->dma;
struct tty_port *t = &port->state->port;
struct tty_struct *tty = tty_port_tty_get(&ourport->port.state->port);
struct dma_tx_state state;
unsigned long flags;
int received;
dmaengine_tx_status(dma->rx_chan, dma->rx_cookie, &state);
received = dma->rx_bytes_requested - state.residue;
async_tx_ack(dma->rx_desc);
spin_lock_irqsave(&port->lock, flags);
if (received)
s3c24xx_uart_copy_rx_to_tty(ourport, t, received);
if (tty) {
tty_flip_buffer_push(t);
tty_kref_put(tty);
}
s3c64xx_start_rx_dma(ourport);
spin_unlock_irqrestore(&port->lock, flags);
}
static void s3c64xx_start_rx_dma(struct s3c24xx_uart_port *ourport)
{
struct s3c24xx_uart_dma *dma = ourport->dma;
dma_sync_single_for_device(ourport->port.dev, dma->rx_addr,
dma->rx_size, DMA_FROM_DEVICE);
dma->rx_desc = dmaengine_prep_slave_single(dma->rx_chan,
dma->rx_addr, dma->rx_size, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT);
if (!dma->rx_desc) {
dev_err(ourport->port.dev, "Unable to get desc for Rx\n");
return;
}
dma->rx_desc->callback = s3c24xx_serial_rx_dma_complete;
dma->rx_desc->callback_param = ourport;
dma->rx_bytes_requested = dma->rx_size;
dma->rx_cookie = dmaengine_submit(dma->rx_desc);
dma_async_issue_pending(dma->rx_chan);
}
/* ? - where has parity gone?? */
#define S3C2410_UERSTAT_PARITY (0x1000)
static irqreturn_t
s3c24xx_serial_rx_chars(int irq, void *dev_id)
static void enable_rx_dma(struct s3c24xx_uart_port *ourport)
{
struct uart_port *port = &ourport->port;
unsigned int ucon;
/* set Rx mode to DMA mode */
ucon = rd_regl(port, S3C2410_UCON);
ucon &= ~(S3C64XX_UCON_RXBURST_MASK |
S3C64XX_UCON_TIMEOUT_MASK |
S3C64XX_UCON_EMPTYINT_EN |
S3C64XX_UCON_DMASUS_EN |
S3C64XX_UCON_TIMEOUT_EN |
S3C64XX_UCON_RXMODE_MASK);
ucon |= S3C64XX_UCON_RXBURST_16 |
0xf << S3C64XX_UCON_TIMEOUT_SHIFT |
S3C64XX_UCON_EMPTYINT_EN |
S3C64XX_UCON_TIMEOUT_EN |
S3C64XX_UCON_RXMODE_DMA;
wr_regl(port, S3C2410_UCON, ucon);
ourport->rx_mode = S3C24XX_RX_DMA;
}
static void enable_rx_pio(struct s3c24xx_uart_port *ourport)
{
struct uart_port *port = &ourport->port;
unsigned int ucon;
/* set Rx mode to DMA mode */
ucon = rd_regl(port, S3C2410_UCON);
ucon &= ~(S3C64XX_UCON_TIMEOUT_MASK |
S3C64XX_UCON_EMPTYINT_EN |
S3C64XX_UCON_DMASUS_EN |
S3C64XX_UCON_TIMEOUT_EN |
S3C64XX_UCON_RXMODE_MASK);
ucon |= 0xf << S3C64XX_UCON_TIMEOUT_SHIFT |
S3C64XX_UCON_TIMEOUT_EN |
S3C64XX_UCON_RXMODE_CPU;
wr_regl(port, S3C2410_UCON, ucon);
ourport->rx_mode = S3C24XX_RX_PIO;
}
static irqreturn_t s3c24xx_serial_rx_chars_dma(int irq, void *dev_id)
{
unsigned int utrstat, ufstat, received;
struct s3c24xx_uart_port *ourport = dev_id;
struct uart_port *port = &ourport->port;
struct s3c24xx_uart_dma *dma = ourport->dma;
struct tty_struct *tty = tty_port_tty_get(&ourport->port.state->port);
struct tty_port *t = &port->state->port;
unsigned long flags;
struct dma_tx_state state;
utrstat = rd_regl(port, S3C2410_UTRSTAT);
ufstat = rd_regl(port, S3C2410_UFSTAT);
spin_lock_irqsave(&port->lock, flags);
if (!(utrstat & S3C2410_UTRSTAT_TIMEOUT)) {
s3c64xx_start_rx_dma(ourport);
if (ourport->rx_mode == S3C24XX_RX_PIO)
enable_rx_dma(ourport);
goto finish;
}
if (ourport->rx_mode == S3C24XX_RX_DMA) {
dmaengine_pause(dma->rx_chan);
dmaengine_tx_status(dma->rx_chan, dma->rx_cookie, &state);
dmaengine_terminate_all(dma->rx_chan);
received = dma->rx_bytes_requested - state.residue;
s3c24xx_uart_copy_rx_to_tty(ourport, t, received);
enable_rx_pio(ourport);
}
uart_rx_drain_fifo(ourport);
if (tty) {
tty_flip_buffer_push(t);
tty_kref_put(tty);
}
wr_regl(port, S3C2410_UTRSTAT, S3C2410_UTRSTAT_TIMEOUT);
finish:
spin_unlock_irqrestore(&port->lock, flags);
return IRQ_HANDLED;
}
static irqreturn_t s3c24xx_serial_rx_chars_pio(int irq, void *dev_id)
{
struct s3c24xx_uart_port *ourport = dev_id;
struct uart_port *port = &ourport->port;
@ -324,16 +720,33 @@ out:
return IRQ_HANDLED;
}
static irqreturn_t s3c24xx_serial_rx_chars(int irq, void *dev_id)
{
struct s3c24xx_uart_port *ourport = dev_id;
if (ourport->dma && ourport->dma->rx_chan)
return s3c24xx_serial_rx_chars_dma(irq, dev_id);
return s3c24xx_serial_rx_chars_pio(irq, dev_id);
}
static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
{
struct s3c24xx_uart_port *ourport = id;
struct uart_port *port = &ourport->port;
struct circ_buf *xmit = &port->state->xmit;
unsigned long flags;
int count = port->fifosize;
int count;
spin_lock_irqsave(&port->lock, flags);
count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
if (ourport->dma && ourport->dma->tx_chan && count >= port->fifosize) {
s3c24xx_serial_start_tx_dma(ourport, count);
goto out;
}
if (port->x_char) {
wr_regb(port, S3C2410_UTXH, port->x_char);
port->icount.tx++;
@ -352,6 +765,7 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
/* try and drain the buffer... */
count = port->fifosize;
while (!uart_circ_empty(xmit) && count-- > 0) {
if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)
break;
@ -453,6 +867,93 @@ static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state)
spin_unlock_irqrestore(&port->lock, flags);
}
static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
{
struct s3c24xx_uart_dma *dma = p->dma;
dma_cap_mask_t mask;
unsigned long flags;
/* Default slave configuration parameters */
dma->rx_conf.direction = DMA_DEV_TO_MEM;
dma->rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
dma->rx_conf.src_addr = p->port.mapbase + S3C2410_URXH;
dma->rx_conf.src_maxburst = 16;
dma->tx_conf.direction = DMA_MEM_TO_DEV;
dma->tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
dma->tx_conf.dst_addr = p->port.mapbase + S3C2410_UTXH;
if (dma_get_cache_alignment() >= 16)
dma->tx_conf.dst_maxburst = 16;
else
dma->tx_conf.dst_maxburst = 1;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
dma->rx_chan = dma_request_slave_channel_compat(mask, dma->fn,
dma->rx_param, p->port.dev, "rx");
if (!dma->rx_chan)
return -ENODEV;
dmaengine_slave_config(dma->rx_chan, &dma->rx_conf);
dma->tx_chan = dma_request_slave_channel_compat(mask, dma->fn,
dma->tx_param, p->port.dev, "tx");
if (!dma->tx_chan) {
dma_release_channel(dma->rx_chan);
return -ENODEV;
}
dmaengine_slave_config(dma->tx_chan, &dma->tx_conf);
/* RX buffer */
dma->rx_size = PAGE_SIZE;
dma->rx_buf = kmalloc(dma->rx_size, GFP_KERNEL);
if (!dma->rx_buf) {
dma_release_channel(dma->rx_chan);
dma_release_channel(dma->tx_chan);
return -ENOMEM;
}
dma->rx_addr = dma_map_single(dma->rx_chan->device->dev, dma->rx_buf,
dma->rx_size, DMA_FROM_DEVICE);
spin_lock_irqsave(&p->port.lock, flags);
/* TX buffer */
dma->tx_addr = dma_map_single(dma->tx_chan->device->dev,
p->port.state->xmit.buf,
UART_XMIT_SIZE, DMA_TO_DEVICE);
spin_unlock_irqrestore(&p->port.lock, flags);
return 0;
}
static void s3c24xx_serial_release_dma(struct s3c24xx_uart_port *p)
{
struct s3c24xx_uart_dma *dma = p->dma;
if (dma->rx_chan) {
dmaengine_terminate_all(dma->rx_chan);
dma_unmap_single(dma->rx_chan->device->dev, dma->rx_addr,
dma->rx_size, DMA_FROM_DEVICE);
kfree(dma->rx_buf);
dma_release_channel(dma->rx_chan);
dma->rx_chan = NULL;
}
if (dma->tx_chan) {
dmaengine_terminate_all(dma->tx_chan);
dma_unmap_single(dma->tx_chan->device->dev, dma->tx_addr,
UART_XMIT_SIZE, DMA_TO_DEVICE);
dma_release_channel(dma->tx_chan);
dma->tx_chan = NULL;
}
}
static void s3c24xx_serial_shutdown(struct uart_port *port)
{
struct s3c24xx_uart_port *ourport = to_ourport(port);
@ -478,6 +979,11 @@ static void s3c24xx_serial_shutdown(struct uart_port *port)
wr_regl(port, S3C64XX_UINTP, 0xf);
wr_regl(port, S3C64XX_UINTM, 0xf);
}
if (ourport->dma)
s3c24xx_serial_release_dma(ourport);
ourport->tx_in_progress = 0;
}
static int s3c24xx_serial_startup(struct uart_port *port)
@ -529,12 +1035,21 @@ err:
static int s3c64xx_serial_startup(struct uart_port *port)
{
struct s3c24xx_uart_port *ourport = to_ourport(port);
unsigned long flags;
unsigned int ufcon;
int ret;
dbg("s3c64xx_serial_startup: port=%p (%08llx,%p)\n",
port, (unsigned long long)port->mapbase, port->membase);
wr_regl(port, S3C64XX_UINTM, 0xf);
if (ourport->dma) {
ret = s3c24xx_serial_request_dma(ourport);
if (ret < 0) {
dev_warn(port->dev, "DMA request failed\n");
return ret;
}
}
ret = request_irq(port->irq, s3c64xx_serial_handle_irq, IRQF_SHARED,
s3c24xx_serial_portname(port), ourport);
@ -549,8 +1064,20 @@ static int s3c64xx_serial_startup(struct uart_port *port)
tx_enabled(port) = 0;
ourport->tx_claimed = 1;
spin_lock_irqsave(&port->lock, flags);
ufcon = rd_regl(port, S3C2410_UFCON);
ufcon |= S3C2410_UFCON_RESETRX | S3C2410_UFCON_RESETTX |
S5PV210_UFCON_RXTRIG8;
wr_regl(port, S3C2410_UFCON, ufcon);
enable_rx_pio(ourport);
spin_unlock_irqrestore(&port->lock, flags);
/* Enable Rx Interrupt */
__clear_bit(S3C64XX_UINTM_RXD, portaddrl(port, S3C64XX_UINTM));
dbg("s3c64xx_serial_startup ok\n");
return ret;
}
@ -1209,6 +1736,18 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
ret = platform_get_irq(platdev, 1);
if (ret > 0)
ourport->tx_irq = ret;
/*
* DMA is currently supported only on DT platforms, if DMA properties
* are specified.
*/
if (platdev->dev.of_node && of_find_property(platdev->dev.of_node,
"dmas", NULL)) {
ourport->dma = devm_kzalloc(port->dev,
sizeof(*ourport->dma),
GFP_KERNEL);
if (!ourport->dma)
return -ENOMEM;
}
ourport->clk = clk_get(&platdev->dev, "uart");
if (IS_ERR(ourport->clk)) {
@ -1857,6 +2396,111 @@ static struct platform_driver samsung_serial_driver = {
module_platform_driver(samsung_serial_driver);
#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
/*
* Early console.
*/
struct samsung_early_console_data {
u32 txfull_mask;
};
static void samsung_early_busyuart(struct uart_port *port)
{
while (!(readl(port->membase + S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXFE))
;
}
static void samsung_early_busyuart_fifo(struct uart_port *port)
{
struct samsung_early_console_data *data = port->private_data;
while (readl(port->membase + S3C2410_UFSTAT) & data->txfull_mask)
;
}
static void samsung_early_putc(struct uart_port *port, int c)
{
if (readl(port->membase + S3C2410_UFCON) & S3C2410_UFCON_FIFOMODE)
samsung_early_busyuart_fifo(port);
else
samsung_early_busyuart(port);
writeb(c, port->membase + S3C2410_UTXH);
}
static void samsung_early_write(struct console *con, const char *s, unsigned n)
{
struct earlycon_device *dev = con->data;
uart_console_write(&dev->port, s, n, samsung_early_putc);
}
static int __init samsung_early_console_setup(struct earlycon_device *device,
const char *opt)
{
if (!device->port.membase)
return -ENODEV;
device->con->write = samsung_early_write;
return 0;
}
/* S3C2410 */
static struct samsung_early_console_data s3c2410_early_console_data = {
.txfull_mask = S3C2410_UFSTAT_TXFULL,
};
static int __init s3c2410_early_console_setup(struct earlycon_device *device,
const char *opt)
{
device->port.private_data = &s3c2410_early_console_data;
return samsung_early_console_setup(device, opt);
}
OF_EARLYCON_DECLARE(s3c2410, "samsung,s3c2410-uart",
s3c2410_early_console_setup);
EARLYCON_DECLARE(s3c2410, s3c2410_early_console_setup);
/* S3C2412, S3C2440, S3C64xx */
static struct samsung_early_console_data s3c2440_early_console_data = {
.txfull_mask = S3C2440_UFSTAT_TXFULL,
};
static int __init s3c2440_early_console_setup(struct earlycon_device *device,
const char *opt)
{
device->port.private_data = &s3c2440_early_console_data;
return samsung_early_console_setup(device, opt);
}
OF_EARLYCON_DECLARE(s3c2412, "samsung,s3c2412-uart",
s3c2440_early_console_setup);
OF_EARLYCON_DECLARE(s3c2440, "samsung,s3c2440-uart",
s3c2440_early_console_setup);
OF_EARLYCON_DECLARE(s3c6400, "samsung,s3c6400-uart",
s3c2440_early_console_setup);
EARLYCON_DECLARE(s3c2412, s3c2440_early_console_setup);
EARLYCON_DECLARE(s3c2440, s3c2440_early_console_setup);
EARLYCON_DECLARE(s3c6400, s3c2440_early_console_setup);
/* S5PV210, EXYNOS */
static struct samsung_early_console_data s5pv210_early_console_data = {
.txfull_mask = S5PV210_UFSTAT_TXFULL,
};
static int __init s5pv210_early_console_setup(struct earlycon_device *device,
const char *opt)
{
device->port.private_data = &s5pv210_early_console_data;
return samsung_early_console_setup(device, opt);
}
OF_EARLYCON_DECLARE(s5pv210, "samsung,s5pv210-uart",
s5pv210_early_console_setup);
OF_EARLYCON_DECLARE(exynos4210, "samsung,exynos4210-uart",
s5pv210_early_console_setup);
EARLYCON_DECLARE(s5pv210, s5pv210_early_console_setup);
EARLYCON_DECLARE(exynos4210, s5pv210_early_console_setup);
#endif
MODULE_ALIAS("platform:samsung-uart");
MODULE_DESCRIPTION("Samsung SoC Serial port driver");
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");

View File

@ -12,6 +12,8 @@
* published by the Free Software Foundation.
*/
#include <linux/dmaengine.h>
struct s3c24xx_uart_info {
char *name;
unsigned int type;
@ -41,6 +43,40 @@ struct s3c24xx_serial_drv_data {
unsigned int fifosize[CONFIG_SERIAL_SAMSUNG_UARTS];
};
struct s3c24xx_uart_dma {
dma_filter_fn fn;
void *rx_param;
void *tx_param;
unsigned int rx_chan_id;
unsigned int tx_chan_id;
struct dma_slave_config rx_conf;
struct dma_slave_config tx_conf;
struct dma_chan *rx_chan;
struct dma_chan *tx_chan;
dma_addr_t rx_addr;
dma_addr_t tx_addr;
dma_cookie_t rx_cookie;
dma_cookie_t tx_cookie;
char *rx_buf;
dma_addr_t tx_transfer_addr;
size_t rx_size;
size_t tx_size;
struct dma_async_tx_descriptor *tx_desc;
struct dma_async_tx_descriptor *rx_desc;
int tx_bytes_requested;
int rx_bytes_requested;
};
struct s3c24xx_uart_port {
unsigned char rx_claimed;
unsigned char tx_claimed;
@ -50,6 +86,10 @@ struct s3c24xx_uart_port {
unsigned int rx_irq;
unsigned int tx_irq;
unsigned int tx_in_progress;
unsigned int tx_mode;
unsigned int rx_mode;
struct s3c24xx_uart_info *info;
struct clk *clk;
struct clk *baudclk;
@ -59,6 +99,8 @@ struct s3c24xx_uart_port {
/* reference to platform data */
struct s3c2410_uartcfg *cfg;
struct s3c24xx_uart_dma *dma;
#ifdef CONFIG_CPU_FREQ
struct notifier_block freq_transition;
#endif

View File

@ -179,14 +179,6 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
if (tty->termios.c_cflag & CBAUD)
uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR);
}
spin_lock_irq(&uport->lock);
if (uart_cts_enabled(uport) &&
!(uport->ops->get_mctrl(uport) & TIOCM_CTS))
uport->hw_stopped = 1;
else
uport->hw_stopped = 0;
spin_unlock_irq(&uport->lock);
}
/*
@ -442,6 +434,7 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
{
struct uart_port *uport = state->uart_port;
struct ktermios *termios;
int hw_stopped;
/*
* If we have no tty, termios, or the port does not exist,
@ -466,6 +459,18 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
uport->status &= ~UPSTAT_DCD_ENABLE;
else
uport->status |= UPSTAT_DCD_ENABLE;
/* reset sw-assisted CTS flow control based on (possibly) new mode */
hw_stopped = uport->hw_stopped;
uport->hw_stopped = uart_softcts_mode(uport) &&
!(uport->ops->get_mctrl(uport) & TIOCM_CTS);
if (uport->hw_stopped) {
if (!hw_stopped)
uport->ops->stop_tx(uport);
} else {
if (hw_stopped)
__uart_start(tty);
}
spin_unlock_irq(&uport->lock);
}
@ -619,22 +624,22 @@ static void uart_throttle(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
struct uart_port *port = state->uart_port;
upf_t mask = 0;
upstat_t mask = 0;
if (I_IXOFF(tty))
mask |= UPF_SOFT_FLOW;
mask |= UPSTAT_AUTOXOFF;
if (tty->termios.c_cflag & CRTSCTS)
mask |= UPF_HARD_FLOW;
mask |= UPSTAT_AUTORTS;
if (port->flags & mask) {
if (port->status & mask) {
port->ops->throttle(port);
mask &= ~port->flags;
mask &= ~port->status;
}
if (mask & UPF_SOFT_FLOW)
if (mask & UPSTAT_AUTOXOFF)
uart_send_xchar(tty, STOP_CHAR(tty));
if (mask & UPF_HARD_FLOW)
if (mask & UPSTAT_AUTORTS)
uart_clear_mctrl(port, TIOCM_RTS);
}
@ -642,22 +647,22 @@ static void uart_unthrottle(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
struct uart_port *port = state->uart_port;
upf_t mask = 0;
upstat_t mask = 0;
if (I_IXOFF(tty))
mask |= UPF_SOFT_FLOW;
mask |= UPSTAT_AUTOXOFF;
if (tty->termios.c_cflag & CRTSCTS)
mask |= UPF_HARD_FLOW;
mask |= UPSTAT_AUTORTS;
if (port->flags & mask) {
if (port->status & mask) {
port->ops->unthrottle(port);
mask &= ~port->flags;
mask &= ~port->status;
}
if (mask & UPF_SOFT_FLOW)
if (mask & UPSTAT_AUTOXOFF)
uart_send_xchar(tty, START_CHAR(tty));
if (mask & UPF_HARD_FLOW)
if (mask & UPSTAT_AUTORTS)
uart_set_mctrl(port, TIOCM_RTS);
}
@ -1351,30 +1356,6 @@ static void uart_set_termios(struct tty_struct *tty,
mask |= TIOCM_RTS;
uart_set_mctrl(uport, mask);
}
/*
* If the port is doing h/w assisted flow control, do nothing.
* We assume that port->hw_stopped has never been set.
*/
if (uport->flags & UPF_HARD_FLOW)
return;
/* Handle turning off CRTSCTS */
if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) {
spin_lock_irq(&uport->lock);
uport->hw_stopped = 0;
__uart_start(tty);
spin_unlock_irq(&uport->lock);
}
/* Handle turning on CRTSCTS */
else if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) {
spin_lock_irq(&uport->lock);
if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS)) {
uport->hw_stopped = 1;
uport->ops->stop_tx(uport);
}
spin_unlock_irq(&uport->lock);
}
}
/*
@ -2008,23 +1989,24 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
}
put_device(tty_dev);
if (console_suspend_enabled || !uart_console(uport))
uport->suspended = 1;
/* Nothing to do if the console is not suspending */
if (!console_suspend_enabled && uart_console(uport))
goto unlock;
uport->suspended = 1;
if (port->flags & ASYNC_INITIALIZED) {
const struct uart_ops *ops = uport->ops;
int tries;
if (console_suspend_enabled || !uart_console(uport)) {
set_bit(ASYNCB_SUSPENDED, &port->flags);
clear_bit(ASYNCB_INITIALIZED, &port->flags);
set_bit(ASYNCB_SUSPENDED, &port->flags);
clear_bit(ASYNCB_INITIALIZED, &port->flags);
spin_lock_irq(&uport->lock);
ops->stop_tx(uport);
ops->set_mctrl(uport, 0);
ops->stop_rx(uport);
spin_unlock_irq(&uport->lock);
}
spin_lock_irq(&uport->lock);
ops->stop_tx(uport);
ops->set_mctrl(uport, 0);
ops->stop_rx(uport);
spin_unlock_irq(&uport->lock);
/*
* Wait for the transmitter to empty.
@ -2036,19 +2018,17 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
drv->dev_name,
drv->tty_driver->name_base + uport->line);
if (console_suspend_enabled || !uart_console(uport))
ops->shutdown(uport);
ops->shutdown(uport);
}
/*
* Disable the console device before suspending.
*/
if (console_suspend_enabled && uart_console(uport))
if (uart_console(uport))
console_stop(uport->cons);
if (console_suspend_enabled || !uart_console(uport))
uart_change_pm(state, UART_PM_STATE_OFF);
uart_change_pm(state, UART_PM_STATE_OFF);
unlock:
mutex_unlock(&port->mutex);
return 0;
@ -2856,7 +2836,7 @@ void uart_handle_cts_change(struct uart_port *uport, unsigned int status)
uport->icount.cts++;
if (uart_cts_enabled(uport)) {
if (uart_softcts_mode(uport)) {
if (uport->hw_stopped) {
if (status) {
uport->hw_stopped = 0;
@ -2869,6 +2849,7 @@ void uart_handle_cts_change(struct uart_port *uport, unsigned int status)
uport->ops->stop_tx(uport);
}
}
}
}
EXPORT_SYMBOL_GPL(uart_handle_cts_change);

View File

@ -858,7 +858,7 @@ static int sci_handle_fifo_overrun(struct uart_port *port)
tty_insert_flip_char(tport, 0, TTY_OVERRUN);
tty_flip_buffer_push(tport);
dev_notice(port->dev, "overrun error\n");
dev_dbg(port->dev, "overrun error\n");
copied++;
}
@ -997,12 +997,15 @@ 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;
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);
err_enabled = scr_status & port_rx_irq_mask(port);
/* Tx Interrupt */
@ -1015,8 +1018,11 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
* DR flags
*/
if (((ssr_status & SCxSR_RDxF(port)) || s->chan_rx) &&
(scr_status & SCSCR_RIE))
(scr_status & SCSCR_RIE)) {
if (port->type == PORT_SCIF || port->type == PORT_HSCIF)
sci_handle_fifo_overrun(port);
ret = sci_rx_interrupt(irq, ptr);
}
/* Error Interrupt */
if ((ssr_status & SCxSR_ERRORS(port)) && err_enabled)
@ -1026,6 +1032,12 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
if ((ssr_status & SCxSR_BRK(port)) && err_enabled)
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);
}
return ret;
}
@ -2605,7 +2617,7 @@ static int sci_probe(struct platform_device *dev)
return 0;
}
static int sci_suspend(struct device *dev)
static __maybe_unused int sci_suspend(struct device *dev)
{
struct sci_port *sport = dev_get_drvdata(dev);
@ -2615,7 +2627,7 @@ static int sci_suspend(struct device *dev)
return 0;
}
static int sci_resume(struct device *dev)
static __maybe_unused int sci_resume(struct device *dev)
{
struct sci_port *sport = dev_get_drvdata(dev);
@ -2625,10 +2637,7 @@ static int sci_resume(struct device *dev)
return 0;
}
static const struct dev_pm_ops sci_dev_pm_ops = {
.suspend = sci_suspend,
.resume = sci_resume,
};
static SIMPLE_DEV_PM_OPS(sci_dev_pm_ops, sci_suspend, sci_resume);
static struct platform_driver sci_driver = {
.probe = sci_probe,

View File

@ -177,7 +177,7 @@ static void sirfsoc_uart_stop_tx(struct uart_port *port)
dmaengine_pause(sirfport->tx_dma_chan);
sirfport->tx_dma_state = TX_DMA_PAUSE;
} else {
if (!sirfport->is_marco)
if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg) &
~uint_en->sirfsoc_txfifo_empty_en);
@ -186,7 +186,7 @@ static void sirfsoc_uart_stop_tx(struct uart_port *port)
uint_en->sirfsoc_txfifo_empty_en);
}
} else {
if (!sirfport->is_marco)
if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg) &
~uint_en->sirfsoc_txfifo_empty_en);
@ -217,7 +217,7 @@ static void sirfsoc_uart_tx_with_dma(struct sirfsoc_uart_port *sirfport)
}
if (sirfport->tx_dma_state == TX_DMA_RUNNING)
return;
if (!sirfport->is_marco)
if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg)&
~(uint_en->sirfsoc_txfifo_empty_en));
@ -244,7 +244,7 @@ static void sirfsoc_uart_tx_with_dma(struct sirfsoc_uart_port *sirfport)
}
if (tran_size < 4)
sirfsoc_uart_pio_tx_chars(sirfport, tran_size);
if (!sirfport->is_marco)
if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg)|
uint_en->sirfsoc_txfifo_empty_en);
@ -293,7 +293,7 @@ static void sirfsoc_uart_start_tx(struct uart_port *port)
sirfsoc_uart_pio_tx_chars(sirfport,
SIRFSOC_UART_IO_TX_REASONABLE_CNT);
wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_START);
if (!sirfport->is_marco)
if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg)|
uint_en->sirfsoc_txfifo_empty_en);
@ -311,7 +311,7 @@ static void sirfsoc_uart_stop_rx(struct uart_port *port)
wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
if (sirfport->rx_dma_chan) {
if (!sirfport->is_marco)
if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg) &
~(SIRFUART_RX_DMA_INT_EN(port, uint_en) |
@ -322,7 +322,7 @@ static void sirfsoc_uart_stop_rx(struct uart_port *port)
uint_en->sirfsoc_rx_done_en);
dmaengine_terminate_all(sirfport->rx_dma_chan);
} else {
if (!sirfport->is_marco)
if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg)&
~(SIRFUART_RX_IO_INT_EN(port, uint_en)));
@ -344,7 +344,7 @@ static void sirfsoc_uart_disable_ms(struct uart_port *port)
if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
wr_regl(port, ureg->sirfsoc_afc_ctrl,
rd_regl(port, ureg->sirfsoc_afc_ctrl) & ~0x3FF);
if (!sirfport->is_marco)
if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg)&
~uint_en->sirfsoc_cts_en);
@ -380,7 +380,7 @@ static void sirfsoc_uart_enable_ms(struct uart_port *port)
wr_regl(port, ureg->sirfsoc_afc_ctrl,
rd_regl(port, ureg->sirfsoc_afc_ctrl) |
SIRFUART_AFC_TX_EN | SIRFUART_AFC_RX_EN);
if (!sirfport->is_marco)
if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg)
| uint_en->sirfsoc_cts_en);
@ -544,7 +544,7 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)
sirfport->rx_io_count = 0;
wr_regl(port, ureg->sirfsoc_int_st_reg,
uint_st->sirfsoc_rx_done);
if (!sirfport->is_marco)
if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg) &
~(uint_en->sirfsoc_rx_done_en));
@ -555,7 +555,7 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)
} else {
wr_regl(port, ureg->sirfsoc_int_st_reg,
uint_st->sirfsoc_rx_done);
if (!sirfport->is_marco)
if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg) |
(uint_en->sirfsoc_rx_done_en));
@ -578,7 +578,7 @@ static void sirfsoc_uart_handle_rx_tmo(struct sirfsoc_uart_port *sirfport)
dmaengine_terminate_all(sirfport->rx_dma_chan);
sirfport->rx_dma_items[sirfport->rx_issued].xmit.head =
SIRFSOC_RX_DMA_BUF_SIZE - tx_state.residue;
if (!sirfport->is_marco)
if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg) &
~(uint_en->sirfsoc_rx_timeout_en));
@ -598,7 +598,7 @@ static void sirfsoc_uart_handle_rx_done(struct sirfsoc_uart_port *sirfport)
sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count);
if (sirfport->rx_io_count == 4) {
sirfport->rx_io_count = 0;
if (!sirfport->is_marco)
if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg) &
~(uint_en->sirfsoc_rx_done_en));
@ -748,7 +748,7 @@ static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port)
for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++)
sirfsoc_rx_submit_one_dma_desc(port, i);
sirfport->rx_completed = sirfport->rx_issued = 0;
if (!sirfport->is_marco)
if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg) |
SIRFUART_RX_DMA_INT_EN(port, uint_en));
@ -770,7 +770,7 @@ static void sirfsoc_uart_start_rx(struct uart_port *port)
if (sirfport->rx_dma_chan)
sirfsoc_uart_start_next_rx_dma(port);
else {
if (!sirfport->is_marco)
if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg) |
SIRFUART_RX_IO_INT_EN(port, uint_en));
@ -1124,7 +1124,7 @@ static void sirfsoc_uart_shutdown(struct uart_port *port)
{
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
if (!sirfport->is_marco)
if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg, 0);
else
wr_regl(port, SIRFUART_INT_EN_CLR, ~0UL);
@ -1271,7 +1271,7 @@ static struct uart_driver sirfsoc_uart_drv = {
static struct of_device_id sirfsoc_uart_ids[] = {
{ .compatible = "sirf,prima2-uart", .data = &sirfsoc_uart,},
{ .compatible = "sirf,marco-uart", .data = &sirfsoc_uart},
{ .compatible = "sirf,atlas7-uart", .data = &sirfsoc_uart},
{ .compatible = "sirf,prima2-usp-uart", .data = &sirfsoc_usp},
{}
};
@ -1350,8 +1350,8 @@ static int sirfsoc_uart_probe(struct platform_device *pdev)
gpio_direction_output(sirfport->rts_gpio, 1);
}
usp_no_flow_control:
if (of_device_is_compatible(pdev->dev.of_node, "sirf,marco-uart"))
sirfport->is_marco = true;
if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-uart"))
sirfport->is_atlas7 = true;
if (of_property_read_u32(pdev->dev.of_node,
"fifosize",
@ -1393,7 +1393,7 @@ usp_no_flow_control:
goto err;
}
port->uartclk = clk_get_rate(sirfport->clk);
if (of_device_is_compatible(pdev->dev.of_node, "sirf,marco-bt-uart")) {
if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-bt-uart")) {
sirfport->clk_general = devm_clk_get(&pdev->dev, "general");
if (IS_ERR(sirfport->clk_general)) {
ret = PTR_ERR(sirfport->clk_general);

View File

@ -421,8 +421,8 @@ struct sirfsoc_uart_port {
bool is_bt_uart;
struct clk *clk_general;
struct clk *clk_noc;
/* for SiRFmarco, there are SET/CLR for UART_INT_EN */
bool is_marco;
/* for SiRFatlas7, there are SET/CLR for UART_INT_EN */
bool is_atlas7;
struct sirfsoc_uart_register *uart_reg;
struct dma_chan *rx_dma_chan;
struct dma_chan *tx_dma_chan;

View File

@ -0,0 +1,793 @@
/*
* Copyright (C) 2012-2015 Spreadtrum Communications Inc.
*
* 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.
*/
#if defined(CONFIG_SERIAL_SPRD_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
#include <linux/clk.h>
#include <linux/console.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
/* device name */
#define UART_NR_MAX 8
#define SPRD_TTY_NAME "ttyS"
#define SPRD_FIFO_SIZE 128
#define SPRD_DEF_RATE 26000000
#define SPRD_BAUD_IO_LIMIT 3000000
#define SPRD_TIMEOUT 256
/* the offset of serial registers and BITs for them */
/* data registers */
#define SPRD_TXD 0x0000
#define SPRD_RXD 0x0004
/* line status register and its BITs */
#define SPRD_LSR 0x0008
#define SPRD_LSR_OE BIT(4)
#define SPRD_LSR_FE BIT(3)
#define SPRD_LSR_PE BIT(2)
#define SPRD_LSR_BI BIT(7)
#define SPRD_LSR_TX_OVER BIT(15)
/* data number in TX and RX fifo */
#define SPRD_STS1 0x000C
/* interrupt enable register and its BITs */
#define SPRD_IEN 0x0010
#define SPRD_IEN_RX_FULL BIT(0)
#define SPRD_IEN_TX_EMPTY BIT(1)
#define SPRD_IEN_BREAK_DETECT BIT(7)
#define SPRD_IEN_TIMEOUT BIT(13)
/* interrupt clear register */
#define SPRD_ICLR 0x0014
/* line control register */
#define SPRD_LCR 0x0018
#define SPRD_LCR_STOP_1BIT 0x10
#define SPRD_LCR_STOP_2BIT 0x30
#define SPRD_LCR_DATA_LEN (BIT(2) | BIT(3))
#define SPRD_LCR_DATA_LEN5 0x0
#define SPRD_LCR_DATA_LEN6 0x4
#define SPRD_LCR_DATA_LEN7 0x8
#define SPRD_LCR_DATA_LEN8 0xc
#define SPRD_LCR_PARITY (BIT(0) | BIT(1))
#define SPRD_LCR_PARITY_EN 0x2
#define SPRD_LCR_EVEN_PAR 0x0
#define SPRD_LCR_ODD_PAR 0x1
/* control register 1 */
#define SPRD_CTL1 0x001C
#define RX_HW_FLOW_CTL_THLD BIT(6)
#define RX_HW_FLOW_CTL_EN BIT(7)
#define TX_HW_FLOW_CTL_EN BIT(8)
#define RX_TOUT_THLD_DEF 0x3E00
#define RX_HFC_THLD_DEF 0x40
/* fifo threshold register */
#define SPRD_CTL2 0x0020
#define THLD_TX_EMPTY 0x40
#define THLD_RX_FULL 0x40
/* config baud rate register */
#define SPRD_CLKD0 0x0024
#define SPRD_CLKD1 0x0028
/* interrupt mask status register */
#define SPRD_IMSR 0x002C
#define SPRD_IMSR_RX_FIFO_FULL BIT(0)
#define SPRD_IMSR_TX_FIFO_EMPTY BIT(1)
#define SPRD_IMSR_BREAK_DETECT BIT(7)
#define SPRD_IMSR_TIMEOUT BIT(13)
struct reg_backup {
u32 ien;
u32 ctrl0;
u32 ctrl1;
u32 ctrl2;
u32 clkd0;
u32 clkd1;
u32 dspwait;
};
struct sprd_uart_port {
struct uart_port port;
struct reg_backup reg_bak;
char name[16];
};
static struct sprd_uart_port *sprd_port[UART_NR_MAX];
static int sprd_ports_num;
static inline unsigned int serial_in(struct uart_port *port, int offset)
{
return readl_relaxed(port->membase + offset);
}
static inline void serial_out(struct uart_port *port, int offset, int value)
{
writel_relaxed(value, port->membase + offset);
}
static unsigned int sprd_tx_empty(struct uart_port *port)
{
if (serial_in(port, SPRD_STS1) & 0xff00)
return 0;
else
return TIOCSER_TEMT;
}
static unsigned int sprd_get_mctrl(struct uart_port *port)
{
return TIOCM_DSR | TIOCM_CTS;
}
static void sprd_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
/* nothing to do */
}
static void sprd_stop_tx(struct uart_port *port)
{
unsigned int ien, iclr;
iclr = serial_in(port, SPRD_ICLR);
ien = serial_in(port, SPRD_IEN);
iclr |= SPRD_IEN_TX_EMPTY;
ien &= ~SPRD_IEN_TX_EMPTY;
serial_out(port, SPRD_ICLR, iclr);
serial_out(port, SPRD_IEN, ien);
}
static void sprd_start_tx(struct uart_port *port)
{
unsigned int ien;
ien = serial_in(port, SPRD_IEN);
if (!(ien & SPRD_IEN_TX_EMPTY)) {
ien |= SPRD_IEN_TX_EMPTY;
serial_out(port, SPRD_IEN, ien);
}
}
static void sprd_stop_rx(struct uart_port *port)
{
unsigned int ien, iclr;
iclr = serial_in(port, SPRD_ICLR);
ien = serial_in(port, SPRD_IEN);
ien &= ~(SPRD_IEN_RX_FULL | SPRD_IEN_BREAK_DETECT);
iclr |= SPRD_IEN_RX_FULL | SPRD_IEN_BREAK_DETECT;
serial_out(port, SPRD_IEN, ien);
serial_out(port, SPRD_ICLR, iclr);
}
/* The Sprd serial does not support this function. */
static void sprd_break_ctl(struct uart_port *port, int break_state)
{
/* nothing to do */
}
static int handle_lsr_errors(struct uart_port *port,
unsigned int *flag,
unsigned int *lsr)
{
int ret = 0;
/* statistics */
if (*lsr & SPRD_LSR_BI) {
*lsr &= ~(SPRD_LSR_FE | SPRD_LSR_PE);
port->icount.brk++;
ret = uart_handle_break(port);
if (ret)
return ret;
} else if (*lsr & SPRD_LSR_PE)
port->icount.parity++;
else if (*lsr & SPRD_LSR_FE)
port->icount.frame++;
if (*lsr & SPRD_LSR_OE)
port->icount.overrun++;
/* mask off conditions which should be ignored */
*lsr &= port->read_status_mask;
if (*lsr & SPRD_LSR_BI)
*flag = TTY_BREAK;
else if (*lsr & SPRD_LSR_PE)
*flag = TTY_PARITY;
else if (*lsr & SPRD_LSR_FE)
*flag = TTY_FRAME;
return ret;
}
static inline void sprd_rx(struct uart_port *port)
{
struct tty_port *tty = &port->state->port;
unsigned int ch, flag, lsr, max_count = SPRD_TIMEOUT;
while ((serial_in(port, SPRD_STS1) & 0x00ff) && max_count--) {
lsr = serial_in(port, SPRD_LSR);
ch = serial_in(port, SPRD_RXD);
flag = TTY_NORMAL;
port->icount.rx++;
if (lsr & (SPRD_LSR_BI | SPRD_LSR_PE |
SPRD_LSR_FE | SPRD_LSR_OE))
if (handle_lsr_errors(port, &lsr, &flag))
continue;
if (uart_handle_sysrq_char(port, ch))
continue;
uart_insert_char(port, lsr, SPRD_LSR_OE, ch, flag);
}
tty_flip_buffer_push(tty);
}
static inline void sprd_tx(struct uart_port *port)
{
struct circ_buf *xmit = &port->state->xmit;
int count;
if (port->x_char) {
serial_out(port, SPRD_TXD, port->x_char);
port->icount.tx++;
port->x_char = 0;
return;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
sprd_stop_tx(port);
return;
}
count = THLD_TX_EMPTY;
do {
serial_out(port, SPRD_TXD, xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
if (uart_circ_empty(xmit))
break;
} while (--count > 0);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
if (uart_circ_empty(xmit))
sprd_stop_tx(port);
}
/* this handles the interrupt from one port */
static irqreturn_t sprd_handle_irq(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
unsigned int ims;
spin_lock(&port->lock);
ims = serial_in(port, SPRD_IMSR);
if (!ims)
return IRQ_NONE;
serial_out(port, SPRD_ICLR, ~0);
if (ims & (SPRD_IMSR_RX_FIFO_FULL |
SPRD_IMSR_BREAK_DETECT | SPRD_IMSR_TIMEOUT))
sprd_rx(port);
if (ims & SPRD_IMSR_TX_FIFO_EMPTY)
sprd_tx(port);
spin_unlock(&port->lock);
return IRQ_HANDLED;
}
static int sprd_startup(struct uart_port *port)
{
int ret = 0;
unsigned int ien, fc;
unsigned int timeout;
struct sprd_uart_port *sp;
unsigned long flags;
serial_out(port, SPRD_CTL2, ((THLD_TX_EMPTY << 8) | THLD_RX_FULL));
/* clear rx fifo */
timeout = SPRD_TIMEOUT;
while (timeout-- && serial_in(port, SPRD_STS1) & 0x00ff)
serial_in(port, SPRD_RXD);
/* clear tx fifo */
timeout = SPRD_TIMEOUT;
while (timeout-- && serial_in(port, SPRD_STS1) & 0xff00)
cpu_relax();
/* clear interrupt */
serial_out(port, SPRD_IEN, 0);
serial_out(port, SPRD_ICLR, ~0);
/* allocate irq */
sp = container_of(port, struct sprd_uart_port, port);
snprintf(sp->name, sizeof(sp->name), "sprd_serial%d", port->line);
ret = devm_request_irq(port->dev, port->irq, sprd_handle_irq,
IRQF_SHARED, sp->name, port);
if (ret) {
dev_err(port->dev, "fail to request serial irq %d, ret=%d\n",
port->irq, ret);
return ret;
}
fc = serial_in(port, SPRD_CTL1);
fc |= RX_TOUT_THLD_DEF | RX_HFC_THLD_DEF;
serial_out(port, SPRD_CTL1, fc);
/* enable interrupt */
spin_lock_irqsave(&port->lock, flags);
ien = serial_in(port, SPRD_IEN);
ien |= SPRD_IEN_RX_FULL | SPRD_IEN_BREAK_DETECT | SPRD_IEN_TIMEOUT;
serial_out(port, SPRD_IEN, ien);
spin_unlock_irqrestore(&port->lock, flags);
return 0;
}
static void sprd_shutdown(struct uart_port *port)
{
serial_out(port, SPRD_IEN, 0);
serial_out(port, SPRD_ICLR, ~0);
devm_free_irq(port->dev, port->irq, port);
}
static void sprd_set_termios(struct uart_port *port,
struct ktermios *termios,
struct ktermios *old)
{
unsigned int baud, quot;
unsigned int lcr = 0, fc;
unsigned long flags;
/* ask the core to calculate the divisor for us */
baud = uart_get_baud_rate(port, termios, old, 0, SPRD_BAUD_IO_LIMIT);
quot = (unsigned int)((port->uartclk + baud / 2) / baud);
/* set data length */
switch (termios->c_cflag & CSIZE) {
case CS5:
lcr |= SPRD_LCR_DATA_LEN5;
break;
case CS6:
lcr |= SPRD_LCR_DATA_LEN6;
break;
case CS7:
lcr |= SPRD_LCR_DATA_LEN7;
break;
case CS8:
default:
lcr |= SPRD_LCR_DATA_LEN8;
break;
}
/* calculate stop bits */
lcr &= ~(SPRD_LCR_STOP_1BIT | SPRD_LCR_STOP_2BIT);
if (termios->c_cflag & CSTOPB)
lcr |= SPRD_LCR_STOP_2BIT;
else
lcr |= SPRD_LCR_STOP_1BIT;
/* calculate parity */
lcr &= ~SPRD_LCR_PARITY;
termios->c_cflag &= ~CMSPAR; /* no support mark/space */
if (termios->c_cflag & PARENB) {
lcr |= SPRD_LCR_PARITY_EN;
if (termios->c_cflag & PARODD)
lcr |= SPRD_LCR_ODD_PAR;
else
lcr |= SPRD_LCR_EVEN_PAR;
}
spin_lock_irqsave(&port->lock, flags);
/* update the per-port timeout */
uart_update_timeout(port, termios->c_cflag, baud);
port->read_status_mask = SPRD_LSR_OE;
if (termios->c_iflag & INPCK)
port->read_status_mask |= SPRD_LSR_FE | SPRD_LSR_PE;
if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
port->read_status_mask |= SPRD_LSR_BI;
/* characters to ignore */
port->ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= SPRD_LSR_PE | SPRD_LSR_FE;
if (termios->c_iflag & IGNBRK) {
port->ignore_status_mask |= SPRD_LSR_BI;
/*
* If we're ignoring parity and break indicators,
* ignore overruns too (for real raw support).
*/
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= SPRD_LSR_OE;
}
/* flow control */
fc = serial_in(port, SPRD_CTL1);
fc &= ~(RX_HW_FLOW_CTL_THLD | RX_HW_FLOW_CTL_EN | TX_HW_FLOW_CTL_EN);
if (termios->c_cflag & CRTSCTS) {
fc |= RX_HW_FLOW_CTL_THLD;
fc |= RX_HW_FLOW_CTL_EN;
fc |= TX_HW_FLOW_CTL_EN;
}
/* clock divider bit0~bit15 */
serial_out(port, SPRD_CLKD0, quot & 0xffff);
/* clock divider bit16~bit20 */
serial_out(port, SPRD_CLKD1, (quot & 0x1f0000) >> 16);
serial_out(port, SPRD_LCR, lcr);
fc |= RX_TOUT_THLD_DEF | RX_HFC_THLD_DEF;
serial_out(port, SPRD_CTL1, fc);
spin_unlock_irqrestore(&port->lock, flags);
/* Don't rewrite B0 */
if (tty_termios_baud_rate(termios))
tty_termios_encode_baud_rate(termios, baud, baud);
}
static const char *sprd_type(struct uart_port *port)
{
return "SPX";
}
static void sprd_release_port(struct uart_port *port)
{
/* nothing to do */
}
static int sprd_request_port(struct uart_port *port)
{
return 0;
}
static void sprd_config_port(struct uart_port *port, int flags)
{
if (flags & UART_CONFIG_TYPE)
port->type = PORT_SPRD;
}
static int sprd_verify_port(struct uart_port *port,
struct serial_struct *ser)
{
if (ser->type != PORT_SPRD)
return -EINVAL;
if (port->irq != ser->irq)
return -EINVAL;
return 0;
}
static struct uart_ops serial_sprd_ops = {
.tx_empty = sprd_tx_empty,
.get_mctrl = sprd_get_mctrl,
.set_mctrl = sprd_set_mctrl,
.stop_tx = sprd_stop_tx,
.start_tx = sprd_start_tx,
.stop_rx = sprd_stop_rx,
.break_ctl = sprd_break_ctl,
.startup = sprd_startup,
.shutdown = sprd_shutdown,
.set_termios = sprd_set_termios,
.type = sprd_type,
.release_port = sprd_release_port,
.request_port = sprd_request_port,
.config_port = sprd_config_port,
.verify_port = sprd_verify_port,
};
#ifdef CONFIG_SERIAL_SPRD_CONSOLE
static inline void wait_for_xmitr(struct uart_port *port)
{
unsigned int status, tmout = 10000;
/* wait up to 10ms for the character(s) to be sent */
do {
status = serial_in(port, SPRD_STS1);
if (--tmout == 0)
break;
udelay(1);
} while (status & 0xff00);
}
static void sprd_console_putchar(struct uart_port *port, int ch)
{
wait_for_xmitr(port);
serial_out(port, SPRD_TXD, ch);
}
static void sprd_console_write(struct console *co, const char *s,
unsigned int count)
{
struct uart_port *port = &sprd_port[co->index]->port;
int locked = 1;
unsigned long flags;
if (port->sysrq)
locked = 0;
else if (oops_in_progress)
locked = spin_trylock_irqsave(&port->lock, flags);
else
spin_lock_irqsave(&port->lock, flags);
uart_console_write(port, s, count, sprd_console_putchar);
/* wait for transmitter to become empty */
wait_for_xmitr(port);
if (locked)
spin_unlock_irqrestore(&port->lock, flags);
}
static int __init sprd_console_setup(struct console *co, char *options)
{
struct uart_port *port;
int baud = 115200;
int bits = 8;
int parity = 'n';
int flow = 'n';
if (co->index >= UART_NR_MAX || co->index < 0)
co->index = 0;
port = &sprd_port[co->index]->port;
if (port == NULL) {
pr_info("serial port %d not yet initialized\n", co->index);
return -ENODEV;
}
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
return uart_set_options(port, co, baud, parity, bits, flow);
}
static struct uart_driver sprd_uart_driver;
static struct console sprd_console = {
.name = SPRD_TTY_NAME,
.write = sprd_console_write,
.device = uart_console_device,
.setup = sprd_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &sprd_uart_driver,
};
#define SPRD_CONSOLE (&sprd_console)
/* Support for earlycon */
static void sprd_putc(struct uart_port *port, int c)
{
unsigned int timeout = SPRD_TIMEOUT;
while (timeout-- &&
!(readl(port->membase + SPRD_LSR) & SPRD_LSR_TX_OVER))
cpu_relax();
writeb(c, port->membase + SPRD_TXD);
}
static void sprd_early_write(struct console *con, const char *s,
unsigned n)
{
struct earlycon_device *dev = con->data;
uart_console_write(&dev->port, s, n, sprd_putc);
}
static int __init sprd_early_console_setup(
struct earlycon_device *device,
const char *opt)
{
if (!device->port.membase)
return -ENODEV;
device->con->write = sprd_early_write;
return 0;
}
EARLYCON_DECLARE(sprd_serial, sprd_early_console_setup);
OF_EARLYCON_DECLARE(sprd_serial, "sprd,sc9836-uart",
sprd_early_console_setup);
#else /* !CONFIG_SERIAL_SPRD_CONSOLE */
#define SPRD_CONSOLE NULL
#endif
static struct uart_driver sprd_uart_driver = {
.owner = THIS_MODULE,
.driver_name = "sprd_serial",
.dev_name = SPRD_TTY_NAME,
.major = 0,
.minor = 0,
.nr = UART_NR_MAX,
.cons = SPRD_CONSOLE,
};
static int sprd_probe_dt_alias(int index, struct device *dev)
{
struct device_node *np;
int ret = index;
if (!IS_ENABLED(CONFIG_OF))
return ret;
np = dev->of_node;
if (!np)
return ret;
ret = of_alias_get_id(np, "serial");
if (IS_ERR_VALUE(ret))
ret = index;
else if (ret >= ARRAY_SIZE(sprd_port) || sprd_port[ret] != NULL) {
dev_warn(dev, "requested serial port %d not available.\n", ret);
ret = index;
}
return ret;
}
static int sprd_remove(struct platform_device *dev)
{
struct sprd_uart_port *sup = platform_get_drvdata(dev);
if (sup) {
uart_remove_one_port(&sprd_uart_driver, &sup->port);
sprd_port[sup->port.line] = NULL;
sprd_ports_num--;
}
if (!sprd_ports_num)
uart_unregister_driver(&sprd_uart_driver);
return 0;
}
static int sprd_probe(struct platform_device *pdev)
{
struct resource *res;
struct uart_port *up;
struct clk *clk;
int irq;
int index;
int ret;
for (index = 0; index < ARRAY_SIZE(sprd_port); index++)
if (sprd_port[index] == NULL)
break;
if (index == ARRAY_SIZE(sprd_port))
return -EBUSY;
index = sprd_probe_dt_alias(index, &pdev->dev);
sprd_port[index] = devm_kzalloc(&pdev->dev,
sizeof(*sprd_port[index]), GFP_KERNEL);
if (!sprd_port[index])
return -ENOMEM;
up = &sprd_port[index]->port;
up->dev = &pdev->dev;
up->line = index;
up->type = PORT_SPRD;
up->iotype = SERIAL_IO_PORT;
up->uartclk = SPRD_DEF_RATE;
up->fifosize = SPRD_FIFO_SIZE;
up->ops = &serial_sprd_ops;
up->flags = UPF_BOOT_AUTOCONF;
clk = devm_clk_get(&pdev->dev, NULL);
if (!IS_ERR(clk))
up->uartclk = clk_get_rate(clk);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "not provide mem resource\n");
return -ENODEV;
}
up->mapbase = res->start;
up->membase = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(up->membase))
return PTR_ERR(up->membase);
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "not provide irq resource\n");
return -ENODEV;
}
up->irq = irq;
if (!sprd_ports_num) {
ret = uart_register_driver(&sprd_uart_driver);
if (ret < 0) {
pr_err("Failed to register SPRD-UART driver\n");
return ret;
}
}
sprd_ports_num++;
ret = uart_add_one_port(&sprd_uart_driver, up);
if (ret) {
sprd_port[index] = NULL;
sprd_remove(pdev);
}
platform_set_drvdata(pdev, up);
return ret;
}
static int sprd_suspend(struct device *dev)
{
struct sprd_uart_port *sup = dev_get_drvdata(dev);
uart_suspend_port(&sprd_uart_driver, &sup->port);
return 0;
}
static int sprd_resume(struct device *dev)
{
struct sprd_uart_port *sup = dev_get_drvdata(dev);
uart_resume_port(&sprd_uart_driver, &sup->port);
return 0;
}
static SIMPLE_DEV_PM_OPS(sprd_pm_ops, sprd_suspend, sprd_resume);
static const struct of_device_id serial_ids[] = {
{.compatible = "sprd,sc9836-uart",},
{}
};
static struct platform_driver sprd_platform_driver = {
.probe = sprd_probe,
.remove = sprd_remove,
.driver = {
.name = "sprd_serial",
.of_match_table = of_match_ptr(serial_ids),
.pm = &sprd_pm_ops,
},
};
module_platform_driver(sprd_platform_driver);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Spreadtrum SoC serial driver series");

View File

@ -637,10 +637,12 @@ static void cdns_uart_set_termios(struct uart_port *port,
spin_lock_irqsave(&port->lock, flags);
/* Empty the receive FIFO 1st before making changes */
while ((cdns_uart_readl(CDNS_UART_SR_OFFSET) &
CDNS_UART_SR_RXEMPTY) != CDNS_UART_SR_RXEMPTY) {
cdns_uart_readl(CDNS_UART_FIFO_OFFSET);
/* 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) &
CDNS_UART_SR_TXEMPTY)) {
cpu_relax();
}
}
/* Disable the TX and RX to set baud rate */

View File

@ -557,3 +557,9 @@ int tty_buffer_set_limit(struct tty_port *port, int limit)
return 0;
}
EXPORT_SYMBOL_GPL(tty_buffer_set_limit);
/* slave ptys can claim nested buffer lock when handling BRK and INTR */
void tty_buffer_set_lock_subclass(struct tty_port *port)
{
lockdep_set_subclass(&port->buf.lock, TTY_LOCK_SLAVE);
}

View File

@ -530,7 +530,7 @@ EXPORT_SYMBOL(tty_termios_hw_change);
* Locking: termios_rwsem
*/
int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
static int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
{
struct ktermios old_termios;
struct tty_ldisc *ld;
@ -563,7 +563,6 @@ int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
up_write(&tty->termios_rwsem);
return 0;
}
EXPORT_SYMBOL_GPL(tty_set_termios);
/**
* set_termios - set termios values for a tty

View File

@ -4,18 +4,8 @@
#include <linux/semaphore.h>
#include <linux/sched.h>
/*
* Nested tty locks are necessary for releasing pty pairs.
* The stable lock order is master pty first, then slave pty.
*/
/* Legacy tty mutex glue */
enum {
TTY_MUTEX_NORMAL,
TTY_MUTEX_SLAVE,
};
/*
* Getting the big tty mutex.
*/
@ -46,12 +36,8 @@ EXPORT_SYMBOL(tty_unlock);
void __lockfunc tty_lock_slave(struct tty_struct *tty)
{
if (tty && tty != tty->link) {
WARN_ON(!mutex_is_locked(&tty->link->legacy_mutex) ||
!tty->driver->type == TTY_DRIVER_TYPE_PTY ||
!tty->driver->type == PTY_TYPE_SLAVE);
if (tty && tty != tty->link)
tty_lock(tty);
}
}
void __lockfunc tty_unlock_slave(struct tty_struct *tty)
@ -62,5 +48,5 @@ void __lockfunc tty_unlock_slave(struct tty_struct *tty)
void tty_set_lock_subclass(struct tty_struct *tty)
{
lockdep_set_subclass(&tty->legacy_mutex, TTY_MUTEX_SLAVE);
lockdep_set_subclass(&tty->legacy_mutex, TTY_LOCK_SLAVE);
}

View File

@ -500,6 +500,7 @@ void invert_screen(struct vc_data *vc, int offset, int count, int viewed)
#endif
if (DO_UPDATE(vc))
do_update_region(vc, (unsigned long) p, count);
notify_update(vc);
}
/* used by selection: complement pointer position */
@ -516,6 +517,7 @@ void complement_pos(struct vc_data *vc, int offset)
scr_writew(old, screenpos(vc, old_offset, 1));
if (DO_UPDATE(vc))
vc->vc_sw->con_putc(vc, old, oldy, oldx);
notify_update(vc);
}
old_offset = offset;
@ -533,8 +535,8 @@ void complement_pos(struct vc_data *vc, int offset)
oldy = (offset >> 1) / vc->vc_cols;
vc->vc_sw->con_putc(vc, new, oldy, oldx);
}
notify_update(vc);
}
}
static void insert_char(struct vc_data *vc, unsigned int nr)
@ -3318,11 +3320,8 @@ static int vt_bind(struct con_driver *con)
if (first == 0 && last == MAX_NR_CONSOLES -1)
deflt = 1;
if (first != -1) {
console_lock();
if (first != -1)
do_bind_con_driver(csw, first, last, deflt);
console_unlock();
}
first = -1;
last = -1;
@ -3362,9 +3361,7 @@ static int vt_unbind(struct con_driver *con)
deflt = 1;
if (first != -1) {
console_lock();
ret = do_unbind_con_driver(csw, first, last, deflt);
console_unlock();
if (ret != 0)
return ret;
}
@ -3394,11 +3391,15 @@ static ssize_t store_bind(struct device *dev, struct device_attribute *attr,
struct con_driver *con = dev_get_drvdata(dev);
int bind = simple_strtoul(buf, NULL, 0);
console_lock();
if (bind)
vt_bind(con);
else
vt_unbind(con);
console_unlock();
return count;
}
@ -3665,8 +3666,7 @@ int do_unregister_con_driver(const struct consw *csw)
for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
struct con_driver *con_driver = &registered_con_driver[i];
if (con_driver->con == csw &&
con_driver->flag & CON_DRIVER_FLAG_INIT) {
if (con_driver->con == csw) {
vtconsole_deinit_device(con_driver);
device_destroy(vtconsole_class,
MKDEV(0, con_driver->node));

View File

@ -12,6 +12,7 @@
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/mod_devicetable.h>
#include <linux/console.h>
#define PNP_NAME_LEN 50
@ -309,15 +310,22 @@ struct pnp_fixup {
#define PNP_DISABLE 0x0004
#define PNP_CONFIGURABLE 0x0008
#define PNP_REMOVABLE 0x0010
#define PNP_CONSOLE 0x0020
#define pnp_can_read(dev) (((dev)->protocol->get) && \
((dev)->capabilities & PNP_READ))
#define pnp_can_write(dev) (((dev)->protocol->set) && \
((dev)->capabilities & PNP_WRITE))
#define pnp_can_disable(dev) (((dev)->protocol->disable) && \
((dev)->capabilities & PNP_DISABLE))
#define pnp_can_disable(dev) (((dev)->protocol->disable) && \
((dev)->capabilities & PNP_DISABLE) && \
(!((dev)->capabilities & PNP_CONSOLE) || \
console_suspend_enabled))
#define pnp_can_configure(dev) ((!(dev)->active) && \
((dev)->capabilities & PNP_CONFIGURABLE))
#define pnp_can_suspend(dev) (((dev)->protocol->suspend) && \
(!((dev)->capabilities & PNP_CONSOLE) || \
console_suspend_enabled))
#ifdef CONFIG_ISAPNP
extern struct pnp_protocol isapnp_protocol;

View File

@ -85,6 +85,9 @@ struct uart_8250_port {
unsigned char mcr_force; /* mask of forced bits */
unsigned char cur_iotype; /* Running I/O type */
unsigned int rpm_tx_active;
unsigned char canary; /* non-zero during system sleep
* if no_console_suspend
*/
/*
* Some bits in registers are cleared on a read, so they must
@ -126,6 +129,7 @@ extern int serial8250_do_startup(struct uart_port *port);
extern void serial8250_do_shutdown(struct uart_port *port);
extern void serial8250_do_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate);
extern void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl);
extern int fsl8250_handle_irq(struct uart_port *port);
int serial8250_handle_irq(struct uart_port *port, unsigned int iir);
unsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr);

View File

@ -123,6 +123,7 @@ struct uart_port {
void (*set_termios)(struct uart_port *,
struct ktermios *new,
struct ktermios *old);
void (*set_mctrl)(struct uart_port *, unsigned int);
int (*startup)(struct uart_port *port);
void (*shutdown)(struct uart_port *port);
void (*throttle)(struct uart_port *port);
@ -190,8 +191,10 @@ struct uart_port {
#define UPF_NO_TXEN_TEST ((__force upf_t) (1 << 15))
#define UPF_MAGIC_MULTIPLIER ((__force upf_t) ASYNC_MAGIC_MULTIPLIER /* 16 */ )
/* Port has hardware-assisted h/w flow control (iow, auto-RTS *not* auto-CTS) */
#define UPF_HARD_FLOW ((__force upf_t) (1 << 21))
/* Port has hardware-assisted h/w flow control */
#define UPF_AUTO_CTS ((__force upf_t) (1 << 20))
#define UPF_AUTO_RTS ((__force upf_t) (1 << 21))
#define UPF_HARD_FLOW ((__force upf_t) (UPF_AUTO_CTS | UPF_AUTO_RTS))
/* Port has hardware-assisted s/w flow control */
#define UPF_SOFT_FLOW ((__force upf_t) (1 << 22))
#define UPF_CONS_FLOW ((__force upf_t) (1 << 23))
@ -213,11 +216,17 @@ struct uart_port {
#error Change mask not equivalent to userspace-visible bit defines
#endif
/* status must be updated while holding port lock */
/*
* Must hold termios_rwsem, port mutex and port lock to change;
* can hold any one lock to read.
*/
upstat_t status;
#define UPSTAT_CTS_ENABLE ((__force upstat_t) (1 << 0))
#define UPSTAT_DCD_ENABLE ((__force upstat_t) (1 << 1))
#define UPSTAT_AUTORTS ((__force upstat_t) (1 << 2))
#define UPSTAT_AUTOCTS ((__force upstat_t) (1 << 3))
#define UPSTAT_AUTOXOFF ((__force upstat_t) (1 << 4))
int hw_stopped; /* sw-assisted CTS flow state */
unsigned int mctrl; /* current modem ctrl settings */
@ -391,6 +400,13 @@ static inline bool uart_cts_enabled(struct uart_port *uport)
return !!(uport->status & UPSTAT_CTS_ENABLE);
}
static inline bool uart_softcts_mode(struct uart_port *uport)
{
upstat_t mask = UPSTAT_CTS_ENABLE | UPSTAT_AUTOCTS;
return ((uport->status & mask) == UPSTAT_CTS_ENABLE);
}
/*
* The following are helper functions for the low level drivers.
*/

View File

@ -104,6 +104,31 @@
S3C2410_UCON_RXIRQMODE | \
S3C2410_UCON_RXFIFO_TOI)
#define S3C64XX_UCON_TXBURST_1 (0<<20)
#define S3C64XX_UCON_TXBURST_4 (1<<20)
#define S3C64XX_UCON_TXBURST_8 (2<<20)
#define S3C64XX_UCON_TXBURST_16 (3<<20)
#define S3C64XX_UCON_TXBURST_MASK (0xf<<20)
#define S3C64XX_UCON_RXBURST_1 (0<<16)
#define S3C64XX_UCON_RXBURST_4 (1<<16)
#define S3C64XX_UCON_RXBURST_8 (2<<16)
#define S3C64XX_UCON_RXBURST_16 (3<<16)
#define S3C64XX_UCON_RXBURST_MASK (0xf<<16)
#define S3C64XX_UCON_TIMEOUT_SHIFT (12)
#define S3C64XX_UCON_TIMEOUT_MASK (0xf<<12)
#define S3C64XX_UCON_EMPTYINT_EN (1<<11)
#define S3C64XX_UCON_DMASUS_EN (1<<10)
#define S3C64XX_UCON_TXINT_LEVEL (1<<9)
#define S3C64XX_UCON_RXINT_LEVEL (1<<8)
#define S3C64XX_UCON_TIMEOUT_EN (1<<7)
#define S3C64XX_UCON_ERRINT_EN (1<<6)
#define S3C64XX_UCON_TXMODE_DMA (2<<2)
#define S3C64XX_UCON_TXMODE_CPU (1<<2)
#define S3C64XX_UCON_TXMODE_MASK (3<<2)
#define S3C64XX_UCON_RXMODE_DMA (2<<0)
#define S3C64XX_UCON_RXMODE_CPU (1<<0)
#define S3C64XX_UCON_RXMODE_MASK (3<<0)
#define S3C2410_UFCON_FIFOMODE (1<<0)
#define S3C2410_UFCON_TXTRIG0 (0<<6)
#define S3C2410_UFCON_RXTRIG8 (1<<4)
@ -155,6 +180,7 @@
#define S3C2440_UFSTAT_TXMASK (63<<8)
#define S3C2440_UFSTAT_RXMASK (63)
#define S3C2410_UTRSTAT_TIMEOUT (1<<3)
#define S3C2410_UTRSTAT_TXE (1<<2)
#define S3C2410_UTRSTAT_TXFE (1<<1)
#define S3C2410_UTRSTAT_RXDR (1<<0)
@ -179,8 +205,10 @@
#define S3C64XX_UINTM 0x38
#define S3C64XX_UINTM_RXD (0)
#define S3C64XX_UINTM_ERROR (1)
#define S3C64XX_UINTM_TXD (2)
#define S3C64XX_UINTM_RXD_MSK (1 << S3C64XX_UINTM_RXD)
#define S3C64XX_UINTM_ERR_MSK (1 << S3C64XX_UINTM_ERROR)
#define S3C64XX_UINTM_TXD_MSK (1 << S3C64XX_UINTM_TXD)
/* Following are specific to S5PV210 */

View File

@ -14,6 +14,29 @@
#include <linux/llist.h>
/*
* Lock subclasses for tty locks
*
* TTY_LOCK_NORMAL is for normal ttys and master ptys.
* TTY_LOCK_SLAVE is for slave ptys only.
*
* Lock subclasses are necessary for handling nested locking with pty pairs.
* tty locks which use nested locking:
*
* legacy_mutex - Nested tty locks are necessary for releasing pty pairs.
* The stable lock order is master pty first, then slave pty.
* termios_rwsem - The stable lock order is tty_buffer lock->termios_rwsem.
* Subclassing this lock enables the slave pty to hold its
* termios_rwsem when claiming the master tty_buffer lock.
* tty_buffer lock - slave ptys can claim nested buffer lock when handling
* signal chars. The stable lock order is slave pty, then
* master.
*/
enum {
TTY_LOCK_NORMAL = 0,
TTY_LOCK_SLAVE,
};
/*
* (Note: the *_driver.minor_start values 1, 64, 128, 192 are
@ -443,6 +466,7 @@ extern void tty_flush_to_ldisc(struct tty_struct *tty);
extern void tty_buffer_free_all(struct tty_port *port);
extern void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld);
extern void tty_buffer_init(struct tty_port *port);
extern void tty_buffer_set_lock_subclass(struct tty_port *port);
extern speed_t tty_termios_baud_rate(struct ktermios *termios);
extern speed_t tty_termios_input_baud_rate(struct ktermios *termios);
extern void tty_termios_encode_baud_rate(struct ktermios *termios,
@ -467,7 +491,6 @@ static inline speed_t tty_get_baud_rate(struct tty_struct *tty)
extern void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old);
extern int tty_termios_hw_change(struct ktermios *a, struct ktermios *b);
extern int tty_set_termios(struct tty_struct *tty, struct ktermios *kt);
extern struct tty_ldisc *tty_ldisc_ref(struct tty_struct *);
extern void tty_ldisc_deref(struct tty_ldisc *);

View File

@ -21,10 +21,6 @@
#ifndef VT_BUF_HAVE_RW
#define scr_writew(val, addr) (*(addr) = (val))
#define scr_readw(addr) (*(addr))
#define scr_memcpyw(d, s, c) memcpy(d, s, c)
#define scr_memmovew(d, s, c) memmove(d, s, c)
#define VT_BUF_HAVE_MEMCPYW
#define VT_BUF_HAVE_MEMMOVEW
#endif
#ifndef VT_BUF_HAVE_MEMSETW

View File

@ -55,7 +55,8 @@
#define PORT_ALTR_16550_F64 27 /* Altera 16550 UART with 64 FIFOs */
#define PORT_ALTR_16550_F128 28 /* Altera 16550 UART with 128 FIFOs */
#define PORT_RT2880 29 /* Ralink RT2880 internal UART */
#define PORT_MAX_8250 29 /* max port ID */
#define PORT_16550A_FSL64 30 /* Freescale 16550 UART with 64 FIFOs */
#define PORT_MAX_8250 30 /* max port ID */
/*
* ARM specific type numbers. These are not currently guaranteed
@ -248,4 +249,13 @@
/* MESON */
#define PORT_MESON 109
/* Conexant Digicolor */
#define PORT_DIGICOLOR 110
/* SPRD SERIAL */
#define PORT_SPRD 111
/* Cris v10 / v32 SoC */
#define PORT_CRIS 112
#endif /* _UAPILINUX_SERIAL_CORE_H */

View File

@ -86,7 +86,8 @@
#define UART_FCR6_T_TRIGGER_8 0x10 /* Mask for transmit trigger set at 8 */
#define UART_FCR6_T_TRIGGER_24 0x20 /* Mask for transmit trigger set at 24 */
#define UART_FCR6_T_TRIGGER_30 0x30 /* Mask for transmit trigger set at 30 */
#define UART_FCR7_64BYTE 0x20 /* Go into 64 byte mode (TI16C750) */
#define UART_FCR7_64BYTE 0x20 /* Go into 64 byte mode (TI16C750 and
some Freescale UARTs) */
#define UART_FCR_R_TRIG_SHIFT 6
#define UART_FCR_R_TRIG_BITS(x) \