TTY/Serial driver patches for 3.16-rc1

Here is the big tty / serial driver pull request for 3.16-rc1.
 
 A variety of different serial driver fixes and updates and additions,
 nothing huge, and no real major core tty changes at all.
 
 All have been in linux-next for a while.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iEYEABECAAYFAlONXgoACgkQMUfUDdst+ymdSwCgwL0xmWjFYr/UbJ4LslOZ29Q4
 BFQAoKyYe9LsfEyodBPabxJjKUtj1htz
 =ZGSN
 -----END PGP SIGNATURE-----

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

Pull tty/serial driver updates from Greg KH:
 "Here is the big tty / serial driver pull request for 3.16-rc1.

  A variety of different serial driver fixes and updates and additions,
  nothing huge, and no real major core tty changes at all.

  All have been in linux-next for a while"

* tag 'tty-3.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (84 commits)
  Revert "serial: imx: remove the DMA wait queue"
  serial: kgdb_nmi: Improve console integration with KDB I/O
  serial: kgdb_nmi: Switch from tasklets to real timers
  serial: kgdb_nmi: Use container_of() to locate private data
  serial: cpm_uart: No LF conversion in put_poll_char()
  serial: sirf: Fix compilation failure
  console: Remove superfluous readonly check
  console: Use explicit pointer type for vc_uni_pagedir* fields
  vgacon: Fix & cleanup refcounting
  ARM: tty: Move HVC DCC assembly to arch/arm
  tty/hvc/hvc_console: Fix wakeup of HVC thread on hvc_kick()
  drivers/tty/n_hdlc.c: replace kmalloc/memset by kzalloc
  vt: emulate 8- and 24-bit colour codes.
  printk/of_serial: fix serial console cessation part way through boot.
  serial: 8250_dma: check the result of TX buffer mapping
  serial: uart: add hw flow control support configuration
  tty/serial: at91: add interrupts for modem control lines
  tty/serial: at91: use mctrl_gpio helpers
  tty/serial: Add GPIOLIB helpers for controlling modem lines
  ARM: at91: gpio: implement get_direction
  ...
This commit is contained in:
Linus Torvalds 2014-06-03 09:01:02 -07:00
commit 49eb7b0750
70 changed files with 4047 additions and 1304 deletions

View File

@ -13,8 +13,9 @@ Required properties:
Optional properties:
- atmel,use-dma-rx: use of PDC or DMA for receiving data
- atmel,use-dma-tx: use of PDC or DMA for transmitting data
- rts-gpios: specify a GPIO for RTS line. It will use specified PIO instead of the peripheral
function pin for the USART RTS feature. If unsure, don't specify this property.
- {rts,cts,dtr,dsr,rng,dcd}-gpios: specify a GPIO for RTS/CTS/DTR/DSR/RI/DCD line respectively.
It will use specified PIO instead of the peripheral function pin for the USART feature.
If unsure, don't specify this property.
- add dma bindings for dma transfer:
- dmas: DMA specifier, consisting of a phandle to DMA controller node,
memory peripheral interface and USART DMA channel ID, FIFO configuration.
@ -35,7 +36,12 @@ Example:
clock-names = "usart";
atmel,use-dma-rx;
atmel,use-dma-tx;
rts-gpios = <&pioD 15 0>;
rts-gpios = <&pioD 15 GPIO_ACTIVE_LOW>;
cts-gpios = <&pioD 16 GPIO_ACTIVE_LOW>;
dtr-gpios = <&pioD 17 GPIO_ACTIVE_LOW>;
dsr-gpios = <&pioD 18 GPIO_ACTIVE_LOW>;
dcd-gpios = <&pioD 20 GPIO_ACTIVE_LOW>;
rng-gpios = <&pioD 19 GPIO_ACTIVE_LOW>;
};
- use DMA:

View File

@ -0,0 +1,33 @@
* NXP SC16IS7xx advanced Universal Asynchronous Receiver-Transmitter (UART)
Required properties:
- compatible: Should be one of the following:
- "nxp,sc16is740" for NXP SC16IS740,
- "nxp,sc16is741" for NXP SC16IS741,
- "nxp,sc16is750" for NXP SC16IS750,
- "nxp,sc16is752" for NXP SC16IS752,
- "nxp,sc16is760" for NXP SC16IS760,
- "nxp,sc16is762" for NXP SC16IS762.
- reg: I2C address of the SC16IS7xx device.
- interrupt-parent: The phandle for the interrupt controller that
services interrupts for this IC.
- interrupts: Should contain the UART interrupt
- clocks: Reference to the IC source clock.
Optional properties:
- gpio-controller: Marks the device node as a GPIO controller.
- #gpio-cells: Should be two. The first cell is the GPIO number and
the second cell is used to specify the GPIO polarity:
0 = active high,
1 = active low.
Example:
sc16is750: sc16is750@51 {
compatible = "nxp,sc16is750";
reg = <0x51>;
clocks = <&clk20m>;
interrupt-parent = <&gpio3>;
interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
gpio-controller;
#gpio-cells = <2>;
};

View File

@ -37,6 +37,7 @@ Optional properties:
- auto-flow-control: one way to enable automatic flow control support. The
driver is allowed to detect support for the capability even without this
property.
- has-hw-flow-control: the hardware has flow control capability.
Example:

View File

@ -4,6 +4,7 @@ Required properties:
- compatible: Must contain one of the following:
- "renesas,scif-r8a7779" for R8A7779 (R-Car H1) SCIF compatible UART.
- "renesas,scif-r8a7790" for R8A7790 (R-Car H2) SCIF compatible UART.
- "renesas,scifa-r8a7790" for R8A7790 (R-Car H2) SCIFA compatible UART.
- "renesas,scifb-r8a7790" for R8A7790 (R-Car H2) SCIFB compatible UART.

View File

@ -883,6 +883,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
which are not unmapped.
earlycon= [KNL] Output early console device and options.
uart[8250],io,<addr>[,options]
uart[8250],mmio,<addr>[,options]
uart[8250],mmio32,<addr>[,options]
@ -892,6 +893,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
(mmio) or 32-bit (mmio32).
The options are the same as for ttyS, above.
pl011,<addr>
Start an early, polled-mode console on a pl011 serial
port at the specified address. The pl011 serial port
must already be setup and configured. Options are not
yet supported.
smh Use ARM semihosting calls for early console.
earlyprintk= [X86,SH,BLACKFIN,ARM,M68k]
earlyprintk=vga
earlyprintk=efi

View File

@ -429,3 +429,28 @@ thus:
struct uart_port port;
int my_stuff;
};
Modem control lines via GPIO
----------------------------
Some helpers are provided in order to set/get modem control lines via GPIO.
mctrl_gpio_init(dev, idx):
This will get the {cts,rts,...}-gpios from device tree if they are
present and request them, set direction etc, and return an
allocated structure. devm_* functions are used, so there's no need
to call mctrl_gpio_free().
mctrl_gpio_free(dev, gpios):
This will free the requested gpios in mctrl_gpio_init().
As devm_* function are used, there's generally no need to call
this function.
mctrl_gpio_to_gpiod(gpios, gidx)
This returns the gpio structure associated to the modem line index.
mctrl_gpio_set(gpios, mctrl):
This will sets the gpios according to the mctrl state.
mctrl_gpio_get(gpios, mctrl):
This will update mctrl with the gpios values.

View File

@ -0,0 +1,41 @@
/* Copyright (c) 2010, 2014 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <asm/barrier.h>
static inline u32 __dcc_getstatus(void)
{
u32 __ret;
asm volatile("mrc p14, 0, %0, c0, c1, 0 @ read comms ctrl reg"
: "=r" (__ret) : : "cc");
return __ret;
}
static inline char __dcc_getchar(void)
{
char __c;
asm volatile("mrc p14, 0, %0, c0, c5, 0 @ read comms data reg"
: "=r" (__c));
isb();
return __c;
}
static inline void __dcc_putchar(char c)
{
asm volatile("mcr p14, 0, %0, c0, c5, 0 @ write a char"
: /* no output register */
: "r" (c));
isb();
}

View File

@ -15,6 +15,7 @@
#include <linux/dma-mapping.h>
#include <linux/gpio.h>
#include <linux/gpio/driver.h>
#include <linux/platform_device.h>
#include <linux/i2c-gpio.h>
@ -924,7 +925,6 @@ static struct resource dbgu_resources[] = {
static struct atmel_uart_data dbgu_data = {
.use_dma_tx = 0,
.use_dma_rx = 0, /* DBGU not capable of receive DMA */
.rts_gpio = -EINVAL,
};
static u64 dbgu_dmamask = DMA_BIT_MASK(32);
@ -963,7 +963,14 @@ static struct resource uart0_resources[] = {
static struct atmel_uart_data uart0_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
};
static struct gpiod_lookup_table uart0_gpios_table = {
.dev_id = "atmel_usart",
.table = {
GPIO_LOOKUP("pioA", 21, "rts", GPIO_ACTIVE_LOW),
{ },
},
};
static u64 uart0_dmamask = DMA_BIT_MASK(32);
@ -994,7 +1001,7 @@ static inline void configure_usart0_pins(unsigned pins)
* We need to drive the pin manually. The serial driver will driver
* this to high when initializing.
*/
uart0_data.rts_gpio = AT91_PIN_PA21;
gpiod_add_lookup_table(&uart0_gpios_table);
}
}
@ -1014,7 +1021,6 @@ static struct resource uart1_resources[] = {
static struct atmel_uart_data uart1_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
};
static u64 uart1_dmamask = DMA_BIT_MASK(32);
@ -1066,7 +1072,6 @@ static struct resource uart2_resources[] = {
static struct atmel_uart_data uart2_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
};
static u64 uart2_dmamask = DMA_BIT_MASK(32);
@ -1110,7 +1115,6 @@ static struct resource uart3_resources[] = {
static struct atmel_uart_data uart3_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
};
static u64 uart3_dmamask = DMA_BIT_MASK(32);

View File

@ -819,7 +819,6 @@ static struct resource dbgu_resources[] = {
static struct atmel_uart_data dbgu_data = {
.use_dma_tx = 0,
.use_dma_rx = 0, /* DBGU not capable of receive DMA */
.rts_gpio = -EINVAL,
};
static u64 dbgu_dmamask = DMA_BIT_MASK(32);
@ -858,7 +857,6 @@ static struct resource uart0_resources[] = {
static struct atmel_uart_data uart0_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
};
static u64 uart0_dmamask = DMA_BIT_MASK(32);
@ -910,7 +908,6 @@ static struct resource uart1_resources[] = {
static struct atmel_uart_data uart1_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
};
static u64 uart1_dmamask = DMA_BIT_MASK(32);
@ -954,7 +951,6 @@ static struct resource uart2_resources[] = {
static struct atmel_uart_data uart2_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
};
static u64 uart2_dmamask = DMA_BIT_MASK(32);
@ -998,7 +994,6 @@ static struct resource uart3_resources[] = {
static struct atmel_uart_data uart3_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
};
static u64 uart3_dmamask = DMA_BIT_MASK(32);
@ -1042,7 +1037,6 @@ static struct resource uart4_resources[] = {
static struct atmel_uart_data uart4_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
};
static u64 uart4_dmamask = DMA_BIT_MASK(32);
@ -1081,7 +1075,6 @@ static struct resource uart5_resources[] = {
static struct atmel_uart_data uart5_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
};
static u64 uart5_dmamask = DMA_BIT_MASK(32);

View File

@ -881,7 +881,6 @@ static struct resource dbgu_resources[] = {
static struct atmel_uart_data dbgu_data = {
.use_dma_tx = 0,
.use_dma_rx = 0, /* DBGU not capable of receive DMA */
.rts_gpio = -EINVAL,
};
static u64 dbgu_dmamask = DMA_BIT_MASK(32);
@ -920,7 +919,6 @@ static struct resource uart0_resources[] = {
static struct atmel_uart_data uart0_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
};
static u64 uart0_dmamask = DMA_BIT_MASK(32);
@ -964,7 +962,6 @@ static struct resource uart1_resources[] = {
static struct atmel_uart_data uart1_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
};
static u64 uart1_dmamask = DMA_BIT_MASK(32);
@ -1008,7 +1005,6 @@ static struct resource uart2_resources[] = {
static struct atmel_uart_data uart2_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
};
static u64 uart2_dmamask = DMA_BIT_MASK(32);

View File

@ -1326,7 +1326,6 @@ static struct resource dbgu_resources[] = {
static struct atmel_uart_data dbgu_data = {
.use_dma_tx = 0,
.use_dma_rx = 0, /* DBGU not capable of receive DMA */
.rts_gpio = -EINVAL,
};
static u64 dbgu_dmamask = DMA_BIT_MASK(32);
@ -1365,7 +1364,6 @@ static struct resource uart0_resources[] = {
static struct atmel_uart_data uart0_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
};
static u64 uart0_dmamask = DMA_BIT_MASK(32);
@ -1409,7 +1407,6 @@ static struct resource uart1_resources[] = {
static struct atmel_uart_data uart1_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
};
static u64 uart1_dmamask = DMA_BIT_MASK(32);
@ -1453,7 +1450,6 @@ static struct resource uart2_resources[] = {
static struct atmel_uart_data uart2_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
};
static u64 uart2_dmamask = DMA_BIT_MASK(32);

View File

@ -1528,7 +1528,6 @@ static struct resource dbgu_resources[] = {
static struct atmel_uart_data dbgu_data = {
.use_dma_tx = 0,
.use_dma_rx = 0,
.rts_gpio = -EINVAL,
};
static u64 dbgu_dmamask = DMA_BIT_MASK(32);
@ -1567,7 +1566,6 @@ static struct resource uart0_resources[] = {
static struct atmel_uart_data uart0_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
};
static u64 uart0_dmamask = DMA_BIT_MASK(32);
@ -1611,7 +1609,6 @@ static struct resource uart1_resources[] = {
static struct atmel_uart_data uart1_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
};
static u64 uart1_dmamask = DMA_BIT_MASK(32);
@ -1655,7 +1652,6 @@ static struct resource uart2_resources[] = {
static struct atmel_uart_data uart2_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
};
static u64 uart2_dmamask = DMA_BIT_MASK(32);
@ -1699,7 +1695,6 @@ static struct resource uart3_resources[] = {
static struct atmel_uart_data uart3_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
};
static u64 uart3_dmamask = DMA_BIT_MASK(32);

View File

@ -993,7 +993,6 @@ static struct resource dbgu_resources[] = {
static struct atmel_uart_data dbgu_data = {
.use_dma_tx = 0,
.use_dma_rx = 0, /* DBGU not capable of receive DMA */
.rts_gpio = -EINVAL,
};
static u64 dbgu_dmamask = DMA_BIT_MASK(32);
@ -1032,7 +1031,6 @@ static struct resource uart0_resources[] = {
static struct atmel_uart_data uart0_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
};
static u64 uart0_dmamask = DMA_BIT_MASK(32);
@ -1084,7 +1082,6 @@ static struct resource uart1_resources[] = {
static struct atmel_uart_data uart1_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
};
static u64 uart1_dmamask = DMA_BIT_MASK(32);
@ -1128,7 +1125,6 @@ static struct resource uart2_resources[] = {
static struct atmel_uart_data uart2_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
};
static u64 uart2_dmamask = DMA_BIT_MASK(32);
@ -1172,7 +1168,6 @@ static struct resource uart3_resources[] = {
static struct atmel_uart_data uart3_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
.rts_gpio = -EINVAL,
};
static u64 uart3_dmamask = DMA_BIT_MASK(32);

View File

@ -50,6 +50,7 @@ static int at91_gpiolib_request(struct gpio_chip *chip, unsigned offset);
static void at91_gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip);
static void at91_gpiolib_set(struct gpio_chip *chip, unsigned offset, int val);
static int at91_gpiolib_get(struct gpio_chip *chip, unsigned offset);
static int at91_gpiolib_get_direction(struct gpio_chip *chip, unsigned offset);
static int at91_gpiolib_direction_output(struct gpio_chip *chip,
unsigned offset, int val);
static int at91_gpiolib_direction_input(struct gpio_chip *chip,
@ -61,6 +62,7 @@ static int at91_gpiolib_to_irq(struct gpio_chip *chip, unsigned offset);
.chip = { \
.label = name, \
.request = at91_gpiolib_request, \
.get_direction = at91_gpiolib_get_direction, \
.direction_input = at91_gpiolib_direction_input, \
.direction_output = at91_gpiolib_direction_output, \
.get = at91_gpiolib_get, \
@ -800,6 +802,17 @@ static int at91_gpiolib_request(struct gpio_chip *chip, unsigned offset)
return 0;
}
static int at91_gpiolib_get_direction(struct gpio_chip *chip, unsigned offset)
{
struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
void __iomem *pio = at91_gpio->regbase;
unsigned mask = 1 << offset;
u32 osr;
osr = __raw_readl(pio + PIO_OSR);
return !(osr & mask);
}
static int at91_gpiolib_direction_input(struct gpio_chip *chip,
unsigned offset)
{

View File

@ -112,6 +112,9 @@ config IOMMU_HELPER
config KERNEL_MODE_NEON
def_bool y
config FIX_EARLYCON_MEM
def_bool y
source "init/Kconfig"
source "kernel/Kconfig.freezer"

View File

@ -20,15 +20,6 @@ config STRICT_DEVMEM
If in doubt, say Y.
config EARLY_PRINTK
bool "Early printk support"
default y
help
Say Y here if you want to have an early console using the
earlyprintk=<name>[,<addr>][,<options>] kernel parameter. It
is assumed that the early console device has been initialised
by the boot loader prior to starting the Linux kernel.
config PID_IN_CONTEXTIDR
bool "Write the current PID to the CONTEXTIDR register"
help

View File

@ -18,7 +18,6 @@ arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o topology.o
arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o
arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
arm64-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND) += sleep.o suspend.o
arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o
arm64-obj-$(CONFIG_KGDB) += kgdb.o

View File

@ -1,156 +0,0 @@
/*
* Earlyprintk support.
*
* Copyright (C) 2012 ARM Ltd.
* Author: Catalin Marinas <catalin.marinas@arm.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
#include <linux/console.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/io.h>
#include <linux/amba/serial.h>
#include <linux/serial_reg.h>
#include <asm/fixmap.h>
static void __iomem *early_base;
static void (*printch)(char ch);
/*
* PL011 single character TX.
*/
static void pl011_printch(char ch)
{
while (readl_relaxed(early_base + UART01x_FR) & UART01x_FR_TXFF)
;
writeb_relaxed(ch, early_base + UART01x_DR);
while (readl_relaxed(early_base + UART01x_FR) & UART01x_FR_BUSY)
;
}
/*
* Semihosting-based debug console
*/
static void smh_printch(char ch)
{
asm volatile("mov x1, %0\n"
"mov x0, #3\n"
"hlt 0xf000\n"
: : "r" (&ch) : "x0", "x1", "memory");
}
/*
* 8250/16550 (8-bit aligned registers) single character TX.
*/
static void uart8250_8bit_printch(char ch)
{
while (!(readb_relaxed(early_base + UART_LSR) & UART_LSR_THRE))
;
writeb_relaxed(ch, early_base + UART_TX);
}
/*
* 8250/16550 (32-bit aligned registers) single character TX.
*/
static void uart8250_32bit_printch(char ch)
{
while (!(readl_relaxed(early_base + (UART_LSR << 2)) & UART_LSR_THRE))
;
writel_relaxed(ch, early_base + (UART_TX << 2));
}
struct earlycon_match {
const char *name;
void (*printch)(char ch);
};
static const struct earlycon_match earlycon_match[] __initconst = {
{ .name = "pl011", .printch = pl011_printch, },
{ .name = "smh", .printch = smh_printch, },
{ .name = "uart8250-8bit", .printch = uart8250_8bit_printch, },
{ .name = "uart8250-32bit", .printch = uart8250_32bit_printch, },
{}
};
static void early_write(struct console *con, const char *s, unsigned n)
{
while (n-- > 0) {
if (*s == '\n')
printch('\r');
printch(*s);
s++;
}
}
static struct console early_console_dev = {
.name = "earlycon",
.write = early_write,
.flags = CON_PRINTBUFFER | CON_BOOT,
.index = -1,
};
/*
* Parse earlyprintk=... parameter in the format:
*
* <name>[,<addr>][,<options>]
*
* and register the early console. It is assumed that the UART has been
* initialised by the bootloader already.
*/
static int __init setup_early_printk(char *buf)
{
const struct earlycon_match *match = earlycon_match;
phys_addr_t paddr = 0;
if (!buf) {
pr_warning("No earlyprintk arguments passed.\n");
return 0;
}
while (match->name) {
size_t len = strlen(match->name);
if (!strncmp(buf, match->name, len)) {
buf += len;
break;
}
match++;
}
if (!match->name) {
pr_warning("Unknown earlyprintk arguments: %s\n", buf);
return 0;
}
/* I/O address */
if (!strncmp(buf, ",0x", 3)) {
char *e;
paddr = simple_strtoul(buf + 1, &e, 16);
buf = e;
}
/* no options parsing yet */
if (paddr)
early_base = (void __iomem *)set_fixmap_offset_io(FIX_EARLYCON_MEM_BASE, paddr);
printch = match->printch;
early_console = &early_console_dev;
register_console(&early_console_dev);
return 0;
}
early_param("earlyprintk", setup_early_printk);

View File

@ -261,6 +261,9 @@ config ARCH_HWEIGHT_CFLAGS
config ARCH_SUPPORTS_UPROBES
def_bool y
config FIX_EARLYCON_MEM
def_bool y
source "init/Kconfig"
source "kernel/Kconfig.freezer"

View File

@ -118,10 +118,6 @@ static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu)
int hci_uart_tx_wakeup(struct hci_uart *hu)
{
struct tty_struct *tty = hu->tty;
struct hci_dev *hdev = hu->hdev;
struct sk_buff *skb;
if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) {
set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
return 0;
@ -129,6 +125,22 @@ int hci_uart_tx_wakeup(struct hci_uart *hu)
BT_DBG("");
schedule_work(&hu->write_work);
return 0;
}
static void hci_uart_write_work(struct work_struct *work)
{
struct hci_uart *hu = container_of(work, struct hci_uart, write_work);
struct tty_struct *tty = hu->tty;
struct hci_dev *hdev = hu->hdev;
struct sk_buff *skb;
/* REVISIT: should we cope with bad skbs or ->write() returning
* and error value ?
*/
restart:
clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
@ -153,7 +165,6 @@ restart:
goto restart;
clear_bit(HCI_UART_SENDING, &hu->tx_state);
return 0;
}
static void hci_uart_init_work(struct work_struct *work)
@ -282,6 +293,7 @@ static int hci_uart_tty_open(struct tty_struct *tty)
tty->receive_room = 65536;
INIT_WORK(&hu->init_ready, hci_uart_init_work);
INIT_WORK(&hu->write_work, hci_uart_write_work);
spin_lock_init(&hu->rx_lock);
@ -319,6 +331,8 @@ static void hci_uart_tty_close(struct tty_struct *tty)
if (hdev)
hci_uart_close(hdev);
cancel_work_sync(&hu->write_work);
if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) {
if (hdev) {
if (test_bit(HCI_UART_REGISTERED, &hu->flags))

View File

@ -68,6 +68,7 @@ struct hci_uart {
unsigned long hdev_flags;
struct work_struct init_ready;
struct work_struct write_work;
struct hci_uart_proto *proto;
void *priv;

View File

@ -62,6 +62,7 @@ enum parport_pc_pci_cards {
timedia_9079a,
timedia_9079b,
timedia_9079c,
wch_ch353_1s1p,
wch_ch353_2s1p,
sunix_2s1p,
};
@ -148,6 +149,7 @@ static struct parport_pc_pci cards[] = {
/* timedia_9079a */ { 1, { { 2, 3 }, } },
/* timedia_9079b */ { 1, { { 2, 3 }, } },
/* timedia_9079c */ { 1, { { 2, 3 }, } },
/* wch_ch353_1s1p*/ { 1, { { 1, -1}, } },
/* wch_ch353_2s1p*/ { 1, { { 2, -1}, } },
/* sunix_2s1p */ { 1, { { 3, -1 }, } },
};
@ -253,6 +255,7 @@ static struct pci_device_id parport_serial_pci_tbl[] = {
{ 0x1409, 0x7168, 0x1409, 0xd079, 0, 0, timedia_9079c },
/* WCH CARDS */
{ 0x4348, 0x5053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, wch_ch353_1s1p},
{ 0x4348, 0x7053, 0x4348, 0x3253, 0, 0, wch_ch353_2s1p},
/*
@ -479,6 +482,12 @@ static struct pciserial_board pci_parport_serial_boards[] = {
.base_baud = 921600,
.uart_offset = 8,
},
[wch_ch353_1s1p] = {
.flags = FL_BASE0|FL_BASE_BARS,
.num_ports = 1,
.base_baud = 115200,
.uart_offset = 8,
},
[wch_ch353_2s1p] = {
.flags = FL_BASE0|FL_BASE_BARS,
.num_ports = 2,

View File

@ -760,10 +760,17 @@ static int khvcd(void *unused)
if (poll_mask == 0)
schedule();
else {
unsigned long j_timeout;
if (timeout < MAX_TIMEOUT)
timeout += (timeout >> 6) + 1;
msleep_interruptible(timeout);
/*
* We don't use msleep_interruptible otherwise
* "kick" will fail to wake us up
*/
j_timeout = msecs_to_jiffies(timeout) + 1;
schedule_timeout_interruptible(j_timeout);
}
}
__set_current_state(TASK_RUNNING);

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
/* Copyright (c) 2010, 2014 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -8,20 +8,11 @@
* 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 Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/console.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
#include <asm/dcc.h>
#include <asm/processor.h>
#include "hvc_console.h"
@ -30,35 +21,6 @@
#define DCC_STATUS_RX (1 << 30)
#define DCC_STATUS_TX (1 << 29)
static inline u32 __dcc_getstatus(void)
{
u32 __ret;
asm volatile("mrc p14, 0, %0, c0, c1, 0 @ read comms ctrl reg"
: "=r" (__ret) : : "cc");
return __ret;
}
static inline char __dcc_getchar(void)
{
char __c;
asm volatile("mrc p14, 0, %0, c0, c5, 0 @ read comms data reg"
: "=r" (__c));
isb();
return __c;
}
static inline void __dcc_putchar(char c)
{
asm volatile("mcr p14, 0, %0, c0, c5, 0 @ write a char"
: /* no output register */
: "r" (c));
isb();
}
static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count)
{
int i;

View File

@ -848,13 +848,11 @@ static struct n_hdlc *n_hdlc_alloc(void)
{
struct n_hdlc_buf *buf;
int i;
struct n_hdlc *n_hdlc = kmalloc(sizeof(*n_hdlc), GFP_KERNEL);
struct n_hdlc *n_hdlc = kzalloc(sizeof(*n_hdlc), GFP_KERNEL);
if (!n_hdlc)
return NULL;
memset(n_hdlc, 0, sizeof(*n_hdlc));
n_hdlc_buf_list_init(&n_hdlc->rx_free_buf_list);
n_hdlc_buf_list_init(&n_hdlc->tx_free_buf_list);
n_hdlc_buf_list_init(&n_hdlc->rx_buf_list);
@ -952,8 +950,6 @@ static char hdlc_register_ok[] __initdata =
KERN_INFO "N_HDLC line discipline registered.\n";
static char hdlc_register_fail[] __initdata =
KERN_ERR "error registering line discipline: %d\n";
static char hdlc_init_fail[] __initdata =
KERN_INFO "N_HDLC: init failure %d\n";
static int __init n_hdlc_init(void)
{
@ -973,8 +969,6 @@ static int __init n_hdlc_init(void)
else
printk(hdlc_register_fail, status);
if (status)
printk(hdlc_init_fail, status);
return status;
} /* end of init_module() */

View File

@ -1926,13 +1926,8 @@ static void serial8250_put_poll_char(struct uart_port *port,
wait_for_xmitr(up, BOTH_EMPTY);
/*
* Send the character out.
* If a LF, also do CR...
*/
serial_port_out(port, UART_TX, c);
if (c == 10) {
wait_for_xmitr(up, BOTH_EMPTY);
serial_port_out(port, UART_TX, 13);
}
/*
* Finally, wait for transmitter to become empty
@ -2338,9 +2333,11 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
* the trigger, or the MCR RTS bit is cleared. In the case where
* the remote UART is not using CTS auto flow control, we must
* have sufficient FIFO entries for the latency of the remote
* UART to respond. IOW, at least 32 bytes of FIFO.
* UART to respond. IOW, at least 32 bytes of FIFO. Also enable
* AFE if hw flow control is supported
*/
if (up->capabilities & UART_CAP_AFE && port->fifosize >= 32) {
if ((up->capabilities & UART_CAP_AFE && (port->fifosize >= 32)) ||
(port->flags & UPF_HARD_FLOW)) {
up->mcr &= ~UART_MCR_AFE;
if (termios->c_cflag & CRTSCTS)
up->mcr |= UART_MCR_AFE;

View File

@ -192,21 +192,28 @@ int serial8250_request_dma(struct uart_8250_port *p)
dma->rx_buf = dma_alloc_coherent(dma->rxchan->device->dev, dma->rx_size,
&dma->rx_addr, GFP_KERNEL);
if (!dma->rx_buf) {
dma_release_channel(dma->rxchan);
dma_release_channel(dma->txchan);
return -ENOMEM;
}
if (!dma->rx_buf)
goto err;
/* TX buffer */
dma->tx_addr = dma_map_single(dma->txchan->device->dev,
p->port.state->xmit.buf,
UART_XMIT_SIZE,
DMA_TO_DEVICE);
if (dma_mapping_error(dma->txchan->device->dev, dma->tx_addr)) {
dma_free_coherent(dma->rxchan->device->dev, dma->rx_size,
dma->rx_buf, dma->rx_addr);
goto err;
}
dev_dbg_ratelimited(p->port.dev, "got both dma channels\n");
return 0;
err:
dma_release_channel(dma->rxchan);
dma_release_channel(dma->txchan);
return -ENOMEM;
}
EXPORT_SYMBOL_GPL(serial8250_request_dma);

View File

@ -62,6 +62,70 @@ struct dw8250_data {
struct uart_8250_dma dma;
};
struct dw8250_acpi_desc {
void (*set_termios)(struct uart_port *p, struct ktermios *termios,
struct ktermios *old);
};
#define BYT_PRV_CLK 0x800
#define BYT_PRV_CLK_EN (1 << 0)
#define BYT_PRV_CLK_M_VAL_SHIFT 1
#define BYT_PRV_CLK_N_VAL_SHIFT 16
#define BYT_PRV_CLK_UPDATE (1 << 31)
static void byt_set_termios(struct uart_port *p, struct ktermios *termios,
struct ktermios *old)
{
unsigned int baud = tty_termios_baud_rate(termios);
unsigned int m, n;
u32 reg;
/*
* For baud rates 0.5M, 1M, 1.5M, 2M, 2.5M, 3M, 3.5M and 4M the
* dividers must be adjusted.
*
* uartclk = (m / n) * 100 MHz, where m <= n
*/
switch (baud) {
case 500000:
case 1000000:
case 2000000:
case 4000000:
m = 64;
n = 100;
p->uartclk = 64000000;
break;
case 3500000:
m = 56;
n = 100;
p->uartclk = 56000000;
break;
case 1500000:
case 3000000:
m = 48;
n = 100;
p->uartclk = 48000000;
break;
case 2500000:
m = 40;
n = 100;
p->uartclk = 40000000;
break;
default:
m = 2304;
n = 3125;
p->uartclk = 73728000;
}
/* Reset the clock */
reg = (m << BYT_PRV_CLK_M_VAL_SHIFT) | (n << BYT_PRV_CLK_N_VAL_SHIFT);
writel(reg, p->membase + BYT_PRV_CLK);
reg |= BYT_PRV_CLK_EN | BYT_PRV_CLK_UPDATE;
writel(reg, p->membase + BYT_PRV_CLK);
serial8250_do_set_termios(p, termios, old);
}
static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
{
struct dw8250_data *d = p->private_data;
@ -278,6 +342,7 @@ static int dw8250_probe_acpi(struct uart_8250_port *up,
{
const struct acpi_device_id *id;
struct uart_port *p = &up->port;
struct dw8250_acpi_desc *acpi_desc;
dw8250_setup_port(up);
@ -290,14 +355,18 @@ static int dw8250_probe_acpi(struct uart_8250_port *up,
p->serial_out = dw8250_serial_out32;
p->regshift = 2;
if (!p->uartclk)
p->uartclk = (unsigned int)id->driver_data;
up->dma = &data->dma;
up->dma->rxconf.src_maxburst = p->fifosize / 4;
up->dma->txconf.dst_maxburst = p->fifosize / 4;
acpi_desc = (struct dw8250_acpi_desc *)id->driver_data;
if (!acpi_desc)
return 0;
if (acpi_desc->set_termios)
p->set_termios = acpi_desc->set_termios;
return 0;
}
@ -445,12 +514,16 @@ static const struct of_device_id dw8250_of_match[] = {
};
MODULE_DEVICE_TABLE(of, dw8250_of_match);
static struct dw8250_acpi_desc byt_8250_desc = {
.set_termios = byt_set_termios,
};
static const struct acpi_device_id dw8250_acpi_match[] = {
{ "INT33C4", 0 },
{ "INT33C5", 0 },
{ "INT3434", 0 },
{ "INT3435", 0 },
{ "80860F0A", 0 },
{ "80860F0A", (kernel_ulong_t)&byt_8250_desc},
{ },
};
MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);

View File

@ -35,18 +35,8 @@
#include <linux/serial_8250.h>
#include <asm/io.h>
#include <asm/serial.h>
#ifdef CONFIG_FIX_EARLYCON_MEM
#include <asm/pgtable.h>
#include <asm/fixmap.h>
#endif
struct early_serial8250_device {
struct uart_port port;
char options[16]; /* e.g., 115200n8 */
unsigned int baud;
};
static struct early_serial8250_device early_device;
static struct earlycon_device *early_device;
unsigned int __weak __init serial8250_early_in(struct uart_port *port, int offset)
{
@ -100,7 +90,7 @@ static void __init serial_putc(struct uart_port *port, int c)
static void __init early_serial8250_write(struct console *console,
const char *s, unsigned int count)
{
struct uart_port *port = &early_device.port;
struct uart_port *port = &early_device->port;
unsigned int ier;
/* Save the IER and disable interrupts */
@ -129,7 +119,7 @@ static unsigned int __init probe_baud(struct uart_port *port)
return (port->uartclk / 16) / quot;
}
static void __init init_port(struct early_serial8250_device *device)
static void __init init_port(struct earlycon_device *device)
{
struct uart_port *port = &device->port;
unsigned int divisor;
@ -148,128 +138,42 @@ static void __init init_port(struct early_serial8250_device *device)
serial8250_early_out(port, UART_LCR, c & ~UART_LCR_DLAB);
}
static int __init parse_options(struct early_serial8250_device *device,
char *options)
static int __init early_serial8250_setup(struct earlycon_device *device,
const char *options)
{
struct uart_port *port = &device->port;
int mmio, mmio32, length;
if (!options)
return -ENODEV;
port->uartclk = BASE_BAUD * 16;
mmio = !strncmp(options, "mmio,", 5);
mmio32 = !strncmp(options, "mmio32,", 7);
if (mmio || mmio32) {
port->iotype = (mmio ? UPIO_MEM : UPIO_MEM32);
port->mapbase = simple_strtoul(options + (mmio ? 5 : 7),
&options, 0);
if (mmio32)
port->regshift = 2;
#ifdef CONFIG_FIX_EARLYCON_MEM
set_fixmap_nocache(FIX_EARLYCON_MEM_BASE,
port->mapbase & PAGE_MASK);
port->membase =
(void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE);
port->membase += port->mapbase & ~PAGE_MASK;
#else
port->membase = ioremap_nocache(port->mapbase, 64);
if (!port->membase) {
printk(KERN_ERR "%s: Couldn't ioremap 0x%llx\n",
__func__,
(unsigned long long) port->mapbase);
return -ENOMEM;
}
#endif
} else if (!strncmp(options, "io,", 3)) {
port->iotype = UPIO_PORT;
port->iobase = simple_strtoul(options + 3, &options, 0);
mmio = 0;
} else
return -EINVAL;
options = strchr(options, ',');
if (options) {
options++;
device->baud = simple_strtoul(options, NULL, 0);
length = min(strcspn(options, " ") + 1,
(size_t)(sizeof(device->options)));
strlcpy(device->options, options, length);
} else {
device->baud = probe_baud(port);
snprintf(device->options, sizeof(device->options), "%u",
device->baud);
}
if (mmio || mmio32)
printk(KERN_INFO
"Early serial console at MMIO%s 0x%llx (options '%s')\n",
mmio32 ? "32" : "",
(unsigned long long)port->mapbase,
device->options);
else
printk(KERN_INFO
"Early serial console at I/O port 0x%lx (options '%s')\n",
port->iobase,
device->options);
return 0;
}
static struct console early_serial8250_console __initdata = {
.name = "uart",
.write = early_serial8250_write,
.flags = CON_PRINTBUFFER | CON_BOOT,
.index = -1,
};
static int __init early_serial8250_setup(char *options)
{
struct early_serial8250_device *device = &early_device;
int err;
if (device->port.membase || device->port.iobase)
if (!(device->port.membase || device->port.iobase))
return 0;
err = parse_options(device, options);
if (err < 0)
return err;
if (!device->baud)
device->baud = probe_baud(&device->port);
init_port(device);
early_device = device;
device->con->write = early_serial8250_write;
return 0;
}
EARLYCON_DECLARE(uart8250, early_serial8250_setup);
EARLYCON_DECLARE(uart, early_serial8250_setup);
int __init setup_early_serial8250_console(char *cmdline)
{
char *options;
int err;
char match[] = "uart8250";
options = strstr(cmdline, "uart8250,");
if (!options) {
options = strstr(cmdline, "uart,");
if (!options)
return 0;
}
if (cmdline && cmdline[4] == ',')
match[4] = '\0';
options = strchr(cmdline, ',') + 1;
err = early_serial8250_setup(options);
if (err < 0)
return err;
register_console(&early_serial8250_console);
return 0;
return setup_earlycon(cmdline, match, early_serial8250_setup);
}
int serial8250_find_port_for_earlycon(void)
{
struct early_serial8250_device *device = &early_device;
struct uart_port *port = &device->port;
struct earlycon_device *device = early_device;
struct uart_port *port = device ? &device->port : NULL;
int line;
int ret;
if (!device->port.membase && !device->port.iobase)
if (!port || (!port->membase && !port->iobase))
return -ENODEV;
line = serial8250_find_port(port);
@ -284,5 +188,3 @@ int serial8250_find_port_for_earlycon(void)
return ret;
}
early_param("earlycon", setup_early_serial8250_console);

View File

@ -1753,6 +1753,8 @@ pci_wch_ch353_setup(struct serial_private *priv,
#define PCI_VENDOR_ID_ADVANTECH 0x13fe
#define PCI_DEVICE_ID_INTEL_CE4100_UART 0x2e66
#define PCI_DEVICE_ID_ADVANTECH_PCI3620 0x3620
#define PCI_DEVICE_ID_ADVANTECH_PCI3618 0x3618
#define PCI_DEVICE_ID_ADVANTECH_PCIf618 0xf618
#define PCI_DEVICE_ID_TITAN_200I 0x8028
#define PCI_DEVICE_ID_TITAN_400I 0x8048
#define PCI_DEVICE_ID_TITAN_800I 0x8088
@ -1778,6 +1780,7 @@ pci_wch_ch353_setup(struct serial_private *priv,
#define PCI_DEVICE_ID_WCH_CH352_2S 0x3253
#define PCI_DEVICE_ID_WCH_CH353_4S 0x3453
#define PCI_DEVICE_ID_WCH_CH353_2S1PF 0x5046
#define PCI_DEVICE_ID_WCH_CH353_1S1P 0x5053
#define PCI_DEVICE_ID_WCH_CH353_2S1P 0x7053
#define PCI_VENDOR_ID_AGESTAR 0x5372
#define PCI_DEVICE_ID_AGESTAR_9375 0x6872
@ -2410,6 +2413,14 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID,
.setup = pci_omegapci_setup,
},
/* WCH CH353 1S1P card (16550 clone) */
{
.vendor = PCI_VENDOR_ID_WCH,
.device = PCI_DEVICE_ID_WCH_CH353_1S1P,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = pci_wch_ch353_setup,
},
/* WCH CH353 2S1P card (16550 clone) */
{
.vendor = PCI_VENDOR_ID_WCH,
@ -3526,6 +3537,7 @@ static const struct pci_device_id blacklist[] = {
/* multi-io cards handled by parport_serial */
{ PCI_DEVICE(0x4348, 0x7053), }, /* WCH CH353 2S1P */
{ PCI_DEVICE(0x4348, 0x5053), }, /* WCH CH353 1S1P */
};
/*
@ -3880,6 +3892,13 @@ static struct pci_device_id serial_pci_tbl[] = {
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3620,
PCI_DEVICE_ID_ADVANTECH_PCI3620, 0x0001, 0, 0,
pbn_b2_8_921600 },
/* Advantech also use 0x3618 and 0xf618 */
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3618,
PCI_DEVICE_ID_ADVANTECH_PCI3618, PCI_ANY_ID, 0, 0,
pbn_b0_4_921600 },
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCIf618,
PCI_DEVICE_ID_ADVANTECH_PCI3618, PCI_ANY_ID, 0, 0,
pbn_b0_4_921600 },
{ PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
PCI_SUBVENDOR_ID_CONNECT_TECH,
PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,

View File

@ -61,6 +61,7 @@ config SERIAL_8250_CONSOLE
bool "Console on 8250/16550 and compatible serial port"
depends on SERIAL_8250=y
select SERIAL_CORE_CONSOLE
select SERIAL_EARLYCON
---help---
If you say Y here, it will be possible to use a serial port as the
system console (the system console is the device which receives all
@ -90,11 +91,6 @@ config SERIAL_8250_CONSOLE
If unsure, say N.
config FIX_EARLYCON_MEM
bool
depends on X86
default y
config SERIAL_8250_GSC
tristate
depends on SERIAL_8250 && GSC

View File

@ -7,6 +7,13 @@ if TTY
menu "Serial drivers"
depends on HAS_IOMEM
config SERIAL_EARLYCON
bool
help
Support for early consoles with the earlycon parameter. This enables
the console before standard serial driver is probed. The console is
enabled when early_param is processed.
source "drivers/tty/serial/8250/Kconfig"
comment "Non-8250 serial port support"
@ -53,6 +60,7 @@ config SERIAL_AMBA_PL011_CONSOLE
bool "Support for console on AMBA serial port"
depends on SERIAL_AMBA_PL011=y
select SERIAL_CORE_CONSOLE
select SERIAL_EARLYCON
---help---
Say Y here if you wish to use an AMBA PrimeCell UART as the system
console (the system console is the device which receives all kernel
@ -65,6 +73,18 @@ config SERIAL_AMBA_PL011_CONSOLE
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
config SERIAL_EARLYCON_ARM_SEMIHOST
bool "Early console using ARM semihosting"
depends on ARM64 || ARM
select SERIAL_CORE
select SERIAL_CORE_CONSOLE
select SERIAL_EARLYCON
help
Support for early debug console using ARM semihosting. This enables
the console before standard serial driver is probed. This is enabled
with "earlycon=smh" on the kernel command line. The console is
enabled when early_param is processed.
config SERIAL_SB1250_DUART
tristate "BCM1xxx on-chip DUART serial support"
depends on SIBYTE_SB1xxx_SOC=y
@ -97,6 +117,7 @@ config SERIAL_ATMEL
bool "AT91 / AT32 on-chip serial port support"
depends on ARCH_AT91 || AVR32
select SERIAL_CORE
select SERIAL_MCTRL_GPIO
help
This enables the driver for the on-chip UARTs of the Atmel
AT91 and AT32 processors.
@ -1160,6 +1181,16 @@ config SERIAL_SCCNXP_CONSOLE
help
Support for console on SCCNXP serial ports.
config SERIAL_SC16IS7XX
tristate "SC16IS7xx serial support"
depends on I2C
select SERIAL_CORE
select REGMAP_I2C if I2C
help
This selects support for SC16IS7xx serial ports.
Supported ICs are SC16IS740, SC16IS741, SC16IS750, SC16IS752,
SC16IS760 and SC16IS762.
config SERIAL_BFIN_SPORT
tristate "Blackfin SPORT emulate UART"
depends on BLACKFIN
@ -1323,7 +1354,7 @@ config SERIAL_IFX6X60
config SERIAL_PCH_UART
tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) UART"
depends on PCI
depends on PCI && (X86_32 || COMPILE_TEST)
select SERIAL_CORE
help
This driver is for PCH(Platform controller Hub) UART of Intel EG20T
@ -1369,18 +1400,19 @@ config SERIAL_MXS_AUART_CONSOLE
Enable a MXS AUART port to be the system console.
config SERIAL_XILINX_PS_UART
tristate "Xilinx PS UART support"
tristate "Cadence (Xilinx Zynq) UART support"
depends on OF
select SERIAL_CORE
help
This driver supports the Xilinx PS UART port.
This driver supports the Cadence UART. It is found e.g. in Xilinx
Zynq.
config SERIAL_XILINX_PS_UART_CONSOLE
bool "Xilinx PS UART console support"
bool "Cadence UART console support"
depends on SERIAL_XILINX_PS_UART=y
select SERIAL_CORE_CONSOLE
help
Enable a Xilinx PS UART port to be the system console.
Enable a Cadence UART port to be the system console.
config SERIAL_AR933X
tristate "AR933X serial port support"
@ -1479,6 +1511,7 @@ config SERIAL_RP2_NR_UARTS
config SERIAL_FSL_LPUART
tristate "Freescale lpuart serial port support"
depends on HAS_DMA
select SERIAL_CORE
help
Support for the on-chip lpuart on some Freescale SOCs.
@ -1508,6 +1541,20 @@ config SERIAL_ST_ASC_CONSOLE
depends on SERIAL_ST_ASC=y
select SERIAL_CORE_CONSOLE
config SERIAL_MEN_Z135
tristate "MEN 16z135 Support"
select SERIAL_CORE
depends on MCB
help
Say yes here to enable support for the MEN 16z135 High Speed UART IP-Core
on a MCB carrier.
This driver can also be build as a module. If so, the module will be called
men_z135_uart.ko
endmenu
config SERIAL_MCTRL_GPIO
tristate
endif # TTY

View File

@ -5,6 +5,9 @@
obj-$(CONFIG_SERIAL_CORE) += serial_core.o
obj-$(CONFIG_SERIAL_21285) += 21285.o
obj-$(CONFIG_SERIAL_EARLYCON) += earlycon.o
obj-$(CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST) += earlycon-arm-semihost.o
# These Sparc drivers have to appear before others such as 8250
# which share ttySx minor node space. Otherwise console device
# names change and other unplesantries.
@ -48,6 +51,7 @@ obj-$(CONFIG_SERIAL_MPSC) += mpsc.o
obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o
obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o
obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o
obj-$(CONFIG_SERIAL_SC16IS7XX) += sc16is7xx.o
obj-$(CONFIG_SERIAL_JSM) += jsm/
obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o
@ -87,3 +91,7 @@ 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_MEN_Z135) += men_z135_uart.o
# GPIOLIB helpers for modem control lines
obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o

View File

@ -303,7 +303,7 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port *
/* Optionally make use of an RX channel as well */
chan = dma_request_slave_channel(dev, "rx");
if (!chan && plat->dma_rx_param) {
chan = dma_request_channel(mask, plat->dma_filter, plat->dma_rx_param);
@ -2045,6 +2045,34 @@ static struct console amba_console = {
};
#define AMBA_CONSOLE (&amba_console)
static void pl011_putc(struct uart_port *port, int c)
{
while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF)
;
writeb(c, port->membase + UART01x_DR);
while (readl(port->membase + UART01x_FR) & UART01x_FR_BUSY)
;
}
static void pl011_early_write(struct console *con, const char *s, unsigned n)
{
struct earlycon_device *dev = con->data;
uart_console_write(&dev->port, s, n, pl011_putc);
}
static int __init pl011_early_console_setup(struct earlycon_device *device,
const char *opt)
{
if (!device->port.membase)
return -ENODEV;
device->con->write = pl011_early_write;
return 0;
}
EARLYCON_DECLARE(pl011, pl011_early_console_setup);
#else
#define AMBA_CONSOLE NULL
#endif

View File

@ -43,6 +43,9 @@
#include <linux/platform_data/atmel.h>
#include <linux/timer.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/err.h>
#include <linux/irq.h>
#include <asm/io.h>
#include <asm/ioctls.h>
@ -57,6 +60,8 @@
#include <linux/serial_core.h>
#include "serial_mctrl_gpio.h"
static void atmel_start_rx(struct uart_port *port);
static void atmel_stop_rx(struct uart_port *port);
@ -162,8 +167,10 @@ struct atmel_uart_port {
struct circ_buf rx_ring;
struct serial_rs485 rs485; /* rs485 settings */
int rts_gpio; /* optional RTS GPIO */
struct mctrl_gpios *gpios;
int gpio_irq[UART_GPIO_MAX];
unsigned int tx_done_mask;
bool ms_irq_enabled;
bool is_usart; /* usart or uart */
struct timer_list uart_timer; /* uart timer */
int (*prepare_rx)(struct uart_port *port);
@ -237,6 +244,50 @@ static bool atmel_use_dma_rx(struct uart_port *port)
return atmel_port->use_dma_rx;
}
static unsigned int atmel_get_lines_status(struct uart_port *port)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
unsigned int status, ret = 0;
status = UART_GET_CSR(port);
mctrl_gpio_get(atmel_port->gpios, &ret);
if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
UART_GPIO_CTS))) {
if (ret & TIOCM_CTS)
status &= ~ATMEL_US_CTS;
else
status |= ATMEL_US_CTS;
}
if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
UART_GPIO_DSR))) {
if (ret & TIOCM_DSR)
status &= ~ATMEL_US_DSR;
else
status |= ATMEL_US_DSR;
}
if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
UART_GPIO_RI))) {
if (ret & TIOCM_RI)
status &= ~ATMEL_US_RI;
else
status |= ATMEL_US_RI;
}
if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
UART_GPIO_DCD))) {
if (ret & TIOCM_CD)
status &= ~ATMEL_US_DCD;
else
status |= ATMEL_US_DCD;
}
return status;
}
/* Enable or disable the rs485 support */
void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
{
@ -296,17 +347,6 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
unsigned int mode;
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
/*
* AT91RM9200 Errata #39: RTS0 is not internally connected
* to PA21. We need to drive the pin as a GPIO.
*/
if (gpio_is_valid(atmel_port->rts_gpio)) {
if (mctrl & TIOCM_RTS)
gpio_set_value(atmel_port->rts_gpio, 0);
else
gpio_set_value(atmel_port->rts_gpio, 1);
}
if (mctrl & TIOCM_RTS)
control |= ATMEL_US_RTSEN;
else
@ -319,6 +359,8 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
UART_PUT_CR(port, control);
mctrl_gpio_set(atmel_port->gpios, mctrl);
/* Local loopback mode? */
mode = UART_GET_MR(port) & ~ATMEL_US_CHMODE;
if (mctrl & TIOCM_LOOP)
@ -346,7 +388,8 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
*/
static u_int atmel_get_mctrl(struct uart_port *port)
{
unsigned int status, ret = 0;
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
unsigned int ret = 0, status;
status = UART_GET_CSR(port);
@ -362,7 +405,7 @@ static u_int atmel_get_mctrl(struct uart_port *port)
if (!(status & ATMEL_US_RI))
ret |= TIOCM_RI;
return ret;
return mctrl_gpio_get(atmel_port->gpios, &ret);
}
/*
@ -449,8 +492,38 @@ static void atmel_stop_rx(struct uart_port *port)
*/
static void atmel_enable_ms(struct uart_port *port)
{
UART_PUT_IER(port, ATMEL_US_RIIC | ATMEL_US_DSRIC
| ATMEL_US_DCDIC | ATMEL_US_CTSIC);
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
uint32_t ier = 0;
/*
* Interrupt should not be enabled twice
*/
if (atmel_port->ms_irq_enabled)
return;
atmel_port->ms_irq_enabled = true;
if (atmel_port->gpio_irq[UART_GPIO_CTS] >= 0)
enable_irq(atmel_port->gpio_irq[UART_GPIO_CTS]);
else
ier |= ATMEL_US_CTSIC;
if (atmel_port->gpio_irq[UART_GPIO_DSR] >= 0)
enable_irq(atmel_port->gpio_irq[UART_GPIO_DSR]);
else
ier |= ATMEL_US_DSRIC;
if (atmel_port->gpio_irq[UART_GPIO_RI] >= 0)
enable_irq(atmel_port->gpio_irq[UART_GPIO_RI]);
else
ier |= ATMEL_US_RIIC;
if (atmel_port->gpio_irq[UART_GPIO_DCD] >= 0)
enable_irq(atmel_port->gpio_irq[UART_GPIO_DCD]);
else
ier |= ATMEL_US_DCDIC;
UART_PUT_IER(port, ier);
}
/*
@ -1039,11 +1112,31 @@ atmel_handle_status(struct uart_port *port, unsigned int pending,
static irqreturn_t atmel_interrupt(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
unsigned int status, pending, pass_counter = 0;
bool gpio_handled = false;
do {
status = UART_GET_CSR(port);
status = atmel_get_lines_status(port);
pending = status & UART_GET_IMR(port);
if (!gpio_handled) {
/*
* Dealing with GPIO interrupt
*/
if (irq == atmel_port->gpio_irq[UART_GPIO_CTS])
pending |= ATMEL_US_CTSIC;
if (irq == atmel_port->gpio_irq[UART_GPIO_DSR])
pending |= ATMEL_US_DSRIC;
if (irq == atmel_port->gpio_irq[UART_GPIO_RI])
pending |= ATMEL_US_RIIC;
if (irq == atmel_port->gpio_irq[UART_GPIO_DCD])
pending |= ATMEL_US_DCDIC;
gpio_handled = true;
}
if (!pending)
break;
@ -1523,6 +1616,45 @@ static void atmel_get_ip_name(struct uart_port *port)
}
}
static void atmel_free_gpio_irq(struct uart_port *port)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
enum mctrl_gpio_idx i;
for (i = 0; i < UART_GPIO_MAX; i++)
if (atmel_port->gpio_irq[i] >= 0)
free_irq(atmel_port->gpio_irq[i], port);
}
static int atmel_request_gpio_irq(struct uart_port *port)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
int *irq = atmel_port->gpio_irq;
enum mctrl_gpio_idx i;
int err = 0;
for (i = 0; (i < UART_GPIO_MAX) && !err; i++) {
if (irq[i] < 0)
continue;
irq_set_status_flags(irq[i], IRQ_NOAUTOEN);
err = request_irq(irq[i], atmel_interrupt, IRQ_TYPE_EDGE_BOTH,
"atmel_serial", port);
if (err)
dev_err(port->dev, "atmel_startup - Can't get %d irq\n",
irq[i]);
}
/*
* If something went wrong, rollback.
*/
while (err && (--i >= 0))
if (irq[i] >= 0)
free_irq(irq[i], port);
return err;
}
/*
* Perform initialization and enable port for reception
*/
@ -1539,6 +1671,7 @@ static int atmel_startup(struct uart_port *port)
* handle an unexpected interrupt
*/
UART_PUT_IDR(port, -1);
atmel_port->ms_irq_enabled = false;
/*
* Allocate the IRQ
@ -1550,6 +1683,13 @@ static int atmel_startup(struct uart_port *port)
return retval;
}
/*
* Get the GPIO lines IRQ
*/
retval = atmel_request_gpio_irq(port);
if (retval)
goto free_irq;
/*
* Initialize DMA (if necessary)
*/
@ -1568,7 +1708,7 @@ static int atmel_startup(struct uart_port *port)
}
/* Save current CSR for comparison in atmel_tasklet_func() */
atmel_port->irq_status_prev = UART_GET_CSR(port);
atmel_port->irq_status_prev = atmel_get_lines_status(port);
atmel_port->irq_status = atmel_port->irq_status_prev;
/*
@ -1614,6 +1754,11 @@ static int atmel_startup(struct uart_port *port)
}
return 0;
free_irq:
free_irq(port->irq, port);
return retval;
}
/*
@ -1661,9 +1806,12 @@ static void atmel_shutdown(struct uart_port *port)
atmel_port->rx_ring.tail = 0;
/*
* Free the interrupt
* Free the interrupts
*/
free_irq(port->irq, port);
atmel_free_gpio_irq(port);
atmel_port->ms_irq_enabled = false;
}
/*
@ -2324,6 +2472,26 @@ static int atmel_serial_resume(struct platform_device *pdev)
#define atmel_serial_resume NULL
#endif
static int atmel_init_gpios(struct atmel_uart_port *p, struct device *dev)
{
enum mctrl_gpio_idx i;
struct gpio_desc *gpiod;
p->gpios = mctrl_gpio_init(dev, 0);
if (IS_ERR_OR_NULL(p->gpios))
return -1;
for (i = 0; i < UART_GPIO_MAX; i++) {
gpiod = mctrl_gpio_to_gpiod(p->gpios, i);
if (gpiod && (gpiod_get_direction(gpiod) == GPIOF_DIR_IN))
p->gpio_irq[i] = gpiod_to_irq(gpiod);
else
p->gpio_irq[i] = -EINVAL;
}
return 0;
}
static int atmel_serial_probe(struct platform_device *pdev)
{
struct atmel_uart_port *port;
@ -2359,25 +2527,11 @@ static int atmel_serial_probe(struct platform_device *pdev)
port = &atmel_ports[ret];
port->backup_imr = 0;
port->uart.line = ret;
port->rts_gpio = -EINVAL; /* Invalid, zero could be valid */
if (pdata)
port->rts_gpio = pdata->rts_gpio;
else if (np)
port->rts_gpio = of_get_named_gpio(np, "rts-gpios", 0);
if (gpio_is_valid(port->rts_gpio)) {
ret = devm_gpio_request(&pdev->dev, port->rts_gpio, "RTS");
if (ret) {
dev_err(&pdev->dev, "error requesting RTS GPIO\n");
goto err;
}
/* Default to 1 as RTS is active low */
ret = gpio_direction_output(port->rts_gpio, 1);
if (ret) {
dev_err(&pdev->dev, "error setting up RTS GPIO\n");
goto err;
}
}
ret = atmel_init_gpios(port, &pdev->dev);
if (ret < 0)
dev_err(&pdev->dev, "%s",
"Failed to initialize GPIOs. The serial port may not work as expected");
ret = atmel_init_port(port, pdev);
if (ret)

View File

@ -971,7 +971,7 @@ static void cpm_uart_config_port(struct uart_port *port, int flags)
* Note that this is called with interrupts already disabled
*/
static void cpm_uart_early_write(struct uart_cpm_port *pinfo,
const char *string, u_int count)
const char *string, u_int count, bool handle_linefeed)
{
unsigned int i;
cbd_t __iomem *bdp, *bdbase;
@ -1013,7 +1013,7 @@ static void cpm_uart_early_write(struct uart_cpm_port *pinfo,
bdp++;
/* if a LF, also do CR... */
if (*string == 10) {
if (handle_linefeed && *string == 10) {
while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0)
;
@ -1111,7 +1111,7 @@ static void cpm_put_poll_char(struct uart_port *port,
static char ch[2];
ch[0] = (char)c;
cpm_uart_early_write(pinfo, ch, 1);
cpm_uart_early_write(pinfo, ch, 1, false);
}
#endif /* CONFIG_CONSOLE_POLL */
@ -1275,7 +1275,7 @@ static void cpm_uart_console_write(struct console *co, const char *s,
spin_lock_irqsave(&pinfo->port.lock, flags);
}
cpm_uart_early_write(pinfo, s, count);
cpm_uart_early_write(pinfo, s, count, true);
if (unlikely(nolock)) {
local_irq_restore(flags);

View File

@ -0,0 +1,61 @@
/*
* Copyright (C) 2012 ARM Ltd.
* Author: Marc Zyngier <marc.zyngier@arm.com>
*
* Adapted for ARM and earlycon:
* Copyright (C) 2014 Linaro Ltd.
* Author: Rob Herring <robh@kernel.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
#include <linux/console.h>
#include <linux/init.h>
#include <linux/serial_core.h>
#ifdef CONFIG_THUMB2_KERNEL
#define SEMIHOST_SWI "0xab"
#else
#define SEMIHOST_SWI "0x123456"
#endif
/*
* Semihosting-based debug console
*/
static void smh_putc(struct uart_port *port, int c)
{
#ifdef CONFIG_ARM64
asm volatile("mov x1, %0\n"
"mov x0, #3\n"
"hlt 0xf000\n"
: : "r" (&c) : "x0", "x1", "memory");
#else
asm volatile("mov r1, %0\n"
"mov r0, #3\n"
"svc " SEMIHOST_SWI "\n"
: : "r" (&c) : "r0", "r1", "memory");
#endif
}
static void smh_write(struct console *con, const char *s, unsigned n)
{
struct earlycon_device *dev = con->data;
uart_console_write(&dev->port, s, n, smh_putc);
}
int __init early_smh_setup(struct earlycon_device *device, const char *opt)
{
device->con->write = smh_write;
return 0;
}
EARLYCON_DECLARE(smh, early_smh_setup);

View File

@ -0,0 +1,144 @@
/*
* Copyright (C) 2014 Linaro Ltd.
* Author: Rob Herring <robh@kernel.org>
*
* Based on 8250 earlycon:
* (c) Copyright 2004 Hewlett-Packard Development Company, L.P.
* Bjorn Helgaas <bjorn.helgaas@hp.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/console.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/serial_core.h>
#ifdef CONFIG_FIX_EARLYCON_MEM
#include <asm/fixmap.h>
#endif
#include <asm/serial.h>
static struct console early_con = {
.name = "earlycon",
.flags = CON_PRINTBUFFER | CON_BOOT,
.index = -1,
};
static struct earlycon_device early_console_dev = {
.con = &early_con,
};
static void __iomem * __init earlycon_map(unsigned long paddr, size_t size)
{
void __iomem *base;
#ifdef CONFIG_FIX_EARLYCON_MEM
set_fixmap_io(FIX_EARLYCON_MEM_BASE, paddr & PAGE_MASK);
base = (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE);
base += paddr & ~PAGE_MASK;
#else
base = ioremap(paddr, size);
#endif
if (!base)
pr_err("%s: Couldn't map 0x%llx\n", __func__,
(unsigned long long)paddr);
return base;
}
static int __init parse_options(struct earlycon_device *device,
char *options)
{
struct uart_port *port = &device->port;
int mmio, mmio32, length;
unsigned long addr;
if (!options)
return -ENODEV;
mmio = !strncmp(options, "mmio,", 5);
mmio32 = !strncmp(options, "mmio32,", 7);
if (mmio || mmio32) {
port->iotype = (mmio ? UPIO_MEM : UPIO_MEM32);
options += mmio ? 5 : 7;
addr = simple_strtoul(options, NULL, 0);
port->mapbase = addr;
if (mmio32)
port->regshift = 2;
} else if (!strncmp(options, "io,", 3)) {
port->iotype = UPIO_PORT;
options += 3;
addr = simple_strtoul(options, NULL, 0);
port->iobase = addr;
mmio = 0;
} else if (!strncmp(options, "0x", 2)) {
port->iotype = UPIO_MEM;
addr = simple_strtoul(options, NULL, 0);
port->mapbase = addr;
} else {
return -EINVAL;
}
port->uartclk = BASE_BAUD * 16;
options = strchr(options, ',');
if (options) {
options++;
device->baud = simple_strtoul(options, NULL, 0);
length = min(strcspn(options, " ") + 1,
(size_t)(sizeof(device->options)));
strlcpy(device->options, options, length);
}
if (mmio || mmio32)
pr_info("Early serial console at MMIO%s 0x%llx (options '%s')\n",
mmio32 ? "32" : "",
(unsigned long long)port->mapbase,
device->options);
else
pr_info("Early serial console at I/O port 0x%lx (options '%s')\n",
port->iobase,
device->options);
return 0;
}
int __init setup_earlycon(char *buf, const char *match,
int (*setup)(struct earlycon_device *, const char *))
{
int err;
size_t len;
struct uart_port *port = &early_console_dev.port;
if (!buf || !match || !setup)
return 0;
len = strlen(match);
if (strncmp(buf, match, len))
return 0;
if (buf[len] && (buf[len] != ','))
return 0;
buf += len + 1;
err = parse_options(&early_console_dev, buf);
/* On parsing error, pass the options buf to the setup function */
if (!err)
buf = NULL;
if (port->mapbase)
port->membase = earlycon_map(port->mapbase, 64);
early_console_dev.con->data = &early_console_dev;
err = setup(&early_console_dev, buf);
if (err < 0)
return err;
if (!early_console_dev.con->write)
return -ENODEV;
register_console(early_console_dev.con);
return 0;
}

View File

@ -842,6 +842,7 @@ static void __exit efm32_uart_exit(void)
platform_driver_unregister(&efm32_uart_driver);
uart_unregister_driver(&efm32_uart_reg);
}
module_exit(efm32_uart_exit);
MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
MODULE_DESCRIPTION("EFM32 UART/USART driver");

View File

@ -116,7 +116,7 @@
#define UCR3_DSR (1<<10) /* Data set ready */
#define UCR3_DCD (1<<9) /* Data carrier detect */
#define UCR3_RI (1<<8) /* Ring indicator */
#define UCR3_TIMEOUTEN (1<<7) /* Timeout interrupt enable */
#define UCR3_ADNIMP (1<<7) /* Autobaud Detection Not Improved */
#define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */
#define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */
#define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */
@ -444,6 +444,10 @@ static void imx_stop_rx(struct uart_port *port)
temp = readl(sport->port.membase + UCR2);
writel(temp & ~UCR2_RXEN, sport->port.membase + UCR2);
/* disable the `Receiver Ready Interrrupt` */
temp = readl(sport->port.membase + UCR1);
writel(temp & ~UCR1_RRDYEN, sport->port.membase + UCR1);
}
/*
@ -1070,7 +1074,7 @@ static void imx_disable_dma(struct imx_port *sport)
static int imx_startup(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
int retval;
int retval, i;
unsigned long flags, temp;
retval = clk_prepare_enable(sport->clk_per);
@ -1098,17 +1102,15 @@ static int imx_startup(struct uart_port *port)
writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
if (USE_IRDA(sport)) {
/* reset fifo's and state machines */
int i = 100;
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);
}
}
/* Reset fifo's and state machines */
i = 100;
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);
/*
* Allocate the IRQ(s) i.MX1 has three interrupts whereas later
@ -1163,18 +1165,9 @@ static int imx_startup(struct uart_port *port)
temp |= UCR2_IRTS;
writel(temp, sport->port.membase + UCR2);
if (USE_IRDA(sport)) {
/* clear RX-FIFO */
int i = 64;
while ((--i > 0) &&
(readl(sport->port.membase + URXD0) & URXD_CHARRDY)) {
barrier();
}
}
if (!is_imx1_uart(sport)) {
temp = readl(sport->port.membase + UCR3);
temp |= IMX21_UCR3_RXDMUXSEL;
temp |= IMX21_UCR3_RXDMUXSEL | UCR3_ADNIMP;
writel(temp, sport->port.membase + UCR3);
}

View File

@ -44,13 +44,22 @@ MODULE_PARM_DESC(magic, "magic sequence to enter NMI debugger (default $3#33)");
static bool kgdb_nmi_tty_enabled;
static int kgdb_nmi_console_setup(struct console *co, char *options)
{
/* The NMI console uses the dbg_io_ops to issue console messages. To
* avoid duplicate messages during kdb sessions we must inform kdb's
* I/O utilities that messages sent to the console will automatically
* be displayed on the dbg_io.
*/
dbg_io_ops->is_console = true;
return 0;
}
static void kgdb_nmi_console_write(struct console *co, const char *s, uint c)
{
int i;
if (!kgdb_nmi_tty_enabled || atomic_read(&kgdb_active) >= 0)
return;
for (i = 0; i < c; i++)
dbg_io_ops->write_char(s[i]);
}
@ -65,6 +74,7 @@ static struct tty_driver *kgdb_nmi_console_device(struct console *co, int *idx)
static struct console kgdb_nmi_console = {
.name = "ttyNMI",
.setup = kgdb_nmi_console_setup,
.write = kgdb_nmi_console_write,
.device = kgdb_nmi_console_device,
.flags = CON_PRINTBUFFER | CON_ANYTIME | CON_ENABLED,
@ -80,29 +90,10 @@ static struct console kgdb_nmi_console = {
struct kgdb_nmi_tty_priv {
struct tty_port port;
struct tasklet_struct tlet;
struct timer_list timer;
STRUCT_KFIFO(char, KGDB_NMI_FIFO_SIZE) fifo;
};
static struct kgdb_nmi_tty_priv *kgdb_nmi_port_to_priv(struct tty_port *port)
{
return container_of(port, struct kgdb_nmi_tty_priv, port);
}
/*
* Our debugging console is polled in a tasklet, so we'll check for input
* every tick. In HZ-less mode, we should program the next tick. We have
* to use the lowlevel stuff as no locks should be grabbed.
*/
#ifdef CONFIG_HIGH_RES_TIMERS
static void kgdb_tty_poke(void)
{
tick_program_event(ktime_get(), 0);
}
#else
static inline void kgdb_tty_poke(void) {}
#endif
static struct tty_port *kgdb_nmi_port;
static void kgdb_tty_recv(int ch)
@ -113,14 +104,13 @@ static void kgdb_tty_recv(int ch)
if (!kgdb_nmi_port || ch < 0)
return;
/*
* Can't use port->tty->driver_data as tty might be not there. Tasklet
* Can't use port->tty->driver_data as tty might be not there. Timer
* will check for tty and will get the ref, but here we don't have to
* do that, and actually, we can't: we're in NMI context, no locks are
* possible.
*/
priv = kgdb_nmi_port_to_priv(kgdb_nmi_port);
priv = container_of(kgdb_nmi_port, struct kgdb_nmi_tty_priv, port);
kfifo_in(&priv->fifo, &c, 1);
kgdb_tty_poke();
}
static int kgdb_nmi_poll_one_knock(void)
@ -204,7 +194,8 @@ static void kgdb_nmi_tty_receiver(unsigned long data)
struct kgdb_nmi_tty_priv *priv = (void *)data;
char ch;
tasklet_schedule(&priv->tlet);
priv->timer.expires = jiffies + (HZ/100);
add_timer(&priv->timer);
if (likely(!kgdb_nmi_tty_enabled || !kfifo_len(&priv->fifo)))
return;
@ -216,18 +207,22 @@ static void kgdb_nmi_tty_receiver(unsigned long data)
static int kgdb_nmi_tty_activate(struct tty_port *port, struct tty_struct *tty)
{
struct kgdb_nmi_tty_priv *priv = tty->driver_data;
struct kgdb_nmi_tty_priv *priv =
container_of(port, struct kgdb_nmi_tty_priv, port);
kgdb_nmi_port = port;
tasklet_schedule(&priv->tlet);
priv->timer.expires = jiffies + (HZ/100);
add_timer(&priv->timer);
return 0;
}
static void kgdb_nmi_tty_shutdown(struct tty_port *port)
{
struct kgdb_nmi_tty_priv *priv = port->tty->driver_data;
struct kgdb_nmi_tty_priv *priv =
container_of(port, struct kgdb_nmi_tty_priv, port);
tasklet_kill(&priv->tlet);
del_timer(&priv->timer);
kgdb_nmi_port = NULL;
}
@ -246,7 +241,7 @@ static int kgdb_nmi_tty_install(struct tty_driver *drv, struct tty_struct *tty)
return -ENOMEM;
INIT_KFIFO(priv->fifo);
tasklet_init(&priv->tlet, kgdb_nmi_tty_receiver, (unsigned long)priv);
setup_timer(&priv->timer, kgdb_nmi_tty_receiver, (unsigned long)priv);
tty_port_init(&priv->port);
priv->port.ops = &kgdb_nmi_tty_port_ops;
tty->driver_data = priv;

View File

@ -0,0 +1,867 @@
/*
* MEN 16z135 High Speed UART
*
* Copyright (C) 2014 MEN Mikroelektronik GmbH (www.men.de)
* Author: Johannes Thumshirn <johannes.thumshirn@men.de>
*
* 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ":" fmt
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/serial_core.h>
#include <linux/ioport.h>
#include <linux/io.h>
#include <linux/tty_flip.h>
#include <linux/bitops.h>
#include <linux/mcb.h>
#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
#define MEN_Z135_RX_RAM 0x4
#define MEN_Z135_TX_RAM 0x400
#define MEN_Z135_RX_CTRL 0x800
#define MEN_Z135_TX_CTRL 0x804
#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_MEM_SIZE 0x818
#define IS_IRQ(x) ((x) & 1)
#define IRQ_ID(x) (((x) >> 1) & 7)
#define MEN_Z135_IER_RXCIEN BIT(0) /* RX Space IRQ */
#define MEN_Z135_IER_TXCIEN BIT(1) /* TX Space IRQ */
#define MEN_Z135_IER_RLSIEN BIT(2) /* Receiver Line Status IRQ */
#define MEN_Z135_IER_MSIEN BIT(3) /* Modem Status IRQ */
#define MEN_Z135_ALL_IRQS (MEN_Z135_IER_RXCIEN \
| MEN_Z135_IER_RLSIEN \
| MEN_Z135_IER_MSIEN \
| MEN_Z135_IER_TXCIEN)
#define MEN_Z135_MCR_DTR BIT(24)
#define MEN_Z135_MCR_RTS BIT(25)
#define MEN_Z135_MCR_OUT1 BIT(26)
#define MEN_Z135_MCR_OUT2 BIT(27)
#define MEN_Z135_MCR_LOOP BIT(28)
#define MEN_Z135_MCR_RCFC BIT(29)
#define MEN_Z135_MSR_DCTS BIT(0)
#define MEN_Z135_MSR_DDSR BIT(1)
#define MEN_Z135_MSR_DRI BIT(2)
#define MEN_Z135_MSR_DDCD BIT(3)
#define MEN_Z135_MSR_CTS BIT(4)
#define MEN_Z135_MSR_DSR BIT(5)
#define MEN_Z135_MSR_RI BIT(6)
#define MEN_Z135_MSR_DCD BIT(7)
#define MEN_Z135_LCR_SHIFT 8 /* LCR shift mask */
#define MEN_Z135_WL5 0 /* CS5 */
#define MEN_Z135_WL6 1 /* CS6 */
#define MEN_Z135_WL7 2 /* CS7 */
#define MEN_Z135_WL8 3 /* CS8 */
#define MEN_Z135_STB_SHIFT 2 /* Stopbits */
#define MEN_Z135_NSTB1 0
#define MEN_Z135_NSTB2 1
#define MEN_Z135_PEN_SHIFT 3 /* Parity enable */
#define MEN_Z135_PAR_DIS 0
#define MEN_Z135_PAR_ENA 1
#define MEN_Z135_PTY_SHIFT 4 /* Parity type */
#define MEN_Z135_PTY_ODD 0
#define MEN_Z135_PTY_EVN 1
#define MEN_Z135_LSR_DR BIT(0)
#define MEN_Z135_LSR_OE BIT(1)
#define MEN_Z135_LSR_PE BIT(2)
#define MEN_Z135_LSR_FE BIT(3)
#define MEN_Z135_LSR_BI BIT(4)
#define MEN_Z135_LSR_THEP BIT(5)
#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 LCR(x) (((x) >> MEN_Z135_LCR_SHIFT) & 0xff)
#define BYTES_TO_ALIGN(x) ((x) & 0x3)
static int line;
static int txlvl = 5;
module_param(txlvl, int, S_IRUGO);
MODULE_PARM_DESC(txlvl, "TX IRQ trigger level 0-7, default 5 (128 byte)");
static int rxlvl = 6;
module_param(rxlvl, int, S_IRUGO);
MODULE_PARM_DESC(rxlvl, "RX IRQ trigger level 0-7, default 6 (256 byte)");
static int align;
module_param(align, int, S_IRUGO);
MODULE_PARM_DESC(align, "Keep hardware FIFO write pointer aligned, default 0");
struct men_z135_port {
struct uart_port port;
struct mcb_device *mdev;
unsigned char *rxbuf;
u32 stat_reg;
spinlock_t lock;
};
#define to_men_z135(port) container_of((port), struct men_z135_port, port)
/**
* men_z135_reg_set() - Set value in register
* @uart: The UART port
* @addr: Register address
* @val: value to set
*/
static inline void men_z135_reg_set(struct men_z135_port *uart,
u32 addr, u32 val)
{
struct uart_port *port = &uart->port;
unsigned long flags;
u32 reg;
spin_lock_irqsave(&uart->lock, flags);
reg = ioread32(port->membase + addr);
reg |= val;
iowrite32(reg, port->membase + addr);
spin_unlock_irqrestore(&uart->lock, flags);
}
/**
* men_z135_reg_clr() - Unset value in register
* @uart: The UART port
* @addr: Register address
* @val: value to clear
*/
static inline void men_z135_reg_clr(struct men_z135_port *uart,
u32 addr, u32 val)
{
struct uart_port *port = &uart->port;
unsigned long flags;
u32 reg;
spin_lock_irqsave(&uart->lock, flags);
reg = ioread32(port->membase + addr);
reg &= ~val;
iowrite32(reg, port->membase + addr);
spin_unlock_irqrestore(&uart->lock, flags);
}
/**
* men_z135_handle_modem_status() - Handle change of modem status
* @port: The UART port
*
* Handle change of modem status register. This is done by reading the "delta"
* versions of DCD (Data Carrier Detect) and CTS (Clear To Send).
*/
static void men_z135_handle_modem_status(struct men_z135_port *uart)
{
if (uart->stat_reg & 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)
uart_handle_cts_change(&uart->port,
uart->stat_reg & ~MEN_Z135_MSR_CTS);
}
static void men_z135_handle_lsr(struct men_z135_port *uart)
{
struct uart_port *port = &uart->port;
u8 lsr;
lsr = (uart->stat_reg >> 16) & 0xff;
if (lsr & MEN_Z135_LSR_OE)
port->icount.overrun++;
if (lsr & MEN_Z135_LSR_PE)
port->icount.parity++;
if (lsr & MEN_Z135_LSR_FE)
port->icount.frame++;
if (lsr & MEN_Z135_LSR_BI) {
port->icount.brk++;
uart_handle_break(port);
}
}
/**
* get_rx_fifo_content() - Get the number of bytes in RX FIFO
* @uart: The UART port
*
* Read RXC register from hardware and return current FIFO fill size.
*/
static u16 get_rx_fifo_content(struct men_z135_port *uart)
{
struct uart_port *port = &uart->port;
u32 stat_reg;
u16 rxc;
u8 rxc_lo;
u8 rxc_hi;
stat_reg = ioread32(port->membase + MEN_Z135_STAT_REG);
rxc_lo = stat_reg >> 24;
rxc_hi = (stat_reg & 0xC0) >> 6;
rxc = rxc_lo | (rxc_hi << 8);
return rxc;
}
/**
* men_z135_handle_rx() - RX tasklet routine
* @arg: Pointer to struct men_z135_port
*
* Copy from RX FIFO and acknowledge number of bytes copied.
*/
static void men_z135_handle_rx(struct men_z135_port *uart)
{
struct uart_port *port = &uart->port;
struct tty_port *tport = &port->state->port;
int copied;
u16 size;
int room;
size = get_rx_fifo_content(uart);
if (size == 0)
return;
/* Avoid accidently accessing TX FIFO instead of RX FIFO. Last
* longword in RX FIFO cannot be read.(0x004-0x3FF)
*/
if (size > MEN_Z135_FIFO_WATERMARK)
size = MEN_Z135_FIFO_WATERMARK;
room = tty_buffer_request_room(tport, size);
if (room != size)
dev_warn(&uart->mdev->dev,
"Not enough room in flip buffer, truncating to %d\n",
room);
if (room == 0)
return;
memcpy_fromio(uart->rxbuf, port->membase + MEN_Z135_RX_RAM, room);
/* Be sure to first copy all data and then acknowledge it */
mb();
iowrite32(room, port->membase + MEN_Z135_RX_CTRL);
copied = tty_insert_flip_string(tport, uart->rxbuf, room);
if (copied != room)
dev_warn(&uart->mdev->dev,
"Only copied %d instead of %d bytes\n",
copied, room);
port->icount.rx += copied;
tty_flip_buffer_push(tport);
}
/**
* men_z135_handle_tx() - TX tasklet routine
* @arg: Pointer to struct men_z135_port
*
*/
static void men_z135_handle_tx(struct men_z135_port *uart)
{
struct uart_port *port = &uart->port;
struct circ_buf *xmit = &port->state->xmit;
u32 txc;
u32 wptr;
int qlen;
int n;
int txfree;
int head;
int tail;
int s;
if (uart_circ_empty(xmit))
goto out;
if (uart_tx_stopped(port))
goto out;
if (port->x_char)
goto out;
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
/* calculate bytes to copy */
qlen = uart_circ_chars_pending(xmit);
if (qlen <= 0)
goto out;
wptr = ioread32(port->membase + MEN_Z135_TX_CTRL);
txc = (wptr >> 16) & 0x3ff;
wptr &= 0x3ff;
if (txc > MEN_Z135_FIFO_WATERMARK)
txc = MEN_Z135_FIFO_WATERMARK;
txfree = MEN_Z135_FIFO_WATERMARK - txc;
if (txfree <= 0) {
pr_err("Not enough room in TX FIFO have %d, need %d\n",
txfree, qlen);
goto irq_en;
}
/* if we're not aligned, it's better to copy only 1 or 2 bytes and
* then the rest.
*/
if (align && qlen >= 3 && BYTES_TO_ALIGN(wptr))
n = 4 - BYTES_TO_ALIGN(wptr);
else if (qlen > txfree)
n = txfree;
else
n = qlen;
if (n <= 0)
goto irq_en;
head = xmit->head & (UART_XMIT_SIZE - 1);
tail = xmit->tail & (UART_XMIT_SIZE - 1);
s = ((head >= tail) ? head : UART_XMIT_SIZE) - tail;
n = min(n, s);
memcpy_toio(port->membase + MEN_Z135_TX_RAM, &xmit->buf[xmit->tail], n);
xmit->tail = (xmit->tail + n) & (UART_XMIT_SIZE - 1);
mmiowb();
iowrite32(n & 0x3ff, port->membase + MEN_Z135_TX_CTRL);
port->icount.tx += n;
irq_en:
if (!uart_circ_empty(xmit))
men_z135_reg_set(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN);
else
men_z135_reg_clr(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN);
out:
return;
}
/**
* men_z135_intr() - Handle legacy IRQs
* @irq: The IRQ number
* @data: Pointer to UART port
*
* Check IIR register to see which tasklet to start.
*/
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;
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:
men_z135_handle_lsr(uart);
break;
default:
dev_warn(&uart->mdev->dev, "Unknown IRQ id %d\n", irq_id);
return IRQ_NONE;
}
return IRQ_HANDLED;
}
/**
* men_z135_request_irq() - Request IRQ for 16z135 core
* @uart: z135 private uart port structure
*
* Request an IRQ for 16z135 to use. First try using MSI, if it fails
* fall back to using legacy interrupts.
*/
static int men_z135_request_irq(struct men_z135_port *uart)
{
struct device *dev = &uart->mdev->dev;
struct uart_port *port = &uart->port;
int err = 0;
err = request_irq(port->irq, men_z135_intr, IRQF_SHARED,
"men_z135_intr", uart);
if (err)
dev_err(dev, "Error %d getting interrupt\n", err);
return err;
}
/**
* men_z135_tx_empty() - Handle tx_empty call
* @port: The UART port
*
* This function tests whether the TX FIFO and shifter for the port
* described by @port is empty.
*/
static unsigned int men_z135_tx_empty(struct uart_port *port)
{
u32 wptr;
u16 txc;
wptr = ioread32(port->membase + MEN_Z135_TX_CTRL);
txc = (wptr >> 16) & 0x3ff;
if (txc == 0)
return TIOCSER_TEMT;
else
return 0;
}
/**
* men_z135_set_mctrl() - Set modem control lines
* @port: The UART port
* @mctrl: The modem control lines
*
* This function sets the modem control lines for a port described by @port
* to the state described by @mctrl
*/
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;
if (mctrl & TIOCM_RTS)
conf_reg |= MEN_Z135_MCR_RTS;
if (mctrl & TIOCM_DTR)
conf_reg |= MEN_Z135_MCR_DTR;
if (mctrl & TIOCM_OUT1)
conf_reg |= MEN_Z135_MCR_OUT1;
if (mctrl & TIOCM_OUT2)
conf_reg |= MEN_Z135_MCR_OUT2;
if (mctrl & TIOCM_LOOP)
conf_reg |= MEN_Z135_MCR_LOOP;
men_z135_reg_set(uart, MEN_Z135_CONF_REG, conf_reg);
}
/**
* men_z135_get_mctrl() - Get modem control lines
* @port: The UART port
*
* Retruns the current state of modem control inputs.
*/
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);
if (msr & MEN_Z135_MSR_CTS)
mctrl |= TIOCM_CTS;
if (msr & MEN_Z135_MSR_DSR)
mctrl |= TIOCM_DSR;
if (msr & MEN_Z135_MSR_RI)
mctrl |= TIOCM_RI;
if (msr & MEN_Z135_MSR_DCD)
mctrl |= TIOCM_CAR;
return mctrl;
}
/**
* men_z135_stop_tx() - Stop transmitting characters
* @port: The UART port
*
* Stop transmitting characters. This might be due to CTS line becomming
* inactive or the tty layer indicating we want to stop transmission due to
* an XOFF character.
*/
static void men_z135_stop_tx(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_TXCIEN);
}
/**
* men_z135_start_tx() - Start transmitting characters
* @port: The UART port
*
* Start transmitting character. This actually doesn't transmit anything, but
* fires off the TX tasklet.
*/
static void men_z135_start_tx(struct uart_port *port)
{
struct men_z135_port *uart = to_men_z135(port);
men_z135_handle_tx(uart);
}
/**
* men_z135_stop_rx() - Stop receiving characters
* @port: The UART port
*
* Stop receiving characters; the port is in the process of being closed.
*/
static void men_z135_stop_rx(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_RXCIEN);
}
/**
* men_z135_enable_ms() - Enable Modem Status
* port:
*
* Enable Modem Status IRQ.
*/
static void men_z135_enable_ms(struct uart_port *port)
{
struct men_z135_port *uart = to_men_z135(port);
men_z135_reg_set(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_MSIEN);
}
static int men_z135_startup(struct uart_port *port)
{
struct men_z135_port *uart = to_men_z135(port);
int err;
u32 conf_reg = 0;
err = men_z135_request_irq(uart);
if (err)
return -ENODEV;
conf_reg = ioread32(port->membase + MEN_Z135_CONF_REG);
/* Activate all but TX space available IRQ */
conf_reg |= MEN_Z135_ALL_IRQS & ~MEN_Z135_IER_TXCIEN;
conf_reg &= ~(0xff << 16);
conf_reg |= (txlvl << 16);
conf_reg |= (rxlvl << 20);
iowrite32(conf_reg, port->membase + MEN_Z135_CONF_REG);
return 0;
}
static void men_z135_shutdown(struct uart_port *port)
{
struct men_z135_port *uart = to_men_z135(port);
u32 conf_reg = 0;
conf_reg |= MEN_Z135_ALL_IRQS;
men_z135_reg_clr(uart, MEN_Z135_CONF_REG, conf_reg);
free_irq(uart->port.irq, uart);
}
static void men_z135_set_termios(struct uart_port *port,
struct ktermios *termios,
struct ktermios *old)
{
unsigned int baud;
u32 conf_reg;
u32 bd_reg;
u32 uart_freq;
u8 lcr;
conf_reg = ioread32(port->membase + MEN_Z135_CONF_REG);
lcr = LCR(conf_reg);
/* byte size */
switch (termios->c_cflag & CSIZE) {
case CS5:
lcr |= MEN_Z135_WL5;
break;
case CS6:
lcr |= MEN_Z135_WL6;
break;
case CS7:
lcr |= MEN_Z135_WL7;
break;
case CS8:
lcr |= MEN_Z135_WL8;
break;
}
/* stop bits */
if (termios->c_cflag & CSTOPB)
lcr |= MEN_Z135_NSTB2 << MEN_Z135_STB_SHIFT;
/* parity */
if (termios->c_cflag & PARENB) {
lcr |= MEN_Z135_PAR_ENA << MEN_Z135_PEN_SHIFT;
if (termios->c_cflag & PARODD)
lcr |= MEN_Z135_PTY_ODD << MEN_Z135_PTY_SHIFT;
else
lcr |= MEN_Z135_PTY_EVN << MEN_Z135_PTY_SHIFT;
} else
lcr |= MEN_Z135_PAR_DIS << MEN_Z135_PEN_SHIFT;
termios->c_cflag &= ~CMSPAR; /* Mark/Space parity is not supported */
conf_reg |= lcr << MEN_Z135_LCR_SHIFT;
iowrite32(conf_reg, port->membase + MEN_Z135_CONF_REG);
uart_freq = ioread32(port->membase + MEN_Z135_UART_FREQ);
if (uart_freq == 0)
uart_freq = MEN_Z135_BASECLK;
baud = uart_get_baud_rate(port, termios, old, 0, uart_freq / 16);
spin_lock(&port->lock);
if (tty_termios_baud_rate(termios))
tty_termios_encode_baud_rate(termios, baud, baud);
bd_reg = uart_freq / (4 * baud);
iowrite32(bd_reg, port->membase + MEN_Z135_BAUD_REG);
uart_update_timeout(port, termios->c_cflag, baud);
spin_unlock(&port->lock);
}
static const char *men_z135_type(struct uart_port *port)
{
return KBUILD_MODNAME;
}
static void men_z135_release_port(struct uart_port *port)
{
iounmap(port->membase);
port->membase = NULL;
release_mem_region(port->mapbase, MEN_Z135_MEM_SIZE);
}
static int men_z135_request_port(struct uart_port *port)
{
int size = MEN_Z135_MEM_SIZE;
if (!request_mem_region(port->mapbase, size, "men_z135_port"))
return -EBUSY;
port->membase = ioremap(port->mapbase, MEN_Z135_MEM_SIZE);
if (port->membase == NULL) {
release_mem_region(port->mapbase, MEN_Z135_MEM_SIZE);
return -ENOMEM;
}
return 0;
}
static void men_z135_config_port(struct uart_port *port, int type)
{
port->type = PORT_MEN_Z135;
men_z135_request_port(port);
}
static int men_z135_verify_port(struct uart_port *port,
struct serial_struct *serinfo)
{
return -EINVAL;
}
static struct uart_ops men_z135_ops = {
.tx_empty = men_z135_tx_empty,
.set_mctrl = men_z135_set_mctrl,
.get_mctrl = men_z135_get_mctrl,
.stop_tx = men_z135_stop_tx,
.start_tx = men_z135_start_tx,
.stop_rx = men_z135_stop_rx,
.enable_ms = men_z135_enable_ms,
.startup = men_z135_startup,
.shutdown = men_z135_shutdown,
.set_termios = men_z135_set_termios,
.type = men_z135_type,
.release_port = men_z135_release_port,
.request_port = men_z135_request_port,
.config_port = men_z135_config_port,
.verify_port = men_z135_verify_port,
};
static struct uart_driver men_z135_driver = {
.owner = THIS_MODULE,
.driver_name = KBUILD_MODNAME,
.dev_name = "ttyHSU",
.major = 0,
.minor = 0,
.nr = MEN_Z135_MAX_PORTS,
};
/**
* men_z135_probe() - Probe a z135 instance
* @mdev: The MCB device
* @id: The MCB device ID
*
* men_z135_probe does the basic setup of hardware resources and registers the
* new uart port to the tty layer.
*/
static int men_z135_probe(struct mcb_device *mdev,
const struct mcb_device_id *id)
{
struct men_z135_port *uart;
struct resource *mem;
struct device *dev;
int err;
dev = &mdev->dev;
uart = devm_kzalloc(dev, sizeof(struct men_z135_port), GFP_KERNEL);
if (!uart)
return -ENOMEM;
uart->rxbuf = (unsigned char *)__get_free_page(GFP_KERNEL);
if (!uart->rxbuf)
return -ENOMEM;
mem = &mdev->mem;
mcb_set_drvdata(mdev, uart);
uart->port.uartclk = MEN_Z135_BASECLK * 16;
uart->port.fifosize = MEN_Z135_FIFO_SIZE;
uart->port.iotype = UPIO_MEM;
uart->port.ops = &men_z135_ops;
uart->port.irq = mcb_get_irq(mdev);
uart->port.iotype = UPIO_MEM;
uart->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
uart->port.line = line++;
uart->port.dev = dev;
uart->port.type = PORT_MEN_Z135;
uart->port.mapbase = mem->start;
uart->port.membase = NULL;
uart->mdev = mdev;
spin_lock_init(&uart->port.lock);
spin_lock_init(&uart->lock);
err = uart_add_one_port(&men_z135_driver, &uart->port);
if (err)
goto err;
return 0;
err:
free_page((unsigned long) uart->rxbuf);
dev_err(dev, "Failed to add UART: %d\n", err);
return err;
}
/**
* men_z135_remove() - Remove a z135 instance from the system
*
* @mdev: The MCB device
*/
static void men_z135_remove(struct mcb_device *mdev)
{
struct men_z135_port *uart = mcb_get_drvdata(mdev);
line--;
uart_remove_one_port(&men_z135_driver, &uart->port);
free_page((unsigned long) uart->rxbuf);
}
static const struct mcb_device_id men_z135_ids[] = {
{ .device = 0x87 },
};
MODULE_DEVICE_TABLE(mcb, men_z135_ids);
static struct mcb_driver mcb_driver = {
.driver = {
.name = "z135-uart",
.owner = THIS_MODULE,
},
.probe = men_z135_probe,
.remove = men_z135_remove,
.id_table = men_z135_ids,
};
/**
* men_z135_init() - Driver Registration Routine
*
* men_z135_init is the first routine called when the driver is loaded. All it
* does is register with the legacy MEN Chameleon subsystem.
*/
static int __init men_z135_init(void)
{
int err;
err = uart_register_driver(&men_z135_driver);
if (err) {
pr_err("Failed to register UART: %d\n", err);
return err;
}
err = mcb_register_driver(&mcb_driver);
if (err) {
pr_err("Failed to register MCB driver: %d\n", err);
uart_unregister_driver(&men_z135_driver);
return err;
}
return 0;
}
module_init(men_z135_init);
/**
* men_z135_exit() - Driver Exit Routine
*
* men_z135_exit is called just before the driver is removed from memory.
*/
static void __exit men_z135_exit(void)
{
mcb_unregister_driver(&mcb_driver);
uart_unregister_driver(&men_z135_driver);
}
module_exit(men_z135_exit);
MODULE_AUTHOR("Johannes Thumshirn <johannes.thumshirn@men.de>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("MEN 16z135 High Speed UART");
MODULE_ALIAS("mcb:16z135");

View File

@ -29,7 +29,7 @@
#include <asm/irq.h>
#include <asm/parisc-device.h>
#ifdef CONFIG_MAGIC_SYSRQ
#if defined(CONFIG_SERIAL_MUX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#include <linux/sysrq.h>
#define SUPPORT_SYSRQ
#endif
@ -613,7 +613,7 @@ static void __exit mux_exit(void)
{
/* Delete the Mux timer. */
if(port_cnt > 0) {
del_timer(&mux_timer);
del_timer_sync(&mux_timer);
#ifdef CONFIG_SERIAL_MUX_CONSOLE
unregister_console(&mux_console);
#endif

View File

@ -173,6 +173,7 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
{
struct uart_8250_port port8250;
memset(&port8250, 0, sizeof(port8250));
port.type = port_type;
port8250.port = port;
if (port.fifosize)
@ -182,6 +183,10 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
"auto-flow-control"))
port8250.capabilities |= UART_CAP_AFE;
if (of_property_read_bool(ofdev->dev.of_node,
"has-hw-flow-control"))
port8250.port.flags |= UPF_HARD_FLOW;
ret = serial8250_register_8250_port(&port8250);
break;
}

View File

@ -163,10 +163,6 @@ struct uart_omap_port {
u8 wakeups_enabled;
u32 features;
int DTR_gpio;
int DTR_inverted;
int DTR_active;
struct serial_rs485 rs485;
int rts_gpio;
@ -184,8 +180,6 @@ static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
/* Forward declaration of functions */
static void serial_omap_mdr1_errataset(struct uart_omap_port *up, u8 mdr1);
static struct workqueue_struct *serial_omap_uart_wq;
static inline unsigned int serial_in(struct uart_omap_port *up, int offset)
{
offset <<= up->port.regshift;
@ -398,11 +392,8 @@ static void transmit_chars(struct uart_omap_port *up, unsigned int lsr)
break;
} while (--count > 0);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) {
spin_unlock(&up->port.lock);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&up->port);
spin_lock(&up->port.lock);
}
if (uart_circ_empty(xmit))
serial_omap_stop_tx(&up->port);
@ -697,16 +688,6 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
serial_out(up, UART_MCR, up->mcr);
pm_runtime_mark_last_busy(up->dev);
pm_runtime_put_autosuspend(up->dev);
if (gpio_is_valid(up->DTR_gpio) &&
!!(mctrl & TIOCM_DTR) != up->DTR_active) {
up->DTR_active = !up->DTR_active;
if (gpio_cansleep(up->DTR_gpio))
schedule_work(&up->qos_work);
else
gpio_set_value(up->DTR_gpio,
up->DTR_active != up->DTR_inverted);
}
}
static void serial_omap_break_ctl(struct uart_port *port, int break_state)
@ -850,9 +831,6 @@ static void serial_omap_uart_qos_work(struct work_struct *work)
qos_work);
pm_qos_update_request(&up->pm_qos_request, up->latency);
if (gpio_is_valid(up->DTR_gpio))
gpio_set_value_cansleep(up->DTR_gpio,
up->DTR_active != up->DTR_inverted);
}
static void
@ -1420,7 +1398,7 @@ serial_omap_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg)
switch (cmd) {
case TIOCSRS485:
if (copy_from_user(&rs485conf, (struct serial_rs485 *) arg,
if (copy_from_user(&rs485conf, (void __user *) arg,
sizeof(rs485conf)))
return -EFAULT;
@ -1428,7 +1406,7 @@ serial_omap_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg)
break;
case TIOCGRS485:
if (copy_to_user((struct serial_rs485 *) arg,
if (copy_to_user((void __user *) arg,
&(to_uart_omap_port(port)->rs485),
sizeof(rs485conf)))
return -EFAULT;
@ -1614,7 +1592,7 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up,
/* check for tx enable gpio */
up->rts_gpio = of_get_named_gpio_flags(np, "rts-gpio", 0, &flags);
if (gpio_is_valid(up->rts_gpio)) {
ret = gpio_request(up->rts_gpio, "omap-serial");
ret = devm_gpio_request(up->dev, up->rts_gpio, "omap-serial");
if (ret < 0)
return ret;
ret = gpio_direction_output(up->rts_gpio,
@ -1644,10 +1622,13 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up,
static int serial_omap_probe(struct platform_device *pdev)
{
struct uart_omap_port *up;
struct resource *mem, *irq;
struct omap_uart_port_info *omap_up_info = dev_get_platdata(&pdev->dev);
int ret, uartirq = 0, wakeirq = 0;
struct uart_omap_port *up;
struct resource *mem;
void __iomem *base;
int uartirq = 0;
int wakeirq = 0;
int ret;
/* The optional wakeirq may be specified in the board dts file */
if (pdev->dev.of_node) {
@ -1658,48 +1639,19 @@ static int serial_omap_probe(struct platform_device *pdev)
omap_up_info = of_get_uart_port_info(&pdev->dev);
pdev->dev.platform_data = omap_up_info;
} else {
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!irq) {
dev_err(&pdev->dev, "no irq resource?\n");
return -ENODEV;
}
uartirq = irq->start;
}
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
dev_err(&pdev->dev, "no mem resource?\n");
return -ENODEV;
}
if (!devm_request_mem_region(&pdev->dev, mem->start, resource_size(mem),
pdev->dev.driver->name)) {
dev_err(&pdev->dev, "memory region already claimed\n");
return -EBUSY;
}
if (gpio_is_valid(omap_up_info->DTR_gpio) &&
omap_up_info->DTR_present) {
ret = gpio_request(omap_up_info->DTR_gpio, "omap-serial");
if (ret < 0)
return ret;
ret = gpio_direction_output(omap_up_info->DTR_gpio,
omap_up_info->DTR_inverted);
if (ret < 0)
return ret;
uartirq = platform_get_irq(pdev, 0);
if (uartirq < 0)
return -EPROBE_DEFER;
}
up = devm_kzalloc(&pdev->dev, sizeof(*up), GFP_KERNEL);
if (!up)
return -ENOMEM;
if (gpio_is_valid(omap_up_info->DTR_gpio) &&
omap_up_info->DTR_present) {
up->DTR_gpio = omap_up_info->DTR_gpio;
up->DTR_inverted = omap_up_info->DTR_inverted;
} else
up->DTR_gpio = -EINVAL;
up->DTR_active = 0;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(base))
return PTR_ERR(base);
up->dev = &pdev->dev;
up->port.dev = &pdev->dev;
@ -1733,14 +1685,7 @@ static int serial_omap_probe(struct platform_device *pdev)
sprintf(up->name, "OMAP UART%d", up->port.line);
up->port.mapbase = mem->start;
up->port.membase = devm_ioremap(&pdev->dev, mem->start,
resource_size(mem));
if (!up->port.membase) {
dev_err(&pdev->dev, "can't ioremap UART\n");
ret = -ENOMEM;
goto err_ioremap;
}
up->port.membase = base;
up->port.flags = omap_up_info->flags;
up->port.uartclk = omap_up_info->uartclk;
if (!up->port.uartclk) {
@ -1754,12 +1699,12 @@ static int serial_omap_probe(struct platform_device *pdev)
up->calc_latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;
pm_qos_add_request(&up->pm_qos_request,
PM_QOS_CPU_DMA_LATENCY, up->latency);
serial_omap_uart_wq = create_singlethread_workqueue(up->name);
INIT_WORK(&up->qos_work, serial_omap_uart_qos_work);
platform_set_drvdata(pdev, up);
if (omap_up_info->autosuspend_timeout == 0)
omap_up_info->autosuspend_timeout = -1;
device_init_wakeup(up->dev, true);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev,
@ -1786,7 +1731,6 @@ static int serial_omap_probe(struct platform_device *pdev)
err_add_port:
pm_runtime_put(&pdev->dev);
pm_runtime_disable(&pdev->dev);
err_ioremap:
err_rs485:
err_port_line:
dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n",

View File

@ -257,6 +257,8 @@ struct eg20t_port {
dma_addr_t rx_buf_dma;
struct dentry *debugfs;
#define IRQ_NAME_SIZE 17
char irq_name[IRQ_NAME_SIZE];
/* protect the eg20t_port private structure and io access to membase */
spinlock_t lock;
@ -1343,7 +1345,7 @@ static int pch_uart_startup(struct uart_port *port)
return ret;
ret = request_irq(priv->port.irq, pch_uart_interrupt, IRQF_SHARED,
KBUILD_MODNAME, priv);
priv->irq_name, priv);
if (ret < 0)
return ret;
@ -1588,13 +1590,8 @@ static void pch_uart_put_poll_char(struct uart_port *port,
wait_for_xmitr(priv, UART_LSR_THRE);
/*
* Send the character out.
* If a LF, also do CR...
*/
iowrite8(c, priv->membase + PCH_UART_THR);
if (c == 10) {
wait_for_xmitr(priv, UART_LSR_THRE);
iowrite8(13, priv->membase + PCH_UART_THR);
}
/*
* Finally, wait for transmitter to become empty
@ -1818,6 +1815,10 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
priv->port.line = board->line_no;
priv->trigger = PCH_UART_HAL_TRIGGER_M;
snprintf(priv->irq_name, IRQ_NAME_SIZE,
KBUILD_MODNAME ":" PCH_UART_DRIVER_DEVICE "%d",
priv->port.line);
spin_lock_init(&priv->port.lock);
pci_set_drvdata(pdev, priv);

View File

@ -711,13 +711,8 @@ static void serial_pxa_put_poll_char(struct uart_port *port,
wait_for_xmitr(up);
/*
* Send the character out.
* If a LF, also do CR...
*/
serial_out(up, UART_TX, c);
if (c == 10) {
wait_for_xmitr(up);
serial_out(up, UART_TX, 13);
}
/*
* Finally, wait for transmitter to become empty

View File

@ -53,6 +53,29 @@
#include "samsung.h"
#if defined(CONFIG_SERIAL_SAMSUNG_DEBUG) && \
defined(CONFIG_DEBUG_LL) && \
!defined(MODULE)
extern void printascii(const char *);
__printf(1, 2)
static void dbg(const char *fmt, ...)
{
va_list va;
char buff[256];
va_start(va, fmt);
vscnprintf(buff, sizeof(buf), fmt, va);
va_end(va);
printascii(buff);
}
#else
#define dbg(fmt, ...) do { if (0) no_printk(fmt, ##__VA_ARGS__); } while (0)
#endif
/* UART name and device definitions */
#define S3C24XX_SERIAL_NAME "ttySAC"
@ -468,8 +491,8 @@ static int s3c24xx_serial_startup(struct uart_port *port)
struct s3c24xx_uart_port *ourport = to_ourport(port);
int ret;
dbg("s3c24xx_serial_startup: port=%p (%08lx,%p)\n",
port->mapbase, port->membase);
dbg("s3c24xx_serial_startup: port=%p (%08llx,%p)\n",
port, (unsigned long long)port->mapbase, port->membase);
rx_enabled(port) = 1;
@ -514,8 +537,8 @@ static int s3c64xx_serial_startup(struct uart_port *port)
struct s3c24xx_uart_port *ourport = to_ourport(port);
int ret;
dbg("s3c64xx_serial_startup: port=%p (%08lx,%p)\n",
port->mapbase, port->membase);
dbg("s3c64xx_serial_startup: port=%p (%08llx,%p)\n",
port, (unsigned long long)port->mapbase, port->membase);
wr_regl(port, S3C64XX_UINTM, 0xf);
@ -1160,7 +1183,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
return -EINVAL;
}
dbg("resource %p (%lx..%lx)\n", res, res->start, res->end);
dbg("resource %pR)\n", res);
port->membase = devm_ioremap(port->dev, res->start, resource_size(res));
if (!port->membase) {
@ -1203,7 +1226,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
wr_regl(port, S3C64XX_UINTSP, 0xf);
}
dbg("port: map=%08x, mem=%08x, irq=%d (%d,%d), clock=%ld\n",
dbg("port: map=%08x, mem=%p, irq=%d (%d,%d), clock=%u\n",
port->mapbase, port->membase, port->irq,
ourport->rx_irq, ourport->tx_irq, port->uartclk);

View File

@ -1,3 +1,6 @@
#ifndef __SAMSUNG_H
#define __SAMSUNG_H
/*
* Driver for Samsung SoC onboard UARTs.
*
@ -77,24 +80,4 @@ struct s3c24xx_uart_port {
#define wr_regb(port, reg, val) __raw_writeb(val, portaddr(port, reg))
#define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg))
#if defined(CONFIG_SERIAL_SAMSUNG_DEBUG) && \
defined(CONFIG_DEBUG_LL) && \
!defined(MODULE)
extern void printascii(const char *);
static void dbg(const char *fmt, ...)
{
va_list va;
char buff[256];
va_start(va, fmt);
vsprintf(buff, fmt, va);
va_end(va);
printascii(buff);
}
#else
#define dbg(x...) do { } while (0)
#endif

File diff suppressed because it is too large Load Diff

View File

@ -474,9 +474,7 @@ static void sccnxp_timer(unsigned long data)
sccnxp_handle_events(s);
spin_unlock_irqrestore(&s->lock, flags);
if (!timer_pending(&s->timer))
mod_timer(&s->timer, jiffies +
usecs_to_jiffies(s->pdata.poll_time_us));
mod_timer(&s->timer, jiffies + usecs_to_jiffies(s->pdata.poll_time_us));
}
static irqreturn_t sccnxp_ist(int irq, void *dev_id)
@ -674,6 +672,8 @@ static void sccnxp_set_termios(struct uart_port *port,
port->ignore_status_mask = 0;
if (termios->c_iflag & IGNBRK)
port->ignore_status_mask |= SR_BRK;
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= SR_PE;
if (!(termios->c_cflag & CREAD))
port->ignore_status_mask |= SR_PE | SR_OVR | SR_FE | SR_BRK;

View File

@ -174,8 +174,12 @@ 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);
}
if (tty_port_cts_enabled(port)) {
/*
* if hw support flow control without software intervention,
* then skip the below check
*/
if (tty_port_cts_enabled(port) &&
!(uport->flags & UPF_HARD_FLOW)) {
spin_lock_irq(&uport->lock);
if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS))
tty->hw_stopped = 1;
@ -2239,6 +2243,9 @@ static void uart_poll_put_char(struct tty_driver *driver, int line, char ch)
return;
port = state->uart_port;
if (ch == '\n')
port->ops->poll_put_char(port, '\r');
port->ops->poll_put_char(port, ch);
}
#endif
@ -2772,7 +2779,9 @@ void uart_handle_cts_change(struct uart_port *uport, unsigned int status)
uport->icount.cts++;
if (tty_port_cts_enabled(port)) {
/* skip below code if the hw flow control is supported */
if (tty_port_cts_enabled(port) &&
!(uport->flags & UPF_HARD_FLOW)) {
if (tty->hw_stopped) {
if (status) {
tty->hw_stopped = 0;

View File

@ -0,0 +1,143 @@
/*
* Helpers for controlling modem lines via GPIO
*
* Copyright (C) 2014 Paratronic S.A.
*
* 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.
*
* 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.
*
*/
#include <linux/err.h>
#include <linux/device.h>
#include <linux/gpio/consumer.h>
#include <uapi/asm-generic/termios.h>
#include "serial_mctrl_gpio.h"
struct mctrl_gpios {
struct gpio_desc *gpio[UART_GPIO_MAX];
};
static const struct {
const char *name;
unsigned int mctrl;
bool dir_out;
} mctrl_gpios_desc[UART_GPIO_MAX] = {
{ "cts", TIOCM_CTS, false, },
{ "dsr", TIOCM_DSR, false, },
{ "dcd", TIOCM_CD, false, },
{ "rng", TIOCM_RNG, false, },
{ "rts", TIOCM_RTS, true, },
{ "dtr", TIOCM_DTR, true, },
{ "out1", TIOCM_OUT1, true, },
{ "out2", TIOCM_OUT2, true, },
};
void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
{
enum mctrl_gpio_idx i;
if (IS_ERR_OR_NULL(gpios))
return;
for (i = 0; i < UART_GPIO_MAX; i++)
if (!IS_ERR_OR_NULL(gpios->gpio[i]) &&
mctrl_gpios_desc[i].dir_out)
gpiod_set_value(gpios->gpio[i],
!!(mctrl & mctrl_gpios_desc[i].mctrl));
}
EXPORT_SYMBOL_GPL(mctrl_gpio_set);
struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
enum mctrl_gpio_idx gidx)
{
if (!IS_ERR_OR_NULL(gpios) && !IS_ERR_OR_NULL(gpios->gpio[gidx]))
return gpios->gpio[gidx];
else
return NULL;
}
EXPORT_SYMBOL_GPL(mctrl_gpio_to_gpiod);
unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
{
enum mctrl_gpio_idx i;
/*
* return it unchanged if the structure is not allocated
*/
if (IS_ERR_OR_NULL(gpios))
return *mctrl;
for (i = 0; i < UART_GPIO_MAX; i++) {
if (!IS_ERR_OR_NULL(gpios->gpio[i]) &&
!mctrl_gpios_desc[i].dir_out) {
if (gpiod_get_value(gpios->gpio[i]))
*mctrl |= mctrl_gpios_desc[i].mctrl;
else
*mctrl &= ~mctrl_gpios_desc[i].mctrl;
}
}
return *mctrl;
}
EXPORT_SYMBOL_GPL(mctrl_gpio_get);
struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx)
{
struct mctrl_gpios *gpios;
enum mctrl_gpio_idx i;
int err;
gpios = devm_kzalloc(dev, sizeof(*gpios), GFP_KERNEL);
if (!gpios)
return ERR_PTR(-ENOMEM);
for (i = 0; i < UART_GPIO_MAX; i++) {
gpios->gpio[i] = devm_gpiod_get_index(dev,
mctrl_gpios_desc[i].name,
idx);
/*
* The GPIOs are maybe not all filled,
* this is not an error.
*/
if (IS_ERR_OR_NULL(gpios->gpio[i]))
continue;
if (mctrl_gpios_desc[i].dir_out)
err = gpiod_direction_output(gpios->gpio[i], 0);
else
err = gpiod_direction_input(gpios->gpio[i]);
if (err) {
dev_dbg(dev, "Unable to set direction for %s GPIO",
mctrl_gpios_desc[i].name);
devm_gpiod_put(dev, gpios->gpio[i]);
gpios->gpio[i] = NULL;
}
}
return gpios;
}
EXPORT_SYMBOL_GPL(mctrl_gpio_init);
void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
{
enum mctrl_gpio_idx i;
if (IS_ERR_OR_NULL(gpios))
return;
for (i = 0; i < UART_GPIO_MAX; i++)
if (!IS_ERR_OR_NULL(gpios->gpio[i]))
devm_gpiod_put(dev, gpios->gpio[i]);
devm_kfree(dev, gpios);
}
EXPORT_SYMBOL_GPL(mctrl_gpio_free);

View File

@ -0,0 +1,110 @@
/*
* Helpers for controlling modem lines via GPIO
*
* Copyright (C) 2014 Paratronic S.A.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef __SERIAL_MCTRL_GPIO__
#define __SERIAL_MCTRL_GPIO__
#include <linux/err.h>
#include <linux/device.h>
#include <linux/gpio/consumer.h>
enum mctrl_gpio_idx {
UART_GPIO_CTS,
UART_GPIO_DSR,
UART_GPIO_DCD,
UART_GPIO_RNG,
UART_GPIO_RI = UART_GPIO_RNG,
UART_GPIO_RTS,
UART_GPIO_DTR,
UART_GPIO_OUT1,
UART_GPIO_OUT2,
UART_GPIO_MAX,
};
/*
* Opaque descriptor for modem lines controlled by GPIOs
*/
struct mctrl_gpios;
#ifdef CONFIG_GPIOLIB
/*
* Set state of the modem control output lines via GPIOs.
*/
void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl);
/*
* Get state of the modem control output lines from GPIOs.
* The mctrl flags are updated and returned.
*/
unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl);
/*
* Returns the associated struct gpio_desc to the modem line gidx
*/
struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
enum mctrl_gpio_idx gidx);
/*
* Request and set direction of modem control lines GPIOs.
* devm_* functions are used, so there's no need to call mctrl_gpio_free().
* Returns a pointer to the allocated mctrl structure if ok, -ENOMEM on
* allocation error.
*/
struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx);
/*
* Free the mctrl_gpios structure.
* Normally, this function will not be called, as the GPIOs will
* be disposed of by the resource management code.
*/
void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios);
#else /* GPIOLIB */
static inline
void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
{
}
static inline
unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
{
return *mctrl;
}
static inline
struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
enum mctrl_gpio_idx gidx)
{
return ERR_PTR(-ENOSYS);
}
static inline
struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx)
{
return ERR_PTR(-ENOSYS);
}
static inline
void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
{
}
#endif /* GPIOLIB */
#endif

View File

@ -535,13 +535,8 @@ static void serial_txx9_put_poll_char(struct uart_port *port, unsigned char c)
wait_for_xmitr(up);
/*
* Send the character out.
* If a LF, also do CR...
*/
sio_out(up, TXX9_SITFIFO, c);
if (c == 10) {
wait_for_xmitr(up);
sio_out(up, TXX9_SITFIFO, 13);
}
/*
* Finally, wait for transmitter to become empty

View File

@ -358,9 +358,11 @@ static irqreturn_t sirfsoc_uart_usp_cts_handler(int irq, void *dev_id)
{
struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)dev_id;
struct uart_port *port = &sirfport->port;
spin_lock(&port->lock);
if (gpio_is_valid(sirfport->cts_gpio) && sirfport->ms_enabled)
uart_handle_cts_change(port,
!gpio_get_value(sirfport->cts_gpio));
spin_unlock(&port->lock);
return IRQ_HANDLED;
}
@ -428,10 +430,6 @@ sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count)
sirfport->rx_io_count += rx_count;
port->icount.rx += rx_count;
spin_unlock(&port->lock);
tty_flip_buffer_push(&port->state->port);
spin_lock(&port->lock);
return rx_count;
}
@ -465,6 +463,7 @@ static void sirfsoc_uart_tx_dma_complete_callback(void *param)
struct circ_buf *xmit = &port->state->xmit;
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
xmit->tail = (xmit->tail + sirfport->transfer_size) &
(UART_XMIT_SIZE - 1);
port->icount.tx += sirfport->transfer_size;
@ -473,10 +472,9 @@ static void sirfsoc_uart_tx_dma_complete_callback(void *param)
if (sirfport->tx_dma_addr)
dma_unmap_single(port->dev, sirfport->tx_dma_addr,
sirfport->transfer_size, DMA_TO_DEVICE);
spin_lock_irqsave(&sirfport->tx_lock, flags);
sirfport->tx_dma_state = TX_DMA_IDLE;
sirfsoc_uart_tx_with_dma(sirfport);
spin_unlock_irqrestore(&sirfport->tx_lock, flags);
spin_unlock_irqrestore(&port->lock, flags);
}
static void sirfsoc_uart_insert_rx_buf_to_tty(
@ -489,7 +487,6 @@ static void sirfsoc_uart_insert_rx_buf_to_tty(
inserted = tty_insert_flip_string(tport,
sirfport->rx_dma_items[sirfport->rx_completed].xmit.buf, count);
port->icount.rx += inserted;
tty_flip_buffer_push(tport);
}
static void sirfsoc_rx_submit_one_dma_desc(struct uart_port *port, int index)
@ -525,7 +522,7 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)
unsigned long flags;
struct dma_tx_state tx_state;
spin_lock_irqsave(&sirfport->rx_lock, flags);
spin_lock_irqsave(&port->lock, flags);
while (DMA_COMPLETE == dmaengine_tx_status(sirfport->rx_dma_chan,
sirfport->rx_dma_items[sirfport->rx_completed].cookie, &tx_state)) {
sirfsoc_uart_insert_rx_buf_to_tty(sirfport,
@ -541,12 +538,8 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)
wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) |
SIRFUART_IO_MODE);
spin_unlock_irqrestore(&sirfport->rx_lock, flags);
spin_lock(&port->lock);
sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count);
spin_unlock(&port->lock);
if (sirfport->rx_io_count == 4) {
spin_lock_irqsave(&sirfport->rx_lock, flags);
sirfport->rx_io_count = 0;
wr_regl(port, ureg->sirfsoc_int_st_reg,
uint_st->sirfsoc_rx_done);
@ -557,11 +550,8 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)
else
wr_regl(port, SIRFUART_INT_EN_CLR,
uint_en->sirfsoc_rx_done_en);
spin_unlock_irqrestore(&sirfport->rx_lock, flags);
sirfsoc_uart_start_next_rx_dma(port);
} else {
spin_lock_irqsave(&sirfport->rx_lock, flags);
wr_regl(port, ureg->sirfsoc_int_st_reg,
uint_st->sirfsoc_rx_done);
if (!sirfport->is_marco)
@ -571,8 +561,9 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)
else
wr_regl(port, ureg->sirfsoc_int_en_reg,
uint_en->sirfsoc_rx_done_en);
spin_unlock_irqrestore(&sirfport->rx_lock, flags);
}
spin_unlock_irqrestore(&port->lock, flags);
tty_flip_buffer_push(&port->state->port);
}
static void sirfsoc_uart_handle_rx_tmo(struct sirfsoc_uart_port *sirfport)
@ -581,8 +572,6 @@ static void sirfsoc_uart_handle_rx_tmo(struct sirfsoc_uart_port *sirfport)
struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
struct dma_tx_state tx_state;
spin_lock(&sirfport->rx_lock);
dmaengine_tx_status(sirfport->rx_dma_chan,
sirfport->rx_dma_items[sirfport->rx_issued].cookie, &tx_state);
dmaengine_terminate_all(sirfport->rx_dma_chan);
@ -595,7 +584,6 @@ static void sirfsoc_uart_handle_rx_tmo(struct sirfsoc_uart_port *sirfport)
else
wr_regl(port, SIRFUART_INT_EN_CLR,
uint_en->sirfsoc_rx_timeout_en);
spin_unlock(&sirfport->rx_lock);
tasklet_schedule(&sirfport->rx_tmo_process_tasklet);
}
@ -659,7 +647,6 @@ static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id)
intr_status &= port->read_status_mask;
uart_insert_char(port, intr_status,
uint_en->sirfsoc_rx_oflow_en, 0, flag);
tty_flip_buffer_push(&state->port);
}
recv_char:
if ((sirfport->uart_reg->uart_type == SIRF_REAL_UART) &&
@ -684,6 +671,9 @@ recv_char:
sirfsoc_uart_pio_rx_chars(port,
SIRFSOC_UART_IO_RX_MAX_CNT);
}
spin_unlock(&port->lock);
tty_flip_buffer_push(&state->port);
spin_lock(&port->lock);
if (intr_status & uint_st->sirfsoc_txfifo_empty) {
if (sirfport->tx_dma_chan)
sirfsoc_uart_tx_with_dma(sirfport);
@ -702,6 +692,7 @@ recv_char:
}
}
spin_unlock(&port->lock);
return IRQ_HANDLED;
}
@ -713,7 +704,7 @@ static void sirfsoc_uart_rx_dma_complete_tl(unsigned long param)
struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
unsigned long flags;
struct dma_tx_state tx_state;
spin_lock_irqsave(&sirfport->rx_lock, flags);
spin_lock_irqsave(&port->lock, flags);
while (DMA_COMPLETE == dmaengine_tx_status(sirfport->rx_dma_chan,
sirfport->rx_dma_items[sirfport->rx_completed].cookie, &tx_state)) {
sirfsoc_uart_insert_rx_buf_to_tty(sirfport,
@ -726,17 +717,20 @@ static void sirfsoc_uart_rx_dma_complete_tl(unsigned long param)
sirfport->rx_completed++;
sirfport->rx_completed %= SIRFSOC_RX_LOOP_BUF_CNT;
}
spin_unlock_irqrestore(&sirfport->rx_lock, flags);
spin_unlock_irqrestore(&port->lock, flags);
tty_flip_buffer_push(&port->state->port);
}
static void sirfsoc_uart_rx_dma_complete_callback(void *param)
{
struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param;
spin_lock(&sirfport->rx_lock);
unsigned long flags;
spin_lock_irqsave(&sirfport->port.lock, flags);
sirfport->rx_issued++;
sirfport->rx_issued %= SIRFSOC_RX_LOOP_BUF_CNT;
spin_unlock(&sirfport->rx_lock);
tasklet_schedule(&sirfport->rx_dma_complete_tasklet);
spin_unlock_irqrestore(&sirfport->port.lock, flags);
}
/* submit rx dma task into dmaengine */
@ -745,18 +739,14 @@ static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port)
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
unsigned long flags;
int i;
spin_lock_irqsave(&sirfport->rx_lock, flags);
sirfport->rx_io_count = 0;
wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) &
~SIRFUART_IO_MODE);
spin_unlock_irqrestore(&sirfport->rx_lock, flags);
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;
spin_lock_irqsave(&sirfport->rx_lock, flags);
if (!sirfport->is_marco)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg) |
@ -764,7 +754,6 @@ static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port)
else
wr_regl(port, ureg->sirfsoc_int_en_reg,
SIRFUART_RX_DMA_INT_EN(port, uint_en));
spin_unlock_irqrestore(&sirfport->rx_lock, flags);
}
static void sirfsoc_uart_start_rx(struct uart_port *port)
@ -1228,7 +1217,7 @@ static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch)
while (rd_regl(port,
ureg->sirfsoc_tx_fifo_status) & ufifo_st->ff_full(port->line))
cpu_relax();
wr_regb(port, ureg->sirfsoc_tx_fifo_data, ch);
wr_regl(port, ureg->sirfsoc_tx_fifo_data, ch);
}
static void sirfsoc_uart_console_write(struct console *co, const char *s,
@ -1369,8 +1358,6 @@ usp_no_flow_control:
ret = -EFAULT;
goto err;
}
spin_lock_init(&sirfport->rx_lock);
spin_lock_init(&sirfport->tx_lock);
tasklet_init(&sirfport->rx_dma_complete_tasklet,
sirfsoc_uart_rx_dma_complete_tl, (unsigned long)sirfport);
tasklet_init(&sirfport->rx_tmo_process_tasklet,

View File

@ -424,8 +424,6 @@ struct sirfsoc_uart_port {
struct dma_chan *tx_dma_chan;
dma_addr_t tx_dma_addr;
struct dma_async_tx_descriptor *tx_dma_desc;
spinlock_t rx_lock;
spinlock_t tx_lock;
struct tasklet_struct rx_dma_complete_tasklet;
struct tasklet_struct rx_tmo_process_tasklet;
unsigned int rx_io_count;
@ -441,9 +439,7 @@ struct sirfsoc_uart_port {
/* Register Access Control */
#define portaddr(port, reg) ((port)->membase + (reg))
#define rd_regb(port, reg) (__raw_readb(portaddr(port, reg)))
#define rd_regl(port, reg) (__raw_readl(portaddr(port, reg)))
#define wr_regb(port, reg, val) __raw_writeb(val, portaddr(port, reg))
#define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg))
/* UART Port Mask */

View File

@ -194,9 +194,9 @@ static inline u32 asc_txfifo_is_empty(struct uart_port *port)
return asc_in(port, ASC_STA) & ASC_STA_TE;
}
static inline int asc_txfifo_is_full(struct uart_port *port)
static inline u32 asc_txfifo_is_half_empty(struct uart_port *port)
{
return asc_in(port, ASC_STA) & ASC_STA_TF;
return asc_in(port, ASC_STA) & ASC_STA_THE;
}
static inline const char *asc_port_name(struct uart_port *port)
@ -628,7 +628,7 @@ static int asc_get_poll_char(struct uart_port *port)
static void asc_put_poll_char(struct uart_port *port, unsigned char c)
{
while (asc_txfifo_is_full(port))
while (!asc_txfifo_is_half_empty(port))
cpu_relax();
asc_out(port, ASC_TXBUF, c);
}
@ -783,7 +783,7 @@ static void asc_console_putchar(struct uart_port *port, int ch)
unsigned int timeout = 1000000;
/* Wait for upto 1 second in case flow control is stopping us. */
while (--timeout && asc_txfifo_is_full(port))
while (--timeout && !asc_txfifo_is_half_empty(port))
udelay(1);
asc_out(port, ASC_TXBUF, ch);

View File

@ -418,14 +418,23 @@ static struct uart_ops ulite_ops = {
#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
static void ulite_console_wait_tx(struct uart_port *port)
{
int i;
u8 val;
unsigned long timeout;
/* Spin waiting for TX fifo to have space available */
for (i = 0; i < 100000; i++) {
/*
* Spin waiting for TX fifo to have space available.
* When using the Microblaze Debug Module this can take up to 1s
*/
timeout = jiffies + msecs_to_jiffies(1000);
while (1) {
val = uart_in32(ULITE_STATUS, port);
if ((val & ULITE_STATUS_TXFULL) == 0)
break;
if (time_after(jiffies, timeout)) {
dev_warn(port->dev,
"timeout waiting for TX buffer empty\n");
break;
}
cpu_relax();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -179,7 +179,6 @@ struct uni_pagedir {
unsigned long sum;
unsigned char *inverse_translations[4];
u16 *inverse_trans_unicode;
int readonly;
};
static struct uni_pagedir *dflt;
@ -262,7 +261,7 @@ u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode)
int m;
if (glyph < 0 || glyph >= MAX_GLYPH)
return 0;
else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc))
else if (!(p = *conp->vc_uni_pagedir_loc))
return glyph;
else if (use_unicode) {
if (!p->inverse_trans_unicode)
@ -287,7 +286,7 @@ static void update_user_maps(void)
for (i = 0; i < MAX_NR_CONSOLES; i++) {
if (!vc_cons_allocated(i))
continue;
p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
p = *vc_cons[i].d->vc_uni_pagedir_loc;
if (p && p != q) {
set_inverse_transl(vc_cons[i].d, p, USER_MAP);
set_inverse_trans_unicode(vc_cons[i].d, p);
@ -418,10 +417,10 @@ void con_free_unimap(struct vc_data *vc)
{
struct uni_pagedir *p;
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
p = *vc->vc_uni_pagedir_loc;
if (!p)
return;
*vc->vc_uni_pagedir_loc = 0;
*vc->vc_uni_pagedir_loc = NULL;
if (--p->refcount)
return;
con_release_unimap(p);
@ -436,7 +435,7 @@ static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)
for (i = 0; i < MAX_NR_CONSOLES; i++) {
if (!vc_cons_allocated(i))
continue;
q = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
q = *vc_cons[i].d->vc_uni_pagedir_loc;
if (!q || q == p || q->sum != p->sum)
continue;
for (j = 0; j < 32; j++) {
@ -459,7 +458,7 @@ static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)
}
if (j == 32) {
q->refcount++;
*conp->vc_uni_pagedir_loc = (unsigned long)q;
*conp->vc_uni_pagedir_loc = q;
con_release_unimap(p);
kfree(p);
return 1;
@ -500,10 +499,7 @@ static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
{
struct uni_pagedir *p, *q;
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
if (p && p->readonly)
return -EIO;
p = *vc->vc_uni_pagedir_loc;
if (!p || --p->refcount) {
q = kzalloc(sizeof(*p), GFP_KERNEL);
if (!q) {
@ -512,7 +508,7 @@ static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
return -ENOMEM;
}
q->refcount=1;
*vc->vc_uni_pagedir_loc = (unsigned long)q;
*vc->vc_uni_pagedir_loc = q;
} else {
if (p == dflt) dflt = NULL;
p->refcount++;
@ -536,19 +532,13 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
int err = 0, err1, i;
struct uni_pagedir *p, *q;
if (!ct)
return 0;
console_lock();
/* Save original vc_unipagdir_loc in case we allocate a new one */
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
if (p->readonly) {
console_unlock();
return -EIO;
}
if (!ct) {
console_unlock();
return 0;
}
p = *vc->vc_uni_pagedir_loc;
if (p->refcount > 1) {
int j, k;
@ -564,7 +554,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
* Since refcount was > 1, con_clear_unimap() allocated a
* a new uni_pagedir for this vc. Re: p != q
*/
q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
q = *vc->vc_uni_pagedir_loc;
/*
* uni_pgdir is a 32*32*64 table with rows allocated
@ -586,7 +576,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
err1 = con_insert_unipair(q, l, p2[k]);
if (err1) {
p->refcount++;
*vc->vc_uni_pagedir_loc = (unsigned long)p;
*vc->vc_uni_pagedir_loc = p;
con_release_unimap(q);
kfree(q);
console_unlock();
@ -655,12 +645,12 @@ int con_set_default_unimap(struct vc_data *vc)
struct uni_pagedir *p;
if (dflt) {
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
p = *vc->vc_uni_pagedir_loc;
if (p == dflt)
return 0;
dflt->refcount++;
*vc->vc_uni_pagedir_loc = (unsigned long)dflt;
*vc->vc_uni_pagedir_loc = dflt;
if (p && !--p->refcount) {
con_release_unimap(p);
kfree(p);
@ -674,7 +664,7 @@ int con_set_default_unimap(struct vc_data *vc)
if (err)
return err;
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
p = *vc->vc_uni_pagedir_loc;
q = dfont_unitable;
for (i = 0; i < 256; i++)
@ -685,7 +675,7 @@ int con_set_default_unimap(struct vc_data *vc)
}
if (con_unify_unimap(vc, p)) {
dflt = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
dflt = *vc->vc_uni_pagedir_loc;
return err;
}
@ -713,9 +703,9 @@ int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
if (*dst_vc->vc_uni_pagedir_loc == *src_vc->vc_uni_pagedir_loc)
return 0;
con_free_unimap(dst_vc);
q = (struct uni_pagedir *)*src_vc->vc_uni_pagedir_loc;
q = *src_vc->vc_uni_pagedir_loc;
q->refcount++;
*dst_vc->vc_uni_pagedir_loc = (long)q;
*dst_vc->vc_uni_pagedir_loc = q;
return 0;
}
EXPORT_SYMBOL(con_copy_unimap);
@ -737,7 +727,7 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni
ect = 0;
if (*vc->vc_uni_pagedir_loc) {
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
p = *vc->vc_uni_pagedir_loc;
for (i = 0; i < 32; i++)
if ((p1 = p->uni_pgdir[i]))
for (j = 0; j < 32; j++)
@ -810,7 +800,7 @@ conv_uni_to_pc(struct vc_data *conp, long ucs)
if (!*conp->vc_uni_pagedir_loc)
return -3;
p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
p = *conp->vc_uni_pagedir_loc;
if ((p1 = p->uni_pgdir[ucs >> 11]) &&
(p2 = p1[(ucs >> 6) & 0x1f]) &&
(h = p2[ucs & 0x3f]) < MAX_GLYPH)

View File

@ -735,7 +735,7 @@ static void visual_init(struct vc_data *vc, int num, int init)
vc->vc_num = num;
vc->vc_display_fg = &master_display_fg;
vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir;
vc->vc_uni_pagedir = 0;
vc->vc_uni_pagedir = NULL;
vc->vc_hi_font_mask = 0;
vc->vc_complement_mask = 0;
vc->vc_can_do_color = 0;
@ -1231,6 +1231,52 @@ static void default_attr(struct vc_data *vc)
vc->vc_color = vc->vc_def_color;
}
struct rgb { u8 r; u8 g; u8 b; };
struct rgb rgb_from_256(int i)
{
struct rgb c;
if (i < 8) { /* Standard colours. */
c.r = i&1 ? 0xaa : 0x00;
c.g = i&2 ? 0xaa : 0x00;
c.b = i&4 ? 0xaa : 0x00;
} else if (i < 16) {
c.r = i&1 ? 0xff : 0x55;
c.g = i&2 ? 0xff : 0x55;
c.b = i&4 ? 0xff : 0x55;
} else if (i < 232) { /* 6x6x6 colour cube. */
c.r = (i - 16) / 36 * 85 / 2;
c.g = (i - 16) / 6 % 6 * 85 / 2;
c.b = (i - 16) % 6 * 85 / 2;
} else /* Grayscale ramp. */
c.r = c.g = c.b = i * 10 - 2312;
return c;
}
static void rgb_foreground(struct vc_data *vc, struct rgb c)
{
u8 hue, max = c.r;
if (c.g > max)
max = c.g;
if (c.b > max)
max = c.b;
hue = (c.r > max/2 ? 4 : 0)
| (c.g > max/2 ? 2 : 0)
| (c.b > max/2 ? 1 : 0);
if (hue == 7 && max <= 0x55)
hue = 0, vc->vc_intensity = 2;
else
vc->vc_intensity = (max > 0xaa) + 1;
vc->vc_color = (vc->vc_color & 0xf0) | hue;
}
static void rgb_background(struct vc_data *vc, struct rgb c)
{
/* For backgrounds, err on the dark side. */
vc->vc_color = (vc->vc_color & 0x0f)
| (c.r&0x80) >> 1 | (c.g&0x80) >> 2 | (c.b&0x80) >> 3;
}
/* console_lock is held */
static void csi_m(struct vc_data *vc)
{
@ -1302,8 +1348,7 @@ static void csi_m(struct vc_data *vc)
case 27:
vc->vc_reverse = 0;
break;
case 38:
case 48: /* ITU T.416
case 38: /* ITU T.416
* Higher colour modes.
* They break the usual properties of SGR codes
* and thus need to be detected and ignored by
@ -1315,15 +1360,41 @@ static void csi_m(struct vc_data *vc)
i++;
if (i > vc->vc_npar)
break;
if (vc->vc_par[i] == 5) /* 256 colours */
i++; /* ubiquitous */
else if (vc->vc_par[i] == 2) /* 24 bit colours */
i += 3; /* extremely rare */
if (vc->vc_par[i] == 5 && /* 256 colours */
i < vc->vc_npar) { /* ubiquitous */
i++;
rgb_foreground(vc,
rgb_from_256(vc->vc_par[i]));
} else if (vc->vc_par[i] == 2 && /* 24 bit */
i <= vc->vc_npar + 3) {/* extremely rare */
struct rgb c = {r:vc->vc_par[i+1],
g:vc->vc_par[i+2],
b:vc->vc_par[i+3]};
rgb_foreground(vc, c);
i += 3;
}
/* Subcommands 3 (CMY) and 4 (CMYK) are so insane
* that detecting them is not worth the few extra
* bytes of kernel's size.
* there's no point in supporting them.
*/
break;
case 48:
i++;
if (i > vc->vc_npar)
break;
if (vc->vc_par[i] == 5 && /* 256 colours */
i < vc->vc_npar) {
i++;
rgb_background(vc,
rgb_from_256(vc->vc_par[i]));
} else if (vc->vc_par[i] == 2 && /* 24 bit */
i <= vc->vc_npar + 3) {
struct rgb c = {r:vc->vc_par[i+1],
g:vc->vc_par[i+2],
b:vc->vc_par[i+3]};
rgb_background(vc, c);
i += 3;
}
break;
case 39:
vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0);
break;

View File

@ -87,7 +87,8 @@ static void vgacon_save_screen(struct vc_data *c);
static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
int lines);
static void vgacon_invert_region(struct vc_data *c, u16 * p, int count);
static unsigned long vgacon_uni_pagedir[2];
static struct uni_pagedir *vgacon_uni_pagedir;
static int vgacon_refcount;
/* Description of the hardware situation */
static int vga_init_done __read_mostly;
@ -553,7 +554,7 @@ static const char *vgacon_startup(void)
static void vgacon_init(struct vc_data *c, int init)
{
unsigned long p;
struct uni_pagedir *p;
/*
* We cannot be loaded as a module, therefore init is always 1,
@ -575,12 +576,12 @@ static void vgacon_init(struct vc_data *c, int init)
if (vga_512_chars)
c->vc_hi_font_mask = 0x0800;
p = *c->vc_uni_pagedir_loc;
if (c->vc_uni_pagedir_loc == &c->vc_uni_pagedir ||
!--c->vc_uni_pagedir_loc[1])
if (c->vc_uni_pagedir_loc != &vgacon_uni_pagedir) {
con_free_unimap(c);
c->vc_uni_pagedir_loc = vgacon_uni_pagedir;
vgacon_uni_pagedir[1]++;
if (!vgacon_uni_pagedir[0] && p)
c->vc_uni_pagedir_loc = &vgacon_uni_pagedir;
vgacon_refcount++;
}
if (!vgacon_uni_pagedir && p)
con_set_default_unimap(c);
/* Only set the default if the user didn't deliberately override it */
@ -597,7 +598,7 @@ static void vgacon_deinit(struct vc_data *c)
vga_set_mem_top(c);
}
if (!--vgacon_uni_pagedir[1])
if (!--vgacon_refcount)
con_free_unimap(c);
c->vc_uni_pagedir_loc = &c->vc_uni_pagedir;
con_set_default_unimap(c);

View File

@ -17,6 +17,7 @@
#include <linux/workqueue.h>
struct vt_struct;
struct uni_pagedir;
#define NPAR 16
@ -104,8 +105,8 @@ struct vc_data {
unsigned int vc_bell_pitch; /* Console bell pitch */
unsigned int vc_bell_duration; /* Console bell duration */
struct vc_data **vc_display_fg; /* [!] Ptr to var holding fg console for this display */
unsigned long vc_uni_pagedir;
unsigned long *vc_uni_pagedir_loc; /* [!] Location of uni_pagedir variable for this console */
struct uni_pagedir *vc_uni_pagedir;
struct uni_pagedir **vc_uni_pagedir_loc; /* [!] Location of uni_pagedir variable for this console */
bool vc_panic_force_write; /* when oops/panic this VC can accept forced output/blanking */
/* additional information is in vt_kern.h */
};

View File

@ -84,7 +84,6 @@ struct atmel_uart_data {
short use_dma_rx; /* use receive DMA? */
void __iomem *regs; /* virt. base address, if any */
struct serial_rs485 rs485; /* rs485 settings */
int rts_gpio; /* optional RTS GPIO */
};
/* CAN */

View File

@ -285,6 +285,22 @@ static inline int uart_poll_timeout(struct uart_port *port)
/*
* Console helpers.
*/
struct earlycon_device {
struct console *con;
struct uart_port port;
char options[16]; /* e.g., 115200n8 */
unsigned int baud;
};
int setup_earlycon(char *buf, const char *match,
int (*setup)(struct earlycon_device *, const char *));
#define EARLYCON_DECLARE(name, func) \
static int __init name ## _setup_earlycon(char *buf) \
{ \
return setup_earlycon(buf, __stringify(name), func); \
} \
early_param("earlycon", name ## _setup_earlycon);
struct uart_port *uart_get_console(struct uart_port *ports, int nr,
struct console *c);
void uart_parse_options(char *options, int *baud, int *parity, int *bits,

View File

@ -92,7 +92,10 @@
* This function is called by the low-level tty driver to signal
* that line discpline should try to send more characters to the
* low-level driver for transmission. If the line discpline does
* not have any more data to send, it can just return.
* not have any more data to send, it can just return. If the line
* discipline does have some data to send, please arise a tasklet
* or workqueue to do the real data transfer. Do not send data in
* this hook, it may leads to a deadlock.
*
* int (*hangup)(struct tty_struct *)
*

View File

@ -211,7 +211,7 @@
/* VIA VT8500 SoC */
#define PORT_VT8500 97
/* Xilinx PSS UART */
/* Cadence (Xilinx Zynq) UART */
#define PORT_XUARTPS 98
/* Atheros AR933X SoC */
@ -238,4 +238,10 @@
/* Tilera TILE-Gx UART */
#define PORT_TILEGX 106
/* MEN 16z135 UART */
#define PORT_MEN_Z135 107
/* SC16IS74xx */
#define PORT_SC16IS7XX 108
#endif /* _UAPILINUX_SERIAL_CORE_H */

View File

@ -32,7 +32,7 @@
#define UART_IIR 2 /* In: Interrupt ID Register */
#define UART_IIR_NO_INT 0x01 /* No interrupts pending */
#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */
#define UART_IIR_ID 0x0e /* Mask for the interrupt ID */
#define UART_IIR_MSI 0x00 /* Modem status interrupt */
#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */
#define UART_IIR_RDI 0x04 /* Receiver data interrupt */

View File

@ -2413,6 +2413,7 @@ int unregister_console(struct console *console)
if (console_drivers != NULL && console->flags & CON_CONSDEV)
console_drivers->flags |= CON_CONSDEV;
console->flags &= ~CON_ENABLED;
console_unlock();
console_sysfs_notify();
return res;