Merge branch 'earlycon-dt' into for-next
This commit is contained in:
commit
728dd198aa
|
@ -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>;
|
||||
};
|
|
@ -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]
|
||||
earlyprintk=vga
|
||||
earlyprintk=efi
|
||||
|
|
|
@ -33,18 +33,21 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
extern struct of_cpu_method __cpu_method_of_table_begin[];
|
||||
extern struct of_cpu_method __cpu_method_of_table_end[];
|
||||
extern struct of_cpu_method __cpu_method_of_table[];
|
||||
|
||||
static const struct of_cpu_method __cpu_method_of_table_sentinel
|
||||
__used __section(__cpu_method_of_table_end);
|
||||
|
||||
|
||||
static int __init set_smp_ops_by_method(struct device_node *node)
|
||||
{
|
||||
const char *method;
|
||||
struct of_cpu_method *m = __cpu_method_of_table_begin;
|
||||
struct of_cpu_method *m = __cpu_method_of_table;
|
||||
|
||||
if (of_property_read_string(node, "enable-method", &method))
|
||||
return 0;
|
||||
|
||||
for (; m < __cpu_method_of_table_end; m++)
|
||||
for (; m->method; m++)
|
||||
if (!strcmp(m->method, method)) {
|
||||
smp_set_ops(m->ops);
|
||||
return 1;
|
||||
|
|
|
@ -289,14 +289,12 @@ int __init mx35_clocks_init(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __init mx35_clocks_init_dt(struct device_node *ccm_node)
|
||||
static void __init mx35_clocks_init_dt(struct device_node *ccm_node)
|
||||
{
|
||||
clk_data.clks = clk;
|
||||
clk_data.clk_num = ARRAY_SIZE(clk);
|
||||
of_clk_add_provider(ccm_node, of_clk_src_onecell_get, &clk_data);
|
||||
|
||||
mx35_clocks_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
CLK_OF_DECLARE(imx35, "fsl,imx35-ccm", mx35_clocks_init_dt);
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -24,8 +24,7 @@ static DEFINE_SPINLOCK(clk_lock);
|
|||
* Gate clocks
|
||||
*/
|
||||
|
||||
static void __init rk2928_gate_clk_init(struct device_node *node,
|
||||
void *data)
|
||||
static void __init rk2928_gate_clk_init(struct device_node *node)
|
||||
{
|
||||
struct clk_onecell_data *clk_data;
|
||||
const char *clk_parent;
|
||||
|
|
|
@ -1278,8 +1278,7 @@ static void __init of_sunxi_table_clock_setup(const struct of_device_id *clk_mat
|
|||
const struct of_device_id *match;
|
||||
void (*setup_function)(struct device_node *, const void *) = function;
|
||||
|
||||
for_each_matching_node(np, clk_match) {
|
||||
match = of_match_node(clk_match, np);
|
||||
for_each_matching_node_and_match(np, clk_match, &match) {
|
||||
data = match->data;
|
||||
setup_function(np, data);
|
||||
}
|
||||
|
@ -1310,7 +1309,7 @@ static void __init sunxi_clock_protect(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void __init sunxi_init_clocks(void)
|
||||
static void __init sunxi_init_clocks(struct device_node *np)
|
||||
{
|
||||
/* Register factor clocks */
|
||||
of_sunxi_table_clock_setup(clk_factors_match, sunxi_factors_clk_setup);
|
||||
|
|
|
@ -221,7 +221,7 @@ static void __init of_ti_gate_clk_setup(struct device_node *node)
|
|||
{
|
||||
_of_ti_gate_clk_setup(node, &omap_gate_clk_ops, NULL);
|
||||
}
|
||||
CLK_OF_DECLARE(ti_gate_clk, "ti,gate-clock", of_ti_gate_clk_setup)
|
||||
CLK_OF_DECLARE(ti_gate_clk, "ti,gate-clock", of_ti_gate_clk_setup);
|
||||
|
||||
static void __init of_ti_wait_gate_clk_setup(struct device_node *node)
|
||||
{
|
||||
|
|
|
@ -27,7 +27,7 @@ void __init clocksource_of_init(void)
|
|||
{
|
||||
struct device_node *np;
|
||||
const struct of_device_id *match;
|
||||
clocksource_of_init_fn init_func;
|
||||
of_init_fn_1 init_func;
|
||||
unsigned clocksources = 0;
|
||||
|
||||
for_each_matching_node_and_match(np, __clksrc_of_table, &match) {
|
||||
|
|
|
@ -96,7 +96,7 @@ static struct irq_domain_ops icoll_irq_domain_ops = {
|
|||
.xlate = irq_domain_xlate_onecell,
|
||||
};
|
||||
|
||||
static void __init icoll_of_init(struct device_node *np,
|
||||
static int __init icoll_of_init(struct device_node *np,
|
||||
struct device_node *interrupt_parent)
|
||||
{
|
||||
icoll_base = of_iomap(np, 0);
|
||||
|
@ -110,6 +110,6 @@ static void __init icoll_of_init(struct device_node *np,
|
|||
|
||||
icoll_domain = irq_domain_add_linear(np, ICOLL_NUM_IRQS,
|
||||
&icoll_irq_domain_ops, NULL);
|
||||
WARN_ON(!icoll_domain);
|
||||
return icoll_domain ? 0 : -ENODEV;
|
||||
}
|
||||
IRQCHIP_DECLARE(mxs, "fsl,icoll", icoll_of_init);
|
||||
|
|
|
@ -1323,8 +1323,7 @@ static struct s3c24xx_irq_of_ctrl s3c2410_ctrl[] = {
|
|||
};
|
||||
|
||||
int __init s3c2410_init_intc_of(struct device_node *np,
|
||||
struct device_node *interrupt_parent,
|
||||
struct s3c24xx_irq_of_ctrl *ctrl, int num_ctrl)
|
||||
struct device_node *interrupt_parent)
|
||||
{
|
||||
return s3c_init_intc_of(np, interrupt_parent,
|
||||
s3c2410_ctrl, ARRAY_SIZE(s3c2410_ctrl));
|
||||
|
@ -1346,8 +1345,7 @@ static struct s3c24xx_irq_of_ctrl s3c2416_ctrl[] = {
|
|||
};
|
||||
|
||||
int __init s3c2416_init_intc_of(struct device_node *np,
|
||||
struct device_node *interrupt_parent,
|
||||
struct s3c24xx_irq_of_ctrl *ctrl, int num_ctrl)
|
||||
struct device_node *interrupt_parent)
|
||||
{
|
||||
return s3c_init_intc_of(np, interrupt_parent,
|
||||
s3c2416_ctrl, ARRAY_SIZE(s3c2416_ctrl));
|
||||
|
|
|
@ -19,11 +19,11 @@
|
|||
* special section.
|
||||
*/
|
||||
static const struct of_device_id
|
||||
irqchip_of_match_end __used __section(__irqchip_of_end);
|
||||
irqchip_of_match_end __used __section(__irqchip_of_table_end);
|
||||
|
||||
extern struct of_device_id __irqchip_begin[];
|
||||
extern struct of_device_id __irqchip_of_table[];
|
||||
|
||||
void __init irqchip_init(void)
|
||||
{
|
||||
of_irq_init(__irqchip_begin);
|
||||
of_irq_init(__irqchip_of_table);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#ifndef _IRQCHIP_H
|
||||
#define _IRQCHIP_H
|
||||
|
||||
#include <linux/of.h>
|
||||
|
||||
/*
|
||||
* This macro must be used by the different irqchip drivers to declare
|
||||
* the association between their DT compatible string and their
|
||||
|
@ -21,9 +23,6 @@
|
|||
* @compstr: compatible string of the irqchip driver
|
||||
* @fn: initialization function
|
||||
*/
|
||||
#define IRQCHIP_DECLARE(name,compstr,fn) \
|
||||
static const struct of_device_id irqchip_of_match_##name \
|
||||
__used __section(__irqchip_of_table) \
|
||||
= { .compatible = compstr, .data = fn }
|
||||
#define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
obj-y = base.o device.o platform.o
|
||||
obj-$(CONFIG_OF_FLATTREE) += fdt.o
|
||||
obj-$(CONFIG_OF_EARLY_FLATTREE) += fdt_address.o
|
||||
obj-$(CONFIG_OF_PROMTREE) += pdt.o
|
||||
obj-$(CONFIG_OF_ADDRESS) += address.o
|
||||
obj-$(CONFIG_OF_IRQ) += irq.o
|
||||
|
@ -12,3 +13,4 @@ obj-$(CONFIG_OF_MTD) += of_mtd.o
|
|||
obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
|
||||
|
||||
CFLAGS_fdt.o = -I$(src)/../../scripts/dtc/libfdt
|
||||
CFLAGS_fdt_address.o = -I$(src)/../../scripts/dtc/libfdt
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/libfdt.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/serial_core.h>
|
||||
|
||||
#include <asm/setup.h> /* for COMMAND_LINE_SIZE */
|
||||
#include <asm/page.h>
|
||||
|
@ -696,6 +697,61 @@ static inline void early_init_dt_check_for_initrd(unsigned long node)
|
|||
}
|
||||
#endif /* CONFIG_BLK_DEV_INITRD */
|
||||
|
||||
#ifdef CONFIG_SERIAL_EARLYCON
|
||||
extern struct of_device_id __earlycon_of_table[];
|
||||
|
||||
int __init early_init_dt_scan_chosen_serial(void)
|
||||
{
|
||||
int offset;
|
||||
const char *p;
|
||||
int l;
|
||||
const struct of_device_id *match = __earlycon_of_table;
|
||||
const void *fdt = initial_boot_params;
|
||||
|
||||
offset = fdt_path_offset(fdt, "/chosen");
|
||||
if (offset < 0)
|
||||
offset = fdt_path_offset(fdt, "/chosen@0");
|
||||
if (offset < 0)
|
||||
return -ENOENT;
|
||||
|
||||
p = fdt_getprop(fdt, offset, "stdout-path", &l);
|
||||
if (!p)
|
||||
p = fdt_getprop(fdt, offset, "linux,stdout-path", &l);
|
||||
if (!p || !l)
|
||||
return -ENOENT;
|
||||
|
||||
/* Get the node specified by stdout-path */
|
||||
offset = fdt_path_offset(fdt, p);
|
||||
if (offset < 0)
|
||||
return -ENODEV;
|
||||
|
||||
while (match->compatible) {
|
||||
unsigned long addr;
|
||||
if (fdt_node_check_compatible(fdt, offset, match->compatible)) {
|
||||
match++;
|
||||
continue;
|
||||
}
|
||||
|
||||
addr = fdt_translate_address(fdt, offset);
|
||||
if (!addr)
|
||||
return -ENXIO;
|
||||
|
||||
of_setup_earlycon(addr, match->data);
|
||||
return 0;
|
||||
}
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int __init setup_of_earlycon(char *buf)
|
||||
{
|
||||
if (buf)
|
||||
return 0;
|
||||
|
||||
return early_init_dt_scan_chosen_serial();
|
||||
}
|
||||
early_param("earlycon", setup_of_earlycon);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* early_init_dt_scan_root - fetch the top level address and size cells
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,241 @@
|
|||
/*
|
||||
* FDT Address translation based on u-boot fdt_support.c which in turn was
|
||||
* based on the kernel unflattened DT address translation code.
|
||||
*
|
||||
* (C) Copyright 2007
|
||||
* Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com
|
||||
*
|
||||
* Copyright 2010-2011 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* 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, or (at your option)
|
||||
* any later version.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/libfdt.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_fdt.h>
|
||||
#include <linux/sizes.h>
|
||||
|
||||
/* Max address size we deal with */
|
||||
#define OF_MAX_ADDR_CELLS 4
|
||||
#define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \
|
||||
(ns) > 0)
|
||||
|
||||
/* Debug utility */
|
||||
#ifdef DEBUG
|
||||
static void __init of_dump_addr(const char *s, const __be32 *addr, int na)
|
||||
{
|
||||
pr_debug("%s", s);
|
||||
while(na--)
|
||||
pr_cont(" %08x", *(addr++));
|
||||
pr_debug("\n");
|
||||
}
|
||||
#else
|
||||
static void __init of_dump_addr(const char *s, const __be32 *addr, int na) { }
|
||||
#endif
|
||||
|
||||
/* Callbacks for bus specific translators */
|
||||
struct of_bus {
|
||||
void (*count_cells)(const void *blob, int parentoffset,
|
||||
int *addrc, int *sizec);
|
||||
u64 (*map)(__be32 *addr, const __be32 *range,
|
||||
int na, int ns, int pna);
|
||||
int (*translate)(__be32 *addr, u64 offset, int na);
|
||||
};
|
||||
|
||||
/* Default translator (generic bus) */
|
||||
static void __init fdt_bus_default_count_cells(const void *blob, int parentoffset,
|
||||
int *addrc, int *sizec)
|
||||
{
|
||||
const __be32 *prop;
|
||||
|
||||
if (addrc) {
|
||||
prop = fdt_getprop(blob, parentoffset, "#address-cells", NULL);
|
||||
if (prop)
|
||||
*addrc = be32_to_cpup(prop);
|
||||
else
|
||||
*addrc = dt_root_addr_cells;
|
||||
}
|
||||
|
||||
if (sizec) {
|
||||
prop = fdt_getprop(blob, parentoffset, "#size-cells", NULL);
|
||||
if (prop)
|
||||
*sizec = be32_to_cpup(prop);
|
||||
else
|
||||
*sizec = dt_root_size_cells;
|
||||
}
|
||||
}
|
||||
|
||||
static u64 __init fdt_bus_default_map(__be32 *addr, const __be32 *range,
|
||||
int na, int ns, int pna)
|
||||
{
|
||||
u64 cp, s, da;
|
||||
|
||||
cp = of_read_number(range, na);
|
||||
s = of_read_number(range + na + pna, ns);
|
||||
da = of_read_number(addr, na);
|
||||
|
||||
pr_debug("FDT: default map, cp=%llx, s=%llx, da=%llx\n",
|
||||
cp, s, da);
|
||||
|
||||
if (da < cp || da >= (cp + s))
|
||||
return OF_BAD_ADDR;
|
||||
return da - cp;
|
||||
}
|
||||
|
||||
static int __init fdt_bus_default_translate(__be32 *addr, u64 offset, int na)
|
||||
{
|
||||
u64 a = of_read_number(addr, na);
|
||||
memset(addr, 0, na * 4);
|
||||
a += offset;
|
||||
if (na > 1)
|
||||
addr[na - 2] = cpu_to_fdt32(a >> 32);
|
||||
addr[na - 1] = cpu_to_fdt32(a & 0xffffffffu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Array of bus specific translators */
|
||||
static const struct of_bus of_busses[] __initconst = {
|
||||
/* Default */
|
||||
{
|
||||
.count_cells = fdt_bus_default_count_cells,
|
||||
.map = fdt_bus_default_map,
|
||||
.translate = fdt_bus_default_translate,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init fdt_translate_one(const void *blob, int parent,
|
||||
const struct of_bus *bus,
|
||||
const struct of_bus *pbus, __be32 *addr,
|
||||
int na, int ns, int pna, const char *rprop)
|
||||
{
|
||||
const __be32 *ranges;
|
||||
int rlen;
|
||||
int rone;
|
||||
u64 offset = OF_BAD_ADDR;
|
||||
|
||||
ranges = fdt_getprop(blob, parent, rprop, &rlen);
|
||||
if (!ranges)
|
||||
return 1;
|
||||
if (rlen == 0) {
|
||||
offset = of_read_number(addr, na);
|
||||
memset(addr, 0, pna * 4);
|
||||
pr_debug("FDT: empty ranges, 1:1 translation\n");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
pr_debug("FDT: walking ranges...\n");
|
||||
|
||||
/* Now walk through the ranges */
|
||||
rlen /= 4;
|
||||
rone = na + pna + ns;
|
||||
for (; rlen >= rone; rlen -= rone, ranges += rone) {
|
||||
offset = bus->map(addr, ranges, na, ns, pna);
|
||||
if (offset != OF_BAD_ADDR)
|
||||
break;
|
||||
}
|
||||
if (offset == OF_BAD_ADDR) {
|
||||
pr_debug("FDT: not found !\n");
|
||||
return 1;
|
||||
}
|
||||
memcpy(addr, ranges + na, 4 * pna);
|
||||
|
||||
finish:
|
||||
of_dump_addr("FDT: parent translation for:", addr, pna);
|
||||
pr_debug("FDT: with offset: %llx\n", offset);
|
||||
|
||||
/* Translate it into parent bus space */
|
||||
return pbus->translate(addr, offset, pna);
|
||||
}
|
||||
|
||||
/*
|
||||
* Translate an address from the device-tree into a CPU physical address,
|
||||
* this walks up the tree and applies the various bus mappings on the
|
||||
* way.
|
||||
*
|
||||
* Note: We consider that crossing any level with #size-cells == 0 to mean
|
||||
* that translation is impossible (that is we are not dealing with a value
|
||||
* that can be mapped to a cpu physical address). This is not really specified
|
||||
* that way, but this is traditionally the way IBM at least do things
|
||||
*/
|
||||
u64 __init fdt_translate_address(const void *blob, int node_offset)
|
||||
{
|
||||
int parent, len;
|
||||
const struct of_bus *bus, *pbus;
|
||||
const __be32 *reg;
|
||||
__be32 addr[OF_MAX_ADDR_CELLS];
|
||||
int na, ns, pna, pns;
|
||||
u64 result = OF_BAD_ADDR;
|
||||
|
||||
pr_debug("FDT: ** translation for device %s **\n",
|
||||
fdt_get_name(blob, node_offset, NULL));
|
||||
|
||||
reg = fdt_getprop(blob, node_offset, "reg", &len);
|
||||
if (!reg) {
|
||||
pr_err("FDT: warning: device tree node '%s' has no address.\n",
|
||||
fdt_get_name(blob, node_offset, NULL));
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* Get parent & match bus type */
|
||||
parent = fdt_parent_offset(blob, node_offset);
|
||||
if (parent < 0)
|
||||
goto bail;
|
||||
bus = &of_busses[0];
|
||||
|
||||
/* Cound address cells & copy address locally */
|
||||
bus->count_cells(blob, parent, &na, &ns);
|
||||
if (!OF_CHECK_COUNTS(na, ns)) {
|
||||
pr_err("FDT: Bad cell count for %s\n",
|
||||
fdt_get_name(blob, node_offset, NULL));
|
||||
goto bail;
|
||||
}
|
||||
memcpy(addr, reg, na * 4);
|
||||
|
||||
pr_debug("FDT: bus (na=%d, ns=%d) on %s\n",
|
||||
na, ns, fdt_get_name(blob, parent, NULL));
|
||||
of_dump_addr("OF: translating address:", addr, na);
|
||||
|
||||
/* Translate */
|
||||
for (;;) {
|
||||
/* Switch to parent bus */
|
||||
node_offset = parent;
|
||||
parent = fdt_parent_offset(blob, node_offset);
|
||||
|
||||
/* If root, we have finished */
|
||||
if (parent < 0) {
|
||||
pr_debug("FDT: reached root node\n");
|
||||
result = of_read_number(addr, na);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Get new parent bus and counts */
|
||||
pbus = &of_busses[0];
|
||||
pbus->count_cells(blob, parent, &pna, &pns);
|
||||
if (!OF_CHECK_COUNTS(pna, pns)) {
|
||||
pr_err("FDT: Bad cell count for %s\n",
|
||||
fdt_get_name(blob, node_offset, NULL));
|
||||
break;
|
||||
}
|
||||
|
||||
pr_debug("FDT: parent bus (na=%d, ns=%d) on %s\n",
|
||||
pna, pns, fdt_get_name(blob, parent, NULL));
|
||||
|
||||
/* Apply bus translation */
|
||||
if (fdt_translate_one(blob, node_offset, bus, pbus,
|
||||
addr, na, ns, pna, "ranges"))
|
||||
break;
|
||||
|
||||
/* Complete the move up one level */
|
||||
na = pna;
|
||||
ns = pns;
|
||||
bus = pbus;
|
||||
|
||||
of_dump_addr("FDT: one level translation:", addr, na);
|
||||
}
|
||||
bail:
|
||||
return result;
|
||||
}
|
|
@ -188,7 +188,7 @@ static int __init __reserved_mem_init_node(struct reserved_mem *rmem)
|
|||
if (!of_flat_dt_is_compatible(rmem->fdt_node, compat))
|
||||
continue;
|
||||
|
||||
if (initfn(rmem, rmem->fdt_node, rmem->name) == 0) {
|
||||
if (initfn(rmem) == 0) {
|
||||
pr_info("Reserved memory: initialized node %s, compatible id %s\n",
|
||||
rmem->name, compat);
|
||||
return 0;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,16 @@ 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_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
|
||||
|
@ -1160,6 +1178,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
|
||||
|
@ -1369,18 +1397,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"
|
||||
|
@ -1508,6 +1537,16 @@ config SERIAL_ST_ASC_CONSOLE
|
|||
depends on SERIAL_ST_ASC=y
|
||||
select SERIAL_CORE_CONSOLE
|
||||
|
||||
config SERIAL_MEN_Z135
|
||||
tristate "MEN 16z135 Support"
|
||||
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
|
||||
|
||||
endif # TTY
|
||||
|
|
|
@ -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,4 @@ 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
|
||||
|
|
|
@ -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,35 @@ 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);
|
||||
OF_EARLYCON_DECLARE(pl011, "arm,pl011", pl011_early_console_setup);
|
||||
|
||||
#else
|
||||
#define AMBA_CONSOLE NULL
|
||||
#endif
|
||||
|
|
|
@ -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);
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* 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>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/mod_devicetable.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 const struct of_device_id __earlycon_of_table_sentinel
|
||||
__used __section(__earlycon_of_table_end);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int __init of_setup_earlycon(unsigned long addr,
|
||||
int (*setup)(struct earlycon_device *, const char *))
|
||||
{
|
||||
int err;
|
||||
struct uart_port *port = &early_console_dev.port;
|
||||
|
||||
port->iotype = UPIO_MEM;
|
||||
port->mapbase = addr;
|
||||
port->uartclk = BASE_BAUD * 16;
|
||||
port->membase = earlycon_map(addr, SZ_4K);
|
||||
|
||||
early_console_dev.con->data = &early_console_dev;
|
||||
err = setup(&early_console_dev, NULL);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (!early_console_dev.con->write)
|
||||
return -ENODEV;
|
||||
|
||||
|
||||
register_console(early_console_dev.con);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,866 @@
|
|||
/*
|
||||
* 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) /* TX Space IRQ */
|
||||
#define MEN_Z135_IER_TXCIEN BIT(1) /* RX 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);
|
||||
|
||||
conf_reg |= MEN_Z135_ALL_IRQS;
|
||||
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");
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2239,6 +2239,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
|
||||
|
|
|
@ -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
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -139,52 +139,23 @@
|
|||
#define TRACE_SYSCALLS()
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CLKSRC_OF
|
||||
#define CLKSRC_OF_TABLES() . = ALIGN(8); \
|
||||
VMLINUX_SYMBOL(__clksrc_of_table) = .; \
|
||||
*(__clksrc_of_table) \
|
||||
*(__clksrc_of_table_end)
|
||||
#else
|
||||
#define CLKSRC_OF_TABLES()
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_IRQCHIP
|
||||
#define IRQCHIP_OF_MATCH_TABLE() \
|
||||
#define ___OF_TABLE(cfg, name) _OF_TABLE_##cfg(name)
|
||||
#define __OF_TABLE(cfg, name) ___OF_TABLE(cfg, name)
|
||||
#define OF_TABLE(cfg, name) __OF_TABLE(config_enabled(cfg), name)
|
||||
#define _OF_TABLE_0(name)
|
||||
#define _OF_TABLE_1(name) \
|
||||
. = ALIGN(8); \
|
||||
VMLINUX_SYMBOL(__irqchip_begin) = .; \
|
||||
*(__irqchip_of_table) \
|
||||
*(__irqchip_of_end)
|
||||
#else
|
||||
#define IRQCHIP_OF_MATCH_TABLE()
|
||||
#endif
|
||||
VMLINUX_SYMBOL(__##name##_of_table) = .; \
|
||||
*(__##name##_of_table) \
|
||||
*(__##name##_of_table_end)
|
||||
|
||||
#ifdef CONFIG_COMMON_CLK
|
||||
#define CLK_OF_TABLES() . = ALIGN(8); \
|
||||
VMLINUX_SYMBOL(__clk_of_table) = .; \
|
||||
*(__clk_of_table) \
|
||||
*(__clk_of_table_end)
|
||||
#else
|
||||
#define CLK_OF_TABLES()
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OF_RESERVED_MEM
|
||||
#define RESERVEDMEM_OF_TABLES() \
|
||||
. = ALIGN(8); \
|
||||
VMLINUX_SYMBOL(__reservedmem_of_table) = .; \
|
||||
*(__reservedmem_of_table) \
|
||||
*(__reservedmem_of_table_end)
|
||||
#else
|
||||
#define RESERVEDMEM_OF_TABLES()
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
#define CPU_METHOD_OF_TABLES() . = ALIGN(8); \
|
||||
VMLINUX_SYMBOL(__cpu_method_of_table_begin) = .; \
|
||||
*(__cpu_method_of_table) \
|
||||
VMLINUX_SYMBOL(__cpu_method_of_table_end) = .;
|
||||
#else
|
||||
#define CPU_METHOD_OF_TABLES()
|
||||
#endif
|
||||
#define CLKSRC_OF_TABLES() OF_TABLE(CONFIG_CLKSRC_OF, clksrc)
|
||||
#define IRQCHIP_OF_MATCH_TABLE() OF_TABLE(CONFIG_IRQCHIP, irqchip)
|
||||
#define CLK_OF_TABLES() OF_TABLE(CONFIG_COMMON_CLK, clk)
|
||||
#define RESERVEDMEM_OF_TABLES() OF_TABLE(CONFIG_OF_RESERVED_MEM, reservedmem)
|
||||
#define CPU_METHOD_OF_TABLES() OF_TABLE(CONFIG_SMP, cpu_method)
|
||||
#define EARLYCON_OF_TABLES() OF_TABLE(CONFIG_SERIAL_EARLYCON, earlycon)
|
||||
|
||||
#define KERNEL_DTB() \
|
||||
STRUCT_ALIGN(); \
|
||||
|
@ -513,7 +484,8 @@
|
|||
CLKSRC_OF_TABLES() \
|
||||
CPU_METHOD_OF_TABLES() \
|
||||
KERNEL_DTB() \
|
||||
IRQCHIP_OF_MATCH_TABLE()
|
||||
IRQCHIP_OF_MATCH_TABLE() \
|
||||
EARLYCON_OF_TABLES()
|
||||
|
||||
#define INIT_TEXT \
|
||||
*(.init.text) \
|
||||
|
|
|
@ -498,10 +498,7 @@ struct clk_onecell_data {
|
|||
|
||||
extern struct of_device_id __clk_of_table;
|
||||
|
||||
#define CLK_OF_DECLARE(name, compat, fn) \
|
||||
static const struct of_device_id __clk_of_table_##name \
|
||||
__used __section(__clk_of_table) \
|
||||
= { .compatible = compat, .data = fn };
|
||||
#define CLK_OF_DECLARE(name, compat, fn) OF_DECLARE_1(clk, name, compat, fn)
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
int of_clk_add_provider(struct device_node *np,
|
||||
|
|
|
@ -339,23 +339,13 @@ extern int clocksource_mmio_init(void __iomem *, const char *,
|
|||
|
||||
extern int clocksource_i8253_init(void);
|
||||
|
||||
struct device_node;
|
||||
typedef void(*clocksource_of_init_fn)(struct device_node *);
|
||||
#define CLOCKSOURCE_OF_DECLARE(name, compat, fn) \
|
||||
OF_DECLARE_1(clksrc, name, compat, fn)
|
||||
|
||||
#ifdef CONFIG_CLKSRC_OF
|
||||
extern void clocksource_of_init(void);
|
||||
|
||||
#define CLOCKSOURCE_OF_DECLARE(name, compat, fn) \
|
||||
static const struct of_device_id __clksrc_of_table_##name \
|
||||
__used __section(__clksrc_of_table) \
|
||||
= { .compatible = compat, \
|
||||
.data = (fn == (clocksource_of_init_fn)NULL) ? fn : fn }
|
||||
#else
|
||||
static inline void clocksource_of_init(void) {}
|
||||
#define CLOCKSOURCE_OF_DECLARE(name, compat, fn) \
|
||||
static const struct of_device_id __clksrc_of_table_##name \
|
||||
__attribute__((unused)) \
|
||||
= { .compatible = compat, \
|
||||
.data = (fn == (clocksource_of_init_fn)NULL) ? fn : fn }
|
||||
#endif
|
||||
|
||||
#endif /* _LINUX_CLOCKSOURCE_H */
|
||||
|
|
|
@ -757,4 +757,26 @@ static inline int of_get_available_child_count(const struct device_node *np)
|
|||
return num;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
#define _OF_DECLARE(table, name, compat, fn, fn_type) \
|
||||
static const struct of_device_id __of_table_##name \
|
||||
__used __section(__##table##_of_table) \
|
||||
= { .compatible = compat, \
|
||||
.data = (fn == (fn_type)NULL) ? fn : fn }
|
||||
#else
|
||||
#define _OF_DECLARE(table, name, compat, fn, fn_type) \
|
||||
static const struct of_device_id __of_table_##name \
|
||||
__attribute__((unused)) \
|
||||
= { .compatible = compat, \
|
||||
.data = (fn == (fn_type)NULL) ? fn : fn }
|
||||
#endif
|
||||
|
||||
typedef int (*of_init_fn_2)(struct device_node *, struct device_node *);
|
||||
typedef void (*of_init_fn_1)(struct device_node *);
|
||||
|
||||
#define OF_DECLARE_1(table, name, compat, fn) \
|
||||
_OF_DECLARE(table, name, compat, fn, of_init_fn_1)
|
||||
#define OF_DECLARE_2(table, name, compat, fn) \
|
||||
_OF_DECLARE(table, name, compat, fn, of_init_fn_2)
|
||||
|
||||
#endif /* _LINUX_OF_H */
|
||||
|
|
|
@ -83,6 +83,7 @@ extern void unflatten_device_tree(void);
|
|||
extern void unflatten_and_copy_device_tree(void);
|
||||
extern void early_init_devtree(void *);
|
||||
extern void early_get_first_memblock_info(void *, phys_addr_t *);
|
||||
extern u64 fdt_translate_address(const void *blob, int node_offset);
|
||||
#else /* CONFIG_OF_FLATTREE */
|
||||
static inline void early_init_fdt_scan_reserved_mem(void) {}
|
||||
static inline const char *of_flat_dt_get_machine_name(void) { return NULL; }
|
||||
|
|
|
@ -21,33 +21,19 @@ struct reserved_mem_ops {
|
|||
struct device *dev);
|
||||
};
|
||||
|
||||
typedef int (*reservedmem_of_init_fn)(struct reserved_mem *rmem,
|
||||
unsigned long node, const char *uname);
|
||||
typedef int (*reservedmem_of_init_fn)(struct reserved_mem *rmem);
|
||||
|
||||
#define RESERVEDMEM_OF_DECLARE(name, compat, init) \
|
||||
_OF_DECLARE(reservedmem, name, compat, init, reservedmem_of_init_fn)
|
||||
|
||||
#ifdef CONFIG_OF_RESERVED_MEM
|
||||
void fdt_init_reserved_mem(void);
|
||||
void fdt_reserved_mem_save_node(unsigned long node, const char *uname,
|
||||
phys_addr_t base, phys_addr_t size);
|
||||
|
||||
#define RESERVEDMEM_OF_DECLARE(name, compat, init) \
|
||||
static const struct of_device_id __reservedmem_of_table_##name \
|
||||
__used __section(__reservedmem_of_table) \
|
||||
= { .compatible = compat, \
|
||||
.data = (init == (reservedmem_of_init_fn)NULL) ? \
|
||||
init : init }
|
||||
|
||||
#else
|
||||
static inline void fdt_init_reserved_mem(void) { }
|
||||
static inline void fdt_reserved_mem_save_node(unsigned long node,
|
||||
const char *uname, phys_addr_t base, phys_addr_t size) { }
|
||||
|
||||
#define RESERVEDMEM_OF_DECLARE(name, compat, init) \
|
||||
static const struct of_device_id __reservedmem_of_table_##name \
|
||||
__attribute__((unused)) \
|
||||
= { .compatible = compat, \
|
||||
.data = (init == (reservedmem_of_init_fn)NULL) ? \
|
||||
init : init }
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* __OF_RESERVED_MEM_H */
|
||||
|
|
|
@ -285,6 +285,28 @@ 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 *));
|
||||
|
||||
extern int of_setup_earlycon(unsigned long addr,
|
||||
int (*setup)(struct earlycon_device *, const char *));
|
||||
|
||||
#define EARLYCON_DECLARE(name, func) \
|
||||
static int __init name ## _setup_earlycon(char *buf) \
|
||||
{ \
|
||||
return setup_earlycon(buf, __stringify(name), func); \
|
||||
} \
|
||||
early_param("earlycon", name ## _setup_earlycon);
|
||||
|
||||
#define OF_EARLYCON_DECLARE(name, compat, fn) \
|
||||
_OF_DECLARE(earlycon, name, compat, fn, void *)
|
||||
|
||||
struct uart_port *uart_get_console(struct uart_port *ports, int nr,
|
||||
struct console *c);
|
||||
void uart_parse_options(char *options, int *baud, int *parity, int *bits,
|
||||
|
|
|
@ -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 *)
|
||||
*
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue