diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2015-07-20 10:08:17 -0700 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2015-07-20 10:08:17 -0700 |
commit | c57d5621d2f2dc238f4b9c4d00b2a54187a75445 (patch) | |
tree | ece13738a44545fb110e5d73adbf2625bc7a1ea6 /drivers/tty | |
parent | 6ccfe64c770139675a080ee5029ded7d89d9ea0d (diff) | |
parent | 52721d9d3334c1cb1f76219a161084094ec634dc (diff) | |
download | blackbird-op-linux-c57d5621d2f2dc238f4b9c4d00b2a54187a75445.tar.gz blackbird-op-linux-c57d5621d2f2dc238f4b9c4d00b2a54187a75445.zip |
Merge tag 'v4.2-rc3' into next
Sync up with Linux 4.2-rc3 to bring in infrastructure (OF) pieces.
Diffstat (limited to 'drivers/tty')
106 files changed, 6275 insertions, 6156 deletions
diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index b24aa010f68c..c01f45095877 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig @@ -419,4 +419,51 @@ config DA_CONSOLE help This enables a console on a Dash channel. +config MIPS_EJTAG_FDC_TTY + bool "MIPS EJTAG Fast Debug Channel TTY" + depends on MIPS_CDMM + help + This enables a TTY and console on the MIPS EJTAG Fast Debug Channels, + if they are present. This can be useful when working with an EJTAG + probe which supports it, to get console output and a login prompt via + EJTAG without needing to connect a serial cable. + + TTY devices are named e.g. ttyFDC3c2 (for FDC channel 2 of the FDC on + CPU3). + + The console can be enabled with console=fdc1 (for FDC channel 1 on all + CPUs). Do not use the console unless there is a debug probe attached + to drain the FDC TX FIFO. + + If unsure, say N. + +config MIPS_EJTAG_FDC_EARLYCON + bool "Early FDC console" + depends on MIPS_EJTAG_FDC_TTY + help + This registers a console on FDC channel 1 very early during boot (from + MIPS arch code). This is useful for bring-up and debugging early boot + issues. + + Do not enable unless there is a debug probe attached to drain the FDC + TX FIFO. + + If unsure, say N. + +config MIPS_EJTAG_FDC_KGDB + bool "Use KGDB over an FDC channel" + depends on MIPS_EJTAG_FDC_TTY && KGDB + default y + help + This enables the use of KGDB over an FDC channel, allowing KGDB to be + used remotely or when a serial port isn't available. + +config MIPS_EJTAG_FDC_KGDB_CHAN + int "KGDB FDC channel" + depends on MIPS_EJTAG_FDC_KGDB + range 2 15 + default 3 + help + FDC channel number to use for KGDB. + endif # TTY diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile index 58ad1c05b7f8..5817e2397463 100644 --- a/drivers/tty/Makefile +++ b/drivers/tty/Makefile @@ -29,5 +29,6 @@ obj-$(CONFIG_SYNCLINK) += synclink.o obj-$(CONFIG_PPC_EPAPR_HV_BYTECHAN) += ehv_bytechan.o obj-$(CONFIG_GOLDFISH_TTY) += goldfish.o obj-$(CONFIG_DA_TTY) += metag_da.o +obj-$(CONFIG_MIPS_EJTAG_FDC_TTY) += mips_ejtag_fdc.o obj-y += ipwireless/ diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index b2d760055952..e53d9a512c6d 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -966,9 +966,7 @@ static void rs_throttle(struct tty_struct * tty) struct serial_state *info = tty->driver_data; unsigned long flags; #ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("throttle %s: %d....\n", tty_name(tty, buf), + printk("throttle %s: %d....\n", tty_name(tty), tty->ldisc.chars_in_buffer(tty)); #endif @@ -991,9 +989,7 @@ static void rs_unthrottle(struct tty_struct * tty) struct serial_state *info = tty->driver_data; unsigned long flags; #ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("unthrottle %s: %d....\n", tty_name(tty, buf), + printk("unthrottle %s: %d....\n", tty_name(tty), tty->ldisc.chars_in_buffer(tty)); #endif @@ -1786,7 +1782,8 @@ static int __exit amiga_serial_remove(struct platform_device *pdev) struct serial_state *state = platform_get_drvdata(pdev); /* printk("Unloading %s: version %s\n", serial_name, serial_version); */ - if ((error = tty_unregister_driver(serial_driver))) + error = tty_unregister_driver(serial_driver); + if (error) printk("SERIAL: failed to unregister serial driver (%d)\n", error); put_tty_driver(serial_driver); diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index fd66f57390d0..87f6578c6f4a 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c @@ -2861,9 +2861,7 @@ static void cy_throttle(struct tty_struct *tty) unsigned long flags; #ifdef CY_DEBUG_THROTTLE - char buf[64]; - - printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty, buf), + printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty), tty->ldisc.chars_in_buffer(tty), info->line); #endif @@ -2902,10 +2900,8 @@ static void cy_unthrottle(struct tty_struct *tty) unsigned long flags; #ifdef CY_DEBUG_THROTTLE - char buf[64]; - printk(KERN_DEBUG "cyc:unthrottle %s: %ld...ttyC%d\n", - tty_name(tty, buf), tty_chars_in_buffer(tty), info->line); + tty_name(tty), tty_chars_in_buffer(tty), info->line); #endif if (serial_paranoia_check(info, tty->name, "cy_unthrottle")) diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c index 967b2c2b7cf1..0f82c0b146f6 100644 --- a/drivers/tty/goldfish.c +++ b/drivers/tty/goldfish.c @@ -59,7 +59,7 @@ static void goldfish_tty_do_write(int line, const char *buf, unsigned count) struct goldfish_tty *qtty = &goldfish_ttys[line]; void __iomem *base = qtty->base; spin_lock_irqsave(&qtty->lock, irq_flags); - gf_write64((u64)buf, base + GOLDFISH_TTY_DATA_PTR, + gf_write_ptr(buf, base + GOLDFISH_TTY_DATA_PTR, base + GOLDFISH_TTY_DATA_PTR_HIGH); writel(count, base + GOLDFISH_TTY_DATA_LEN); writel(GOLDFISH_TTY_CMD_WRITE_BUFFER, base + GOLDFISH_TTY_CMD); @@ -81,7 +81,7 @@ static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id) count = tty_prepare_flip_string(&qtty->port, &buf, count); spin_lock_irqsave(&qtty->lock, irq_flags); - gf_write64((u64)buf, base + GOLDFISH_TTY_DATA_PTR, + gf_write_ptr(buf, base + GOLDFISH_TTY_DATA_PTR, base + GOLDFISH_TTY_DATA_PTR_HIGH); writel(count, base + GOLDFISH_TTY_DATA_LEN); writel(GOLDFISH_TTY_CMD_READ_BUFFER, base + GOLDFISH_TTY_CMD); @@ -229,7 +229,6 @@ static int goldfish_tty_probe(struct platform_device *pdev) { struct goldfish_tty *qtty; int ret = -EINVAL; - int i; struct resource *r; struct device *ttydev; void __iomem *base; @@ -293,7 +292,6 @@ static int goldfish_tty_probe(struct platform_device *pdev) mutex_unlock(&goldfish_tty_lock); return 0; - tty_unregister_device(goldfish_tty_driver, i); err_tty_register_device_failed: free_irq(irq, pdev); err_request_irq_failed: diff --git a/drivers/tty/hvc/Kconfig b/drivers/tty/hvc/Kconfig index 8902f9b4df71..2509d057b99c 100644 --- a/drivers/tty/hvc/Kconfig +++ b/drivers/tty/hvc/Kconfig @@ -42,13 +42,6 @@ config HVC_RTAS help IBM Console device driver which makes use of RTAS -config HVC_BEAT - bool "Toshiba's Beat Hypervisor Console support" - depends on PPC_CELLEB - select HVC_DRIVER - help - Toshiba's Cell Reference Set Beat Console device driver - config HVC_IUCV bool "z/VM IUCV Hypervisor console support (VM only)" depends on S390 diff --git a/drivers/tty/hvc/Makefile b/drivers/tty/hvc/Makefile index 4ca3723b0a3a..6a2702be76d1 100644 --- a/drivers/tty/hvc/Makefile +++ b/drivers/tty/hvc/Makefile @@ -4,7 +4,6 @@ obj-$(CONFIG_HVC_OLD_HVSI) += hvsi.o obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o obj-$(CONFIG_HVC_TILE) += hvc_tile.o obj-$(CONFIG_HVC_DCC) += hvc_dcc.o -obj-$(CONFIG_HVC_BEAT) += hvc_beat.o obj-$(CONFIG_HVC_DRIVER) += hvc_console.o obj-$(CONFIG_HVC_IRQ) += hvc_irq.o obj-$(CONFIG_HVC_XEN) += hvc_xen.o diff --git a/drivers/tty/hvc/hvc_beat.c b/drivers/tty/hvc/hvc_beat.c deleted file mode 100644 index 1560d235449e..000000000000 --- a/drivers/tty/hvc/hvc_beat.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Beat hypervisor console driver - * - * (C) Copyright 2006 TOSHIBA CORPORATION - * - * This code is based on drivers/char/hvc_rtas.c: - * (C) Copyright IBM Corporation 2001-2005 - * (C) Copyright Red Hat, Inc. 2005 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/err.h> -#include <linux/string.h> -#include <linux/console.h> -#include <asm/prom.h> -#include <asm/hvconsole.h> -#include <asm/firmware.h> - -#include "hvc_console.h" - -extern int64_t beat_get_term_char(uint64_t, uint64_t *, uint64_t *, uint64_t *); -extern int64_t beat_put_term_char(uint64_t, uint64_t, uint64_t, uint64_t); - -struct hvc_struct *hvc_beat_dev = NULL; - -/* bug: only one queue is available regardless of vtermno */ -static int hvc_beat_get_chars(uint32_t vtermno, char *buf, int cnt) -{ - static unsigned char q[sizeof(unsigned long) * 2] - __attribute__((aligned(sizeof(unsigned long)))); - static int qlen = 0; - u64 got; - -again: - if (qlen) { - if (qlen > cnt) { - memcpy(buf, q, cnt); - qlen -= cnt; - memmove(q + cnt, q, qlen); - return cnt; - } else { /* qlen <= cnt */ - int r; - - memcpy(buf, q, qlen); - r = qlen; - qlen = 0; - return r; - } - } - if (beat_get_term_char(vtermno, &got, - ((u64 *)q), ((u64 *)q) + 1) == 0) { - qlen = got; - goto again; - } - return 0; -} - -static int hvc_beat_put_chars(uint32_t vtermno, const char *buf, int cnt) -{ - unsigned long kb[2]; - int rest, nlen; - - for (rest = cnt; rest > 0; rest -= nlen) { - nlen = (rest > 16) ? 16 : rest; - memcpy(kb, buf, nlen); - beat_put_term_char(vtermno, nlen, kb[0], kb[1]); - buf += nlen; - } - return cnt; -} - -static const struct hv_ops hvc_beat_get_put_ops = { - .get_chars = hvc_beat_get_chars, - .put_chars = hvc_beat_put_chars, -}; - -static int hvc_beat_useit = 1; - -static int hvc_beat_config(char *p) -{ - hvc_beat_useit = simple_strtoul(p, NULL, 0); - return 0; -} - -static int __init hvc_beat_console_init(void) -{ - if (hvc_beat_useit && of_machine_is_compatible("Beat")) { - hvc_instantiate(0, 0, &hvc_beat_get_put_ops); - } - return 0; -} - -/* temp */ -static int __init hvc_beat_init(void) -{ - struct hvc_struct *hp; - - if (!firmware_has_feature(FW_FEATURE_BEAT)) - return -ENODEV; - - hp = hvc_alloc(0, 0, &hvc_beat_get_put_ops, 16); - if (IS_ERR(hp)) - return PTR_ERR(hp); - hvc_beat_dev = hp; - return 0; -} - -static void __exit hvc_beat_exit(void) -{ - if (hvc_beat_dev) - hvc_remove(hvc_beat_dev); -} - -module_init(hvc_beat_init); -module_exit(hvc_beat_exit); - -__setup("hvc_beat=", hvc_beat_config); - -console_initcall(hvc_beat_console_init); diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index 4fcec1d793a7..4e9c4cc9e1b5 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -319,7 +319,8 @@ static int hvc_install(struct tty_driver *driver, struct tty_struct *tty) int rc; /* Auto increments kref reference if found. */ - if (!(hp = hvc_get_by_index(tty->index))) + hp = hvc_get_by_index(tty->index); + if (!hp) return -ENODEV; tty->driver_data = hp; diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c index f78a87b07872..bb809cf36617 100644 --- a/drivers/tty/hvc/hvc_iucv.c +++ b/drivers/tty/hvc/hvc_iucv.c @@ -1345,7 +1345,7 @@ static int param_get_vmidfilter(char *buffer, const struct kernel_param *kp) #define param_check_vmidfilter(name, p) __param_check(name, p, void) -static struct kernel_param_ops param_ops_vmidfilter = { +static const struct kernel_param_ops param_ops_vmidfilter = { .set = param_set_vmidfilter, .get = param_get_vmidfilter, }; diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c index 071551bf3e9a..47b54c6aefd2 100644 --- a/drivers/tty/hvc/hvc_opal.c +++ b/drivers/tty/hvc/hvc_opal.c @@ -29,6 +29,7 @@ #include <linux/of.h> #include <linux/of_platform.h> #include <linux/export.h> +#include <linux/interrupt.h> #include <asm/hvconsole.h> #include <asm/prom.h> @@ -41,7 +42,7 @@ static const char hvc_opal_name[] = "hvc_opal"; -static struct of_device_id hvc_opal_match[] = { +static const struct of_device_id hvc_opal_match[] = { { .name = "serial", .compatible = "ibm,opal-console-raw" }, { .name = "serial", .compatible = "ibm,opal-console-hvsi" }, { }, @@ -61,7 +62,6 @@ static struct hvc_opal_priv *hvc_opal_privs[MAX_NR_HVC_CONSOLES]; /* For early boot console */ static struct hvc_opal_priv hvc_opal_boot_priv; static u32 hvc_opal_boot_termno; -static bool hvc_opal_event_registered; static const struct hv_ops hvc_opal_raw_ops = { .get_chars = opal_get_chars, @@ -162,28 +162,15 @@ static const struct hv_ops hvc_opal_hvsi_ops = { .tiocmset = hvc_opal_hvsi_tiocmset, }; -static int hvc_opal_console_event(struct notifier_block *nb, - unsigned long events, void *change) -{ - if (events & OPAL_EVENT_CONSOLE_INPUT) - hvc_kick(); - return 0; -} - -static struct notifier_block hvc_opal_console_nb = { - .notifier_call = hvc_opal_console_event, -}; - static int hvc_opal_probe(struct platform_device *dev) { const struct hv_ops *ops; struct hvc_struct *hp; struct hvc_opal_priv *pv; hv_protocol_t proto; - unsigned int termno, boot = 0; + unsigned int termno, irq, boot = 0; const __be32 *reg; - if (of_device_is_compatible(dev->dev.of_node, "ibm,opal-console-raw")) { proto = HV_PROTOCOL_RAW; ops = &hvc_opal_raw_ops; @@ -227,18 +214,18 @@ static int hvc_opal_probe(struct platform_device *dev) dev->dev.of_node->full_name, boot ? " (boot console)" : ""); - /* We don't do IRQ ... */ - hp = hvc_alloc(termno, 0, ops, MAX_VIO_PUT_CHARS); + irq = opal_event_request(ilog2(OPAL_EVENT_CONSOLE_INPUT)); + if (!irq) { + pr_err("hvc_opal: Unable to map interrupt for device %s\n", + dev->dev.of_node->full_name); + return irq; + } + + hp = hvc_alloc(termno, irq, ops, MAX_VIO_PUT_CHARS); if (IS_ERR(hp)) return PTR_ERR(hp); dev_set_drvdata(&dev->dev, hp); - /* ... but we use OPAL event to kick the console */ - if (!hvc_opal_event_registered) { - opal_notifier_register(&hvc_opal_console_nb); - hvc_opal_event_registered = true; - } - return 0; } diff --git a/drivers/tty/hvc/hvc_tile.c b/drivers/tty/hvc/hvc_tile.c index 3f6cd3102db5..9da1e842bbe9 100644 --- a/drivers/tty/hvc/hvc_tile.c +++ b/drivers/tty/hvc/hvc_tile.c @@ -51,7 +51,8 @@ int tile_console_write(const char *buf, int count) _SIM_CONTROL_OPERATOR_BITS)); return 0; } else { - return hv_console_write((HV_VirtAddr)buf, count); + /* Translate 0 bytes written to EAGAIN for hvc_console_print. */ + return hv_console_write((HV_VirtAddr)buf, count) ?: -EAGAIN; } } diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index f1e57425e39f..a9d837f83ce8 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c @@ -289,7 +289,7 @@ static int xen_initial_domain_console_init(void) return -ENOMEM; } - info->irq = bind_virq_to_irq(VIRQ_CONSOLE, 0); + info->irq = bind_virq_to_irq(VIRQ_CONSOLE, 0, false); info->vtermno = HVC_COOKIE; spin_lock(&xencons_lock); @@ -299,11 +299,27 @@ static int xen_initial_domain_console_init(void) return 0; } +static void xen_console_update_evtchn(struct xencons_info *info) +{ + if (xen_hvm_domain()) { + uint64_t v = 0; + int err; + + err = hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &v); + if (!err && v) + info->evtchn = v; + } else + info->evtchn = xen_start_info->console.domU.evtchn; +} + void xen_console_resume(void) { struct xencons_info *info = vtermno_to_xencons(HVC_COOKIE); - if (info != NULL && info->irq) + if (info != NULL && info->irq) { + if (!xen_initial_domain()) + xen_console_update_evtchn(info); rebind_evtchn_irq(info->evtchn, info->irq); + } } static void xencons_disconnect_backend(struct xencons_info *info) diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index 81ff7e1bfb1a..f7ff97c0ad34 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -1044,8 +1044,8 @@ static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address, * It is possible that the vty-server was removed between the time that * the conn was registered and now. */ - if (!(rc = request_irq(irq, &hvcs_handle_interrupt, - 0, "ibmhvcs", hvcsd))) { + rc = request_irq(irq, &hvcs_handle_interrupt, 0, "ibmhvcs", hvcsd); + if (!rc) { /* * It is possible the vty-server was removed after the irq was * requested but before we have time to enable interrupts. diff --git a/drivers/tty/ipwireless/hardware.c b/drivers/tty/ipwireless/hardware.c index 5c77e1eac4ee..ad7031a4f3c4 100644 --- a/drivers/tty/ipwireless/hardware.c +++ b/drivers/tty/ipwireless/hardware.c @@ -1455,7 +1455,7 @@ static void __handle_setup_get_version_rsp(struct ipw_hardware *hw) return; } - set_RTS(hw, PRIO_SETUP, channel_idx, + ret = set_RTS(hw, PRIO_SETUP, channel_idx, (hw->control_lines [channel_idx] & IPW_CONTROL_LINE_RTS) != 0); if (ret) { diff --git a/drivers/tty/metag_da.c b/drivers/tty/metag_da.c index 3774600741d8..9325262289f9 100644 --- a/drivers/tty/metag_da.c +++ b/drivers/tty/metag_da.c @@ -640,25 +640,7 @@ err_destroy_ports: put_tty_driver(channel_driver); return ret; } - -static void dashtty_exit(void) -{ - int nport; - struct dashtty_port *dport; - - del_timer_sync(&put_timer); - kthread_stop(dashtty_thread); - del_timer_sync(&poll_timer); - tty_unregister_driver(channel_driver); - for (nport = 0; nport < NUM_TTY_CHANNELS; nport++) { - dport = &dashtty_ports[nport]; - tty_port_destroy(&dport->port); - } - put_tty_driver(channel_driver); -} - -module_init(dashtty_init); -module_exit(dashtty_exit); +device_initcall(dashtty_init); #ifdef CONFIG_DA_CONSOLE diff --git a/drivers/tty/mips_ejtag_fdc.c b/drivers/tty/mips_ejtag_fdc.c new file mode 100644 index 000000000000..358323c83b4f --- /dev/null +++ b/drivers/tty/mips_ejtag_fdc.c @@ -0,0 +1,1304 @@ +/* + * TTY driver for MIPS EJTAG Fast Debug Channels. + * + * Copyright (C) 2007-2015 Imagination Technologies Ltd + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for more + * details. + */ + +#include <linux/atomic.h> +#include <linux/bitops.h> +#include <linux/completion.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/export.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/kgdb.h> +#include <linux/kthread.h> +#include <linux/sched.h> +#include <linux/serial.h> +#include <linux/serial_core.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/tty.h> +#include <linux/tty_driver.h> +#include <linux/tty_flip.h> +#include <linux/uaccess.h> + +#include <asm/cdmm.h> +#include <asm/irq.h> + +/* Register offsets */ +#define REG_FDACSR 0x00 /* FDC Access Control and Status Register */ +#define REG_FDCFG 0x08 /* FDC Configuration Register */ +#define REG_FDSTAT 0x10 /* FDC Status Register */ +#define REG_FDRX 0x18 /* FDC Receive Register */ +#define REG_FDTX(N) (0x20+0x8*(N)) /* FDC Transmit Register n (0..15) */ + +/* Register fields */ + +#define REG_FDCFG_TXINTTHRES_SHIFT 18 +#define REG_FDCFG_TXINTTHRES (0x3 << REG_FDCFG_TXINTTHRES_SHIFT) +#define REG_FDCFG_TXINTTHRES_DISABLED (0x0 << REG_FDCFG_TXINTTHRES_SHIFT) +#define REG_FDCFG_TXINTTHRES_EMPTY (0x1 << REG_FDCFG_TXINTTHRES_SHIFT) +#define REG_FDCFG_TXINTTHRES_NOTFULL (0x2 << REG_FDCFG_TXINTTHRES_SHIFT) +#define REG_FDCFG_TXINTTHRES_NEAREMPTY (0x3 << REG_FDCFG_TXINTTHRES_SHIFT) +#define REG_FDCFG_RXINTTHRES_SHIFT 16 +#define REG_FDCFG_RXINTTHRES (0x3 << REG_FDCFG_RXINTTHRES_SHIFT) +#define REG_FDCFG_RXINTTHRES_DISABLED (0x0 << REG_FDCFG_RXINTTHRES_SHIFT) +#define REG_FDCFG_RXINTTHRES_FULL (0x1 << REG_FDCFG_RXINTTHRES_SHIFT) +#define REG_FDCFG_RXINTTHRES_NOTEMPTY (0x2 << REG_FDCFG_RXINTTHRES_SHIFT) +#define REG_FDCFG_RXINTTHRES_NEARFULL (0x3 << REG_FDCFG_RXINTTHRES_SHIFT) +#define REG_FDCFG_TXFIFOSIZE_SHIFT 8 +#define REG_FDCFG_TXFIFOSIZE (0xff << REG_FDCFG_TXFIFOSIZE_SHIFT) +#define REG_FDCFG_RXFIFOSIZE_SHIFT 0 +#define REG_FDCFG_RXFIFOSIZE (0xff << REG_FDCFG_RXFIFOSIZE_SHIFT) + +#define REG_FDSTAT_TXCOUNT_SHIFT 24 +#define REG_FDSTAT_TXCOUNT (0xff << REG_FDSTAT_TXCOUNT_SHIFT) +#define REG_FDSTAT_RXCOUNT_SHIFT 16 +#define REG_FDSTAT_RXCOUNT (0xff << REG_FDSTAT_RXCOUNT_SHIFT) +#define REG_FDSTAT_RXCHAN_SHIFT 4 +#define REG_FDSTAT_RXCHAN (0xf << REG_FDSTAT_RXCHAN_SHIFT) +#define REG_FDSTAT_RXE BIT(3) /* Rx Empty */ +#define REG_FDSTAT_RXF BIT(2) /* Rx Full */ +#define REG_FDSTAT_TXE BIT(1) /* Tx Empty */ +#define REG_FDSTAT_TXF BIT(0) /* Tx Full */ + +/* Default channel for the early console */ +#define CONSOLE_CHANNEL 1 + +#define NUM_TTY_CHANNELS 16 + +#define RX_BUF_SIZE 1024 + +/* + * When the IRQ is unavailable, the FDC state must be polled for incoming data + * and space becoming available in TX FIFO. + */ +#define FDC_TTY_POLL (HZ / 50) + +struct mips_ejtag_fdc_tty; + +/** + * struct mips_ejtag_fdc_tty_port - Wrapper struct for FDC tty_port. + * @port: TTY port data + * @driver: TTY driver. + * @rx_lock: Lock for rx_buf. + * This protects between the hard interrupt and user + * context. It's also held during read SWITCH operations. + * @rx_buf: Read buffer. + * @xmit_lock: Lock for xmit_*, and port.xmit_buf. + * This protects between user context and kernel thread. + * It is used from chars_in_buffer()/write_room() TTY + * callbacks which are used during wait operations, so a + * mutex is unsuitable. + * @xmit_cnt: Size of xmit buffer contents. + * @xmit_head: Head of xmit buffer where data is written. + * @xmit_tail: Tail of xmit buffer where data is read. + * @xmit_empty: Completion for xmit buffer being empty. + */ +struct mips_ejtag_fdc_tty_port { + struct tty_port port; + struct mips_ejtag_fdc_tty *driver; + raw_spinlock_t rx_lock; + void *rx_buf; + spinlock_t xmit_lock; + unsigned int xmit_cnt; + unsigned int xmit_head; + unsigned int xmit_tail; + struct completion xmit_empty; +}; + +/** + * struct mips_ejtag_fdc_tty - Driver data for FDC as a whole. + * @dev: FDC device (for dev_*() logging). + * @driver: TTY driver. + * @cpu: CPU number for this FDC. + * @fdc_name: FDC name (not for base of channel names). + * @driver_name: Base of driver name. + * @ports: Per-channel data. + * @waitqueue: Wait queue for waiting for TX data, or for space in TX + * FIFO. + * @lock: Lock to protect FDCFG (interrupt enable). + * @thread: KThread for writing out data to FDC. + * @reg: FDC registers. + * @tx_fifo: TX FIFO size. + * @xmit_size: Size of each port's xmit buffer. + * @xmit_total: Total number of bytes (from all ports) to transmit. + * @xmit_next: Next port number to transmit from (round robin). + * @xmit_full: Indicates TX FIFO is full, we're waiting for space. + * @irq: IRQ number (negative if no IRQ). + * @removing: Indicates the device is being removed and @poll_timer + * should not be restarted. + * @poll_timer: Timer for polling for interrupt events when @irq < 0. + * @sysrq_pressed: Whether the magic sysrq key combination has been + * detected. See mips_ejtag_fdc_handle(). + */ +struct mips_ejtag_fdc_tty { + struct device *dev; + struct tty_driver *driver; + unsigned int cpu; + char fdc_name[16]; + char driver_name[16]; + struct mips_ejtag_fdc_tty_port ports[NUM_TTY_CHANNELS]; + wait_queue_head_t waitqueue; + raw_spinlock_t lock; + struct task_struct *thread; + + void __iomem *reg; + u8 tx_fifo; + + unsigned int xmit_size; + atomic_t xmit_total; + unsigned int xmit_next; + bool xmit_full; + + int irq; + bool removing; + struct timer_list poll_timer; + +#ifdef CONFIG_MAGIC_SYSRQ + bool sysrq_pressed; +#endif +}; + +/* Hardware access */ + +static inline void mips_ejtag_fdc_write(struct mips_ejtag_fdc_tty *priv, + unsigned int offs, unsigned int data) +{ + __raw_writel(data, priv->reg + offs); +} + +static inline unsigned int mips_ejtag_fdc_read(struct mips_ejtag_fdc_tty *priv, + unsigned int offs) +{ + return __raw_readl(priv->reg + offs); +} + +/* Encoding of byte stream in FDC words */ + +/** + * struct fdc_word - FDC word encoding some number of bytes of data. + * @word: Raw FDC word. + * @bytes: Number of bytes encoded by @word. + */ +struct fdc_word { + u32 word; + unsigned int bytes; +}; + +/* + * This is a compact encoding which allows every 1 byte, 2 byte, and 3 byte + * sequence to be encoded in a single word, while allowing the majority of 4 + * byte sequences (including all ASCII and common binary data) to be encoded in + * a single word too. + * _______________________ _____________ + * | FDC Word | | + * |31-24|23-16|15-8 | 7-0 | Bytes | + * |_____|_____|_____|_____|_____________| + * | | | | | | + * |0x80 |0x80 |0x80 | WW | WW | + * |0x81 |0x81 | XX | WW | WW XX | + * |0x82 | YY | XX | WW | WW XX YY | + * | ZZ | YY | XX | WW | WW XX YY ZZ | + * |_____|_____|_____|_____|_____________| + * + * Note that the 4-byte encoding can only be used where none of the other 3 + * encodings match, otherwise it must fall back to the 3 byte encoding. + */ + +/* ranges >= 1 && sizes[0] >= 1 */ +static struct fdc_word mips_ejtag_fdc_encode(const char **ptrs, + unsigned int *sizes, + unsigned int ranges) +{ + struct fdc_word word = { 0, 0 }; + const char **ptrs_end = ptrs + ranges; + + for (; ptrs < ptrs_end; ++ptrs) { + const char *ptr = *(ptrs++); + const char *end = ptr + *(sizes++); + + for (; ptr < end; ++ptr) { + word.word |= (u8)*ptr << (8*word.bytes); + ++word.bytes; + if (word.bytes == 4) + goto done; + } + } +done: + /* Choose the appropriate encoding */ + switch (word.bytes) { + case 4: + /* 4 byte encoding, but don't match the 1-3 byte encodings */ + if ((word.word >> 8) != 0x808080 && + (word.word >> 16) != 0x8181 && + (word.word >> 24) != 0x82) + break; + /* Fall back to a 3 byte encoding */ + word.bytes = 3; + word.word &= 0x00ffffff; + case 3: + /* 3 byte encoding */ + word.word |= 0x82000000; + break; + case 2: + /* 2 byte encoding */ + word.word |= 0x81810000; + break; + case 1: + /* 1 byte encoding */ + word.word |= 0x80808000; + break; + } + return word; +} + +static unsigned int mips_ejtag_fdc_decode(u32 word, char *buf) +{ + buf[0] = (u8)word; + word >>= 8; + if (word == 0x808080) + return 1; + buf[1] = (u8)word; + word >>= 8; + if (word == 0x8181) + return 2; + buf[2] = (u8)word; + word >>= 8; + if (word == 0x82) + return 3; + buf[3] = (u8)word; + return 4; +} + +/* Console operations */ + +/** + * struct mips_ejtag_fdc_console - Wrapper struct for FDC consoles. + * @cons: Console object. + * @tty_drv: TTY driver associated with this console. + * @lock: Lock to protect concurrent access to other fields. + * This is raw because it may be used very early. + * @initialised: Whether the console is initialised. + * @regs: Registers base address for each CPU. + */ +struct mips_ejtag_fdc_console { + struct console cons; + struct tty_driver *tty_drv; + raw_spinlock_t lock; + bool initialised; + void __iomem *regs[NR_CPUS]; +}; + +/* Low level console write shared by early console and normal console */ +static void mips_ejtag_fdc_console_write(struct console *c, const char *s, + unsigned int count) +{ + struct mips_ejtag_fdc_console *cons = + container_of(c, struct mips_ejtag_fdc_console, cons); + void __iomem *regs; + struct fdc_word word; + unsigned long flags; + unsigned int i, buf_len, cpu; + bool done_cr = false; + char buf[4]; + const char *buf_ptr = buf; + /* Number of bytes of input data encoded up to each byte in buf */ + u8 inc[4]; + + local_irq_save(flags); + cpu = smp_processor_id(); + regs = cons->regs[cpu]; + /* First console output on this CPU? */ + if (!regs) { + regs = mips_cdmm_early_probe(0xfd); + cons->regs[cpu] = regs; + } + /* Already tried and failed to find FDC on this CPU? */ + if (IS_ERR(regs)) + goto out; + while (count) { + /* + * Copy the next few characters to a buffer so we can inject + * carriage returns before newlines. + */ + for (buf_len = 0, i = 0; buf_len < 4 && i < count; ++buf_len) { + if (s[i] == '\n' && !done_cr) { + buf[buf_len] = '\r'; + done_cr = true; + } else { + buf[buf_len] = s[i]; + done_cr = false; + ++i; + } + inc[buf_len] = i; + } + word = mips_ejtag_fdc_encode(&buf_ptr, &buf_len, 1); + count -= inc[word.bytes - 1]; + s += inc[word.bytes - 1]; + + /* Busy wait until there's space in fifo */ + while (__raw_readl(regs + REG_FDSTAT) & REG_FDSTAT_TXF) + ; + __raw_writel(word.word, regs + REG_FDTX(c->index)); + } +out: + local_irq_restore(flags); +} + +static struct tty_driver *mips_ejtag_fdc_console_device(struct console *c, + int *index) +{ + struct mips_ejtag_fdc_console *cons = + container_of(c, struct mips_ejtag_fdc_console, cons); + + *index = c->index; + return cons->tty_drv; +} + +/* Initialise an FDC console (early or normal */ +static int __init mips_ejtag_fdc_console_init(struct mips_ejtag_fdc_console *c) +{ + void __iomem *regs; + unsigned long flags; + int ret = 0; + + raw_spin_lock_irqsave(&c->lock, flags); + /* Don't init twice */ + if (c->initialised) + goto out; + /* Look for the FDC device */ + regs = mips_cdmm_early_probe(0xfd); + if (IS_ERR(regs)) { + ret = PTR_ERR(regs); + goto out; + } + + c->initialised = true; + c->regs[smp_processor_id()] = regs; + register_console(&c->cons); +out: + raw_spin_unlock_irqrestore(&c->lock, flags); + return ret; +} + +static struct mips_ejtag_fdc_console mips_ejtag_fdc_con = { + .cons = { + .name = "fdc", + .write = mips_ejtag_fdc_console_write, + .device = mips_ejtag_fdc_console_device, + .flags = CON_PRINTBUFFER, + .index = -1, + }, + .lock = __RAW_SPIN_LOCK_UNLOCKED(mips_ejtag_fdc_con.lock), +}; + +/* TTY RX/TX operations */ + +/** + * mips_ejtag_fdc_put_chan() - Write out a block of channel data. + * @priv: Pointer to driver private data. + * @chan: Channel number. + * + * Write a single block of data out to the debug adapter. If the circular buffer + * is wrapped then only the first block is written. + * + * Returns: The number of bytes that were written. + */ +static unsigned int mips_ejtag_fdc_put_chan(struct mips_ejtag_fdc_tty *priv, + unsigned int chan) +{ + struct mips_ejtag_fdc_tty_port *dport; + struct tty_struct *tty; + const char *ptrs[2]; + unsigned int sizes[2] = { 0 }; + struct fdc_word word = { .bytes = 0 }; + unsigned long flags; + + dport = &priv->ports[chan]; + spin_lock(&dport->xmit_lock); + if (dport->xmit_cnt) { + ptrs[0] = dport->port.xmit_buf + dport->xmit_tail; + sizes[0] = min_t(unsigned int, + priv->xmit_size - dport->xmit_tail, + dport->xmit_cnt); + ptrs[1] = dport->port.xmit_buf; + sizes[1] = dport->xmit_cnt - sizes[0]; + word = mips_ejtag_fdc_encode(ptrs, sizes, 1 + !!sizes[1]); + + dev_dbg(priv->dev, "%s%u: out %08x: \"%*pE%*pE\"\n", + priv->driver_name, chan, word.word, + min_t(int, word.bytes, sizes[0]), ptrs[0], + max_t(int, 0, word.bytes - sizes[0]), ptrs[1]); + + local_irq_save(flags); + /* Maybe we raced with the console and TX FIFO is full */ + if (mips_ejtag_fdc_read(priv, REG_FDSTAT) & REG_FDSTAT_TXF) + word.bytes = 0; + else + mips_ejtag_fdc_write(priv, REG_FDTX(chan), word.word); + local_irq_restore(flags); + + dport->xmit_cnt -= word.bytes; + if (!dport->xmit_cnt) { + /* Reset pointers to avoid wraps */ + dport->xmit_head = 0; + dport->xmit_tail = 0; + complete(&dport->xmit_empty); + } else { + dport->xmit_tail += word.bytes; + if (dport->xmit_tail >= priv->xmit_size) + dport->xmit_tail -= priv->xmit_size; + } + atomic_sub(word.bytes, &priv->xmit_total); + } + spin_unlock(&dport->xmit_lock); + + /* If we've made more data available, wake up tty */ + if (sizes[0] && word.bytes) { + tty = tty_port_tty_get(&dport->port); + if (tty) { + tty_wakeup(tty); + tty_kref_put(tty); + } + } + + return word.bytes; +} + +/** + * mips_ejtag_fdc_put() - Kernel thread to write out channel data to FDC. + * @arg: Driver pointer. + * + * This kernel thread runs while @priv->xmit_total != 0, and round robins the + * channels writing out blocks of buffered data to the FDC TX FIFO. + */ +static int mips_ejtag_fdc_put(void *arg) +{ + struct mips_ejtag_fdc_tty *priv = arg; + struct mips_ejtag_fdc_tty_port *dport; + unsigned int ret; + u32 cfg; + + __set_current_state(TASK_RUNNING); + while (!kthread_should_stop()) { + /* Wait for data to actually write */ + wait_event_interruptible(priv->waitqueue, + atomic_read(&priv->xmit_total) || + kthread_should_stop()); + if (kthread_should_stop()) + break; + + /* Wait for TX FIFO space to write data */ + raw_spin_lock_irq(&priv->lock); + if (mips_ejtag_fdc_read(priv, REG_FDSTAT) & REG_FDSTAT_TXF) { + priv->xmit_full = true; + if (priv->irq >= 0) { + /* Enable TX interrupt */ + cfg = mips_ejtag_fdc_read(priv, REG_FDCFG); + cfg &= ~REG_FDCFG_TXINTTHRES; + cfg |= REG_FDCFG_TXINTTHRES_NOTFULL; + mips_ejtag_fdc_write(priv, REG_FDCFG, cfg); + } + } + raw_spin_unlock_irq(&priv->lock); + wait_event_interruptible(priv->waitqueue, + !(mips_ejtag_fdc_read(priv, REG_FDSTAT) + & REG_FDSTAT_TXF) || + kthread_should_stop()); + if (kthread_should_stop()) + break; + + /* Find next channel with data to output */ + for (;;) { + dport = &priv->ports[priv->xmit_next]; + spin_lock(&dport->xmit_lock); + ret = dport->xmit_cnt; + spin_unlock(&dport->xmit_lock); + if (ret) + break; + /* Round robin */ + ++priv->xmit_next; + if (priv->xmit_next >= NUM_TTY_CHANNELS) + priv->xmit_next = 0; + } + + /* Try writing data to the chosen channel */ + ret = mips_ejtag_fdc_put_chan(priv, priv->xmit_next); + + /* + * If anything was output, move on to the next channel so as not + * to starve other channels. + */ + if (ret) { + ++priv->xmit_next; + if (priv->xmit_next >= NUM_TTY_CHANNELS) + priv->xmit_next = 0; + } + } + + return 0; +} + +/** + * mips_ejtag_fdc_handle() - Handle FDC events. + * @priv: Pointer to driver private data. + * + * Handle FDC events, such as new incoming data which needs draining out of the + * RX FIFO and feeding into the appropriate TTY ports, and space becoming + * available in the TX FIFO which would allow more data to be written out. + */ +static void mips_ejtag_fdc_handle(struct mips_ejtag_fdc_tty *priv) +{ + struct mips_ejtag_fdc_tty_port *dport; + unsigned int stat, channel, data, cfg, i, flipped; + int len; + char buf[4]; + + for (;;) { + /* Find which channel the next FDC word is destined for */ + stat = mips_ejtag_fdc_read(priv, REG_FDSTAT); + if (stat & REG_FDSTAT_RXE) + break; + channel = (stat & REG_FDSTAT_RXCHAN) >> REG_FDSTAT_RXCHAN_SHIFT; + dport = &priv->ports[channel]; + + /* Read out the FDC word, decode it, and pass to tty layer */ + raw_spin_lock(&dport->rx_lock); + data = mips_ejtag_fdc_read(priv, REG_FDRX); + + len = mips_ejtag_fdc_decode(data, buf); + dev_dbg(priv->dev, "%s%u: in %08x: \"%*pE\"\n", + priv->driver_name, channel, data, len, buf); + + flipped = 0; + for (i = 0; i < len; ++i) { +#ifdef CONFIG_MAGIC_SYSRQ +#ifdef CONFIG_MIPS_EJTAG_FDC_KGDB + /* Support just Ctrl+C with KGDB channel */ + if (channel == CONFIG_MIPS_EJTAG_FDC_KGDB_CHAN) { + if (buf[i] == '\x03') { /* ^C */ + handle_sysrq('g'); + continue; + } + } +#endif + /* Support Ctrl+O for console channel */ + if (channel == mips_ejtag_fdc_con.cons.index) { + if (buf[i] == '\x0f') { /* ^O */ + priv->sysrq_pressed = + !priv->sysrq_pressed; + if (priv->sysrq_pressed) + continue; + } else if (priv->sysrq_pressed) { + handle_sysrq(buf[i]); + priv->sysrq_pressed = false; + continue; + } + } +#endif /* CONFIG_MAGIC_SYSRQ */ + + /* Check the port isn't being shut down */ + if (!dport->rx_buf) + continue; + + flipped += tty_insert_flip_char(&dport->port, buf[i], + TTY_NORMAL); + } + if (flipped) + tty_flip_buffer_push(&dport->port); + + raw_spin_unlock(&dport->rx_lock); + } + + /* If TX FIFO no longer full we may be able to write more data */ + raw_spin_lock(&priv->lock); + if (priv->xmit_full && !(stat & REG_FDSTAT_TXF)) { + priv->xmit_full = false; + + /* Disable TX interrupt */ + cfg = mips_ejtag_fdc_read(priv, REG_FDCFG); + cfg &= ~REG_FDCFG_TXINTTHRES; + cfg |= REG_FDCFG_TXINTTHRES_DISABLED; + mips_ejtag_fdc_write(priv, REG_FDCFG, cfg); + + /* Wait the kthread so it can try writing more data */ + wake_up_interruptible(&priv->waitqueue); + } + raw_spin_unlock(&priv->lock); +} + +/** + * mips_ejtag_fdc_isr() - Interrupt handler. + * @irq: IRQ number. + * @dev_id: Pointer to driver private data. + * + * This is the interrupt handler, used when interrupts are enabled. + * + * It simply triggers the common FDC handler code. + * + * Returns: IRQ_HANDLED if an FDC interrupt was pending. + * IRQ_NONE otherwise. + */ +static irqreturn_t mips_ejtag_fdc_isr(int irq, void *dev_id) +{ + struct mips_ejtag_fdc_tty *priv = dev_id; + + /* + * We're not using proper per-cpu IRQs, so we must be careful not to + * handle IRQs on CPUs we're not interested in. + * + * Ideally proper per-cpu IRQ handlers could be used, but that doesn't + * fit well with the whole sharing of the main CPU IRQ lines. When we + * have something with a GIC that routes the FDC IRQs (i.e. no sharing + * between handlers) then support could be added more easily. + */ + if (smp_processor_id() != priv->cpu) + return IRQ_NONE; + + /* If no FDC interrupt pending, it wasn't for us */ + if (!(read_c0_cause() & CAUSEF_FDCI)) + return IRQ_NONE; + + mips_ejtag_fdc_handle(priv); + return IRQ_HANDLED; +} + +/** + * mips_ejtag_fdc_tty_timer() - Poll FDC for incoming data. + * @opaque: Pointer to driver private data. + * + * This is the timer handler for when interrupts are disabled and polling the + * FDC state is required. + * + * It simply triggers the common FDC handler code and arranges for further + * polling. + */ +static void mips_ejtag_fdc_tty_timer(unsigned long opaque) +{ + struct mips_ejtag_fdc_tty *priv = (void *)opaque; + + mips_ejtag_fdc_handle(priv); + if (!priv->removing) + mod_timer_pinned(&priv->poll_timer, jiffies + FDC_TTY_POLL); +} + +/* TTY Port operations */ + +static int mips_ejtag_fdc_tty_port_activate(struct tty_port *port, + struct tty_struct *tty) +{ + struct mips_ejtag_fdc_tty_port *dport = + container_of(port, struct mips_ejtag_fdc_tty_port, port); + void *rx_buf; + + /* Allocate the buffer we use for writing data */ + if (tty_port_alloc_xmit_buf(port) < 0) + goto err; + + /* Allocate the buffer we use for reading data */ + rx_buf = kzalloc(RX_BUF_SIZE, GFP_KERNEL); + if (!rx_buf) + goto err_free_xmit; + + raw_spin_lock_irq(&dport->rx_lock); + dport->rx_buf = rx_buf; + raw_spin_unlock_irq(&dport->rx_lock); + + return 0; +err_free_xmit: + tty_port_free_xmit_buf(port); +err: + return -ENOMEM; +} + +static void mips_ejtag_fdc_tty_port_shutdown(struct tty_port *port) +{ + struct mips_ejtag_fdc_tty_port *dport = + container_of(port, struct mips_ejtag_fdc_tty_port, port); + struct mips_ejtag_fdc_tty *priv = dport->driver; + void *rx_buf; + unsigned int count; + + spin_lock(&dport->xmit_lock); + count = dport->xmit_cnt; + spin_unlock(&dport->xmit_lock); + if (count) { + /* + * There's still data to write out, so wake and wait for the + * writer thread to drain the buffer. + */ + wake_up_interruptible(&priv->waitqueue); + wait_for_completion(&dport->xmit_empty); + } + + /* Null the read buffer (timer could still be running!) */ + raw_spin_lock_irq(&dport->rx_lock); + rx_buf = dport->rx_buf; + dport->rx_buf = NULL; + raw_spin_unlock_irq(&dport->rx_lock); + /* Free the read buffer */ + kfree(rx_buf); + + /* Free the write buffer */ + tty_port_free_xmit_buf(port); +} + +static const struct tty_port_operations mips_ejtag_fdc_tty_port_ops = { + .activate = mips_ejtag_fdc_tty_port_activate, + .shutdown = mips_ejtag_fdc_tty_port_shutdown, +}; + +/* TTY operations */ + +static int mips_ejtag_fdc_tty_install(struct tty_driver *driver, + struct tty_struct *tty) +{ + struct mips_ejtag_fdc_tty *priv = driver->driver_state; + + tty->driver_data = &priv->ports[tty->index]; + return tty_port_install(&priv->ports[tty->index].port, driver, tty); +} + +static int mips_ejtag_fdc_tty_open(struct tty_struct *tty, struct file *filp) +{ + return tty_port_open(tty->port, tty, filp); +} + +static void mips_ejtag_fdc_tty_close(struct tty_struct *tty, struct file *filp) +{ + return tty_port_close(tty->port, tty, filp); +} + +static void mips_ejtag_fdc_tty_hangup(struct tty_struct *tty) +{ + struct mips_ejtag_fdc_tty_port *dport = tty->driver_data; + struct mips_ejtag_fdc_tty *priv = dport->driver; + + /* Drop any data in the xmit buffer */ + spin_lock(&dport->xmit_lock); + if (dport->xmit_cnt) { + atomic_sub(dport->xmit_cnt, &priv->xmit_total); + dport->xmit_cnt = 0; + dport->xmit_head = 0; + dport->xmit_tail = 0; + complete(&dport->xmit_empty); + } + spin_unlock(&dport->xmit_lock); + + tty_port_hangup(tty->port); +} + +static int mips_ejtag_fdc_tty_write(struct tty_struct *tty, + const unsigned char *buf, int total) +{ + int count, block; + struct mips_ejtag_fdc_tty_port *dport = tty->driver_data; + struct mips_ejtag_fdc_tty *priv = dport->driver; + + /* + * Write to output buffer. + * + * The reason that we asynchronously write the buffer is because if we + * were to write the buffer synchronously then because the channels are + * per-CPU the buffer would be written to the channel of whatever CPU + * we're running on. + * + * What we actually want to happen is have all input and output done on + * one CPU. + */ + spin_lock(&dport->xmit_lock); + /* Work out how many bytes we can write to the xmit buffer */ + total = min(total, (int)(priv->xmit_size - dport->xmit_cnt)); + atomic_add(total, &priv->xmit_total); + dport->xmit_cnt += total; + /* Write the actual bytes (may need splitting if it wraps) */ + for (count = total; count; count -= block) { + block = min(count, (int)(priv->xmit_size - dport->xmit_head)); + memcpy(dport->port.xmit_buf + dport->xmit_head, buf, block); + dport->xmit_head += block; + if (dport->xmit_head >= priv->xmit_size) + dport->xmit_head -= priv->xmit_size; + buf += block; + } + count = dport->xmit_cnt; + /* Xmit buffer no longer empty? */ + if (count) + reinit_completion(&dport->xmit_empty); + spin_unlock(&dport->xmit_lock); + + /* Wake up the kthread */ + if (total) + wake_up_interruptible(&priv->waitqueue); + return total; +} + +static int mips_ejtag_fdc_tty_write_room(struct tty_struct *tty) +{ + struct mips_ejtag_fdc_tty_port *dport = tty->driver_data; + struct mips_ejtag_fdc_tty *priv = dport->driver; + int room; + + /* Report the space in the xmit buffer */ + spin_lock(&dport->xmit_lock); + room = priv->xmit_size - dport->xmit_cnt; + spin_unlock(&dport->xmit_lock); + + return room; +} + +static int mips_ejtag_fdc_tty_chars_in_buffer(struct tty_struct *tty) +{ + struct mips_ejtag_fdc_tty_port *dport = tty->driver_data; + int chars; + + /* Report the number of bytes in the xmit buffer */ + spin_lock(&dport->xmit_lock); + chars = dport->xmit_cnt; + spin_unlock(&dport->xmit_lock); + + return chars; +} + +static const struct tty_operations mips_ejtag_fdc_tty_ops = { + .install = mips_ejtag_fdc_tty_install, + .open = mips_ejtag_fdc_tty_open, + .close = mips_ejtag_fdc_tty_close, + .hangup = mips_ejtag_fdc_tty_hangup, + .write = mips_ejtag_fdc_tty_write, + .write_room = mips_ejtag_fdc_tty_write_room, + .chars_in_buffer = mips_ejtag_fdc_tty_chars_in_buffer, +}; + +static int mips_ejtag_fdc_tty_probe(struct mips_cdmm_device *dev) +{ + int ret, nport; + struct mips_ejtag_fdc_tty_port *dport; + struct mips_ejtag_fdc_tty *priv; + struct tty_driver *driver; + unsigned int cfg, tx_fifo; + + priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + priv->cpu = dev->cpu; + priv->dev = &dev->dev; + mips_cdmm_set_drvdata(dev, priv); + atomic_set(&priv->xmit_total, 0); + raw_spin_lock_init(&priv->lock); + + priv->reg = devm_ioremap_nocache(priv->dev, dev->res.start, + resource_size(&dev->res)); + if (!priv->reg) { + dev_err(priv->dev, "ioremap failed for resource %pR\n", + &dev->res); + return -ENOMEM; + } + + cfg = mips_ejtag_fdc_read(priv, REG_FDCFG); + tx_fifo = (cfg & REG_FDCFG_TXFIFOSIZE) >> REG_FDCFG_TXFIFOSIZE_SHIFT; + /* Disable interrupts */ + cfg &= ~(REG_FDCFG_TXINTTHRES | REG_FDCFG_RXINTTHRES); + cfg |= REG_FDCFG_TXINTTHRES_DISABLED; + cfg |= REG_FDCFG_RXINTTHRES_DISABLED; + mips_ejtag_fdc_write(priv, REG_FDCFG, cfg); + + /* Make each port's xmit FIFO big enough to fill FDC TX FIFO */ + priv->xmit_size = min(tx_fifo * 4, (unsigned int)SERIAL_XMIT_SIZE); + + driver = tty_alloc_driver(NUM_TTY_CHANNELS, TTY_DRIVER_REAL_RAW); + if (IS_ERR(driver)) + return PTR_ERR(driver); + priv->driver = driver; + + driver->driver_name = "ejtag_fdc"; + snprintf(priv->fdc_name, sizeof(priv->fdc_name), "ttyFDC%u", dev->cpu); + snprintf(priv->driver_name, sizeof(priv->driver_name), "%sc", + priv->fdc_name); + driver->name = priv->driver_name; + driver->major = 0; /* Auto-allocate */ + driver->minor_start = 0; + driver->type = TTY_DRIVER_TYPE_SERIAL; + driver->subtype = SERIAL_TYPE_NORMAL; + driver->init_termios = tty_std_termios; + driver->init_termios.c_cflag |= CLOCAL; + driver->driver_state = priv; + + tty_set_operations(driver, &mips_ejtag_fdc_tty_ops); + for (nport = 0; nport < NUM_TTY_CHANNELS; nport++) { + dport = &priv->ports[nport]; + dport->driver = priv; + tty_port_init(&dport->port); + dport->port.ops = &mips_ejtag_fdc_tty_port_ops; + raw_spin_lock_init(&dport->rx_lock); + spin_lock_init(&dport->xmit_lock); + /* The xmit buffer starts empty, i.e. completely written */ + init_completion(&dport->xmit_empty); + complete(&dport->xmit_empty); + } + + /* Set up the console */ + mips_ejtag_fdc_con.regs[dev->cpu] = priv->reg; + if (dev->cpu == 0) + mips_ejtag_fdc_con.tty_drv = driver; + + init_waitqueue_head(&priv->waitqueue); + priv->thread = kthread_create(mips_ejtag_fdc_put, priv, priv->fdc_name); + if (IS_ERR(priv->thread)) { + ret = PTR_ERR(priv->thread); + dev_err(priv->dev, "Couldn't create kthread (%d)\n", ret); + goto err_destroy_ports; + } + /* + * Bind the writer thread to the right CPU so it can't migrate. + * The channels are per-CPU and we want all channel I/O to be on a + * single predictable CPU. + */ + kthread_bind(priv->thread, dev->cpu); + wake_up_process(priv->thread); + + /* Look for an FDC IRQ */ + priv->irq = -1; + if (get_c0_fdc_int) + priv->irq = get_c0_fdc_int(); + + /* Try requesting the IRQ */ + if (priv->irq >= 0) { + /* + * IRQF_SHARED, IRQF_NO_SUSPEND: The FDC IRQ may be shared with + * other local interrupts such as the timer which sets + * IRQF_TIMER (including IRQF_NO_SUSPEND). + * + * IRQF_NO_THREAD: The FDC IRQ isn't individually maskable so it + * cannot be deferred and handled by a thread on RT kernels. For + * this reason any spinlocks used from the ISR are raw. + */ + ret = devm_request_irq(priv->dev, priv->irq, mips_ejtag_fdc_isr, + IRQF_PERCPU | IRQF_SHARED | + IRQF_NO_THREAD | IRQF_NO_SUSPEND, + priv->fdc_name, priv); + if (ret) + priv->irq = -1; + } + if (priv->irq >= 0) { + /* IRQ is usable, enable RX interrupt */ + raw_spin_lock_irq(&priv->lock); + cfg = mips_ejtag_fdc_read(priv, REG_FDCFG); + cfg &= ~REG_FDCFG_RXINTTHRES; + cfg |= REG_FDCFG_RXINTTHRES_NOTEMPTY; + mips_ejtag_fdc_write(priv, REG_FDCFG, cfg); + raw_spin_unlock_irq(&priv->lock); + } else { + /* If we didn't get an usable IRQ, poll instead */ + setup_timer(&priv->poll_timer, mips_ejtag_fdc_tty_timer, + (unsigned long)priv); + priv->poll_timer.expires = jiffies + FDC_TTY_POLL; + /* + * Always attach the timer to the right CPU. The channels are + * per-CPU so all polling should be from a single CPU. + */ + add_timer_on(&priv->poll_timer, dev->cpu); + + dev_info(priv->dev, "No usable IRQ, polling enabled\n"); + } + + ret = tty_register_driver(driver); + if (ret < 0) { + dev_err(priv->dev, "Couldn't install tty driver (%d)\n", ret); + goto err_stop_irq; + } + + return 0; + +err_stop_irq: + if (priv->irq >= 0) { + raw_spin_lock_irq(&priv->lock); + cfg = mips_ejtag_fdc_read(priv, REG_FDCFG); + /* Disable interrupts */ + cfg &= ~(REG_FDCFG_TXINTTHRES | REG_FDCFG_RXINTTHRES); + cfg |= REG_FDCFG_TXINTTHRES_DISABLED; + cfg |= REG_FDCFG_RXINTTHRES_DISABLED; + mips_ejtag_fdc_write(priv, REG_FDCFG, cfg); + raw_spin_unlock_irq(&priv->lock); + } else { + priv->removing = true; + del_timer_sync(&priv->poll_timer); + } + kthread_stop(priv->thread); +err_destroy_ports: + if (dev->cpu == 0) + mips_ejtag_fdc_con.tty_drv = NULL; + for (nport = 0; nport < NUM_TTY_CHANNELS; nport++) { + dport = &priv->ports[nport]; + tty_port_destroy(&dport->port); + } + put_tty_driver(priv->driver); + return ret; +} + +static int mips_ejtag_fdc_tty_remove(struct mips_cdmm_device *dev) +{ + struct mips_ejtag_fdc_tty *priv = mips_cdmm_get_drvdata(dev); + struct mips_ejtag_fdc_tty_port *dport; + int nport; + unsigned int cfg; + + if (priv->irq >= 0) { + raw_spin_lock_irq(&priv->lock); + cfg = mips_ejtag_fdc_read(priv, REG_FDCFG); + /* Disable interrupts */ + cfg &= ~(REG_FDCFG_TXINTTHRES | REG_FDCFG_RXINTTHRES); + cfg |= REG_FDCFG_TXINTTHRES_DISABLED; + cfg |= REG_FDCFG_RXINTTHRES_DISABLED; + mips_ejtag_fdc_write(priv, REG_FDCFG, cfg); + raw_spin_unlock_irq(&priv->lock); + } else { + priv->removing = true; + del_timer_sync(&priv->poll_timer); + } + kthread_stop(priv->thread); + if (dev->cpu == 0) + mips_ejtag_fdc_con.tty_drv = NULL; + tty_unregister_driver(priv->driver); + for (nport = 0; nport < NUM_TTY_CHANNELS; nport++) { + dport = &priv->ports[nport]; + tty_port_destroy(&dport->port); + } + put_tty_driver(priv->driver); + return 0; +} + +static int mips_ejtag_fdc_tty_cpu_down(struct mips_cdmm_device *dev) +{ + struct mips_ejtag_fdc_tty *priv = mips_cdmm_get_drvdata(dev); + unsigned int cfg; + + if (priv->irq >= 0) { + raw_spin_lock_irq(&priv->lock); + cfg = mips_ejtag_fdc_read(priv, REG_FDCFG); + /* Disable interrupts */ + cfg &= ~(REG_FDCFG_TXINTTHRES | REG_FDCFG_RXINTTHRES); + cfg |= REG_FDCFG_TXINTTHRES_DISABLED; + cfg |= REG_FDCFG_RXINTTHRES_DISABLED; + mips_ejtag_fdc_write(priv, REG_FDCFG, cfg); + raw_spin_unlock_irq(&priv->lock); + } else { + priv->removing = true; + del_timer_sync(&priv->poll_timer); + } + kthread_stop(priv->thread); + + return 0; +} + +static int mips_ejtag_fdc_tty_cpu_up(struct mips_cdmm_device *dev) +{ + struct mips_ejtag_fdc_tty *priv = mips_cdmm_get_drvdata(dev); + unsigned int cfg; + int ret = 0; + + if (priv->irq >= 0) { + /* + * IRQ is usable, enable RX interrupt + * This must be before kthread is restarted, as kthread may + * enable TX interrupt. + */ + raw_spin_lock_irq(&priv->lock); + cfg = mips_ejtag_fdc_read(priv, REG_FDCFG); + cfg &= ~(REG_FDCFG_TXINTTHRES | REG_FDCFG_RXINTTHRES); + cfg |= REG_FDCFG_TXINTTHRES_DISABLED; + cfg |= REG_FDCFG_RXINTTHRES_NOTEMPTY; + mips_ejtag_fdc_write(priv, REG_FDCFG, cfg); + raw_spin_unlock_irq(&priv->lock); + } else { + /* Restart poll timer */ + priv->removing = false; + add_timer_on(&priv->poll_timer, dev->cpu); + } + + /* Restart the kthread */ + priv->thread = kthread_create(mips_ejtag_fdc_put, priv, priv->fdc_name); + if (IS_ERR(priv->thread)) { + ret = PTR_ERR(priv->thread); + dev_err(priv->dev, "Couldn't re-create kthread (%d)\n", ret); + goto out; + } + /* Bind it back to the right CPU and set it off */ + kthread_bind(priv->thread, dev->cpu); + wake_up_process(priv->thread); +out: + return ret; +} + +static struct mips_cdmm_device_id mips_ejtag_fdc_tty_ids[] = { + { .type = 0xfd }, + { } +}; + +static struct mips_cdmm_driver mips_ejtag_fdc_tty_driver = { + .drv = { + .name = "mips_ejtag_fdc", + }, + .probe = mips_ejtag_fdc_tty_probe, + .remove = mips_ejtag_fdc_tty_remove, + .cpu_down = mips_ejtag_fdc_tty_cpu_down, + .cpu_up = mips_ejtag_fdc_tty_cpu_up, + .id_table = mips_ejtag_fdc_tty_ids, +}; +module_mips_cdmm_driver(mips_ejtag_fdc_tty_driver); + +static int __init mips_ejtag_fdc_init_console(void) +{ + return mips_ejtag_fdc_console_init(&mips_ejtag_fdc_con); +} +console_initcall(mips_ejtag_fdc_init_console); + +#ifdef CONFIG_MIPS_EJTAG_FDC_EARLYCON +static struct mips_ejtag_fdc_console mips_ejtag_fdc_earlycon = { + .cons = { + .name = "early_fdc", + .write = mips_ejtag_fdc_console_write, + .flags = CON_PRINTBUFFER | CON_BOOT, + .index = CONSOLE_CHANNEL, + }, + .lock = __RAW_SPIN_LOCK_UNLOCKED(mips_ejtag_fdc_earlycon.lock), +}; + +int __init setup_early_fdc_console(void) +{ + return mips_ejtag_fdc_console_init(&mips_ejtag_fdc_earlycon); +} +#endif + +#ifdef CONFIG_MIPS_EJTAG_FDC_KGDB + +/* read buffer to allow decompaction */ +static unsigned int kgdbfdc_rbuflen; +static unsigned int kgdbfdc_rpos; +static char kgdbfdc_rbuf[4]; + +/* write buffer to allow compaction */ +static unsigned int kgdbfdc_wbuflen; +static char kgdbfdc_wbuf[4]; + +static void __iomem *kgdbfdc_setup(void) +{ + void __iomem *regs; + unsigned int cpu; + + /* Find address, piggy backing off console percpu regs */ + cpu = smp_processor_id(); + regs = mips_ejtag_fdc_con.regs[cpu]; + /* First console output on this CPU? */ + if (!regs) { + regs = mips_cdmm_early_probe(0xfd); + mips_ejtag_fdc_con.regs[cpu] = regs; + } + /* Already tried and failed to find FDC on this CPU? */ + if (IS_ERR(regs)) + return regs; + + return regs; +} + +/* read a character from the read buffer, filling from FDC RX FIFO */ +static int kgdbfdc_read_char(void) +{ + unsigned int stat, channel, data; + void __iomem *regs; + + /* No more data, try and read another FDC word from RX FIFO */ + if (kgdbfdc_rpos >= kgdbfdc_rbuflen) { + kgdbfdc_rpos = 0; + kgdbfdc_rbuflen = 0; + + regs = kgdbfdc_setup(); + if (IS_ERR(regs)) + return NO_POLL_CHAR; + + /* Read next word from KGDB channel */ + do { + stat = __raw_readl(regs + REG_FDSTAT); + + /* No data waiting? */ + if (stat & REG_FDSTAT_RXE) + return NO_POLL_CHAR; + + /* Read next word */ + channel = (stat & REG_FDSTAT_RXCHAN) >> + REG_FDSTAT_RXCHAN_SHIFT; + data = __raw_readl(regs + REG_FDRX); + } while (channel != CONFIG_MIPS_EJTAG_FDC_KGDB_CHAN); + + /* Decode into rbuf */ + kgdbfdc_rbuflen = mips_ejtag_fdc_decode(data, kgdbfdc_rbuf); + } + pr_devel("kgdbfdc r %c\n", kgdbfdc_rbuf[kgdbfdc_rpos]); + return kgdbfdc_rbuf[kgdbfdc_rpos++]; +} + +/* push an FDC word from write buffer to TX FIFO */ +static void kgdbfdc_push_one(void) +{ + const char *bufs[1] = { kgdbfdc_wbuf }; + struct fdc_word word; + void __iomem *regs; + unsigned int i; + + /* Construct a word from any data in buffer */ + word = mips_ejtag_fdc_encode(bufs, &kgdbfdc_wbuflen, 1); + /* Relocate any remaining data to beginnning of buffer */ + kgdbfdc_wbuflen -= word.bytes; + for (i = 0; i < kgdbfdc_wbuflen; ++i) + kgdbfdc_wbuf[i] = kgdbfdc_wbuf[i + word.bytes]; + + regs = kgdbfdc_setup(); + if (IS_ERR(regs)) + return; + + /* Busy wait until there's space in fifo */ + while (__raw_readl(regs + REG_FDSTAT) & REG_FDSTAT_TXF) + ; + __raw_writel(word.word, + regs + REG_FDTX(CONFIG_MIPS_EJTAG_FDC_KGDB_CHAN)); +} + +/* flush the whole write buffer to the TX FIFO */ +static void kgdbfdc_flush(void) +{ + while (kgdbfdc_wbuflen) + kgdbfdc_push_one(); +} + +/* write a character into the write buffer, writing out if full */ +static void kgdbfdc_write_char(u8 chr) +{ + pr_devel("kgdbfdc w %c\n", chr); + kgdbfdc_wbuf[kgdbfdc_wbuflen++] = chr; + if (kgdbfdc_wbuflen >= sizeof(kgdbfdc_wbuf)) + kgdbfdc_push_one(); +} + +static struct kgdb_io kgdbfdc_io_ops = { + .name = "kgdbfdc", + .read_char = kgdbfdc_read_char, + .write_char = kgdbfdc_write_char, + .flush = kgdbfdc_flush, +}; + +static int __init kgdbfdc_init(void) +{ + kgdb_register_io_module(&kgdbfdc_io_ops); + return 0; +} +early_initcall(kgdbfdc_init); +#endif diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index c4343764cc5b..382d3fcba6cc 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -161,7 +161,7 @@ struct gsm_dlci { struct net_device *net; /* network interface, if created */ }; -/* DLCI 0, 62/63 are special or reseved see gsmtty_open */ +/* DLCI 0, 62/63 are special or reserved see gsmtty_open */ #define NUM_DLCI 64 @@ -2274,7 +2274,6 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp, const unsigned char *dp; char *f; int i; - char buf[64]; char flags = TTY_NORMAL; if (debug & 4) @@ -2296,7 +2295,7 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp, break; default: WARN_ONCE(1, "%s: unknown flag %d\n", - tty_name(tty, buf), flags); + tty_name(tty), flags); break; } } @@ -2669,7 +2668,7 @@ static inline void muxnet_put(struct gsm_mux_net *mux_net) static int gsm_mux_net_start_xmit(struct sk_buff *skb, struct net_device *net) { - struct gsm_mux_net *mux_net = (struct gsm_mux_net *)netdev_priv(net); + struct gsm_mux_net *mux_net = netdev_priv(net); struct gsm_dlci *dlci = mux_net->dlci; muxnet_get(mux_net); @@ -2698,7 +2697,7 @@ static void gsm_mux_rx_netchar(struct gsm_dlci *dlci, { struct net_device *net = dlci->net; struct sk_buff *skb; - struct gsm_mux_net *mux_net = (struct gsm_mux_net *)netdev_priv(net); + struct gsm_mux_net *mux_net = netdev_priv(net); muxnet_get(mux_net); /* Allocate an sk_buff */ @@ -2727,7 +2726,7 @@ static void gsm_mux_rx_netchar(struct gsm_dlci *dlci, static int gsm_change_mtu(struct net_device *net, int new_mtu) { - struct gsm_mux_net *mux_net = (struct gsm_mux_net *)netdev_priv(net); + struct gsm_mux_net *mux_net = netdev_priv(net); if ((new_mtu < 8) || (new_mtu > mux_net->dlci->gsm->mtu)) return -EINVAL; net->mtu = new_mtu; @@ -2763,7 +2762,7 @@ static void gsm_destroy_network(struct gsm_dlci *dlci) pr_debug("destroy network interface"); if (!dlci->net) return; - mux_net = (struct gsm_mux_net *)netdev_priv(dlci->net); + mux_net = netdev_priv(dlci->net); muxnet_put(mux_net); } @@ -2801,7 +2800,7 @@ static int gsm_create_network(struct gsm_dlci *dlci, struct gsm_netconfig *nc) return -ENOMEM; } net->mtu = dlci->gsm->mtu; - mux_net = (struct gsm_mux_net *)netdev_priv(net); + mux_net = netdev_priv(net); mux_net->dlci = dlci; kref_init(&mux_net->ref); strncpy(nc->if_name, net->name, IFNAMSIZ); /* return net name */ @@ -2824,7 +2823,7 @@ static int gsm_create_network(struct gsm_dlci *dlci, struct gsm_netconfig *nc) } /* Line discipline for real tty */ -struct tty_ldisc_ops tty_ldisc_packet = { +static struct tty_ldisc_ops tty_ldisc_packet = { .owner = THIS_MODULE, .magic = TTY_LDISC_MAGIC, .name = "n_gsm", @@ -3170,7 +3169,7 @@ static int gsmtty_break_ctl(struct tty_struct *tty, int state) return gsmtty_modem_update(dlci, encode); } -static void gsmtty_remove(struct tty_driver *driver, struct tty_struct *tty) +static void gsmtty_cleanup(struct tty_struct *tty) { struct gsm_dlci *dlci = tty->driver_data; struct gsm_mux *gsm = dlci->gsm; @@ -3178,7 +3177,6 @@ static void gsmtty_remove(struct tty_driver *driver, struct tty_struct *tty) dlci_put(dlci); dlci_put(gsm->dlci[0]); mux_put(gsm); - driver->ttys[tty->index] = NULL; } /* Virtual ttys for the demux */ @@ -3199,7 +3197,7 @@ static const struct tty_operations gsmtty_ops = { .tiocmget = gsmtty_tiocmget, .tiocmset = gsmtty_tiocmset, .break_ctl = gsmtty_break_ctl, - .remove = gsmtty_remove, + .cleanup = gsmtty_cleanup, }; diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 644ddb841d9f..bbc4ce66c2c1 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -600,7 +600,7 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file, add_wait_queue(&tty->read_wait, &wait); for (;;) { - if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) { + if (test_bit(TTY_OTHER_DONE, &tty->flags)) { ret = -EIO; break; } @@ -828,7 +828,7 @@ static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp, /* set bits for operations that won't block */ if (n_hdlc->rx_buf_list.head) mask |= POLLIN | POLLRDNORM; /* readable */ - if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) + if (test_bit(TTY_OTHER_DONE, &tty->flags)) mask |= POLLHUP; if (tty_hung_up_p(filp)) mask |= POLLHUP; diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index cf6e0f2e1331..c9c27f69e101 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -162,6 +162,17 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x, return put_user(x, ptr); } +static inline int tty_copy_to_user(struct tty_struct *tty, + void __user *to, + const void *from, + unsigned long n) +{ + struct n_tty_data *ldata = tty->disc_data; + + tty_audit_add_data(tty, to, n, ldata->icanon); + return copy_to_user(to, from, n); +} + /** * n_tty_kick_worker - start input worker (if required) * @tty: terminal @@ -1179,13 +1190,12 @@ static void n_tty_receive_break(struct tty_struct *tty) static void n_tty_receive_overrun(struct tty_struct *tty) { struct n_tty_data *ldata = tty->disc_data; - char buf[64]; ldata->num_overrun++; if (time_after(jiffies, ldata->overrun_time + HZ) || time_after(ldata->overrun_time, jiffies)) { printk(KERN_WARNING "%s: %d input overrun(s)\n", - tty_name(tty, buf), + tty_name(tty), ldata->num_overrun); ldata->overrun_time = jiffies; ldata->num_overrun = 0; @@ -1460,8 +1470,6 @@ static void n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c) static void n_tty_receive_char_flagged(struct tty_struct *tty, unsigned char c, char flag) { - char buf[64]; - switch (flag) { case TTY_BREAK: n_tty_receive_break(tty); @@ -1475,7 +1483,7 @@ n_tty_receive_char_flagged(struct tty_struct *tty, unsigned char c, char flag) break; default: printk(KERN_ERR "%s: unknown flag %d\n", - tty_name(tty, buf), flag); + tty_name(tty), flag); break; } } @@ -1949,6 +1957,18 @@ static inline int input_available_p(struct tty_struct *tty, int poll) return ldata->commit_head - ldata->read_tail >= amt; } +static inline int check_other_done(struct tty_struct *tty) +{ + int done = test_bit(TTY_OTHER_DONE, &tty->flags); + if (done) { + /* paired with cmpxchg() in check_other_closed(); ensures + * read buffer head index is not stale + */ + smp_mb__after_atomic(); + } + return done; +} + /** * copy_from_read_buf - copy read data directly * @tty: terminal device @@ -2058,8 +2078,8 @@ static int canon_copy_from_read_buf(struct tty_struct *tty, size = N_TTY_BUF_SIZE - tail; n = eol - tail; - if (n > 4096) - n += 4096; + if (n > N_TTY_BUF_SIZE) + n += N_TTY_BUF_SIZE; n += found; c = n; @@ -2072,12 +2092,12 @@ static int canon_copy_from_read_buf(struct tty_struct *tty, __func__, eol, found, n, c, size, more); if (n > size) { - ret = copy_to_user(*b, read_buf_addr(ldata, tail), size); + ret = tty_copy_to_user(tty, *b, read_buf_addr(ldata, tail), size); if (ret) return -EFAULT; - ret = copy_to_user(*b + size, ldata->read_buf, n - size); + ret = tty_copy_to_user(tty, *b + size, ldata->read_buf, n - size); } else - ret = copy_to_user(*b, read_buf_addr(ldata, tail), n); + ret = tty_copy_to_user(tty, *b, read_buf_addr(ldata, tail), n); if (ret) return -EFAULT; @@ -2167,7 +2187,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, struct n_tty_data *ldata = tty->disc_data; unsigned char __user *b = buf; DEFINE_WAIT_FUNC(wait, woken_wake_function); - int c; + int c, done; int minimum, time; ssize_t retval = 0; long timeout; @@ -2235,8 +2255,10 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, ((minimum - (b - buf)) >= 1)) ldata->minimum_to_wake = (minimum - (b - buf)); + done = check_other_done(tty); + if (!input_available_p(tty, 0)) { - if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) { + if (done) { retval = -EIO; break; } @@ -2443,12 +2465,12 @@ static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file, poll_wait(file, &tty->read_wait, wait); poll_wait(file, &tty->write_wait, wait); + if (check_other_done(tty)) + mask |= POLLHUP; if (input_available_p(tty, 1)) mask |= POLLIN | POLLRDNORM; if (tty->packet && tty->link->ctrl_status) mask |= POLLPRI | POLLIN | POLLRDNORM; - if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) - mask |= POLLHUP; if (tty_hung_up_p(file)) mask |= POLLHUP; if (!(mask & (POLLHUP | POLLIN | POLLRDNORM))) { diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c index 74885af8c7bd..80f9de907563 100644 --- a/drivers/tty/nozomi.c +++ b/drivers/tty/nozomi.c @@ -140,8 +140,8 @@ static int debug; #define R_FCR 0x0000 /* Flow Control Register */ #define R_IER 0x0004 /* Interrupt Enable Register */ -#define CONFIG_MAGIC 0xEFEFFEFE -#define TOGGLE_VALID 0x0000 +#define NOZOMI_CONFIG_MAGIC 0xEFEFFEFE +#define TOGGLE_VALID 0x0000 /* Definition of interrupt tokens */ #define MDM_DL1 0x0001 @@ -660,9 +660,9 @@ static int nozomi_read_config_table(struct nozomi *dc) read_mem32((u32 *) &dc->config_table, dc->base_addr + 0, sizeof(struct config_table)); - if (dc->config_table.signature != CONFIG_MAGIC) { + if (dc->config_table.signature != NOZOMI_CONFIG_MAGIC) { dev_err(&dc->pdev->dev, "ConfigTable Bad! 0x%08X != 0x%08X\n", - dc->config_table.signature, CONFIG_MAGIC); + dc->config_table.signature, NOZOMI_CONFIG_MAGIC); return 0; } diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index e72ee629cead..4d5e8409769c 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -53,9 +53,8 @@ static void pty_close(struct tty_struct *tty, struct file *filp) /* Review - krefs on tty_link ?? */ if (!tty->link) return; - tty_flush_to_ldisc(tty->link); set_bit(TTY_OTHER_CLOSED, &tty->link->flags); - wake_up_interruptible(&tty->link->read_wait); + tty_flip_buffer_push(tty->link->port); wake_up_interruptible(&tty->link->write_wait); if (tty->driver->subtype == PTY_TYPE_MASTER) { set_bit(TTY_OTHER_CLOSED, &tty->flags); @@ -243,7 +242,9 @@ static int pty_open(struct tty_struct *tty, struct file *filp) goto out; clear_bit(TTY_IO_ERROR, &tty->flags); + /* TTY_OTHER_CLOSED must be cleared before TTY_OTHER_DONE */ clear_bit(TTY_OTHER_CLOSED, &tty->link->flags); + clear_bit(TTY_OTHER_DONE, &tty->link->flags); set_bit(TTY_THROTTLED, &tty->flags); return 0; diff --git a/drivers/tty/rocket.h b/drivers/tty/rocket.h index ec863f35f1a9..c11a9392f219 100644 --- a/drivers/tty/rocket.h +++ b/drivers/tty/rocket.h @@ -44,7 +44,7 @@ struct rocket_version { #define ROCKET_HUP_NOTIFY 0x00000004 #define ROCKET_SPLIT_TERMIOS 0x00000008 #define ROCKET_SPD_MASK 0x00000070 -#define ROCKET_SPD_HI 0x00000010 /* Use 56000 instead of 38400 bps */ +#define ROCKET_SPD_HI 0x00000010 /* Use 57600 instead of 38400 bps */ #define ROCKET_SPD_VHI 0x00000020 /* Use 115200 instead of 38400 bps */ #define ROCKET_SPD_SHI 0x00000030 /* Use 230400 instead of 38400 bps */ #define ROCKET_SPD_WARP 0x00000040 /* Use 460800 instead of 38400 bps */ diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c index 5dc9c4bfa66e..748c18f8c8cd 100644 --- a/drivers/tty/serial/68328serial.c +++ b/drivers/tty/serial/68328serial.c @@ -508,7 +508,8 @@ static void change_speed(struct m68k_serial *info, struct tty_struct *tty) int i; cflag = tty->termios.c_cflag; - if (!(port = info->port)) + port = info->port; + if (!port) return; ustcnt = uart->ustcnt; diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index b00836851061..c43f74c53cd9 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -21,7 +21,6 @@ struct uart_8250_dma { /* Filter function */ dma_filter_fn fn; - /* Parameter to the filter function */ void *rx_param; void *tx_param; @@ -53,7 +52,7 @@ struct old_serial_port { unsigned int baud_base; unsigned int port; unsigned int irq; - unsigned int flags; + upf_t flags; unsigned char hub6; unsigned char io_type; unsigned char __iomem *iomem_base; @@ -85,9 +84,6 @@ struct serial8250_config { #define UART_BUG_THRE (1 << 3) /* UART has buggy THRE reassertion */ #define UART_BUG_PARITY (1 << 4) /* UART mishandles parity if FIFO enabled */ -#define PROBE_RSA (1 << 0) -#define PROBE_ANY (~0) - #define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) #ifdef CONFIG_SERIAL_8250_SHARE_IRQ @@ -198,3 +194,20 @@ static inline int serial8250_request_dma(struct uart_8250_port *p) } static inline void serial8250_release_dma(struct uart_8250_port *p) { } #endif + +static inline int ns16550a_goto_highspeed(struct uart_8250_port *up) +{ + unsigned char status; + + status = serial_in(up, 0x04); /* EXCR2 */ +#define PRESL(x) ((x) & 0x30) + if (PRESL(status) == 0x10) { + /* already in high speed mode */ + return 0; + } else { + status &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */ + status |= 0x10; /* 1.625 divisor for baud_base --> 921600 */ + serial_out(up, 0x04, status); + } + return 1; +} diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index deae122c9c4b..37fff12dd4d0 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -31,7 +31,6 @@ #include <linux/tty.h> #include <linux/ratelimit.h> #include <linux/tty_flip.h> -#include <linux/serial_core.h> #include <linux/serial.h> #include <linux/serial_8250.h> #include <linux/nmi.h> @@ -61,7 +60,7 @@ static struct uart_driver serial8250_reg; static int serial_index(struct uart_port *port) { - return (serial8250_reg.minor - 64) + port->line; + return port->minor - 64; } static unsigned int skip_txen_test; /* force skip of txen test at init time */ @@ -86,19 +85,6 @@ static unsigned int skip_txen_test; /* force skip of txen test at init time */ #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) -#ifdef CONFIG_SERIAL_8250_DETECT_IRQ -#define CONFIG_SERIAL_DETECT_IRQ 1 -#endif -#ifdef CONFIG_SERIAL_8250_MANY_PORTS -#define CONFIG_SERIAL_MANY_PORTS 1 -#endif - -/* - * HUB6 is always on. This will be removed once the header - * files have been cleaned. - */ -#define CONFIG_HUB6 1 - #include <asm/serial.h> /* * SERIAL_PORT_DFNS tells us about built-in ports that have no @@ -358,34 +344,46 @@ static void default_serial_dl_write(struct uart_8250_port *up, int value) #if defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_SERIAL_8250_RT288X) /* Au1x00/RT288x UART hardware has a weird register layout */ -static const u8 au_io_in_map[] = { - [UART_RX] = 0, - [UART_IER] = 2, - [UART_IIR] = 3, - [UART_LCR] = 5, - [UART_MCR] = 6, - [UART_LSR] = 7, - [UART_MSR] = 8, +static const s8 au_io_in_map[8] = { + 0, /* UART_RX */ + 2, /* UART_IER */ + 3, /* UART_IIR */ + 5, /* UART_LCR */ + 6, /* UART_MCR */ + 7, /* UART_LSR */ + 8, /* UART_MSR */ + -1, /* UART_SCR (unmapped) */ }; -static const u8 au_io_out_map[] = { - [UART_TX] = 1, - [UART_IER] = 2, - [UART_FCR] = 4, - [UART_LCR] = 5, - [UART_MCR] = 6, +static const s8 au_io_out_map[8] = { + 1, /* UART_TX */ + 2, /* UART_IER */ + 4, /* UART_FCR */ + 5, /* UART_LCR */ + 6, /* UART_MCR */ + -1, /* UART_LSR (unmapped) */ + -1, /* UART_MSR (unmapped) */ + -1, /* UART_SCR (unmapped) */ }; static unsigned int au_serial_in(struct uart_port *p, int offset) { - offset = au_io_in_map[offset] << p->regshift; - return __raw_readl(p->membase + offset); + if (offset >= ARRAY_SIZE(au_io_in_map)) + return UINT_MAX; + offset = au_io_in_map[offset]; + if (offset < 0) + return UINT_MAX; + return __raw_readl(p->membase + (offset << p->regshift)); } static void au_serial_out(struct uart_port *p, int offset, int value) { - offset = au_io_out_map[offset] << p->regshift; - __raw_writel(value, p->membase + offset); + if (offset >= ARRAY_SIZE(au_io_out_map)) + return; + offset = au_io_out_map[offset]; + if (offset < 0) + return; + __raw_writel(value, p->membase + (offset << p->regshift)); } /* Au1x00 haven't got a standard divisor latch */ @@ -439,6 +437,18 @@ static unsigned int mem32_serial_in(struct uart_port *p, int offset) return readl(p->membase + offset); } +static void mem32be_serial_out(struct uart_port *p, int offset, int value) +{ + offset = offset << p->regshift; + iowrite32be(value, p->membase + offset); +} + +static unsigned int mem32be_serial_in(struct uart_port *p, int offset) +{ + offset = offset << p->regshift; + return ioread32be(p->membase + offset); +} + static unsigned int io_serial_in(struct uart_port *p, int offset) { offset = offset << p->regshift; @@ -477,6 +487,11 @@ static void set_io_from_upio(struct uart_port *p) p->serial_out = mem32_serial_out; break; + case UPIO_MEM32BE: + p->serial_in = mem32be_serial_in; + p->serial_out = mem32be_serial_out; + break; + #if defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_SERIAL_8250_RT288X) case UPIO_AU: p->serial_in = au_serial_in; @@ -502,6 +517,7 @@ serial_port_out_sync(struct uart_port *p, int offset, int value) switch (p->iotype) { case UPIO_MEM: case UPIO_MEM32: + case UPIO_MEM32BE: case UPIO_AU: p->serial_out(p, offset, value); p->serial_in(p, UART_LCR); /* safe, no side-effects */ @@ -895,7 +911,7 @@ static int broken_efr(struct uart_8250_port *up) /* * Exar ST16C2550 "A2" devices incorrectly detect as * having an EFR, and report an ID of 0x0201. See - * http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-11/4812.html + * http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-11/4812.html */ if (autoconfig_read_divisor_id(up) == 0x0201 && size_fifo(up) == 16) return 1; @@ -903,23 +919,6 @@ static int broken_efr(struct uart_8250_port *up) return 0; } -static inline int ns16550a_goto_highspeed(struct uart_8250_port *up) -{ - unsigned char status; - - status = serial_in(up, 0x04); /* EXCR2 */ -#define PRESL(x) ((x) & 0x30) - if (PRESL(status) == 0x10) { - /* already in high speed mode */ - return 0; - } else { - status &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */ - status |= 0x10; /* 1.625 divisor for baud_base --> 921600 */ - serial_out(up, 0x04, status); - } - return 1; -} - /* * We know that the chip has FIFOs. Does it have an EFR? The * EFR is located in the same register position as the IIR and @@ -1122,7 +1121,7 @@ static void autoconfig_16550a(struct uart_8250_port *up) * whether or not this UART is a 16550A or not, since this will * determine whether or not we can use its FIFO features or not. */ -static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) +static void autoconfig(struct uart_8250_port *up) { unsigned char status1, scratch, scratch2, scratch3; unsigned char save_lcr, save_mcr; @@ -1245,22 +1244,15 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) /* * Only probe for RSA ports if we got the region. */ - if (port->type == PORT_16550A && probeflags & PROBE_RSA) { - int i; - - for (i = 0 ; i < probe_rsa_count; ++i) { - if (probe_rsa[i] == port->iobase && __enable_rsa(up)) { - port->type = PORT_RSA; - break; - } - } - } + if (port->type == PORT_16550A && up->probe & UART_PROBE_RSA && + __enable_rsa(up)) + port->type = PORT_RSA; #endif serial_out(up, UART_LCR, save_lcr); port->fifosize = uart_config[up->port.type].fifo_size; - old_capabilities = up->capabilities; + old_capabilities = up->capabilities; up->capabilities = uart_config[port->type].flags; up->tx_loadsz = uart_config[port->type].tx_loadsz; @@ -1907,6 +1899,48 @@ static void serial8250_backup_timeout(unsigned long data) jiffies + uart_poll_timeout(&up->port) + HZ / 5); } +static int univ8250_setup_irq(struct uart_8250_port *up) +{ + struct uart_port *port = &up->port; + int retval = 0; + + /* + * The above check will only give an accurate result the first time + * the port is opened so this value needs to be preserved. + */ + if (up->bugs & UART_BUG_THRE) { + pr_debug("ttyS%d - using backup timer\n", serial_index(port)); + + up->timer.function = serial8250_backup_timeout; + up->timer.data = (unsigned long)up; + mod_timer(&up->timer, jiffies + + uart_poll_timeout(port) + HZ / 5); + } + + /* + * If the "interrupt" for this port doesn't correspond with any + * hardware interrupt, we use a timer-based system. The original + * driver used to do this with IRQ0. + */ + if (!port->irq) { + up->timer.data = (unsigned long)up; + mod_timer(&up->timer, jiffies + uart_poll_timeout(port)); + } else + retval = serial_link_irq_chain(up); + + return retval; +} + +static void univ8250_release_irq(struct uart_8250_port *up) +{ + struct uart_port *port = &up->port; + + del_timer_sync(&up->timer); + up->timer.function = serial8250_timeout; + if (port->irq) + serial_unlink_irq_chain(up); +} + static unsigned int serial8250_tx_empty(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); @@ -1972,8 +2006,9 @@ EXPORT_SYMBOL_GPL(serial8250_do_set_mctrl); static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl) { if (port->set_mctrl) - return port->set_mctrl(port, mctrl); - return serial8250_do_set_mctrl(port, mctrl); + port->set_mctrl(port, mctrl); + else + serial8250_do_set_mctrl(port, mctrl); } static void serial8250_break_ctl(struct uart_port *port, int break_state) @@ -2211,35 +2246,12 @@ int serial8250_do_startup(struct uart_port *port) if ((!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) || up->port.flags & UPF_BUG_THRE) { up->bugs |= UART_BUG_THRE; - pr_debug("ttyS%d - using backup timer\n", - serial_index(port)); } } - /* - * The above check will only give an accurate result the first time - * the port is opened so this value needs to be preserved. - */ - if (up->bugs & UART_BUG_THRE) { - up->timer.function = serial8250_backup_timeout; - up->timer.data = (unsigned long)up; - mod_timer(&up->timer, jiffies + - uart_poll_timeout(port) + HZ / 5); - } - - /* - * If the "interrupt" for this port doesn't correspond with any - * hardware interrupt, we use a timer-based system. The original - * driver used to do this with IRQ0. - */ - if (!port->irq) { - up->timer.data = (unsigned long)up; - mod_timer(&up->timer, jiffies + uart_poll_timeout(port)); - } else { - retval = serial_link_irq_chain(up); - if (retval) - goto out; - } + retval = up->ops->setup_irq(up); + if (retval) + goto out; /* * Now, initialize the UART @@ -2270,7 +2282,7 @@ int serial8250_do_startup(struct uart_port *port) is variable. So, let's just don't test if we receive TX irq. This way, we'll never enable UART_BUG_TXEN. */ - if (skip_txen_test || up->port.flags & UPF_NO_TXEN_TEST) + if (up->port.flags & UPF_NO_TXEN_TEST) goto dont_test_tx_en; /* @@ -2397,10 +2409,7 @@ void serial8250_do_shutdown(struct uart_port *port) serial_port_in(port, UART_RX); serial8250_rpm_put(up); - del_timer_sync(&up->timer); - up->timer.function = serial8250_timeout; - if (port->irq) - serial_unlink_irq_chain(up); + up->ops->release_irq(up); } EXPORT_SYMBOL_GPL(serial8250_do_shutdown); @@ -2719,6 +2728,8 @@ serial8250_pm(struct uart_port *port, unsigned int state, static unsigned int serial8250_port_size(struct uart_8250_port *pt) { + if (pt->port.mapsize) + return pt->port.mapsize; if (pt->port.iotype == UPIO_AU) { if (pt->port.type == PORT_RT2880) return 0x100; @@ -2743,6 +2754,7 @@ static int serial8250_request_std_resource(struct uart_8250_port *up) case UPIO_AU: case UPIO_TSI: case UPIO_MEM32: + case UPIO_MEM32BE: case UPIO_MEM: if (!port->mapbase) break; @@ -2779,6 +2791,7 @@ static void serial8250_release_std_resource(struct uart_8250_port *up) case UPIO_AU: case UPIO_TSI: case UPIO_MEM32: + case UPIO_MEM32BE: case UPIO_MEM: if (!port->mapbase) break; @@ -2798,6 +2811,7 @@ static void serial8250_release_std_resource(struct uart_8250_port *up) } } +#ifdef CONFIG_SERIAL_8250_RSA static int serial8250_request_rsa_resource(struct uart_8250_port *up) { unsigned long start = UART_RSA_BASE << up->port.regshift; @@ -2832,14 +2846,13 @@ static void serial8250_release_rsa_resource(struct uart_8250_port *up) break; } } +#endif static void serial8250_release_port(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); serial8250_release_std_resource(up); - if (port->type == PORT_RSA) - serial8250_release_rsa_resource(up); } static int serial8250_request_port(struct uart_port *port) @@ -2851,11 +2864,6 @@ static int serial8250_request_port(struct uart_port *port) return -ENODEV; ret = serial8250_request_std_resource(up); - if (ret == 0 && port->type == PORT_RSA) { - ret = serial8250_request_rsa_resource(up); - if (ret < 0) - serial8250_release_std_resource(up); - } return ret; } @@ -3003,7 +3011,6 @@ static void register_dev_spec_attr_grp(struct uart_8250_port *up) static void serial8250_config_port(struct uart_port *port, int flags) { struct uart_8250_port *up = up_to_u8250p(port); - int probeflags = PROBE_ANY; int ret; if (port->type == PORT_8250_CIR) @@ -3017,15 +3024,11 @@ static void serial8250_config_port(struct uart_port *port, int flags) if (ret < 0) return; - ret = serial8250_request_rsa_resource(up); - if (ret < 0) - probeflags &= ~PROBE_RSA; - if (port->iotype != up->cur_iotype) set_io_from_upio(port); if (flags & UART_CONFIG_TYPE) - autoconfig(up, probeflags); + autoconfig(up); /* if access method is AU, it is a 16550 with a quirk */ if (port->type == PORT_16550A && port->iotype == UPIO_AU) @@ -3038,8 +3041,6 @@ static void serial8250_config_port(struct uart_port *port, int flags) if (port->type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ) autoconfig_irq(up); - if (port->type != PORT_RSA && probeflags & PROBE_RSA) - serial8250_release_rsa_resource(up); if (port->type == PORT_UNKNOWN) serial8250_release_std_resource(up); @@ -3073,7 +3074,7 @@ serial8250_type(struct uart_port *port) return uart_config[type].name; } -static struct uart_ops serial8250_pops = { +static const struct uart_ops serial8250_pops = { .tx_empty = serial8250_tx_empty, .set_mctrl = serial8250_set_mctrl, .get_mctrl = serial8250_get_mctrl, @@ -3100,6 +3101,14 @@ static struct uart_ops serial8250_pops = { #endif }; +static const struct uart_ops *base_ops; +static struct uart_ops univ8250_port_ops; + +static const struct uart_8250_ops univ8250_driver_ops = { + .setup_irq = univ8250_setup_irq, + .release_irq = univ8250_release_irq, +}; + static struct uart_8250_port serial8250_ports[UART_NR]; /** @@ -3130,6 +3139,105 @@ void serial8250_set_isa_configurator( } EXPORT_SYMBOL(serial8250_set_isa_configurator); +static void serial8250_init_port(struct uart_8250_port *up) +{ + struct uart_port *port = &up->port; + + spin_lock_init(&port->lock); + port->ops = &serial8250_pops; + + up->cur_iotype = 0xFF; +} + +static void serial8250_set_defaults(struct uart_8250_port *up) +{ + struct uart_port *port = &up->port; + + if (up->port.flags & UPF_FIXED_TYPE) { + unsigned int type = up->port.type; + + if (!up->port.fifosize) + up->port.fifosize = uart_config[type].fifo_size; + if (!up->tx_loadsz) + up->tx_loadsz = uart_config[type].tx_loadsz; + if (!up->capabilities) + up->capabilities = uart_config[type].flags; + } + + set_io_from_upio(port); + + /* default dma handlers */ + if (up->dma) { + if (!up->dma->tx_dma) + up->dma->tx_dma = serial8250_tx_dma; + if (!up->dma->rx_dma) + up->dma->rx_dma = serial8250_rx_dma; + } +} + +#ifdef CONFIG_SERIAL_8250_RSA + +static void univ8250_config_port(struct uart_port *port, int flags) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + up->probe &= ~UART_PROBE_RSA; + if (port->type == PORT_RSA) { + if (serial8250_request_rsa_resource(up) == 0) + up->probe |= UART_PROBE_RSA; + } else if (flags & UART_CONFIG_TYPE) { + int i; + + for (i = 0; i < probe_rsa_count; i++) { + if (probe_rsa[i] == up->port.iobase) { + if (serial8250_request_rsa_resource(up) == 0) + up->probe |= UART_PROBE_RSA; + break; + } + } + } + + base_ops->config_port(port, flags); + + if (port->type != PORT_RSA && up->probe & UART_PROBE_RSA) + serial8250_release_rsa_resource(up); +} + +static int univ8250_request_port(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + int ret; + + ret = base_ops->request_port(port); + if (ret == 0 && port->type == PORT_RSA) { + ret = serial8250_request_rsa_resource(up); + if (ret < 0) + base_ops->release_port(port); + } + + return ret; +} + +static void univ8250_release_port(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + if (port->type == PORT_RSA) + serial8250_release_rsa_resource(up); + base_ops->release_port(port); +} + +static void univ8250_rsa_support(struct uart_ops *ops) +{ + ops->config_port = univ8250_config_port; + ops->request_port = univ8250_request_port; + ops->release_port = univ8250_release_port; +} + +#else +#define univ8250_rsa_support(x) do { } while (0) +#endif /* CONFIG_SERIAL_8250_RSA */ + static void __init serial8250_isa_init_ports(void) { struct uart_8250_port *up; @@ -3148,21 +3256,27 @@ static void __init serial8250_isa_init_ports(void) struct uart_port *port = &up->port; port->line = i; - spin_lock_init(&port->lock); + serial8250_init_port(up); + if (!base_ops) + base_ops = port->ops; + port->ops = &univ8250_port_ops; init_timer(&up->timer); up->timer.function = serial8250_timeout; - up->cur_iotype = 0xFF; + + up->ops = &univ8250_driver_ops; /* * ALPHA_KLUDGE_MCR needs to be killed. */ up->mcr_mask = ~ALPHA_KLUDGE_MCR; up->mcr_force = ALPHA_KLUDGE_MCR; - - port->ops = &serial8250_pops; } + /* chain base port ops to support Remote Supervisor Adapter */ + univ8250_port_ops = *base_ops; + univ8250_rsa_support(&univ8250_port_ops); + if (share_irqs) irqflag = IRQF_SHARED; @@ -3180,26 +3294,14 @@ static void __init serial8250_isa_init_ports(void) port->membase = old_serial_port[i].iomem_base; port->iotype = old_serial_port[i].io_type; port->regshift = old_serial_port[i].iomem_reg_shift; - set_io_from_upio(port); + serial8250_set_defaults(up); + port->irqflags |= irqflag; if (serial8250_isa_config != NULL) serial8250_isa_config(i, &up->port, &up->capabilities); - } } -static void -serial8250_init_fixed_type_port(struct uart_8250_port *up, unsigned int type) -{ - up->port.type = type; - if (!up->port.fifosize) - up->port.fifosize = uart_config[type].fifo_size; - if (!up->tx_loadsz) - up->tx_loadsz = uart_config[type].tx_loadsz; - if (!up->capabilities) - up->capabilities = uart_config[type].flags; -} - static void __init serial8250_register_ports(struct uart_driver *drv, struct device *dev) { @@ -3213,8 +3315,8 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev) up->port.dev = dev; - if (up->port.flags & UPF_FIXED_TYPE) - serial8250_init_fixed_type_port(up, up->port.type); + if (skip_txen_test) + up->port.flags |= UPF_NO_TXEN_TEST; uart_add_one_port(drv, &up->port); } @@ -3236,10 +3338,9 @@ static void serial8250_console_putchar(struct uart_port *port, int ch) * * The console_lock must be held when we get here. */ -static void -serial8250_console_write(struct console *co, const char *s, unsigned int count) +static void serial8250_console_write(struct uart_8250_port *up, const char *s, + unsigned int count) { - struct uart_8250_port *up = &serial8250_ports[co->index]; struct uart_port *port = &up->port; unsigned long flags; unsigned int ier; @@ -3311,14 +3412,51 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) serial8250_rpm_put(up); } -static int serial8250_console_setup(struct console *co, char *options) +static void univ8250_console_write(struct console *co, const char *s, + unsigned int count) +{ + struct uart_8250_port *up = &serial8250_ports[co->index]; + + serial8250_console_write(up, s, count); +} + +static unsigned int probe_baud(struct uart_port *port) +{ + unsigned char lcr, dll, dlm; + unsigned int quot; + + lcr = serial_port_in(port, UART_LCR); + serial_port_out(port, UART_LCR, lcr | UART_LCR_DLAB); + dll = serial_port_in(port, UART_DLL); + dlm = serial_port_in(port, UART_DLM); + serial_port_out(port, UART_LCR, lcr); + + quot = (dlm << 8) | dll; + return (port->uartclk / 16) / quot; +} + +static int serial8250_console_setup(struct uart_port *port, char *options, bool probe) { - struct uart_port *port; int baud = 9600; int bits = 8; int parity = 'n'; int flow = 'n'; + if (!port->iobase && !port->membase) + return -ENODEV; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else if (probe) + baud = probe_baud(port); + + return uart_set_options(port, port->cons, baud, parity, bits, flow); +} + +static int univ8250_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + /* * Check whether an invalid uart number has been specified, and * if so, search for the first available port that does have @@ -3327,53 +3465,87 @@ static int serial8250_console_setup(struct console *co, char *options) if (co->index >= nr_uarts) co->index = 0; port = &serial8250_ports[co->index].port; - if (!port->iobase && !port->membase) - return -ENODEV; + /* link port to console */ + port->cons = co; - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - - return uart_set_options(port, co, baud, parity, bits, flow); + return serial8250_console_setup(port, options, false); } -static int serial8250_console_early_setup(void) +/** + * univ8250_console_match - non-standard console matching + * @co: registering console + * @name: name from console command line + * @idx: index from console command line + * @options: ptr to option string from console command line + * + * Only attempts to match console command lines of the form: + * console=uart[8250],io|mmio|mmio32,<addr>[,<options>] + * console=uart[8250],0x<addr>[,<options>] + * This form is used to register an initial earlycon boot console and + * replace it with the serial8250_console at 8250 driver init. + * + * Performs console setup for a match (as required by interface) + * If no <options> are specified, then assume the h/w is already setup. + * + * Returns 0 if console matches; otherwise non-zero to use default matching + */ +static int univ8250_console_match(struct console *co, char *name, int idx, + char *options) { - return serial8250_find_port_for_earlycon(); + char match[] = "uart"; /* 8250-specific earlycon name */ + unsigned char iotype; + unsigned long addr; + int i; + + if (strncmp(name, match, 4) != 0) + return -ENODEV; + + if (uart_parse_earlycon(options, &iotype, &addr, &options)) + return -ENODEV; + + /* try to match the port specified on the command line */ + for (i = 0; i < nr_uarts; i++) { + struct uart_port *port = &serial8250_ports[i].port; + + if (port->iotype != iotype) + continue; + if ((iotype == UPIO_MEM || iotype == UPIO_MEM32) && + (port->mapbase != addr)) + continue; + if (iotype == UPIO_PORT && port->iobase != addr) + continue; + + co->index = i; + port->cons = co; + return serial8250_console_setup(port, options, true); + } + + return -ENODEV; } -static struct console serial8250_console = { +static struct console univ8250_console = { .name = "ttyS", - .write = serial8250_console_write, + .write = univ8250_console_write, .device = uart_console_device, - .setup = serial8250_console_setup, - .early_setup = serial8250_console_early_setup, + .setup = univ8250_console_setup, + .match = univ8250_console_match, .flags = CON_PRINTBUFFER | CON_ANYTIME, .index = -1, .data = &serial8250_reg, }; -static int __init serial8250_console_init(void) +static int __init univ8250_console_init(void) { + if (nr_uarts == 0) + return -ENODEV; + serial8250_isa_init_ports(); - register_console(&serial8250_console); + register_console(&univ8250_console); return 0; } -console_initcall(serial8250_console_init); - -int serial8250_find_port(struct uart_port *p) -{ - int line; - struct uart_port *port; - - for (line = 0; line < nr_uarts; line++) { - port = &serial8250_ports[line].port; - if (uart_match_port(p, port)) - return line; - } - return -ENODEV; -} +console_initcall(univ8250_console_init); -#define SERIAL8250_CONSOLE &serial8250_console +#define SERIAL8250_CONSOLE &univ8250_console #else #define SERIAL8250_CONSOLE NULL #endif @@ -3397,7 +3569,7 @@ int __init early_serial_setup(struct uart_port *port) { struct uart_port *p; - if (port->line >= ARRAY_SIZE(serial8250_ports)) + if (port->line >= ARRAY_SIZE(serial8250_ports) || nr_uarts == 0) return -ENODEV; serial8250_isa_init_ports(); @@ -3412,19 +3584,19 @@ int __init early_serial_setup(struct uart_port *port) p->iotype = port->iotype; p->flags = port->flags; p->mapbase = port->mapbase; + p->mapsize = port->mapsize; p->private_data = port->private_data; p->type = port->type; p->line = port->line; - set_io_from_upio(p); + serial8250_set_defaults(up_to_u8250p(p)); + if (port->serial_in) p->serial_in = port->serial_in; if (port->serial_out) p->serial_out = port->serial_out; if (port->handle_irq) p->handle_irq = port->handle_irq; - else - p->handle_irq = serial8250_default_handle_irq; return 0; } @@ -3444,7 +3616,8 @@ void serial8250_suspend_port(int line) port->type != PORT_8250) { unsigned char canary = 0xa5; serial_out(up, UART_SCR, canary); - up->canary = canary; + if (serial_in(up, UART_SCR) == canary) + up->canary = canary; } uart_suspend_port(&serial8250_reg, port); @@ -3666,14 +3839,15 @@ int serial8250_register_8250_port(struct uart_8250_port *up) uart->port.flags = up->port.flags | UPF_BOOT_AUTOCONF; uart->bugs = up->bugs; uart->port.mapbase = up->port.mapbase; + uart->port.mapsize = up->port.mapsize; uart->port.private_data = up->port.private_data; - uart->port.fifosize = up->port.fifosize; uart->tx_loadsz = up->tx_loadsz; uart->capabilities = up->capabilities; uart->port.throttle = up->port.throttle; uart->port.unthrottle = up->port.unthrottle; uart->port.rs485_config = up->port.rs485_config; uart->port.rs485 = up->port.rs485; + uart->dma = up->dma; /* Take tx_loadsz from fifosize if it wasn't set separately */ if (uart->port.fifosize && !uart->tx_loadsz) @@ -3682,10 +3856,14 @@ int serial8250_register_8250_port(struct uart_8250_port *up) if (up->port.dev) uart->port.dev = up->port.dev; + if (skip_txen_test) + uart->port.flags |= UPF_NO_TXEN_TEST; + if (up->port.flags & UPF_FIXED_TYPE) - serial8250_init_fixed_type_port(uart, up->port.type); + uart->port.type = up->port.type; + + serial8250_set_defaults(uart); - set_io_from_upio(&uart->port); /* Possibly override default I/O functions. */ if (up->port.serial_in) uart->port.serial_in = up->port.serial_in; @@ -3710,13 +3888,6 @@ int serial8250_register_8250_port(struct uart_8250_port *up) uart->dl_read = up->dl_read; if (up->dl_write) uart->dl_write = up->dl_write; - if (up->dma) { - uart->dma = up->dma; - if (!uart->dma->tx_dma) - uart->dma->tx_dma = serial8250_tx_dma; - if (!uart->dma->rx_dma) - uart->dma->rx_dma = serial8250_rx_dma; - } if (serial8250_isa_config != NULL) serial8250_isa_config(0, &uart->port, @@ -3747,9 +3918,11 @@ void serial8250_unregister_port(int line) uart_remove_one_port(&serial8250_reg, &uart->port); if (serial8250_isa_devs) { uart->port.flags &= ~UPF_BOOT_AUTOCONF; + if (skip_txen_test) + uart->port.flags |= UPF_NO_TXEN_TEST; uart->port.type = PORT_UNKNOWN; uart->port.dev = &serial8250_isa_devs->dev; - uart->capabilities = uart_config[uart->port.type].flags; + uart->capabilities = 0; uart_add_one_port(&serial8250_reg, &uart->port); } else { uart->port.dev = NULL; @@ -3762,6 +3935,9 @@ static int __init serial8250_init(void) { int ret; + if (nr_uarts == 0) + return -ENODEV; + serial8250_isa_init_ports(); printk(KERN_INFO "Serial: 8250/16550 driver, " diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 6ae5b8560e4d..d48b50641e9a 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -17,7 +17,6 @@ #include <linux/io.h> #include <linux/module.h> #include <linux/serial_8250.h> -#include <linux/serial_core.h> #include <linux/serial_reg.h> #include <linux/of.h> #include <linux/of_irq.h> @@ -364,9 +363,9 @@ static int dw8250_probe_of(struct uart_port *p, } if (of_property_read_bool(np, "cts-override")) { - /* Always report DSR as active */ - data->msr_mask_on |= UART_MSR_DSR; - data->msr_mask_off |= UART_MSR_DDSR; + /* Always report CTS as active */ + data->msr_mask_on |= UART_MSR_CTS; + data->msr_mask_off |= UART_MSR_DCTS; } if (of_property_read_bool(np, "ri-override")) { @@ -375,44 +374,40 @@ static int dw8250_probe_of(struct uart_port *p, data->msr_mask_off |= UART_MSR_TERI; } - /* clock got configured through clk api, all done */ - if (p->uartclk) - return 0; + return 0; +} - /* try to find out clock frequency from DT as fallback */ - if (of_property_read_u32(np, "clock-frequency", &val)) { - dev_err(p->dev, "clk or clock-frequency not defined\n"); - return -EINVAL; - } - p->uartclk = val; +static bool dw8250_idma_filter(struct dma_chan *chan, void *param) +{ + struct device *dev = param; - return 0; + if (dev != chan->device->dev->parent) + return false; + + return true; } static int dw8250_probe_acpi(struct uart_8250_port *up, struct dw8250_data *data) { - const struct acpi_device_id *id; struct uart_port *p = &up->port; dw8250_setup_port(up); - id = acpi_match_device(p->dev->driver->acpi_match_table, p->dev); - if (!id) - return -ENODEV; - - if (!p->uartclk) - if (device_property_read_u32(p->dev, "clock-frequency", - &p->uartclk)) - return -EINVAL; - p->iotype = UPIO_MEM32; p->serial_in = dw8250_serial_in32; p->serial_out = dw8250_serial_out32; p->regshift = 2; - up->dma = &data->dma; + /* Platforms with iDMA */ + if (platform_get_resource_byname(to_platform_device(up->port.dev), + IORESOURCE_MEM, "lpss_priv")) { + data->dma.rx_param = up->port.dev->parent; + data->dma.tx_param = up->port.dev->parent; + data->dma.fn = dw8250_idma_filter; + } + up->dma = &data->dma; up->dma->rxconf.src_maxburst = p->fifosize / 4; up->dma->txconf.dst_maxburst = p->fifosize / 4; @@ -425,18 +420,24 @@ static int dw8250_probe(struct platform_device *pdev) { struct uart_8250_port uart = {}; struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + int irq = platform_get_irq(pdev, 0); struct dw8250_data *data; int err; - if (!regs || !irq) { - dev_err(&pdev->dev, "no registers/irq defined\n"); + if (!regs) { + dev_err(&pdev->dev, "no registers defined\n"); return -EINVAL; } + if (irq < 0) { + if (irq != -EPROBE_DEFER) + dev_err(&pdev->dev, "cannot get irq\n"); + return irq; + } + spin_lock_init(&uart.port.lock); uart.port.mapbase = regs->start; - uart.port.irq = irq->start; + uart.port.irq = irq; uart.port.handle_irq = dw8250_handle_irq; uart.port.pm = dw8250_do_pm; uart.port.type = PORT_8250; @@ -453,12 +454,18 @@ static int dw8250_probe(struct platform_device *pdev) return -ENOMEM; data->usr_reg = DW_UART_USR; + + /* Always ask for fixed clock rate from a property. */ + device_property_read_u32(&pdev->dev, "clock-frequency", + &uart.port.uartclk); + + /* If there is separate baudclk, get the rate from it. */ data->clk = devm_clk_get(&pdev->dev, "baudclk"); if (IS_ERR(data->clk) && PTR_ERR(data->clk) != -EPROBE_DEFER) data->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER) return -EPROBE_DEFER; - if (!IS_ERR(data->clk)) { + if (!IS_ERR_OR_NULL(data->clk)) { err = clk_prepare_enable(data->clk); if (err) dev_warn(&pdev->dev, "could not enable optional baudclk: %d\n", @@ -467,6 +474,12 @@ static int dw8250_probe(struct platform_device *pdev) uart.port.uartclk = clk_get_rate(data->clk); } + /* If no clock rate is defined, fail. */ + if (!uart.port.uartclk) { + dev_err(&pdev->dev, "clock rate not defined\n"); + return -EINVAL; + } + data->pclk = devm_clk_get(&pdev->dev, "apb_pclk"); if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER) { err = -EPROBE_DEFER; @@ -629,6 +642,7 @@ static const struct acpi_device_id dw8250_acpi_match[] = { { "80860F0A", 0 }, { "8086228A", 0 }, { "APMC0D08", 0}, + { "AMD0020", 0 }, { }, }; MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match); @@ -649,3 +663,4 @@ module_platform_driver(dw8250_platform_driver); MODULE_AUTHOR("Jamie Iles"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Synopsys DesignWare 8250 serial port driver"); +MODULE_ALIAS("platform:dw-apb-uart"); diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c index c31a22b4f845..771dda29a0f8 100644 --- a/drivers/tty/serial/8250/8250_early.c +++ b/drivers/tty/serial/8250/8250_early.c @@ -29,15 +29,12 @@ #include <linux/tty.h> #include <linux/init.h> #include <linux/console.h> -#include <linux/serial_core.h> #include <linux/serial_reg.h> #include <linux/serial.h> #include <linux/serial_8250.h> #include <asm/io.h> #include <asm/serial.h> -static struct earlycon_device *early_device; - unsigned int __weak __init serial8250_early_in(struct uart_port *port, int offset) { switch (port->iotype) { @@ -45,6 +42,8 @@ unsigned int __weak __init serial8250_early_in(struct uart_port *port, int offse return readb(port->membase + offset); case UPIO_MEM32: return readl(port->membase + (offset << 2)); + case UPIO_MEM32BE: + return ioread32be(port->membase + (offset << 2)); case UPIO_PORT: return inb(port->iobase + offset); default: @@ -61,6 +60,9 @@ void __weak __init serial8250_early_out(struct uart_port *port, int offset, int case UPIO_MEM32: writel(value, port->membase + (offset << 2)); break; + case UPIO_MEM32BE: + iowrite32be(value, port->membase + (offset << 2)); + break; case UPIO_PORT: outb(value, port->iobase + offset); break; @@ -90,7 +92,8 @@ static void __init serial_putc(struct uart_port *port, int c) static void __init early_serial8250_write(struct console *console, const char *s, unsigned int count) { - struct uart_port *port = &early_device->port; + struct earlycon_device *device = console->data; + struct uart_port *port = &device->port; unsigned int ier; /* Save the IER and disable interrupts preserving the UUE bit */ @@ -107,21 +110,6 @@ static void __init early_serial8250_write(struct console *console, serial8250_early_out(port, UART_IER, ier); } -static unsigned int __init probe_baud(struct uart_port *port) -{ - unsigned char lcr, dll, dlm; - unsigned int quot; - - lcr = serial8250_early_in(port, UART_LCR); - serial8250_early_out(port, UART_LCR, lcr | UART_LCR_DLAB); - dll = serial8250_early_in(port, UART_DLL); - dlm = serial8250_early_in(port, UART_DLM); - serial8250_early_out(port, UART_LCR, lcr); - - quot = (dlm << 8) | dll; - return (port->uartclk / 16) / quot; -} - static void __init init_port(struct earlycon_device *device) { struct uart_port *port = &device->port; @@ -143,56 +131,24 @@ static void __init init_port(struct earlycon_device *device) serial8250_early_out(port, UART_LCR, c & ~UART_LCR_DLAB); } -static int __init early_serial8250_setup(struct earlycon_device *device, +int __init early_serial8250_setup(struct earlycon_device *device, const char *options) { if (!(device->port.membase || device->port.iobase)) - return 0; + return -ENODEV; if (!device->baud) { - device->baud = probe_baud(&device->port); - snprintf(device->options, sizeof(device->options), "%u", - device->baud); - } + struct uart_port *port = &device->port; + unsigned int ier; - init_port(device); + /* assume the device was initialized, only mask interrupts */ + ier = serial8250_early_in(port, UART_IER); + serial8250_early_out(port, UART_IER, ier & UART_IER_UUE); + } else + init_port(device); - early_device = device; device->con->write = early_serial8250_write; return 0; } EARLYCON_DECLARE(uart8250, early_serial8250_setup); EARLYCON_DECLARE(uart, early_serial8250_setup); - -int __init setup_early_serial8250_console(char *cmdline) -{ - char match[] = "uart8250"; - - if (cmdline && cmdline[4] == ',') - match[4] = '\0'; - - return setup_earlycon(cmdline, match, early_serial8250_setup); -} - -int serial8250_find_port_for_earlycon(void) -{ - struct earlycon_device *device = early_device; - struct uart_port *port = device ? &device->port : NULL; - int line; - int ret; - - if (!port || (!port->membase && !port->iobase)) - return -ENODEV; - - line = serial8250_find_port(port); - if (line < 0) - return -ENODEV; - - ret = update_console_cmdline("uart", 8250, - "ttyS", line, device->options); - if (ret < 0) - ret = update_console_cmdline("uart", 0, - "ttyS", line, device->options); - - return ret; -} diff --git a/drivers/tty/serial/8250/8250_em.c b/drivers/tty/serial/8250/8250_em.c index ae5eaed6aa85..0b6381214917 100644 --- a/drivers/tty/serial/8250/8250_em.c +++ b/drivers/tty/serial/8250/8250_em.c @@ -21,7 +21,6 @@ #include <linux/io.h> #include <linux/module.h> #include <linux/serial_8250.h> -#include <linux/serial_core.h> #include <linux/serial_reg.h> #include <linux/platform_device.h> #include <linux/clk.h> diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c index 1e6899bc9429..5815e81b5fc6 100644 --- a/drivers/tty/serial/8250/8250_fintek.c +++ b/drivers/tty/serial/8250/8250_fintek.c @@ -234,18 +234,7 @@ static struct pnp_driver fintek_8250_driver = { .id_table = fintek_dev_table, }; -static int fintek_8250_init(void) -{ - return pnp_register_driver(&fintek_8250_driver); -} -module_init(fintek_8250_init); - -static void fintek_8250_exit(void) -{ - pnp_unregister_driver(&fintek_8250_driver); -} -module_exit(fintek_8250_exit); - +module_pnp_driver(fintek_8250_driver); MODULE_DESCRIPTION("Fintek F812164 module"); MODULE_AUTHOR("Ricardo Ribalda <ricardo.ribalda@gmail.com>"); MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/8250/8250_hp300.c b/drivers/tty/serial/8250/8250_hp300.c index b4882082b247..2891958cd842 100644 --- a/drivers/tty/serial/8250/8250_hp300.c +++ b/drivers/tty/serial/8250/8250_hp300.c @@ -10,7 +10,6 @@ #include <linux/string.h> #include <linux/kernel.h> #include <linux/serial.h> -#include <linux/serial_core.h> #include <linux/serial_8250.h> #include <linux/delay.h> #include <linux/dio.h> diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c new file mode 100644 index 000000000000..21bf81fe794f --- /dev/null +++ b/drivers/tty/serial/8250/8250_ingenic.c @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2010 Lars-Peter Clausen <lars@metafoo.de> + * Copyright (C) 2015 Imagination Technologies + * + * Ingenic SoC UART support + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/clk.h> +#include <linux/console.h> +#include <linux/io.h> +#include <linux/libfdt.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_fdt.h> +#include <linux/platform_device.h> +#include <linux/serial_8250.h> +#include <linux/serial_core.h> +#include <linux/serial_reg.h> + +struct ingenic_uart_data { + struct clk *clk_module; + struct clk *clk_baud; + int line; +}; + +#define UART_FCR_UME BIT(4) + +static struct earlycon_device *early_device; + +static uint8_t __init early_in(struct uart_port *port, int offset) +{ + return readl(port->membase + (offset << 2)); +} + +static void __init early_out(struct uart_port *port, int offset, uint8_t value) +{ + writel(value, port->membase + (offset << 2)); +} + +static void __init ingenic_early_console_putc(struct uart_port *port, int c) +{ + uint8_t lsr; + + do { + lsr = early_in(port, UART_LSR); + } while ((lsr & UART_LSR_TEMT) == 0); + + early_out(port, UART_TX, c); +} + +static void __init ingenic_early_console_write(struct console *console, + const char *s, unsigned int count) +{ + uart_console_write(&early_device->port, s, count, + ingenic_early_console_putc); +} + +static void __init ingenic_early_console_setup_clock(struct earlycon_device *dev) +{ + void *fdt = initial_boot_params; + const __be32 *prop; + int offset; + + offset = fdt_path_offset(fdt, "/ext"); + if (offset < 0) + return; + + prop = fdt_getprop(fdt, offset, "clock-frequency", NULL); + if (!prop) + return; + + dev->port.uartclk = be32_to_cpup(prop); +} + +static int __init ingenic_early_console_setup(struct earlycon_device *dev, + const char *opt) +{ + struct uart_port *port = &dev->port; + unsigned int baud, divisor; + + if (!dev->port.membase) + return -ENODEV; + + ingenic_early_console_setup_clock(dev); + + baud = dev->baud ?: 115200; + divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * baud); + + early_out(port, UART_IER, 0); + early_out(port, UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN8); + early_out(port, UART_DLL, 0); + early_out(port, UART_DLM, 0); + early_out(port, UART_LCR, UART_LCR_WLEN8); + early_out(port, UART_FCR, UART_FCR_UME | UART_FCR_CLEAR_XMIT | + UART_FCR_CLEAR_RCVR | UART_FCR_ENABLE_FIFO); + early_out(port, UART_MCR, UART_MCR_RTS | UART_MCR_DTR); + + early_out(port, UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN8); + early_out(port, UART_DLL, divisor & 0xff); + early_out(port, UART_DLM, (divisor >> 8) & 0xff); + early_out(port, UART_LCR, UART_LCR_WLEN8); + + early_device = dev; + dev->con->write = ingenic_early_console_write; + + return 0; +} + +EARLYCON_DECLARE(jz4740_uart, ingenic_early_console_setup); +OF_EARLYCON_DECLARE(jz4740_uart, "ingenic,jz4740-uart", + ingenic_early_console_setup); + +EARLYCON_DECLARE(jz4775_uart, ingenic_early_console_setup); +OF_EARLYCON_DECLARE(jz4775_uart, "ingenic,jz4775-uart", + ingenic_early_console_setup); + +EARLYCON_DECLARE(jz4780_uart, ingenic_early_console_setup); +OF_EARLYCON_DECLARE(jz4780_uart, "ingenic,jz4780-uart", + ingenic_early_console_setup); + +static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value) +{ + switch (offset) { + case UART_FCR: + /* UART module enable */ + value |= UART_FCR_UME; + break; + + case UART_IER: + value |= (value & 0x4) << 2; + break; + + default: + break; + } + + writeb(value, p->membase + (offset << p->regshift)); +} + +static int ingenic_uart_probe(struct platform_device *pdev) +{ + struct uart_8250_port uart = {}; + struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + struct ingenic_uart_data *data; + int err, line; + + if (!regs || !irq) { + dev_err(&pdev->dev, "no registers/irq defined\n"); + return -EINVAL; + } + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + spin_lock_init(&uart.port.lock); + uart.port.type = PORT_16550; + uart.port.flags = UPF_SKIP_TEST | UPF_IOREMAP | UPF_FIXED_TYPE; + uart.port.iotype = UPIO_MEM; + uart.port.mapbase = regs->start; + uart.port.regshift = 2; + uart.port.serial_out = ingenic_uart_serial_out; + uart.port.irq = irq->start; + uart.port.dev = &pdev->dev; + + /* Check for a fixed line number */ + line = of_alias_get_id(pdev->dev.of_node, "serial"); + if (line >= 0) + uart.port.line = line; + + uart.port.membase = devm_ioremap(&pdev->dev, regs->start, + resource_size(regs)); + if (!uart.port.membase) + return -ENOMEM; + + data->clk_module = devm_clk_get(&pdev->dev, "module"); + if (IS_ERR(data->clk_module)) { + err = PTR_ERR(data->clk_module); + if (err != -EPROBE_DEFER) + dev_err(&pdev->dev, + "unable to get module clock: %d\n", err); + return err; + } + + data->clk_baud = devm_clk_get(&pdev->dev, "baud"); + if (IS_ERR(data->clk_baud)) { + err = PTR_ERR(data->clk_baud); + if (err != -EPROBE_DEFER) + dev_err(&pdev->dev, + "unable to get baud clock: %d\n", err); + return err; + } + + err = clk_prepare_enable(data->clk_module); + if (err) { + dev_err(&pdev->dev, "could not enable module clock: %d\n", err); + goto out; + } + + err = clk_prepare_enable(data->clk_baud); + if (err) { + dev_err(&pdev->dev, "could not enable baud clock: %d\n", err); + goto out_disable_moduleclk; + } + uart.port.uartclk = clk_get_rate(data->clk_baud); + + data->line = serial8250_register_8250_port(&uart); + if (data->line < 0) { + err = data->line; + goto out_disable_baudclk; + } + + platform_set_drvdata(pdev, data); + return 0; + +out_disable_baudclk: + clk_disable_unprepare(data->clk_baud); +out_disable_moduleclk: + clk_disable_unprepare(data->clk_module); +out: + return err; +} + +static int ingenic_uart_remove(struct platform_device *pdev) +{ + struct ingenic_uart_data *data = platform_get_drvdata(pdev); + + serial8250_unregister_port(data->line); + clk_disable_unprepare(data->clk_module); + clk_disable_unprepare(data->clk_baud); + return 0; +} + +static const struct of_device_id of_match[] = { + { .compatible = "ingenic,jz4740-uart" }, + { .compatible = "ingenic,jz4775-uart" }, + { .compatible = "ingenic,jz4780-uart" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match); + +static struct platform_driver ingenic_uart_platform_driver = { + .driver = { + .name = "ingenic-uart", + .owner = THIS_MODULE, + .of_match_table = of_match, + }, + .probe = ingenic_uart_probe, + .remove = ingenic_uart_remove, +}; + +module_platform_driver(ingenic_uart_platform_driver); + +MODULE_AUTHOR("Paul Burton"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Ingenic SoC UART driver"); diff --git a/drivers/tty/serial/8250/8250_lpc18xx.c b/drivers/tty/serial/8250/8250_lpc18xx.c new file mode 100644 index 000000000000..99cd478851ff --- /dev/null +++ b/drivers/tty/serial/8250/8250_lpc18xx.c @@ -0,0 +1,230 @@ +/* + * Serial port driver for NXP LPC18xx/43xx UART + * + * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com> + * + * Based on 8250_mtk.c: + * Copyright (c) 2014 MundoReader S.L. + * Matthias Brugger <matthias.bgg@gmail.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/clk.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> + +#include "8250.h" + +/* Additional LPC18xx/43xx 8250 registers and bits */ +#define LPC18XX_UART_RS485CTRL (0x04c / sizeof(u32)) +#define LPC18XX_UART_RS485CTRL_NMMEN BIT(0) +#define LPC18XX_UART_RS485CTRL_DCTRL BIT(4) +#define LPC18XX_UART_RS485CTRL_OINV BIT(5) +#define LPC18XX_UART_RS485DLY (0x054 / sizeof(u32)) +#define LPC18XX_UART_RS485DLY_MAX 255 + +struct lpc18xx_uart_data { + struct uart_8250_dma dma; + struct clk *clk_uart; + struct clk *clk_reg; + int line; +}; + +static int lpc18xx_rs485_config(struct uart_port *port, + struct serial_rs485 *rs485) +{ + struct uart_8250_port *up = up_to_u8250p(port); + u32 rs485_ctrl_reg = 0; + u32 rs485_dly_reg = 0; + unsigned baud_clk; + + if (rs485->flags & SER_RS485_ENABLED) + memset(rs485->padding, 0, sizeof(rs485->padding)); + else + memset(rs485, 0, sizeof(*rs485)); + + rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | + SER_RS485_RTS_AFTER_SEND; + + if (rs485->flags & SER_RS485_ENABLED) { + rs485_ctrl_reg |= LPC18XX_UART_RS485CTRL_NMMEN | + LPC18XX_UART_RS485CTRL_DCTRL; + + if (rs485->flags & SER_RS485_RTS_ON_SEND) { + rs485_ctrl_reg |= LPC18XX_UART_RS485CTRL_OINV; + rs485->flags &= ~SER_RS485_RTS_AFTER_SEND; + } else { + rs485->flags |= SER_RS485_RTS_AFTER_SEND; + } + } + + if (rs485->delay_rts_after_send) { + baud_clk = port->uartclk / up->dl_read(up); + rs485_dly_reg = DIV_ROUND_UP(rs485->delay_rts_after_send + * baud_clk, MSEC_PER_SEC); + + if (rs485_dly_reg > LPC18XX_UART_RS485DLY_MAX) + rs485_dly_reg = LPC18XX_UART_RS485DLY_MAX; + + /* Calculate the resulting delay in ms */ + rs485->delay_rts_after_send = (rs485_dly_reg * MSEC_PER_SEC) + / baud_clk; + } + + /* Delay RTS before send not supported */ + rs485->delay_rts_before_send = 0; + + serial_out(up, LPC18XX_UART_RS485CTRL, rs485_ctrl_reg); + serial_out(up, LPC18XX_UART_RS485DLY, rs485_dly_reg); + + port->rs485 = *rs485; + + return 0; +} + +static void lpc18xx_uart_serial_out(struct uart_port *p, int offset, int value) +{ + /* + * For DMA mode one must ensure that the UART_FCR_DMA_SELECT + * bit is set when FIFO is enabled. Even if DMA is not used + * setting this bit doesn't seem to affect anything. + */ + if (offset == UART_FCR && (value & UART_FCR_ENABLE_FIFO)) + value |= UART_FCR_DMA_SELECT; + + offset = offset << p->regshift; + writel(value, p->membase + offset); +} + +static int lpc18xx_serial_probe(struct platform_device *pdev) +{ + struct lpc18xx_uart_data *data; + struct uart_8250_port uart; + struct resource *res; + int irq, ret; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "irq not found"); + return irq; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "memory resource not found"); + return -EINVAL; + } + + memset(&uart, 0, sizeof(uart)); + + uart.port.membase = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!uart.port.membase) + return -ENOMEM; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->clk_uart = devm_clk_get(&pdev->dev, "uartclk"); + if (IS_ERR(data->clk_uart)) { + dev_err(&pdev->dev, "uart clock not found\n"); + return PTR_ERR(data->clk_uart); + } + + data->clk_reg = devm_clk_get(&pdev->dev, "reg"); + if (IS_ERR(data->clk_reg)) { + dev_err(&pdev->dev, "reg clock not found\n"); + return PTR_ERR(data->clk_reg); + } + + ret = clk_prepare_enable(data->clk_reg); + if (ret) { + dev_err(&pdev->dev, "unable to enable reg clock\n"); + return ret; + } + + ret = clk_prepare_enable(data->clk_uart); + if (ret) { + dev_err(&pdev->dev, "unable to enable uart clock\n"); + goto dis_clk_reg; + } + + ret = of_alias_get_id(pdev->dev.of_node, "serial"); + if (ret >= 0) + uart.port.line = ret; + + data->dma.rx_param = data; + data->dma.tx_param = data; + + spin_lock_init(&uart.port.lock); + uart.port.dev = &pdev->dev; + uart.port.irq = irq; + uart.port.iotype = UPIO_MEM32; + uart.port.mapbase = res->start; + uart.port.regshift = 2; + uart.port.type = PORT_16550A; + uart.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SKIP_TEST; + uart.port.uartclk = clk_get_rate(data->clk_uart); + uart.port.private_data = data; + uart.port.rs485_config = lpc18xx_rs485_config; + uart.port.serial_out = lpc18xx_uart_serial_out; + + uart.dma = &data->dma; + uart.dma->rxconf.src_maxburst = 1; + uart.dma->txconf.dst_maxburst = 1; + + ret = serial8250_register_8250_port(&uart); + if (ret < 0) { + dev_err(&pdev->dev, "unable to register 8250 port\n"); + goto dis_uart_clk; + } + + data->line = ret; + platform_set_drvdata(pdev, data); + + return 0; + +dis_uart_clk: + clk_disable_unprepare(data->clk_uart); +dis_clk_reg: + clk_disable_unprepare(data->clk_reg); + return ret; +} + +static int lpc18xx_serial_remove(struct platform_device *pdev) +{ + struct lpc18xx_uart_data *data = platform_get_drvdata(pdev); + + serial8250_unregister_port(data->line); + clk_disable_unprepare(data->clk_uart); + clk_disable_unprepare(data->clk_reg); + + return 0; +} + +static const struct of_device_id lpc18xx_serial_match[] = { + { .compatible = "nxp,lpc1850-uart" }, + { }, +}; +MODULE_DEVICE_TABLE(of, lpc18xx_serial_match); + +static struct platform_driver lpc18xx_serial_driver = { + .probe = lpc18xx_serial_probe, + .remove = lpc18xx_serial_remove, + .driver = { + .name = "lpc18xx-uart", + .of_match_table = lpc18xx_serial_match, + }, +}; +module_platform_driver(lpc18xx_serial_driver); + +MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>"); +MODULE_DESCRIPTION("Serial port driver NXP LPC18xx/43xx devices"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c index 7a11fac775c4..78883ca64ddd 100644 --- a/drivers/tty/serial/8250/8250_mtk.c +++ b/drivers/tty/serial/8250/8250_mtk.c @@ -34,6 +34,7 @@ struct mtk8250_data { int line; struct clk *uart_clk; + struct clk *bus_clk; }; static void @@ -115,6 +116,36 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios, tty_termios_encode_baud_rate(termios, baud, baud); } +static int mtk8250_runtime_suspend(struct device *dev) +{ + struct mtk8250_data *data = dev_get_drvdata(dev); + + clk_disable_unprepare(data->uart_clk); + clk_disable_unprepare(data->bus_clk); + + return 0; +} + +static int mtk8250_runtime_resume(struct device *dev) +{ + struct mtk8250_data *data = dev_get_drvdata(dev); + int err; + + err = clk_prepare_enable(data->uart_clk); + if (err) { + dev_warn(dev, "Can't enable clock\n"); + return err; + } + + err = clk_prepare_enable(data->bus_clk); + if (err) { + dev_warn(dev, "Can't enable bus clock\n"); + return err; + } + + return 0; +} + static void mtk8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old) { @@ -130,22 +161,24 @@ mtk8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old) static int mtk8250_probe_of(struct platform_device *pdev, struct uart_port *p, struct mtk8250_data *data) { - int err; - struct device_node *np = pdev->dev.of_node; - - data->uart_clk = of_clk_get(np, 0); + data->uart_clk = devm_clk_get(&pdev->dev, "baud"); if (IS_ERR(data->uart_clk)) { - dev_warn(&pdev->dev, "Can't get timer clock\n"); - return PTR_ERR(data->uart_clk); + /* + * For compatibility with older device trees try unnamed + * clk when no baud clk can be found. + */ + data->uart_clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(data->uart_clk)) { + dev_warn(&pdev->dev, "Can't get uart clock\n"); + return PTR_ERR(data->uart_clk); + } + + return 0; } - err = clk_prepare_enable(data->uart_clk); - if (err) { - dev_warn(&pdev->dev, "Can't prepare clock\n"); - clk_put(data->uart_clk); - return err; - } - p->uartclk = clk_get_rate(data->uart_clk); + data->bus_clk = devm_clk_get(&pdev->dev, "bus"); + if (IS_ERR(data->bus_clk)) + return PTR_ERR(data->bus_clk); return 0; } @@ -190,19 +223,24 @@ static int mtk8250_probe(struct platform_device *pdev) uart.port.regshift = 2; uart.port.private_data = data; uart.port.set_termios = mtk8250_set_termios; + uart.port.uartclk = clk_get_rate(data->uart_clk); /* Disable Rate Fix function */ writel(0x0, uart.port.membase + (MTK_UART_RATE_FIX << uart.port.regshift)); - data->line = serial8250_register_8250_port(&uart); - if (data->line < 0) - return data->line; - platform_set_drvdata(pdev, data); - pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); + if (!pm_runtime_enabled(&pdev->dev)) { + err = mtk8250_runtime_resume(&pdev->dev); + if (err) + return err; + } + + data->line = serial8250_register_8250_port(&uart); + if (data->line < 0) + return data->line; return 0; } @@ -214,13 +252,13 @@ static int mtk8250_remove(struct platform_device *pdev) pm_runtime_get_sync(&pdev->dev); serial8250_unregister_port(data->line); - if (!IS_ERR(data->uart_clk)) { - clk_disable_unprepare(data->uart_clk); - clk_put(data->uart_clk); - } pm_runtime_disable(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); + + if (!pm_runtime_status_suspended(&pdev->dev)) + mtk8250_runtime_suspend(&pdev->dev); + return 0; } @@ -244,28 +282,6 @@ static int mtk8250_resume(struct device *dev) } #endif /* CONFIG_PM_SLEEP */ -#ifdef CONFIG_PM -static int mtk8250_runtime_suspend(struct device *dev) -{ - struct mtk8250_data *data = dev_get_drvdata(dev); - - if (!IS_ERR(data->uart_clk)) - clk_disable_unprepare(data->uart_clk); - - return 0; -} - -static int mtk8250_runtime_resume(struct device *dev) -{ - struct mtk8250_data *data = dev_get_drvdata(dev); - - if (!IS_ERR(data->uart_clk)) - clk_prepare_enable(data->uart_clk); - - return 0; -} -#endif - static const struct dev_pm_ops mtk8250_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(mtk8250_suspend, mtk8250_resume) SET_RUNTIME_PM_OPS(mtk8250_runtime_suspend, mtk8250_runtime_resume, @@ -289,6 +305,21 @@ static struct platform_driver mtk8250_platform_driver = { }; module_platform_driver(mtk8250_platform_driver); +#ifdef CONFIG_SERIAL_8250_CONSOLE +static int __init early_mtk8250_setup(struct earlycon_device *device, + const char *options) +{ + if (!device->port.membase) + return -ENODEV; + + device->port.iotype = UPIO_MEM32; + + return early_serial8250_setup(device, NULL); +} + +OF_EARLYCON_DECLARE(mtk8250, "mediatek,mt6577-uart", early_mtk8250_setup); +#endif + MODULE_AUTHOR("Matthias Brugger"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Mediatek 8250 serial port driver"); diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index fe6d2e51da09..d75a66c72750 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -11,7 +11,6 @@ #include <linux/io.h> #include <linux/module.h> #include <linux/serial_8250.h> -#include <linux/serial_core.h> #include <linux/serial_reg.h> #include <linux/tty_flip.h> #include <linux/platform_device.h> @@ -23,6 +22,7 @@ #include <linux/pm_runtime.h> #include <linux/console.h> #include <linux/pm_qos.h> +#include <linux/pm_wakeirq.h> #include <linux/dma-mapping.h> #include "8250.h" @@ -99,6 +99,7 @@ struct omap8250_priv { struct pm_qos_request pm_qos_request; struct work_struct qos_work; struct uart_8250_dma omap8250_dma; + spinlock_t rx_dma_lock; }; static u32 uart_read(struct uart_8250_port *up, u32 reg) @@ -552,39 +553,71 @@ static void omap8250_uart_qos_work(struct work_struct *work) pm_qos_update_request(&priv->pm_qos_request, priv->latency); } -static irqreturn_t omap_wake_irq(int irq, void *dev_id) +#ifdef CONFIG_SERIAL_8250_DMA +static int omap_8250_dma_handle_irq(struct uart_port *port); +#endif + +static irqreturn_t omap8250_irq(int irq, void *dev_id) { struct uart_port *port = dev_id; + struct uart_8250_port *up = up_to_u8250p(port); + unsigned int iir; int ret; - ret = port->handle_irq(port); - if (ret) - return IRQ_HANDLED; - return IRQ_NONE; +#ifdef CONFIG_SERIAL_8250_DMA + if (up->dma) { + ret = omap_8250_dma_handle_irq(port); + return IRQ_RETVAL(ret); + } +#endif + + serial8250_rpm_get(up); + iir = serial_port_in(port, UART_IIR); + ret = serial8250_handle_irq(port, iir); + serial8250_rpm_put(up); + + return IRQ_RETVAL(ret); } static int omap_8250_startup(struct uart_port *port) { - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); + struct uart_8250_port *up = up_to_u8250p(port); struct omap8250_priv *priv = port->private_data; - int ret; if (priv->wakeirq) { - ret = request_irq(priv->wakeirq, omap_wake_irq, - port->irqflags, "uart wakeup irq", port); + ret = dev_pm_set_dedicated_wake_irq(port->dev, priv->wakeirq); if (ret) return ret; - disable_irq(priv->wakeirq); } pm_runtime_get_sync(port->dev); - ret = serial8250_do_startup(port); - if (ret) + up->mcr = 0; + serial_out(up, UART_FCR, UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); + + serial_out(up, UART_LCR, UART_LCR_WLEN8); + + up->lsr_saved_flags = 0; + up->msr_saved_flags = 0; + + if (up->dma) { + ret = serial8250_request_dma(up); + if (ret) { + dev_warn_ratelimited(port->dev, + "failed to request DMA\n"); + up->dma = NULL; + } + } + + ret = request_irq(port->irq, omap8250_irq, IRQF_SHARED, + dev_name(port->dev), port); + if (ret < 0) goto err; + up->ier = UART_IER_RLSI | UART_IER_RDI; + serial_out(up, UART_IER, up->ier); + #ifdef CONFIG_PM up->capabilities |= UART_CAP_RPM; #endif @@ -604,15 +637,13 @@ static int omap_8250_startup(struct uart_port *port) err: pm_runtime_mark_last_busy(port->dev); pm_runtime_put_autosuspend(port->dev); - if (priv->wakeirq) - free_irq(priv->wakeirq, port); + dev_pm_clear_wake_irq(port->dev); return ret; } static void omap_8250_shutdown(struct uart_port *port) { - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); + struct uart_8250_port *up = up_to_u8250p(port); struct omap8250_priv *priv = port->private_data; flush_work(&priv->qos_work); @@ -622,13 +653,24 @@ static void omap_8250_shutdown(struct uart_port *port) pm_runtime_get_sync(port->dev); serial_out(up, UART_OMAP_WER, 0); - serial8250_do_shutdown(port); + + up->ier = 0; + serial_out(up, UART_IER, 0); + + if (up->dma) + serial8250_release_dma(up); + + /* + * Disable break condition and FIFOs + */ + if (up->lcr & UART_LCR_SBC) + serial_out(up, UART_LCR, up->lcr & ~UART_LCR_SBC); + serial_out(up, UART_FCR, UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); pm_runtime_mark_last_busy(port->dev); pm_runtime_put_autosuspend(port->dev); - - if (priv->wakeirq) - free_irq(priv->wakeirq, port); + free_irq(port->irq, port); + dev_pm_clear_wake_irq(port->dev); } static void omap_8250_throttle(struct uart_port *port) @@ -670,14 +712,21 @@ static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir); static void __dma_rx_do_complete(struct uart_8250_port *p, bool error) { + struct omap8250_priv *priv = p->port.private_data; struct uart_8250_dma *dma = p->dma; struct tty_port *tty_port = &p->port.state->port; struct dma_tx_state state; int count; + unsigned long flags; dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr, dma->rx_size, DMA_FROM_DEVICE); + spin_lock_irqsave(&priv->rx_dma_lock, flags); + + if (!dma->rx_running) + goto unlock; + dma->rx_running = 0; dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state); dmaengine_terminate_all(dma->rxchan); @@ -686,6 +735,9 @@ static void __dma_rx_do_complete(struct uart_8250_port *p, bool error) tty_insert_flip_string(tty_port, dma->rx_buf, count); p->port.icount.rx += count; +unlock: + spin_unlock_irqrestore(&priv->rx_dma_lock, flags); + if (!error) omap_8250_rx_dma(p, 0); @@ -697,28 +749,45 @@ static void __dma_rx_complete(void *param) __dma_rx_do_complete(param, false); } +static void omap_8250_rx_dma_flush(struct uart_8250_port *p) +{ + struct omap8250_priv *priv = p->port.private_data; + struct uart_8250_dma *dma = p->dma; + unsigned long flags; + + spin_lock_irqsave(&priv->rx_dma_lock, flags); + + if (!dma->rx_running) { + spin_unlock_irqrestore(&priv->rx_dma_lock, flags); + return; + } + + dmaengine_pause(dma->rxchan); + + spin_unlock_irqrestore(&priv->rx_dma_lock, flags); + + __dma_rx_do_complete(p, true); +} + static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir) { + struct omap8250_priv *priv = p->port.private_data; struct uart_8250_dma *dma = p->dma; + int err = 0; struct dma_async_tx_descriptor *desc; + unsigned long flags; switch (iir & 0x3f) { case UART_IIR_RLSI: /* 8250_core handles errors and break interrupts */ - if (dma->rx_running) { - dmaengine_pause(dma->rxchan); - __dma_rx_do_complete(p, true); - } + omap_8250_rx_dma_flush(p); return -EIO; case UART_IIR_RX_TIMEOUT: /* * If RCVR FIFO trigger level was not reached, complete the * transfer and let 8250_core copy the remaining data. */ - if (dma->rx_running) { - dmaengine_pause(dma->rxchan); - __dma_rx_do_complete(p, true); - } + omap_8250_rx_dma_flush(p); return -ETIMEDOUT; case UART_IIR_RDI: /* @@ -730,24 +799,25 @@ static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir) * the DMA won't do anything soon so we have to cancel the DMA * transfer and purge the FIFO manually. */ - if (dma->rx_running) { - dmaengine_pause(dma->rxchan); - __dma_rx_do_complete(p, true); - } + omap_8250_rx_dma_flush(p); return -ETIMEDOUT; default: break; } + spin_lock_irqsave(&priv->rx_dma_lock, flags); + if (dma->rx_running) - return 0; + goto out; desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr, dma->rx_size, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) - return -EBUSY; + if (!desc) { + err = -EBUSY; + goto out; + } dma->rx_running = 1; desc->callback = __dma_rx_complete; @@ -759,7 +829,9 @@ static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir) dma->rx_size, DMA_FROM_DEVICE); dma_async_issue_pending(dma->rxchan); - return 0; +out: + spin_unlock_irqrestore(&priv->rx_dma_lock, flags); + return err; } static int omap_8250_tx_dma(struct uart_8250_port *p); @@ -975,6 +1047,13 @@ static inline int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir) } #endif +static int omap8250_no_handle_irq(struct uart_port *port) +{ + /* IRQ has not been requested but handling irq? */ + WARN_ONCE(1, "Unexpected irq handling before port startup\n"); + return 0; +} + static int omap8250_probe(struct platform_device *pdev) { struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1066,6 +1145,8 @@ static int omap8250_probe(struct platform_device *pdev) priv->latency); INIT_WORK(&priv->qos_work, omap8250_uart_qos_work); + spin_lock_init(&priv->rx_dma_lock); + device_init_wakeup(&pdev->dev, true); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, -1); @@ -1076,6 +1157,7 @@ static int omap8250_probe(struct platform_device *pdev) pm_runtime_get_sync(&pdev->dev); omap_serial_fill_features_erratas(&up, priv); + up.port.handle_irq = omap8250_no_handle_irq; #ifdef CONFIG_SERIAL_8250_DMA if (pdev->dev.of_node) { /* @@ -1089,7 +1171,6 @@ static int omap8250_probe(struct platform_device *pdev) ret = of_property_count_strings(pdev->dev.of_node, "dma-names"); if (ret == 2) { up.dma = &priv->omap8250_dma; - up.port.handle_irq = omap_8250_dma_handle_irq; priv->omap8250_dma.fn = the_no_dma_filter_fn; priv->omap8250_dma.tx_dma = omap_8250_tx_dma; priv->omap8250_dma.rx_dma = omap_8250_rx_dma; @@ -1130,31 +1211,6 @@ static int omap8250_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM - -static inline void omap8250_enable_wakeirq(struct omap8250_priv *priv, - bool enable) -{ - if (!priv->wakeirq) - return; - - if (enable) - enable_irq(priv->wakeirq); - else - disable_irq_nosync(priv->wakeirq); -} - -static void omap8250_enable_wakeup(struct omap8250_priv *priv, - bool enable) -{ - if (enable == priv->wakeups_enabled) - return; - - omap8250_enable_wakeirq(priv, enable); - priv->wakeups_enabled = enable; -} -#endif - #ifdef CONFIG_PM_SLEEP static int omap8250_prepare(struct device *dev) { @@ -1181,11 +1237,6 @@ static int omap8250_suspend(struct device *dev) serial8250_suspend_port(priv->line); flush_work(&priv->qos_work); - - if (device_may_wakeup(dev)) - omap8250_enable_wakeup(priv, true); - else - omap8250_enable_wakeup(priv, false); return 0; } @@ -1193,9 +1244,6 @@ static int omap8250_resume(struct device *dev) { struct omap8250_priv *priv = dev_get_drvdata(dev); - if (device_may_wakeup(dev)) - omap8250_enable_wakeup(priv, false); - serial8250_resume_port(priv->line); return 0; } @@ -1237,7 +1285,6 @@ static int omap8250_runtime_suspend(struct device *dev) return -EBUSY; } - omap8250_enable_wakeup(priv, true); if (up->dma) omap_8250_rx_dma(up, UART_IIR_RX_TIMEOUT); @@ -1258,7 +1305,6 @@ static int omap8250_runtime_resume(struct device *dev) return 0; up = serial8250_get_port(priv->line); - omap8250_enable_wakeup(priv, false); loss_cntx = omap8250_lost_context(up); if (loss_cntx) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 892eb32cdef4..e55f18b93fe7 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -21,12 +21,14 @@ #include <linux/serial_core.h> #include <linux/8250_pci.h> #include <linux/bitops.h> +#include <linux/rational.h> #include <asm/byteorder.h> #include <asm/io.h> #include <linux/dmaengine.h> #include <linux/platform_data/dma-dw.h> +#include <linux/platform_data/dma-hsu.h> #include "8250.h" @@ -1392,45 +1394,22 @@ byt_set_termios(struct uart_port *p, struct ktermios *termios, struct ktermios *old) { unsigned int baud = tty_termios_baud_rate(termios); - unsigned int m, n; + unsigned long fref = 100000000, fuart = baud * 16; + unsigned long w = BIT(15) - 1; + unsigned long m, n; u32 reg; + /* Get Fuart closer to Fref */ + fuart *= rounddown_pow_of_two(fref / fuart); + /* * For baud rates 0.5M, 1M, 1.5M, 2M, 2.5M, 3M, 3.5M and 4M the * dividers must be adjusted. * * uartclk = (m / n) * 100 MHz, where m <= n */ - switch (baud) { - case 500000: - case 1000000: - case 2000000: - case 4000000: - m = 64; - n = 100; - p->uartclk = 64000000; - break; - case 3500000: - m = 56; - n = 100; - p->uartclk = 56000000; - break; - case 1500000: - case 3000000: - m = 48; - n = 100; - p->uartclk = 48000000; - break; - case 2500000: - m = 40; - n = 100; - p->uartclk = 40000000; - break; - default: - m = 2304; - n = 3125; - p->uartclk = 73728000; - } + rational_best_approximation(fuart, fref, w, w, &m, &n); + p->uartclk = fuart; /* Reset the clock */ reg = (m << BYT_PRV_CLK_M_VAL_SHIFT) | (n << BYT_PRV_CLK_N_VAL_SHIFT); @@ -1525,6 +1504,167 @@ byt_serial_setup(struct serial_private *priv, return ret; } +#define INTEL_MID_UART_PS 0x30 +#define INTEL_MID_UART_MUL 0x34 +#define INTEL_MID_UART_DIV 0x38 + +static void intel_mid_set_termios(struct uart_port *p, + struct ktermios *termios, + struct ktermios *old, + unsigned long fref) +{ + unsigned int baud = tty_termios_baud_rate(termios); + unsigned short ps = 16; + unsigned long fuart = baud * ps; + unsigned long w = BIT(24) - 1; + unsigned long mul, div; + + if (fref < fuart) { + /* Find prescaler value that satisfies Fuart < Fref */ + if (fref > baud) + ps = fref / baud; /* baud rate too high */ + else + ps = 1; /* PLL case */ + fuart = baud * ps; + } else { + /* Get Fuart closer to Fref */ + fuart *= rounddown_pow_of_two(fref / fuart); + } + + rational_best_approximation(fuart, fref, w, w, &mul, &div); + p->uartclk = fuart * 16 / ps; /* core uses ps = 16 always */ + + writel(ps, p->membase + INTEL_MID_UART_PS); /* set PS */ + writel(mul, p->membase + INTEL_MID_UART_MUL); /* set MUL */ + writel(div, p->membase + INTEL_MID_UART_DIV); + + serial8250_do_set_termios(p, termios, old); +} + +static void intel_mid_set_termios_38_4M(struct uart_port *p, + struct ktermios *termios, + struct ktermios *old) +{ + intel_mid_set_termios(p, termios, old, 38400000); +} + +static void intel_mid_set_termios_50M(struct uart_port *p, + struct ktermios *termios, + struct ktermios *old) +{ + /* + * The uart clk is 50Mhz, and the baud rate come from: + * baud = 50M * MUL / (DIV * PS * DLAB) + */ + intel_mid_set_termios(p, termios, old, 50000000); +} + +static bool intel_mid_dma_filter(struct dma_chan *chan, void *param) +{ + struct hsu_dma_slave *s = param; + + if (s->dma_dev != chan->device->dev || s->chan_id != chan->chan_id) + return false; + + chan->private = s; + return true; +} + +static int intel_mid_serial_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx, + int index, struct pci_dev *dma_dev) +{ + struct device *dev = port->port.dev; + struct uart_8250_dma *dma; + struct hsu_dma_slave *tx_param, *rx_param; + + dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL); + if (!dma) + return -ENOMEM; + + tx_param = devm_kzalloc(dev, sizeof(*tx_param), GFP_KERNEL); + if (!tx_param) + return -ENOMEM; + + rx_param = devm_kzalloc(dev, sizeof(*rx_param), GFP_KERNEL); + if (!rx_param) + return -ENOMEM; + + rx_param->chan_id = index * 2 + 1; + tx_param->chan_id = index * 2; + + dma->rxconf.src_maxburst = 64; + dma->txconf.dst_maxburst = 64; + + rx_param->dma_dev = &dma_dev->dev; + tx_param->dma_dev = &dma_dev->dev; + + dma->fn = intel_mid_dma_filter; + dma->rx_param = rx_param; + dma->tx_param = tx_param; + + port->port.type = PORT_16750; + port->port.flags |= UPF_FIXED_PORT | UPF_FIXED_TYPE; + port->dma = dma; + + return pci_default_setup(priv, board, port, idx); +} + +#define PCI_DEVICE_ID_INTEL_PNW_UART1 0x081b +#define PCI_DEVICE_ID_INTEL_PNW_UART2 0x081c +#define PCI_DEVICE_ID_INTEL_PNW_UART3 0x081d + +static int pnw_serial_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) +{ + struct pci_dev *pdev = priv->dev; + struct pci_dev *dma_dev; + int index; + + switch (pdev->device) { + case PCI_DEVICE_ID_INTEL_PNW_UART1: + index = 0; + break; + case PCI_DEVICE_ID_INTEL_PNW_UART2: + index = 1; + break; + case PCI_DEVICE_ID_INTEL_PNW_UART3: + index = 2; + break; + default: + return -EINVAL; + } + + dma_dev = pci_get_slot(pdev->bus, PCI_DEVFN(PCI_SLOT(pdev->devfn), 3)); + + port->port.set_termios = intel_mid_set_termios_50M; + + return intel_mid_serial_setup(priv, board, port, idx, index, dma_dev); +} + +#define PCI_DEVICE_ID_INTEL_TNG_UART 0x1191 + +static int tng_serial_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) +{ + struct pci_dev *pdev = priv->dev; + struct pci_dev *dma_dev; + int index = PCI_FUNC(pdev->devfn); + + /* Currently no support for HSU port0 */ + if (index-- == 0) + return -ENODEV; + + dma_dev = pci_get_slot(pdev->bus, PCI_DEVFN(5, 0)); + + port->port.set_termios = intel_mid_set_termios_38_4M; + + return intel_mid_serial_setup(priv, board, port, idx, index, dma_dev); +} + static int pci_omegapci_setup(struct serial_private *priv, const struct pciserial_board *board, @@ -1550,95 +1690,71 @@ static int pci_fintek_setup(struct serial_private *priv, struct uart_8250_port *port, int idx) { struct pci_dev *pdev = priv->dev; - unsigned long base; - unsigned long iobase; - unsigned long ciobase = 0; u8 config_base; + u16 iobase; + + config_base = 0x40 + 0x08 * idx; + + /* Get the io address from configuration space */ + pci_read_config_word(pdev, config_base + 4, &iobase); + + dev_dbg(&pdev->dev, "%s: idx=%d iobase=0x%x", __func__, idx, iobase); + + port->port.iotype = UPIO_PORT; + port->port.iobase = iobase; + + return 0; +} + +static int pci_fintek_init(struct pci_dev *dev) +{ + unsigned long iobase; + u32 max_port, i; u32 bar_data[3]; + u8 config_base; - /* - * Find each UARTs offset in PCI configuraion space - */ - switch (idx) { - case 0: - config_base = 0x40; - break; - case 1: - config_base = 0x48; - break; - case 2: - config_base = 0x50; - break; - case 3: - config_base = 0x58; - break; - case 4: - config_base = 0x60; - break; - case 5: - config_base = 0x68; - break; - case 6: - config_base = 0x70; - break; - case 7: - config_base = 0x78; - break; - case 8: - config_base = 0x80; - break; - case 9: - config_base = 0x88; + switch (dev->device) { + case 0x1104: /* 4 ports */ + case 0x1108: /* 8 ports */ + max_port = dev->device & 0xff; break; - case 10: - config_base = 0x90; - break; - case 11: - config_base = 0x98; + case 0x1112: /* 12 ports */ + max_port = 12; break; default: - /* Unknown number of ports, get out of here */ return -EINVAL; } - if (idx < 4) { - base = pci_resource_start(priv->dev, 3); - ciobase = (int)(base + (0x8 * idx)); - } - /* Get the io address dispatch from the BIOS */ - pci_read_config_dword(pdev, 0x24, &bar_data[0]); - pci_read_config_dword(pdev, 0x20, &bar_data[1]); - pci_read_config_dword(pdev, 0x1c, &bar_data[2]); + pci_read_config_dword(dev, 0x24, &bar_data[0]); + pci_read_config_dword(dev, 0x20, &bar_data[1]); + pci_read_config_dword(dev, 0x1c, &bar_data[2]); - /* Calculate Real IO Port */ - iobase = (bar_data[idx/4] & 0xffffffe0) + (idx % 4) * 8; + for (i = 0; i < max_port; ++i) { + /* UART0 configuration offset start from 0x40 */ + config_base = 0x40 + 0x08 * i; - dev_dbg(&pdev->dev, "%s: idx=%d iobase=0x%lx ciobase=0x%lx config_base=0x%2x\n", - __func__, idx, iobase, ciobase, config_base); + /* Calculate Real IO Port */ + iobase = (bar_data[i / 4] & 0xffffffe0) + (i % 4) * 8; - /* Enable UART I/O port */ - pci_write_config_byte(pdev, config_base + 0x00, 0x01); + /* Enable UART I/O port */ + pci_write_config_byte(dev, config_base + 0x00, 0x01); - /* Select 128-byte FIFO and 8x FIFO threshold */ - pci_write_config_byte(pdev, config_base + 0x01, 0x33); + /* Select 128-byte FIFO and 8x FIFO threshold */ + pci_write_config_byte(dev, config_base + 0x01, 0x33); - /* LSB UART */ - pci_write_config_byte(pdev, config_base + 0x04, (u8)(iobase & 0xff)); + /* LSB UART */ + pci_write_config_byte(dev, config_base + 0x04, + (u8)(iobase & 0xff)); - /* MSB UART */ - pci_write_config_byte(pdev, config_base + 0x05, (u8)((iobase & 0xff00) >> 8)); + /* MSB UART */ + pci_write_config_byte(dev, config_base + 0x05, + (u8)((iobase & 0xff00) >> 8)); - /* irq number, this usually fails, but the spec says to do it anyway. */ - pci_write_config_byte(pdev, config_base + 0x06, pdev->irq); - - port->port.iotype = UPIO_PORT; - port->port.iobase = iobase; - port->port.mapbase = 0; - port->port.membase = NULL; - port->port.regshift = 0; + pci_write_config_byte(dev, config_base + 0x06, dev->irq); + } - return 0; + return max_port; } static int skip_tx_en_setup(struct serial_private *priv, @@ -1707,6 +1823,9 @@ static int pci_eg20t_init(struct pci_dev *dev) #endif } +#define PCI_DEVICE_ID_EXAR_XR17V4358 0x4358 +#define PCI_DEVICE_ID_EXAR_XR17V8358 0x8358 + static int pci_xr17c154_setup(struct serial_private *priv, const struct pciserial_board *board, @@ -1716,6 +1835,15 @@ pci_xr17c154_setup(struct serial_private *priv, return pci_default_setup(priv, board, port, idx); } +static inline int +xr17v35x_has_slave(struct serial_private *priv) +{ + const int dev_id = priv->dev->device; + + return ((dev_id == PCI_DEVICE_ID_EXAR_XR17V4358) || + (dev_id == PCI_DEVICE_ID_EXAR_XR17V8358)); +} + static int pci_xr17v35x_setup(struct serial_private *priv, const struct pciserial_board *board, @@ -1730,6 +1858,13 @@ pci_xr17v35x_setup(struct serial_private *priv, port->port.flags |= UPF_EXAR_EFR; /* + * Setup the uart clock for the devices on expansion slot to + * half the clock speed of the main chip (which is 125MHz) + */ + if (xr17v35x_has_slave(priv) && idx >= 8) + port->port.uartclk = (7812500 * 16 / 2); + + /* * Setup Multipurpose Input/Output pins. */ if (idx == 0) { @@ -1989,6 +2124,34 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { }, { .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_PNW_UART1, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pnw_serial_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_PNW_UART2, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pnw_serial_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_PNW_UART3, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pnw_serial_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_TNG_UART, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = tng_serial_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, .device = PCI_DEVICE_ID_INTEL_BSW_UART1, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, @@ -2376,6 +2539,20 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .setup = pci_xr17v35x_setup, }, + { + .vendor = PCI_VENDOR_ID_EXAR, + .device = PCI_DEVICE_ID_EXAR_XR17V4358, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_xr17v35x_setup, + }, + { + .vendor = PCI_VENDOR_ID_EXAR, + .device = PCI_DEVICE_ID_EXAR_XR17V8358, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_xr17v35x_setup, + }, /* * Xircom cards */ @@ -2653,6 +2830,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .setup = pci_fintek_setup, + .init = pci_fintek_init, }, { .vendor = 0x1c29, @@ -2660,6 +2838,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .setup = pci_fintek_setup, + .init = pci_fintek_init, }, { .vendor = 0x1c29, @@ -2667,6 +2846,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .setup = pci_fintek_setup, + .init = pci_fintek_init, }, /* @@ -2852,6 +3032,8 @@ enum pci_board_num_t { pbn_exar_XR17V352, pbn_exar_XR17V354, pbn_exar_XR17V358, + pbn_exar_XR17V4358, + pbn_exar_XR17V8358, pbn_exar_ibm_saturn, pbn_pasemi_1682M, pbn_ni8430_2, @@ -2864,6 +3046,8 @@ enum pci_board_num_t { pbn_ADDIDATA_PCIe_8_3906250, pbn_ce4100_1_115200, pbn_byt, + pbn_pnw, + pbn_tng, pbn_qrk, pbn_omegapci, pbn_NETMOS9900_2s_115200, @@ -3536,6 +3720,22 @@ static struct pciserial_board pci_boards[] = { .reg_shift = 0, .first_offset = 0, }, + [pbn_exar_XR17V4358] = { + .flags = FL_BASE0, + .num_ports = 12, + .base_baud = 7812500, + .uart_offset = 0x400, + .reg_shift = 0, + .first_offset = 0, + }, + [pbn_exar_XR17V8358] = { + .flags = FL_BASE0, + .num_ports = 16, + .base_baud = 7812500, + .uart_offset = 0x400, + .reg_shift = 0, + .first_offset = 0, + }, [pbn_exar_ibm_saturn] = { .flags = FL_BASE0, .num_ports = 1, @@ -3630,6 +3830,16 @@ static struct pciserial_board pci_boards[] = { .uart_offset = 0x80, .reg_shift = 2, }, + [pbn_pnw] = { + .flags = FL_BASE0, + .num_ports = 1, + .base_baud = 115200, + }, + [pbn_tng] = { + .flags = FL_BASE0, + .num_ports = 1, + .base_baud = 1843200, + }, [pbn_qrk] = { .flags = FL_BASE0, .num_ports = 1, @@ -4006,41 +4216,41 @@ static void pciserial_remove_one(struct pci_dev *dev) pci_disable_device(dev); } -#ifdef CONFIG_PM -static int pciserial_suspend_one(struct pci_dev *dev, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int pciserial_suspend_one(struct device *dev) { - struct serial_private *priv = pci_get_drvdata(dev); + struct pci_dev *pdev = to_pci_dev(dev); + struct serial_private *priv = pci_get_drvdata(pdev); if (priv) pciserial_suspend_ports(priv); - pci_save_state(dev); - pci_set_power_state(dev, pci_choose_state(dev, state)); return 0; } -static int pciserial_resume_one(struct pci_dev *dev) +static int pciserial_resume_one(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); + struct serial_private *priv = pci_get_drvdata(pdev); int err; - struct serial_private *priv = pci_get_drvdata(dev); - - pci_set_power_state(dev, PCI_D0); - pci_restore_state(dev); if (priv) { /* * The device may have been disabled. Re-enable it. */ - err = pci_enable_device(dev); + err = pci_enable_device(pdev); /* FIXME: We cannot simply error out here */ if (err) - dev_err(&dev->dev, "Unable to re-enable ports, trying to continue.\n"); + dev_err(dev, "Unable to re-enable ports, trying to continue.\n"); pciserial_resume_ports(priv); } return 0; } #endif +static SIMPLE_DEV_PM_OPS(pciserial_pm_ops, pciserial_suspend_one, + pciserial_resume_one); + static struct pci_device_id serial_pci_tbl[] = { /* Advantech use PCI_DEVICE_ID_ADVANTECH_PCI3620 (0x3620) as 'PCI_SUBVENDOR_ID' */ { PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3620, @@ -4921,7 +5131,7 @@ static struct pci_device_id serial_pci_tbl[] = { 0, 0, pbn_exar_XR17C158 }, /* - * Exar Corp. XR17V35[248] Dual/Quad/Octal PCIe UARTs + * Exar Corp. XR17V[48]35[248] Dual/Quad/Octal/Hexa PCIe UARTs */ { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17V352, PCI_ANY_ID, PCI_ANY_ID, @@ -4935,7 +5145,14 @@ static struct pci_device_id serial_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_exar_XR17V358 }, - + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17V4358, + PCI_ANY_ID, PCI_ANY_ID, + 0, + 0, pbn_exar_XR17V4358 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17V8358, + PCI_ANY_ID, PCI_ANY_ID, + 0, + 0, pbn_exar_XR17V8358 }, /* * Topic TP560 Data/Fax/Voice 56k modem (reported by Evan Clarke) */ @@ -5363,6 +5580,26 @@ static struct pci_device_id serial_pci_tbl[] = { pbn_byt }, /* + * Intel Penwell + */ + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PNW_UART1, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_pnw}, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PNW_UART2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_pnw}, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PNW_UART3, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_pnw}, + + /* + * Intel Tangier + */ + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TNG_UART, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_tng}, + + /* * Intel Quark x1000 */ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_QRK_UART, @@ -5510,10 +5747,9 @@ static struct pci_driver serial_pci_driver = { .name = "serial", .probe = pciserial_init_one, .remove = pciserial_remove_one, -#ifdef CONFIG_PM - .suspend = pciserial_suspend_one, - .resume = pciserial_resume_one, -#endif + .driver = { + .pm = &pciserial_pm_ops, + }, .id_table = serial_pci_tbl, .err_handler = &serial8250_err_handler, }; diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c new file mode 100644 index 000000000000..7d79425c2b09 --- /dev/null +++ b/drivers/tty/serial/8250/8250_uniphier.c @@ -0,0 +1,257 @@ +/* + * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> + +#include "8250.h" + +/* Most (but not all) of UniPhier UART devices have 64-depth FIFO. */ +#define UNIPHIER_UART_DEFAULT_FIFO_SIZE 64 + +#define UNIPHIER_UART_CHAR_FCR 3 /* Character / FIFO Control Register */ +#define UNIPHIER_UART_LCR_MCR 4 /* Line/Modem Control Register */ +#define UNIPHIER_UART_LCR_SHIFT 8 +#define UNIPHIER_UART_DLR 9 /* Divisor Latch Register */ + +struct uniphier8250_priv { + int line; + struct clk *clk; + spinlock_t atomic_write_lock; +}; + +/* + * The register map is slightly different from that of 8250. + * IO callbacks must be overridden for correct access to FCR, LCR, and MCR. + */ +static unsigned int uniphier_serial_in(struct uart_port *p, int offset) +{ + unsigned int valshift = 0; + + switch (offset) { + case UART_LCR: + valshift = UNIPHIER_UART_LCR_SHIFT; + /* fall through */ + case UART_MCR: + offset = UNIPHIER_UART_LCR_MCR; + break; + default: + break; + } + + offset <<= p->regshift; + + /* + * The return value must be masked with 0xff because LCR and MCR reside + * in the same register that must be accessed by 32-bit write/read. + * 8 or 16 bit access to this hardware result in unexpected behavior. + */ + return (readl(p->membase + offset) >> valshift) & 0xff; +} + +static void uniphier_serial_out(struct uart_port *p, int offset, int value) +{ + unsigned int valshift = 0; + bool normal = false; + + switch (offset) { + case UART_FCR: + offset = UNIPHIER_UART_CHAR_FCR; + break; + case UART_LCR: + valshift = UNIPHIER_UART_LCR_SHIFT; + /* Divisor latch access bit does not exist. */ + value &= ~(UART_LCR_DLAB << valshift); + /* fall through */ + case UART_MCR: + offset = UNIPHIER_UART_LCR_MCR; + break; + default: + normal = true; + break; + } + + offset <<= p->regshift; + + if (normal) { + writel(value, p->membase + offset); + } else { + /* + * Special case: two registers share the same address that + * must be 32-bit accessed. As this is not longer atomic safe, + * take a lock just in case. + */ + struct uniphier8250_priv *priv = p->private_data; + unsigned long flags; + u32 tmp; + + spin_lock_irqsave(&priv->atomic_write_lock, flags); + tmp = readl(p->membase + offset); + tmp &= ~(0xff << valshift); + tmp |= value << valshift; + writel(tmp, p->membase + offset); + spin_unlock_irqrestore(&priv->atomic_write_lock, flags); + } +} + +/* + * This hardware does not have the divisor latch access bit. + * The divisor latch register exists at different address. + * Override dl_read/write callbacks. + */ +static int uniphier_serial_dl_read(struct uart_8250_port *up) +{ + return readl(up->port.membase + UNIPHIER_UART_DLR); +} + +static void uniphier_serial_dl_write(struct uart_8250_port *up, int value) +{ + writel(value, up->port.membase + UNIPHIER_UART_DLR); +} + +static int uniphier_of_serial_setup(struct device *dev, struct uart_port *port, + struct uniphier8250_priv *priv) +{ + int ret; + u32 prop; + struct device_node *np = dev->of_node; + + ret = of_alias_get_id(np, "serial"); + if (ret < 0) { + dev_err(dev, "failed to get alias id\n"); + return ret; + } + port->line = priv->line = ret; + + /* Get clk rate through clk driver */ + priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) { + dev_err(dev, "failed to get clock\n"); + return PTR_ERR(priv->clk); + } + + ret = clk_prepare_enable(priv->clk); + if (ret < 0) + return ret; + + port->uartclk = clk_get_rate(priv->clk); + + /* Check for fifo size */ + if (of_property_read_u32(np, "fifo-size", &prop) == 0) + port->fifosize = prop; + else + port->fifosize = UNIPHIER_UART_DEFAULT_FIFO_SIZE; + + return 0; +} + +static int uniphier_uart_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct uart_8250_port up; + struct uniphier8250_priv *priv; + struct resource *regs; + void __iomem *membase; + int irq; + int ret; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) { + dev_err(dev, "failed to get memory resource"); + return -EINVAL; + } + + membase = devm_ioremap(dev, regs->start, resource_size(regs)); + if (!membase) + return -ENOMEM; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "failed to get IRQ number"); + return irq; + } + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + memset(&up, 0, sizeof(up)); + + ret = uniphier_of_serial_setup(dev, &up.port, priv); + if (ret < 0) + return ret; + + spin_lock_init(&priv->atomic_write_lock); + + up.port.dev = dev; + up.port.private_data = priv; + up.port.mapbase = regs->start; + up.port.mapsize = resource_size(regs); + up.port.membase = membase; + up.port.irq = irq; + + up.port.type = PORT_16550A; + up.port.iotype = UPIO_MEM32; + up.port.regshift = 2; + up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE; + up.capabilities = UART_CAP_FIFO; + + up.port.serial_in = uniphier_serial_in; + up.port.serial_out = uniphier_serial_out; + up.dl_read = uniphier_serial_dl_read; + up.dl_write = uniphier_serial_dl_write; + + ret = serial8250_register_8250_port(&up); + if (ret < 0) { + dev_err(dev, "failed to register 8250 port\n"); + return ret; + } + + platform_set_drvdata(pdev, priv); + + return 0; +} + +static int uniphier_uart_remove(struct platform_device *pdev) +{ + struct uniphier8250_priv *priv = platform_get_drvdata(pdev); + + serial8250_unregister_port(priv->line); + clk_disable_unprepare(priv->clk); + + return 0; +} + +static const struct of_device_id uniphier_uart_match[] = { + { .compatible = "socionext,uniphier-uart" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, uniphier_uart_match); + +static struct platform_driver uniphier_uart_platform_driver = { + .probe = uniphier_uart_probe, + .remove = uniphier_uart_remove, + .driver = { + .name = "uniphier-uart", + .of_match_table = uniphier_uart_match, + }, +}; +module_platform_driver(uniphier_uart_platform_driver); + +MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>"); +MODULE_DESCRIPTION("UniPhier UART driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index 6f7f2d753def..e1de1181b322 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -108,6 +108,7 @@ config SERIAL_8250_PCI tristate "8250/16550 PCI device support" if EXPERT depends on SERIAL_8250 && PCI default SERIAL_8250 + select RATIONAL help This builds standard PCI serial support. You may be able to disable this feature if you only need legacy serial support. @@ -335,9 +336,33 @@ config SERIAL_8250_FINTEK LPC to 4 UART. This device has some RS485 functionality not available through the PNP driver. If unsure, say N. +config SERIAL_8250_LPC18XX + bool "NXP LPC18xx/43xx serial port support" + depends on SERIAL_8250 && OF && (ARCH_LPC18XX || COMPILE_TEST) + default ARCH_LPC18XX + help + If you have a LPC18xx/43xx based board and want to use the + serial port, say Y to this option. If unsure, say Y. + config SERIAL_8250_MT6577 bool "Mediatek serial port support" depends on SERIAL_8250 && ARCH_MEDIATEK help If you have a Mediatek based board and want to use the serial port, say Y to this option. If unsure, say N. + +config SERIAL_8250_UNIPHIER + tristate "Support for UniPhier on-chip UART" + depends on SERIAL_8250 && ARCH_UNIPHIER + help + If you have a UniPhier based board and want to use the on-chip + serial ports, say Y to this option. If unsure, say N. + +config SERIAL_8250_INGENIC + bool "Support for Ingenic SoC serial ports" + depends on SERIAL_8250_CONSOLE && OF_FLATTREE + select LIBFDT + select SERIAL_EARLYCON + help + If you have a system using an Ingenic SoC and wish to make use of + its UARTs, say Y to this option. If unsure, say N. diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile index 31e7cdc6865c..706295913c34 100644 --- a/drivers/tty/serial/8250/Makefile +++ b/drivers/tty/serial/8250/Makefile @@ -22,4 +22,9 @@ obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o obj-$(CONFIG_SERIAL_8250_OMAP) += 8250_omap.o obj-$(CONFIG_SERIAL_8250_FINTEK) += 8250_fintek.o +obj-$(CONFIG_SERIAL_8250_LPC18XX) += 8250_lpc18xx.o obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o +obj-$(CONFIG_SERIAL_8250_UNIPHIER) += 8250_uniphier.o +obj-$(CONFIG_SERIAL_8250_INGENIC) += 8250_ingenic.o + +CFLAGS_8250_ingenic.o += -I$(srctree)/scripts/dtc/libfdt diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index d2501f01cd03..76e65b714471 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -20,7 +20,7 @@ comment "Non-8250 serial port support" config SERIAL_AMBA_PL010 tristate "ARM AMBA PL010 serial port support" - depends on ARM_AMBA && (BROKEN || !ARCH_VERSATILE) + depends on ARM_AMBA select SERIAL_CORE help This selects the ARM(R) AMBA(R) PrimeCell PL010 UART. If you have @@ -241,7 +241,6 @@ config SERIAL_SAMSUNG tristate "Samsung SoC serial support" depends on PLAT_SAMSUNG || ARCH_EXYNOS select SERIAL_CORE - select SERIAL_EARLYCON help Support for the on-chip UARTs on the Samsung S3C24XX series CPUs, providing /dev/ttySAC0, 1 and 2 (note, some machines may not @@ -277,6 +276,7 @@ config SERIAL_SAMSUNG_CONSOLE bool "Support for console on Samsung SoC serial port" depends on SERIAL_SAMSUNG=y select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON help Allow selection of the S3C24XX on-board serial ports for use as an virtual console. @@ -483,16 +483,6 @@ config SERIAL_SA1100_CONSOLE your boot loader (lilo or loadlin) about how to pass options to the kernel at boot time.) -config SERIAL_MFD_HSU - tristate "Medfield High Speed UART support" - depends on PCI - select SERIAL_CORE - -config SERIAL_MFD_HSU_CONSOLE - bool "Medfile HSU serial console support" - depends on SERIAL_MFD_HSU=y - select SERIAL_CORE_CONSOLE - config SERIAL_BFIN tristate "Blackfin serial port support" depends on BLACKFIN @@ -738,7 +728,7 @@ config SERIAL_IP22_ZILOG_CONSOLE config SERIAL_SH_SCI tristate "SuperH SCI(F) serial port support" - depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST + depends on SUPERH || ARCH_SHMOBILE || H8300 || COMPILE_TEST select SERIAL_CORE config SERIAL_SH_SCI_NR_UARTS @@ -835,7 +825,7 @@ config SERIAL_MCF_CONSOLE config SERIAL_PMACZILOG tristate "Mac or PowerMac z85c30 ESCC support" - depends on (M68K && MAC) || (PPC_OF && PPC_PMAC) + depends on (M68K && MAC) || PPC_PMAC select SERIAL_CORE help This driver supports the Zilog z85C30 serial ports found on @@ -878,7 +868,7 @@ config SERIAL_PMACZILOG_CONSOLE config SERIAL_CPM tristate "CPM SCC/SMC serial port support" - depends on CPM2 || 8xx + depends on CPM2 || CPM1 select SERIAL_CORE help This driver supports the SCC and SMC serial ports on Motorola @@ -1054,7 +1044,7 @@ config SERIAL_SGI_IOC3 config SERIAL_MSM bool "MSM on-chip serial port support" - depends on ARCH_MSM || ARCH_QCOM + depends on ARCH_QCOM select SERIAL_CORE config SERIAL_MSM_CONSOLE @@ -1063,18 +1053,6 @@ config SERIAL_MSM_CONSOLE select SERIAL_CORE_CONSOLE select SERIAL_EARLYCON -config SERIAL_MSM_HS - tristate "MSM UART High Speed: Serial Driver" - depends on ARCH_MSM7X00A || ARCH_MSM7X30 || ARCH_QSD8X50 - select SERIAL_CORE - help - If you have a machine based on MSM family of SoCs, you - can enable its onboard high speed serial port by enabling - this option. - - Choose M here to compile it as a module. The module will be - called msm_serial_hs. - config SERIAL_VT8500 bool "VIA VT8500 on-chip serial port support" depends on ARCH_VT8500 @@ -1153,7 +1131,7 @@ config SERIAL_OMAP_CONSOLE config SERIAL_OF_PLATFORM_NWPSERIAL tristate "NWP serial port driver" - depends on PPC_OF && PPC_DCR + depends on PPC_DCR select SERIAL_OF_PLATFORM select SERIAL_CORE_CONSOLE select SERIAL_CORE @@ -1201,15 +1179,42 @@ config SERIAL_SCCNXP_CONSOLE help Support for console on SCCNXP serial ports. +config SERIAL_SC16IS7XX_CORE + tristate + 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. + tristate "SC16IS7xx serial support" + select SERIAL_CORE + depends on I2C || SPI_MASTER + help + This selects support for SC16IS7xx serial ports. + Supported ICs are SC16IS740, SC16IS741, SC16IS750, SC16IS752, + SC16IS760 and SC16IS762. Select supported buses using options below. + +config SERIAL_SC16IS7XX_I2C + bool "SC16IS7xx for I2C interface" + depends on SERIAL_SC16IS7XX + depends on I2C + select SERIAL_SC16IS7XX_CORE if SERIAL_SC16IS7XX + select REGMAP_I2C if I2C + default y + help + Enable SC16IS7xx driver on I2C bus, + If required say y, and say n to i2c if not required, + Enabled by default to support oldconfig. + You must select at least one bus for the driver to be built. + +config SERIAL_SC16IS7XX_SPI + bool "SC16IS7xx for spi interface" + depends on SERIAL_SC16IS7XX + depends on SPI_MASTER + select SERIAL_SC16IS7XX_CORE if SERIAL_SC16IS7XX + select REGMAP_SPI if SPI_MASTER + help + Enable SC16IS7xx driver on SPI bus, + If required say y, and say n to spi if not required, + This is additional support to exsisting driver. + You must select at least one bus for the driver to be built. config SERIAL_BFIN_SPORT tristate "Blackfin SPORT emulate UART" @@ -1371,7 +1376,7 @@ config SERIAL_ALTERA_UART_CONSOLE config SERIAL_IFX6X60 tristate "SPI protocol driver for Infineon 6x60 modem (EXPERIMENTAL)" - depends on GPIOLIB && SPI + depends on GPIOLIB && SPI && HAS_DMA help Support for the IFX6x60 modem devices on Intel MID platforms. @@ -1400,14 +1405,6 @@ config SERIAL_PCH_UART_CONSOLE (the system console is the device which receives all kernel messages and warnings and which allows logins in single user mode). -config SERIAL_MSM_SMD - bool "Enable tty device interface for some SMD ports" - default n - depends on MSM_SMD - help - Enables userspace clients to read and write to some streaming SMD - ports via tty device interface for MSM chipset. - config SERIAL_MXS_AUART depends on ARCH_MXS tristate "MXS AUART support" @@ -1611,6 +1608,23 @@ config SERIAL_SPRD_CONSOLE with "earlycon" on the kernel command line. The console is enabled when early_param is processed. +config SERIAL_STM32 + tristate "STMicroelectronics STM32 serial port support" + select SERIAL_CORE + depends on ARM || COMPILE_TEST + help + This driver is for the on-chip Serial Controller on + STMicroelectronics STM32 MCUs. + USART supports Rx & Tx functionality. + It support all industry standard baud rates. + + If unsure, say N. + +config SERIAL_STM32_CONSOLE + bool "Support for console on STM32" + depends on SERIAL_STM32=y + select SERIAL_CORE_CONSOLE + endmenu config SERIAL_MCTRL_GPIO diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 599be4b05a26..5ab41119b3dc 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -53,7 +53,7 @@ obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o obj-$(CONFIG_SERIAL_ETRAXFS) += etraxfs-uart.o obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o -obj-$(CONFIG_SERIAL_SC16IS7XX) += sc16is7xx.o +obj-$(CONFIG_SERIAL_SC16IS7XX_CORE) += sc16is7xx.o obj-$(CONFIG_SERIAL_JSM) += jsm/ obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o @@ -62,7 +62,6 @@ obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o obj-$(CONFIG_SERIAL_MSM) += msm_serial.o -obj-$(CONFIG_SERIAL_MSM_HS) += msm_serial_hs.o obj-$(CONFIG_SERIAL_NETX) += netx-serial.o obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o @@ -78,10 +77,8 @@ obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o -obj-$(CONFIG_SERIAL_MFD_HSU) += mfd.o obj-$(CONFIG_SERIAL_IFX6X60) += ifx6x60.o obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o -obj-$(CONFIG_SERIAL_MSM_SMD) += msm_smd_tty.o obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o @@ -95,6 +92,7 @@ obj-$(CONFIG_SERIAL_FSL_LPUART) += fsl_lpuart.o obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR) += digicolor-usart.o obj-$(CONFIG_SERIAL_MEN_Z135) += men_z135_uart.o obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o +obj-$(CONFIG_SERIAL_STM32) += stm32-usart.o # GPIOLIB helpers for modem control lines obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c index 0fefdd8931a2..32df2a0cb060 100644 --- a/drivers/tty/serial/altera_jtaguart.c +++ b/drivers/tty/serial/altera_jtaguart.c @@ -387,7 +387,7 @@ console_initcall(altera_jtaguart_console_init); #define ALTERA_JTAGUART_CONSOLE NULL -#endif /* CONFIG_ALTERA_JTAGUART_CONSOLE */ +#endif /* CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE */ static struct uart_driver altera_jtaguart_driver = { .owner = THIS_MODULE, diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c index b2859fe07e14..fd87a6f574e3 100644 --- a/drivers/tty/serial/altera_uart.c +++ b/drivers/tty/serial/altera_uart.c @@ -493,7 +493,7 @@ console_initcall(altera_uart_console_init); #define ALTERA_UART_CONSOLE NULL -#endif /* CONFIG_ALTERA_UART_CONSOLE */ +#endif /* CONFIG_SERIAL_ALTERA_UART_CONSOLE */ /* * Define the altera_uart UART driver structure. diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 8d94c194f090..50cf5b10ceed 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -58,6 +58,7 @@ #include <linux/pinctrl/consumer.h> #include <linux/sizes.h> #include <linux/io.h> +#include <linux/acpi.h> #define UART_NR 14 @@ -78,6 +79,8 @@ struct vendor_data { bool oversampling; bool dma_threshold; bool cts_event_workaround; + bool always_enabled; + bool fixed_options; unsigned int (*get_fifosize)(struct amba_device *dev); }; @@ -94,9 +97,19 @@ static struct vendor_data vendor_arm = { .oversampling = false, .dma_threshold = false, .cts_event_workaround = false, + .always_enabled = false, + .fixed_options = false, .get_fifosize = get_fifosize_arm, }; +static struct vendor_data vendor_sbsa = { + .oversampling = false, + .dma_threshold = false, + .cts_event_workaround = false, + .always_enabled = true, + .fixed_options = true, +}; + static unsigned int get_fifosize_st(struct amba_device *dev) { return 64; @@ -109,6 +122,8 @@ static struct vendor_data vendor_st = { .oversampling = true, .dma_threshold = true, .cts_event_workaround = true, + .always_enabled = false, + .fixed_options = false, .get_fifosize = get_fifosize_st, }; @@ -157,6 +172,7 @@ struct uart_amba_port { unsigned int lcrh_rx; /* vendor-specific */ unsigned int old_cr; /* state during shutdown */ bool autorts; + unsigned int fixed_baud; /* vendor-set fixed baud rate */ char type[12]; #ifdef CONFIG_DMA_ENGINE /* DMA stuff */ @@ -164,6 +180,7 @@ struct uart_amba_port { bool using_rx_dma; struct pl011_dmarx_data dmarx; struct pl011_dmatx_data dmatx; + bool dma_probed; #endif }; @@ -261,10 +278,11 @@ static void pl011_sgbuf_free(struct dma_chan *chan, struct pl011_sgbuf *sg, } } -static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port *uap) +static void pl011_dma_probe(struct uart_amba_port *uap) { /* DMA is the sole user of the platform data right now */ struct amba_pl011_data *plat = dev_get_platdata(uap->port.dev); + struct device *dev = uap->port.dev; struct dma_slave_config tx_conf = { .dst_addr = uap->port.mapbase + UART01x_DR, .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, @@ -275,9 +293,14 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port * struct dma_chan *chan; dma_cap_mask_t mask; - chan = dma_request_slave_channel(dev, "tx"); + uap->dma_probed = true; + chan = dma_request_slave_channel_reason(dev, "tx"); + if (IS_ERR(chan)) { + if (PTR_ERR(chan) == -EPROBE_DEFER) { + uap->dma_probed = false; + return; + } - if (!chan) { /* We need platform data */ if (!plat || !plat->dma_filter) { dev_info(uap->port.dev, "no DMA platform data\n"); @@ -385,63 +408,17 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port * } } -#ifndef MODULE -/* - * Stack up the UARTs and let the above initcall be done at device - * initcall time, because the serial driver is called as an arch - * initcall, and at this time the DMA subsystem is not yet registered. - * At this point the driver will switch over to using DMA where desired. - */ -struct dma_uap { - struct list_head node; - struct uart_amba_port *uap; - struct device *dev; -}; - -static LIST_HEAD(pl011_dma_uarts); - -static int __init pl011_dma_initcall(void) -{ - struct list_head *node, *tmp; - - list_for_each_safe(node, tmp, &pl011_dma_uarts) { - struct dma_uap *dmau = list_entry(node, struct dma_uap, node); - pl011_dma_probe_initcall(dmau->dev, dmau->uap); - list_del(node); - kfree(dmau); - } - return 0; -} - -device_initcall(pl011_dma_initcall); - -static void pl011_dma_probe(struct device *dev, struct uart_amba_port *uap) -{ - struct dma_uap *dmau = kzalloc(sizeof(struct dma_uap), GFP_KERNEL); - if (dmau) { - dmau->uap = uap; - dmau->dev = dev; - list_add_tail(&dmau->node, &pl011_dma_uarts); - } -} -#else -static void pl011_dma_probe(struct device *dev, struct uart_amba_port *uap) -{ - pl011_dma_probe_initcall(dev, uap); -} -#endif - static void pl011_dma_remove(struct uart_amba_port *uap) { - /* TODO: remove the initcall if it has not yet executed */ if (uap->dmatx.chan) dma_release_channel(uap->dmatx.chan); if (uap->dmarx.chan) dma_release_channel(uap->dmarx.chan); } -/* Forward declare this for the refill routine */ +/* Forward declare these for the refill routine */ static int pl011_dma_tx_refill(struct uart_amba_port *uap); +static void pl011_start_tx_pio(struct uart_amba_port *uap); /* * The current DMA TX buffer has been sent. @@ -479,14 +456,13 @@ static void pl011_dma_tx_callback(void *data) return; } - if (pl011_dma_tx_refill(uap) <= 0) { + if (pl011_dma_tx_refill(uap) <= 0) /* * We didn't queue a DMA buffer for some reason, but we * have data pending to be sent. Re-enable the TX IRQ. */ - uap->im |= UART011_TXIM; - writew(uap->im, uap->port.membase + UART011_IMSC); - } + pl011_start_tx_pio(uap); + spin_unlock_irqrestore(&uap->port.lock, flags); } @@ -664,12 +640,10 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap) if (!uap->dmatx.queued) { if (pl011_dma_tx_refill(uap) > 0) { uap->im &= ~UART011_TXIM; - ret = true; - } else { - uap->im |= UART011_TXIM; + writew(uap->im, uap->port.membase + + UART011_IMSC); + } else ret = false; - } - writew(uap->im, uap->port.membase + UART011_IMSC); } else if (!(uap->dmacr & UART011_TXDMAE)) { uap->dmacr |= UART011_TXDMAE; writew(uap->dmacr, @@ -1021,6 +995,9 @@ static void pl011_dma_startup(struct uart_amba_port *uap) { int ret; + if (!uap->dma_probed) + pl011_dma_probe(uap); + if (!uap->dmatx.chan) return; @@ -1142,7 +1119,7 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap) #else /* Blank functions if the DMA engine is not available */ -static inline void pl011_dma_probe(struct device *dev, struct uart_amba_port *uap) +static inline void pl011_dma_probe(struct uart_amba_port *uap) { } @@ -1208,15 +1185,23 @@ static void pl011_stop_tx(struct uart_port *port) pl011_dma_tx_stop(uap); } +static void pl011_tx_chars(struct uart_amba_port *uap, bool from_irq); + +/* Start TX with programmed I/O only (no DMA) */ +static void pl011_start_tx_pio(struct uart_amba_port *uap) +{ + uap->im |= UART011_TXIM; + writew(uap->im, uap->port.membase + UART011_IMSC); + pl011_tx_chars(uap, false); +} + static void pl011_start_tx(struct uart_port *port) { struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); - if (!pl011_dma_tx_start(uap)) { - uap->im |= UART011_TXIM; - writew(uap->im, uap->port.membase + UART011_IMSC); - } + if (!pl011_dma_tx_start(uap)) + pl011_start_tx_pio(uap); } static void pl011_stop_rx(struct uart_port *port) @@ -1274,16 +1259,29 @@ __acquires(&uap->port.lock) spin_lock(&uap->port.lock); } -static void pl011_tx_chars(struct uart_amba_port *uap) +static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c, + bool from_irq) +{ + if (unlikely(!from_irq) && + readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) + return false; /* unable to transmit character */ + + writew(c, uap->port.membase + UART01x_DR); + uap->port.icount.tx++; + + return true; +} + +static void pl011_tx_chars(struct uart_amba_port *uap, bool from_irq) { struct circ_buf *xmit = &uap->port.state->xmit; - int count; + int count = uap->fifosize >> 1; if (uap->port.x_char) { - writew(uap->port.x_char, uap->port.membase + UART01x_DR); - uap->port.icount.tx++; + if (!pl011_tx_char(uap, uap->port.x_char, from_irq)) + return; uap->port.x_char = 0; - return; + --count; } if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) { pl011_stop_tx(&uap->port); @@ -1294,14 +1292,15 @@ static void pl011_tx_chars(struct uart_amba_port *uap) if (pl011_dma_tx_irq(uap)) return; - count = uap->fifosize >> 1; do { - writew(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - uap->port.icount.tx++; - if (uart_circ_empty(xmit)) + if (likely(from_irq) && count-- == 0) break; - } while (--count > 0); + + if (!pl011_tx_char(uap, xmit->buf[xmit->tail], from_irq)) + break; + + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + } while (!uart_circ_empty(xmit)); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&uap->port); @@ -1334,30 +1333,39 @@ static void pl011_modem_status(struct uart_amba_port *uap) wake_up_interruptible(&uap->port.state->port.delta_msr_wait); } +static void check_apply_cts_event_workaround(struct uart_amba_port *uap) +{ + unsigned int dummy_read; + + if (!uap->vendor->cts_event_workaround) + return; + + /* workaround to make sure that all bits are unlocked.. */ + writew(0x00, uap->port.membase + UART011_ICR); + + /* + * WA: introduce 26ns(1 uart clk) delay before W1C; + * single apb access will incur 2 pclk(133.12Mhz) delay, + * so add 2 dummy reads + */ + dummy_read = readw(uap->port.membase + UART011_ICR); + dummy_read = readw(uap->port.membase + UART011_ICR); +} + static irqreturn_t pl011_int(int irq, void *dev_id) { struct uart_amba_port *uap = dev_id; unsigned long flags; unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT; + u16 imsc; int handled = 0; - unsigned int dummy_read; spin_lock_irqsave(&uap->port.lock, flags); - status = readw(uap->port.membase + UART011_MIS); + imsc = readw(uap->port.membase + UART011_IMSC); + status = readw(uap->port.membase + UART011_RIS) & imsc; if (status) { do { - if (uap->vendor->cts_event_workaround) { - /* workaround to make sure that all bits are unlocked.. */ - writew(0x00, uap->port.membase + UART011_ICR); - - /* - * WA: introduce 26ns(1 uart clk) delay before W1C; - * single apb access will incur 2 pclk(133.12Mhz) delay, - * so add 2 dummy reads - */ - dummy_read = readw(uap->port.membase + UART011_ICR); - dummy_read = readw(uap->port.membase + UART011_ICR); - } + check_apply_cts_event_workaround(uap); writew(status & ~(UART011_TXIS|UART011_RTIS| UART011_RXIS), @@ -1373,12 +1381,12 @@ static irqreturn_t pl011_int(int irq, void *dev_id) UART011_CTSMIS|UART011_RIMIS)) pl011_modem_status(uap); if (status & UART011_TXIS) - pl011_tx_chars(uap); + pl011_tx_chars(uap, true); if (pass_counter-- == 0) break; - status = readw(uap->port.membase + UART011_MIS); + status = readw(uap->port.membase + UART011_RIS) & imsc; } while (status != 0); handled = 1; } @@ -1573,52 +1581,51 @@ static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h) } } +static int pl011_allocate_irq(struct uart_amba_port *uap) +{ + writew(uap->im, uap->port.membase + UART011_IMSC); + + return request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap); +} + +/* + * Enable interrupts, only timeouts when using DMA + * if initial RX DMA job failed, start in interrupt mode + * as well. + */ +static void pl011_enable_interrupts(struct uart_amba_port *uap) +{ + spin_lock_irq(&uap->port.lock); + + /* Clear out any spuriously appearing RX interrupts */ + writew(UART011_RTIS | UART011_RXIS, + uap->port.membase + UART011_ICR); + uap->im = UART011_RTIM; + if (!pl011_dma_rx_running(uap)) + uap->im |= UART011_RXIM; + writew(uap->im, uap->port.membase + UART011_IMSC); + spin_unlock_irq(&uap->port.lock); +} + static int pl011_startup(struct uart_port *port) { struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); - unsigned int cr, lcr_h, fbrd, ibrd; + unsigned int cr; int retval; retval = pl011_hwinit(port); if (retval) goto clk_dis; - writew(uap->im, uap->port.membase + UART011_IMSC); - - /* - * Allocate the IRQ - */ - retval = request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap); + retval = pl011_allocate_irq(uap); if (retval) goto clk_dis; writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS); - /* - * Provoke TX FIFO interrupt into asserting. Taking care to preserve - * baud rate and data format specified by FBRD, IBRD and LCRH as the - * UART may already be in use as a console. - */ spin_lock_irq(&uap->port.lock); - fbrd = readw(uap->port.membase + UART011_FBRD); - ibrd = readw(uap->port.membase + UART011_IBRD); - lcr_h = readw(uap->port.membase + uap->lcrh_rx); - - cr = UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_LBE; - writew(cr, uap->port.membase + UART011_CR); - writew(0, uap->port.membase + UART011_FBRD); - writew(1, uap->port.membase + UART011_IBRD); - pl011_write_lcr_h(uap, 0); - writew(0, uap->port.membase + UART01x_DR); - while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY) - barrier(); - - writew(fbrd, uap->port.membase + UART011_FBRD); - writew(ibrd, uap->port.membase + UART011_IBRD); - pl011_write_lcr_h(uap, lcr_h); - /* restore RTS and DTR */ cr = uap->old_cr & (UART011_CR_RTS | UART011_CR_DTR); cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE; @@ -1634,20 +1641,7 @@ static int pl011_startup(struct uart_port *port) /* Startup DMA */ pl011_dma_startup(uap); - /* - * Finally, enable interrupts, only timeouts when using DMA - * if initial RX DMA job failed, start in interrupt mode - * as well. - */ - spin_lock_irq(&uap->port.lock); - /* Clear out any spuriously appearing RX interrupts */ - writew(UART011_RTIS | UART011_RXIS, - uap->port.membase + UART011_ICR); - uap->im = UART011_RTIM; - if (!pl011_dma_rx_running(uap)) - uap->im |= UART011_RXIM; - writew(uap->im, uap->port.membase + UART011_IMSC); - spin_unlock_irq(&uap->port.lock); + pl011_enable_interrupts(uap); return 0; @@ -1656,6 +1650,28 @@ static int pl011_startup(struct uart_port *port) return retval; } +static int sbsa_uart_startup(struct uart_port *port) +{ + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); + int retval; + + retval = pl011_hwinit(port); + if (retval) + return retval; + + retval = pl011_allocate_irq(uap); + if (retval) + return retval; + + /* The SBSA UART does not support any modem status lines. */ + uap->old_status = 0; + + pl011_enable_interrupts(uap); + + return 0; +} + static void pl011_shutdown_channel(struct uart_amba_port *uap, unsigned int lcrh) { @@ -1666,34 +1682,15 @@ static void pl011_shutdown_channel(struct uart_amba_port *uap, writew(val, uap->port.membase + lcrh); } -static void pl011_shutdown(struct uart_port *port) +/* + * disable the port. It should not disable RTS and DTR. + * Also RTS and DTR state should be preserved to restore + * it during startup(). + */ +static void pl011_disable_uart(struct uart_amba_port *uap) { - struct uart_amba_port *uap = - container_of(port, struct uart_amba_port, port); unsigned int cr; - /* - * disable all interrupts - */ - spin_lock_irq(&uap->port.lock); - uap->im = 0; - writew(uap->im, uap->port.membase + UART011_IMSC); - writew(0xffff, uap->port.membase + UART011_ICR); - spin_unlock_irq(&uap->port.lock); - - pl011_dma_shutdown(uap); - - /* - * Free the interrupt - */ - free_irq(uap->port.irq, uap); - - /* - * disable the port - * disable the port. It should not disable RTS and DTR. - * Also RTS and DTR state should be preserved to restore - * it during startup(). - */ uap->autorts = false; spin_lock_irq(&uap->port.lock); cr = readw(uap->port.membase + UART011_CR); @@ -1709,6 +1706,32 @@ static void pl011_shutdown(struct uart_port *port) pl011_shutdown_channel(uap, uap->lcrh_rx); if (uap->lcrh_rx != uap->lcrh_tx) pl011_shutdown_channel(uap, uap->lcrh_tx); +} + +static void pl011_disable_interrupts(struct uart_amba_port *uap) +{ + spin_lock_irq(&uap->port.lock); + + /* mask all interrupts and clear all pending ones */ + uap->im = 0; + writew(uap->im, uap->port.membase + UART011_IMSC); + writew(0xffff, uap->port.membase + UART011_ICR); + + spin_unlock_irq(&uap->port.lock); +} + +static void pl011_shutdown(struct uart_port *port) +{ + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); + + pl011_disable_interrupts(uap); + + pl011_dma_shutdown(uap); + + free_irq(uap->port.irq, uap); + + pl011_disable_uart(uap); /* * Shut down the clock producer @@ -1729,6 +1752,51 @@ static void pl011_shutdown(struct uart_port *port) uap->port.ops->flush_buffer(port); } +static void sbsa_uart_shutdown(struct uart_port *port) +{ + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); + + pl011_disable_interrupts(uap); + + free_irq(uap->port.irq, uap); + + if (uap->port.ops->flush_buffer) + uap->port.ops->flush_buffer(port); +} + +static void +pl011_setup_status_masks(struct uart_port *port, struct ktermios *termios) +{ + port->read_status_mask = UART011_DR_OE | 255; + if (termios->c_iflag & INPCK) + port->read_status_mask |= UART011_DR_FE | UART011_DR_PE; + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) + port->read_status_mask |= UART011_DR_BE; + + /* + * Characters to ignore + */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= UART011_DR_FE | UART011_DR_PE; + if (termios->c_iflag & IGNBRK) { + port->ignore_status_mask |= UART011_DR_BE; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= UART011_DR_OE; + } + + /* + * Ignore all characters if CREAD is not set. + */ + if ((termios->c_cflag & CREAD) == 0) + port->ignore_status_mask |= UART_DUMMY_DR_RX; +} + static void pl011_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) @@ -1793,33 +1861,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, */ uart_update_timeout(port, termios->c_cflag, baud); - port->read_status_mask = UART011_DR_OE | 255; - if (termios->c_iflag & INPCK) - port->read_status_mask |= UART011_DR_FE | UART011_DR_PE; - if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) - port->read_status_mask |= UART011_DR_BE; - - /* - * Characters to ignore - */ - port->ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= UART011_DR_FE | UART011_DR_PE; - if (termios->c_iflag & IGNBRK) { - port->ignore_status_mask |= UART011_DR_BE; - /* - * If we're ignoring parity and break indicators, - * ignore overruns too (for real raw support). - */ - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= UART011_DR_OE; - } - - /* - * Ignore all characters if CREAD is not set. - */ - if ((termios->c_cflag & CREAD) == 0) - port->ignore_status_mask |= UART_DUMMY_DR_RX; + pl011_setup_status_masks(port, termios); if (UART_ENABLE_MS(port, termios->c_cflag)) pl011_enable_ms(port); @@ -1874,6 +1916,27 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, spin_unlock_irqrestore(&port->lock, flags); } +static void +sbsa_uart_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); + unsigned long flags; + + tty_termios_encode_baud_rate(termios, uap->fixed_baud, uap->fixed_baud); + + /* The SBSA UART only supports 8n1 without hardware flow control. */ + termios->c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD); + termios->c_cflag &= ~(CMSPAR | CRTSCTS); + termios->c_cflag |= CS8 | CLOCAL; + + spin_lock_irqsave(&port->lock, flags); + uart_update_timeout(port, CS8, uap->fixed_baud); + pl011_setup_status_masks(port, termios); + spin_unlock_irqrestore(&port->lock, flags); +} + static const char *pl011_type(struct uart_port *port) { struct uart_amba_port *uap = @@ -1949,6 +2012,37 @@ static struct uart_ops amba_pl011_pops = { #endif }; +static void sbsa_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +} + +static unsigned int sbsa_uart_get_mctrl(struct uart_port *port) +{ + return 0; +} + +static const struct uart_ops sbsa_uart_pops = { + .tx_empty = pl011_tx_empty, + .set_mctrl = sbsa_uart_set_mctrl, + .get_mctrl = sbsa_uart_get_mctrl, + .stop_tx = pl011_stop_tx, + .start_tx = pl011_start_tx, + .stop_rx = pl011_stop_rx, + .startup = sbsa_uart_startup, + .shutdown = sbsa_uart_shutdown, + .set_termios = sbsa_uart_set_termios, + .type = pl011_type, + .release_port = pl011_release_port, + .request_port = pl011_request_port, + .config_port = pl011_config_port, + .verify_port = pl011_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_init = pl011_hwinit, + .poll_get_char = pl011_get_poll_char, + .poll_put_char = pl011_put_poll_char, +#endif +}; + static struct uart_amba_port *amba_ports[UART_NR]; #ifdef CONFIG_SERIAL_AMBA_PL011_CONSOLE @@ -1967,7 +2061,7 @@ static void pl011_console_write(struct console *co, const char *s, unsigned int count) { struct uart_amba_port *uap = amba_ports[co->index]; - unsigned int status, old_cr, new_cr; + unsigned int status, old_cr = 0, new_cr; unsigned long flags; int locked = 1; @@ -1984,10 +2078,12 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) /* * First save the CR then disable the interrupts */ - old_cr = readw(uap->port.membase + UART011_CR); - new_cr = old_cr & ~UART011_CR_CTSEN; - new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE; - writew(new_cr, uap->port.membase + UART011_CR); + if (!uap->vendor->always_enabled) { + old_cr = readw(uap->port.membase + UART011_CR); + new_cr = old_cr & ~UART011_CR_CTSEN; + new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE; + writew(new_cr, uap->port.membase + UART011_CR); + } uart_console_write(&uap->port, s, count, pl011_console_putchar); @@ -1998,7 +2094,8 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) do { status = readw(uap->port.membase + UART01x_FR); } while (status & UART01x_FR_BUSY); - writew(old_cr, uap->port.membase + UART011_CR); + if (!uap->vendor->always_enabled) + writew(old_cr, uap->port.membase + UART011_CR); if (locked) spin_unlock(&uap->port.lock); @@ -2079,10 +2176,15 @@ static int __init pl011_console_setup(struct console *co, char *options) uap->port.uartclk = clk_get_rate(uap->clk); - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - else - pl011_console_get_options(uap, &baud, &parity, &bits); + if (uap->vendor->fixed_options) { + baud = uap->fixed_baud; + } else { + if (options) + uart_parse_options(options, + &baud, &parity, &bits, &flow); + else + pl011_console_get_options(uap, &baud, &parity, &bits); + } return uart_set_options(&uap->port, co, baud, parity, bits, flow); } @@ -2174,97 +2276,126 @@ static int pl011_probe_dt_alias(int index, struct device *dev) return ret; } -static int pl011_probe(struct amba_device *dev, const struct amba_id *id) +/* unregisters the driver also if no more ports are left */ +static void pl011_unregister_port(struct uart_amba_port *uap) { - struct uart_amba_port *uap; - struct vendor_data *vendor = id->data; - void __iomem *base; - int i, ret; + int i; + bool busy = false; + + for (i = 0; i < ARRAY_SIZE(amba_ports); i++) { + if (amba_ports[i] == uap) + amba_ports[i] = NULL; + else if (amba_ports[i]) + busy = true; + } + pl011_dma_remove(uap); + if (!busy) + uart_unregister_driver(&amba_reg); +} + +static int pl011_find_free_port(void) +{ + int i; for (i = 0; i < ARRAY_SIZE(amba_ports); i++) if (amba_ports[i] == NULL) - break; - - if (i == ARRAY_SIZE(amba_ports)) - return -EBUSY; + return i; - uap = devm_kzalloc(&dev->dev, sizeof(struct uart_amba_port), - GFP_KERNEL); - if (uap == NULL) - return -ENOMEM; + return -EBUSY; +} - i = pl011_probe_dt_alias(i, &dev->dev); +static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap, + struct resource *mmiobase, int index) +{ + void __iomem *base; - base = devm_ioremap(&dev->dev, dev->res.start, - resource_size(&dev->res)); + base = devm_ioremap_resource(dev, mmiobase); if (!base) return -ENOMEM; - uap->clk = devm_clk_get(&dev->dev, NULL); - if (IS_ERR(uap->clk)) - return PTR_ERR(uap->clk); + index = pl011_probe_dt_alias(index, dev); - uap->vendor = vendor; - uap->lcrh_rx = vendor->lcrh_rx; - uap->lcrh_tx = vendor->lcrh_tx; uap->old_cr = 0; - uap->fifosize = vendor->get_fifosize(dev); - uap->port.dev = &dev->dev; - uap->port.mapbase = dev->res.start; + uap->port.dev = dev; + uap->port.mapbase = mmiobase->start; uap->port.membase = base; uap->port.iotype = UPIO_MEM; - uap->port.irq = dev->irq[0]; uap->port.fifosize = uap->fifosize; - uap->port.ops = &amba_pl011_pops; uap->port.flags = UPF_BOOT_AUTOCONF; - uap->port.line = i; - pl011_dma_probe(&dev->dev, uap); + uap->port.line = index; - /* Ensure interrupts from this UART are masked and cleared */ - writew(0, uap->port.membase + UART011_IMSC); - writew(0xffff, uap->port.membase + UART011_ICR); + amba_ports[index] = uap; - snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev)); + return 0; +} - amba_ports[i] = uap; +static int pl011_register_port(struct uart_amba_port *uap) +{ + int ret; - amba_set_drvdata(dev, uap); + /* Ensure interrupts from this UART are masked and cleared */ + writew(0, uap->port.membase + UART011_IMSC); + writew(0xffff, uap->port.membase + UART011_ICR); if (!amba_reg.state) { ret = uart_register_driver(&amba_reg); if (ret < 0) { - pr_err("Failed to register AMBA-PL011 driver\n"); + dev_err(uap->port.dev, + "Failed to register AMBA-PL011 driver\n"); return ret; } } ret = uart_add_one_port(&amba_reg, &uap->port); - if (ret) { - amba_ports[i] = NULL; - uart_unregister_driver(&amba_reg); - pl011_dma_remove(uap); - } + if (ret) + pl011_unregister_port(uap); return ret; } +static int pl011_probe(struct amba_device *dev, const struct amba_id *id) +{ + struct uart_amba_port *uap; + struct vendor_data *vendor = id->data; + int portnr, ret; + + portnr = pl011_find_free_port(); + if (portnr < 0) + return portnr; + + uap = devm_kzalloc(&dev->dev, sizeof(struct uart_amba_port), + GFP_KERNEL); + if (!uap) + return -ENOMEM; + + uap->clk = devm_clk_get(&dev->dev, NULL); + if (IS_ERR(uap->clk)) + return PTR_ERR(uap->clk); + + uap->vendor = vendor; + uap->lcrh_rx = vendor->lcrh_rx; + uap->lcrh_tx = vendor->lcrh_tx; + uap->fifosize = vendor->get_fifosize(dev); + uap->port.irq = dev->irq[0]; + uap->port.ops = &amba_pl011_pops; + + snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev)); + + ret = pl011_setup_port(&dev->dev, uap, &dev->res, portnr); + if (ret) + return ret; + + amba_set_drvdata(dev, uap); + + return pl011_register_port(uap); +} + static int pl011_remove(struct amba_device *dev) { struct uart_amba_port *uap = amba_get_drvdata(dev); - bool busy = false; - int i; uart_remove_one_port(&amba_reg, &uap->port); - - for (i = 0; i < ARRAY_SIZE(amba_ports); i++) - if (amba_ports[i] == uap) - amba_ports[i] = NULL; - else if (amba_ports[i]) - busy = true; - - pl011_dma_remove(uap); - if (!busy) - uart_unregister_driver(&amba_reg); + pl011_unregister_port(uap); return 0; } @@ -2292,6 +2423,86 @@ static int pl011_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(pl011_dev_pm_ops, pl011_suspend, pl011_resume); +static int sbsa_uart_probe(struct platform_device *pdev) +{ + struct uart_amba_port *uap; + struct resource *r; + int portnr, ret; + int baudrate; + + /* + * Check the mandatory baud rate parameter in the DT node early + * so that we can easily exit with the error. + */ + if (pdev->dev.of_node) { + struct device_node *np = pdev->dev.of_node; + + ret = of_property_read_u32(np, "current-speed", &baudrate); + if (ret) + return ret; + } else { + baudrate = 115200; + } + + portnr = pl011_find_free_port(); + if (portnr < 0) + return portnr; + + uap = devm_kzalloc(&pdev->dev, sizeof(struct uart_amba_port), + GFP_KERNEL); + if (!uap) + return -ENOMEM; + + uap->vendor = &vendor_sbsa; + uap->fifosize = 32; + uap->port.irq = platform_get_irq(pdev, 0); + uap->port.ops = &sbsa_uart_pops; + uap->fixed_baud = baudrate; + + snprintf(uap->type, sizeof(uap->type), "SBSA"); + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + ret = pl011_setup_port(&pdev->dev, uap, r, portnr); + if (ret) + return ret; + + platform_set_drvdata(pdev, uap); + + return pl011_register_port(uap); +} + +static int sbsa_uart_remove(struct platform_device *pdev) +{ + struct uart_amba_port *uap = platform_get_drvdata(pdev); + + uart_remove_one_port(&amba_reg, &uap->port); + pl011_unregister_port(uap); + return 0; +} + +static const struct of_device_id sbsa_uart_of_match[] = { + { .compatible = "arm,sbsa-uart", }, + {}, +}; +MODULE_DEVICE_TABLE(of, sbsa_uart_of_match); + +static const struct acpi_device_id sbsa_uart_acpi_match[] = { + { "ARMH0011", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, sbsa_uart_acpi_match); + +static struct platform_driver arm_sbsa_uart_platform_driver = { + .probe = sbsa_uart_probe, + .remove = sbsa_uart_remove, + .driver = { + .name = "sbsa-uart", + .of_match_table = of_match_ptr(sbsa_uart_of_match), + .acpi_match_table = ACPI_PTR(sbsa_uart_acpi_match), + }, +}; + static struct amba_id pl011_ids[] = { { .id = 0x00041011, @@ -2322,11 +2533,14 @@ static int __init pl011_init(void) { printk(KERN_INFO "Serial: AMBA PL011 UART driver\n"); + if (platform_driver_register(&arm_sbsa_uart_platform_driver)) + pr_warn("could not register SBSA UART platform driver\n"); return amba_driver_register(&pl011_driver); } static void __exit pl011_exit(void) { + platform_driver_unregister(&arm_sbsa_uart_platform_driver); amba_driver_unregister(&pl011_driver); } diff --git a/drivers/tty/serial/apbuart.c b/drivers/tty/serial/apbuart.c index 4f0f95e358e8..f3af317131ac 100644 --- a/drivers/tty/serial/apbuart.c +++ b/drivers/tty/serial/apbuart.c @@ -572,7 +572,7 @@ static int apbuart_probe(struct platform_device *op) return 0; } -static struct of_device_id apbuart_match[] = { +static const struct of_device_id apbuart_match[] = { { .name = "GAISLER_APBUART", }, diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c index 77fc9faa74a4..1519d2ca7705 100644 --- a/drivers/tty/serial/ar933x_uart.c +++ b/drivers/tty/serial/ar933x_uart.c @@ -649,7 +649,7 @@ static int ar933x_uart_probe(struct platform_device *pdev) id = 0; } - if (id > CONFIG_SERIAL_AR933X_NR_UARTS) + if (id >= CONFIG_SERIAL_AR933X_NR_UARTS) return -EINVAL; irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 4e959c43f680..2a8f528153e7 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -165,6 +165,7 @@ struct atmel_uart_port { struct tasklet_struct tasklet; unsigned int irq_status; unsigned int irq_status_prev; + unsigned int status_change; struct circ_buf rx_ring; @@ -315,8 +316,7 @@ static int atmel_config_rs485(struct uart_port *port, if (rs485conf->flags & SER_RS485_ENABLED) { dev_dbg(port->dev, "Setting UART to RS485\n"); atmel_port->tx_done_mask = ATMEL_US_TXEMPTY; - if ((rs485conf->delay_rts_after_send) > 0) - UART_PUT_TTGR(port, rs485conf->delay_rts_after_send); + UART_PUT_TTGR(port, rs485conf->delay_rts_after_send); mode |= ATMEL_US_USMODE_RS485; } else { dev_dbg(port->dev, "Setting UART to RS232\n"); @@ -354,8 +354,7 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl) /* override mode to RS485 if needed, otherwise keep the current mode */ if (port->rs485.flags & SER_RS485_ENABLED) { - if ((port->rs485.delay_rts_after_send) > 0) - UART_PUT_TTGR(port, port->rs485.delay_rts_after_send); + UART_PUT_TTGR(port, port->rs485.delay_rts_after_send); mode &= ~ATMEL_US_USMODE; mode |= ATMEL_US_USMODE_RS485; } @@ -855,7 +854,7 @@ static int atmel_prepare_tx_dma(struct uart_port *port) spin_lock_init(&atmel_port->lock_tx); sg_init_table(&atmel_port->sg_tx, 1); /* UART circular tx buffer is an aligned page. */ - BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK); + BUG_ON(!PAGE_ALIGNED(port->state->xmit.buf)); sg_set_page(&atmel_port->sg_tx, virt_to_page(port->state->xmit.buf), UART_XMIT_SIZE, @@ -880,6 +879,7 @@ static int atmel_prepare_tx_dma(struct uart_port *port) config.direction = DMA_MEM_TO_DEV; config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; config.dst_addr = port->mapbase + ATMEL_US_THR; + config.dst_maxburst = 1; ret = dmaengine_slave_config(atmel_port->chan_tx, &config); @@ -1034,10 +1034,10 @@ static int atmel_prepare_rx_dma(struct uart_port *port) spin_lock_init(&atmel_port->lock_rx); sg_init_table(&atmel_port->sg_rx, 1); /* UART circular rx buffer is an aligned page. */ - BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK); + BUG_ON(!PAGE_ALIGNED(ring->buf)); sg_set_page(&atmel_port->sg_rx, virt_to_page(ring->buf), - ATMEL_SERIAL_RINGSIZE, + sizeof(struct atmel_uart_char) * ATMEL_SERIAL_RINGSIZE, (int)ring->buf & ~PAGE_MASK); nent = dma_map_sg(port->dev, &atmel_port->sg_rx, @@ -1059,6 +1059,7 @@ static int atmel_prepare_rx_dma(struct uart_port *port) config.direction = DMA_DEV_TO_MEM; config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; config.src_addr = port->mapbase + ATMEL_US_RHR; + config.src_maxburst = 1; ret = dmaengine_slave_config(atmel_port->chan_rx, &config); @@ -1175,6 +1176,9 @@ atmel_handle_status(struct uart_port *port, unsigned int pending, if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC | ATMEL_US_CTSIC)) { atmel_port->irq_status = status; + atmel_port->status_change = atmel_port->irq_status ^ + atmel_port->irq_status_prev; + atmel_port->irq_status_prev = status; tasklet_schedule(&atmel_port->tasklet); } } @@ -1521,17 +1525,14 @@ static void atmel_tasklet_func(unsigned long data) { struct uart_port *port = (struct uart_port *)data; struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - unsigned int status; - unsigned int status_change; + unsigned int status = atmel_port->irq_status; + unsigned int status_change = atmel_port->status_change; /* The interrupt handler does not take the lock */ spin_lock(&port->lock); atmel_port->schedule_tx(port); - status = atmel_port->irq_status; - status_change = status ^ atmel_port->irq_status_prev; - if (status_change & (ATMEL_US_RI | ATMEL_US_DSR | ATMEL_US_DCD | ATMEL_US_CTS)) { /* TODO: All reads to CSR will clear these interrupts! */ @@ -1546,7 +1547,7 @@ static void atmel_tasklet_func(unsigned long data) wake_up_interruptible(&port->state->port.delta_msr_wait); - atmel_port->irq_status_prev = status; + atmel_port->status_change = 0; } atmel_port->schedule_rx(port); @@ -1554,7 +1555,7 @@ static void atmel_tasklet_func(unsigned long data) spin_unlock(&port->lock); } -static int atmel_init_property(struct atmel_uart_port *atmel_port, +static void atmel_init_property(struct atmel_uart_port *atmel_port, struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -1595,7 +1596,6 @@ static int atmel_init_property(struct atmel_uart_port *atmel_port, atmel_port->use_dma_tx = false; } - return 0; } static void atmel_init_rs485(struct uart_port *port, @@ -1777,10 +1777,13 @@ static int atmel_startup(struct uart_port *port) if (retval) goto free_irq; + tasklet_enable(&atmel_port->tasklet); + /* * Initialize DMA (if necessary) */ atmel_init_property(atmel_port, pdev); + atmel_set_ops(port); if (atmel_port->prepare_rx) { retval = atmel_port->prepare_rx(port); @@ -1879,6 +1882,7 @@ static void atmel_shutdown(struct uart_port *port) * Clear out any scheduled tasklets before * we destroy the buffers */ + tasklet_disable(&atmel_port->tasklet); tasklet_kill(&atmel_port->tasklet); /* @@ -2056,8 +2060,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, /* mode */ if (port->rs485.flags & SER_RS485_ENABLED) { - if ((port->rs485.delay_rts_after_send) > 0) - UART_PUT_TTGR(port, port->rs485.delay_rts_after_send); + UART_PUT_TTGR(port, port->rs485.delay_rts_after_send); mode |= ATMEL_US_USMODE_RS485; } else if (termios->c_cflag & CRTSCTS) { /* RS232 with hardware handshake (RTS/CTS) */ @@ -2256,8 +2259,8 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port, struct uart_port *port = &atmel_port->uart; struct atmel_uart_data *pdata = dev_get_platdata(&pdev->dev); - if (!atmel_init_property(atmel_port, pdev)) - atmel_set_ops(port); + atmel_init_property(atmel_port, pdev); + atmel_set_ops(port); atmel_init_rs485(port, pdev); @@ -2272,6 +2275,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port, tasklet_init(&atmel_port->tasklet, atmel_tasklet_func, (unsigned long)port); + tasklet_disable(&atmel_port->tasklet); memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring)); @@ -2581,8 +2585,8 @@ static int atmel_init_gpios(struct atmel_uart_port *p, struct device *dev) struct gpio_desc *gpiod; p->gpios = mctrl_gpio_init(dev, 0); - if (IS_ERR_OR_NULL(p->gpios)) - return -1; + if (IS_ERR(p->gpios)) + return PTR_ERR(p->gpios); for (i = 0; i < UART_GPIO_MAX; i++) { gpiod = mctrl_gpio_to_gpiod(p->gpios, i); @@ -2635,9 +2639,10 @@ static int atmel_serial_probe(struct platform_device *pdev) spin_lock_init(&port->lock_suspended); ret = atmel_init_gpios(port, &pdev->dev); - if (ret < 0) - dev_err(&pdev->dev, "%s", - "Failed to initialize GPIOs. The serial port may not work as expected"); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to initialize GPIOs."); + goto err; + } ret = atmel_init_port(port, pdev); if (ret) diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c index 01d83df08e3d..681e0f3d5e0e 100644 --- a/drivers/tty/serial/bcm63xx_uart.c +++ b/drivers/tty/serial/bcm63xx_uart.c @@ -854,7 +854,7 @@ static int bcm_uart_probe(struct platform_device *pdev) ret = uart_add_one_port(&bcm_uart_driver, port); if (ret) { - ports[pdev->id].membase = 0; + ports[pdev->id].membase = NULL; return ret; } platform_set_drvdata(pdev, port); @@ -868,7 +868,7 @@ static int bcm_uart_remove(struct platform_device *pdev) port = platform_get_drvdata(pdev); uart_remove_one_port(&bcm_uart_driver, port); /* mark port as free */ - ports[pdev->id].membase = 0; + ports[pdev->id].membase = NULL; return 0; } diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c index 43b3e2c233ff..ae3cf94b146b 100644 --- a/drivers/tty/serial/bfin_uart.c +++ b/drivers/tty/serial/bfin_uart.c @@ -74,8 +74,8 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart); static void bfin_serial_reset_irda(struct uart_port *port); -#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \ - defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS) +#if defined(SERIAL_BFIN_CTSRTS) || \ + defined(SERIAL_BFIN_HARD_CTSRTS) static unsigned int bfin_serial_get_mctrl(struct uart_port *port) { struct bfin_serial_port *uart = (struct bfin_serial_port *)port; @@ -110,7 +110,7 @@ static irqreturn_t bfin_serial_mctrl_cts_int(int irq, void *dev_id) struct bfin_serial_port *uart = dev_id; struct uart_port *uport = &uart->port; unsigned int status = bfin_serial_get_mctrl(uport); -#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS +#ifdef SERIAL_BFIN_HARD_CTSRTS UART_CLEAR_SCTS(uart); if (uport->hw_stopped) { @@ -464,6 +464,7 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) int x_pos, pos; unsigned long flags; + dma_disable_irq_nosync(uart->rx_dma_channel); spin_lock_irqsave(&uart->rx_lock, flags); /* 2D DMA RX buffer ring is used. Because curr_y_count and @@ -496,6 +497,7 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) } spin_unlock_irqrestore(&uart->rx_lock, flags); + dma_enable_irq(uart->rx_dma_channel); mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES); } @@ -698,7 +700,7 @@ static int bfin_serial_startup(struct uart_port *port) # endif #endif -#ifdef CONFIG_SERIAL_BFIN_CTSRTS +#ifdef SERIAL_BFIN_CTSRTS if (uart->cts_pin >= 0) { if (request_irq(gpio_to_irq(uart->cts_pin), bfin_serial_mctrl_cts_int, @@ -716,7 +718,7 @@ static int bfin_serial_startup(struct uart_port *port) gpio_direction_output(uart->rts_pin, 0); } #endif -#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS +#ifdef SERIAL_BFIN_HARD_CTSRTS if (uart->cts_pin >= 0) { if (request_irq(uart->status_irq, bfin_serial_mctrl_cts_int, 0, "BFIN_UART_MODEM_STATUS", uart)) { @@ -764,13 +766,13 @@ static void bfin_serial_shutdown(struct uart_port *port) free_irq(uart->tx_irq, uart); #endif -#ifdef CONFIG_SERIAL_BFIN_CTSRTS +#ifdef SERIAL_BFIN_CTSRTS if (uart->cts_pin >= 0) free_irq(gpio_to_irq(uart->cts_pin), uart); if (uart->rts_pin >= 0) gpio_free(uart->rts_pin); #endif -#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS +#ifdef SERIAL_BFIN_HARD_CTSRTS if (uart->cts_pin >= 0) free_irq(uart->status_irq, uart); #endif @@ -786,7 +788,7 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios, unsigned int ier, lcr = 0; unsigned long timeout; -#ifdef CONFIG_SERIAL_BFIN_CTSRTS +#ifdef SERIAL_BFIN_CTSRTS if (old == NULL && uart->cts_pin != -1) termios->c_cflag |= CRTSCTS; else if (uart->cts_pin == -1) @@ -1108,8 +1110,8 @@ bfin_serial_console_setup(struct console *co, char *options) int baud = 57600; int bits = 8; int parity = 'n'; -# if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \ - defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS) +# if defined(SERIAL_BFIN_CTSRTS) || \ + defined(SERIAL_BFIN_HARD_CTSRTS) int flow = 'r'; # else int flow = 'n'; @@ -1320,8 +1322,8 @@ static int bfin_serial_probe(struct platform_device *pdev) init_timer(&(uart->rx_dma_timer)); #endif -#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \ - defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS) +#if defined(SERIAL_BFIN_CTSRTS) || \ + defined(SERIAL_BFIN_HARD_CTSRTS) res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (res == NULL) uart->cts_pin = -1; diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c index 6e11c275f2ab..d5d2dd7c7917 100644 --- a/drivers/tty/serial/clps711x.c +++ b/drivers/tty/serial/clps711x.c @@ -501,6 +501,8 @@ static int uart_clps711x_probe(struct platform_device *pdev) platform_set_drvdata(pdev, s); s->gpios = mctrl_gpio_init(&pdev->dev, 0); + if (IS_ERR(s->gpios)) + return PTR_ERR(s->gpios); ret = uart_add_one_port(&clps711x_uart, &s->port); if (ret) diff --git a/drivers/tty/serial/cpm_uart/Makefile b/drivers/tty/serial/cpm_uart/Makefile index e072724ea754..896a5d57881c 100644 --- a/drivers/tty/serial/cpm_uart/Makefile +++ b/drivers/tty/serial/cpm_uart/Makefile @@ -6,6 +6,6 @@ obj-$(CONFIG_SERIAL_CPM) += cpm_uart.o # Select the correct platform objects. cpm_uart-objs-$(CONFIG_CPM2) += cpm_uart_cpm2.o -cpm_uart-objs-$(CONFIG_8xx) += cpm_uart_cpm1.o +cpm_uart-objs-$(CONFIG_CPM1) += cpm_uart_cpm1.o cpm_uart-objs := cpm_uart_core.o $(cpm_uart-objs-y) diff --git a/drivers/tty/serial/cpm_uart/cpm_uart.h b/drivers/tty/serial/cpm_uart/cpm_uart.h index cf34d26ff6cd..0ad027b95873 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart.h +++ b/drivers/tty/serial/cpm_uart/cpm_uart.h @@ -19,7 +19,7 @@ #if defined(CONFIG_CPM2) #include "cpm_uart_cpm2.h" -#elif defined(CONFIG_8xx) +#elif defined(CONFIG_CPM1) #include "cpm_uart_cpm1.h" #endif diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c index fddb1fd4d9d3..08431adeacd5 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c @@ -1435,7 +1435,7 @@ static int cpm_uart_remove(struct platform_device *ofdev) return uart_remove_one_port(&cpm_reg, &pinfo->port); } -static struct of_device_id cpm_uart_match[] = { +static const struct of_device_id cpm_uart_match[] = { { .compatible = "fsl,cpm1-smc-uart", }, diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index 0c1825b0b41d..3e4470af5c50 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c @@ -56,10 +56,6 @@ static char *serial_version = "$Revision: 1.25 $"; #error "RX_TIMEOUT_TICKS == 0 not allowed, use 1" #endif -#if defined(CONFIG_ETRAX_RS485_ON_PA) && defined(CONFIG_ETRAX_RS485_ON_PORT_G) -#error "Disable either CONFIG_ETRAX_RS485_ON_PA or CONFIG_ETRAX_RS485_ON_PORT_G" -#endif - /* * All of the compatibilty code so we can compile serial.c against * older kernels is hidden in serial_compat.h @@ -455,30 +451,6 @@ static struct e100_serial rs_table[] = { static struct fast_timer fast_timers[NR_PORTS]; #endif -#ifdef CONFIG_ETRAX_SERIAL_PROC_ENTRY -#define PROCSTAT(x) x -struct ser_statistics_type { - int overrun_cnt; - int early_errors_cnt; - int ser_ints_ok_cnt; - int errors_cnt; - unsigned long int processing_flip; - unsigned long processing_flip_still_room; - unsigned long int timeout_flush_cnt; - int rx_dma_ints; - int tx_dma_ints; - int rx_tot; - int tx_tot; -}; - -static struct ser_statistics_type ser_stat[NR_PORTS]; - -#else - -#define PROCSTAT(x) - -#endif /* CONFIG_ETRAX_SERIAL_PROC_ENTRY */ - /* RS-485 */ #if defined(CONFIG_ETRAX_RS485) #ifdef CONFIG_ETRAX_FAST_TIMER @@ -487,9 +459,6 @@ static struct fast_timer fast_timers_rs485[NR_PORTS]; #if defined(CONFIG_ETRAX_RS485_ON_PA) static int rs485_pa_bit = CONFIG_ETRAX_RS485_ON_PA_BIT; #endif -#if defined(CONFIG_ETRAX_RS485_ON_PORT_G) -static int rs485_port_g_bit = CONFIG_ETRAX_RS485_ON_PORT_G_BIT; -#endif #endif /* Info and macros needed for each ports extra control/status signals. */ @@ -739,10 +708,10 @@ static unsigned char dummy_ser[NR_PORTS] = {0xFF, 0xFF, 0xFF,0xFF}; defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED) || \ defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED) || \ defined(CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED) -#define CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED +#define ETRAX_SERX_DTR_RI_DSR_CD_MIXED #endif -#ifdef CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED +#ifdef ETRAX_SERX_DTR_RI_DSR_CD_MIXED /* The pins can be mixed on PA and PB */ #define CONTROL_PINS_PORT_NOT_USED(line) \ &dummy_ser[line], &dummy_ser[line], \ @@ -835,7 +804,7 @@ static const struct control_pins e100_modem_pins[NR_PORTS] = #endif } }; -#else /* CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */ +#else /* ETRAX_SERX_DTR_RI_DSR_CD_MIXED */ /* All pins are on either PA or PB for each serial port */ #define CONTROL_PINS_PORT_NOT_USED(line) \ @@ -917,7 +886,7 @@ static const struct control_pins e100_modem_pins[NR_PORTS] = #endif } }; -#endif /* !CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */ +#endif /* !ETRAX_SERX_DTR_RI_DSR_CD_MIXED */ #define E100_RTS_MASK 0x20 #define E100_CTS_MASK 0x40 @@ -1367,16 +1336,6 @@ e100_enable_rs485(struct tty_struct *tty, struct serial_rs485 *r) #if defined(CONFIG_ETRAX_RS485_ON_PA) *R_PORT_PA_DATA = port_pa_data_shadow |= (1 << rs485_pa_bit); #endif -#if defined(CONFIG_ETRAX_RS485_ON_PORT_G) - REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, - rs485_port_g_bit, 1); -#endif -#if defined(CONFIG_ETRAX_RS485_LTC1387) - REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, - CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 1); - REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, - CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 1); -#endif info->rs485 = *r; @@ -1676,7 +1635,8 @@ alloc_recv_buffer(unsigned int size) { struct etrax_recv_buffer *buffer; - if (!(buffer = kmalloc(sizeof *buffer + size, GFP_ATOMIC))) + buffer = kmalloc(sizeof *buffer + size, GFP_ATOMIC); + if (!buffer) return NULL; buffer->next = NULL; @@ -1712,7 +1672,8 @@ add_char_and_flag(struct e100_serial *info, unsigned char data, unsigned char fl { struct etrax_recv_buffer *buffer; if (info->uses_dma_in) { - if (!(buffer = alloc_recv_buffer(4))) + buffer = alloc_recv_buffer(4); + if (!buffer) return 0; buffer->length = 1; @@ -1750,7 +1711,8 @@ static unsigned int handle_descr_data(struct e100_serial *info, append_recv_buffer(info, buffer); - if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE))) + buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE); + if (!buffer) panic("%s: Failed to allocate memory for receive buffer!\n", __func__); descr->buf = virt_to_phys(buffer->buffer); @@ -1841,7 +1803,6 @@ static void receive_chars_dma(struct e100_serial *info) */ unsigned char data = info->ioport[REG_DATA]; - PROCSTAT(ser_stat[info->line].errors_cnt++); DEBUG_LOG(info->line, "#dERR: s d 0x%04X\n", ((rstat & SER_ERROR_MASK) << 8) | data); @@ -1867,7 +1828,8 @@ static int start_recv_dma(struct e100_serial *info) /* Set up the receiving descriptors */ for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) { - if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE))) + buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE); + if (!buffer) panic("%s: Failed to allocate memory for receive buffer!\n", __func__); descr[i].ctrl = d_int; @@ -1943,7 +1905,6 @@ tr_interrupt(int irq, void *dev_id) /* Read jiffies_usec first, * we want this time to be as late as possible */ - PROCSTAT(ser_stat[info->line].tx_dma_ints++); info->last_tx_active_usec = GET_JIFFIES_USEC(); info->last_tx_active = jiffies; transmit_chars_dma(info); @@ -2022,7 +1983,6 @@ static int force_eop_if_needed(struct e100_serial *info) */ if (!info->forced_eop) { info->forced_eop = 1; - PROCSTAT(ser_stat[info->line].timeout_flush_cnt++); TIMERD(DEBUG_LOG(info->line, "timeout EOP %i\n", info->line)); FORCE_EOP(info); } @@ -2374,7 +2334,6 @@ static void handle_ser_rx_interrupt(struct e100_serial *info) DEBUG_LOG(info->line, "#iERR s d %04X\n", ((rstat & SER_ERROR_MASK) << 8) | data); } - PROCSTAT(ser_stat[info->line].early_errors_cnt++); } else { /* It was a valid byte, now let the DMA do the rest */ unsigned long curr_time_u = GET_JIFFIES_USEC(); unsigned long curr_time = jiffies; @@ -2407,7 +2366,6 @@ static void handle_ser_rx_interrupt(struct e100_serial *info) DINTR2(DEBUG_LOG(info->line, "ser_rx OK %d\n", info->line)); info->break_detected_cnt = 0; - PROCSTAT(ser_stat[info->line].ser_ints_ok_cnt++); } /* Restarting the DMA never hurts */ *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart); @@ -2867,19 +2825,6 @@ change_speed(struct e100_serial *info) *R_SERIAL_PRESCALE = divisor; info->baud = SERIAL_PRESCALE_BASE/divisor; } -#ifdef CONFIG_ETRAX_EXTERN_PB6CLK_ENABLED - else if ((info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8 && - info->custom_divisor == 1) || - (info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ && - info->custom_divisor == 8)) { - /* ext_clk selected */ - alt_source = - IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, extern) | - IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, extern); - DBAUD(printk("using external baudrate: %lu\n", CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8)); - info->baud = CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8; - } -#endif else { /* Bad baudbase, we don't support using timer0 @@ -3216,9 +3161,7 @@ rs_throttle(struct tty_struct * tty) { struct e100_serial *info = (struct e100_serial *)tty->driver_data; #ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("throttle %s: %lu....\n", tty_name(tty, buf), + printk("throttle %s: %lu....\n", tty_name(tty), (unsigned long)tty->ldisc.chars_in_buffer(tty)); #endif DFLOW(DEBUG_LOG(info->line,"rs_throttle %lu\n", tty->ldisc.chars_in_buffer(tty))); @@ -3238,9 +3181,7 @@ rs_unthrottle(struct tty_struct * tty) { struct e100_serial *info = (struct e100_serial *)tty->driver_data; #ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("unthrottle %s: %lu....\n", tty_name(tty, buf), + printk("unthrottle %s: %lu....\n", tty_name(tty), (unsigned long)tty->ldisc.chars_in_buffer(tty)); #endif DFLOW(DEBUG_LOG(info->line,"rs_unthrottle ldisc %d\n", tty->ldisc.chars_in_buffer(tty))); @@ -3725,16 +3666,6 @@ rs_close(struct tty_struct *tty, struct file * filp) #if defined(CONFIG_ETRAX_RS485_ON_PA) *R_PORT_PA_DATA = port_pa_data_shadow &= ~(1 << rs485_pa_bit); #endif -#if defined(CONFIG_ETRAX_RS485_ON_PORT_G) - REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, - rs485_port_g_bit, 0); -#endif -#if defined(CONFIG_ETRAX_RS485_LTC1387) - REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, - CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 0); - REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, - CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 0); -#endif } #endif @@ -4263,15 +4194,6 @@ static int __init rs_init(void) return -EBUSY; } #endif -#if defined(CONFIG_ETRAX_RS485_ON_PORT_G) - if (cris_io_interface_allocate_pins(if_serial_0, 'g', rs485_pa_bit, - rs485_port_g_bit)) { - printk(KERN_ERR "ETRAX100LX serial: Could not allocate " - "RS485 pin\n"); - put_tty_driver(driver); - return -EBUSY; - } -#endif #endif /* Initialize the tty_driver structure */ diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c index 64fe25a4285c..f09636083426 100644 --- a/drivers/tty/serial/earlycon.c +++ b/drivers/tty/serial/earlycon.c @@ -10,6 +10,9 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/console.h> #include <linux/kernel.h> #include <linux/init.h> @@ -34,6 +37,10 @@ static struct earlycon_device early_console_dev = { .con = &early_con, }; +extern struct earlycon_id __earlycon_table[]; +static const struct earlycon_id __earlycon_table_sentinel + __used __section(__earlycon_table_end); + static const struct of_device_id __earlycon_of_table_sentinel __used __section(__earlycon_of_table_end); @@ -54,53 +61,41 @@ static void __iomem * __init earlycon_map(unsigned long paddr, size_t size) return base; } -static int __init parse_options(struct earlycon_device *device, - char *options) +static int __init parse_options(struct earlycon_device *device, char *options) { struct uart_port *port = &device->port; - int mmio, mmio32, length; + int length; unsigned long addr; - if (!options) - return -ENODEV; + if (uart_parse_earlycon(options, &port->iotype, &addr, &options)) + return -EINVAL; - mmio = !strncmp(options, "mmio,", 5); - mmio32 = !strncmp(options, "mmio32,", 7); - if (mmio || mmio32) { - port->iotype = (mmio ? UPIO_MEM : UPIO_MEM32); - options += mmio ? 5 : 7; - addr = simple_strtoul(options, NULL, 0); + switch (port->iotype) { + case UPIO_MEM32: + case UPIO_MEM32BE: + port->regshift = 2; /* fall-through */ + case UPIO_MEM: port->mapbase = addr; - if (mmio32) - port->regshift = 2; - } else if (!strncmp(options, "io,", 3)) { - port->iotype = UPIO_PORT; - options += 3; - addr = simple_strtoul(options, NULL, 0); + break; + case UPIO_PORT: port->iobase = addr; - mmio = 0; - } else if (!strncmp(options, "0x", 2)) { - port->iotype = UPIO_MEM; - addr = simple_strtoul(options, NULL, 0); - port->mapbase = addr; - } else { + break; + default: return -EINVAL; } - port->uartclk = BASE_BAUD * 16; - - options = strchr(options, ','); if (options) { - options++; device->baud = simple_strtoul(options, NULL, 0); length = min(strcspn(options, " ") + 1, (size_t)(sizeof(device->options))); strlcpy(device->options, options, length); } - if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM32) + if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM32 || + port->iotype == UPIO_MEM32BE) pr_info("Early serial console at MMIO%s 0x%llx (options '%s')\n", - mmio32 ? "32" : "", + (port->iotype == UPIO_MEM) ? "" : + (port->iotype == UPIO_MEM32) ? "32" : "32be", (unsigned long long)port->mapbase, device->options); else @@ -111,34 +106,21 @@ static int __init parse_options(struct earlycon_device *device, return 0; } -int __init setup_earlycon(char *buf, const char *match, - int (*setup)(struct earlycon_device *, const char *)) +static int __init register_earlycon(char *buf, const struct earlycon_id *match) { int err; - size_t len; struct uart_port *port = &early_console_dev.port; - if (!buf || !match || !setup) - return 0; - - len = strlen(match); - if (strncmp(buf, match, len)) - return 0; - if (buf[len] && (buf[len] != ',')) - return 0; - - buf += len + 1; - - err = parse_options(&early_console_dev, buf); /* On parsing error, pass the options buf to the setup function */ - if (!err) + if (buf && !parse_options(&early_console_dev, buf)) buf = NULL; + port->uartclk = BASE_BAUD * 16; if (port->mapbase) port->membase = earlycon_map(port->mapbase, 64); early_console_dev.con->data = &early_console_dev; - err = setup(&early_console_dev, buf); + err = match->setup(&early_console_dev, buf); if (err < 0) return err; if (!early_console_dev.con->write) @@ -148,6 +130,72 @@ int __init setup_earlycon(char *buf, const char *match, return 0; } +/** + * setup_earlycon - match and register earlycon console + * @buf: earlycon param string + * + * Registers the earlycon console matching the earlycon specified + * in the param string @buf. Acceptable param strings are of the form + * <name>,io|mmio|mmio32|mmio32be,<addr>,<options> + * <name>,0x<addr>,<options> + * <name>,<options> + * <name> + * + * Only for the third form does the earlycon setup() method receive the + * <options> string in the 'options' parameter; all other forms set + * the parameter to NULL. + * + * Returns 0 if an attempt to register the earlycon was made, + * otherwise negative error code + */ +int __init setup_earlycon(char *buf) +{ + const struct earlycon_id *match; + + if (!buf || !buf[0]) + return -EINVAL; + + if (early_con.flags & CON_ENABLED) + return -EALREADY; + + for (match = __earlycon_table; match->name[0]; match++) { + size_t len = strlen(match->name); + + if (strncmp(buf, match->name, len)) + continue; + + if (buf[len]) { + if (buf[len] != ',') + continue; + buf += len + 1; + } else + buf = NULL; + + return register_earlycon(buf, match); + } + + return -ENOENT; +} + +/* early_param wrapper for setup_earlycon() */ +static int __init param_setup_earlycon(char *buf) +{ + int err; + + /* + * Just 'earlycon' is a valid param for devicetree earlycons; + * don't generate a warning from parse_early_params() in that case + */ + if (!buf || !buf[0]) + return 0; + + err = setup_earlycon(buf); + if (err == -ENOENT || err == -EALREADY) + return 0; + return err; +} +early_param("earlycon", param_setup_earlycon); + int __init of_setup_earlycon(unsigned long addr, int (*setup)(struct earlycon_device *, const char *)) { diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 3ad1458bfeb0..08ce76f4f261 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -257,7 +257,7 @@ struct lpuart_port { struct timer_list lpuart_timer; }; -static struct of_device_id lpuart_dt_ids[] = { +static const struct of_device_id lpuart_dt_ids[] = { { .compatible = "fsl,vf610-lpuart", }, diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c index 45fc323b95e6..ffc7cb2585a6 100644 --- a/drivers/tty/serial/icom.c +++ b/drivers/tty/serial/icom.c @@ -1504,7 +1504,8 @@ static int icom_probe(struct pci_dev *dev, return retval; } - if ( (retval = pci_request_regions(dev, "icom"))) { + retval = pci_request_regions(dev, "icom"); + if (retval) { dev_err(&dev->dev, "pci_request_regions FAILED\n"); pci_disable_device(dev); return retval; @@ -1512,7 +1513,8 @@ static int icom_probe(struct pci_dev *dev, pci_set_master(dev); - if ( (retval = pci_read_config_dword(dev, PCI_COMMAND, &command_reg))) { + retval = pci_read_config_dword(dev, PCI_COMMAND, &command_reg); + if (retval) { dev_err(&dev->dev, "PCI Config read FAILED\n"); return retval; } @@ -1556,9 +1558,8 @@ static int icom_probe(struct pci_dev *dev, } /* save off irq and request irq line */ - if ( (retval = request_irq(dev->irq, icom_interrupt, - IRQF_SHARED, ICOM_DRIVER_NAME, - (void *) icom_adapter))) { + retval = request_irq(dev->irq, icom_interrupt, IRQF_SHARED, ICOM_DRIVER_NAME, (void *)icom_adapter); + if (retval) { goto probe_exit2; } diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c index 590390970996..536a33b99be9 100644 --- a/drivers/tty/serial/ifx6x60.c +++ b/drivers/tty/serial/ifx6x60.c @@ -1175,7 +1175,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi) ret = request_irq(gpio_to_irq(ifx_dev->gpio.reset_out), ifx_spi_reset_interrupt, IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, DRVNAME, - (void *)ifx_dev); + ifx_dev); if (ret) { dev_err(&spi->dev, "Unable to get irq %x\n", gpio_to_irq(ifx_dev->gpio.reset_out)); @@ -1185,9 +1185,8 @@ static int ifx_spi_spi_probe(struct spi_device *spi) ret = ifx_spi_reset(ifx_dev); ret = request_irq(gpio_to_irq(ifx_dev->gpio.srdy), - ifx_spi_srdy_interrupt, - IRQF_TRIGGER_RISING, DRVNAME, - (void *)ifx_dev); + ifx_spi_srdy_interrupt, IRQF_TRIGGER_RISING, DRVNAME, + ifx_dev); if (ret) { dev_err(&spi->dev, "Unable to get irq %x", gpio_to_irq(ifx_dev->gpio.srdy)); @@ -1212,7 +1211,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi) return 0; error_ret7: - free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), (void *)ifx_dev); + free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), ifx_dev); error_ret6: gpio_free(ifx_dev->gpio.srdy); error_ret5: @@ -1243,8 +1242,8 @@ static int ifx_spi_spi_remove(struct spi_device *spi) /* stop activity */ tasklet_kill(&ifx_dev->io_work_tasklet); /* free irq */ - free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), (void *)ifx_dev); - free_irq(gpio_to_irq(ifx_dev->gpio.srdy), (void *)ifx_dev); + free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), ifx_dev); + free_irq(gpio_to_irq(ifx_dev->gpio.srdy), ifx_dev); gpio_free(ifx_dev->gpio.srdy); gpio_free(ifx_dev->gpio.mrdy); @@ -1381,7 +1380,7 @@ static void __exit ifx_spi_exit(void) /* unregister */ tty_unregister_driver(tty_drv); put_tty_driver(tty_drv); - spi_unregister_driver((void *)&ifx_spi_driver); + spi_unregister_driver(&ifx_spi_driver); unregister_reboot_notifier(&ifx_modem_reboot_notifier_block); } @@ -1420,7 +1419,7 @@ static int __init ifx_spi_init(void) goto err_free_tty; } - result = spi_register_driver((void *)&ifx_spi_driver); + result = spi_register_driver(&ifx_spi_driver); if (result) { pr_err("%s: spi_register_driver failed(%d)", DRVNAME, result); @@ -1436,7 +1435,7 @@ static int __init ifx_spi_init(void) return 0; err_unreg_spi: - spi_unregister_driver((void *)&ifx_spi_driver); + spi_unregister_driver(&ifx_spi_driver); err_unreg_tty: tty_unregister_driver(tty_drv); err_free_tty: diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 0eb29b1c47ac..2c90dc31bfaa 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -1,13 +1,10 @@ /* - * Driver for Motorola IMX serial ports + * Driver for Motorola/Freescale IMX serial ports * - * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. * - * Author: Sascha Hauer <sascha@saschahauer.de> - * Copyright (C) 2004 Pengutronix - * - * Copyright (C) 2009 emlix GmbH - * Author: Fabian Godehardt (added IrDA support for iMX) + * Author: Sascha Hauer <sascha@saschahauer.de> + * Copyright (C) 2004 Pengutronix * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,13 +15,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * [29-Mar-2005] Mike Lee - * Added hardware handshake */ #if defined(CONFIG_SERIAL_IMX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) @@ -189,7 +179,7 @@ #define UART_NR 8 -/* i.mx21 type uart runs on all i.mx except i.mx1 */ +/* i.MX21 type uart runs on all i.mx except i.MX1 and i.MX6q */ enum imx_uart_type { IMX1_UART, IMX21_UART, @@ -206,10 +196,8 @@ struct imx_port { struct uart_port port; struct timer_list timer; unsigned int old_status; - int txirq, rxirq, rtsirq; unsigned int have_rtscts:1; unsigned int dte_mode:1; - unsigned int use_irda:1; unsigned int irda_inv_rx:1; unsigned int irda_inv_tx:1; unsigned short trcv_delay; /* transceiver delay */ @@ -236,12 +224,6 @@ struct imx_port_ucrs { unsigned int ucr3; }; -#ifdef CONFIG_IRDA -#define USE_IRDA(sport) ((sport)->use_irda) -#else -#define USE_IRDA(sport) (0) -#endif - static struct imx_uart_data imx_uart_devdata[] = { [IMX1_UART] = { .uts_reg = IMX1_UTS, @@ -257,7 +239,7 @@ static struct imx_uart_data imx_uart_devdata[] = { }, }; -static struct platform_device_id imx_uart_devtype[] = { +static const struct platform_device_id imx_uart_devtype[] = { { .name = "imx1-uart", .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX1_UART], @@ -273,7 +255,7 @@ static struct platform_device_id imx_uart_devtype[] = { }; MODULE_DEVICE_TABLE(platform, imx_uart_devtype); -static struct of_device_id imx_uart_dt_ids[] = { +static const struct of_device_id imx_uart_dt_ids[] = { { .compatible = "fsl,imx6q-uart", .data = &imx_uart_devdata[IMX6Q_UART], }, { .compatible = "fsl,imx1-uart", .data = &imx_uart_devdata[IMX1_UART], }, { .compatible = "fsl,imx21-uart", .data = &imx_uart_devdata[IMX21_UART], }, @@ -376,48 +358,6 @@ static void imx_stop_tx(struct uart_port *port) struct imx_port *sport = (struct imx_port *)port; unsigned long temp; - if (USE_IRDA(sport)) { - /* half duplex - wait for end of transmission */ - int n = 256; - while ((--n > 0) && - !(readl(sport->port.membase + USR2) & USR2_TXDC)) { - udelay(5); - barrier(); - } - /* - * irda transceiver - wait a bit more to avoid - * cutoff, hardware dependent - */ - udelay(sport->trcv_delay); - - /* - * half duplex - reactivate receive mode, - * flush receive pipe echo crap - */ - if (readl(sport->port.membase + USR2) & USR2_TXDC) { - temp = readl(sport->port.membase + UCR1); - temp &= ~(UCR1_TXMPTYEN | UCR1_TRDYEN); - writel(temp, sport->port.membase + UCR1); - - temp = readl(sport->port.membase + UCR4); - temp &= ~(UCR4_TCEN); - writel(temp, sport->port.membase + UCR4); - - while (readl(sport->port.membase + URXD0) & - URXD_CHARRDY) - barrier(); - - temp = readl(sport->port.membase + UCR1); - temp |= UCR1_RRDYEN; - writel(temp, sport->port.membase + UCR1); - - temp = readl(sport->port.membase + UCR4); - temp |= UCR4_DREN; - writel(temp, sport->port.membase + UCR4); - } - return; - } - /* * We are maybe in the SMP context, so if the DMA TX thread is running * on other cpu, we have to wait for it to finish. @@ -425,8 +365,23 @@ static void imx_stop_tx(struct uart_port *port) if (sport->dma_is_enabled && sport->dma_is_txing) return; - temp = readl(sport->port.membase + UCR1); - writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1); + temp = readl(port->membase + UCR1); + writel(temp & ~UCR1_TXMPTYEN, port->membase + UCR1); + + /* in rs485 mode disable transmitter if shifter is empty */ + if (port->rs485.flags & SER_RS485_ENABLED && + readl(port->membase + USR2) & USR2_TXDC) { + temp = readl(port->membase + UCR2); + if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND) + temp &= ~UCR2_CTS; + else + temp |= UCR2_CTS; + writel(temp, port->membase + UCR2); + + temp = readl(port->membase + UCR4); + temp &= ~UCR4_TCEN; + writel(temp, port->membase + UCR4); + } } /* @@ -620,15 +575,18 @@ static void imx_start_tx(struct uart_port *port) struct imx_port *sport = (struct imx_port *)port; unsigned long temp; - if (USE_IRDA(sport)) { - /* half duplex in IrDA mode; have to disable receive mode */ - temp = readl(sport->port.membase + UCR4); - temp &= ~(UCR4_DREN); - writel(temp, sport->port.membase + UCR4); + if (port->rs485.flags & SER_RS485_ENABLED) { + /* enable transmitter and shifter empty irq */ + temp = readl(port->membase + UCR2); + if (port->rs485.flags & SER_RS485_RTS_ON_SEND) + temp &= ~UCR2_CTS; + else + temp |= UCR2_CTS; + writel(temp, port->membase + UCR2); - temp = readl(sport->port.membase + UCR1); - temp &= ~(UCR1_RRDYEN); - writel(temp, sport->port.membase + UCR1); + temp = readl(port->membase + UCR4); + temp |= UCR4_TCEN; + writel(temp, port->membase + UCR4); } if (!sport->dma_is_enabled) { @@ -636,16 +594,6 @@ static void imx_start_tx(struct uart_port *port) writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1); } - if (USE_IRDA(sport)) { - temp = readl(sport->port.membase + UCR1); - temp |= UCR1_TRDYEN; - writel(temp, sport->port.membase + UCR1); - - temp = readl(sport->port.membase + UCR4); - temp |= UCR4_TCEN; - writel(temp, sport->port.membase + UCR4); - } - if (sport->dma_is_enabled) { if (sport->port.x_char) { /* We have X-char to send, so enable TX IRQ and @@ -796,6 +744,7 @@ static irqreturn_t imx_int(int irq, void *dev_id) unsigned int sts2; sts = readl(sport->port.membase + USR1); + sts2 = readl(sport->port.membase + USR2); if (sts & USR1_RRDY) { if (sport->dma_is_enabled) @@ -804,8 +753,10 @@ static irqreturn_t imx_int(int irq, void *dev_id) imx_rxint(irq, dev_id); } - if (sts & USR1_TRDY && - readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN) + if ((sts & USR1_TRDY && + readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN) || + (sts2 & USR2_TXDC && + readl(sport->port.membase + UCR4) & UCR4_TCEN)) imx_txint(irq, dev_id); if (sts & USR1_RTSD) @@ -814,11 +765,10 @@ static irqreturn_t imx_int(int irq, void *dev_id) if (sts & USR1_AWAKE) writel(USR1_AWAKE, sport->port.membase + USR1); - sts2 = readl(sport->port.membase + USR2); if (sts2 & USR2_ORE) { dev_err(sport->port.dev, "Rx FIFO overrun\n"); sport->port.icount.overrun++; - writel(sts2 | USR2_ORE, sport->port.membase + USR2); + writel(USR2_ORE, sport->port.membase + USR2); } return IRQ_HANDLED; @@ -866,11 +816,13 @@ static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl) struct imx_port *sport = (struct imx_port *)port; unsigned long temp; - temp = readl(sport->port.membase + UCR2) & ~(UCR2_CTS | UCR2_CTSC); - if (mctrl & TIOCM_RTS) - temp |= UCR2_CTS | UCR2_CTSC; - - writel(temp, sport->port.membase + UCR2); + if (!(port->rs485.flags & SER_RS485_ENABLED)) { + temp = readl(sport->port.membase + UCR2); + temp &= ~(UCR2_CTS | UCR2_CTSC); + if (mctrl & TIOCM_RTS) + temp |= UCR2_CTS | UCR2_CTSC; + writel(temp, sport->port.membase + UCR2); + } temp = readl(sport->port.membase + uts_reg(sport)) & ~UTS_LOOP; if (mctrl & TIOCM_LOOP) @@ -901,7 +853,7 @@ static void imx_break_ctl(struct uart_port *port, int break_state) #define TXTL 2 /* reset default */ #define RXTL 1 /* reset default */ -static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode) +static void imx_setup_ufcr(struct imx_port *sport, unsigned int mode) { unsigned int val; @@ -909,7 +861,6 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode) val = readl(sport->port.membase + UFCR) & (UFCR_RFDIV | UFCR_DCEDTE); val |= TXTL << UFCR_TXTL_SHF | RXTL; writel(val, sport->port.membase + UFCR); - return 0; } #define RX_BUF_SIZE (PAGE_SIZE) @@ -959,6 +910,14 @@ static void dma_rx_callback(void *data) status = dmaengine_tx_status(chan, (dma_cookie_t)0, &state); count = RX_BUF_SIZE - state.residue; + + if (readl(sport->port.membase + USR2) & USR2_IDLE) { + /* In condition [3] the SDMA counted up too early */ + count--; + + writel(USR2_IDLE, sport->port.membase + USR2); + } + dev_dbg(sport->port.dev, "We get %d bytes.\n", count); if (count) { @@ -1156,15 +1115,18 @@ static int imx_startup(struct uart_port *port) */ temp = readl(sport->port.membase + UCR4); - if (USE_IRDA(sport)) - temp |= UCR4_IRSC; - /* set the trigger level for CTS */ temp &= ~(UCR4_CTSTL_MASK << UCR4_CTSTL_SHF); temp |= CTSTL << UCR4_CTSTL_SHF; writel(temp & ~UCR4_DREN, sport->port.membase + UCR4); + /* Can we enable the DMA support? */ + if (is_imx6q_uart(sport) && !uart_console(port) && + !sport->dma_is_inited) + imx_uart_dma_init(sport); + + spin_lock_irqsave(&sport->port.lock, flags); /* Reset fifo's and state machines */ i = 100; @@ -1175,16 +1137,11 @@ static int imx_startup(struct uart_port *port) while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0)) udelay(1); - /* Can we enable the DMA support? */ - if (is_imx6q_uart(sport) && !uart_console(port) && - !sport->dma_is_inited) - imx_uart_dma_init(sport); - - spin_lock_irqsave(&sport->port.lock, flags); /* * Finally, clear and enable interrupts */ writel(USR1_RTSD, sport->port.membase + USR1); + writel(USR2_ORE, sport->port.membase + USR2); if (sport->dma_is_inited && !sport->dma_is_enabled) imx_enable_dma(sport); @@ -1192,17 +1149,8 @@ static int imx_startup(struct uart_port *port) temp = readl(sport->port.membase + UCR1); temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN; - if (USE_IRDA(sport)) { - temp |= UCR1_IREN; - temp &= ~(UCR1_RTSDEN); - } - writel(temp, sport->port.membase + UCR1); - /* Clear any pending ORE flag before enabling interrupt */ - temp = readl(sport->port.membase + USR2); - writel(temp | USR2_ORE, sport->port.membase + USR2); - temp = readl(sport->port.membase + UCR4); temp |= UCR4_OREN; writel(temp, sport->port.membase + UCR4); @@ -1219,38 +1167,12 @@ static int imx_startup(struct uart_port *port) writel(temp, sport->port.membase + UCR3); } - if (USE_IRDA(sport)) { - temp = readl(sport->port.membase + UCR4); - if (sport->irda_inv_rx) - temp |= UCR4_INVR; - else - temp &= ~(UCR4_INVR); - writel(temp | UCR4_DREN, sport->port.membase + UCR4); - - temp = readl(sport->port.membase + UCR3); - if (sport->irda_inv_tx) - temp |= UCR3_INVT; - else - temp &= ~(UCR3_INVT); - writel(temp, sport->port.membase + UCR3); - } - /* * Enable modem status interrupts */ imx_enable_ms(&sport->port); spin_unlock_irqrestore(&sport->port.lock, flags); - if (USE_IRDA(sport)) { - struct imxuart_platform_data *pdata; - pdata = dev_get_platdata(sport->port.dev); - sport->irda_inv_rx = pdata->irda_inv_rx; - sport->irda_inv_tx = pdata->irda_inv_tx; - sport->trcv_delay = pdata->transceiver_delay; - if (pdata->irda_enable) - pdata->irda_enable(1); - } - return 0; } @@ -1286,13 +1208,6 @@ static void imx_shutdown(struct uart_port *port) writel(temp, sport->port.membase + UCR2); spin_unlock_irqrestore(&sport->port.lock, flags); - if (USE_IRDA(sport)) { - struct imxuart_platform_data *pdata; - pdata = dev_get_platdata(sport->port.dev); - if (pdata->irda_enable) - pdata->irda_enable(0); - } - /* * Stop our timer. */ @@ -1305,8 +1220,6 @@ static void imx_shutdown(struct uart_port *port) spin_lock_irqsave(&sport->port.lock, flags); temp = readl(sport->port.membase + UCR1); temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN); - if (USE_IRDA(sport)) - temp &= ~(UCR1_IREN); writel(temp, sport->port.membase + UCR1); spin_unlock_irqrestore(&sport->port.lock, flags); @@ -1320,7 +1233,7 @@ static void imx_flush_buffer(struct uart_port *port) struct imx_port *sport = (struct imx_port *)port; struct scatterlist *sgl = &sport->tx_sgl[0]; unsigned long temp; - int i = 100, ubir, ubmr, ubrc, uts; + int i = 100, ubir, ubmr, uts; if (!sport->dma_chan_tx) return; @@ -1345,7 +1258,6 @@ static void imx_flush_buffer(struct uart_port *port) */ ubir = readl(sport->port.membase + UBIR); ubmr = readl(sport->port.membase + UBMR); - ubrc = readl(sport->port.membase + UBRC); uts = readl(sport->port.membase + IMX21_UTS); temp = readl(sport->port.membase + UCR2); @@ -1358,7 +1270,6 @@ static void imx_flush_buffer(struct uart_port *port) /* Restore the registers */ writel(ubir, sport->port.membase + UBIR); writel(ubmr, sport->port.membase + UBMR); - writel(ubrc, sport->port.membase + UBRC); writel(uts, sport->port.membase + IMX21_UTS); } @@ -1375,15 +1286,6 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, uint64_t tdiv64; /* - * If we don't support modem control lines, don't allow - * these to be set. - */ - if (0) { - termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR); - termios->c_cflag |= CLOCAL; - } - - /* * We only support CS7 and CS8. */ while ((termios->c_cflag & CSIZE) != CS7 && @@ -1401,11 +1303,26 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, if (termios->c_cflag & CRTSCTS) { if (sport->have_rtscts) { ucr2 &= ~UCR2_IRTS; - ucr2 |= UCR2_CTSC; + + if (port->rs485.flags & SER_RS485_ENABLED) { + /* + * RTS is mandatory for rs485 operation, so keep + * it under manual control and keep transmitter + * disabled. + */ + if (!(port->rs485.flags & + SER_RS485_RTS_AFTER_SEND)) + ucr2 |= UCR2_CTS; + } else { + ucr2 |= UCR2_CTSC; + } } else { termios->c_cflag &= ~CRTSCTS; } - } + } else if (port->rs485.flags & SER_RS485_ENABLED) + /* disable transmitter */ + if (!(port->rs485.flags & SER_RS485_RTS_AFTER_SEND)) + ucr2 |= UCR2_CTS; if (termios->c_cflag & CSTOPB) ucr2 |= UCR2_STPB; @@ -1471,24 +1388,16 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, sport->port.membase + UCR2); old_txrxen &= (UCR2_TXEN | UCR2_RXEN); - if (USE_IRDA(sport)) { - /* - * use maximum available submodule frequency to - * avoid missing short pulses due to low sampling rate - */ + /* custom-baudrate handling */ + div = sport->port.uartclk / (baud * 16); + if (baud == 38400 && quot != div) + baud = sport->port.uartclk / (quot * 16); + + div = sport->port.uartclk / (baud * 16); + if (div > 7) + div = 7; + if (!div) div = 1; - } else { - /* custom-baudrate handling */ - div = sport->port.uartclk / (baud * 16); - if (baud == 38400 && quot != div) - baud = sport->port.uartclk / (quot * 16); - - div = sport->port.uartclk / (baud * 16); - if (div > 7) - div = 7; - if (!div) - div = 1; - } rational_best_approximation(16 * div * baud, sport->port.uartclk, 1 << 16, 1 << 16, &num, &denom); @@ -1635,6 +1544,38 @@ static void imx_poll_put_char(struct uart_port *port, unsigned char c) } #endif +static int imx_rs485_config(struct uart_port *port, + struct serial_rs485 *rs485conf) +{ + struct imx_port *sport = (struct imx_port *)port; + + /* unimplemented */ + rs485conf->delay_rts_before_send = 0; + rs485conf->delay_rts_after_send = 0; + rs485conf->flags |= SER_RS485_RX_DURING_TX; + + /* RTS is required to control the transmitter */ + if (!sport->have_rtscts) + rs485conf->flags &= ~SER_RS485_ENABLED; + + if (rs485conf->flags & SER_RS485_ENABLED) { + unsigned long temp; + + /* disable transmitter */ + temp = readl(sport->port.membase + UCR2); + temp &= ~UCR2_CTSC; + if (rs485conf->flags & SER_RS485_RTS_AFTER_SEND) + temp &= ~UCR2_CTS; + else + temp |= UCR2_CTS; + writel(temp, sport->port.membase + UCR2); + } + + port->rs485 = *rs485conf; + + return 0; +} + static struct uart_ops imx_pops = { .tx_empty = imx_tx_empty, .set_mctrl = imx_set_mctrl, @@ -1927,9 +1868,6 @@ static int serial_imx_probe_dt(struct imx_port *sport, if (of_get_property(np, "fsl,uart-has-rtscts", NULL)) sport->have_rtscts = 1; - if (of_get_property(np, "fsl,irda-mode", NULL)) - sport->use_irda = 1; - if (of_get_property(np, "fsl,dte-mode", NULL)) sport->dte_mode = 1; @@ -1958,9 +1896,6 @@ static void serial_imx_probe_pdata(struct imx_port *sport, if (pdata->flags & IMXUART_HAVE_RTSCTS) sport->have_rtscts = 1; - - if (pdata->flags & IMXUART_IRDA) - sport->use_irda = 1; } static int serial_imx_probe(struct platform_device *pdev) @@ -1969,6 +1904,7 @@ static int serial_imx_probe(struct platform_device *pdev) void __iomem *base; int ret = 0; struct resource *res; + int txirq, rxirq, rtsirq; sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL); if (!sport) @@ -1985,17 +1921,21 @@ static int serial_imx_probe(struct platform_device *pdev) if (IS_ERR(base)) return PTR_ERR(base); + rxirq = platform_get_irq(pdev, 0); + txirq = platform_get_irq(pdev, 1); + rtsirq = platform_get_irq(pdev, 2); + sport->port.dev = &pdev->dev; sport->port.mapbase = res->start; sport->port.membase = base; sport->port.type = PORT_IMX, sport->port.iotype = UPIO_MEM; - sport->port.irq = platform_get_irq(pdev, 0); - sport->rxirq = platform_get_irq(pdev, 0); - sport->txirq = platform_get_irq(pdev, 1); - sport->rtsirq = platform_get_irq(pdev, 2); + sport->port.irq = rxirq; sport->port.fifosize = 32; sport->port.ops = &imx_pops; + sport->port.rs485_config = imx_rs485_config; + sport->port.rs485.flags = + SER_RS485_RTS_ON_SEND | SER_RS485_RX_DURING_TX; sport->port.flags = UPF_BOOT_AUTOCONF; init_timer(&sport->timer); sport->timer.function = imx_timeout; @@ -2021,27 +1961,18 @@ static int serial_imx_probe(struct platform_device *pdev) * Allocate the IRQ(s) i.MX1 has three interrupts whereas later * chips only have one interrupt. */ - if (sport->txirq > 0) { - ret = devm_request_irq(&pdev->dev, sport->rxirq, imx_rxint, 0, + if (txirq > 0) { + ret = devm_request_irq(&pdev->dev, rxirq, imx_rxint, 0, dev_name(&pdev->dev), sport); if (ret) return ret; - ret = devm_request_irq(&pdev->dev, sport->txirq, imx_txint, 0, + ret = devm_request_irq(&pdev->dev, txirq, imx_txint, 0, dev_name(&pdev->dev), sport); if (ret) return ret; - - /* do not use RTS IRQ on IrDA */ - if (!USE_IRDA(sport)) { - ret = devm_request_irq(&pdev->dev, sport->rtsirq, - imx_rtsint, 0, - dev_name(&pdev->dev), sport); - if (ret) - return ret; - } } else { - ret = devm_request_irq(&pdev->dev, sport->port.irq, imx_int, 0, + ret = devm_request_irq(&pdev->dev, rxirq, imx_int, 0, dev_name(&pdev->dev), sport); if (ret) return ret; diff --git a/drivers/tty/serial/ioc3_serial.c b/drivers/tty/serial/ioc3_serial.c index abd7ea26ed9a..27b5fefac171 100644 --- a/drivers/tty/serial/ioc3_serial.c +++ b/drivers/tty/serial/ioc3_serial.c @@ -2137,7 +2137,8 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd) /* register port with the serial core */ - if ((ret = ioc3_serial_core_attach(is, idd))) + ret = ioc3_serial_core_attach(is, idd); + if (ret) goto out4; Num_of_ioc3_cards++; diff --git a/drivers/tty/serial/ioc4_serial.c b/drivers/tty/serial/ioc4_serial.c index aa28209f44c1..e5c42fef69d2 100644 --- a/drivers/tty/serial/ioc4_serial.c +++ b/drivers/tty/serial/ioc4_serial.c @@ -1011,7 +1011,8 @@ static irqreturn_t ioc4_intr(int irq, void *arg) */ for (xx = 0; xx < num_intrs; xx++) { intr_info = &soft->is_intr_type[intr_type].is_intr_info[xx]; - if ((this_mir = this_ir & intr_info->sd_bits)) { + this_mir = this_ir & intr_info->sd_bits; + if (this_mir) { /* Disable owned interrupts, call handler */ handled++; write_ireg(soft, intr_info->sd_bits, IOC4_W_IEC, @@ -2865,10 +2866,12 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd) /* register port with the serial core - 1 rs232, 1 rs422 */ - if ((ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS232))) + ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS232); + if (ret) goto out4; - if ((ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS422))) + ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS422); + if (ret) goto out5; Num_of_ioc4_cards++; diff --git a/drivers/tty/serial/jsm/jsm_cls.c b/drivers/tty/serial/jsm/jsm_cls.c index bfb0681195b6..4eb12a9cae76 100644 --- a/drivers/tty/serial/jsm/jsm_cls.c +++ b/drivers/tty/serial/jsm/jsm_cls.c @@ -570,7 +570,7 @@ static inline void cls_parse_isr(struct jsm_board *brd, uint port) * verified in the interrupt routine. */ - if (port > brd->nasync) + if (port >= brd->nasync) return; ch = brd->channels[port]; diff --git a/drivers/tty/serial/jsm/jsm_neo.c b/drivers/tty/serial/jsm/jsm_neo.c index 7291c2117daa..932b2accd06f 100644 --- a/drivers/tty/serial/jsm/jsm_neo.c +++ b/drivers/tty/serial/jsm/jsm_neo.c @@ -724,7 +724,7 @@ static inline void neo_parse_isr(struct jsm_board *brd, u32 port) if (!brd) return; - if (port > brd->maxports) + if (port >= brd->maxports) return; ch = brd->channels[port]; @@ -840,7 +840,7 @@ static inline void neo_parse_lsr(struct jsm_board *brd, u32 port) if (!brd) return; - if (port > brd->maxports) + if (port >= brd->maxports) return; ch = brd->channels[port]; @@ -1180,7 +1180,7 @@ static irqreturn_t neo_intr(int irq, void *voidbrd) */ /* Verify the port is in range. */ - if (port > brd->nasync) + if (port >= brd->nasync) continue; ch = brd->channels[port]; diff --git a/drivers/tty/serial/kgdb_nmi.c b/drivers/tty/serial/kgdb_nmi.c index 129dc5be6028..117df151627d 100644 --- a/drivers/tty/serial/kgdb_nmi.c +++ b/drivers/tty/serial/kgdb_nmi.c @@ -173,18 +173,18 @@ static int kgdb_nmi_poll_one_knock(void) bool kgdb_nmi_poll_knock(void) { if (kgdb_nmi_knock < 0) - return 1; + return true; while (1) { int ret; ret = kgdb_nmi_poll_one_knock(); if (ret == NO_POLL_CHAR) - return 0; + return false; else if (ret == 1) break; } - return 1; + return true; } /* diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index 79f9a9eff545..077377259a2c 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -782,7 +782,7 @@ static int max3100_probe(struct spi_device *spi) pdata = dev_get_platdata(&spi->dev); max3100s[i]->crystal = pdata->crystal; max3100s[i]->loopback = pdata->loopback; - max3100s[i]->poll_time = pdata->poll_time * HZ / 1000; + max3100s[i]->poll_time = msecs_to_jiffies(pdata->poll_time); if (pdata->poll_time > 0 && max3100s[i]->poll_time == 0) max3100s[i]->poll_time = 1; max3100s[i]->max3100_hw_suspend = pdata->max3100_hw_suspend; diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c index a9b0ab38a68c..02eb32217685 100644 --- a/drivers/tty/serial/mcf.c +++ b/drivers/tty/serial/mcf.c @@ -597,7 +597,7 @@ console_initcall(mcf_console_init); #define MCF_CONSOLE NULL /****************************************************************************/ -#endif /* CONFIG_MCF_CONSOLE */ +#endif /* CONFIG_SERIAL_MCF_CONSOLE */ /****************************************************************************/ /* diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c index 67c036702629..0fc83c962d10 100644 --- a/drivers/tty/serial/meson_uart.c +++ b/drivers/tty/serial/meson_uart.c @@ -370,7 +370,7 @@ static int meson_uart_verify_port(struct uart_port *port, static void meson_uart_release_port(struct uart_port *port) { if (port->flags & UPF_IOREMAP) { - iounmap(port->membase); + devm_iounmap(port->dev, port->membase); port->membase = NULL; } } diff --git a/drivers/tty/serial/mfd.c b/drivers/tty/serial/mfd.c deleted file mode 100644 index 8fe4501d7565..000000000000 --- a/drivers/tty/serial/mfd.c +++ /dev/null @@ -1,1505 +0,0 @@ -/* - * mfd.c: driver for High Speed UART device of Intel Medfield platform - * - * Refer pxa.c, 8250.c and some other drivers in drivers/serial/ - * - * (C) Copyright 2010 Intel Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; version 2 - * of the License. - */ - -/* Notes: - * 1. DMA channel allocation: 0/1 channel are assigned to port 0, - * 2/3 chan to port 1, 4/5 chan to port 3. Even number chans - * are used for RX, odd chans for TX - * - * 2. The RI/DSR/DCD/DTR are not pinned out, DCD & DSR are always - * asserted, only when the HW is reset the DDCD and DDSR will - * be triggered - */ - -#if defined(CONFIG_SERIAL_MFD_HSU_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/console.h> -#include <linux/sysrq.h> -#include <linux/slab.h> -#include <linux/serial_reg.h> -#include <linux/circ_buf.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/serial_core.h> -#include <linux/serial_mfd.h> -#include <linux/dma-mapping.h> -#include <linux/pci.h> -#include <linux/nmi.h> -#include <linux/io.h> -#include <linux/debugfs.h> -#include <linux/pm_runtime.h> - -#define HSU_DMA_BUF_SIZE 2048 - -#define chan_readl(chan, offset) readl(chan->reg + offset) -#define chan_writel(chan, offset, val) writel(val, chan->reg + offset) - -#define mfd_readl(obj, offset) readl(obj->reg + offset) -#define mfd_writel(obj, offset, val) writel(val, obj->reg + offset) - -static int hsu_dma_enable; -module_param(hsu_dma_enable, int, 0); -MODULE_PARM_DESC(hsu_dma_enable, - "It is a bitmap to set working mode, if bit[x] is 1, then port[x] will work in DMA mode, otherwise in PIO mode."); - -struct hsu_dma_buffer { - u8 *buf; - dma_addr_t dma_addr; - u32 dma_size; - u32 ofs; -}; - -struct hsu_dma_chan { - u32 id; - enum dma_data_direction dirt; - struct uart_hsu_port *uport; - void __iomem *reg; -}; - -struct uart_hsu_port { - struct uart_port port; - unsigned char ier; - unsigned char lcr; - unsigned char mcr; - unsigned int lsr_break_flag; - char name[12]; - int index; - struct device *dev; - - struct hsu_dma_chan *txc; - struct hsu_dma_chan *rxc; - struct hsu_dma_buffer txbuf; - struct hsu_dma_buffer rxbuf; - int use_dma; /* flag for DMA/PIO */ - int running; - int dma_tx_on; -}; - -/* Top level data structure of HSU */ -struct hsu_port { - void __iomem *reg; - unsigned long paddr; - unsigned long iolen; - u32 irq; - - struct uart_hsu_port port[3]; - struct hsu_dma_chan chans[10]; - - struct dentry *debugfs; -}; - -static inline unsigned int serial_in(struct uart_hsu_port *up, int offset) -{ - unsigned int val; - - if (offset > UART_MSR) { - offset <<= 2; - val = readl(up->port.membase + offset); - } else - val = (unsigned int)readb(up->port.membase + offset); - - return val; -} - -static inline void serial_out(struct uart_hsu_port *up, int offset, int value) -{ - if (offset > UART_MSR) { - offset <<= 2; - writel(value, up->port.membase + offset); - } else { - unsigned char val = value & 0xff; - writeb(val, up->port.membase + offset); - } -} - -#ifdef CONFIG_DEBUG_FS - -#define HSU_REGS_BUFSIZE 1024 - - -static ssize_t port_show_regs(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct uart_hsu_port *up = file->private_data; - char *buf; - u32 len = 0; - ssize_t ret; - - buf = kzalloc(HSU_REGS_BUFSIZE, GFP_KERNEL); - if (!buf) - return 0; - - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "MFD HSU port[%d] regs:\n", up->index); - - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "=================================\n"); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "IER: \t\t0x%08x\n", serial_in(up, UART_IER)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "IIR: \t\t0x%08x\n", serial_in(up, UART_IIR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "LCR: \t\t0x%08x\n", serial_in(up, UART_LCR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "MCR: \t\t0x%08x\n", serial_in(up, UART_MCR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "LSR: \t\t0x%08x\n", serial_in(up, UART_LSR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "MSR: \t\t0x%08x\n", serial_in(up, UART_MSR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "FOR: \t\t0x%08x\n", serial_in(up, UART_FOR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "PS: \t\t0x%08x\n", serial_in(up, UART_PS)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "MUL: \t\t0x%08x\n", serial_in(up, UART_MUL)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "DIV: \t\t0x%08x\n", serial_in(up, UART_DIV)); - - if (len > HSU_REGS_BUFSIZE) - len = HSU_REGS_BUFSIZE; - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); - return ret; -} - -static ssize_t dma_show_regs(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct hsu_dma_chan *chan = file->private_data; - char *buf; - u32 len = 0; - ssize_t ret; - - buf = kzalloc(HSU_REGS_BUFSIZE, GFP_KERNEL); - if (!buf) - return 0; - - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "MFD HSU DMA channel [%d] regs:\n", chan->id); - - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "=================================\n"); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "CR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_CR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "DCR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_DCR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "BSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_BSR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "MOTSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_MOTSR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D0SAR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D0TSR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D1SAR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D1TSR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D2SAR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D2TSR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D3SAR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D3TSR)); - - if (len > HSU_REGS_BUFSIZE) - len = HSU_REGS_BUFSIZE; - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); - return ret; -} - -static const struct file_operations port_regs_ops = { - .owner = THIS_MODULE, - .open = simple_open, - .read = port_show_regs, - .llseek = default_llseek, -}; - -static const struct file_operations dma_regs_ops = { - .owner = THIS_MODULE, - .open = simple_open, - .read = dma_show_regs, - .llseek = default_llseek, -}; - -static int hsu_debugfs_init(struct hsu_port *hsu) -{ - int i; - char name[32]; - - hsu->debugfs = debugfs_create_dir("hsu", NULL); - if (!hsu->debugfs) - return -ENOMEM; - - for (i = 0; i < 3; i++) { - snprintf(name, sizeof(name), "port_%d_regs", i); - debugfs_create_file(name, S_IFREG | S_IRUGO, - hsu->debugfs, (void *)(&hsu->port[i]), &port_regs_ops); - } - - for (i = 0; i < 6; i++) { - snprintf(name, sizeof(name), "dma_chan_%d_regs", i); - debugfs_create_file(name, S_IFREG | S_IRUGO, - hsu->debugfs, (void *)&hsu->chans[i], &dma_regs_ops); - } - - return 0; -} - -static void hsu_debugfs_remove(struct hsu_port *hsu) -{ - if (hsu->debugfs) - debugfs_remove_recursive(hsu->debugfs); -} - -#else -static inline int hsu_debugfs_init(struct hsu_port *hsu) -{ - return 0; -} - -static inline void hsu_debugfs_remove(struct hsu_port *hsu) -{ -} -#endif /* CONFIG_DEBUG_FS */ - -static void serial_hsu_enable_ms(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - - up->ier |= UART_IER_MSI; - serial_out(up, UART_IER, up->ier); -} - -static void hsu_dma_tx(struct uart_hsu_port *up) -{ - struct circ_buf *xmit = &up->port.state->xmit; - struct hsu_dma_buffer *dbuf = &up->txbuf; - int count; - - /* test_and_set_bit may be better, but anyway it's in lock protected mode */ - if (up->dma_tx_on) - return; - - /* Update the circ buf info */ - xmit->tail += dbuf->ofs; - xmit->tail &= UART_XMIT_SIZE - 1; - - up->port.icount.tx += dbuf->ofs; - dbuf->ofs = 0; - - /* Disable the channel */ - chan_writel(up->txc, HSU_CH_CR, 0x0); - - if (!uart_circ_empty(xmit) && !uart_tx_stopped(&up->port)) { - dma_sync_single_for_device(up->port.dev, - dbuf->dma_addr, - dbuf->dma_size, - DMA_TO_DEVICE); - - count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); - dbuf->ofs = count; - - /* Reprogram the channel */ - chan_writel(up->txc, HSU_CH_D0SAR, dbuf->dma_addr + xmit->tail); - chan_writel(up->txc, HSU_CH_D0TSR, count); - - /* Reenable the channel */ - chan_writel(up->txc, HSU_CH_DCR, 0x1 - | (0x1 << 8) - | (0x1 << 16) - | (0x1 << 24)); - up->dma_tx_on = 1; - chan_writel(up->txc, HSU_CH_CR, 0x1); - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); -} - -/* The buffer is already cache coherent */ -static void hsu_dma_start_rx_chan(struct hsu_dma_chan *rxc, - struct hsu_dma_buffer *dbuf) -{ - dbuf->ofs = 0; - - chan_writel(rxc, HSU_CH_BSR, 32); - chan_writel(rxc, HSU_CH_MOTSR, 4); - - chan_writel(rxc, HSU_CH_D0SAR, dbuf->dma_addr); - chan_writel(rxc, HSU_CH_D0TSR, dbuf->dma_size); - chan_writel(rxc, HSU_CH_DCR, 0x1 | (0x1 << 8) - | (0x1 << 16) - | (0x1 << 24) /* timeout bit, see HSU Errata 1 */ - ); - chan_writel(rxc, HSU_CH_CR, 0x3); -} - -/* Protected by spin_lock_irqsave(port->lock) */ -static void serial_hsu_start_tx(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - - if (up->use_dma) { - hsu_dma_tx(up); - } else if (!(up->ier & UART_IER_THRI)) { - up->ier |= UART_IER_THRI; - serial_out(up, UART_IER, up->ier); - } -} - -static void serial_hsu_stop_tx(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - struct hsu_dma_chan *txc = up->txc; - - if (up->use_dma) - chan_writel(txc, HSU_CH_CR, 0x0); - else if (up->ier & UART_IER_THRI) { - up->ier &= ~UART_IER_THRI; - serial_out(up, UART_IER, up->ier); - } -} - -/* This is always called in spinlock protected mode, so - * modify timeout timer is safe here */ -static void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts, - unsigned long *flags) -{ - struct hsu_dma_buffer *dbuf = &up->rxbuf; - struct hsu_dma_chan *chan = up->rxc; - struct uart_port *port = &up->port; - struct tty_port *tport = &port->state->port; - int count; - - /* - * First need to know how many is already transferred, - * then check if its a timeout DMA irq, and return - * the trail bytes out, push them up and reenable the - * channel - */ - - /* Timeout IRQ, need wait some time, see Errata 2 */ - if (int_sts & 0xf00) - udelay(2); - - /* Stop the channel */ - chan_writel(chan, HSU_CH_CR, 0x0); - - count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr; - if (!count) { - /* Restart the channel before we leave */ - chan_writel(chan, HSU_CH_CR, 0x3); - return; - } - - dma_sync_single_for_cpu(port->dev, dbuf->dma_addr, - dbuf->dma_size, DMA_FROM_DEVICE); - - /* - * Head will only wrap around when we recycle - * the DMA buffer, and when that happens, we - * explicitly set tail to 0. So head will - * always be greater than tail. - */ - tty_insert_flip_string(tport, dbuf->buf, count); - port->icount.rx += count; - - dma_sync_single_for_device(up->port.dev, dbuf->dma_addr, - dbuf->dma_size, DMA_FROM_DEVICE); - - /* Reprogram the channel */ - chan_writel(chan, HSU_CH_D0SAR, dbuf->dma_addr); - chan_writel(chan, HSU_CH_D0TSR, dbuf->dma_size); - chan_writel(chan, HSU_CH_DCR, 0x1 - | (0x1 << 8) - | (0x1 << 16) - | (0x1 << 24) /* timeout bit, see HSU Errata 1 */ - ); - spin_unlock_irqrestore(&up->port.lock, *flags); - tty_flip_buffer_push(tport); - spin_lock_irqsave(&up->port.lock, *flags); - - chan_writel(chan, HSU_CH_CR, 0x3); - -} - -static void serial_hsu_stop_rx(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - struct hsu_dma_chan *chan = up->rxc; - - if (up->use_dma) - chan_writel(chan, HSU_CH_CR, 0x2); - else { - up->ier &= ~UART_IER_RLSI; - up->port.read_status_mask &= ~UART_LSR_DR; - serial_out(up, UART_IER, up->ier); - } -} - -static inline void receive_chars(struct uart_hsu_port *up, int *status, - unsigned long *flags) -{ - unsigned int ch, flag; - unsigned int max_count = 256; - - do { - ch = serial_in(up, UART_RX); - flag = TTY_NORMAL; - up->port.icount.rx++; - - if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE | - UART_LSR_FE | UART_LSR_OE))) { - - dev_warn(up->dev, "We really rush into ERR/BI case" - "status = 0x%02x", *status); - /* For statistics only */ - if (*status & UART_LSR_BI) { - *status &= ~(UART_LSR_FE | UART_LSR_PE); - up->port.icount.brk++; - /* - * We do the SysRQ and SAK checking - * here because otherwise the break - * may get masked by ignore_status_mask - * or read_status_mask. - */ - if (uart_handle_break(&up->port)) - goto ignore_char; - } else if (*status & UART_LSR_PE) - up->port.icount.parity++; - else if (*status & UART_LSR_FE) - up->port.icount.frame++; - if (*status & UART_LSR_OE) - up->port.icount.overrun++; - - /* Mask off conditions which should be ignored. */ - *status &= up->port.read_status_mask; - -#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE - if (up->port.cons && - up->port.cons->index == up->port.line) { - /* Recover the break flag from console xmit */ - *status |= up->lsr_break_flag; - up->lsr_break_flag = 0; - } -#endif - if (*status & UART_LSR_BI) { - flag = TTY_BREAK; - } else if (*status & UART_LSR_PE) - flag = TTY_PARITY; - else if (*status & UART_LSR_FE) - flag = TTY_FRAME; - } - - if (uart_handle_sysrq_char(&up->port, ch)) - goto ignore_char; - - uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag); - ignore_char: - *status = serial_in(up, UART_LSR); - } while ((*status & UART_LSR_DR) && max_count--); - - spin_unlock_irqrestore(&up->port.lock, *flags); - tty_flip_buffer_push(&up->port.state->port); - spin_lock_irqsave(&up->port.lock, *flags); -} - -static void transmit_chars(struct uart_hsu_port *up) -{ - struct circ_buf *xmit = &up->port.state->xmit; - int count; - - if (up->port.x_char) { - serial_out(up, UART_TX, up->port.x_char); - up->port.icount.tx++; - up->port.x_char = 0; - return; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { - serial_hsu_stop_tx(&up->port); - return; - } - - /* The IRQ is for TX FIFO half-empty */ - count = up->port.fifosize / 2; - - do { - serial_out(up, UART_TX, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - - up->port.icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (--count > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); - - if (uart_circ_empty(xmit)) - serial_hsu_stop_tx(&up->port); -} - -static inline void check_modem_status(struct uart_hsu_port *up) -{ - int status; - - status = serial_in(up, UART_MSR); - - if ((status & UART_MSR_ANY_DELTA) == 0) - return; - - if (status & UART_MSR_TERI) - up->port.icount.rng++; - if (status & UART_MSR_DDSR) - up->port.icount.dsr++; - /* We may only get DDCD when HW init and reset */ - if (status & UART_MSR_DDCD) - uart_handle_dcd_change(&up->port, status & UART_MSR_DCD); - /* Will start/stop_tx accordingly */ - if (status & UART_MSR_DCTS) - uart_handle_cts_change(&up->port, status & UART_MSR_CTS); - - wake_up_interruptible(&up->port.state->port.delta_msr_wait); -} - -/* - * This handles the interrupt from one port. - */ -static irqreturn_t port_irq(int irq, void *dev_id) -{ - struct uart_hsu_port *up = dev_id; - unsigned int iir, lsr; - unsigned long flags; - - if (unlikely(!up->running)) - return IRQ_NONE; - - spin_lock_irqsave(&up->port.lock, flags); - if (up->use_dma) { - lsr = serial_in(up, UART_LSR); - if (unlikely(lsr & (UART_LSR_BI | UART_LSR_PE | - UART_LSR_FE | UART_LSR_OE))) - dev_warn(up->dev, - "Got lsr irq while using DMA, lsr = 0x%2x\n", - lsr); - check_modem_status(up); - spin_unlock_irqrestore(&up->port.lock, flags); - return IRQ_HANDLED; - } - - iir = serial_in(up, UART_IIR); - if (iir & UART_IIR_NO_INT) { - spin_unlock_irqrestore(&up->port.lock, flags); - return IRQ_NONE; - } - - lsr = serial_in(up, UART_LSR); - if (lsr & UART_LSR_DR) - receive_chars(up, &lsr, &flags); - check_modem_status(up); - - /* lsr will be renewed during the receive_chars */ - if (lsr & UART_LSR_THRE) - transmit_chars(up); - - spin_unlock_irqrestore(&up->port.lock, flags); - return IRQ_HANDLED; -} - -static inline void dma_chan_irq(struct hsu_dma_chan *chan) -{ - struct uart_hsu_port *up = chan->uport; - unsigned long flags; - u32 int_sts; - - spin_lock_irqsave(&up->port.lock, flags); - - if (!up->use_dma || !up->running) - goto exit; - - /* - * No matter what situation, need read clear the IRQ status - * There is a bug, see Errata 5, HSD 2900918 - */ - int_sts = chan_readl(chan, HSU_CH_SR); - - /* Rx channel */ - if (chan->dirt == DMA_FROM_DEVICE) - hsu_dma_rx(up, int_sts, &flags); - - /* Tx channel */ - if (chan->dirt == DMA_TO_DEVICE) { - chan_writel(chan, HSU_CH_CR, 0x0); - up->dma_tx_on = 0; - hsu_dma_tx(up); - } - -exit: - spin_unlock_irqrestore(&up->port.lock, flags); - return; -} - -static irqreturn_t dma_irq(int irq, void *dev_id) -{ - struct hsu_port *hsu = dev_id; - u32 int_sts, i; - - int_sts = mfd_readl(hsu, HSU_GBL_DMAISR); - - /* Currently we only have 6 channels may be used */ - for (i = 0; i < 6; i++) { - if (int_sts & 0x1) - dma_chan_irq(&hsu->chans[i]); - int_sts >>= 1; - } - - return IRQ_HANDLED; -} - -static unsigned int serial_hsu_tx_empty(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - unsigned long flags; - unsigned int ret; - - spin_lock_irqsave(&up->port.lock, flags); - ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0; - spin_unlock_irqrestore(&up->port.lock, flags); - - return ret; -} - -static unsigned int serial_hsu_get_mctrl(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - unsigned char status; - unsigned int ret; - - status = serial_in(up, UART_MSR); - - ret = 0; - if (status & UART_MSR_DCD) - ret |= TIOCM_CAR; - if (status & UART_MSR_RI) - ret |= TIOCM_RNG; - if (status & UART_MSR_DSR) - ret |= TIOCM_DSR; - if (status & UART_MSR_CTS) - ret |= TIOCM_CTS; - return ret; -} - -static void serial_hsu_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - unsigned char mcr = 0; - - if (mctrl & TIOCM_RTS) - mcr |= UART_MCR_RTS; - if (mctrl & TIOCM_DTR) - mcr |= UART_MCR_DTR; - if (mctrl & TIOCM_OUT1) - mcr |= UART_MCR_OUT1; - if (mctrl & TIOCM_OUT2) - mcr |= UART_MCR_OUT2; - if (mctrl & TIOCM_LOOP) - mcr |= UART_MCR_LOOP; - - mcr |= up->mcr; - - serial_out(up, UART_MCR, mcr); -} - -static void serial_hsu_break_ctl(struct uart_port *port, int break_state) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - unsigned long flags; - - spin_lock_irqsave(&up->port.lock, flags); - if (break_state == -1) - up->lcr |= UART_LCR_SBC; - else - up->lcr &= ~UART_LCR_SBC; - serial_out(up, UART_LCR, up->lcr); - spin_unlock_irqrestore(&up->port.lock, flags); -} - -/* - * What special to do: - * 1. chose the 64B fifo mode - * 2. start dma or pio depends on configuration - * 3. we only allocate dma memory when needed - */ -static int serial_hsu_startup(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - unsigned long flags; - - pm_runtime_get_sync(up->dev); - - /* - * Clear the FIFO buffers and disable them. - * (they will be reenabled in set_termios()) - */ - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); - serial_out(up, UART_FCR, 0); - - /* Clear the interrupt registers. */ - (void) serial_in(up, UART_LSR); - (void) serial_in(up, UART_RX); - (void) serial_in(up, UART_IIR); - (void) serial_in(up, UART_MSR); - - /* Now, initialize the UART, default is 8n1 */ - serial_out(up, UART_LCR, UART_LCR_WLEN8); - - spin_lock_irqsave(&up->port.lock, flags); - - up->port.mctrl |= TIOCM_OUT2; - serial_hsu_set_mctrl(&up->port, up->port.mctrl); - - /* - * Finally, enable interrupts. Note: Modem status interrupts - * are set via set_termios(), which will be occurring imminently - * anyway, so we don't enable them here. - */ - if (!up->use_dma) - up->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE; - else - up->ier = 0; - serial_out(up, UART_IER, up->ier); - - spin_unlock_irqrestore(&up->port.lock, flags); - - /* DMA init */ - if (up->use_dma) { - struct hsu_dma_buffer *dbuf; - struct circ_buf *xmit = &port->state->xmit; - - up->dma_tx_on = 0; - - /* First allocate the RX buffer */ - dbuf = &up->rxbuf; - dbuf->buf = kzalloc(HSU_DMA_BUF_SIZE, GFP_KERNEL); - if (!dbuf->buf) { - up->use_dma = 0; - goto exit; - } - dbuf->dma_addr = dma_map_single(port->dev, - dbuf->buf, - HSU_DMA_BUF_SIZE, - DMA_FROM_DEVICE); - dbuf->dma_size = HSU_DMA_BUF_SIZE; - - /* Start the RX channel right now */ - hsu_dma_start_rx_chan(up->rxc, dbuf); - - /* Next init the TX DMA */ - dbuf = &up->txbuf; - dbuf->buf = xmit->buf; - dbuf->dma_addr = dma_map_single(port->dev, - dbuf->buf, - UART_XMIT_SIZE, - DMA_TO_DEVICE); - dbuf->dma_size = UART_XMIT_SIZE; - - /* This should not be changed all around */ - chan_writel(up->txc, HSU_CH_BSR, 32); - chan_writel(up->txc, HSU_CH_MOTSR, 4); - dbuf->ofs = 0; - } - -exit: - /* And clear the interrupt registers again for luck. */ - (void) serial_in(up, UART_LSR); - (void) serial_in(up, UART_RX); - (void) serial_in(up, UART_IIR); - (void) serial_in(up, UART_MSR); - - up->running = 1; - return 0; -} - -static void serial_hsu_shutdown(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - unsigned long flags; - - /* Disable interrupts from this port */ - up->ier = 0; - serial_out(up, UART_IER, 0); - up->running = 0; - - spin_lock_irqsave(&up->port.lock, flags); - up->port.mctrl &= ~TIOCM_OUT2; - serial_hsu_set_mctrl(&up->port, up->port.mctrl); - spin_unlock_irqrestore(&up->port.lock, flags); - - /* Disable break condition and FIFOs */ - serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC); - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | - UART_FCR_CLEAR_XMIT); - serial_out(up, UART_FCR, 0); - - pm_runtime_put(up->dev); -} - -static void -serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - unsigned char cval, fcr = 0; - unsigned long flags; - unsigned int baud, quot; - u32 ps, mul; - - switch (termios->c_cflag & CSIZE) { - case CS5: - cval = UART_LCR_WLEN5; - break; - case CS6: - cval = UART_LCR_WLEN6; - break; - case CS7: - cval = UART_LCR_WLEN7; - break; - default: - case CS8: - cval = UART_LCR_WLEN8; - break; - } - - /* CMSPAR isn't supported by this driver */ - termios->c_cflag &= ~CMSPAR; - - if (termios->c_cflag & CSTOPB) - cval |= UART_LCR_STOP; - if (termios->c_cflag & PARENB) - cval |= UART_LCR_PARITY; - if (!(termios->c_cflag & PARODD)) - cval |= UART_LCR_EPAR; - - /* - * The base clk is 50Mhz, and the baud rate come from: - * baud = 50M * MUL / (DIV * PS * DLAB) - * - * For those basic low baud rate we can get the direct - * scalar from 2746800, like 115200 = 2746800/24. For those - * higher baud rate, we handle them case by case, mainly by - * adjusting the MUL/PS registers, and DIV register is kept - * as default value 0x3d09 to make things simple - */ - baud = uart_get_baud_rate(port, termios, old, 0, 4000000); - - quot = 1; - ps = 0x10; - mul = 0x3600; - switch (baud) { - case 3500000: - mul = 0x3345; - ps = 0xC; - break; - case 1843200: - mul = 0x2400; - break; - case 3000000: - case 2500000: - case 2000000: - case 1500000: - case 1000000: - case 500000: - /* mul/ps/quot = 0x9C4/0x10/0x1 will make a 500000 bps */ - mul = baud / 500000 * 0x9C4; - break; - default: - /* Use uart_get_divisor to get quot for other baud rates */ - quot = 0; - } - - if (!quot) - quot = uart_get_divisor(port, baud); - - if ((up->port.uartclk / quot) < (2400 * 16)) - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_1B; - else if ((up->port.uartclk / quot) < (230400 * 16)) - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_16B; - else - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_32B; - - fcr |= UART_FCR_HSU_64B_FIFO; - - /* - * Ok, we're now changing the port state. Do it with - * interrupts disabled. - */ - spin_lock_irqsave(&up->port.lock, flags); - - /* Update the per-port timeout */ - uart_update_timeout(port, termios->c_cflag, baud); - - up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; - if (termios->c_iflag & INPCK) - up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) - up->port.read_status_mask |= UART_LSR_BI; - - /* Characters to ignore */ - up->port.ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; - if (termios->c_iflag & IGNBRK) { - up->port.ignore_status_mask |= UART_LSR_BI; - /* - * If we're ignoring parity and break indicators, - * ignore overruns too (for real raw support). - */ - if (termios->c_iflag & IGNPAR) - up->port.ignore_status_mask |= UART_LSR_OE; - } - - /* Ignore all characters if CREAD is not set */ - if ((termios->c_cflag & CREAD) == 0) - up->port.ignore_status_mask |= UART_LSR_DR; - - /* - * CTS flow control flag and modem status interrupts, disable - * MSI by default - */ - up->ier &= ~UART_IER_MSI; - if (UART_ENABLE_MS(&up->port, termios->c_cflag)) - up->ier |= UART_IER_MSI; - - serial_out(up, UART_IER, up->ier); - - if (termios->c_cflag & CRTSCTS) - up->mcr |= UART_MCR_AFE | UART_MCR_RTS; - else - up->mcr &= ~UART_MCR_AFE; - - serial_out(up, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */ - serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */ - serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */ - serial_out(up, UART_LCR, cval); /* reset DLAB */ - serial_out(up, UART_MUL, mul); /* set MUL */ - serial_out(up, UART_PS, ps); /* set PS */ - up->lcr = cval; /* Save LCR */ - serial_hsu_set_mctrl(&up->port, up->port.mctrl); - serial_out(up, UART_FCR, fcr); - spin_unlock_irqrestore(&up->port.lock, flags); -} - -static void -serial_hsu_pm(struct uart_port *port, unsigned int state, - unsigned int oldstate) -{ -} - -static void serial_hsu_release_port(struct uart_port *port) -{ -} - -static int serial_hsu_request_port(struct uart_port *port) -{ - return 0; -} - -static void serial_hsu_config_port(struct uart_port *port, int flags) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - up->port.type = PORT_MFD; -} - -static int -serial_hsu_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - /* We don't want the core code to modify any port params */ - return -EINVAL; -} - -static const char * -serial_hsu_type(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - return up->name; -} - -/* Mainly for uart console use */ -static struct uart_hsu_port *serial_hsu_ports[3]; -static struct uart_driver serial_hsu_reg; - -#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE - -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - -/* Wait for transmitter & holding register to empty */ -static inline void wait_for_xmitr(struct uart_hsu_port *up) -{ - unsigned int status, tmout = 1000; - - /* Wait up to 1ms for the character to be sent. */ - do { - status = serial_in(up, UART_LSR); - - if (status & UART_LSR_BI) - up->lsr_break_flag = UART_LSR_BI; - - if (--tmout == 0) - break; - udelay(1); - } while (!(status & BOTH_EMPTY)); - - /* Wait up to 1s for flow control if necessary */ - if (up->port.flags & UPF_CONS_FLOW) { - tmout = 1000000; - while (--tmout && - ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0)) - udelay(1); - } -} - -static void serial_hsu_console_putchar(struct uart_port *port, int ch) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - - wait_for_xmitr(up); - serial_out(up, UART_TX, ch); -} - -/* - * Print a string to the serial port trying not to disturb - * any possible real use of the port... - * - * The console_lock must be held when we get here. - */ -static void -serial_hsu_console_write(struct console *co, const char *s, unsigned int count) -{ - struct uart_hsu_port *up = serial_hsu_ports[co->index]; - unsigned long flags; - unsigned int ier; - int locked = 1; - - touch_nmi_watchdog(); - - local_irq_save(flags); - if (up->port.sysrq) - locked = 0; - else if (oops_in_progress) { - locked = spin_trylock(&up->port.lock); - } else - spin_lock(&up->port.lock); - - /* First save the IER then disable the interrupts */ - ier = serial_in(up, UART_IER); - serial_out(up, UART_IER, 0); - - uart_console_write(&up->port, s, count, serial_hsu_console_putchar); - - /* - * Finally, wait for transmitter to become empty - * and restore the IER - */ - wait_for_xmitr(up); - serial_out(up, UART_IER, ier); - - if (locked) - spin_unlock(&up->port.lock); - local_irq_restore(flags); -} - -static struct console serial_hsu_console; - -static int __init -serial_hsu_console_setup(struct console *co, char *options) -{ - struct uart_hsu_port *up; - int baud = 115200; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - if (co->index == -1 || co->index >= serial_hsu_reg.nr) - co->index = 0; - up = serial_hsu_ports[co->index]; - if (!up) - return -ENODEV; - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - - return uart_set_options(&up->port, co, baud, parity, bits, flow); -} - -static struct console serial_hsu_console = { - .name = "ttyMFD", - .write = serial_hsu_console_write, - .device = uart_console_device, - .setup = serial_hsu_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &serial_hsu_reg, -}; - -#define SERIAL_HSU_CONSOLE (&serial_hsu_console) -#else -#define SERIAL_HSU_CONSOLE NULL -#endif - -static struct uart_ops serial_hsu_pops = { - .tx_empty = serial_hsu_tx_empty, - .set_mctrl = serial_hsu_set_mctrl, - .get_mctrl = serial_hsu_get_mctrl, - .stop_tx = serial_hsu_stop_tx, - .start_tx = serial_hsu_start_tx, - .stop_rx = serial_hsu_stop_rx, - .enable_ms = serial_hsu_enable_ms, - .break_ctl = serial_hsu_break_ctl, - .startup = serial_hsu_startup, - .shutdown = serial_hsu_shutdown, - .set_termios = serial_hsu_set_termios, - .pm = serial_hsu_pm, - .type = serial_hsu_type, - .release_port = serial_hsu_release_port, - .request_port = serial_hsu_request_port, - .config_port = serial_hsu_config_port, - .verify_port = serial_hsu_verify_port, -}; - -static struct uart_driver serial_hsu_reg = { - .owner = THIS_MODULE, - .driver_name = "MFD serial", - .dev_name = "ttyMFD", - .major = TTY_MAJOR, - .minor = 128, - .nr = 3, - .cons = SERIAL_HSU_CONSOLE, -}; - -#ifdef CONFIG_PM -static int serial_hsu_suspend(struct pci_dev *pdev, pm_message_t state) -{ - void *priv = pci_get_drvdata(pdev); - struct uart_hsu_port *up; - - /* Make sure this is not the internal dma controller */ - if (priv && (pdev->device != 0x081E)) { - up = priv; - uart_suspend_port(&serial_hsu_reg, &up->port); - } - - pci_save_state(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - return 0; -} - -static int serial_hsu_resume(struct pci_dev *pdev) -{ - void *priv = pci_get_drvdata(pdev); - struct uart_hsu_port *up; - int ret; - - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - - ret = pci_enable_device(pdev); - if (ret) - dev_warn(&pdev->dev, - "HSU: can't re-enable device, try to continue\n"); - - if (priv && (pdev->device != 0x081E)) { - up = priv; - uart_resume_port(&serial_hsu_reg, &up->port); - } - return 0; -} - -static int serial_hsu_runtime_idle(struct device *dev) -{ - pm_schedule_suspend(dev, 500); - return -EBUSY; -} - -static int serial_hsu_runtime_suspend(struct device *dev) -{ - return 0; -} - -static int serial_hsu_runtime_resume(struct device *dev) -{ - return 0; -} -#else -#define serial_hsu_suspend NULL -#define serial_hsu_resume NULL -#define serial_hsu_runtime_idle NULL -#define serial_hsu_runtime_suspend NULL -#define serial_hsu_runtime_resume NULL -#endif - -static const struct dev_pm_ops serial_hsu_pm_ops = { - .runtime_suspend = serial_hsu_runtime_suspend, - .runtime_resume = serial_hsu_runtime_resume, - .runtime_idle = serial_hsu_runtime_idle, -}; - -/* temp global pointer before we settle down on using one or four PCI dev */ -static struct hsu_port *phsu; - -static int serial_hsu_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct uart_hsu_port *uport; - int index, ret; - - printk(KERN_INFO "HSU: found PCI Serial controller(ID: %04x:%04x)\n", - pdev->vendor, pdev->device); - - switch (pdev->device) { - case 0x081B: - index = 0; - break; - case 0x081C: - index = 1; - break; - case 0x081D: - index = 2; - break; - case 0x081E: - /* internal DMA controller */ - index = 3; - break; - default: - dev_err(&pdev->dev, "HSU: out of index!"); - return -ENODEV; - } - - ret = pci_enable_device(pdev); - if (ret) - return ret; - - if (index == 3) { - /* DMA controller */ - ret = request_irq(pdev->irq, dma_irq, 0, "hsu_dma", phsu); - if (ret) { - dev_err(&pdev->dev, "can not get IRQ\n"); - goto err_disable; - } - pci_set_drvdata(pdev, phsu); - } else { - /* UART port 0~2 */ - uport = &phsu->port[index]; - uport->port.irq = pdev->irq; - uport->port.dev = &pdev->dev; - uport->dev = &pdev->dev; - - ret = request_irq(pdev->irq, port_irq, 0, uport->name, uport); - if (ret) { - dev_err(&pdev->dev, "can not get IRQ\n"); - goto err_disable; - } - uart_add_one_port(&serial_hsu_reg, &uport->port); - - pci_set_drvdata(pdev, uport); - } - - pm_runtime_put_noidle(&pdev->dev); - pm_runtime_allow(&pdev->dev); - - return 0; - -err_disable: - pci_disable_device(pdev); - return ret; -} - -static void hsu_global_init(void) -{ - struct hsu_port *hsu; - struct uart_hsu_port *uport; - struct hsu_dma_chan *dchan; - int i, ret; - - hsu = kzalloc(sizeof(struct hsu_port), GFP_KERNEL); - if (!hsu) - return; - - /* Get basic io resource and map it */ - hsu->paddr = 0xffa28000; - hsu->iolen = 0x1000; - - if (!(request_mem_region(hsu->paddr, hsu->iolen, "HSU global"))) - pr_warn("HSU: error in request mem region\n"); - - hsu->reg = ioremap_nocache((unsigned long)hsu->paddr, hsu->iolen); - if (!hsu->reg) { - pr_err("HSU: error in ioremap\n"); - ret = -ENOMEM; - goto err_free_region; - } - - /* Initialise the 3 UART ports */ - uport = hsu->port; - for (i = 0; i < 3; i++) { - uport->port.type = PORT_MFD; - uport->port.iotype = UPIO_MEM; - uport->port.mapbase = (resource_size_t)hsu->paddr - + HSU_PORT_REG_OFFSET - + i * HSU_PORT_REG_LENGTH; - uport->port.membase = hsu->reg + HSU_PORT_REG_OFFSET - + i * HSU_PORT_REG_LENGTH; - - sprintf(uport->name, "hsu_port%d", i); - uport->port.fifosize = 64; - uport->port.ops = &serial_hsu_pops; - uport->port.line = i; - uport->port.flags = UPF_IOREMAP; - /* set the scalable maxim support rate to 2746800 bps */ - uport->port.uartclk = 115200 * 24 * 16; - - uport->running = 0; - uport->txc = &hsu->chans[i * 2]; - uport->rxc = &hsu->chans[i * 2 + 1]; - - serial_hsu_ports[i] = uport; - uport->index = i; - - if (hsu_dma_enable & (1<<i)) - uport->use_dma = 1; - else - uport->use_dma = 0; - - uport++; - } - - /* Initialise 6 dma channels */ - dchan = hsu->chans; - for (i = 0; i < 6; i++) { - dchan->id = i; - dchan->dirt = (i & 0x1) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; - dchan->uport = &hsu->port[i/2]; - dchan->reg = hsu->reg + HSU_DMA_CHANS_REG_OFFSET + - i * HSU_DMA_CHANS_REG_LENGTH; - - dchan++; - } - - phsu = hsu; - hsu_debugfs_init(hsu); - return; - -err_free_region: - release_mem_region(hsu->paddr, hsu->iolen); - kfree(hsu); - return; -} - -static void serial_hsu_remove(struct pci_dev *pdev) -{ - void *priv = pci_get_drvdata(pdev); - struct uart_hsu_port *up; - - if (!priv) - return; - - pm_runtime_forbid(&pdev->dev); - pm_runtime_get_noresume(&pdev->dev); - - /* For port 0/1/2, priv is the address of uart_hsu_port */ - if (pdev->device != 0x081E) { - up = priv; - uart_remove_one_port(&serial_hsu_reg, &up->port); - } - - free_irq(pdev->irq, priv); - pci_disable_device(pdev); -} - -/* First 3 are UART ports, and the 4th is the DMA */ -static const struct pci_device_id pci_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081B) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081C) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081D) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081E) }, - {}, -}; - -static struct pci_driver hsu_pci_driver = { - .name = "HSU serial", - .id_table = pci_ids, - .probe = serial_hsu_probe, - .remove = serial_hsu_remove, - .suspend = serial_hsu_suspend, - .resume = serial_hsu_resume, - .driver = { - .pm = &serial_hsu_pm_ops, - }, -}; - -static int __init hsu_pci_init(void) -{ - int ret; - - hsu_global_init(); - - ret = uart_register_driver(&serial_hsu_reg); - if (ret) - return ret; - - return pci_register_driver(&hsu_pci_driver); -} - -static void __exit hsu_pci_exit(void) -{ - pci_unregister_driver(&hsu_pci_driver); - uart_unregister_driver(&serial_hsu_reg); - - hsu_debugfs_remove(phsu); - - kfree(phsu); -} - -module_init(hsu_pci_init); -module_exit(hsu_pci_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_DEVICE_TABLE(pci, pci_ids); diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c index 3308ef243dc3..6fc07eb9d74e 100644 --- a/drivers/tty/serial/mpc52xx_uart.c +++ b/drivers/tty/serial/mpc52xx_uart.c @@ -405,7 +405,7 @@ static struct psc_ops mpc5200b_psc_ops = { .get_mr1 = mpc52xx_psc_get_mr1, }; -#endif /* CONFIG_MPC52xx */ +#endif /* CONFIG_PPC_MPC52xx */ #ifdef CONFIG_PPC_MPC512x #define FIFO_512x(port) ((struct mpc512x_psc_fifo __iomem *)(PSC(port)+1)) @@ -1717,7 +1717,7 @@ static struct uart_driver mpc52xx_uart_driver = { /* OF Platform Driver */ /* ======================================================================== */ -static struct of_device_id mpc52xx_uart_of_match[] = { +static const struct of_device_id mpc52xx_uart_of_match[] = { #ifdef CONFIG_PPC_MPC52xx { .compatible = "fsl,mpc5200b-psc-uart", .data = &mpc5200b_psc_ops, }, { .compatible = "fsl,mpc5200-psc-uart", .data = &mpc52xx_psc_ops, }, diff --git a/drivers/tty/serial/mpsc.c b/drivers/tty/serial/mpsc.c index 856fd5a5fa3c..82bb6d1fe23b 100644 --- a/drivers/tty/serial/mpsc.c +++ b/drivers/tty/serial/mpsc.c @@ -913,7 +913,8 @@ static int mpsc_make_ready(struct mpsc_port_info *pi) if (!pi->ready) { mpsc_init_hw(pi); - if ((rc = mpsc_alloc_ring_mem(pi))) + rc = mpsc_alloc_ring_mem(pi); + if (rc) return rc; mpsc_init_rings(pi); pi->ready = 1; @@ -1895,7 +1896,8 @@ static int mpsc_shared_drv_probe(struct platform_device *dev) int rc = -ENODEV; if (dev->id == 0) { - if (!(rc = mpsc_shared_map_regs(dev))) { + rc = mpsc_shared_map_regs(dev); + if (!rc) { pdata = (struct mpsc_shared_pdata *) dev_get_platdata(&dev->dev); @@ -2081,14 +2083,16 @@ static int mpsc_drv_probe(struct platform_device *dev) if (dev->id < MPSC_NUM_CTLRS) { pi = &mpsc_ports[dev->id]; - if (!(rc = mpsc_drv_map_regs(pi, dev))) { + rc = mpsc_drv_map_regs(pi, dev); + if (!rc) { mpsc_drv_get_platform_data(pi, dev, dev->id); pi->port.dev = &dev->dev; - if (!(rc = mpsc_make_ready(pi))) { + rc = mpsc_make_ready(pi); + if (!rc) { spin_lock_init(&pi->tx_lock); - if (!(rc = uart_add_one_port(&mpsc_reg, - &pi->port))) { + rc = uart_add_one_port(&mpsc_reg, &pi->port); + if (!rc) { rc = 0; } else { mpsc_release_port((struct uart_port *) @@ -2136,9 +2140,12 @@ static int __init mpsc_drv_init(void) memset(mpsc_ports, 0, sizeof(mpsc_ports)); memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs)); - if (!(rc = uart_register_driver(&mpsc_reg))) { - if (!(rc = platform_driver_register(&mpsc_shared_driver))) { - if ((rc = platform_driver_register(&mpsc_driver))) { + rc = uart_register_driver(&mpsc_reg); + if (!rc) { + rc = platform_driver_register(&mpsc_shared_driver); + if (!rc) { + rc = platform_driver_register(&mpsc_driver); + if (rc) { platform_driver_unregister(&mpsc_shared_driver); uart_unregister_driver(&mpsc_reg); } diff --git a/drivers/tty/serial/msm_serial.h b/drivers/tty/serial/msm_serial.h index 3e1c7138d8cd..737f69fe7113 100644 --- a/drivers/tty/serial/msm_serial.h +++ b/drivers/tty/serial/msm_serial.h @@ -170,15 +170,6 @@ void msm_serial_set_mnd_regs_from_uartclk(struct uart_port *port) msm_serial_set_mnd_regs_tcxoby4(port); } -/* - * TROUT has a specific defect that makes it report it's uartclk - * as 19.2Mhz (TCXO) when it's actually 4.8Mhz (TCXO/4). This special - * cases TROUT to use the right clock. - */ -#ifdef CONFIG_MACH_TROUT -#define msm_serial_set_mnd_regs msm_serial_set_mnd_regs_tcxoby4 -#else #define msm_serial_set_mnd_regs msm_serial_set_mnd_regs_from_uartclk -#endif #endif /* __DRIVERS_SERIAL_MSM_SERIAL_H */ diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c deleted file mode 100644 index 62da8534ba75..000000000000 --- a/drivers/tty/serial/msm_serial_hs.c +++ /dev/null @@ -1,1874 +0,0 @@ -/* - * MSM 7k/8k High speed uart driver - * - * Copyright (c) 2007-2011, Code Aurora Forum. All rights reserved. - * Copyright (c) 2008 Google Inc. - * Modified: Nick Pelly <npelly@google.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * Has optional support for uart power management independent of linux - * suspend/resume: - * - * RX wakeup. - * UART wakeup can be triggered by RX activity (using a wakeup GPIO on the - * UART RX pin). This should only be used if there is not a wakeup - * GPIO on the UART CTS, and the first RX byte is known (for example, with the - * Bluetooth Texas Instruments HCILL protocol), since the first RX byte will - * always be lost. RTS will be asserted even while the UART is off in this mode - * of operation. See msm_serial_hs_platform_data.rx_wakeup_irq. - */ - -#include <linux/module.h> - -#include <linux/serial.h> -#include <linux/serial_core.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/io.h> -#include <linux/ioport.h> -#include <linux/kernel.h> -#include <linux/timer.h> -#include <linux/clk.h> -#include <linux/platform_device.h> -#include <linux/pm_runtime.h> -#include <linux/dma-mapping.h> -#include <linux/dmapool.h> -#include <linux/wait.h> -#include <linux/workqueue.h> - -#include <linux/atomic.h> -#include <asm/irq.h> - -#include <mach/hardware.h> -#include <mach/dma.h> -#include <linux/platform_data/msm_serial_hs.h> - -/* HSUART Registers */ -#define UARTDM_MR1_ADDR 0x0 -#define UARTDM_MR2_ADDR 0x4 - -/* Data Mover result codes */ -#define RSLT_FIFO_CNTR_BMSK (0xE << 28) -#define RSLT_VLD BIT(1) - -/* write only register */ -#define UARTDM_CSR_ADDR 0x8 -#define UARTDM_CSR_115200 0xFF -#define UARTDM_CSR_57600 0xEE -#define UARTDM_CSR_38400 0xDD -#define UARTDM_CSR_28800 0xCC -#define UARTDM_CSR_19200 0xBB -#define UARTDM_CSR_14400 0xAA -#define UARTDM_CSR_9600 0x99 -#define UARTDM_CSR_7200 0x88 -#define UARTDM_CSR_4800 0x77 -#define UARTDM_CSR_3600 0x66 -#define UARTDM_CSR_2400 0x55 -#define UARTDM_CSR_1200 0x44 -#define UARTDM_CSR_600 0x33 -#define UARTDM_CSR_300 0x22 -#define UARTDM_CSR_150 0x11 -#define UARTDM_CSR_75 0x00 - -/* write only register */ -#define UARTDM_TF_ADDR 0x70 -#define UARTDM_TF2_ADDR 0x74 -#define UARTDM_TF3_ADDR 0x78 -#define UARTDM_TF4_ADDR 0x7C - -/* write only register */ -#define UARTDM_CR_ADDR 0x10 -#define UARTDM_IMR_ADDR 0x14 - -#define UARTDM_IPR_ADDR 0x18 -#define UARTDM_TFWR_ADDR 0x1c -#define UARTDM_RFWR_ADDR 0x20 -#define UARTDM_HCR_ADDR 0x24 -#define UARTDM_DMRX_ADDR 0x34 -#define UARTDM_IRDA_ADDR 0x38 -#define UARTDM_DMEN_ADDR 0x3c - -/* UART_DM_NO_CHARS_FOR_TX */ -#define UARTDM_NCF_TX_ADDR 0x40 - -#define UARTDM_BADR_ADDR 0x44 - -#define UARTDM_SIM_CFG_ADDR 0x80 -/* Read Only register */ -#define UARTDM_SR_ADDR 0x8 - -/* Read Only register */ -#define UARTDM_RF_ADDR 0x70 -#define UARTDM_RF2_ADDR 0x74 -#define UARTDM_RF3_ADDR 0x78 -#define UARTDM_RF4_ADDR 0x7C - -/* Read Only register */ -#define UARTDM_MISR_ADDR 0x10 - -/* Read Only register */ -#define UARTDM_ISR_ADDR 0x14 -#define UARTDM_RX_TOTAL_SNAP_ADDR 0x38 - -#define UARTDM_RXFS_ADDR 0x50 - -/* Register field Mask Mapping */ -#define UARTDM_SR_PAR_FRAME_BMSK BIT(5) -#define UARTDM_SR_OVERRUN_BMSK BIT(4) -#define UARTDM_SR_TXEMT_BMSK BIT(3) -#define UARTDM_SR_TXRDY_BMSK BIT(2) -#define UARTDM_SR_RXRDY_BMSK BIT(0) - -#define UARTDM_CR_TX_DISABLE_BMSK BIT(3) -#define UARTDM_CR_RX_DISABLE_BMSK BIT(1) -#define UARTDM_CR_TX_EN_BMSK BIT(2) -#define UARTDM_CR_RX_EN_BMSK BIT(0) - -/* UARTDM_CR channel_comman bit value (register field is bits 8:4) */ -#define RESET_RX 0x10 -#define RESET_TX 0x20 -#define RESET_ERROR_STATUS 0x30 -#define RESET_BREAK_INT 0x40 -#define START_BREAK 0x50 -#define STOP_BREAK 0x60 -#define RESET_CTS 0x70 -#define RESET_STALE_INT 0x80 -#define RFR_LOW 0xD0 -#define RFR_HIGH 0xE0 -#define CR_PROTECTION_EN 0x100 -#define STALE_EVENT_ENABLE 0x500 -#define STALE_EVENT_DISABLE 0x600 -#define FORCE_STALE_EVENT 0x400 -#define CLEAR_TX_READY 0x300 -#define RESET_TX_ERROR 0x800 -#define RESET_TX_DONE 0x810 - -#define UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK 0xffffff00 -#define UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK 0x3f -#define UARTDM_MR1_CTS_CTL_BMSK 0x40 -#define UARTDM_MR1_RX_RDY_CTL_BMSK 0x80 - -#define UARTDM_MR2_ERROR_MODE_BMSK 0x40 -#define UARTDM_MR2_BITS_PER_CHAR_BMSK 0x30 - -/* bits per character configuration */ -#define FIVE_BPC (0 << 4) -#define SIX_BPC (1 << 4) -#define SEVEN_BPC (2 << 4) -#define EIGHT_BPC (3 << 4) - -#define UARTDM_MR2_STOP_BIT_LEN_BMSK 0xc -#define STOP_BIT_ONE (1 << 2) -#define STOP_BIT_TWO (3 << 2) - -#define UARTDM_MR2_PARITY_MODE_BMSK 0x3 - -/* Parity configuration */ -#define NO_PARITY 0x0 -#define EVEN_PARITY 0x1 -#define ODD_PARITY 0x2 -#define SPACE_PARITY 0x3 - -#define UARTDM_IPR_STALE_TIMEOUT_MSB_BMSK 0xffffff80 -#define UARTDM_IPR_STALE_LSB_BMSK 0x1f - -/* These can be used for both ISR and IMR register */ -#define UARTDM_ISR_TX_READY_BMSK BIT(7) -#define UARTDM_ISR_CURRENT_CTS_BMSK BIT(6) -#define UARTDM_ISR_DELTA_CTS_BMSK BIT(5) -#define UARTDM_ISR_RXLEV_BMSK BIT(4) -#define UARTDM_ISR_RXSTALE_BMSK BIT(3) -#define UARTDM_ISR_RXBREAK_BMSK BIT(2) -#define UARTDM_ISR_RXHUNT_BMSK BIT(1) -#define UARTDM_ISR_TXLEV_BMSK BIT(0) - -/* Field definitions for UART_DM_DMEN*/ -#define UARTDM_TX_DM_EN_BMSK 0x1 -#define UARTDM_RX_DM_EN_BMSK 0x2 - -#define UART_FIFOSIZE 64 -#define UARTCLK 7372800 - -/* Rx DMA request states */ -enum flush_reason { - FLUSH_NONE, - FLUSH_DATA_READY, - FLUSH_DATA_INVALID, /* values after this indicate invalid data */ - FLUSH_IGNORE = FLUSH_DATA_INVALID, - FLUSH_STOP, - FLUSH_SHUTDOWN, -}; - -/* UART clock states */ -enum msm_hs_clk_states_e { - MSM_HS_CLK_PORT_OFF, /* port not in use */ - MSM_HS_CLK_OFF, /* clock disabled */ - MSM_HS_CLK_REQUEST_OFF, /* disable after TX and RX flushed */ - MSM_HS_CLK_ON, /* clock enabled */ -}; - -/* Track the forced RXSTALE flush during clock off sequence. - * These states are only valid during MSM_HS_CLK_REQUEST_OFF */ -enum msm_hs_clk_req_off_state_e { - CLK_REQ_OFF_START, - CLK_REQ_OFF_RXSTALE_ISSUED, - CLK_REQ_OFF_FLUSH_ISSUED, - CLK_REQ_OFF_RXSTALE_FLUSHED, -}; - -/** - * struct msm_hs_tx - * @tx_ready_int_en: ok to dma more tx? - * @dma_in_flight: tx dma in progress - * @xfer: top level DMA command pointer structure - * @command_ptr: third level command struct pointer - * @command_ptr_ptr: second level command list struct pointer - * @mapped_cmd_ptr: DMA view of third level command struct - * @mapped_cmd_ptr_ptr: DMA view of second level command list struct - * @tx_count: number of bytes to transfer in DMA transfer - * @dma_base: DMA view of UART xmit buffer - * - * This structure describes a single Tx DMA transaction. MSM DMA - * commands have two levels of indirection. The top level command - * ptr points to a list of command ptr which in turn points to a - * single DMA 'command'. In our case each Tx transaction consists - * of a single second level pointer pointing to a 'box type' command. - */ -struct msm_hs_tx { - unsigned int tx_ready_int_en; - unsigned int dma_in_flight; - struct msm_dmov_cmd xfer; - dmov_box *command_ptr; - u32 *command_ptr_ptr; - dma_addr_t mapped_cmd_ptr; - dma_addr_t mapped_cmd_ptr_ptr; - int tx_count; - dma_addr_t dma_base; -}; - -/** - * struct msm_hs_rx - * @flush: Rx DMA request state - * @xfer: top level DMA command pointer structure - * @cmdptr_dmaaddr: DMA view of second level command structure - * @command_ptr: third level DMA command pointer structure - * @command_ptr_ptr: second level DMA command list pointer - * @mapped_cmd_ptr: DMA view of the third level command structure - * @wait: wait for DMA completion before shutdown - * @buffer: destination buffer for RX DMA - * @rbuffer: DMA view of buffer - * @pool: dma pool out of which coherent rx buffer is allocated - * @tty_work: private work-queue for tty flip buffer push task - * - * This structure describes a single Rx DMA transaction. Rx DMA - * transactions use box mode DMA commands. - */ -struct msm_hs_rx { - enum flush_reason flush; - struct msm_dmov_cmd xfer; - dma_addr_t cmdptr_dmaaddr; - dmov_box *command_ptr; - u32 *command_ptr_ptr; - dma_addr_t mapped_cmd_ptr; - wait_queue_head_t wait; - dma_addr_t rbuffer; - unsigned char *buffer; - struct dma_pool *pool; - struct work_struct tty_work; -}; - -/** - * struct msm_hs_rx_wakeup - * @irq: IRQ line to be configured as interrupt source on Rx activity - * @ignore: boolean value. 1 = ignore the wakeup interrupt - * @rx_to_inject: extra character to be inserted to Rx tty on wakeup - * @inject_rx: 1 = insert rx_to_inject. 0 = do not insert extra character - * - * This is an optional structure required for UART Rx GPIO IRQ based - * wakeup from low power state. UART wakeup can be triggered by RX activity - * (using a wakeup GPIO on the UART RX pin). This should only be used if - * there is not a wakeup GPIO on the UART CTS, and the first RX byte is - * known (eg., with the Bluetooth Texas Instruments HCILL protocol), - * since the first RX byte will always be lost. RTS will be asserted even - * while the UART is clocked off in this mode of operation. - */ -struct msm_hs_rx_wakeup { - int irq; /* < 0 indicates low power wakeup disabled */ - unsigned char ignore; - unsigned char inject_rx; - char rx_to_inject; -}; - -/** - * struct msm_hs_port - * @uport: embedded uart port structure - * @imr_reg: shadow value of UARTDM_IMR - * @clk: uart input clock handle - * @tx: Tx transaction related data structure - * @rx: Rx transaction related data structure - * @dma_tx_channel: Tx DMA command channel - * @dma_rx_channel Rx DMA command channel - * @dma_tx_crci: Tx channel rate control interface number - * @dma_rx_crci: Rx channel rate control interface number - * @clk_off_timer: Timer to poll DMA event completion before clock off - * @clk_off_delay: clk_off_timer poll interval - * @clk_state: overall clock state - * @clk_req_off_state: post flush clock states - * @rx_wakeup: optional rx_wakeup feature related data - * @exit_lpm_cb: optional callback to exit low power mode - * - * Low level serial port structure. - */ -struct msm_hs_port { - struct uart_port uport; - unsigned long imr_reg; - struct clk *clk; - struct msm_hs_tx tx; - struct msm_hs_rx rx; - - int dma_tx_channel; - int dma_rx_channel; - int dma_tx_crci; - int dma_rx_crci; - - struct hrtimer clk_off_timer; - ktime_t clk_off_delay; - enum msm_hs_clk_states_e clk_state; - enum msm_hs_clk_req_off_state_e clk_req_off_state; - - struct msm_hs_rx_wakeup rx_wakeup; - void (*exit_lpm_cb)(struct uart_port *); -}; - -#define MSM_UARTDM_BURST_SIZE 16 /* DM burst size (in bytes) */ -#define UARTDM_TX_BUF_SIZE UART_XMIT_SIZE -#define UARTDM_RX_BUF_SIZE 512 - -#define UARTDM_NR 2 - -static struct msm_hs_port q_uart_port[UARTDM_NR]; -static struct platform_driver msm_serial_hs_platform_driver; -static struct uart_driver msm_hs_driver; -static struct uart_ops msm_hs_ops; -static struct workqueue_struct *msm_hs_workqueue; - -#define UARTDM_TO_MSM(uart_port) \ - container_of((uart_port), struct msm_hs_port, uport) - -static unsigned int use_low_power_rx_wakeup(struct msm_hs_port - *msm_uport) -{ - return (msm_uport->rx_wakeup.irq >= 0); -} - -static unsigned int msm_hs_read(struct uart_port *uport, - unsigned int offset) -{ - return ioread32(uport->membase + offset); -} - -static void msm_hs_write(struct uart_port *uport, unsigned int offset, - unsigned int value) -{ - iowrite32(value, uport->membase + offset); -} - -static void msm_hs_release_port(struct uart_port *port) -{ - iounmap(port->membase); -} - -static int msm_hs_request_port(struct uart_port *port) -{ - port->membase = ioremap(port->mapbase, PAGE_SIZE); - if (unlikely(!port->membase)) - return -ENOMEM; - - /* configure the CR Protection to Enable */ - msm_hs_write(port, UARTDM_CR_ADDR, CR_PROTECTION_EN); - return 0; -} - -static int msm_hs_remove(struct platform_device *pdev) -{ - - struct msm_hs_port *msm_uport; - struct device *dev; - - if (pdev->id < 0 || pdev->id >= UARTDM_NR) { - printk(KERN_ERR "Invalid plaform device ID = %d\n", pdev->id); - return -EINVAL; - } - - msm_uport = &q_uart_port[pdev->id]; - dev = msm_uport->uport.dev; - - dma_unmap_single(dev, msm_uport->rx.mapped_cmd_ptr, sizeof(dmov_box), - DMA_TO_DEVICE); - dma_pool_free(msm_uport->rx.pool, msm_uport->rx.buffer, - msm_uport->rx.rbuffer); - dma_pool_destroy(msm_uport->rx.pool); - - dma_unmap_single(dev, msm_uport->rx.cmdptr_dmaaddr, sizeof(u32), - DMA_TO_DEVICE); - dma_unmap_single(dev, msm_uport->tx.mapped_cmd_ptr_ptr, sizeof(u32), - DMA_TO_DEVICE); - dma_unmap_single(dev, msm_uport->tx.mapped_cmd_ptr, sizeof(dmov_box), - DMA_TO_DEVICE); - - uart_remove_one_port(&msm_hs_driver, &msm_uport->uport); - clk_put(msm_uport->clk); - - /* Free the tx resources */ - kfree(msm_uport->tx.command_ptr); - kfree(msm_uport->tx.command_ptr_ptr); - - /* Free the rx resources */ - kfree(msm_uport->rx.command_ptr); - kfree(msm_uport->rx.command_ptr_ptr); - - iounmap(msm_uport->uport.membase); - - return 0; -} - -static int msm_hs_init_clk_locked(struct uart_port *uport) -{ - int ret; - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - ret = clk_enable(msm_uport->clk); - if (ret) { - printk(KERN_ERR "Error could not turn on UART clk\n"); - return ret; - } - - /* Set up the MREG/NREG/DREG/MNDREG */ - ret = clk_set_rate(msm_uport->clk, uport->uartclk); - if (ret) { - printk(KERN_WARNING "Error setting clock rate on UART\n"); - clk_disable(msm_uport->clk); - return ret; - } - - msm_uport->clk_state = MSM_HS_CLK_ON; - return 0; -} - -/* Enable and Disable clocks (Used for power management) */ -static void msm_hs_pm(struct uart_port *uport, unsigned int state, - unsigned int oldstate) -{ - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - if (use_low_power_rx_wakeup(msm_uport) || - msm_uport->exit_lpm_cb) - return; /* ignore linux PM states, - use msm_hs_request_clock API */ - - switch (state) { - case 0: - clk_enable(msm_uport->clk); - break; - case 3: - clk_disable(msm_uport->clk); - break; - default: - dev_err(uport->dev, "msm_serial: Unknown PM state %d\n", - state); - } -} - -/* - * programs the UARTDM_CSR register with correct bit rates - * - * Interrupts should be disabled before we are called, as - * we modify Set Baud rate - * Set receive stale interrupt level, dependent on Bit Rate - * Goal is to have around 8 ms before indicate stale. - * roundup (((Bit Rate * .008) / 10) + 1 - */ -static void msm_hs_set_bps_locked(struct uart_port *uport, - unsigned int bps) -{ - unsigned long rxstale; - unsigned long data; - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - switch (bps) { - case 300: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_75); - rxstale = 1; - break; - case 600: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_150); - rxstale = 1; - break; - case 1200: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_300); - rxstale = 1; - break; - case 2400: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_600); - rxstale = 1; - break; - case 4800: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_1200); - rxstale = 1; - break; - case 9600: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_2400); - rxstale = 2; - break; - case 14400: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_3600); - rxstale = 3; - break; - case 19200: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_4800); - rxstale = 4; - break; - case 28800: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_7200); - rxstale = 6; - break; - case 38400: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_9600); - rxstale = 8; - break; - case 57600: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_14400); - rxstale = 16; - break; - case 76800: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_19200); - rxstale = 16; - break; - case 115200: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_28800); - rxstale = 31; - break; - case 230400: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_57600); - rxstale = 31; - break; - case 460800: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_115200); - rxstale = 31; - break; - case 4000000: - case 3686400: - case 3200000: - case 3500000: - case 3000000: - case 2500000: - case 1500000: - case 1152000: - case 1000000: - case 921600: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_115200); - rxstale = 31; - break; - default: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_2400); - /* default to 9600 */ - bps = 9600; - rxstale = 2; - break; - } - if (bps > 460800) - uport->uartclk = bps * 16; - else - uport->uartclk = UARTCLK; - - if (clk_set_rate(msm_uport->clk, uport->uartclk)) { - printk(KERN_WARNING "Error setting clock rate on UART\n"); - return; - } - - data = rxstale & UARTDM_IPR_STALE_LSB_BMSK; - data |= UARTDM_IPR_STALE_TIMEOUT_MSB_BMSK & (rxstale << 2); - - msm_hs_write(uport, UARTDM_IPR_ADDR, data); -} - -/* - * termios : new ktermios - * oldtermios: old ktermios previous setting - * - * Configure the serial port - */ -static void msm_hs_set_termios(struct uart_port *uport, - struct ktermios *termios, - struct ktermios *oldtermios) -{ - unsigned int bps; - unsigned long data; - unsigned long flags; - unsigned int c_cflag = termios->c_cflag; - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - spin_lock_irqsave(&uport->lock, flags); - clk_enable(msm_uport->clk); - - /* 300 is the minimum baud support by the driver */ - bps = uart_get_baud_rate(uport, termios, oldtermios, 200, 4000000); - - /* Temporary remapping 200 BAUD to 3.2 mbps */ - if (bps == 200) - bps = 3200000; - - msm_hs_set_bps_locked(uport, bps); - - data = msm_hs_read(uport, UARTDM_MR2_ADDR); - data &= ~UARTDM_MR2_PARITY_MODE_BMSK; - /* set parity */ - if (PARENB == (c_cflag & PARENB)) { - if (PARODD == (c_cflag & PARODD)) - data |= ODD_PARITY; - else if (CMSPAR == (c_cflag & CMSPAR)) - data |= SPACE_PARITY; - else - data |= EVEN_PARITY; - } - - /* Set bits per char */ - data &= ~UARTDM_MR2_BITS_PER_CHAR_BMSK; - - switch (c_cflag & CSIZE) { - case CS5: - data |= FIVE_BPC; - break; - case CS6: - data |= SIX_BPC; - break; - case CS7: - data |= SEVEN_BPC; - break; - default: - data |= EIGHT_BPC; - break; - } - /* stop bits */ - if (c_cflag & CSTOPB) { - data |= STOP_BIT_TWO; - } else { - /* otherwise 1 stop bit */ - data |= STOP_BIT_ONE; - } - data |= UARTDM_MR2_ERROR_MODE_BMSK; - /* write parity/bits per char/stop bit configuration */ - msm_hs_write(uport, UARTDM_MR2_ADDR, data); - - /* Configure HW flow control */ - data = msm_hs_read(uport, UARTDM_MR1_ADDR); - - data &= ~(UARTDM_MR1_CTS_CTL_BMSK | UARTDM_MR1_RX_RDY_CTL_BMSK); - - if (c_cflag & CRTSCTS) { - data |= UARTDM_MR1_CTS_CTL_BMSK; - data |= UARTDM_MR1_RX_RDY_CTL_BMSK; - } - - msm_hs_write(uport, UARTDM_MR1_ADDR, data); - - uport->ignore_status_mask = termios->c_iflag & INPCK; - uport->ignore_status_mask |= termios->c_iflag & IGNPAR; - uport->read_status_mask = (termios->c_cflag & CREAD); - - msm_hs_write(uport, UARTDM_IMR_ADDR, 0); - - /* Set Transmit software time out */ - uart_update_timeout(uport, c_cflag, bps); - - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_RX); - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX); - - if (msm_uport->rx.flush == FLUSH_NONE) { - msm_uport->rx.flush = FLUSH_IGNORE; - msm_dmov_stop_cmd(msm_uport->dma_rx_channel, NULL, 1); - } - - msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); - - clk_disable(msm_uport->clk); - spin_unlock_irqrestore(&uport->lock, flags); -} - -/* - * Standard API, Transmitter - * Any character in the transmit shift register is sent - */ -static unsigned int msm_hs_tx_empty(struct uart_port *uport) -{ - unsigned int data; - unsigned int ret = 0; - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - clk_enable(msm_uport->clk); - - data = msm_hs_read(uport, UARTDM_SR_ADDR); - if (data & UARTDM_SR_TXEMT_BMSK) - ret = TIOCSER_TEMT; - - clk_disable(msm_uport->clk); - - return ret; -} - -/* - * Standard API, Stop transmitter. - * Any character in the transmit shift register is sent as - * well as the current data mover transfer . - */ -static void msm_hs_stop_tx_locked(struct uart_port *uport) -{ - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - msm_uport->tx.tx_ready_int_en = 0; -} - -/* - * Standard API, Stop receiver as soon as possible. - * - * Function immediately terminates the operation of the - * channel receiver and any incoming characters are lost. None - * of the receiver status bits are affected by this command and - * characters that are already in the receive FIFO there. - */ -static void msm_hs_stop_rx_locked(struct uart_port *uport) -{ - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - unsigned int data; - - clk_enable(msm_uport->clk); - - /* disable dlink */ - data = msm_hs_read(uport, UARTDM_DMEN_ADDR); - data &= ~UARTDM_RX_DM_EN_BMSK; - msm_hs_write(uport, UARTDM_DMEN_ADDR, data); - - /* Disable the receiver */ - if (msm_uport->rx.flush == FLUSH_NONE) - msm_dmov_stop_cmd(msm_uport->dma_rx_channel, NULL, 1); - - if (msm_uport->rx.flush != FLUSH_SHUTDOWN) - msm_uport->rx.flush = FLUSH_STOP; - - clk_disable(msm_uport->clk); -} - -/* Transmit the next chunk of data */ -static void msm_hs_submit_tx_locked(struct uart_port *uport) -{ - int left; - int tx_count; - dma_addr_t src_addr; - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - struct msm_hs_tx *tx = &msm_uport->tx; - struct circ_buf *tx_buf = &msm_uport->uport.state->xmit; - - if (uart_circ_empty(tx_buf) || uport->state->port.tty->stopped) { - msm_hs_stop_tx_locked(uport); - return; - } - - tx->dma_in_flight = 1; - - tx_count = uart_circ_chars_pending(tx_buf); - - if (UARTDM_TX_BUF_SIZE < tx_count) - tx_count = UARTDM_TX_BUF_SIZE; - - left = UART_XMIT_SIZE - tx_buf->tail; - - if (tx_count > left) - tx_count = left; - - src_addr = tx->dma_base + tx_buf->tail; - dma_sync_single_for_device(uport->dev, src_addr, tx_count, - DMA_TO_DEVICE); - - tx->command_ptr->num_rows = (((tx_count + 15) >> 4) << 16) | - ((tx_count + 15) >> 4); - tx->command_ptr->src_row_addr = src_addr; - - dma_sync_single_for_device(uport->dev, tx->mapped_cmd_ptr, - sizeof(dmov_box), DMA_TO_DEVICE); - - *tx->command_ptr_ptr = CMD_PTR_LP | DMOV_CMD_ADDR(tx->mapped_cmd_ptr); - - dma_sync_single_for_device(uport->dev, tx->mapped_cmd_ptr_ptr, - sizeof(u32), DMA_TO_DEVICE); - - /* Save tx_count to use in Callback */ - tx->tx_count = tx_count; - msm_hs_write(uport, UARTDM_NCF_TX_ADDR, tx_count); - - /* Disable the tx_ready interrupt */ - msm_uport->imr_reg &= ~UARTDM_ISR_TX_READY_BMSK; - msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); - msm_dmov_enqueue_cmd(msm_uport->dma_tx_channel, &tx->xfer); -} - -/* Start to receive the next chunk of data */ -static void msm_hs_start_rx_locked(struct uart_port *uport) -{ - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_STALE_INT); - msm_hs_write(uport, UARTDM_DMRX_ADDR, UARTDM_RX_BUF_SIZE); - msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_ENABLE); - msm_uport->imr_reg |= UARTDM_ISR_RXLEV_BMSK; - msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); - - msm_uport->rx.flush = FLUSH_NONE; - msm_dmov_enqueue_cmd(msm_uport->dma_rx_channel, &msm_uport->rx.xfer); - - /* might have finished RX and be ready to clock off */ - hrtimer_start(&msm_uport->clk_off_timer, msm_uport->clk_off_delay, - HRTIMER_MODE_REL); -} - -/* Enable the transmitter Interrupt */ -static void msm_hs_start_tx_locked(struct uart_port *uport) -{ - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - clk_enable(msm_uport->clk); - - if (msm_uport->exit_lpm_cb) - msm_uport->exit_lpm_cb(uport); - - if (msm_uport->tx.tx_ready_int_en == 0) { - msm_uport->tx.tx_ready_int_en = 1; - msm_hs_submit_tx_locked(uport); - } - - clk_disable(msm_uport->clk); -} - -/* - * This routine is called when we are done with a DMA transfer - * - * This routine is registered with Data mover when we set - * up a Data Mover transfer. It is called from Data mover ISR - * when the DMA transfer is done. - */ -static void msm_hs_dmov_tx_callback(struct msm_dmov_cmd *cmd_ptr, - unsigned int result, - struct msm_dmov_errdata *err) -{ - unsigned long flags; - struct msm_hs_port *msm_uport; - - /* DMA did not finish properly */ - WARN_ON((((result & RSLT_FIFO_CNTR_BMSK) >> 28) == 1) && - !(result & RSLT_VLD)); - - msm_uport = container_of(cmd_ptr, struct msm_hs_port, tx.xfer); - - spin_lock_irqsave(&msm_uport->uport.lock, flags); - clk_enable(msm_uport->clk); - - msm_uport->imr_reg |= UARTDM_ISR_TX_READY_BMSK; - msm_hs_write(&msm_uport->uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); - - clk_disable(msm_uport->clk); - spin_unlock_irqrestore(&msm_uport->uport.lock, flags); -} - -/* - * This routine is called when we are done with a DMA transfer or the - * a flush has been sent to the data mover driver. - * - * This routine is registered with Data mover when we set up a Data Mover - * transfer. It is called from Data mover ISR when the DMA transfer is done. - */ -static void msm_hs_dmov_rx_callback(struct msm_dmov_cmd *cmd_ptr, - unsigned int result, - struct msm_dmov_errdata *err) -{ - int retval; - int rx_count; - unsigned long status; - unsigned int error_f = 0; - unsigned long flags; - unsigned int flush; - struct tty_port *port; - struct uart_port *uport; - struct msm_hs_port *msm_uport; - - msm_uport = container_of(cmd_ptr, struct msm_hs_port, rx.xfer); - uport = &msm_uport->uport; - - spin_lock_irqsave(&uport->lock, flags); - clk_enable(msm_uport->clk); - - port = &uport->state->port; - - msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_DISABLE); - - status = msm_hs_read(uport, UARTDM_SR_ADDR); - - /* overflow is not connect to data in a FIFO */ - if (unlikely((status & UARTDM_SR_OVERRUN_BMSK) && - (uport->read_status_mask & CREAD))) { - tty_insert_flip_char(port, 0, TTY_OVERRUN); - uport->icount.buf_overrun++; - error_f = 1; - } - - if (!(uport->ignore_status_mask & INPCK)) - status = status & ~(UARTDM_SR_PAR_FRAME_BMSK); - - if (unlikely(status & UARTDM_SR_PAR_FRAME_BMSK)) { - /* Can not tell difference between parity & frame error */ - uport->icount.parity++; - error_f = 1; - if (uport->ignore_status_mask & IGNPAR) - tty_insert_flip_char(port, 0, TTY_PARITY); - } - - if (error_f) - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_ERROR_STATUS); - - if (msm_uport->clk_req_off_state == CLK_REQ_OFF_FLUSH_ISSUED) - msm_uport->clk_req_off_state = CLK_REQ_OFF_RXSTALE_FLUSHED; - - flush = msm_uport->rx.flush; - if (flush == FLUSH_IGNORE) - msm_hs_start_rx_locked(uport); - if (flush == FLUSH_STOP) - msm_uport->rx.flush = FLUSH_SHUTDOWN; - if (flush >= FLUSH_DATA_INVALID) - goto out; - - rx_count = msm_hs_read(uport, UARTDM_RX_TOTAL_SNAP_ADDR); - - if (0 != (uport->read_status_mask & CREAD)) { - retval = tty_insert_flip_string(port, msm_uport->rx.buffer, - rx_count); - BUG_ON(retval != rx_count); - } - - msm_hs_start_rx_locked(uport); - -out: - clk_disable(msm_uport->clk); - - spin_unlock_irqrestore(&uport->lock, flags); - - if (flush < FLUSH_DATA_INVALID) - queue_work(msm_hs_workqueue, &msm_uport->rx.tty_work); -} - -static void msm_hs_tty_flip_buffer_work(struct work_struct *work) -{ - struct msm_hs_port *msm_uport = - container_of(work, struct msm_hs_port, rx.tty_work); - - tty_flip_buffer_push(&msm_uport->uport.state->port); -} - -/* - * Standard API, Current states of modem control inputs - * - * Since CTS can be handled entirely by HARDWARE we always - * indicate clear to send and count on the TX FIFO to block when - * it fills up. - * - * - TIOCM_DCD - * - TIOCM_CTS - * - TIOCM_DSR - * - TIOCM_RI - * (Unsupported) DCD and DSR will return them high. RI will return low. - */ -static unsigned int msm_hs_get_mctrl_locked(struct uart_port *uport) -{ - return TIOCM_DSR | TIOCM_CAR | TIOCM_CTS; -} - -/* - * True enables UART auto RFR, which indicates we are ready for data if the RX - * buffer is not full. False disables auto RFR, and deasserts RFR to indicate - * we are not ready for data. Must be called with UART clock on. - */ -static void set_rfr_locked(struct uart_port *uport, int auto_rfr) -{ - unsigned int data; - - data = msm_hs_read(uport, UARTDM_MR1_ADDR); - - if (auto_rfr) { - /* enable auto ready-for-receiving */ - data |= UARTDM_MR1_RX_RDY_CTL_BMSK; - msm_hs_write(uport, UARTDM_MR1_ADDR, data); - } else { - /* disable auto ready-for-receiving */ - data &= ~UARTDM_MR1_RX_RDY_CTL_BMSK; - msm_hs_write(uport, UARTDM_MR1_ADDR, data); - /* RFR is active low, set high */ - msm_hs_write(uport, UARTDM_CR_ADDR, RFR_HIGH); - } -} - -/* - * Standard API, used to set or clear RFR - */ -static void msm_hs_set_mctrl_locked(struct uart_port *uport, - unsigned int mctrl) -{ - unsigned int auto_rfr; - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - clk_enable(msm_uport->clk); - - auto_rfr = TIOCM_RTS & mctrl ? 1 : 0; - set_rfr_locked(uport, auto_rfr); - - clk_disable(msm_uport->clk); -} - -/* Standard API, Enable modem status (CTS) interrupt */ -static void msm_hs_enable_ms_locked(struct uart_port *uport) -{ - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - clk_enable(msm_uport->clk); - - /* Enable DELTA_CTS Interrupt */ - msm_uport->imr_reg |= UARTDM_ISR_DELTA_CTS_BMSK; - msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); - - clk_disable(msm_uport->clk); - -} - -/* - * Standard API, Break Signal - * - * Control the transmission of a break signal. ctl eq 0 => break - * signal terminate ctl ne 0 => start break signal - */ -static void msm_hs_break_ctl(struct uart_port *uport, int ctl) -{ - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - clk_enable(msm_uport->clk); - msm_hs_write(uport, UARTDM_CR_ADDR, ctl ? START_BREAK : STOP_BREAK); - clk_disable(msm_uport->clk); -} - -static void msm_hs_config_port(struct uart_port *uport, int cfg_flags) -{ - unsigned long flags; - - spin_lock_irqsave(&uport->lock, flags); - if (cfg_flags & UART_CONFIG_TYPE) { - uport->type = PORT_MSM; - msm_hs_request_port(uport); - } - spin_unlock_irqrestore(&uport->lock, flags); -} - -/* Handle CTS changes (Called from interrupt handler) */ -static void msm_hs_handle_delta_cts_locked(struct uart_port *uport) -{ - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - clk_enable(msm_uport->clk); - - /* clear interrupt */ - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_CTS); - uport->icount.cts++; - - clk_disable(msm_uport->clk); - - /* clear the IOCTL TIOCMIWAIT if called */ - wake_up_interruptible(&uport->state->port.delta_msr_wait); -} - -/* check if the TX path is flushed, and if so clock off - * returns 0 did not clock off, need to retry (still sending final byte) - * -1 did not clock off, do not retry - * 1 if we clocked off - */ -static int msm_hs_check_clock_off_locked(struct uart_port *uport) -{ - unsigned long sr_status; - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - struct circ_buf *tx_buf = &uport->state->xmit; - - /* Cancel if tx tty buffer is not empty, dma is in flight, - * or tx fifo is not empty, or rx fifo is not empty */ - if (msm_uport->clk_state != MSM_HS_CLK_REQUEST_OFF || - !uart_circ_empty(tx_buf) || msm_uport->tx.dma_in_flight || - (msm_uport->imr_reg & UARTDM_ISR_TXLEV_BMSK) || - !(msm_uport->imr_reg & UARTDM_ISR_RXLEV_BMSK)) { - return -1; - } - - /* Make sure the uart is finished with the last byte */ - sr_status = msm_hs_read(uport, UARTDM_SR_ADDR); - if (!(sr_status & UARTDM_SR_TXEMT_BMSK)) - return 0; /* retry */ - - /* Make sure forced RXSTALE flush complete */ - switch (msm_uport->clk_req_off_state) { - case CLK_REQ_OFF_START: - msm_uport->clk_req_off_state = CLK_REQ_OFF_RXSTALE_ISSUED; - msm_hs_write(uport, UARTDM_CR_ADDR, FORCE_STALE_EVENT); - return 0; /* RXSTALE flush not complete - retry */ - case CLK_REQ_OFF_RXSTALE_ISSUED: - case CLK_REQ_OFF_FLUSH_ISSUED: - return 0; /* RXSTALE flush not complete - retry */ - case CLK_REQ_OFF_RXSTALE_FLUSHED: - break; /* continue */ - } - - if (msm_uport->rx.flush != FLUSH_SHUTDOWN) { - if (msm_uport->rx.flush == FLUSH_NONE) - msm_hs_stop_rx_locked(uport); - return 0; /* come back later to really clock off */ - } - - /* we really want to clock off */ - clk_disable(msm_uport->clk); - msm_uport->clk_state = MSM_HS_CLK_OFF; - - if (use_low_power_rx_wakeup(msm_uport)) { - msm_uport->rx_wakeup.ignore = 1; - enable_irq(msm_uport->rx_wakeup.irq); - } - return 1; -} - -static enum hrtimer_restart msm_hs_clk_off_retry(struct hrtimer *timer) -{ - unsigned long flags; - int ret = HRTIMER_NORESTART; - struct msm_hs_port *msm_uport = container_of(timer, struct msm_hs_port, - clk_off_timer); - struct uart_port *uport = &msm_uport->uport; - - spin_lock_irqsave(&uport->lock, flags); - - if (!msm_hs_check_clock_off_locked(uport)) { - hrtimer_forward_now(timer, msm_uport->clk_off_delay); - ret = HRTIMER_RESTART; - } - - spin_unlock_irqrestore(&uport->lock, flags); - - return ret; -} - -static irqreturn_t msm_hs_isr(int irq, void *dev) -{ - unsigned long flags; - unsigned long isr_status; - struct msm_hs_port *msm_uport = dev; - struct uart_port *uport = &msm_uport->uport; - struct circ_buf *tx_buf = &uport->state->xmit; - struct msm_hs_tx *tx = &msm_uport->tx; - struct msm_hs_rx *rx = &msm_uport->rx; - - spin_lock_irqsave(&uport->lock, flags); - - isr_status = msm_hs_read(uport, UARTDM_MISR_ADDR); - - /* Uart RX starting */ - if (isr_status & UARTDM_ISR_RXLEV_BMSK) { - msm_uport->imr_reg &= ~UARTDM_ISR_RXLEV_BMSK; - msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); - } - /* Stale rx interrupt */ - if (isr_status & UARTDM_ISR_RXSTALE_BMSK) { - msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_DISABLE); - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_STALE_INT); - - if (msm_uport->clk_req_off_state == CLK_REQ_OFF_RXSTALE_ISSUED) - msm_uport->clk_req_off_state = - CLK_REQ_OFF_FLUSH_ISSUED; - if (rx->flush == FLUSH_NONE) { - rx->flush = FLUSH_DATA_READY; - msm_dmov_stop_cmd(msm_uport->dma_rx_channel, NULL, 1); - } - } - /* tx ready interrupt */ - if (isr_status & UARTDM_ISR_TX_READY_BMSK) { - /* Clear TX Ready */ - msm_hs_write(uport, UARTDM_CR_ADDR, CLEAR_TX_READY); - - if (msm_uport->clk_state == MSM_HS_CLK_REQUEST_OFF) { - msm_uport->imr_reg |= UARTDM_ISR_TXLEV_BMSK; - msm_hs_write(uport, UARTDM_IMR_ADDR, - msm_uport->imr_reg); - } - - /* Complete DMA TX transactions and submit new transactions */ - tx_buf->tail = (tx_buf->tail + tx->tx_count) & ~UART_XMIT_SIZE; - - tx->dma_in_flight = 0; - - uport->icount.tx += tx->tx_count; - if (tx->tx_ready_int_en) - msm_hs_submit_tx_locked(uport); - - if (uart_circ_chars_pending(tx_buf) < WAKEUP_CHARS) - uart_write_wakeup(uport); - } - if (isr_status & UARTDM_ISR_TXLEV_BMSK) { - /* TX FIFO is empty */ - msm_uport->imr_reg &= ~UARTDM_ISR_TXLEV_BMSK; - msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); - if (!msm_hs_check_clock_off_locked(uport)) - hrtimer_start(&msm_uport->clk_off_timer, - msm_uport->clk_off_delay, - HRTIMER_MODE_REL); - } - - /* Change in CTS interrupt */ - if (isr_status & UARTDM_ISR_DELTA_CTS_BMSK) - msm_hs_handle_delta_cts_locked(uport); - - spin_unlock_irqrestore(&uport->lock, flags); - - return IRQ_HANDLED; -} - -void msm_hs_request_clock_off_locked(struct uart_port *uport) -{ - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - if (msm_uport->clk_state == MSM_HS_CLK_ON) { - msm_uport->clk_state = MSM_HS_CLK_REQUEST_OFF; - msm_uport->clk_req_off_state = CLK_REQ_OFF_START; - if (!use_low_power_rx_wakeup(msm_uport)) - set_rfr_locked(uport, 0); - msm_uport->imr_reg |= UARTDM_ISR_TXLEV_BMSK; - msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); - } -} - -/** - * msm_hs_request_clock_off - request to (i.e. asynchronously) turn off uart - * clock once pending TX is flushed and Rx DMA command is terminated. - * @uport: uart_port structure for the device instance. - * - * This functions puts the device into a partially active low power mode. It - * waits to complete all pending tx transactions, flushes ongoing Rx DMA - * command and terminates UART side Rx transaction, puts UART HW in non DMA - * mode and then clocks off the device. A client calls this when no UART - * data is expected. msm_request_clock_on() must be called before any further - * UART can be sent or received. - */ -void msm_hs_request_clock_off(struct uart_port *uport) -{ - unsigned long flags; - - spin_lock_irqsave(&uport->lock, flags); - msm_hs_request_clock_off_locked(uport); - spin_unlock_irqrestore(&uport->lock, flags); -} - -void msm_hs_request_clock_on_locked(struct uart_port *uport) -{ - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - unsigned int data; - - switch (msm_uport->clk_state) { - case MSM_HS_CLK_OFF: - clk_enable(msm_uport->clk); - disable_irq_nosync(msm_uport->rx_wakeup.irq); - /* fall-through */ - case MSM_HS_CLK_REQUEST_OFF: - if (msm_uport->rx.flush == FLUSH_STOP || - msm_uport->rx.flush == FLUSH_SHUTDOWN) { - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_RX); - data = msm_hs_read(uport, UARTDM_DMEN_ADDR); - data |= UARTDM_RX_DM_EN_BMSK; - msm_hs_write(uport, UARTDM_DMEN_ADDR, data); - } - hrtimer_try_to_cancel(&msm_uport->clk_off_timer); - if (msm_uport->rx.flush == FLUSH_SHUTDOWN) - msm_hs_start_rx_locked(uport); - if (!use_low_power_rx_wakeup(msm_uport)) - set_rfr_locked(uport, 1); - if (msm_uport->rx.flush == FLUSH_STOP) - msm_uport->rx.flush = FLUSH_IGNORE; - msm_uport->clk_state = MSM_HS_CLK_ON; - break; - case MSM_HS_CLK_ON: - break; - case MSM_HS_CLK_PORT_OFF: - break; - } -} - -/** - * msm_hs_request_clock_on - Switch the device from partially active low - * power mode to fully active (i.e. clock on) mode. - * @uport: uart_port structure for the device. - * - * This function switches on the input clock, puts UART HW into DMA mode - * and enqueues an Rx DMA command if the device was in partially active - * mode. It has no effect if called with the device in inactive state. - */ -void msm_hs_request_clock_on(struct uart_port *uport) -{ - unsigned long flags; - - spin_lock_irqsave(&uport->lock, flags); - msm_hs_request_clock_on_locked(uport); - spin_unlock_irqrestore(&uport->lock, flags); -} - -static irqreturn_t msm_hs_rx_wakeup_isr(int irq, void *dev) -{ - unsigned int wakeup = 0; - unsigned long flags; - struct msm_hs_port *msm_uport = dev; - struct uart_port *uport = &msm_uport->uport; - - spin_lock_irqsave(&uport->lock, flags); - if (msm_uport->clk_state == MSM_HS_CLK_OFF) { - /* ignore the first irq - it is a pending irq that occurred - * before enable_irq() */ - if (msm_uport->rx_wakeup.ignore) - msm_uport->rx_wakeup.ignore = 0; - else - wakeup = 1; - } - - if (wakeup) { - /* the uart was clocked off during an rx, wake up and - * optionally inject char into tty rx */ - msm_hs_request_clock_on_locked(uport); - if (msm_uport->rx_wakeup.inject_rx) { - tty_insert_flip_char(&uport->state->port, - msm_uport->rx_wakeup.rx_to_inject, - TTY_NORMAL); - queue_work(msm_hs_workqueue, &msm_uport->rx.tty_work); - } - } - - spin_unlock_irqrestore(&uport->lock, flags); - - return IRQ_HANDLED; -} - -static const char *msm_hs_type(struct uart_port *port) -{ - return (port->type == PORT_MSM) ? "MSM_HS_UART" : NULL; -} - -/* Called when port is opened */ -static int msm_hs_startup(struct uart_port *uport) -{ - int ret; - int rfr_level; - unsigned long flags; - unsigned int data; - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - struct circ_buf *tx_buf = &uport->state->xmit; - struct msm_hs_tx *tx = &msm_uport->tx; - struct msm_hs_rx *rx = &msm_uport->rx; - - rfr_level = uport->fifosize; - if (rfr_level > 16) - rfr_level -= 16; - - tx->dma_base = dma_map_single(uport->dev, tx_buf->buf, UART_XMIT_SIZE, - DMA_TO_DEVICE); - - /* do not let tty layer execute RX in global workqueue, use a - * dedicated workqueue managed by this driver */ - uport->state->port.low_latency = 1; - - /* turn on uart clk */ - ret = msm_hs_init_clk_locked(uport); - if (unlikely(ret)) { - printk(KERN_ERR "Turning uartclk failed!\n"); - goto err_msm_hs_init_clk; - } - - /* Set auto RFR Level */ - data = msm_hs_read(uport, UARTDM_MR1_ADDR); - data &= ~UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK; - data &= ~UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK; - data |= (UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK & (rfr_level << 2)); - data |= (UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK & rfr_level); - msm_hs_write(uport, UARTDM_MR1_ADDR, data); - - /* Make sure RXSTALE count is non-zero */ - data = msm_hs_read(uport, UARTDM_IPR_ADDR); - if (!data) { - data |= 0x1f & UARTDM_IPR_STALE_LSB_BMSK; - msm_hs_write(uport, UARTDM_IPR_ADDR, data); - } - - /* Enable Data Mover Mode */ - data = UARTDM_TX_DM_EN_BMSK | UARTDM_RX_DM_EN_BMSK; - msm_hs_write(uport, UARTDM_DMEN_ADDR, data); - - /* Reset TX */ - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX); - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_RX); - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_ERROR_STATUS); - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_BREAK_INT); - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_STALE_INT); - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_CTS); - msm_hs_write(uport, UARTDM_CR_ADDR, RFR_LOW); - /* Turn on Uart Receiver */ - msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_RX_EN_BMSK); - - /* Turn on Uart Transmitter */ - msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_TX_EN_BMSK); - - /* Initialize the tx */ - tx->tx_ready_int_en = 0; - tx->dma_in_flight = 0; - - tx->xfer.complete_func = msm_hs_dmov_tx_callback; - tx->xfer.execute_func = NULL; - - tx->command_ptr->cmd = CMD_LC | - CMD_DST_CRCI(msm_uport->dma_tx_crci) | CMD_MODE_BOX; - - tx->command_ptr->src_dst_len = (MSM_UARTDM_BURST_SIZE << 16) - | (MSM_UARTDM_BURST_SIZE); - - tx->command_ptr->row_offset = (MSM_UARTDM_BURST_SIZE << 16); - - tx->command_ptr->dst_row_addr = - msm_uport->uport.mapbase + UARTDM_TF_ADDR; - - - /* Turn on Uart Receive */ - rx->xfer.complete_func = msm_hs_dmov_rx_callback; - rx->xfer.execute_func = NULL; - - rx->command_ptr->cmd = CMD_LC | - CMD_SRC_CRCI(msm_uport->dma_rx_crci) | CMD_MODE_BOX; - - rx->command_ptr->src_dst_len = (MSM_UARTDM_BURST_SIZE << 16) - | (MSM_UARTDM_BURST_SIZE); - rx->command_ptr->row_offset = MSM_UARTDM_BURST_SIZE; - rx->command_ptr->src_row_addr = uport->mapbase + UARTDM_RF_ADDR; - - - msm_uport->imr_reg |= UARTDM_ISR_RXSTALE_BMSK; - /* Enable reading the current CTS, no harm even if CTS is ignored */ - msm_uport->imr_reg |= UARTDM_ISR_CURRENT_CTS_BMSK; - - msm_hs_write(uport, UARTDM_TFWR_ADDR, 0); /* TXLEV on empty TX fifo */ - - - ret = request_irq(uport->irq, msm_hs_isr, IRQF_TRIGGER_HIGH, - "msm_hs_uart", msm_uport); - if (unlikely(ret)) { - printk(KERN_ERR "Request msm_hs_uart IRQ failed!\n"); - goto err_request_irq; - } - if (use_low_power_rx_wakeup(msm_uport)) { - ret = request_irq(msm_uport->rx_wakeup.irq, - msm_hs_rx_wakeup_isr, - IRQF_TRIGGER_FALLING, - "msm_hs_rx_wakeup", msm_uport); - if (unlikely(ret)) { - printk(KERN_ERR "Request msm_hs_rx_wakeup IRQ failed!\n"); - free_irq(uport->irq, msm_uport); - goto err_request_irq; - } - disable_irq(msm_uport->rx_wakeup.irq); - } - - spin_lock_irqsave(&uport->lock, flags); - - msm_hs_write(uport, UARTDM_RFWR_ADDR, 0); - msm_hs_start_rx_locked(uport); - - spin_unlock_irqrestore(&uport->lock, flags); - ret = pm_runtime_set_active(uport->dev); - if (ret) - dev_err(uport->dev, "set active error:%d\n", ret); - pm_runtime_enable(uport->dev); - - return 0; - -err_request_irq: -err_msm_hs_init_clk: - dma_unmap_single(uport->dev, tx->dma_base, - UART_XMIT_SIZE, DMA_TO_DEVICE); - return ret; -} - -/* Initialize tx and rx data structures */ -static int uartdm_init_port(struct uart_port *uport) -{ - int ret = 0; - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - struct msm_hs_tx *tx = &msm_uport->tx; - struct msm_hs_rx *rx = &msm_uport->rx; - - /* Allocate the command pointer. Needs to be 64 bit aligned */ - tx->command_ptr = kmalloc(sizeof(dmov_box), GFP_KERNEL | __GFP_DMA); - if (!tx->command_ptr) - return -ENOMEM; - - tx->command_ptr_ptr = kmalloc(sizeof(u32), GFP_KERNEL | __GFP_DMA); - if (!tx->command_ptr_ptr) { - ret = -ENOMEM; - goto err_tx_command_ptr_ptr; - } - - tx->mapped_cmd_ptr = dma_map_single(uport->dev, tx->command_ptr, - sizeof(dmov_box), DMA_TO_DEVICE); - tx->mapped_cmd_ptr_ptr = dma_map_single(uport->dev, - tx->command_ptr_ptr, - sizeof(u32), DMA_TO_DEVICE); - tx->xfer.cmdptr = DMOV_CMD_ADDR(tx->mapped_cmd_ptr_ptr); - - init_waitqueue_head(&rx->wait); - - rx->pool = dma_pool_create("rx_buffer_pool", uport->dev, - UARTDM_RX_BUF_SIZE, 16, 0); - if (!rx->pool) { - pr_err("%s(): cannot allocate rx_buffer_pool", __func__); - ret = -ENOMEM; - goto err_dma_pool_create; - } - - rx->buffer = dma_pool_alloc(rx->pool, GFP_KERNEL, &rx->rbuffer); - if (!rx->buffer) { - pr_err("%s(): cannot allocate rx->buffer", __func__); - ret = -ENOMEM; - goto err_dma_pool_alloc; - } - - /* Allocate the command pointer. Needs to be 64 bit aligned */ - rx->command_ptr = kmalloc(sizeof(dmov_box), GFP_KERNEL | __GFP_DMA); - if (!rx->command_ptr) { - pr_err("%s(): cannot allocate rx->command_ptr", __func__); - ret = -ENOMEM; - goto err_rx_command_ptr; - } - - rx->command_ptr_ptr = kmalloc(sizeof(u32), GFP_KERNEL | __GFP_DMA); - if (!rx->command_ptr_ptr) { - pr_err("%s(): cannot allocate rx->command_ptr_ptr", __func__); - ret = -ENOMEM; - goto err_rx_command_ptr_ptr; - } - - rx->command_ptr->num_rows = ((UARTDM_RX_BUF_SIZE >> 4) << 16) | - (UARTDM_RX_BUF_SIZE >> 4); - - rx->command_ptr->dst_row_addr = rx->rbuffer; - - rx->mapped_cmd_ptr = dma_map_single(uport->dev, rx->command_ptr, - sizeof(dmov_box), DMA_TO_DEVICE); - - *rx->command_ptr_ptr = CMD_PTR_LP | DMOV_CMD_ADDR(rx->mapped_cmd_ptr); - - rx->cmdptr_dmaaddr = dma_map_single(uport->dev, rx->command_ptr_ptr, - sizeof(u32), DMA_TO_DEVICE); - rx->xfer.cmdptr = DMOV_CMD_ADDR(rx->cmdptr_dmaaddr); - - INIT_WORK(&rx->tty_work, msm_hs_tty_flip_buffer_work); - - return ret; - -err_rx_command_ptr_ptr: - kfree(rx->command_ptr); -err_rx_command_ptr: - dma_pool_free(msm_uport->rx.pool, msm_uport->rx.buffer, - msm_uport->rx.rbuffer); -err_dma_pool_alloc: - dma_pool_destroy(msm_uport->rx.pool); -err_dma_pool_create: - dma_unmap_single(uport->dev, msm_uport->tx.mapped_cmd_ptr_ptr, - sizeof(u32), DMA_TO_DEVICE); - dma_unmap_single(uport->dev, msm_uport->tx.mapped_cmd_ptr, - sizeof(dmov_box), DMA_TO_DEVICE); - kfree(msm_uport->tx.command_ptr_ptr); -err_tx_command_ptr_ptr: - kfree(msm_uport->tx.command_ptr); - return ret; -} - -static int msm_hs_probe(struct platform_device *pdev) -{ - int ret; - struct uart_port *uport; - struct msm_hs_port *msm_uport; - struct resource *resource; - const struct msm_serial_hs_platform_data *pdata = - dev_get_platdata(&pdev->dev); - - if (pdev->id < 0 || pdev->id >= UARTDM_NR) { - printk(KERN_ERR "Invalid plaform device ID = %d\n", pdev->id); - return -EINVAL; - } - - msm_uport = &q_uart_port[pdev->id]; - uport = &msm_uport->uport; - - uport->dev = &pdev->dev; - - resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (unlikely(!resource)) - return -ENXIO; - - uport->mapbase = resource->start; - uport->irq = platform_get_irq(pdev, 0); - if (unlikely(uport->irq < 0)) - return -ENXIO; - - if (unlikely(irq_set_irq_wake(uport->irq, 1))) - return -ENXIO; - - if (pdata == NULL || pdata->rx_wakeup_irq < 0) - msm_uport->rx_wakeup.irq = -1; - else { - msm_uport->rx_wakeup.irq = pdata->rx_wakeup_irq; - msm_uport->rx_wakeup.ignore = 1; - msm_uport->rx_wakeup.inject_rx = pdata->inject_rx_on_wakeup; - msm_uport->rx_wakeup.rx_to_inject = pdata->rx_to_inject; - - if (unlikely(msm_uport->rx_wakeup.irq < 0)) - return -ENXIO; - - if (unlikely(irq_set_irq_wake(msm_uport->rx_wakeup.irq, 1))) - return -ENXIO; - } - - if (pdata == NULL) - msm_uport->exit_lpm_cb = NULL; - else - msm_uport->exit_lpm_cb = pdata->exit_lpm_cb; - - resource = platform_get_resource_byname(pdev, IORESOURCE_DMA, - "uartdm_channels"); - if (unlikely(!resource)) - return -ENXIO; - - msm_uport->dma_tx_channel = resource->start; - msm_uport->dma_rx_channel = resource->end; - - resource = platform_get_resource_byname(pdev, IORESOURCE_DMA, - "uartdm_crci"); - if (unlikely(!resource)) - return -ENXIO; - - msm_uport->dma_tx_crci = resource->start; - msm_uport->dma_rx_crci = resource->end; - - uport->iotype = UPIO_MEM; - uport->fifosize = UART_FIFOSIZE; - uport->ops = &msm_hs_ops; - uport->flags = UPF_BOOT_AUTOCONF; - uport->uartclk = UARTCLK; - msm_uport->imr_reg = 0x0; - msm_uport->clk = clk_get(&pdev->dev, "uartdm_clk"); - if (IS_ERR(msm_uport->clk)) - return PTR_ERR(msm_uport->clk); - - ret = uartdm_init_port(uport); - if (unlikely(ret)) - return ret; - - msm_uport->clk_state = MSM_HS_CLK_PORT_OFF; - hrtimer_init(&msm_uport->clk_off_timer, CLOCK_MONOTONIC, - HRTIMER_MODE_REL); - msm_uport->clk_off_timer.function = msm_hs_clk_off_retry; - msm_uport->clk_off_delay = ktime_set(0, 1000000); /* 1ms */ - - uport->line = pdev->id; - return uart_add_one_port(&msm_hs_driver, uport); -} - -static int __init msm_serial_hs_init(void) -{ - int ret, i; - - /* Init all UARTS as non-configured */ - for (i = 0; i < UARTDM_NR; i++) - q_uart_port[i].uport.type = PORT_UNKNOWN; - - msm_hs_workqueue = create_singlethread_workqueue("msm_serial_hs"); - if (unlikely(!msm_hs_workqueue)) - return -ENOMEM; - - ret = uart_register_driver(&msm_hs_driver); - if (unlikely(ret)) { - printk(KERN_ERR "%s failed to load\n", __func__); - goto err_uart_register_driver; - } - - ret = platform_driver_register(&msm_serial_hs_platform_driver); - if (ret) { - printk(KERN_ERR "%s failed to load\n", __func__); - goto err_platform_driver_register; - } - - return ret; - -err_platform_driver_register: - uart_unregister_driver(&msm_hs_driver); -err_uart_register_driver: - destroy_workqueue(msm_hs_workqueue); - return ret; -} -module_init(msm_serial_hs_init); - -/* - * Called by the upper layer when port is closed. - * - Disables the port - * - Unhook the ISR - */ -static void msm_hs_shutdown(struct uart_port *uport) -{ - unsigned long flags; - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - BUG_ON(msm_uport->rx.flush < FLUSH_STOP); - - spin_lock_irqsave(&uport->lock, flags); - clk_enable(msm_uport->clk); - - /* Disable the transmitter */ - msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_TX_DISABLE_BMSK); - /* Disable the receiver */ - msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_RX_DISABLE_BMSK); - - pm_runtime_disable(uport->dev); - pm_runtime_set_suspended(uport->dev); - - /* Free the interrupt */ - free_irq(uport->irq, msm_uport); - if (use_low_power_rx_wakeup(msm_uport)) - free_irq(msm_uport->rx_wakeup.irq, msm_uport); - - msm_uport->imr_reg = 0; - msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); - - wait_event(msm_uport->rx.wait, msm_uport->rx.flush == FLUSH_SHUTDOWN); - - clk_disable(msm_uport->clk); /* to balance local clk_enable() */ - if (msm_uport->clk_state != MSM_HS_CLK_OFF) - clk_disable(msm_uport->clk); /* to balance clk_state */ - msm_uport->clk_state = MSM_HS_CLK_PORT_OFF; - - dma_unmap_single(uport->dev, msm_uport->tx.dma_base, - UART_XMIT_SIZE, DMA_TO_DEVICE); - - spin_unlock_irqrestore(&uport->lock, flags); - - if (cancel_work_sync(&msm_uport->rx.tty_work)) - msm_hs_tty_flip_buffer_work(&msm_uport->rx.tty_work); -} - -static void __exit msm_serial_hs_exit(void) -{ - flush_workqueue(msm_hs_workqueue); - destroy_workqueue(msm_hs_workqueue); - platform_driver_unregister(&msm_serial_hs_platform_driver); - uart_unregister_driver(&msm_hs_driver); -} -module_exit(msm_serial_hs_exit); - -#ifdef CONFIG_PM -static int msm_hs_runtime_idle(struct device *dev) -{ - /* - * returning success from idle results in runtime suspend to be - * called - */ - return 0; -} - -static int msm_hs_runtime_resume(struct device *dev) -{ - struct platform_device *pdev = container_of(dev, struct - platform_device, dev); - struct msm_hs_port *msm_uport = &q_uart_port[pdev->id]; - - msm_hs_request_clock_on(&msm_uport->uport); - return 0; -} - -static int msm_hs_runtime_suspend(struct device *dev) -{ - struct platform_device *pdev = container_of(dev, struct - platform_device, dev); - struct msm_hs_port *msm_uport = &q_uart_port[pdev->id]; - - msm_hs_request_clock_off(&msm_uport->uport); - return 0; -} -#else -#define msm_hs_runtime_idle NULL -#define msm_hs_runtime_resume NULL -#define msm_hs_runtime_suspend NULL -#endif - -static const struct dev_pm_ops msm_hs_dev_pm_ops = { - .runtime_suspend = msm_hs_runtime_suspend, - .runtime_resume = msm_hs_runtime_resume, - .runtime_idle = msm_hs_runtime_idle, -}; - -static struct platform_driver msm_serial_hs_platform_driver = { - .probe = msm_hs_probe, - .remove = msm_hs_remove, - .driver = { - .name = "msm_serial_hs", - .pm = &msm_hs_dev_pm_ops, - }, -}; - -static struct uart_driver msm_hs_driver = { - .owner = THIS_MODULE, - .driver_name = "msm_serial_hs", - .dev_name = "ttyHS", - .nr = UARTDM_NR, - .cons = 0, -}; - -static struct uart_ops msm_hs_ops = { - .tx_empty = msm_hs_tx_empty, - .set_mctrl = msm_hs_set_mctrl_locked, - .get_mctrl = msm_hs_get_mctrl_locked, - .stop_tx = msm_hs_stop_tx_locked, - .start_tx = msm_hs_start_tx_locked, - .stop_rx = msm_hs_stop_rx_locked, - .enable_ms = msm_hs_enable_ms_locked, - .break_ctl = msm_hs_break_ctl, - .startup = msm_hs_startup, - .shutdown = msm_hs_shutdown, - .set_termios = msm_hs_set_termios, - .pm = msm_hs_pm, - .type = msm_hs_type, - .config_port = msm_hs_config_port, - .release_port = msm_hs_release_port, - .request_port = msm_hs_request_port, -}; - -MODULE_DESCRIPTION("High Speed UART Driver for the MSM chipset"); -MODULE_VERSION("1.2"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/tty/serial/msm_smd_tty.c b/drivers/tty/serial/msm_smd_tty.c deleted file mode 100644 index 1238ac370bff..000000000000 --- a/drivers/tty/serial/msm_smd_tty.c +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2011, Code Aurora Forum. All rights reserved. - * Author: Brian Swetland <swetland@google.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include <linux/module.h> -#include <linux/fs.h> -#include <linux/cdev.h> -#include <linux/device.h> -#include <linux/wait.h> - -#include <linux/tty.h> -#include <linux/tty_driver.h> -#include <linux/tty_flip.h> - -#include <mach/msm_smd.h> - -#define MAX_SMD_TTYS 32 - -struct smd_tty_info { - struct tty_port port; - smd_channel_t *ch; -}; - -struct smd_tty_channel_desc { - int id; - const char *name; -}; - -static struct smd_tty_info smd_tty[MAX_SMD_TTYS]; - -static const struct smd_tty_channel_desc smd_default_tty_channels[] = { - { .id = 0, .name = "SMD_DS" }, - { .id = 27, .name = "SMD_GPSNMEA" }, -}; - -static const struct smd_tty_channel_desc *smd_tty_channels = - smd_default_tty_channels; -static int smd_tty_channels_len = ARRAY_SIZE(smd_default_tty_channels); - -static void smd_tty_notify(void *priv, unsigned event) -{ - unsigned char *ptr; - int avail; - struct smd_tty_info *info = priv; - struct tty_struct *tty; - - if (event != SMD_EVENT_DATA) - return; - - tty = tty_port_tty_get(&info->port); - if (!tty) - return; - - for (;;) { - if (test_bit(TTY_THROTTLED, &tty->flags)) - break; - avail = smd_read_avail(info->ch); - if (avail == 0) - break; - - avail = tty_prepare_flip_string(&info->port, &ptr, avail); - - if (smd_read(info->ch, ptr, avail) != avail) { - /* shouldn't be possible since we're in interrupt - ** context here and nobody else could 'steal' our - ** characters. - */ - pr_err("OOPS - smd_tty_buffer mismatch?!"); - } - - tty_flip_buffer_push(&info->port); - } - - /* XXX only when writable and necessary */ - tty_wakeup(tty); - tty_kref_put(tty); -} - -static int smd_tty_port_activate(struct tty_port *tport, struct tty_struct *tty) -{ - struct smd_tty_info *info = container_of(tport, struct smd_tty_info, - port); - int i, res = 0; - const char *name = NULL; - - for (i = 0; i < smd_tty_channels_len; i++) { - if (smd_tty_channels[i].id == tty->index) { - name = smd_tty_channels[i].name; - break; - } - } - if (!name) - return -ENODEV; - - if (info->ch) - smd_kick(info->ch); - else - res = smd_open(name, &info->ch, info, smd_tty_notify); - - if (!res) - tty->driver_data = info; - - return res; -} - -static void smd_tty_port_shutdown(struct tty_port *tport) -{ - struct smd_tty_info *info = container_of(tport, struct smd_tty_info, - port); - - if (info->ch) { - smd_close(info->ch); - info->ch = 0; - } -} - -static int smd_tty_open(struct tty_struct *tty, struct file *f) -{ - struct smd_tty_info *info = smd_tty + tty->index; - - return tty_port_open(&info->port, tty, f); -} - -static void smd_tty_close(struct tty_struct *tty, struct file *f) -{ - struct smd_tty_info *info = tty->driver_data; - - tty_port_close(&info->port, tty, f); -} - -static int smd_tty_write(struct tty_struct *tty, - const unsigned char *buf, int len) -{ - struct smd_tty_info *info = tty->driver_data; - int avail; - - /* if we're writing to a packet channel we will - ** never be able to write more data than there - ** is currently space for - */ - avail = smd_write_avail(info->ch); - if (len > avail) - len = avail; - - return smd_write(info->ch, buf, len); -} - -static int smd_tty_write_room(struct tty_struct *tty) -{ - struct smd_tty_info *info = tty->driver_data; - return smd_write_avail(info->ch); -} - -static int smd_tty_chars_in_buffer(struct tty_struct *tty) -{ - struct smd_tty_info *info = tty->driver_data; - return smd_read_avail(info->ch); -} - -static void smd_tty_unthrottle(struct tty_struct *tty) -{ - struct smd_tty_info *info = tty->driver_data; - smd_kick(info->ch); -} - -static const struct tty_port_operations smd_tty_port_ops = { - .shutdown = smd_tty_port_shutdown, - .activate = smd_tty_port_activate, -}; - -static const struct tty_operations smd_tty_ops = { - .open = smd_tty_open, - .close = smd_tty_close, - .write = smd_tty_write, - .write_room = smd_tty_write_room, - .chars_in_buffer = smd_tty_chars_in_buffer, - .unthrottle = smd_tty_unthrottle, -}; - -static struct tty_driver *smd_tty_driver; - -static int __init smd_tty_init(void) -{ - int ret, i; - - smd_tty_driver = alloc_tty_driver(MAX_SMD_TTYS); - if (smd_tty_driver == 0) - return -ENOMEM; - - smd_tty_driver->driver_name = "smd_tty_driver"; - smd_tty_driver->name = "smd"; - smd_tty_driver->major = 0; - smd_tty_driver->minor_start = 0; - smd_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; - smd_tty_driver->subtype = SERIAL_TYPE_NORMAL; - smd_tty_driver->init_termios = tty_std_termios; - smd_tty_driver->init_termios.c_iflag = 0; - smd_tty_driver->init_termios.c_oflag = 0; - smd_tty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; - smd_tty_driver->init_termios.c_lflag = 0; - smd_tty_driver->flags = TTY_DRIVER_RESET_TERMIOS | - TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; - tty_set_operations(smd_tty_driver, &smd_tty_ops); - - ret = tty_register_driver(smd_tty_driver); - if (ret) - return ret; - - for (i = 0; i < smd_tty_channels_len; i++) { - struct tty_port *port = &smd_tty[smd_tty_channels[i].id].port; - tty_port_init(port); - port->ops = &smd_tty_port_ops; - tty_port_register_device(port, smd_tty_driver, - smd_tty_channels[i].id, NULL); - } - - return 0; -} - -module_init(smd_tty_init); diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index d1298b6cc68e..13cf7738fbdc 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -169,14 +169,14 @@ struct mxs_auart_port { bool ms_irq_enabled; }; -static struct platform_device_id mxs_auart_devtype[] = { +static const struct platform_device_id mxs_auart_devtype[] = { { .name = "mxs-auart-imx23", .driver_data = IMX23_AUART }, { .name = "mxs-auart-imx28", .driver_data = IMX28_AUART }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, mxs_auart_devtype); -static struct of_device_id mxs_auart_dt_ids[] = { +static const struct of_device_id mxs_auart_dt_ids[] = { { .compatible = "fsl,imx28-auart", .data = &mxs_auart_devtype[IMX28_AUART] @@ -1155,14 +1155,14 @@ static int serial_mxs_probe_dt(struct mxs_auart_port *s, return 0; } -static bool mxs_auart_init_gpios(struct mxs_auart_port *s, struct device *dev) +static int mxs_auart_init_gpios(struct mxs_auart_port *s, struct device *dev) { enum mctrl_gpio_idx i; struct gpio_desc *gpiod; s->gpios = mctrl_gpio_init(dev, 0); - if (IS_ERR_OR_NULL(s->gpios)) - return false; + if (IS_ERR(s->gpios)) + return PTR_ERR(s->gpios); /* Block (enabled before) DMA option if RTS or CTS is GPIO line */ if (!RTS_AT_AUART() || !CTS_AT_AUART()) { @@ -1180,7 +1180,7 @@ static bool mxs_auart_init_gpios(struct mxs_auart_port *s, struct device *dev) s->gpio_irq[i] = -EINVAL; } - return true; + return 0; } static void mxs_auart_free_gpio_irq(struct mxs_auart_port *s) @@ -1276,9 +1276,11 @@ static int mxs_auart_probe(struct platform_device *pdev) platform_set_drvdata(pdev, s); - if (!mxs_auart_init_gpios(s, &pdev->dev)) - dev_err(&pdev->dev, - "Failed to initialize GPIOs. The serial port may not work as expected\n"); + ret = mxs_auart_init_gpios(s, &pdev->dev); + if (ret) { + dev_err(&pdev->dev, "Failed to initialize GPIOs.\n"); + return ret; + } /* * Get the GPIO lines IRQ diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c index 33fb94f78967..6823df99bd76 100644 --- a/drivers/tty/serial/of_serial.c +++ b/drivers/tty/serial/of_serial.c @@ -67,14 +67,17 @@ static int of_platform_serial_setup(struct platform_device *ofdev, if (of_property_read_u32(np, "clock-frequency", &clk)) { /* Get clk rate through clk driver if present */ - info->clk = clk_get(&ofdev->dev, NULL); + info->clk = devm_clk_get(&ofdev->dev, NULL); if (IS_ERR(info->clk)) { dev_warn(&ofdev->dev, "clk or clock-frequency not defined\n"); return PTR_ERR(info->clk); } - clk_prepare_enable(info->clk); + ret = clk_prepare_enable(info->clk); + if (ret < 0) + return ret; + clk = clk_get_rate(info->clk); } /* If current-speed was set, then try not to change it. */ @@ -89,6 +92,7 @@ static int of_platform_serial_setup(struct platform_device *ofdev, spin_lock_init(&port->lock); port->mapbase = resource.start; + port->mapsize = resource_size(&resource); /* Check for shifted address mapping */ if (of_property_read_u32(np, "reg-offset", &prop) == 0) @@ -115,7 +119,8 @@ static int of_platform_serial_setup(struct platform_device *ofdev, port->iotype = UPIO_MEM; break; case 4: - port->iotype = UPIO_MEM32; + port->iotype = of_device_is_big_endian(np) ? + UPIO_MEM32BE : UPIO_MEM32; break; default: dev_warn(&ofdev->dev, "unsupported reg-io-width (%d)\n", @@ -155,7 +160,7 @@ out: /* * Try to register a serial port */ -static struct of_device_id of_platform_serial_table[]; +static const struct of_device_id of_platform_serial_table[]; static int of_platform_serial_probe(struct platform_device *ofdev) { const struct of_device_id *match; @@ -186,7 +191,6 @@ static int of_platform_serial_probe(struct platform_device *ofdev) { struct uart_8250_port port8250; memset(&port8250, 0, sizeof(port8250)); - port.type = port_type; port8250.port = port; if (port.fifosize) @@ -320,7 +324,7 @@ static SIMPLE_DEV_PM_OPS(of_serial_pm_ops, of_serial_suspend, of_serial_resume); /* * A few common types, add more as needed. */ -static struct of_device_id of_platform_serial_table[] = { +static const struct of_device_id of_platform_serial_table[] = { { .compatible = "ns8250", .data = (void *)PORT_8250, }, { .compatible = "ns16450", .data = (void *)PORT_16450, }, { .compatible = "ns16550a", .data = (void *)PORT_16550A, }, @@ -344,7 +348,6 @@ static struct of_device_id of_platform_serial_table[] = { { .compatible = "ibm,qpace-nwp-serial", .data = (void *)PORT_NWPSERIAL, }, #endif - { .type = "serial", .data = (void *)PORT_UNKNOWN, }, { /* end of list */ }, }; diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 10256fa04b40..7a2172b5e93c 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -38,6 +38,7 @@ #include <linux/serial_core.h> #include <linux/irq.h> #include <linux/pm_runtime.h> +#include <linux/pm_wakeirq.h> #include <linux/of.h> #include <linux/of_irq.h> #include <linux/gpio.h> @@ -160,7 +161,6 @@ struct uart_omap_port { unsigned long port_activity; int context_loss_cnt; u32 errata; - u8 wakeups_enabled; u32 features; int rts_gpio; @@ -209,28 +209,11 @@ static int serial_omap_get_context_loss_count(struct uart_omap_port *up) return pdata->get_context_loss_count(up->dev); } -static inline void serial_omap_enable_wakeirq(struct uart_omap_port *up, - bool enable) -{ - if (!up->wakeirq) - return; - - if (enable) - enable_irq(up->wakeirq); - else - disable_irq_nosync(up->wakeirq); -} - +/* REVISIT: Remove this when omap3 boots in device tree only mode */ static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable) { struct omap_uart_port_info *pdata = dev_get_platdata(up->dev); - if (enable == up->wakeups_enabled) - return; - - serial_omap_enable_wakeirq(up, enable); - up->wakeups_enabled = enable; - if (!pdata || !pdata->enable_wakeup) return; @@ -750,13 +733,11 @@ static int serial_omap_startup(struct uart_port *port) /* Optional wake-up IRQ */ if (up->wakeirq) { - retval = request_irq(up->wakeirq, serial_omap_irq, - up->port.irqflags, up->name, up); + retval = dev_pm_set_dedicated_wake_irq(up->dev, up->wakeirq); if (retval) { free_irq(up->port.irq, up); return retval; } - disable_irq(up->wakeirq); } dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->port.line); @@ -845,8 +826,7 @@ static void serial_omap_shutdown(struct uart_port *port) pm_runtime_mark_last_busy(up->dev); pm_runtime_put_autosuspend(up->dev); free_irq(up->port.irq, up); - if (up->wakeirq) - free_irq(up->wakeirq, up); + dev_pm_clear_wake_irq(up->dev); } static void serial_omap_uart_qos_work(struct work_struct *work) @@ -1139,13 +1119,6 @@ serial_omap_pm(struct uart_port *port, unsigned int state, serial_out(up, UART_EFR, efr); serial_out(up, UART_LCR, 0); - if (!device_may_wakeup(up->dev)) { - if (!state) - pm_runtime_forbid(up->dev); - else - pm_runtime_allow(up->dev); - } - pm_runtime_mark_last_busy(up->dev); pm_runtime_put_autosuspend(up->dev); } @@ -1654,11 +1627,6 @@ static int serial_omap_probe(struct platform_device *pdev) up->port.type = PORT_OMAP; up->port.iotype = UPIO_MEM; up->port.irq = uartirq; - up->wakeirq = wakeirq; - if (!up->wakeirq) - dev_info(up->port.dev, "no wakeirq for uart%d\n", - up->port.line); - up->port.regshift = 2; up->port.fifosize = 64; up->port.ops = &serial_omap_pops; @@ -1682,6 +1650,11 @@ static int serial_omap_probe(struct platform_device *pdev) goto err_port_line; } + up->wakeirq = wakeirq; + if (!up->wakeirq) + dev_info(up->port.dev, "no wakeirq for uart%d\n", + up->port.line); + ret = serial_omap_probe_rs485(up, pdev->dev.of_node); if (ret < 0) goto err_rs485; @@ -1735,6 +1708,8 @@ static int serial_omap_probe(struct platform_device *pdev) err_add_port: pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); + pm_qos_remove_request(&up->pm_qos_request); + device_init_wakeup(up->dev, false); err_rs485: err_port_line: return ret; diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index 8f515799c9c1..e156e39d620c 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -1846,7 +1846,7 @@ static int __init pmz_register(void) #ifdef CONFIG_PPC_PMAC -static struct of_device_id pmz_match[] = +static const struct of_device_id pmz_match[] = { { .name = "ch-a", diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c index d5d062694bd3..9becba654892 100644 --- a/drivers/tty/serial/pxa.c +++ b/drivers/tty/serial/pxa.c @@ -824,7 +824,7 @@ static const struct dev_pm_ops serial_pxa_pm_ops = { }; #endif -static struct of_device_id serial_pxa_dt_ids[] = { +static const struct of_device_id serial_pxa_dt_ids[] = { { .compatible = "mrvl,pxa-uart", }, { .compatible = "mrvl,mmp-uart", }, {} diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index cf08876922f1..67d0c213b1c7 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -348,7 +348,7 @@ static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport) s3c24xx_serial_start_tx_dma(ourport, count); } -void s3c24xx_serial_start_tx(struct uart_port *port) +static void s3c24xx_serial_start_tx(struct uart_port *port) { struct s3c24xx_uart_port *ourport = to_ourport(port); struct circ_buf *xmit = &port->state->xmit; @@ -1068,8 +1068,9 @@ static int s3c64xx_serial_startup(struct uart_port *port) spin_lock_irqsave(&port->lock, flags); ufcon = rd_regl(port, S3C2410_UFCON); - ufcon |= S3C2410_UFCON_RESETRX | S3C2410_UFCON_RESETTX | - S5PV210_UFCON_RXTRIG8; + ufcon |= S3C2410_UFCON_RESETRX | S5PV210_UFCON_RXTRIG8; + if (!uart_console(port)) + ufcon |= S3C2410_UFCON_RESETTX; wr_regl(port, S3C2410_UFCON, ufcon); enable_rx_pio(ourport); @@ -2336,7 +2337,7 @@ static struct s3c24xx_serial_drv_data exynos5433_serial_drv_data = { #define EXYNOS5433_SERIAL_DRV_DATA (kernel_ulong_t)NULL #endif -static struct platform_device_id s3c24xx_serial_driver_ids[] = { +static const struct platform_device_id s3c24xx_serial_driver_ids[] = { { .name = "s3c2410-uart", .driver_data = S3C2410_SERIAL_DRV_DATA, diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index df9a384dfbda..9e6576004a42 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -25,6 +25,7 @@ #include <linux/serial.h> #include <linux/tty.h> #include <linux/tty_flip.h> +#include <linux/spi/spi.h> #include <linux/uaccess.h> #define SC16IS7XX_NAME "sc16is7xx" @@ -300,25 +301,38 @@ struct sc16is7xx_devtype { int nr_uart; }; +#define SC16IS7XX_RECONF_MD (1 << 0) +#define SC16IS7XX_RECONF_IER (1 << 1) +#define SC16IS7XX_RECONF_RS485 (1 << 2) + +struct sc16is7xx_one_config { + unsigned int flags; + u8 ier_clear; +}; + struct sc16is7xx_one { struct uart_port port; - struct work_struct tx_work; - struct work_struct md_work; + struct kthread_work tx_work; + struct kthread_work reg_work; + struct sc16is7xx_one_config config; }; struct sc16is7xx_port { struct uart_driver uart; struct sc16is7xx_devtype *devtype; struct regmap *regmap; - struct mutex mutex; struct clk *clk; #ifdef CONFIG_GPIOLIB struct gpio_chip gpio; #endif unsigned char buf[SC16IS7XX_FIFO_SIZE]; + struct kthread_worker kworker; + struct task_struct *kworker_task; + struct kthread_work irq_work; struct sc16is7xx_one p[0]; }; +#define to_sc16is7xx_port(p,e) ((container_of((p), struct sc16is7xx_port, e))) #define to_sc16is7xx_one(p,e) ((container_of((p), struct sc16is7xx_one, e))) static u8 sc16is7xx_port_read(struct uart_port *port, u8 reg) @@ -615,9 +629,7 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) !!(msr & SC16IS7XX_MSR_CTS_BIT)); break; case SC16IS7XX_IIR_THRI_SRC: - mutex_lock(&s->mutex); sc16is7xx_handle_tx(port); - mutex_unlock(&s->mutex); break; default: dev_err_ratelimited(port->dev, @@ -628,81 +640,115 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) } while (1); } -static irqreturn_t sc16is7xx_ist(int irq, void *dev_id) +static void sc16is7xx_ist(struct kthread_work *ws) { - struct sc16is7xx_port *s = (struct sc16is7xx_port *)dev_id; + struct sc16is7xx_port *s = to_sc16is7xx_port(ws, irq_work); int i; for (i = 0; i < s->uart.nr; ++i) sc16is7xx_port_irq(s, i); +} + +static irqreturn_t sc16is7xx_irq(int irq, void *dev_id) +{ + struct sc16is7xx_port *s = (struct sc16is7xx_port *)dev_id; + + queue_kthread_work(&s->kworker, &s->irq_work); return IRQ_HANDLED; } -static void sc16is7xx_wq_proc(struct work_struct *ws) +static void sc16is7xx_tx_proc(struct kthread_work *ws) { - struct sc16is7xx_one *one = to_sc16is7xx_one(ws, tx_work); - struct sc16is7xx_port *s = dev_get_drvdata(one->port.dev); + struct uart_port *port = &(to_sc16is7xx_one(ws, tx_work)->port); + + if ((port->rs485.flags & SER_RS485_ENABLED) && + (port->rs485.delay_rts_before_send > 0)) + msleep(port->rs485.delay_rts_before_send); - mutex_lock(&s->mutex); - sc16is7xx_handle_tx(&one->port); - mutex_unlock(&s->mutex); + sc16is7xx_handle_tx(port); } -static void sc16is7xx_stop_tx(struct uart_port* port) +static void sc16is7xx_reconf_rs485(struct uart_port *port) { - struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); - struct circ_buf *xmit = &one->port.state->xmit; - - /* handle rs485 */ - if (port->rs485.flags & SER_RS485_ENABLED) { - /* do nothing if current tx not yet completed */ - int lsr = sc16is7xx_port_read(port, SC16IS7XX_LSR_REG); - if (!(lsr & SC16IS7XX_LSR_TEMT_BIT)) - return; - - if (uart_circ_empty(xmit) && - (port->rs485.delay_rts_after_send > 0)) - mdelay(port->rs485.delay_rts_after_send); + const u32 mask = SC16IS7XX_EFCR_AUTO_RS485_BIT | + SC16IS7XX_EFCR_RTS_INVERT_BIT; + u32 efcr = 0; + struct serial_rs485 *rs485 = &port->rs485; + unsigned long irqflags; + + spin_lock_irqsave(&port->lock, irqflags); + if (rs485->flags & SER_RS485_ENABLED) { + efcr |= SC16IS7XX_EFCR_AUTO_RS485_BIT; + + if (rs485->flags & SER_RS485_RTS_AFTER_SEND) + efcr |= SC16IS7XX_EFCR_RTS_INVERT_BIT; } + spin_unlock_irqrestore(&port->lock, irqflags); - sc16is7xx_port_update(port, SC16IS7XX_IER_REG, - SC16IS7XX_IER_THRI_BIT, - 0); + sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, mask, efcr); +} + +static void sc16is7xx_reg_proc(struct kthread_work *ws) +{ + struct sc16is7xx_one *one = to_sc16is7xx_one(ws, reg_work); + struct sc16is7xx_one_config config; + unsigned long irqflags; + + spin_lock_irqsave(&one->port.lock, irqflags); + config = one->config; + memset(&one->config, 0, sizeof(one->config)); + spin_unlock_irqrestore(&one->port.lock, irqflags); + + if (config.flags & SC16IS7XX_RECONF_MD) + sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG, + SC16IS7XX_MCR_LOOP_BIT, + (one->port.mctrl & TIOCM_LOOP) ? + SC16IS7XX_MCR_LOOP_BIT : 0); + + if (config.flags & SC16IS7XX_RECONF_IER) + sc16is7xx_port_update(&one->port, SC16IS7XX_IER_REG, + config.ier_clear, 0); + + if (config.flags & SC16IS7XX_RECONF_RS485) + sc16is7xx_reconf_rs485(&one->port); } -static void sc16is7xx_stop_rx(struct uart_port* port) +static void sc16is7xx_ier_clear(struct uart_port *port, u8 bit) { + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); - one->port.read_status_mask &= ~SC16IS7XX_LSR_DR_BIT; - sc16is7xx_port_update(port, SC16IS7XX_IER_REG, - SC16IS7XX_LSR_DR_BIT, - 0); + one->config.flags |= SC16IS7XX_RECONF_IER; + one->config.ier_clear |= bit; + queue_kthread_work(&s->kworker, &one->reg_work); +} + +static void sc16is7xx_stop_tx(struct uart_port *port) +{ + sc16is7xx_ier_clear(port, SC16IS7XX_IER_THRI_BIT); +} + +static void sc16is7xx_stop_rx(struct uart_port *port) +{ + sc16is7xx_ier_clear(port, SC16IS7XX_IER_RDI_BIT); } static void sc16is7xx_start_tx(struct uart_port *port) { + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); - /* handle rs485 */ - if ((port->rs485.flags & SER_RS485_ENABLED) && - (port->rs485.delay_rts_before_send > 0)) { - mdelay(port->rs485.delay_rts_before_send); - } - - if (!work_pending(&one->tx_work)) - schedule_work(&one->tx_work); + queue_kthread_work(&s->kworker, &one->tx_work); } static unsigned int sc16is7xx_tx_empty(struct uart_port *port) { - unsigned int lvl, lsr; + unsigned int lsr; - lvl = sc16is7xx_port_read(port, SC16IS7XX_TXLVL_REG); lsr = sc16is7xx_port_read(port, SC16IS7XX_LSR_REG); - return ((lsr & SC16IS7XX_LSR_THRE_BIT) && !lvl) ? TIOCSER_TEMT : 0; + return (lsr & SC16IS7XX_LSR_TEMT_BIT) ? TIOCSER_TEMT : 0; } static unsigned int sc16is7xx_get_mctrl(struct uart_port *port) @@ -713,21 +759,13 @@ static unsigned int sc16is7xx_get_mctrl(struct uart_port *port) return TIOCM_DSR | TIOCM_CAR; } -static void sc16is7xx_md_proc(struct work_struct *ws) -{ - struct sc16is7xx_one *one = to_sc16is7xx_one(ws, md_work); - - sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG, - SC16IS7XX_MCR_LOOP_BIT, - (one->port.mctrl & TIOCM_LOOP) ? - SC16IS7XX_MCR_LOOP_BIT : 0); -} - static void sc16is7xx_set_mctrl(struct uart_port *port, unsigned int mctrl) { + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); - schedule_work(&one->md_work); + one->config.flags |= SC16IS7XX_RECONF_MD; + queue_kthread_work(&s->kworker, &one->reg_work); } static void sc16is7xx_break_ctl(struct uart_port *port, int break_state) @@ -829,17 +867,34 @@ static void sc16is7xx_set_termios(struct uart_port *port, } static int sc16is7xx_config_rs485(struct uart_port *port, - struct serial_rs485 *rs485) + struct serial_rs485 *rs485) { - if (port->rs485.flags & SER_RS485_ENABLED) - sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, - SC16IS7XX_EFCR_AUTO_RS485_BIT, - SC16IS7XX_EFCR_AUTO_RS485_BIT); - else - sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, - SC16IS7XX_EFCR_AUTO_RS485_BIT, - 0); + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + + if (rs485->flags & SER_RS485_ENABLED) { + bool rts_during_rx, rts_during_tx; + + rts_during_rx = rs485->flags & SER_RS485_RTS_AFTER_SEND; + rts_during_tx = rs485->flags & SER_RS485_RTS_ON_SEND; + + if (rts_during_rx == rts_during_tx) + dev_err(port->dev, + "unsupported RTS signalling on_send:%d after_send:%d - exactly one of RS485 RTS flags should be set\n", + rts_during_tx, rts_during_rx); + + /* + * RTS signal is handled by HW, it's timing can't be influenced. + * However, it's sometimes useful to delay TX even without RTS + * control therefore we try to handle .delay_rts_before_send. + */ + if (rs485->delay_rts_after_send) + return -EINVAL; + } + port->rs485 = *rs485; + one->config.flags |= SC16IS7XX_RECONF_RS485; + queue_kthread_work(&s->kworker, &one->reg_work); return 0; } @@ -900,14 +955,20 @@ static int sc16is7xx_startup(struct uart_port *port) static void sc16is7xx_shutdown(struct uart_port *port) { + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + /* Disable all interrupts */ sc16is7xx_port_write(port, SC16IS7XX_IER_REG, 0); /* Disable TX/RX */ - sc16is7xx_port_write(port, SC16IS7XX_EFCR_REG, - SC16IS7XX_EFCR_RXDISABLE_BIT | - SC16IS7XX_EFCR_TXDISABLE_BIT); + sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, + SC16IS7XX_EFCR_RXDISABLE_BIT | + SC16IS7XX_EFCR_TXDISABLE_BIT, + SC16IS7XX_EFCR_RXDISABLE_BIT | + SC16IS7XX_EFCR_TXDISABLE_BIT); sc16is7xx_power(port, 0); + + flush_kthread_worker(&s->kworker); } static const char *sc16is7xx_type(struct uart_port *port) @@ -1025,6 +1086,7 @@ static int sc16is7xx_probe(struct device *dev, struct sc16is7xx_devtype *devtype, struct regmap *regmap, int irq, unsigned long flags) { + struct sched_param sched_param = { .sched_priority = MAX_RT_PRIO / 2 }; unsigned long freq, *pfreq = dev_get_platdata(dev); int i, ret; struct sc16is7xx_port *s; @@ -1048,6 +1110,7 @@ static int sc16is7xx_probe(struct device *dev, else return PTR_ERR(s->clk); } else { + clk_prepare_enable(s->clk); freq = clk_get_rate(s->clk); } @@ -1065,6 +1128,16 @@ static int sc16is7xx_probe(struct device *dev, goto out_clk; } + init_kthread_worker(&s->kworker); + init_kthread_work(&s->irq_work, sc16is7xx_ist); + s->kworker_task = kthread_run(kthread_worker_fn, &s->kworker, + "sc16is7xx"); + if (IS_ERR(s->kworker_task)) { + ret = PTR_ERR(s->kworker_task); + goto out_uart; + } + sched_setscheduler(s->kworker_task, SCHED_FIFO, &sched_param); + #ifdef CONFIG_GPIOLIB if (devtype->nr_gpio) { /* Setup GPIO cotroller */ @@ -1080,12 +1153,10 @@ static int sc16is7xx_probe(struct device *dev, s->gpio.can_sleep = 1; ret = gpiochip_add(&s->gpio); if (ret) - goto out_uart; + goto out_thread; } #endif - mutex_init(&s->mutex); - for (i = 0; i < devtype->nr_uart; ++i) { /* Initialize port data */ s->p[i].port.line = i; @@ -1104,10 +1175,9 @@ static int sc16is7xx_probe(struct device *dev, sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_EFCR_REG, SC16IS7XX_EFCR_RXDISABLE_BIT | SC16IS7XX_EFCR_TXDISABLE_BIT); - /* Initialize queue for start TX */ - INIT_WORK(&s->p[i].tx_work, sc16is7xx_wq_proc); - /* Initialize queue for changing mode */ - INIT_WORK(&s->p[i].md_work, sc16is7xx_md_proc); + /* Initialize kthread work structs */ + init_kthread_work(&s->p[i].tx_work, sc16is7xx_tx_proc); + init_kthread_work(&s->p[i].reg_work, sc16is7xx_reg_proc); /* Register port */ uart_add_one_port(&s->uart, &s->p[i].port); /* Go to suspend mode */ @@ -1115,19 +1185,23 @@ static int sc16is7xx_probe(struct device *dev, } /* Setup interrupt */ - ret = devm_request_threaded_irq(dev, irq, NULL, sc16is7xx_ist, - IRQF_ONESHOT | flags, dev_name(dev), s); + ret = devm_request_irq(dev, irq, sc16is7xx_irq, + IRQF_ONESHOT | flags, dev_name(dev), s); if (!ret) return 0; - mutex_destroy(&s->mutex); + for (i = 0; i < s->uart.nr; i++) + uart_remove_one_port(&s->uart, &s->p[i].port); #ifdef CONFIG_GPIOLIB if (devtype->nr_gpio) gpiochip_remove(&s->gpio); -out_uart: +out_thread: #endif + kthread_stop(s->kworker_task); + +out_uart: uart_unregister_driver(&s->uart); out_clk: @@ -1148,13 +1222,13 @@ static int sc16is7xx_remove(struct device *dev) #endif for (i = 0; i < s->uart.nr; i++) { - cancel_work_sync(&s->p[i].tx_work); - cancel_work_sync(&s->p[i].md_work); uart_remove_one_port(&s->uart, &s->p[i].port); sc16is7xx_power(&s->p[i].port, 0); } - mutex_destroy(&s->mutex); + flush_kthread_worker(&s->kworker); + kthread_stop(s->kworker_task); + uart_unregister_driver(&s->uart); if (!IS_ERR(s->clk)) clk_disable_unprepare(s->clk); @@ -1182,6 +1256,75 @@ static struct regmap_config regcfg = { .precious_reg = sc16is7xx_regmap_precious, }; +#ifdef CONFIG_SERIAL_SC16IS7XX_SPI +static int sc16is7xx_spi_probe(struct spi_device *spi) +{ + struct sc16is7xx_devtype *devtype; + unsigned long flags = 0; + struct regmap *regmap; + int ret; + + /* Setup SPI bus */ + spi->bits_per_word = 8; + /* only supports mode 0 on SC16IS762 */ + spi->mode = spi->mode ? : SPI_MODE_0; + spi->max_speed_hz = spi->max_speed_hz ? : 15000000; + ret = spi_setup(spi); + if (ret) + return ret; + + if (spi->dev.of_node) { + const struct of_device_id *of_id = + of_match_device(sc16is7xx_dt_ids, &spi->dev); + + devtype = (struct sc16is7xx_devtype *)of_id->data; + } else { + const struct spi_device_id *id_entry = spi_get_device_id(spi); + + devtype = (struct sc16is7xx_devtype *)id_entry->driver_data; + flags = IRQF_TRIGGER_FALLING; + } + + regcfg.max_register = (0xf << SC16IS7XX_REG_SHIFT) | + (devtype->nr_uart - 1); + regmap = devm_regmap_init_spi(spi, ®cfg); + + return sc16is7xx_probe(&spi->dev, devtype, regmap, spi->irq, flags); +} + +static int sc16is7xx_spi_remove(struct spi_device *spi) +{ + return sc16is7xx_remove(&spi->dev); +} + +static const struct spi_device_id sc16is7xx_spi_id_table[] = { + { "sc16is74x", (kernel_ulong_t)&sc16is74x_devtype, }, + { "sc16is740", (kernel_ulong_t)&sc16is74x_devtype, }, + { "sc16is741", (kernel_ulong_t)&sc16is74x_devtype, }, + { "sc16is750", (kernel_ulong_t)&sc16is750_devtype, }, + { "sc16is752", (kernel_ulong_t)&sc16is752_devtype, }, + { "sc16is760", (kernel_ulong_t)&sc16is760_devtype, }, + { "sc16is762", (kernel_ulong_t)&sc16is762_devtype, }, + { } +}; + +MODULE_DEVICE_TABLE(spi, sc16is7xx_spi_id_table); + +static struct spi_driver sc16is7xx_spi_uart_driver = { + .driver = { + .name = SC16IS7XX_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(sc16is7xx_dt_ids), + }, + .probe = sc16is7xx_spi_probe, + .remove = sc16is7xx_spi_remove, + .id_table = sc16is7xx_spi_id_table, +}; + +MODULE_ALIAS("spi:sc16is7xx"); +#endif + +#ifdef CONFIG_SERIAL_SC16IS7XX_I2C static int sc16is7xx_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -1213,6 +1356,8 @@ static int sc16is7xx_i2c_remove(struct i2c_client *client) static const struct i2c_device_id sc16is7xx_i2c_id_table[] = { { "sc16is74x", (kernel_ulong_t)&sc16is74x_devtype, }, + { "sc16is740", (kernel_ulong_t)&sc16is74x_devtype, }, + { "sc16is741", (kernel_ulong_t)&sc16is74x_devtype, }, { "sc16is750", (kernel_ulong_t)&sc16is750_devtype, }, { "sc16is752", (kernel_ulong_t)&sc16is752_devtype, }, { "sc16is760", (kernel_ulong_t)&sc16is760_devtype, }, @@ -1231,8 +1376,43 @@ static struct i2c_driver sc16is7xx_i2c_uart_driver = { .remove = sc16is7xx_i2c_remove, .id_table = sc16is7xx_i2c_id_table, }; -module_i2c_driver(sc16is7xx_i2c_uart_driver); + MODULE_ALIAS("i2c:sc16is7xx"); +#endif + +static int __init sc16is7xx_init(void) +{ + int ret = 0; +#ifdef CONFIG_SERIAL_SC16IS7XX_I2C + ret = i2c_add_driver(&sc16is7xx_i2c_uart_driver); + if (ret < 0) { + pr_err("failed to init sc16is7xx i2c --> %d\n", ret); + return ret; + } +#endif + +#ifdef CONFIG_SERIAL_SC16IS7XX_SPI + ret = spi_register_driver(&sc16is7xx_spi_uart_driver); + if (ret < 0) { + pr_err("failed to init sc16is7xx spi --> %d\n", ret); + return ret; + } +#endif + return ret; +} +module_init(sc16is7xx_init); + +static void __exit sc16is7xx_exit(void) +{ +#ifdef CONFIG_SERIAL_SC16IS7XX_I2C + i2c_del_driver(&sc16is7xx_i2c_uart_driver); +#endif + +#ifdef CONFIG_SERIAL_SC16IS7XX_SPI + spi_unregister_driver(&sc16is7xx_spi_uart_driver); +#endif +} +module_exit(sc16is7xx_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jon Ringle <jringle@gridpoint.com>"); diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c index 48e6e41636b2..cf0133ae762d 100644 --- a/drivers/tty/serial/serial-tegra.c +++ b/drivers/tty/serial/serial-tegra.c @@ -131,8 +131,8 @@ struct tegra_uart_port { struct dma_async_tx_descriptor *rx_dma_desc; dma_cookie_t tx_cookie; dma_cookie_t rx_cookie; - int tx_bytes_requested; - int rx_bytes_requested; + unsigned int tx_bytes_requested; + unsigned int rx_bytes_requested; }; static void tegra_uart_start_next_tx(struct tegra_uart_port *tup); @@ -234,6 +234,22 @@ static void tegra_uart_break_ctl(struct uart_port *u, int break_ctl) tup->lcr_shadow = lcr; } +/** + * tegra_uart_wait_cycle_time: Wait for N UART clock periods + * + * @tup: Tegra serial port data structure. + * @cycles: Number of clock periods to wait. + * + * Tegra UARTs are clocked at 16X the baud/bit rate and hence the UART + * clock speed is 16X the current baud rate. + */ +static void tegra_uart_wait_cycle_time(struct tegra_uart_port *tup, + unsigned int cycles) +{ + if (tup->current_baud) + udelay(DIV_ROUND_UP(cycles * 1000000, tup->current_baud * 16)); +} + /* Wait for a symbol-time. */ static void tegra_uart_wait_sym_time(struct tegra_uart_port *tup, unsigned int syms) @@ -263,8 +279,12 @@ static void tegra_uart_fifo_reset(struct tegra_uart_port *tup, u8 fcr_bits) /* Dummy read to ensure the write is posted */ tegra_uart_read(tup, UART_SCR); - /* Wait for the flush to propagate. */ - tegra_uart_wait_sym_time(tup, 1); + /* + * For all tegra devices (up to t210), there is a hardware issue that + * requires software to wait for 32 UART clock periods for the flush + * to propagate, otherwise data could be lost. + */ + tegra_uart_wait_cycle_time(tup, 32); } static int tegra_set_baudrate(struct tegra_uart_port *tup, unsigned int baud) @@ -388,9 +408,9 @@ static void tegra_uart_tx_dma_complete(void *args) struct circ_buf *xmit = &tup->uport.state->xmit; struct dma_tx_state state; unsigned long flags; - int count; + unsigned int count; - dmaengine_tx_status(tup->tx_dma_chan, tup->rx_cookie, &state); + dmaengine_tx_status(tup->tx_dma_chan, tup->tx_cookie, &state); count = tup->tx_bytes_requested - state.residue; async_tx_ack(tup->tx_dma_desc); spin_lock_irqsave(&tup->uport.lock, flags); @@ -480,7 +500,7 @@ static void tegra_uart_stop_tx(struct uart_port *u) struct tegra_uart_port *tup = to_tegra_uport(u); struct circ_buf *xmit = &tup->uport.state->xmit; struct dma_tx_state state; - int count; + unsigned int count; if (tup->tx_in_progress != TEGRA_UART_TX_DMA) return; @@ -530,10 +550,15 @@ static void tegra_uart_handle_rx_pio(struct tegra_uart_port *tup, } static void tegra_uart_copy_rx_to_tty(struct tegra_uart_port *tup, - struct tty_port *tty, int count) + struct tty_port *tty, + unsigned int count) { int copied; + /* If count is zero, then there is no data to be copied */ + if (!count) + return; + tup->uport.icount.rx += count; if (!tty) { dev_err(tup->uport.dev, "No tty port\n"); @@ -555,21 +580,30 @@ static void tegra_uart_rx_dma_complete(void *args) { struct tegra_uart_port *tup = args; struct uart_port *u = &tup->uport; - int count = tup->rx_bytes_requested; + unsigned int count = tup->rx_bytes_requested; struct tty_struct *tty = tty_port_tty_get(&tup->uport.state->port); struct tty_port *port = &u->state->port; unsigned long flags; + struct dma_tx_state state; + enum dma_status status; - async_tx_ack(tup->rx_dma_desc); spin_lock_irqsave(&u->lock, flags); + status = dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state); + + if (status == DMA_IN_PROGRESS) { + dev_dbg(tup->uport.dev, "RX DMA is in progress\n"); + goto done; + } + + async_tx_ack(tup->rx_dma_desc); + /* Deactivate flow control to stop sender */ if (tup->rts_active) set_rts(tup, false); /* If we are here, DMA is stopped */ - if (count) - tegra_uart_copy_rx_to_tty(tup, port, count); + tegra_uart_copy_rx_to_tty(tup, port, count); tegra_uart_handle_rx_pio(tup, port); if (tty) { @@ -584,6 +618,7 @@ static void tegra_uart_rx_dma_complete(void *args) if (tup->rts_active) set_rts(tup, true); +done: spin_unlock_irqrestore(&u->lock, flags); } @@ -594,7 +629,7 @@ static void tegra_uart_handle_rx_dma(struct tegra_uart_port *tup, struct tty_struct *tty = tty_port_tty_get(&tup->uport.state->port); struct tty_port *port = &tup->uport.state->port; struct uart_port *u = &tup->uport; - int count; + unsigned int count; /* Deactivate flow control to stop sender */ if (tup->rts_active) @@ -606,8 +641,7 @@ static void tegra_uart_handle_rx_dma(struct tegra_uart_port *tup, count = tup->rx_bytes_requested - state.residue; /* If we are here, DMA is stopped */ - if (count) - tegra_uart_copy_rx_to_tty(tup, port, count); + tegra_uart_copy_rx_to_tty(tup, port, count); tegra_uart_handle_rx_pio(tup, port); if (tty) { @@ -865,6 +899,16 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup) tup->fcr_shadow |= TEGRA_UART_TX_TRIG_16B; tegra_uart_write(tup, tup->fcr_shadow, UART_FCR); + /* Dummy read to ensure the write is posted */ + tegra_uart_read(tup, UART_SCR); + + /* + * For all tegra devices (up to t210), there is a hardware issue that + * requires software to wait for 3 UART clock periods after enabling + * the TX fifo, otherwise data could be lost. + */ + tegra_uart_wait_cycle_time(tup, 3); + /* * Initialize the UART with default configuration * (115200, N, 8, 1) so that the receive DMA buffer may be @@ -905,6 +949,28 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup) return 0; } +static void tegra_uart_dma_channel_free(struct tegra_uart_port *tup, + bool dma_to_memory) +{ + if (dma_to_memory) { + dmaengine_terminate_all(tup->rx_dma_chan); + dma_release_channel(tup->rx_dma_chan); + dma_free_coherent(tup->uport.dev, TEGRA_UART_RX_DMA_BUFFER_SIZE, + tup->rx_dma_buf_virt, tup->rx_dma_buf_phys); + tup->rx_dma_chan = NULL; + tup->rx_dma_buf_phys = 0; + tup->rx_dma_buf_virt = NULL; + } else { + dmaengine_terminate_all(tup->tx_dma_chan); + dma_release_channel(tup->tx_dma_chan); + dma_unmap_single(tup->uport.dev, tup->tx_dma_buf_phys, + UART_XMIT_SIZE, DMA_TO_DEVICE); + tup->tx_dma_chan = NULL; + tup->tx_dma_buf_phys = 0; + tup->tx_dma_buf_virt = NULL; + } +} + static int tegra_uart_dma_channel_allocate(struct tegra_uart_port *tup, bool dma_to_memory) { @@ -933,67 +999,39 @@ static int tegra_uart_dma_channel_allocate(struct tegra_uart_port *tup, dma_release_channel(dma_chan); return -ENOMEM; } + dma_sconfig.src_addr = tup->uport.mapbase; + dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + dma_sconfig.src_maxburst = 4; + tup->rx_dma_chan = dma_chan; + tup->rx_dma_buf_virt = dma_buf; + tup->rx_dma_buf_phys = dma_phys; } else { dma_phys = dma_map_single(tup->uport.dev, tup->uport.state->xmit.buf, UART_XMIT_SIZE, DMA_TO_DEVICE); + if (dma_mapping_error(tup->uport.dev, dma_phys)) { + dev_err(tup->uport.dev, "dma_map_single tx failed\n"); + dma_release_channel(dma_chan); + return -ENOMEM; + } dma_buf = tup->uport.state->xmit.buf; - } - - if (dma_to_memory) { - dma_sconfig.src_addr = tup->uport.mapbase; - dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; - dma_sconfig.src_maxburst = 4; - } else { dma_sconfig.dst_addr = tup->uport.mapbase; dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; dma_sconfig.dst_maxburst = 16; + tup->tx_dma_chan = dma_chan; + tup->tx_dma_buf_virt = dma_buf; + tup->tx_dma_buf_phys = dma_phys; } ret = dmaengine_slave_config(dma_chan, &dma_sconfig); if (ret < 0) { dev_err(tup->uport.dev, "Dma slave config failed, err = %d\n", ret); - goto scrub; + tegra_uart_dma_channel_free(tup, dma_to_memory); + return ret; } - if (dma_to_memory) { - tup->rx_dma_chan = dma_chan; - tup->rx_dma_buf_virt = dma_buf; - tup->rx_dma_buf_phys = dma_phys; - } else { - tup->tx_dma_chan = dma_chan; - tup->tx_dma_buf_virt = dma_buf; - tup->tx_dma_buf_phys = dma_phys; - } return 0; - -scrub: - dma_release_channel(dma_chan); - return ret; -} - -static void tegra_uart_dma_channel_free(struct tegra_uart_port *tup, - bool dma_to_memory) -{ - struct dma_chan *dma_chan; - - if (dma_to_memory) { - dma_free_coherent(tup->uport.dev, TEGRA_UART_RX_DMA_BUFFER_SIZE, - tup->rx_dma_buf_virt, tup->rx_dma_buf_phys); - dma_chan = tup->rx_dma_chan; - tup->rx_dma_chan = NULL; - tup->rx_dma_buf_phys = 0; - tup->rx_dma_buf_virt = NULL; - } else { - dma_unmap_single(tup->uport.dev, tup->tx_dma_buf_phys, - UART_XMIT_SIZE, DMA_TO_DEVICE); - dma_chan = tup->tx_dma_chan; - tup->tx_dma_chan = NULL; - tup->tx_dma_buf_phys = 0; - tup->tx_dma_buf_virt = NULL; - } - dma_release_channel(dma_chan); } static int tegra_uart_startup(struct uart_port *u) @@ -1060,8 +1098,6 @@ static void tegra_uart_shutdown(struct uart_port *u) tegra_uart_dma_channel_free(tup, true); tegra_uart_dma_channel_free(tup, false); free_irq(u->irq, tup); - - tegra_uart_flush_buffer(u); } static void tegra_uart_enable_ms(struct uart_port *u) @@ -1251,7 +1287,7 @@ static struct tegra_uart_chip_data tegra30_uart_chip_data = { .support_clk_src_div = true, }; -static struct of_device_id tegra_uart_of_match[] = { +static const struct of_device_id tegra_uart_of_match[] = { { .compatible = "nvidia,tegra30-hsuart", .data = &tegra30_uart_chip_data, diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 6a1055ae3437..7ae1592f7ec9 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -335,18 +335,29 @@ unsigned int uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, struct ktermios *old, unsigned int min, unsigned int max) { - unsigned int try, baud, altbaud = 38400; + unsigned int try; + unsigned int baud; + unsigned int altbaud; int hung_up = 0; upf_t flags = port->flags & UPF_SPD_MASK; - if (flags == UPF_SPD_HI) + switch (flags) { + case UPF_SPD_HI: altbaud = 57600; - else if (flags == UPF_SPD_VHI) + break; + case UPF_SPD_VHI: altbaud = 115200; - else if (flags == UPF_SPD_SHI) + break; + case UPF_SPD_SHI: altbaud = 230400; - else if (flags == UPF_SPD_WARP) + break; + case UPF_SPD_WARP: altbaud = 460800; + break; + default: + altbaud = 38400; + break; + } for (try = 0; try < 2; try++) { baud = tty_termios_baud_rate(termios); @@ -894,12 +905,10 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port, * need to rate-limit; it's CAP_SYS_ADMIN only. */ if (uport->flags & UPF_SPD_MASK) { - char buf[64]; - dev_notice(uport->dev, "%s sets custom speed on %s. This is deprecated.\n", current->comm, - tty_name(port->tty, buf)); + tty_name(port->tty)); } uart_change_speed(tty, state, NULL); } @@ -1118,8 +1127,7 @@ uart_wait_modem_status(struct uart_state *state, unsigned long arg) cprev = cnow; } - - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); remove_wait_queue(&port->delta_msr_wait, &wait); return ret; @@ -1766,12 +1774,12 @@ static const struct file_operations uart_proc_fops = { #endif #if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL) -/* +/** * uart_console_write - write a console message to a serial port * @port: the port to write the message * @s: array of characters * @count: number of characters in string to write - * @write: function to write character to port + * @putchar: function to write character to port */ void uart_console_write(struct uart_port *port, const char *s, unsigned int count, @@ -1810,6 +1818,55 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co) } /** + * uart_parse_earlycon - Parse earlycon options + * @p: ptr to 2nd field (ie., just beyond '<name>,') + * @iotype: ptr for decoded iotype (out) + * @addr: ptr for decoded mapbase/iobase (out) + * @options: ptr for <options> field; NULL if not present (out) + * + * Decodes earlycon kernel command line parameters of the form + * earlycon=<name>,io|mmio|mmio32|mmio32be,<addr>,<options> + * console=<name>,io|mmio|mmio32|mmio32be,<addr>,<options> + * + * The optional form + * earlycon=<name>,0x<addr>,<options> + * console=<name>,0x<addr>,<options> + * is also accepted; the returned @iotype will be UPIO_MEM. + * + * Returns 0 on success or -EINVAL on failure + */ +int uart_parse_earlycon(char *p, unsigned char *iotype, unsigned long *addr, + char **options) +{ + if (strncmp(p, "mmio,", 5) == 0) { + *iotype = UPIO_MEM; + p += 5; + } else if (strncmp(p, "mmio32,", 7) == 0) { + *iotype = UPIO_MEM32; + p += 7; + } else if (strncmp(p, "mmio32be,", 9) == 0) { + *iotype = UPIO_MEM32BE; + p += 9; + } else if (strncmp(p, "io,", 3) == 0) { + *iotype = UPIO_PORT; + p += 3; + } else if (strncmp(p, "0x", 2) == 0) { + *iotype = UPIO_MEM; + } else { + return -EINVAL; + } + + *addr = simple_strtoul(p, NULL, 0); + p = strchr(p, ','); + if (p) + p++; + + *options = p; + return 0; +} +EXPORT_SYMBOL_GPL(uart_parse_earlycon); + +/** * uart_parse_options - Parse serial port baud/parity/bits/flow control. * @options: pointer to option string * @baud: pointer to an 'int' variable for the baud rate. @@ -2637,6 +2694,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) state->pm_state = UART_PM_STATE_UNDEFINED; uport->cons = drv->cons; + uport->minor = drv->tty_driver->minor_start + uport->line; /* * If this port is a console, then the spinlock is already diff --git a/drivers/tty/serial/serial_ks8695.c b/drivers/tty/serial/serial_ks8695.c index 5c79bdab985d..b4decf8787de 100644 --- a/drivers/tty/serial/serial_ks8695.c +++ b/drivers/tty/serial/serial_ks8695.c @@ -328,7 +328,7 @@ static int ks8695uart_startup(struct uart_port *port) { int retval; - set_irq_flags(KS8695_IRQ_UART_TX, IRQF_VALID | IRQF_NOAUTOEN); + irq_modify_status(KS8695_IRQ_UART_TX, IRQ_NOREQUEST, IRQ_NOAUTOEN); tx_enable(port, 0); rx_enable(port, 1); ms_enable(port, 1); diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c index a38596c5194e..402f7fb54133 100644 --- a/drivers/tty/serial/serial_mctrl_gpio.c +++ b/drivers/tty/serial/serial_mctrl_gpio.c @@ -48,27 +48,20 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl) int value_array[UART_GPIO_MAX]; unsigned int count = 0; - if (IS_ERR_OR_NULL(gpios)) - return; - for (i = 0; i < UART_GPIO_MAX; i++) - if (!IS_ERR_OR_NULL(gpios->gpio[i]) && - mctrl_gpios_desc[i].dir_out) { + if (gpios->gpio[i] && mctrl_gpios_desc[i].dir_out) { desc_array[count] = gpios->gpio[i]; value_array[count] = !!(mctrl & mctrl_gpios_desc[i].mctrl); count++; } - gpiod_set_array(count, desc_array, value_array); + gpiod_set_array_value(count, desc_array, value_array); } EXPORT_SYMBOL_GPL(mctrl_gpio_set); struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios, enum mctrl_gpio_idx gidx) { - if (!IS_ERR_OR_NULL(gpios) && !IS_ERR_OR_NULL(gpios->gpio[gidx])) - return gpios->gpio[gidx]; - else - return NULL; + return gpios->gpio[gidx]; } EXPORT_SYMBOL_GPL(mctrl_gpio_to_gpiod); @@ -76,15 +69,8 @@ unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl) { enum mctrl_gpio_idx i; - /* - * return it unchanged if the structure is not allocated - */ - if (IS_ERR_OR_NULL(gpios)) - return *mctrl; - for (i = 0; i < UART_GPIO_MAX; i++) { - if (!IS_ERR_OR_NULL(gpios->gpio[i]) && - !mctrl_gpios_desc[i].dir_out) { + if (gpios->gpio[i] && !mctrl_gpios_desc[i].dir_out) { if (gpiod_get_value(gpios->gpio[i])) *mctrl |= mctrl_gpios_desc[i].mctrl; else @@ -100,34 +86,26 @@ struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx) { struct mctrl_gpios *gpios; enum mctrl_gpio_idx i; - int err; gpios = devm_kzalloc(dev, sizeof(*gpios), GFP_KERNEL); if (!gpios) return ERR_PTR(-ENOMEM); for (i = 0; i < UART_GPIO_MAX; i++) { - gpios->gpio[i] = devm_gpiod_get_index(dev, - mctrl_gpios_desc[i].name, - idx); - - /* - * The GPIOs are maybe not all filled, - * this is not an error. - */ - if (IS_ERR_OR_NULL(gpios->gpio[i])) - continue; + enum gpiod_flags flags; if (mctrl_gpios_desc[i].dir_out) - err = gpiod_direction_output(gpios->gpio[i], 0); + flags = GPIOD_OUT_LOW; else - err = gpiod_direction_input(gpios->gpio[i]); - if (err) { - dev_dbg(dev, "Unable to set direction for %s GPIO", - mctrl_gpios_desc[i].name); - devm_gpiod_put(dev, gpios->gpio[i]); - gpios->gpio[i] = NULL; - } + flags = GPIOD_IN; + + gpios->gpio[i] = + devm_gpiod_get_index_optional(dev, + mctrl_gpios_desc[i].name, + idx, flags); + + if (IS_ERR(gpios->gpio[i])) + return ERR_CAST(gpios->gpio[i]); } return gpios; @@ -138,11 +116,8 @@ void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios) { enum mctrl_gpio_idx i; - if (IS_ERR_OR_NULL(gpios)) - return; - for (i = 0; i < UART_GPIO_MAX; i++) - if (!IS_ERR_OR_NULL(gpios->gpio[i])) + if (gpios->gpio[i]) devm_gpiod_put(dev, gpios->gpio[i]); devm_kfree(dev, gpios); } diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 5b50c792ad5f..1b2f894bdc9e 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -81,10 +81,11 @@ struct sci_port { /* Platform configuration */ struct plat_sci_port *cfg; - int overrun_bit; + unsigned int overrun_reg; + unsigned int overrun_mask; unsigned int error_mask; unsigned int sampling_rate; - + resource_size_t reg_size; /* Break timer */ struct timer_list break_timer; @@ -168,6 +169,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, /* @@ -188,6 +191,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, /* @@ -207,6 +212,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid, + [SCPCR] = { 0x30, 16 }, + [SCPDR] = { 0x34, 16 }, }, /* @@ -226,6 +233,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid, + [SCPCR] = { 0x30, 16 }, + [SCPDR] = { 0x34, 16 }, }, /* @@ -246,6 +255,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCSPTR] = { 0x20, 16 }, [SCLSR] = { 0x24, 16 }, [HSSRR] = sci_reg_invalid, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, /* @@ -265,6 +276,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, /* @@ -284,6 +297,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCSPTR] = { 0x20, 16 }, [SCLSR] = { 0x24, 16 }, [HSSRR] = sci_reg_invalid, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, /* @@ -303,6 +318,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCSPTR] = { 0x20, 16 }, [SCLSR] = { 0x24, 16 }, [HSSRR] = { 0x40, 16 }, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, /* @@ -323,6 +340,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCSPTR] = sci_reg_invalid, [SCLSR] = { 0x24, 16 }, [HSSRR] = sci_reg_invalid, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, /* @@ -343,6 +362,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCSPTR] = { 0x24, 16 }, [SCLSR] = { 0x28, 16 }, [HSSRR] = sci_reg_invalid, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, /* @@ -363,6 +384,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, }; @@ -781,7 +804,7 @@ static int sci_handle_errors(struct uart_port *port) struct sci_port *s = to_sci_port(port); /* Handle overruns */ - if (status & (1 << s->overrun_bit)) { + if (status & s->overrun_mask) { port->icount.overrun++; /* overrun error */ @@ -845,13 +868,16 @@ static int sci_handle_fifo_overrun(struct uart_port *port) struct sci_port *s = to_sci_port(port); struct plat_sci_reg *reg; int copied = 0; + u16 status; - reg = sci_getreg(port, SCLSR); + reg = sci_getreg(port, s->overrun_reg); if (!reg->size) return 0; - if ((serial_port_in(port, SCLSR) & (1 << s->overrun_bit))) { - serial_port_out(port, SCLSR, 0); + status = serial_port_in(port, s->overrun_reg); + if (status & s->overrun_mask) { + status &= ~s->overrun_mask; + serial_port_out(port, s->overrun_reg, status); port->icount.overrun++; @@ -996,16 +1022,20 @@ static inline unsigned long port_rx_irq_mask(struct uart_port *port) static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) { - unsigned short ssr_status, scr_status, err_enabled; - unsigned short slr_status = 0; + unsigned short ssr_status, scr_status, err_enabled, orer_status = 0; struct uart_port *port = ptr; struct sci_port *s = to_sci_port(port); irqreturn_t ret = IRQ_NONE; ssr_status = serial_port_in(port, SCxSR); scr_status = serial_port_in(port, SCSCR); - if (port->type == PORT_SCIF || port->type == PORT_HSCIF) - slr_status = serial_port_in(port, SCLSR); + if (s->overrun_reg == SCxSR) + orer_status = ssr_status; + else { + if (sci_getreg(port, s->overrun_reg)->size) + orer_status = serial_port_in(port, s->overrun_reg); + } + err_enabled = scr_status & port_rx_irq_mask(port); /* Tx Interrupt */ @@ -1033,10 +1063,8 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) ret = sci_br_interrupt(irq, ptr); /* Overrun Interrupt */ - if (port->type == PORT_SCIF || port->type == PORT_HSCIF) { - if (slr_status & 0x01) - sci_handle_fifo_overrun(port); - } + if (orer_status & s->overrun_mask) + sci_handle_fifo_overrun(port); return ret; } @@ -1967,18 +1995,40 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, #ifdef CONFIG_SERIAL_SH_SCI_DMA /* - * Calculate delay for 1.5 DMA buffers: see - * drivers/serial/serial_core.c::uart_update_timeout(). With 10 bits - * (CS8), 250Hz, 115200 baud and 64 bytes FIFO, the above function + * Calculate delay for 2 DMA buffers (4 FIFO). + * See drivers/serial/serial_core.c::uart_update_timeout(). With 10 + * bits (CS8), 250Hz, 115200 baud and 64 bytes FIFO, the above function * calculates 1 jiffie for the data plus 5 jiffies for the "slop(e)." - * Then below we calculate 3 jiffies (12ms) for 1.5 DMA buffers (3 FIFO - * sizes), but it has been found out experimentally, that this is not - * enough: the driver too often needlessly runs on a DMA timeout. 20ms - * as a minimum seem to work perfectly. + * Then below we calculate 5 jiffies (20ms) for 2 DMA buffers (4 FIFO + * sizes), but when performing a faster transfer, value obtained by + * this formula is may not enough. Therefore, if value is smaller than + * 20msec, this sets 20msec as timeout of DMA. */ if (s->chan_rx) { - s->rx_timeout = (port->timeout - HZ / 50) * s->buf_len_rx * 3 / - port->fifosize / 2; + unsigned int bits; + + /* byte size and parity */ + switch (termios->c_cflag & CSIZE) { + case CS5: + bits = 7; + break; + case CS6: + bits = 8; + break; + case CS7: + bits = 9; + break; + default: + bits = 10; + break; + } + + if (termios->c_cflag & CSTOPB) + bits++; + if (termios->c_cflag & PARENB) + bits++; + s->rx_timeout = DIV_ROUND_UP((s->buf_len_rx * 2 * bits * HZ) / + (baud / 10), 10); dev_dbg(port->dev, "DMA Rx t-out %ums, tty t-out %u jiffies\n", s->rx_timeout * 1000 / HZ, port->timeout); if (s->rx_timeout < msecs_to_jiffies(20)) @@ -2027,23 +2077,9 @@ static const char *sci_type(struct uart_port *port) return NULL; } -static inline unsigned long sci_port_size(struct uart_port *port) -{ - /* - * Pick an arbitrary size that encapsulates all of the base - * registers by default. This can be optimized later, or derived - * from platform resource data at such a time that ports begin to - * behave more erratically. - */ - if (port->type == PORT_HSCIF) - return 96; - else - return 64; -} - static int sci_remap_port(struct uart_port *port) { - unsigned long size = sci_port_size(port); + struct sci_port *sport = to_sci_port(port); /* * Nothing to do if there's already an established membase. @@ -2052,7 +2088,7 @@ static int sci_remap_port(struct uart_port *port) return 0; if (port->flags & UPF_IOREMAP) { - port->membase = ioremap_nocache(port->mapbase, size); + port->membase = ioremap_nocache(port->mapbase, sport->reg_size); if (unlikely(!port->membase)) { dev_err(port->dev, "can't remap port#%d\n", port->line); return -ENXIO; @@ -2071,23 +2107,28 @@ static int sci_remap_port(struct uart_port *port) static void sci_release_port(struct uart_port *port) { + struct sci_port *sport = to_sci_port(port); + if (port->flags & UPF_IOREMAP) { iounmap(port->membase); port->membase = NULL; } - release_mem_region(port->mapbase, sci_port_size(port)); + release_mem_region(port->mapbase, sport->reg_size); } static int sci_request_port(struct uart_port *port) { - unsigned long size = sci_port_size(port); struct resource *res; + struct sci_port *sport = to_sci_port(port); int ret; - res = request_mem_region(port->mapbase, size, dev_name(port->dev)); - if (unlikely(res == NULL)) + res = request_mem_region(port->mapbase, sport->reg_size, + dev_name(port->dev)); + if (unlikely(res == NULL)) { + dev_err(port->dev, "request_mem_region failed."); return -EBUSY; + } ret = sci_remap_port(port); if (unlikely(ret != 0)) { @@ -2161,6 +2202,7 @@ static int sci_init_single(struct platform_device *dev, return -ENOMEM; port->mapbase = res->start; + sci_port->reg_size = resource_size(res); for (i = 0; i < ARRAY_SIZE(sci_port->irqs); ++i) sci_port->irqs[i] = platform_get_irq(dev, i); @@ -2188,32 +2230,38 @@ static int sci_init_single(struct platform_device *dev, switch (p->type) { case PORT_SCIFB: port->fifosize = 256; - sci_port->overrun_bit = 9; + sci_port->overrun_reg = SCxSR; + sci_port->overrun_mask = SCIFA_ORER; sampling_rate = 16; break; case PORT_HSCIF: port->fifosize = 128; sampling_rate = 0; - sci_port->overrun_bit = 0; + sci_port->overrun_reg = SCLSR; + sci_port->overrun_mask = SCLSR_ORER; break; case PORT_SCIFA: port->fifosize = 64; - sci_port->overrun_bit = 9; + sci_port->overrun_reg = SCxSR; + sci_port->overrun_mask = SCIFA_ORER; sampling_rate = 16; break; case PORT_SCIF: port->fifosize = 16; if (p->regtype == SCIx_SH7705_SCIF_REGTYPE) { - sci_port->overrun_bit = 9; + sci_port->overrun_reg = SCxSR; + sci_port->overrun_mask = SCIFA_ORER; sampling_rate = 16; } else { - sci_port->overrun_bit = 0; + sci_port->overrun_reg = SCLSR; + sci_port->overrun_mask = SCLSR_ORER; sampling_rate = 32; } break; default: port->fifosize = 1; - sci_port->overrun_bit = 5; + sci_port->overrun_reg = SCxSR; + sci_port->overrun_mask = SCI_ORER; sampling_rate = 32; break; } @@ -2259,15 +2307,11 @@ static int sci_init_single(struct platform_device *dev, SCI_DEFAULT_ERROR_MASK : SCIF_DEFAULT_ERROR_MASK; /* - * Establish sensible defaults for the overrun detection, unless - * the part has explicitly disabled support for it. - */ - - /* * Make the error mask inclusive of overrun detection, if * supported. */ - sci_port->error_mask |= 1 << sci_port->overrun_bit; + if (sci_port->overrun_reg == SCxSR) + sci_port->error_mask |= sci_port->overrun_mask; port->type = p->type; port->flags = UPF_FIXED_PORT | p->flags; @@ -2490,6 +2534,12 @@ static const struct of_device_id of_sci_match[] = { .regtype = SCIx_HSCIF_REGTYPE, }, }, { + .compatible = "renesas,sci", + .data = &(const struct sci_port_info) { + .type = PORT_SCI, + .regtype = SCIx_SCI_REGTYPE, + }, + }, { /* Terminator */ }, }; diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h index d5db81a0a430..3393f67b4e84 100644 --- a/drivers/tty/serial/sh-sci.h +++ b/drivers/tty/serial/sh-sci.h @@ -1,7 +1,115 @@ +#include <linux/bitops.h> #include <linux/serial_core.h> #include <linux/io.h> #include <linux/gpio.h> +#define SCI_MAJOR 204 +#define SCI_MINOR_START 8 + + +/* + * SCI register subset common for all port types. + * Not all registers will exist on all parts. + */ +enum { + SCSMR, /* Serial Mode Register */ + SCBRR, /* Bit Rate Register */ + SCSCR, /* Serial Control Register */ + SCxSR, /* Serial Status Register */ + SCFCR, /* FIFO Control Register */ + SCFDR, /* FIFO Data Count Register */ + SCxTDR, /* Transmit (FIFO) Data Register */ + SCxRDR, /* Receive (FIFO) Data Register */ + SCLSR, /* Line Status Register */ + SCTFDR, /* Transmit FIFO Data Count Register */ + SCRFDR, /* Receive FIFO Data Count Register */ + SCSPTR, /* Serial Port Register */ + HSSRR, /* Sampling Rate Register */ + SCPCR, /* Serial Port Control Register */ + SCPDR, /* Serial Port Data Register */ + + SCIx_NR_REGS, +}; + + +/* SCSMR (Serial Mode Register) */ +#define SCSMR_CHR BIT(6) /* 7-bit Character Length */ +#define SCSMR_PE BIT(5) /* Parity Enable */ +#define SCSMR_ODD BIT(4) /* Odd Parity */ +#define SCSMR_STOP BIT(3) /* Stop Bit Length */ +#define SCSMR_CKS 0x0003 /* Clock Select */ + +/* Serial Control Register, SCIFA/SCIFB only bits */ +#define SCSCR_TDRQE BIT(15) /* Tx Data Transfer Request Enable */ +#define SCSCR_RDRQE BIT(14) /* Rx Data Transfer Request Enable */ + +/* SCxSR (Serial Status Register) on SCI */ +#define SCI_TDRE BIT(7) /* Transmit Data Register Empty */ +#define SCI_RDRF BIT(6) /* Receive Data Register Full */ +#define SCI_ORER BIT(5) /* Overrun Error */ +#define SCI_FER BIT(4) /* Framing Error */ +#define SCI_PER BIT(3) /* Parity Error */ +#define SCI_TEND BIT(2) /* Transmit End */ +#define SCI_RESERVED 0x03 /* All reserved bits */ + +#define SCI_DEFAULT_ERROR_MASK (SCI_PER | SCI_FER) + +#define SCI_RDxF_CLEAR ~(SCI_RESERVED | SCI_RDRF) +#define SCI_ERROR_CLEAR ~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER) +#define SCI_TDxE_CLEAR ~(SCI_RESERVED | SCI_TEND | SCI_TDRE) +#define SCI_BREAK_CLEAR ~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER) + +/* SCxSR (Serial Status Register) on SCIF, SCIFA, SCIFB, HSCIF */ +#define SCIF_ER BIT(7) /* Receive Error */ +#define SCIF_TEND BIT(6) /* Transmission End */ +#define SCIF_TDFE BIT(5) /* Transmit FIFO Data Empty */ +#define SCIF_BRK BIT(4) /* Break Detect */ +#define SCIF_FER BIT(3) /* Framing Error */ +#define SCIF_PER BIT(2) /* Parity Error */ +#define SCIF_RDF BIT(1) /* Receive FIFO Data Full */ +#define SCIF_DR BIT(0) /* Receive Data Ready */ +/* SCIF only (optional) */ +#define SCIF_PERC 0xf000 /* Number of Parity Errors */ +#define SCIF_FERC 0x0f00 /* Number of Framing Errors */ +/*SCIFA/SCIFB and SCIF on SH7705/SH7720/SH7721 only */ +#define SCIFA_ORER BIT(9) /* Overrun Error */ + +#define SCIF_DEFAULT_ERROR_MASK (SCIF_PER | SCIF_FER | SCIF_BRK | SCIF_ER) + +#define SCIF_RDxF_CLEAR ~(SCIF_DR | SCIF_RDF) +#define SCIF_ERROR_CLEAR ~(SCIFA_ORER | SCIF_PER | SCIF_FER | SCIF_ER) +#define SCIF_TDxE_CLEAR ~(SCIF_TDFE) +#define SCIF_BREAK_CLEAR ~(SCIF_PER | SCIF_FER | SCIF_BRK) + +/* SCFCR (FIFO Control Register) */ +#define SCFCR_MCE BIT(3) /* Modem Control Enable */ +#define SCFCR_TFRST BIT(2) /* Transmit FIFO Data Register Reset */ +#define SCFCR_RFRST BIT(1) /* Receive FIFO Data Register Reset */ +#define SCFCR_LOOP BIT(0) /* Loopback Test */ + +/* SCLSR (Line Status Register) on (H)SCIF */ +#define SCLSR_ORER BIT(0) /* Overrun Error */ + +/* SCSPTR (Serial Port Register), optional */ +#define SCSPTR_RTSIO BIT(7) /* Serial Port RTS Pin Input/Output */ +#define SCSPTR_RTSDT BIT(6) /* Serial Port RTS Pin Data */ +#define SCSPTR_CTSIO BIT(5) /* Serial Port CTS Pin Input/Output */ +#define SCSPTR_CTSDT BIT(4) /* Serial Port CTS Pin Data */ +#define SCSPTR_SPB2IO BIT(1) /* Serial Port Break Input/Output */ +#define SCSPTR_SPB2DT BIT(0) /* Serial Port Break Data */ + +/* HSSRR HSCIF */ +#define HSCIF_SRE BIT(15) /* Sampling Rate Register Enable */ + +/* SCPCR (Serial Port Control Register), SCIFA/SCIFB only */ +#define SCPCR_RTSC BIT(4) /* Serial Port RTS Pin / Output Pin */ +#define SCPCR_CTSC BIT(3) /* Serial Port CTS Pin / Input Pin */ + +/* SCPDR (Serial Port Data Register), SCIFA/SCIFB only */ +#define SCPDR_RTSD BIT(4) /* Serial Port RTS Output Pin Data */ +#define SCPDR_CTSD BIT(3) /* Serial Port CTS Input Pin Data */ + + #define SCxSR_TEND(port) (((port)->type == PORT_SCI) ? SCI_TEND : SCIF_TEND) #define SCxSR_RDxF(port) (((port)->type == PORT_SCI) ? SCI_RDRF : SCIF_RDF) #define SCxSR_TDxE(port) (((port)->type == PORT_SCI) ? SCI_TDRE : SCIF_TDFE) @@ -15,24 +123,24 @@ defined(CONFIG_CPU_SUBTYPE_SH7720) || \ defined(CONFIG_CPU_SUBTYPE_SH7721) || \ defined(CONFIG_ARCH_SH73A0) || \ - defined(CONFIG_ARCH_SH7372) || \ defined(CONFIG_ARCH_R8A7740) -# define SCxSR_RDxF_CLEAR(port) (serial_port_in(port, SCxSR) & 0xfffc) -# define SCxSR_ERROR_CLEAR(port) (serial_port_in(port, SCxSR) & 0xfd73) -# define SCxSR_TDxE_CLEAR(port) (serial_port_in(port, SCxSR) & 0xffdf) -# define SCxSR_BREAK_CLEAR(port) (serial_port_in(port, SCxSR) & 0xffe3) +# define SCxSR_RDxF_CLEAR(port) \ + (serial_port_in(port, SCxSR) & SCIF_RDxF_CLEAR) +# define SCxSR_ERROR_CLEAR(port) \ + (serial_port_in(port, SCxSR) & SCIF_ERROR_CLEAR) +# define SCxSR_TDxE_CLEAR(port) \ + (serial_port_in(port, SCxSR) & SCIF_TDxE_CLEAR) +# define SCxSR_BREAK_CLEAR(port) \ + (serial_port_in(port, SCxSR) & SCIF_BREAK_CLEAR) #else -# define SCxSR_RDxF_CLEAR(port) (((port)->type == PORT_SCI) ? 0xbc : 0x00fc) -# define SCxSR_ERROR_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x0073) -# define SCxSR_TDxE_CLEAR(port) (((port)->type == PORT_SCI) ? 0x78 : 0x00df) -# define SCxSR_BREAK_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x00e3) +# define SCxSR_RDxF_CLEAR(port) \ + ((((port)->type == PORT_SCI) ? SCI_RDxF_CLEAR : SCIF_RDxF_CLEAR) & 0xff) +# define SCxSR_ERROR_CLEAR(port) \ + ((((port)->type == PORT_SCI) ? SCI_ERROR_CLEAR : SCIF_ERROR_CLEAR) & 0xff) +# define SCxSR_TDxE_CLEAR(port) \ + ((((port)->type == PORT_SCI) ? SCI_TDxE_CLEAR : SCIF_TDxE_CLEAR) & 0xff) +# define SCxSR_BREAK_CLEAR(port) \ + ((((port)->type == PORT_SCI) ? SCI_BREAK_CLEAR : SCIF_BREAK_CLEAR) & 0xff) #endif -/* SCFCR */ -#define SCFCR_RFRST 0x0002 -#define SCFCR_TFRST 0x0004 -#define SCFCR_MCE 0x0008 - -#define SCI_MAJOR 204 -#define SCI_MINOR_START 8 diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c index 27ed0e960880..653cdd5fb508 100644 --- a/drivers/tty/serial/sirfsoc_uart.c +++ b/drivers/tty/serial/sirfsoc_uart.c @@ -36,8 +36,6 @@ sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count); static struct uart_driver sirfsoc_uart_drv; static void sirfsoc_uart_tx_dma_complete_callback(void *param); -static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port); -static void sirfsoc_uart_rx_dma_complete_callback(void *param); static const struct sirfsoc_baudrate_to_regv baudrate_to_regv[] = { {4000000, 2359296}, {3500000, 1310721}, @@ -59,50 +57,7 @@ static const struct sirfsoc_baudrate_to_regv baudrate_to_regv[] = { {9600, 1114979}, }; -static struct sirfsoc_uart_port sirfsoc_uart_ports[SIRFSOC_UART_NR] = { - [0] = { - .port = { - .iotype = UPIO_MEM, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - }, - [1] = { - .port = { - .iotype = UPIO_MEM, - .flags = UPF_BOOT_AUTOCONF, - .line = 1, - }, - }, - [2] = { - .port = { - .iotype = UPIO_MEM, - .flags = UPF_BOOT_AUTOCONF, - .line = 2, - }, - }, - [3] = { - .port = { - .iotype = UPIO_MEM, - .flags = UPF_BOOT_AUTOCONF, - .line = 3, - }, - }, - [4] = { - .port = { - .iotype = UPIO_MEM, - .flags = UPF_BOOT_AUTOCONF, - .line = 4, - }, - }, - [5] = { - .port = { - .iotype = UPIO_MEM, - .flags = UPF_BOOT_AUTOCONF, - .line = 5, - }, - }, -}; +static struct sirfsoc_uart_port *sirf_ports[SIRFSOC_UART_NR]; static inline struct sirfsoc_uart_port *to_sirfport(struct uart_port *port) { @@ -116,8 +71,7 @@ static inline unsigned int sirfsoc_uart_tx_empty(struct uart_port *port) struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status; reg = rd_regl(port, ureg->sirfsoc_tx_fifo_status); - - return (reg & ufifo_st->ff_empty(port->line)) ? TIOCSER_TEMT : 0; + return (reg & ufifo_st->ff_empty(port)) ? TIOCSER_TEMT : 0; } static unsigned int sirfsoc_uart_get_mctrl(struct uart_port *port) @@ -152,6 +106,26 @@ static void sirfsoc_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) unsigned int val = assert ? SIRFUART_AFC_CTRL_RX_THD : 0x0; unsigned int current_val; + if (mctrl & TIOCM_LOOP) { + if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) + wr_regl(port, ureg->sirfsoc_line_ctrl, + rd_regl(port, ureg->sirfsoc_line_ctrl) | + SIRFUART_LOOP_BACK); + else + wr_regl(port, ureg->sirfsoc_mode1, + rd_regl(port, ureg->sirfsoc_mode1) | + SIRFSOC_USP_LOOP_BACK_CTRL); + } else { + if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) + wr_regl(port, ureg->sirfsoc_line_ctrl, + rd_regl(port, ureg->sirfsoc_line_ctrl) & + ~SIRFUART_LOOP_BACK); + else + wr_regl(port, ureg->sirfsoc_mode1, + rd_regl(port, ureg->sirfsoc_mode1) & + ~SIRFSOC_USP_LOOP_BACK_CTRL); + } + if (!sirfport->hw_flow_ctrl || !sirfport->ms_enabled) return; if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) { @@ -182,16 +156,19 @@ static void sirfsoc_uart_stop_tx(struct uart_port *port) rd_regl(port, ureg->sirfsoc_int_en_reg) & ~uint_en->sirfsoc_txfifo_empty_en); else - wr_regl(port, SIRFUART_INT_EN_CLR, + wr_regl(port, ureg->sirfsoc_int_en_clr_reg, uint_en->sirfsoc_txfifo_empty_en); } } else { + if (sirfport->uart_reg->uart_type == SIRF_USP_UART) + wr_regl(port, ureg->sirfsoc_tx_rx_en, rd_regl(port, + ureg->sirfsoc_tx_rx_en) & ~SIRFUART_TX_EN); if (!sirfport->is_atlas7) wr_regl(port, ureg->sirfsoc_int_en_reg, rd_regl(port, ureg->sirfsoc_int_en_reg) & ~uint_en->sirfsoc_txfifo_empty_en); else - wr_regl(port, SIRFUART_INT_EN_CLR, + wr_regl(port, ureg->sirfsoc_int_en_clr_reg, uint_en->sirfsoc_txfifo_empty_en); } } @@ -222,7 +199,7 @@ static void sirfsoc_uart_tx_with_dma(struct sirfsoc_uart_port *sirfport) rd_regl(port, ureg->sirfsoc_int_en_reg)& ~(uint_en->sirfsoc_txfifo_empty_en)); else - wr_regl(port, SIRFUART_INT_EN_CLR, + wr_regl(port, ureg->sirfsoc_int_en_clr_reg, uint_en->sirfsoc_txfifo_empty_en); /* * DMA requires buffer address and buffer length are both aligned with @@ -290,8 +267,11 @@ static void sirfsoc_uart_start_tx(struct uart_port *port) if (sirfport->tx_dma_chan) sirfsoc_uart_tx_with_dma(sirfport); else { - sirfsoc_uart_pio_tx_chars(sirfport, - SIRFSOC_UART_IO_TX_REASONABLE_CNT); + if (sirfport->uart_reg->uart_type == SIRF_USP_UART) + wr_regl(port, ureg->sirfsoc_tx_rx_en, rd_regl(port, + ureg->sirfsoc_tx_rx_en) | SIRFUART_TX_EN); + wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_STOP); + sirfsoc_uart_pio_tx_chars(sirfport, port->fifosize); wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_START); if (!sirfport->is_atlas7) wr_regl(port, ureg->sirfsoc_int_en_reg, @@ -314,21 +294,25 @@ static void sirfsoc_uart_stop_rx(struct uart_port *port) if (!sirfport->is_atlas7) wr_regl(port, ureg->sirfsoc_int_en_reg, rd_regl(port, ureg->sirfsoc_int_en_reg) & - ~(SIRFUART_RX_DMA_INT_EN(port, uint_en) | + ~(SIRFUART_RX_DMA_INT_EN(uint_en, + sirfport->uart_reg->uart_type) | uint_en->sirfsoc_rx_done_en)); else - wr_regl(port, SIRFUART_INT_EN_CLR, - SIRFUART_RX_DMA_INT_EN(port, uint_en)| - uint_en->sirfsoc_rx_done_en); + wr_regl(port, ureg->sirfsoc_int_en_clr_reg, + SIRFUART_RX_DMA_INT_EN(uint_en, + sirfport->uart_reg->uart_type)| + uint_en->sirfsoc_rx_done_en); dmaengine_terminate_all(sirfport->rx_dma_chan); } else { if (!sirfport->is_atlas7) wr_regl(port, ureg->sirfsoc_int_en_reg, rd_regl(port, ureg->sirfsoc_int_en_reg)& - ~(SIRFUART_RX_IO_INT_EN(port, uint_en))); + ~(SIRFUART_RX_IO_INT_EN(uint_en, + sirfport->uart_reg->uart_type))); else - wr_regl(port, SIRFUART_INT_EN_CLR, - SIRFUART_RX_IO_INT_EN(port, uint_en)); + wr_regl(port, ureg->sirfsoc_int_en_clr_reg, + SIRFUART_RX_IO_INT_EN(uint_en, + sirfport->uart_reg->uart_type)); } } @@ -349,7 +333,7 @@ static void sirfsoc_uart_disable_ms(struct uart_port *port) rd_regl(port, ureg->sirfsoc_int_en_reg)& ~uint_en->sirfsoc_cts_en); else - wr_regl(port, SIRFUART_INT_EN_CLR, + wr_regl(port, ureg->sirfsoc_int_en_clr_reg, uint_en->sirfsoc_cts_en); } else disable_irq(gpio_to_irq(sirfport->cts_gpio)); @@ -379,7 +363,8 @@ static void sirfsoc_uart_enable_ms(struct uart_port *port) if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) { wr_regl(port, ureg->sirfsoc_afc_ctrl, rd_regl(port, ureg->sirfsoc_afc_ctrl) | - SIRFUART_AFC_TX_EN | SIRFUART_AFC_RX_EN); + SIRFUART_AFC_TX_EN | SIRFUART_AFC_RX_EN | + SIRFUART_AFC_CTRL_RX_THD); if (!sirfport->is_atlas7) wr_regl(port, ureg->sirfsoc_int_en_reg, rd_regl(port, ureg->sirfsoc_int_en_reg) @@ -417,7 +402,7 @@ sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count) if (!tty) return -ENODEV; while (!(rd_regl(port, ureg->sirfsoc_rx_fifo_status) & - ufifo_st->ff_empty(port->line))) { + ufifo_st->ff_empty(port))) { ch = rd_regl(port, ureg->sirfsoc_rx_fifo_data) | SIRFUART_DUMMY_READ; if (unlikely(uart_handle_sysrq_char(port, ch))) @@ -444,7 +429,7 @@ sirfsoc_uart_pio_tx_chars(struct sirfsoc_uart_port *sirfport, int count) unsigned int num_tx = 0; while (!uart_circ_empty(xmit) && !(rd_regl(port, ureg->sirfsoc_tx_fifo_status) & - ufifo_st->ff_full(port->line)) && + ufifo_st->ff_full(port)) && count--) { wr_regl(port, ureg->sirfsoc_tx_fifo_data, xmit->buf[xmit->tail]); @@ -478,139 +463,6 @@ static void sirfsoc_uart_tx_dma_complete_callback(void *param) spin_unlock_irqrestore(&port->lock, flags); } -static void sirfsoc_uart_insert_rx_buf_to_tty( - struct sirfsoc_uart_port *sirfport, int count) -{ - struct uart_port *port = &sirfport->port; - struct tty_port *tport = &port->state->port; - int inserted; - - inserted = tty_insert_flip_string(tport, - sirfport->rx_dma_items[sirfport->rx_completed].xmit.buf, count); - port->icount.rx += inserted; -} - -static void sirfsoc_rx_submit_one_dma_desc(struct uart_port *port, int index) -{ - struct sirfsoc_uart_port *sirfport = to_sirfport(port); - - sirfport->rx_dma_items[index].xmit.tail = - sirfport->rx_dma_items[index].xmit.head = 0; - sirfport->rx_dma_items[index].desc = - dmaengine_prep_slave_single(sirfport->rx_dma_chan, - sirfport->rx_dma_items[index].dma_addr, SIRFSOC_RX_DMA_BUF_SIZE, - DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); - if (!sirfport->rx_dma_items[index].desc) { - dev_err(port->dev, "DMA slave single fail\n"); - return; - } - sirfport->rx_dma_items[index].desc->callback = - sirfsoc_uart_rx_dma_complete_callback; - sirfport->rx_dma_items[index].desc->callback_param = sirfport; - sirfport->rx_dma_items[index].cookie = - dmaengine_submit(sirfport->rx_dma_items[index].desc); - dma_async_issue_pending(sirfport->rx_dma_chan); -} - -static void sirfsoc_rx_tmo_process_tl(unsigned long param) -{ - struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param; - struct uart_port *port = &sirfport->port; - struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; - struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; - struct sirfsoc_int_status *uint_st = &sirfport->uart_reg->uart_int_st; - unsigned int count; - unsigned long flags; - struct dma_tx_state tx_state; - - spin_lock_irqsave(&port->lock, flags); - while (DMA_COMPLETE == dmaengine_tx_status(sirfport->rx_dma_chan, - sirfport->rx_dma_items[sirfport->rx_completed].cookie, &tx_state)) { - sirfsoc_uart_insert_rx_buf_to_tty(sirfport, - SIRFSOC_RX_DMA_BUF_SIZE); - sirfport->rx_completed++; - sirfport->rx_completed %= SIRFSOC_RX_LOOP_BUF_CNT; - } - count = CIRC_CNT(sirfport->rx_dma_items[sirfport->rx_issued].xmit.head, - sirfport->rx_dma_items[sirfport->rx_issued].xmit.tail, - SIRFSOC_RX_DMA_BUF_SIZE); - if (count > 0) - sirfsoc_uart_insert_rx_buf_to_tty(sirfport, count); - wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, - rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) | - SIRFUART_IO_MODE); - sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count); - if (sirfport->rx_io_count == 4) { - sirfport->rx_io_count = 0; - wr_regl(port, ureg->sirfsoc_int_st_reg, - uint_st->sirfsoc_rx_done); - if (!sirfport->is_atlas7) - wr_regl(port, ureg->sirfsoc_int_en_reg, - rd_regl(port, ureg->sirfsoc_int_en_reg) & - ~(uint_en->sirfsoc_rx_done_en)); - else - wr_regl(port, SIRFUART_INT_EN_CLR, - uint_en->sirfsoc_rx_done_en); - sirfsoc_uart_start_next_rx_dma(port); - } else { - wr_regl(port, ureg->sirfsoc_int_st_reg, - uint_st->sirfsoc_rx_done); - if (!sirfport->is_atlas7) - wr_regl(port, ureg->sirfsoc_int_en_reg, - rd_regl(port, ureg->sirfsoc_int_en_reg) | - (uint_en->sirfsoc_rx_done_en)); - else - wr_regl(port, ureg->sirfsoc_int_en_reg, - uint_en->sirfsoc_rx_done_en); - } - spin_unlock_irqrestore(&port->lock, flags); - tty_flip_buffer_push(&port->state->port); -} - -static void sirfsoc_uart_handle_rx_tmo(struct sirfsoc_uart_port *sirfport) -{ - struct uart_port *port = &sirfport->port; - struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; - struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; - struct dma_tx_state tx_state; - dmaengine_tx_status(sirfport->rx_dma_chan, - sirfport->rx_dma_items[sirfport->rx_issued].cookie, &tx_state); - dmaengine_terminate_all(sirfport->rx_dma_chan); - sirfport->rx_dma_items[sirfport->rx_issued].xmit.head = - SIRFSOC_RX_DMA_BUF_SIZE - tx_state.residue; - if (!sirfport->is_atlas7) - wr_regl(port, ureg->sirfsoc_int_en_reg, - rd_regl(port, ureg->sirfsoc_int_en_reg) & - ~(uint_en->sirfsoc_rx_timeout_en)); - else - wr_regl(port, SIRFUART_INT_EN_CLR, - uint_en->sirfsoc_rx_timeout_en); - tasklet_schedule(&sirfport->rx_tmo_process_tasklet); -} - -static void sirfsoc_uart_handle_rx_done(struct sirfsoc_uart_port *sirfport) -{ - struct uart_port *port = &sirfport->port; - struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; - struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; - struct sirfsoc_int_status *uint_st = &sirfport->uart_reg->uart_int_st; - - sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count); - if (sirfport->rx_io_count == 4) { - sirfport->rx_io_count = 0; - if (!sirfport->is_atlas7) - wr_regl(port, ureg->sirfsoc_int_en_reg, - rd_regl(port, ureg->sirfsoc_int_en_reg) & - ~(uint_en->sirfsoc_rx_done_en)); - else - wr_regl(port, SIRFUART_INT_EN_CLR, - uint_en->sirfsoc_rx_done_en); - wr_regl(port, ureg->sirfsoc_int_st_reg, - uint_st->sirfsoc_rx_timeout); - sirfsoc_uart_start_next_rx_dma(port); - } -} - static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id) { unsigned long intr_status; @@ -628,20 +480,25 @@ static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id) intr_status = rd_regl(port, ureg->sirfsoc_int_st_reg); wr_regl(port, ureg->sirfsoc_int_st_reg, intr_status); intr_status &= rd_regl(port, ureg->sirfsoc_int_en_reg); - if (unlikely(intr_status & (SIRFUART_ERR_INT_STAT(port, uint_st)))) { + if (unlikely(intr_status & (SIRFUART_ERR_INT_STAT(uint_st, + sirfport->uart_reg->uart_type)))) { if (intr_status & uint_st->sirfsoc_rxd_brk) { port->icount.brk++; if (uart_handle_break(port)) goto recv_char; } - if (intr_status & uint_st->sirfsoc_rx_oflow) + if (intr_status & uint_st->sirfsoc_rx_oflow) { port->icount.overrun++; + flag = TTY_OVERRUN; + } if (intr_status & uint_st->sirfsoc_frm_err) { port->icount.frame++; flag = TTY_FRAME; } - if (intr_status & uint_st->sirfsoc_parity_err) + if (intr_status & uint_st->sirfsoc_parity_err) { + port->icount.parity++; flag = TTY_PARITY; + } wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET); wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0); wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START); @@ -662,15 +519,51 @@ recv_char: uart_handle_cts_change(port, cts_status); wake_up_interruptible(&state->port.delta_msr_wait); } - if (sirfport->rx_dma_chan) { - if (intr_status & uint_st->sirfsoc_rx_timeout) - sirfsoc_uart_handle_rx_tmo(sirfport); - if (intr_status & uint_st->sirfsoc_rx_done) - sirfsoc_uart_handle_rx_done(sirfport); - } else { - if (intr_status & SIRFUART_RX_IO_INT_ST(uint_st)) - sirfsoc_uart_pio_rx_chars(port, - SIRFSOC_UART_IO_RX_MAX_CNT); + if (!sirfport->rx_dma_chan && + (intr_status & SIRFUART_RX_IO_INT_ST(uint_st))) { + /* + * chip will trigger continuous RX_TIMEOUT interrupt + * in RXFIFO empty and not trigger if RXFIFO recevice + * data in limit time, original method use RX_TIMEOUT + * will trigger lots of useless interrupt in RXFIFO + * empty.RXFIFO received one byte will trigger RX_DONE + * interrupt.use RX_DONE to wait for data received + * into RXFIFO, use RX_THD/RX_FULL for lots data receive + * and use RX_TIMEOUT for the last left data. + */ + if (intr_status & uint_st->sirfsoc_rx_done) { + if (!sirfport->is_atlas7) { + wr_regl(port, ureg->sirfsoc_int_en_reg, + rd_regl(port, ureg->sirfsoc_int_en_reg) + & ~(uint_en->sirfsoc_rx_done_en)); + wr_regl(port, ureg->sirfsoc_int_en_reg, + rd_regl(port, ureg->sirfsoc_int_en_reg) + | (uint_en->sirfsoc_rx_timeout_en)); + } else { + wr_regl(port, ureg->sirfsoc_int_en_clr_reg, + uint_en->sirfsoc_rx_done_en); + wr_regl(port, ureg->sirfsoc_int_en_reg, + uint_en->sirfsoc_rx_timeout_en); + } + } else { + if (intr_status & uint_st->sirfsoc_rx_timeout) { + if (!sirfport->is_atlas7) { + wr_regl(port, ureg->sirfsoc_int_en_reg, + rd_regl(port, ureg->sirfsoc_int_en_reg) + & ~(uint_en->sirfsoc_rx_timeout_en)); + wr_regl(port, ureg->sirfsoc_int_en_reg, + rd_regl(port, ureg->sirfsoc_int_en_reg) + | (uint_en->sirfsoc_rx_done_en)); + } else { + wr_regl(port, + ureg->sirfsoc_int_en_clr_reg, + uint_en->sirfsoc_rx_timeout_en); + wr_regl(port, ureg->sirfsoc_int_en_reg, + uint_en->sirfsoc_rx_done_en); + } + } + sirfsoc_uart_pio_rx_chars(port, port->fifosize); + } } spin_unlock(&port->lock); tty_flip_buffer_push(&state->port); @@ -684,10 +577,10 @@ recv_char: return IRQ_HANDLED; } else { sirfsoc_uart_pio_tx_chars(sirfport, - SIRFSOC_UART_IO_TX_REASONABLE_CNT); + port->fifosize); if ((uart_circ_empty(xmit)) && (rd_regl(port, ureg->sirfsoc_tx_fifo_status) & - ufifo_st->ff_empty(port->line))) + ufifo_st->ff_empty(port))) sirfsoc_uart_stop_tx(port); } } @@ -697,41 +590,8 @@ recv_char: return IRQ_HANDLED; } -static void sirfsoc_uart_rx_dma_complete_tl(unsigned long param) -{ - struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param; - struct uart_port *port = &sirfport->port; - struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; - struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; - unsigned long flags; - struct dma_tx_state tx_state; - spin_lock_irqsave(&port->lock, flags); - while (DMA_COMPLETE == dmaengine_tx_status(sirfport->rx_dma_chan, - sirfport->rx_dma_items[sirfport->rx_completed].cookie, &tx_state)) { - sirfsoc_uart_insert_rx_buf_to_tty(sirfport, - SIRFSOC_RX_DMA_BUF_SIZE); - if (rd_regl(port, ureg->sirfsoc_int_en_reg) & - uint_en->sirfsoc_rx_timeout_en) - sirfsoc_rx_submit_one_dma_desc(port, - sirfport->rx_completed++); - else - sirfport->rx_completed++; - sirfport->rx_completed %= SIRFSOC_RX_LOOP_BUF_CNT; - } - spin_unlock_irqrestore(&port->lock, flags); - tty_flip_buffer_push(&port->state->port); -} - static void sirfsoc_uart_rx_dma_complete_callback(void *param) { - struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param; - unsigned long flags; - - spin_lock_irqsave(&sirfport->port.lock, flags); - sirfport->rx_issued++; - sirfport->rx_issued %= SIRFSOC_RX_LOOP_BUF_CNT; - tasklet_schedule(&sirfport->rx_dma_complete_tasklet); - spin_unlock_irqrestore(&sirfport->port.lock, flags); } /* submit rx dma task into dmaengine */ @@ -740,21 +600,36 @@ static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port) struct sirfsoc_uart_port *sirfport = to_sirfport(port); struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; - int i; sirfport->rx_io_count = 0; wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) & ~SIRFUART_IO_MODE); - for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++) - sirfsoc_rx_submit_one_dma_desc(port, i); - sirfport->rx_completed = sirfport->rx_issued = 0; + sirfport->rx_dma_items.xmit.tail = + sirfport->rx_dma_items.xmit.head = 0; + sirfport->rx_dma_items.desc = + dmaengine_prep_dma_cyclic(sirfport->rx_dma_chan, + sirfport->rx_dma_items.dma_addr, SIRFSOC_RX_DMA_BUF_SIZE, + SIRFSOC_RX_DMA_BUF_SIZE / 2, + DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); + if (IS_ERR_OR_NULL(sirfport->rx_dma_items.desc)) { + dev_err(port->dev, "DMA slave single fail\n"); + return; + } + sirfport->rx_dma_items.desc->callback = + sirfsoc_uart_rx_dma_complete_callback; + sirfport->rx_dma_items.desc->callback_param = sirfport; + sirfport->rx_dma_items.cookie = + dmaengine_submit(sirfport->rx_dma_items.desc); + dma_async_issue_pending(sirfport->rx_dma_chan); if (!sirfport->is_atlas7) wr_regl(port, ureg->sirfsoc_int_en_reg, rd_regl(port, ureg->sirfsoc_int_en_reg) | - SIRFUART_RX_DMA_INT_EN(port, uint_en)); + SIRFUART_RX_DMA_INT_EN(uint_en, + sirfport->uart_reg->uart_type)); else wr_regl(port, ureg->sirfsoc_int_en_reg, - SIRFUART_RX_DMA_INT_EN(port, uint_en)); + SIRFUART_RX_DMA_INT_EN(uint_en, + sirfport->uart_reg->uart_type)); } static void sirfsoc_uart_start_rx(struct uart_port *port) @@ -773,10 +648,12 @@ static void sirfsoc_uart_start_rx(struct uart_port *port) if (!sirfport->is_atlas7) wr_regl(port, ureg->sirfsoc_int_en_reg, rd_regl(port, ureg->sirfsoc_int_en_reg) | - SIRFUART_RX_IO_INT_EN(port, uint_en)); + SIRFUART_RX_IO_INT_EN(uint_en, + sirfport->uart_reg->uart_type)); else wr_regl(port, ureg->sirfsoc_int_en_reg, - SIRFUART_RX_IO_INT_EN(port, uint_en)); + SIRFUART_RX_IO_INT_EN(uint_en, + sirfport->uart_reg->uart_type)); } } @@ -789,7 +666,7 @@ sirfsoc_usp_calc_sample_div(unsigned long set_rate, unsigned long ioclk_div = 0; unsigned long temp_delta; - for (sample_div = SIRF_MIN_SAMPLE_DIV; + for (sample_div = SIRF_USP_MIN_SAMPLE_DIV; sample_div <= SIRF_MAX_SAMPLE_DIV; sample_div++) { temp_delta = ioclk_rate - (ioclk_rate + (set_rate * sample_div) / 2) @@ -910,10 +787,11 @@ static void sirfsoc_uart_set_termios(struct uart_port *port, config_reg |= SIRFUART_STICK_BIT_MARK; else config_reg |= SIRFUART_STICK_BIT_SPACE; - } else if (termios->c_cflag & PARODD) { - config_reg |= SIRFUART_STICK_BIT_ODD; } else { - config_reg |= SIRFUART_STICK_BIT_EVEN; + if (termios->c_cflag & PARODD) + config_reg |= SIRFUART_STICK_BIT_ODD; + else + config_reg |= SIRFUART_STICK_BIT_EVEN; } } } else { @@ -976,7 +854,7 @@ static void sirfsoc_uart_set_termios(struct uart_port *port, wr_regl(port, ureg->sirfsoc_tx_fifo_op, (txfifo_op_reg & ~SIRFUART_FIFO_START)); if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) { - config_reg |= SIRFUART_RECV_TIMEOUT(port, rx_time_out); + config_reg |= SIRFUART_UART_RECV_TIMEOUT(rx_time_out); wr_regl(port, ureg->sirfsoc_line_ctrl, config_reg); } else { /*tx frame ctrl*/ @@ -999,7 +877,7 @@ static void sirfsoc_uart_set_termios(struct uart_port *port, wr_regl(port, ureg->sirfsoc_rx_frame_ctrl, len_val); /*async param*/ wr_regl(port, ureg->sirfsoc_async_param_reg, - (SIRFUART_RECV_TIMEOUT(port, rx_time_out)) | + (SIRFUART_USP_RECV_TIMEOUT(rx_time_out)) | (sample_div_reg & SIRFSOC_USP_ASYNC_DIV2_MASK) << SIRFSOC_USP_ASYNC_DIV2_OFFSET); } @@ -1011,6 +889,7 @@ static void sirfsoc_uart_set_termios(struct uart_port *port, wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, SIRFUART_DMA_MODE); else wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, SIRFUART_IO_MODE); + sirfport->rx_period_time = 20000000; /* Reset Rx/Tx FIFO Threshold level for proper baudrate */ if (set_baud < 1000000) threshold_div = 1; @@ -1032,19 +911,10 @@ static void sirfsoc_uart_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) { struct sirfsoc_uart_port *sirfport = to_sirfport(port); - if (!state) { - if (sirfport->is_bt_uart) { - clk_prepare_enable(sirfport->clk_noc); - clk_prepare_enable(sirfport->clk_general); - } + if (!state) clk_prepare_enable(sirfport->clk); - } else { + else clk_disable_unprepare(sirfport->clk); - if (sirfport->is_bt_uart) { - clk_disable_unprepare(sirfport->clk_general); - clk_disable_unprepare(sirfport->clk_noc); - } - } } static int sirfsoc_uart_startup(struct uart_port *port) @@ -1053,7 +923,7 @@ static int sirfsoc_uart_startup(struct uart_port *port) struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; unsigned int index = port->line; int ret; - set_irq_flags(port->irq, IRQF_VALID | IRQF_NOAUTOEN); + irq_modify_status(port->irq, IRQ_NOREQUEST, IRQ_NOAUTOEN); ret = request_irq(port->irq, sirfsoc_uart_isr, 0, @@ -1064,7 +934,6 @@ static int sirfsoc_uart_startup(struct uart_port *port) index, port->irq); goto irq_err; } - /* initial hardware settings */ wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl, rd_regl(port, ureg->sirfsoc_tx_dma_io_ctrl) | @@ -1072,6 +941,9 @@ static int sirfsoc_uart_startup(struct uart_port *port) wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) | SIRFUART_IO_MODE); + wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, + rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) & + ~SIRFUART_RX_DMA_FLUSH); wr_regl(port, ureg->sirfsoc_tx_dma_io_len, 0); wr_regl(port, ureg->sirfsoc_rx_dma_io_len, 0); wr_regl(port, ureg->sirfsoc_tx_rx_en, SIRFUART_RX_EN | SIRFUART_TX_EN); @@ -1080,7 +952,6 @@ static int sirfsoc_uart_startup(struct uart_port *port) SIRFSOC_USP_ENDIAN_CTRL_LSBF | SIRFSOC_USP_EN); wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_RESET); - wr_regl(port, ureg->sirfsoc_tx_fifo_op, 0); wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET); wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0); wr_regl(port, ureg->sirfsoc_tx_fifo_ctrl, SIRFUART_FIFO_THD(port)); @@ -1100,8 +971,8 @@ static int sirfsoc_uart_startup(struct uart_port *port) sirfport->ms_enabled = false; if (sirfport->uart_reg->uart_type == SIRF_USP_UART && sirfport->hw_flow_ctrl) { - set_irq_flags(gpio_to_irq(sirfport->cts_gpio), - IRQF_VALID | IRQF_NOAUTOEN); + irq_modify_status(gpio_to_irq(sirfport->cts_gpio), + IRQ_NOREQUEST, IRQ_NOAUTOEN); ret = request_irq(gpio_to_irq(sirfport->cts_gpio), sirfsoc_uart_usp_cts_handler, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "usp_cts_irq", sirfport); @@ -1110,8 +981,16 @@ static int sirfsoc_uart_startup(struct uart_port *port) goto init_rx_err; } } - enable_irq(port->irq); + if (sirfport->rx_dma_chan && !sirfport->is_hrt_enabled) { + sirfport->is_hrt_enabled = true; + sirfport->rx_period_time = 20000000; + sirfport->rx_dma_items.xmit.tail = + sirfport->rx_dma_items.xmit.head = 0; + hrtimer_start(&sirfport->hrt, + ns_to_ktime(sirfport->rx_period_time), + HRTIMER_MODE_REL); + } return 0; init_rx_err: @@ -1127,7 +1006,7 @@ static void sirfsoc_uart_shutdown(struct uart_port *port) if (!sirfport->is_atlas7) wr_regl(port, ureg->sirfsoc_int_en_reg, 0); else - wr_regl(port, SIRFUART_INT_EN_CLR, ~0UL); + wr_regl(port, ureg->sirfsoc_int_en_clr_reg, ~0UL); free_irq(port->irq, sirfport); if (sirfport->ms_enabled) @@ -1139,6 +1018,13 @@ static void sirfsoc_uart_shutdown(struct uart_port *port) } if (sirfport->tx_dma_chan) sirfport->tx_dma_state = TX_DMA_IDLE; + if (sirfport->rx_dma_chan && sirfport->is_hrt_enabled) { + while ((rd_regl(port, ureg->sirfsoc_rx_fifo_status) & + SIRFUART_RX_FIFO_MASK) > 0) + ; + sirfport->is_hrt_enabled = false; + hrtimer_cancel(&sirfport->hrt); + } } static const char *sirfsoc_uart_type(struct uart_port *port) @@ -1196,27 +1082,29 @@ sirfsoc_uart_console_setup(struct console *co, char *options) unsigned int bits = 8; unsigned int parity = 'n'; unsigned int flow = 'n'; - struct uart_port *port = &sirfsoc_uart_ports[co->index].port; - struct sirfsoc_uart_port *sirfport = to_sirfport(port); - struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; + struct sirfsoc_uart_port *sirfport; + struct sirfsoc_register *ureg; if (co->index < 0 || co->index >= SIRFSOC_UART_NR) - return -EINVAL; - - if (!port->mapbase) + co->index = 1; + sirfport = sirf_ports[co->index]; + if (!sirfport) + return -ENODEV; + ureg = &sirfport->uart_reg->uart_reg; + if (!sirfport->port.mapbase) return -ENODEV; /* enable usp in mode1 register */ if (sirfport->uart_reg->uart_type == SIRF_USP_UART) - wr_regl(port, ureg->sirfsoc_mode1, SIRFSOC_USP_EN | + wr_regl(&sirfport->port, ureg->sirfsoc_mode1, SIRFSOC_USP_EN | SIRFSOC_USP_ENDIAN_CTRL_LSBF); if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); - port->cons = co; + sirfport->port.cons = co; /* default console tx/rx transfer using io mode */ sirfport->rx_dma_chan = NULL; sirfport->tx_dma_chan = NULL; - return uart_set_options(port, co, baud, parity, bits, flow); + return uart_set_options(&sirfport->port, co, baud, parity, bits, flow); } static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch) @@ -1224,8 +1112,8 @@ static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch) struct sirfsoc_uart_port *sirfport = to_sirfport(port); struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status; - while (rd_regl(port, - ureg->sirfsoc_tx_fifo_status) & ufifo_st->ff_full(port->line)) + while (rd_regl(port, ureg->sirfsoc_tx_fifo_status) & + ufifo_st->ff_full(port)) cpu_relax(); wr_regl(port, ureg->sirfsoc_tx_fifo_data, ch); } @@ -1233,8 +1121,10 @@ static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch) static void sirfsoc_uart_console_write(struct console *co, const char *s, unsigned int count) { - struct uart_port *port = &sirfsoc_uart_ports[co->index].port; - uart_console_write(port, s, count, sirfsoc_uart_console_putchar); + struct sirfsoc_uart_port *sirfport = sirf_ports[co->index]; + + uart_console_write(&sirfport->port, s, count, + sirfsoc_uart_console_putchar); } static struct console sirfsoc_uart_console = { @@ -1269,10 +1159,75 @@ static struct uart_driver sirfsoc_uart_drv = { #endif }; +static enum hrtimer_restart + sirfsoc_uart_rx_dma_hrtimer_callback(struct hrtimer *hrt) +{ + struct sirfsoc_uart_port *sirfport; + struct uart_port *port; + int count, inserted; + struct dma_tx_state tx_state; + struct tty_struct *tty; + struct sirfsoc_register *ureg; + struct circ_buf *xmit; + + sirfport = container_of(hrt, struct sirfsoc_uart_port, hrt); + port = &sirfport->port; + inserted = 0; + tty = port->state->port.tty; + ureg = &sirfport->uart_reg->uart_reg; + xmit = &sirfport->rx_dma_items.xmit; + dmaengine_tx_status(sirfport->rx_dma_chan, + sirfport->rx_dma_items.cookie, &tx_state); + xmit->head = SIRFSOC_RX_DMA_BUF_SIZE - tx_state.residue; + count = CIRC_CNT_TO_END(xmit->head, xmit->tail, + SIRFSOC_RX_DMA_BUF_SIZE); + while (count > 0) { + inserted = tty_insert_flip_string(tty->port, + (const unsigned char *)&xmit->buf[xmit->tail], count); + if (!inserted) + goto next_hrt; + port->icount.rx += inserted; + xmit->tail = (xmit->tail + inserted) & + (SIRFSOC_RX_DMA_BUF_SIZE - 1); + count = CIRC_CNT_TO_END(xmit->head, xmit->tail, + SIRFSOC_RX_DMA_BUF_SIZE); + tty_flip_buffer_push(tty->port); + } + /* + * if RX DMA buffer data have all push into tty buffer, and there is + * only little data(less than a dma transfer unit) left in rxfifo, + * fetch it out in pio mode and switch back to dma immediately + */ + if (!inserted && !count && + ((rd_regl(port, ureg->sirfsoc_rx_fifo_status) & + SIRFUART_RX_FIFO_MASK) > 0)) { + /* switch to pio mode */ + wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, + rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) | + SIRFUART_IO_MODE); + while ((rd_regl(port, ureg->sirfsoc_rx_fifo_status) & + SIRFUART_RX_FIFO_MASK) > 0) { + if (sirfsoc_uart_pio_rx_chars(port, 16) > 0) + tty_flip_buffer_push(tty->port); + } + wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET); + wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0); + wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START); + /* switch back to dma mode */ + wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, + rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) & + ~SIRFUART_IO_MODE); + } +next_hrt: + hrtimer_forward_now(hrt, ns_to_ktime(sirfport->rx_period_time)); + return HRTIMER_RESTART; +} + static struct of_device_id sirfsoc_uart_ids[] = { { .compatible = "sirf,prima2-uart", .data = &sirfsoc_uart,}, { .compatible = "sirf,atlas7-uart", .data = &sirfsoc_uart}, { .compatible = "sirf,prima2-usp-uart", .data = &sirfsoc_usp}, + { .compatible = "sirf,atlas7-usp-uart", .data = &sirfsoc_usp}, {} }; MODULE_DEVICE_TABLE(of, sirfsoc_uart_ids); @@ -1283,7 +1238,6 @@ static int sirfsoc_uart_probe(struct platform_device *pdev) struct uart_port *port; struct resource *res; int ret; - int i, j; struct dma_slave_config slv_cfg = { .src_maxburst = 2, }; @@ -1293,16 +1247,15 @@ static int sirfsoc_uart_probe(struct platform_device *pdev) const struct of_device_id *match; match = of_match_node(sirfsoc_uart_ids, pdev->dev.of_node); - if (of_property_read_u32(pdev->dev.of_node, "cell-index", &pdev->id)) { - dev_err(&pdev->dev, - "Unable to find cell-index in uart node.\n"); - ret = -EFAULT; + sirfport = devm_kzalloc(&pdev->dev, sizeof(*sirfport), GFP_KERNEL); + if (!sirfport) { + ret = -ENOMEM; goto err; } - if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-usp-uart")) - pdev->id += ((struct sirfsoc_uart_register *) - match->data)->uart_param.register_uart_nr; - sirfport = &sirfsoc_uart_ports[pdev->id]; + sirfport->port.line = of_alias_get_id(pdev->dev.of_node, "serial"); + sirf_ports[sirfport->port.line] = sirfport; + sirfport->port.iotype = UPIO_MEM; + sirfport->port.flags = UPF_BOOT_AUTOCONF; port = &sirfport->port; port->dev = &pdev->dev; port->private_data = sirfport; @@ -1310,9 +1263,12 @@ static int sirfsoc_uart_probe(struct platform_device *pdev) sirfport->hw_flow_ctrl = of_property_read_bool(pdev->dev.of_node, "sirf,uart-has-rtscts"); - if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-uart")) + if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-uart") || + of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-uart")) sirfport->uart_reg->uart_type = SIRF_REAL_UART; - if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-usp-uart")) { + if (of_device_is_compatible(pdev->dev.of_node, + "sirf,prima2-usp-uart") || of_device_is_compatible( + pdev->dev.of_node, "sirf,atlas7-usp-uart")) { sirfport->uart_reg->uart_type = SIRF_USP_UART; if (!sirfport->hw_flow_ctrl) goto usp_no_flow_control; @@ -1350,7 +1306,8 @@ static int sirfsoc_uart_probe(struct platform_device *pdev) gpio_direction_output(sirfport->rts_gpio, 1); } usp_no_flow_control: - if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-uart")) + if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-uart") || + of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-usp-uart")) sirfport->is_atlas7 = true; if (of_property_read_u32(pdev->dev.of_node, @@ -1368,12 +1325,9 @@ usp_no_flow_control: ret = -EFAULT; goto err; } - tasklet_init(&sirfport->rx_dma_complete_tasklet, - sirfsoc_uart_rx_dma_complete_tl, (unsigned long)sirfport); - tasklet_init(&sirfport->rx_tmo_process_tasklet, - sirfsoc_rx_tmo_process_tl, (unsigned long)sirfport); port->mapbase = res->start; - port->membase = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + port->membase = devm_ioremap(&pdev->dev, + res->start, resource_size(res)); if (!port->membase) { dev_err(&pdev->dev, "Cannot remap resource.\n"); ret = -ENOMEM; @@ -1393,20 +1347,6 @@ usp_no_flow_control: goto err; } port->uartclk = clk_get_rate(sirfport->clk); - if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-bt-uart")) { - sirfport->clk_general = devm_clk_get(&pdev->dev, "general"); - if (IS_ERR(sirfport->clk_general)) { - ret = PTR_ERR(sirfport->clk_general); - goto err; - } - sirfport->clk_noc = devm_clk_get(&pdev->dev, "noc"); - if (IS_ERR(sirfport->clk_noc)) { - ret = PTR_ERR(sirfport->clk_noc); - goto err; - } - sirfport->is_bt_uart = true; - } else - sirfport->is_bt_uart = false; port->ops = &sirfsoc_uart_ops; spin_lock_init(&port->lock); @@ -1419,30 +1359,32 @@ usp_no_flow_control: } sirfport->rx_dma_chan = dma_request_slave_channel(port->dev, "rx"); - for (i = 0; sirfport->rx_dma_chan && i < SIRFSOC_RX_LOOP_BUF_CNT; i++) { - sirfport->rx_dma_items[i].xmit.buf = - dma_alloc_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE, - &sirfport->rx_dma_items[i].dma_addr, GFP_KERNEL); - if (!sirfport->rx_dma_items[i].xmit.buf) { - dev_err(port->dev, "Uart alloc bufa failed\n"); - ret = -ENOMEM; - goto alloc_coherent_err; - } - sirfport->rx_dma_items[i].xmit.head = - sirfport->rx_dma_items[i].xmit.tail = 0; + sirfport->rx_dma_items.xmit.buf = + dma_alloc_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE, + &sirfport->rx_dma_items.dma_addr, GFP_KERNEL); + if (!sirfport->rx_dma_items.xmit.buf) { + dev_err(port->dev, "Uart alloc bufa failed\n"); + ret = -ENOMEM; + goto alloc_coherent_err; } + sirfport->rx_dma_items.xmit.head = + sirfport->rx_dma_items.xmit.tail = 0; if (sirfport->rx_dma_chan) dmaengine_slave_config(sirfport->rx_dma_chan, &slv_cfg); sirfport->tx_dma_chan = dma_request_slave_channel(port->dev, "tx"); if (sirfport->tx_dma_chan) dmaengine_slave_config(sirfport->tx_dma_chan, &tx_slv_cfg); + if (sirfport->rx_dma_chan) { + hrtimer_init(&sirfport->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + sirfport->hrt.function = sirfsoc_uart_rx_dma_hrtimer_callback; + sirfport->is_hrt_enabled = false; + } return 0; alloc_coherent_err: - for (j = 0; j < i; j++) - dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE, - sirfport->rx_dma_items[j].xmit.buf, - sirfport->rx_dma_items[j].dma_addr); + dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE, + sirfport->rx_dma_items.xmit.buf, + sirfport->rx_dma_items.dma_addr); dma_release_channel(sirfport->rx_dma_chan); err: return ret; @@ -1454,13 +1396,11 @@ static int sirfsoc_uart_remove(struct platform_device *pdev) struct uart_port *port = &sirfport->port; uart_remove_one_port(&sirfsoc_uart_drv, port); if (sirfport->rx_dma_chan) { - int i; dmaengine_terminate_all(sirfport->rx_dma_chan); dma_release_channel(sirfport->rx_dma_chan); - for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++) - dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE, - sirfport->rx_dma_items[i].xmit.buf, - sirfport->rx_dma_items[i].dma_addr); + dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE, + sirfport->rx_dma_items.xmit.buf, + sirfport->rx_dma_items.dma_addr); } if (sirfport->tx_dma_chan) { dmaengine_terminate_all(sirfport->tx_dma_chan); diff --git a/drivers/tty/serial/sirfsoc_uart.h b/drivers/tty/serial/sirfsoc_uart.h index 727eb6b88fff..eb162b012eec 100644 --- a/drivers/tty/serial/sirfsoc_uart.h +++ b/drivers/tty/serial/sirfsoc_uart.h @@ -6,11 +6,11 @@ * Licensed under GPLv2 or later. */ #include <linux/bitops.h> +#include <linux/log2.h> +#include <linux/hrtimer.h> struct sirfsoc_uart_param { const char *uart_name; const char *port_name; - u32 uart_nr; - u32 register_uart_nr; }; struct sirfsoc_register { @@ -21,6 +21,7 @@ struct sirfsoc_register { u32 sirfsoc_tx_rx_en; u32 sirfsoc_int_en_reg; u32 sirfsoc_int_st_reg; + u32 sirfsoc_int_en_clr_reg; u32 sirfsoc_tx_dma_io_ctrl; u32 sirfsoc_tx_dma_io_len; u32 sirfsoc_tx_fifo_ctrl; @@ -45,8 +46,8 @@ struct sirfsoc_register { u32 sirfsoc_async_param_reg; }; -typedef u32 (*fifo_full_mask)(int line); -typedef u32 (*fifo_empty_mask)(int line); +typedef u32 (*fifo_full_mask)(struct uart_port *port); +typedef u32 (*fifo_empty_mask)(struct uart_port *port); struct sirfsoc_fifo_status { fifo_full_mask ff_full; @@ -105,21 +106,20 @@ struct sirfsoc_uart_register { enum sirfsoc_uart_type uart_type; }; -u32 usp_ff_full(int line) +u32 uart_usp_ff_full_mask(struct uart_port *port) { - return 0x80; -} -u32 usp_ff_empty(int line) -{ - return 0x100; -} -u32 uart_ff_full(int line) -{ - return (line == 1) ? (0x20) : (0x80); + u32 full_bit; + + full_bit = ilog2(port->fifosize); + return (1 << full_bit); } -u32 uart_ff_empty(int line) + +u32 uart_usp_ff_empty_mask(struct uart_port *port) { - return (line == 1) ? (0x40) : (0x100); + u32 empty_bit; + + empty_bit = ilog2(port->fifosize) + 1; + return (1 << empty_bit); } struct sirfsoc_uart_register sirfsoc_usp = { .uart_reg = { @@ -145,6 +145,7 @@ struct sirfsoc_uart_register sirfsoc_usp = { .sirfsoc_rx_fifo_op = 0x0130, .sirfsoc_rx_fifo_status = 0x0134, .sirfsoc_rx_fifo_data = 0x0138, + .sirfsoc_int_en_clr_reg = 0x140, }, .uart_int_en = { .sirfsoc_rx_done_en = BIT(0), @@ -177,14 +178,12 @@ struct sirfsoc_uart_register sirfsoc_usp = { .sirfsoc_rxd_brk = BIT(15), }, .fifo_status = { - .ff_full = usp_ff_full, - .ff_empty = usp_ff_empty, + .ff_full = uart_usp_ff_full_mask, + .ff_empty = uart_usp_ff_empty_mask, }, .uart_param = { .uart_name = "ttySiRF", .port_name = "sirfsoc-uart", - .uart_nr = 2, - .register_uart_nr = 3, }, }; @@ -195,6 +194,7 @@ struct sirfsoc_uart_register sirfsoc_uart = { .sirfsoc_divisor = 0x0050, .sirfsoc_int_en_reg = 0x0054, .sirfsoc_int_st_reg = 0x0058, + .sirfsoc_int_en_clr_reg = 0x0060, .sirfsoc_tx_dma_io_ctrl = 0x0100, .sirfsoc_tx_dma_io_len = 0x0104, .sirfsoc_tx_fifo_ctrl = 0x0108, @@ -249,14 +249,12 @@ struct sirfsoc_uart_register sirfsoc_uart = { .sirfsoc_rts = BIT(15), }, .fifo_status = { - .ff_full = uart_ff_full, - .ff_empty = uart_ff_empty, + .ff_full = uart_usp_ff_full_mask, + .ff_empty = uart_usp_ff_empty_mask, }, .uart_param = { .uart_name = "ttySiRF", .port_name = "sirfsoc_uart", - .uart_nr = 3, - .register_uart_nr = 0, }, }; /* uart io ctrl */ @@ -296,10 +294,10 @@ struct sirfsoc_uart_register sirfsoc_uart = { #define SIRFUART_IO_MODE BIT(0) #define SIRFUART_DMA_MODE 0x0 +#define SIRFUART_RX_DMA_FLUSH 0x4 -/* Macro Specific*/ -#define SIRFUART_INT_EN_CLR 0x0060 /* Baud Rate Calculation */ +#define SIRF_USP_MIN_SAMPLE_DIV 0x1 #define SIRF_MIN_SAMPLE_DIV 0xf #define SIRF_MAX_SAMPLE_DIV 0x3f #define SIRF_IOCLK_DIV_MAX 0xffff @@ -326,55 +324,54 @@ struct sirfsoc_uart_register sirfsoc_uart = { #define SIRFSOC_USP_RX_CLK_DIVISOR_OFFSET 24 #define SIRFSOC_USP_ASYNC_DIV2_MASK 0x3f #define SIRFSOC_USP_ASYNC_DIV2_OFFSET 16 - +#define SIRFSOC_USP_LOOP_BACK_CTRL BIT(2) /* USP-UART Common */ #define SIRFSOC_UART_RX_TIMEOUT(br, to) (((br) * (((to) + 999) / 1000)) / 1000) #define SIRFUART_RECV_TIMEOUT_VALUE(x) \ (((x) > 0xFFFF) ? 0xFFFF : ((x) & 0xFFFF)) -#define SIRFUART_RECV_TIMEOUT(port, x) \ - (((port)->line > 2) ? (x & 0xFFFF) : ((x) & 0xFFFF) << 16) +#define SIRFUART_USP_RECV_TIMEOUT(x) (x & 0xFFFF) +#define SIRFUART_UART_RECV_TIMEOUT(x) ((x & 0xFFFF) << 16) -#define SIRFUART_FIFO_THD(port) ((port->line) == 1 ? 16 : 64) -#define SIRFUART_ERR_INT_STAT(port, unit_st) \ +#define SIRFUART_FIFO_THD(port) (port->fifosize >> 1) +#define SIRFUART_ERR_INT_STAT(unit_st, uart_type) \ (uint_st->sirfsoc_rx_oflow | \ uint_st->sirfsoc_frm_err | \ uint_st->sirfsoc_rxd_brk | \ - ((port->line > 2) ? 0 : uint_st->sirfsoc_parity_err)) -#define SIRFUART_RX_IO_INT_EN(port, uint_en) \ - (uint_en->sirfsoc_rx_timeout_en |\ + ((uart_type != SIRF_REAL_UART) ? \ + 0 : uint_st->sirfsoc_parity_err)) +#define SIRFUART_RX_IO_INT_EN(uint_en, uart_type) \ + (uint_en->sirfsoc_rx_done_en |\ uint_en->sirfsoc_rxfifo_thd_en |\ uint_en->sirfsoc_rxfifo_full_en |\ uint_en->sirfsoc_frm_err_en |\ uint_en->sirfsoc_rx_oflow_en |\ uint_en->sirfsoc_rxd_brk_en |\ - ((port->line > 2) ? 0 : uint_en->sirfsoc_parity_err_en)) + ((uart_type != SIRF_REAL_UART) ? \ + 0 : uint_en->sirfsoc_parity_err_en)) #define SIRFUART_RX_IO_INT_ST(uint_st) \ - (uint_st->sirfsoc_rx_timeout |\ - uint_st->sirfsoc_rxfifo_thd |\ - uint_st->sirfsoc_rxfifo_full) + (uint_st->sirfsoc_rxfifo_thd |\ + uint_st->sirfsoc_rxfifo_full|\ + uint_st->sirfsoc_rx_done |\ + uint_st->sirfsoc_rx_timeout) #define SIRFUART_CTS_INT_ST(uint_st) (uint_st->sirfsoc_cts) -#define SIRFUART_RX_DMA_INT_EN(port, uint_en) \ - (uint_en->sirfsoc_rx_timeout_en |\ - uint_en->sirfsoc_frm_err_en |\ +#define SIRFUART_RX_DMA_INT_EN(uint_en, uart_type) \ + (uint_en->sirfsoc_frm_err_en |\ uint_en->sirfsoc_rx_oflow_en |\ uint_en->sirfsoc_rxd_brk_en |\ - ((port->line > 2) ? 0 : uint_en->sirfsoc_parity_err_en)) + ((uart_type != SIRF_REAL_UART) ? \ + 0 : uint_en->sirfsoc_parity_err_en)) /* Generic Definitions */ #define SIRFSOC_UART_NAME "ttySiRF" #define SIRFSOC_UART_MAJOR 0 #define SIRFSOC_UART_MINOR 0 #define SIRFUART_PORT_NAME "sirfsoc-uart" #define SIRFUART_MAP_SIZE 0x200 -#define SIRFSOC_UART_NR 6 +#define SIRFSOC_UART_NR 11 #define SIRFSOC_PORT_TYPE 0xa5 /* Uart Common Use Macro*/ -#define SIRFSOC_RX_DMA_BUF_SIZE 256 +#define SIRFSOC_RX_DMA_BUF_SIZE (1024 * 32) #define BYTES_TO_ALIGN(dma_addr) ((unsigned long)(dma_addr) & 0x3) -#define LOOP_DMA_BUFA_FILL 1 -#define LOOP_DMA_BUFB_FILL 2 -#define TX_TRAN_PIO 1 -#define TX_TRAN_DMA 2 /* Uart Fifo Level Chk */ #define SIRFUART_TX_FIFO_SC_OFFSET 0 #define SIRFUART_TX_FIFO_LC_OFFSET 10 @@ -389,8 +386,8 @@ struct sirfsoc_uart_register sirfsoc_uart = { #define SIRFUART_RX_FIFO_CHK_SC SIRFUART_TX_FIFO_CHK_SC #define SIRFUART_RX_FIFO_CHK_LC SIRFUART_TX_FIFO_CHK_LC #define SIRFUART_RX_FIFO_CHK_HC SIRFUART_TX_FIFO_CHK_HC +#define SIRFUART_RX_FIFO_MASK 0x7f /* Indicate how many buffers used */ -#define SIRFSOC_RX_LOOP_BUF_CNT 2 /* For Fast Baud Rate Calculation */ struct sirfsoc_baudrate_to_regv { @@ -404,7 +401,7 @@ enum sirfsoc_tx_state { TX_DMA_PAUSE, }; -struct sirfsoc_loop_buffer { +struct sirfsoc_rx_buffer { struct circ_buf xmit; dma_cookie_t cookie; struct dma_async_tx_descriptor *desc; @@ -417,10 +414,6 @@ struct sirfsoc_uart_port { struct uart_port port; struct clk *clk; - /* UART6 for BT usage in A7DA platform need multi-clock source */ - bool is_bt_uart; - struct clk *clk_general; - struct clk *clk_noc; /* for SiRFatlas7, there are SET/CLR for UART_INT_EN */ bool is_atlas7; struct sirfsoc_uart_register *uart_reg; @@ -428,17 +421,16 @@ struct sirfsoc_uart_port { struct dma_chan *tx_dma_chan; dma_addr_t tx_dma_addr; struct dma_async_tx_descriptor *tx_dma_desc; - struct tasklet_struct rx_dma_complete_tasklet; - struct tasklet_struct rx_tmo_process_tasklet; unsigned int rx_io_count; unsigned long transfer_size; enum sirfsoc_tx_state tx_dma_state; unsigned int cts_gpio; unsigned int rts_gpio; - struct sirfsoc_loop_buffer rx_dma_items[SIRFSOC_RX_LOOP_BUF_CNT]; - int rx_completed; - int rx_issued; + struct sirfsoc_rx_buffer rx_dma_items; + struct hrtimer hrt; + bool is_hrt_enabled; + unsigned long rx_period_time; }; /* Register Access Control */ @@ -447,10 +439,6 @@ struct sirfsoc_uart_port { #define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg)) /* UART Port Mask */ -#define SIRFUART_FIFOLEVEL_MASK(port) ((port->line == 1) ? (0x1f) : (0x7f)) -#define SIRFUART_FIFOFULL_MASK(port) ((port->line == 1) ? (0x20) : (0x80)) -#define SIRFUART_FIFOEMPTY_MASK(port) ((port->line == 1) ? (0x40) : (0x100)) - -/* I/O Mode */ -#define SIRFSOC_UART_IO_RX_MAX_CNT 256 -#define SIRFSOC_UART_IO_TX_REASONABLE_CNT 256 +#define SIRFUART_FIFOLEVEL_MASK(port) ((port->fifosize - 1) & 0xFFF) +#define SIRFUART_FIFOFULL_MASK(port) (port->fifosize & 0xFFF) +#define SIRFUART_FIFOEMPTY_MASK(port) ((port->fifosize & 0xFFF) << 1) diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c index bca975f5093b..3866516c2926 100644 --- a/drivers/tty/serial/sprd_serial.c +++ b/drivers/tty/serial/sprd_serial.c @@ -493,6 +493,8 @@ static int sprd_verify_port(struct uart_port *port, return -EINVAL; if (port->irq != ser->irq) return -EINVAL; + if (port->iotype != ser->io_type) + return -EINVAL; return 0; } @@ -707,14 +709,14 @@ static int sprd_probe(struct platform_device *pdev) up->dev = &pdev->dev; up->line = index; up->type = PORT_SPRD; - up->iotype = SERIAL_IO_PORT; + up->iotype = UPIO_MEM; up->uartclk = SPRD_DEF_RATE; up->fifosize = SPRD_FIFO_SIZE; up->ops = &serial_sprd_ops; up->flags = UPF_BOOT_AUTOCONF; clk = devm_clk_get(&pdev->dev, NULL); - if (!IS_ERR(clk)) + if (!IS_ERR_OR_NULL(clk)) up->uartclk = clk_get_rate(clk); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -754,6 +756,7 @@ static int sprd_probe(struct platform_device *pdev) return ret; } +#ifdef CONFIG_PM_SLEEP static int sprd_suspend(struct device *dev) { struct sprd_uart_port *sup = dev_get_drvdata(dev); @@ -771,6 +774,7 @@ static int sprd_resume(struct device *dev) return 0; } +#endif static SIMPLE_DEV_PM_OPS(sprd_pm_ops, sprd_suspend, sprd_resume); diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c index 712b03a076b8..d625664ce1b5 100644 --- a/drivers/tty/serial/st-asc.c +++ b/drivers/tty/serial/st-asc.c @@ -720,7 +720,7 @@ static struct asc_port *asc_of_get_asc_port(struct platform_device *pdev) } #ifdef CONFIG_OF -static struct of_device_id asc_match[] = { +static const struct of_device_id asc_match[] = { { .compatible = "st,asc", }, {}, }; diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c new file mode 100644 index 000000000000..4a6eab6da63e --- /dev/null +++ b/drivers/tty/serial/stm32-usart.c @@ -0,0 +1,739 @@ +/* + * Copyright (C) Maxime Coquelin 2015 + * Author: Maxime Coquelin <mcoquelin.stm32@gmail.com> + * License terms: GNU General Public License (GPL), version 2 + * + * Inspired by st-asc.c from STMicroelectronics (c) + */ + +#if defined(CONFIG_SERIAL_STM32_USART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include <linux/module.h> +#include <linux/serial.h> +#include <linux/console.h> +#include <linux/sysrq.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/delay.h> +#include <linux/spinlock.h> +#include <linux/pm_runtime.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/serial_core.h> +#include <linux/clk.h> + +#define DRIVER_NAME "stm32-usart" + +/* Register offsets */ +#define USART_SR 0x00 +#define USART_DR 0x04 +#define USART_BRR 0x08 +#define USART_CR1 0x0c +#define USART_CR2 0x10 +#define USART_CR3 0x14 +#define USART_GTPR 0x18 + +/* USART_SR */ +#define USART_SR_PE BIT(0) +#define USART_SR_FE BIT(1) +#define USART_SR_NF BIT(2) +#define USART_SR_ORE BIT(3) +#define USART_SR_IDLE BIT(4) +#define USART_SR_RXNE BIT(5) +#define USART_SR_TC BIT(6) +#define USART_SR_TXE BIT(7) +#define USART_SR_LBD BIT(8) +#define USART_SR_CTS BIT(9) +#define USART_SR_ERR_MASK (USART_SR_LBD | USART_SR_ORE | \ + USART_SR_FE | USART_SR_PE) +/* Dummy bits */ +#define USART_SR_DUMMY_RX BIT(16) + +/* USART_DR */ +#define USART_DR_MASK GENMASK(8, 0) + +/* USART_BRR */ +#define USART_BRR_DIV_F_MASK GENMASK(3, 0) +#define USART_BRR_DIV_M_MASK GENMASK(15, 4) +#define USART_BRR_DIV_M_SHIFT 4 + +/* USART_CR1 */ +#define USART_CR1_SBK BIT(0) +#define USART_CR1_RWU BIT(1) +#define USART_CR1_RE BIT(2) +#define USART_CR1_TE BIT(3) +#define USART_CR1_IDLEIE BIT(4) +#define USART_CR1_RXNEIE BIT(5) +#define USART_CR1_TCIE BIT(6) +#define USART_CR1_TXEIE BIT(7) +#define USART_CR1_PEIE BIT(8) +#define USART_CR1_PS BIT(9) +#define USART_CR1_PCE BIT(10) +#define USART_CR1_WAKE BIT(11) +#define USART_CR1_M BIT(12) +#define USART_CR1_UE BIT(13) +#define USART_CR1_OVER8 BIT(15) +#define USART_CR1_IE_MASK GENMASK(8, 4) + +/* USART_CR2 */ +#define USART_CR2_ADD_MASK GENMASK(3, 0) +#define USART_CR2_LBDL BIT(5) +#define USART_CR2_LBDIE BIT(6) +#define USART_CR2_LBCL BIT(8) +#define USART_CR2_CPHA BIT(9) +#define USART_CR2_CPOL BIT(10) +#define USART_CR2_CLKEN BIT(11) +#define USART_CR2_STOP_2B BIT(13) +#define USART_CR2_STOP_MASK GENMASK(13, 12) +#define USART_CR2_LINEN BIT(14) + +/* USART_CR3 */ +#define USART_CR3_EIE BIT(0) +#define USART_CR3_IREN BIT(1) +#define USART_CR3_IRLP BIT(2) +#define USART_CR3_HDSEL BIT(3) +#define USART_CR3_NACK BIT(4) +#define USART_CR3_SCEN BIT(5) +#define USART_CR3_DMAR BIT(6) +#define USART_CR3_DMAT BIT(7) +#define USART_CR3_RTSE BIT(8) +#define USART_CR3_CTSE BIT(9) +#define USART_CR3_CTSIE BIT(10) +#define USART_CR3_ONEBIT BIT(11) + +/* USART_GTPR */ +#define USART_GTPR_PSC_MASK GENMASK(7, 0) +#define USART_GTPR_GT_MASK GENMASK(15, 8) + +#define DRIVER_NAME "stm32-usart" +#define STM32_SERIAL_NAME "ttyS" +#define STM32_MAX_PORTS 6 + +struct stm32_port { + struct uart_port port; + struct clk *clk; + bool hw_flow_control; +}; + +static struct stm32_port stm32_ports[STM32_MAX_PORTS]; +static struct uart_driver stm32_usart_driver; + +static void stm32_stop_tx(struct uart_port *port); + +static inline struct stm32_port *to_stm32_port(struct uart_port *port) +{ + return container_of(port, struct stm32_port, port); +} + +static void stm32_set_bits(struct uart_port *port, u32 reg, u32 bits) +{ + u32 val; + + val = readl_relaxed(port->membase + reg); + val |= bits; + writel_relaxed(val, port->membase + reg); +} + +static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits) +{ + u32 val; + + val = readl_relaxed(port->membase + reg); + val &= ~bits; + writel_relaxed(val, port->membase + reg); +} + +static void stm32_receive_chars(struct uart_port *port) +{ + struct tty_port *tport = &port->state->port; + unsigned long c; + u32 sr; + char flag; + + if (port->irq_wake) + pm_wakeup_event(tport->tty->dev, 0); + + while ((sr = readl_relaxed(port->membase + USART_SR)) & USART_SR_RXNE) { + sr |= USART_SR_DUMMY_RX; + c = readl_relaxed(port->membase + USART_DR); + flag = TTY_NORMAL; + port->icount.rx++; + + if (sr & USART_SR_ERR_MASK) { + if (sr & USART_SR_LBD) { + port->icount.brk++; + if (uart_handle_break(port)) + continue; + } else if (sr & USART_SR_ORE) { + port->icount.overrun++; + } else if (sr & USART_SR_PE) { + port->icount.parity++; + } else if (sr & USART_SR_FE) { + port->icount.frame++; + } + + sr &= port->read_status_mask; + + if (sr & USART_SR_LBD) + flag = TTY_BREAK; + else if (sr & USART_SR_PE) + flag = TTY_PARITY; + else if (sr & USART_SR_FE) + flag = TTY_FRAME; + } + + if (uart_handle_sysrq_char(port, c)) + continue; + uart_insert_char(port, sr, USART_SR_ORE, c, flag); + } + + spin_unlock(&port->lock); + tty_flip_buffer_push(tport); + spin_lock(&port->lock); +} + +static void stm32_transmit_chars(struct uart_port *port) +{ + struct circ_buf *xmit = &port->state->xmit; + + if (port->x_char) { + writel_relaxed(port->x_char, port->membase + USART_DR); + port->x_char = 0; + port->icount.tx++; + return; + } + + if (uart_tx_stopped(port)) { + stm32_stop_tx(port); + return; + } + + if (uart_circ_empty(xmit)) { + stm32_stop_tx(port); + return; + } + + writel_relaxed(xmit->buf[xmit->tail], port->membase + USART_DR); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (uart_circ_empty(xmit)) + stm32_stop_tx(port); +} + +static irqreturn_t stm32_interrupt(int irq, void *ptr) +{ + struct uart_port *port = ptr; + u32 sr; + + spin_lock(&port->lock); + + sr = readl_relaxed(port->membase + USART_SR); + + if (sr & USART_SR_RXNE) + stm32_receive_chars(port); + + if (sr & USART_SR_TXE) + stm32_transmit_chars(port); + + spin_unlock(&port->lock); + + return IRQ_HANDLED; +} + +static unsigned int stm32_tx_empty(struct uart_port *port) +{ + return readl_relaxed(port->membase + USART_SR) & USART_SR_TXE; +} + +static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS)) + stm32_set_bits(port, USART_CR3, USART_CR3_RTSE); + else + stm32_clr_bits(port, USART_CR3, USART_CR3_RTSE); +} + +static unsigned int stm32_get_mctrl(struct uart_port *port) +{ + /* This routine is used to get signals of: DCD, DSR, RI, and CTS */ + return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; +} + +/* Transmit stop */ +static void stm32_stop_tx(struct uart_port *port) +{ + stm32_clr_bits(port, USART_CR1, USART_CR1_TXEIE); +} + +/* There are probably characters waiting to be transmitted. */ +static void stm32_start_tx(struct uart_port *port) +{ + struct circ_buf *xmit = &port->state->xmit; + + if (uart_circ_empty(xmit)) + return; + + stm32_set_bits(port, USART_CR1, USART_CR1_TXEIE | USART_CR1_TE); +} + +/* Throttle the remote when input buffer is about to overflow. */ +static void stm32_throttle(struct uart_port *port) +{ + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + stm32_clr_bits(port, USART_CR1, USART_CR1_RXNEIE); + spin_unlock_irqrestore(&port->lock, flags); +} + +/* Unthrottle the remote, the input buffer can now accept data. */ +static void stm32_unthrottle(struct uart_port *port) +{ + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + stm32_set_bits(port, USART_CR1, USART_CR1_RXNEIE); + spin_unlock_irqrestore(&port->lock, flags); +} + +/* Receive stop */ +static void stm32_stop_rx(struct uart_port *port) +{ + stm32_clr_bits(port, USART_CR1, USART_CR1_RXNEIE); +} + +/* Handle breaks - ignored by us */ +static void stm32_break_ctl(struct uart_port *port, int break_state) +{ +} + +static int stm32_startup(struct uart_port *port) +{ + const char *name = to_platform_device(port->dev)->name; + u32 val; + int ret; + + ret = request_irq(port->irq, stm32_interrupt, IRQF_NO_SUSPEND, + name, port); + if (ret) + return ret; + + val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE; + stm32_set_bits(port, USART_CR1, val); + + return 0; +} + +static void stm32_shutdown(struct uart_port *port) +{ + u32 val; + + val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE; + stm32_set_bits(port, USART_CR1, val); + + free_irq(port->irq, port); +} + +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + unsigned int baud; + u32 usartdiv, mantissa, fraction, oversampling; + tcflag_t cflag = termios->c_cflag; + u32 cr1, cr2, cr3; + unsigned long flags; + + if (!stm32_port->hw_flow_control) + cflag &= ~CRTSCTS; + + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 8); + + spin_lock_irqsave(&port->lock, flags); + + /* Stop serial port and reset value */ + writel_relaxed(0, port->membase + USART_CR1); + + cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE; + cr2 = 0; + cr3 = 0; + + if (cflag & CSTOPB) + cr2 |= USART_CR2_STOP_2B; + + if (cflag & PARENB) { + cr1 |= USART_CR1_PCE; + if ((cflag & CSIZE) == CS8) + cr1 |= USART_CR1_M; + } + + if (cflag & PARODD) + cr1 |= USART_CR1_PS; + + port->status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS); + if (cflag & CRTSCTS) { + port->status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS; + cr3 |= USART_CR3_CTSE; + } + + usartdiv = DIV_ROUND_CLOSEST(port->uartclk, baud); + + /* + * The USART supports 16 or 8 times oversampling. + * By default we prefer 16 times oversampling, so that the receiver + * has a better tolerance to clock deviations. + * 8 times oversampling is only used to achieve higher speeds. + */ + if (usartdiv < 16) { + oversampling = 8; + stm32_set_bits(port, USART_CR1, USART_CR1_OVER8); + } else { + oversampling = 16; + stm32_clr_bits(port, USART_CR1, USART_CR1_OVER8); + } + + mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT; + fraction = usartdiv % oversampling; + writel_relaxed(mantissa | fraction, port->membase + USART_BRR); + + uart_update_timeout(port, cflag, baud); + + port->read_status_mask = USART_SR_ORE; + if (termios->c_iflag & INPCK) + port->read_status_mask |= USART_SR_PE | USART_SR_FE; + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) + port->read_status_mask |= USART_SR_LBD; + + /* Characters to ignore */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask = USART_SR_PE | USART_SR_FE; + if (termios->c_iflag & IGNBRK) { + port->ignore_status_mask |= USART_SR_LBD; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= USART_SR_ORE; + } + + /* Ignore all characters if CREAD is not set */ + if ((termios->c_cflag & CREAD) == 0) + port->ignore_status_mask |= USART_SR_DUMMY_RX; + + writel_relaxed(cr3, port->membase + USART_CR3); + writel_relaxed(cr2, port->membase + USART_CR2); + writel_relaxed(cr1, port->membase + USART_CR1); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *stm32_type(struct uart_port *port) +{ + return (port->type == PORT_STM32) ? DRIVER_NAME : NULL; +} + +static void stm32_release_port(struct uart_port *port) +{ +} + +static int stm32_request_port(struct uart_port *port) +{ + return 0; +} + +static void stm32_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) + port->type = PORT_STM32; +} + +static int +stm32_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + /* No user changeable parameters */ + return -EINVAL; +} + +static void stm32_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) +{ + struct stm32_port *stm32port = container_of(port, + struct stm32_port, port); + unsigned long flags = 0; + + switch (state) { + case UART_PM_STATE_ON: + clk_prepare_enable(stm32port->clk); + break; + case UART_PM_STATE_OFF: + spin_lock_irqsave(&port->lock, flags); + stm32_clr_bits(port, USART_CR1, USART_CR1_UE); + spin_unlock_irqrestore(&port->lock, flags); + clk_disable_unprepare(stm32port->clk); + break; + } +} + +static const struct uart_ops stm32_uart_ops = { + .tx_empty = stm32_tx_empty, + .set_mctrl = stm32_set_mctrl, + .get_mctrl = stm32_get_mctrl, + .stop_tx = stm32_stop_tx, + .start_tx = stm32_start_tx, + .throttle = stm32_throttle, + .unthrottle = stm32_unthrottle, + .stop_rx = stm32_stop_rx, + .break_ctl = stm32_break_ctl, + .startup = stm32_startup, + .shutdown = stm32_shutdown, + .set_termios = stm32_set_termios, + .pm = stm32_pm, + .type = stm32_type, + .release_port = stm32_release_port, + .request_port = stm32_request_port, + .config_port = stm32_config_port, + .verify_port = stm32_verify_port, +}; + +static int stm32_init_port(struct stm32_port *stm32port, + struct platform_device *pdev) +{ + struct uart_port *port = &stm32port->port; + struct resource *res; + int ret; + + port->iotype = UPIO_MEM; + port->flags = UPF_BOOT_AUTOCONF; + port->ops = &stm32_uart_ops; + port->dev = &pdev->dev; + port->irq = platform_get_irq(pdev, 0); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + port->membase = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(port->membase)) + return PTR_ERR(port->membase); + port->mapbase = res->start; + + spin_lock_init(&port->lock); + + stm32port->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(stm32port->clk)) + return PTR_ERR(stm32port->clk); + + /* Ensure that clk rate is correct by enabling the clk */ + ret = clk_prepare_enable(stm32port->clk); + if (ret) + return ret; + + stm32port->port.uartclk = clk_get_rate(stm32port->clk); + if (!stm32port->port.uartclk) + ret = -EINVAL; + + clk_disable_unprepare(stm32port->clk); + + return ret; +} + +static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + int id; + + if (!np) + return NULL; + + id = of_alias_get_id(np, "serial"); + if (id < 0) + id = 0; + + if (WARN_ON(id >= STM32_MAX_PORTS)) + return NULL; + + stm32_ports[id].hw_flow_control = of_property_read_bool(np, + "auto-flow-control"); + stm32_ports[id].port.line = id; + return &stm32_ports[id]; +} + +#ifdef CONFIG_OF +static const struct of_device_id stm32_match[] = { + { .compatible = "st,stm32-usart", }, + { .compatible = "st,stm32-uart", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, stm32_match); +#endif + +static int stm32_serial_probe(struct platform_device *pdev) +{ + int ret; + struct stm32_port *stm32port; + + stm32port = stm32_of_get_stm32_port(pdev); + if (!stm32port) + return -ENODEV; + + ret = stm32_init_port(stm32port, pdev); + if (ret) + return ret; + + ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port); + if (ret) + return ret; + + platform_set_drvdata(pdev, &stm32port->port); + + return 0; +} + +static int stm32_serial_remove(struct platform_device *pdev) +{ + struct uart_port *port = platform_get_drvdata(pdev); + + return uart_remove_one_port(&stm32_usart_driver, port); +} + + +#ifdef CONFIG_SERIAL_STM32_CONSOLE +static void stm32_console_putchar(struct uart_port *port, int ch) +{ + while (!(readl_relaxed(port->membase + USART_SR) & USART_SR_TXE)) + cpu_relax(); + + writel_relaxed(ch, port->membase + USART_DR); +} + +static void stm32_console_write(struct console *co, const char *s, unsigned cnt) +{ + struct uart_port *port = &stm32_ports[co->index].port; + unsigned long flags; + u32 old_cr1, new_cr1; + int locked = 1; + + local_irq_save(flags); + if (port->sysrq) + locked = 0; + else if (oops_in_progress) + locked = spin_trylock(&port->lock); + else + spin_lock(&port->lock); + + /* Save and disable interrupts */ + old_cr1 = readl_relaxed(port->membase + USART_CR1); + new_cr1 = old_cr1 & ~USART_CR1_IE_MASK; + writel_relaxed(new_cr1, port->membase + USART_CR1); + + uart_console_write(port, s, cnt, stm32_console_putchar); + + /* Restore interrupt state */ + writel_relaxed(old_cr1, port->membase + USART_CR1); + + if (locked) + spin_unlock(&port->lock); + local_irq_restore(flags); +} + +static int stm32_console_setup(struct console *co, char *options) +{ + struct stm32_port *stm32port; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (co->index >= STM32_MAX_PORTS) + return -ENODEV; + + stm32port = &stm32_ports[co->index]; + + /* + * This driver does not support early console initialization + * (use ARM early printk support instead), so we only expect + * this to be called during the uart port registration when the + * driver gets probed and the port should be mapped at that point. + */ + if (stm32port->port.mapbase == 0 || stm32port->port.membase == NULL) + return -ENXIO; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(&stm32port->port, co, baud, parity, bits, flow); +} + +static struct console stm32_console = { + .name = STM32_SERIAL_NAME, + .device = uart_console_device, + .write = stm32_console_write, + .setup = stm32_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &stm32_usart_driver, +}; + +#define STM32_SERIAL_CONSOLE (&stm32_console) + +#else +#define STM32_SERIAL_CONSOLE NULL +#endif /* CONFIG_SERIAL_STM32_CONSOLE */ + +static struct uart_driver stm32_usart_driver = { + .driver_name = DRIVER_NAME, + .dev_name = STM32_SERIAL_NAME, + .major = 0, + .minor = 0, + .nr = STM32_MAX_PORTS, + .cons = STM32_SERIAL_CONSOLE, +}; + +static struct platform_driver stm32_serial_driver = { + .probe = stm32_serial_probe, + .remove = stm32_serial_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = of_match_ptr(stm32_match), + }, +}; + +static int __init usart_init(void) +{ + static char banner[] __initdata = "STM32 USART driver initialized"; + int ret; + + pr_info("%s\n", banner); + + ret = uart_register_driver(&stm32_usart_driver); + if (ret) + return ret; + + ret = platform_driver_register(&stm32_serial_driver); + if (ret) + uart_unregister_driver(&stm32_usart_driver); + + return ret; +} + +static void __exit usart_exit(void) +{ + platform_driver_unregister(&stm32_serial_driver); + uart_unregister_driver(&stm32_usart_driver); +} + +module_init(usart_init); +module_exit(usart_exit); + +MODULE_ALIAS("platform:" DRIVER_NAME); +MODULE_DESCRIPTION("STMicroelectronics STM32 serial port driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c index 189f52e3111f..b1c6bd3d483f 100644 --- a/drivers/tty/serial/uartlite.c +++ b/drivers/tty/serial/uartlite.c @@ -622,7 +622,7 @@ static int ulite_release(struct device *dev) #if defined(CONFIG_OF) /* Match table for of_platform binding */ -static struct of_device_id ulite_of_match[] = { +static const struct of_device_id ulite_of_match[] = { { .compatible = "xlnx,opb-uartlite-1.00.b", }, { .compatible = "xlnx,xps-uartlite-1.00.a", }, {} @@ -632,7 +632,8 @@ MODULE_DEVICE_TABLE(of, ulite_of_match); static int ulite_probe(struct platform_device *pdev) { - struct resource *res, *res2; + struct resource *res; + int irq; int id = pdev->id; #ifdef CONFIG_OF const __be32 *prop; @@ -646,11 +647,11 @@ static int ulite_probe(struct platform_device *pdev) if (!res) return -ENODEV; - res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res2) - return -ENODEV; + irq = platform_get_irq(pdev, 0); + if (irq <= 0) + return -ENXIO; - return ulite_assign(&pdev->dev, id, res->start, res2->start); + return ulite_assign(&pdev->dev, id, res->start, irq); } static int ulite_remove(struct platform_device *pdev) diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c index 14d10fcfd210..7d2532b23969 100644 --- a/drivers/tty/serial/ucc_uart.c +++ b/drivers/tty/serial/ucc_uart.c @@ -1473,7 +1473,7 @@ static int ucc_uart_remove(struct platform_device *ofdev) return 0; } -static struct of_device_id ucc_uart_match[] = { +static const struct of_device_id ucc_uart_match[] = { { .type = "serial", .compatible = "ucc_uart", diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index cff531a51a78..009e0dbc12d2 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -37,10 +37,7 @@ #define CDNS_UART_MINOR 0 /* works best with devtmpfs */ #define CDNS_UART_NR_PORTS 2 #define CDNS_UART_FIFO_SIZE 64 /* FIFO size */ -#define CDNS_UART_REGISTER_SPACE 0xFFF - -#define cdns_uart_readl(offset) ioread32(port->membase + offset) -#define cdns_uart_writel(val, offset) iowrite32(val, port->membase + offset) +#define CDNS_UART_REGISTER_SPACE 0x1000 /* Rx Trigger level */ static int rx_trigger_level = 56; @@ -195,7 +192,7 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id) /* Read the interrupt status register to determine which * interrupt(s) is/are active. */ - isrstatus = cdns_uart_readl(CDNS_UART_ISR_OFFSET); + isrstatus = readl(port->membase + CDNS_UART_ISR_OFFSET); /* * There is no hardware break detection, so we interpret framing @@ -203,14 +200,15 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id) * there's another non-zero byte at the end of the sequence. */ if (isrstatus & CDNS_UART_IXR_FRAMING) { - while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) & + while (!(readl(port->membase + CDNS_UART_SR_OFFSET) & CDNS_UART_SR_RXEMPTY)) { - if (!cdns_uart_readl(CDNS_UART_FIFO_OFFSET)) { + if (!readl(port->membase + CDNS_UART_FIFO_OFFSET)) { port->read_status_mask |= CDNS_UART_IXR_BRK; isrstatus &= ~CDNS_UART_IXR_FRAMING; } } - cdns_uart_writel(CDNS_UART_IXR_FRAMING, CDNS_UART_ISR_OFFSET); + writel(CDNS_UART_IXR_FRAMING, + port->membase + CDNS_UART_ISR_OFFSET); } /* drop byte with parity error if IGNPAR specified */ @@ -223,9 +221,9 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id) if ((isrstatus & CDNS_UART_IXR_TOUT) || (isrstatus & CDNS_UART_IXR_RXTRIG)) { /* Receive Timeout Interrupt */ - while ((cdns_uart_readl(CDNS_UART_SR_OFFSET) & - CDNS_UART_SR_RXEMPTY) != CDNS_UART_SR_RXEMPTY) { - data = cdns_uart_readl(CDNS_UART_FIFO_OFFSET); + while (!(readl(port->membase + CDNS_UART_SR_OFFSET) & + CDNS_UART_SR_RXEMPTY)) { + data = readl(port->membase + CDNS_UART_FIFO_OFFSET); /* Non-NULL byte after BREAK is garbage (99%) */ if (data && (port->read_status_mask & @@ -275,8 +273,8 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id) /* Dispatch an appropriate handler */ if ((isrstatus & CDNS_UART_IXR_TXEMPTY) == CDNS_UART_IXR_TXEMPTY) { if (uart_circ_empty(&port->state->xmit)) { - cdns_uart_writel(CDNS_UART_IXR_TXEMPTY, - CDNS_UART_IDR_OFFSET); + writel(CDNS_UART_IXR_TXEMPTY, + port->membase + CDNS_UART_IDR_OFFSET); } else { numbytes = port->fifosize; /* Break if no more data available in the UART buffer */ @@ -287,9 +285,9 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id) * and write it to the cdns_uart's TX_FIFO * register. */ - cdns_uart_writel( - port->state->xmit.buf[port->state->xmit. - tail], CDNS_UART_FIFO_OFFSET); + writel(port->state->xmit.buf[ + port->state->xmit.tail], + port->membase + CDNS_UART_FIFO_OFFSET); port->icount.tx++; @@ -307,7 +305,7 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id) } } - cdns_uart_writel(isrstatus, CDNS_UART_ISR_OFFSET); + writel(isrstatus, port->membase + CDNS_UART_ISR_OFFSET); /* be sure to release the lock and tty before leaving */ spin_unlock_irqrestore(&port->lock, flags); @@ -397,14 +395,14 @@ static unsigned int cdns_uart_set_baud_rate(struct uart_port *port, &div8); /* Write new divisors to hardware */ - mreg = cdns_uart_readl(CDNS_UART_MR_OFFSET); + mreg = readl(port->membase + CDNS_UART_MR_OFFSET); if (div8) mreg |= CDNS_UART_MR_CLKSEL; else mreg &= ~CDNS_UART_MR_CLKSEL; - cdns_uart_writel(mreg, CDNS_UART_MR_OFFSET); - cdns_uart_writel(cd, CDNS_UART_BAUDGEN_OFFSET); - cdns_uart_writel(bdiv, CDNS_UART_BAUDDIV_OFFSET); + writel(mreg, port->membase + CDNS_UART_MR_OFFSET); + writel(cd, port->membase + CDNS_UART_BAUDGEN_OFFSET); + writel(bdiv, port->membase + CDNS_UART_BAUDDIV_OFFSET); cdns_uart->baud = baud; return calc_baud; @@ -451,9 +449,9 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb, spin_lock_irqsave(&cdns_uart->port->lock, flags); /* Disable the TX and RX to set baud rate */ - ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); + ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET); ctrl_reg |= CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS; - cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); + writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET); spin_unlock_irqrestore(&cdns_uart->port->lock, flags); @@ -478,11 +476,11 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb, spin_lock_irqsave(&cdns_uart->port->lock, flags); /* Set TX/RX Reset */ - ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); + ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET); ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST; - cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); + writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET); - while (cdns_uart_readl(CDNS_UART_CR_OFFSET) & + while (readl(port->membase + CDNS_UART_CR_OFFSET) & (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST)) cpu_relax(); @@ -491,11 +489,11 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb, * enable bit and RX enable bit to enable the transmitter and * receiver. */ - cdns_uart_writel(rx_timeout, CDNS_UART_RXTOUT_OFFSET); - ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); + writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET); + ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET); ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS); ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN; - cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); + writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET); spin_unlock_irqrestore(&cdns_uart->port->lock, flags); @@ -517,14 +515,14 @@ static void cdns_uart_start_tx(struct uart_port *port) if (uart_circ_empty(&port->state->xmit) || uart_tx_stopped(port)) return; - status = cdns_uart_readl(CDNS_UART_CR_OFFSET); + status = readl(port->membase + CDNS_UART_CR_OFFSET); /* Set the TX enable bit and clear the TX disable bit to enable the * transmitter. */ - cdns_uart_writel((status & ~CDNS_UART_CR_TX_DIS) | CDNS_UART_CR_TX_EN, - CDNS_UART_CR_OFFSET); + writel((status & ~CDNS_UART_CR_TX_DIS) | CDNS_UART_CR_TX_EN, + port->membase + CDNS_UART_CR_OFFSET); - while (numbytes-- && ((cdns_uart_readl(CDNS_UART_SR_OFFSET) & + while (numbytes-- && ((readl(port->membase + CDNS_UART_SR_OFFSET) & CDNS_UART_SR_TXFULL)) != CDNS_UART_SR_TXFULL) { /* Break if no more data available in the UART buffer */ if (uart_circ_empty(&port->state->xmit)) @@ -533,9 +531,8 @@ static void cdns_uart_start_tx(struct uart_port *port) /* Get the data from the UART circular buffer and * write it to the cdns_uart's TX_FIFO register. */ - cdns_uart_writel( - port->state->xmit.buf[port->state->xmit.tail], - CDNS_UART_FIFO_OFFSET); + writel(port->state->xmit.buf[port->state->xmit.tail], + port->membase + CDNS_UART_FIFO_OFFSET); port->icount.tx++; /* Adjust the tail of the UART buffer and wrap @@ -544,9 +541,9 @@ static void cdns_uart_start_tx(struct uart_port *port) port->state->xmit.tail = (port->state->xmit.tail + 1) & (UART_XMIT_SIZE - 1); } - cdns_uart_writel(CDNS_UART_IXR_TXEMPTY, CDNS_UART_ISR_OFFSET); + writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_ISR_OFFSET); /* Enable the TX Empty interrupt */ - cdns_uart_writel(CDNS_UART_IXR_TXEMPTY, CDNS_UART_IER_OFFSET); + writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IER_OFFSET); if (uart_circ_chars_pending(&port->state->xmit) < WAKEUP_CHARS) uart_write_wakeup(port); @@ -560,10 +557,10 @@ static void cdns_uart_stop_tx(struct uart_port *port) { unsigned int regval; - regval = cdns_uart_readl(CDNS_UART_CR_OFFSET); + regval = readl(port->membase + CDNS_UART_CR_OFFSET); regval |= CDNS_UART_CR_TX_DIS; /* Disable the transmitter */ - cdns_uart_writel(regval, CDNS_UART_CR_OFFSET); + writel(regval, port->membase + CDNS_UART_CR_OFFSET); } /** @@ -574,10 +571,10 @@ static void cdns_uart_stop_rx(struct uart_port *port) { unsigned int regval; - regval = cdns_uart_readl(CDNS_UART_CR_OFFSET); + regval = readl(port->membase + CDNS_UART_CR_OFFSET); regval |= CDNS_UART_CR_RX_DIS; /* Disable the receiver */ - cdns_uart_writel(regval, CDNS_UART_CR_OFFSET); + writel(regval, port->membase + CDNS_UART_CR_OFFSET); } /** @@ -590,7 +587,8 @@ static unsigned int cdns_uart_tx_empty(struct uart_port *port) { unsigned int status; - status = cdns_uart_readl(CDNS_UART_SR_OFFSET) & CDNS_UART_SR_TXEMPTY; + status = readl(port->membase + CDNS_UART_SR_OFFSET) & + CDNS_UART_SR_TXEMPTY; return status ? TIOCSER_TEMT : 0; } @@ -607,15 +605,15 @@ static void cdns_uart_break_ctl(struct uart_port *port, int ctl) spin_lock_irqsave(&port->lock, flags); - status = cdns_uart_readl(CDNS_UART_CR_OFFSET); + status = readl(port->membase + CDNS_UART_CR_OFFSET); if (ctl == -1) - cdns_uart_writel(CDNS_UART_CR_STARTBRK | status, - CDNS_UART_CR_OFFSET); + writel(CDNS_UART_CR_STARTBRK | status, + port->membase + CDNS_UART_CR_OFFSET); else { if ((status & CDNS_UART_CR_STOPBRK) == 0) - cdns_uart_writel(CDNS_UART_CR_STOPBRK | status, - CDNS_UART_CR_OFFSET); + writel(CDNS_UART_CR_STOPBRK | status, + port->membase + CDNS_UART_CR_OFFSET); } spin_unlock_irqrestore(&port->lock, flags); } @@ -638,17 +636,18 @@ static void cdns_uart_set_termios(struct uart_port *port, spin_lock_irqsave(&port->lock, flags); /* Wait for the transmit FIFO to empty before making changes */ - if (!(cdns_uart_readl(CDNS_UART_CR_OFFSET) & CDNS_UART_CR_TX_DIS)) { - while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) & + if (!(readl(port->membase + CDNS_UART_CR_OFFSET) & + CDNS_UART_CR_TX_DIS)) { + while (!(readl(port->membase + CDNS_UART_SR_OFFSET) & CDNS_UART_SR_TXEMPTY)) { cpu_relax(); } } /* Disable the TX and RX to set baud rate */ - ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); + ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET); ctrl_reg |= CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS; - cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); + writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET); /* * Min baud rate = 6bps and Max Baud Rate is 10Mbps for 100Mhz clk @@ -667,20 +666,20 @@ static void cdns_uart_set_termios(struct uart_port *port, uart_update_timeout(port, termios->c_cflag, baud); /* Set TX/RX Reset */ - ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); + ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET); ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST; - cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); + writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET); /* * Clear the RX disable and TX disable bits and then set the TX enable * bit and RX enable bit to enable the transmitter and receiver. */ - ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); + ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET); ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS); ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN; - cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); + writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET); - cdns_uart_writel(rx_timeout, CDNS_UART_RXTOUT_OFFSET); + writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET); port->read_status_mask = CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_RXTRIG | CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_TOUT; @@ -700,7 +699,7 @@ static void cdns_uart_set_termios(struct uart_port *port, CDNS_UART_IXR_TOUT | CDNS_UART_IXR_PARITY | CDNS_UART_IXR_FRAMING | CDNS_UART_IXR_OVERRUN; - mode_reg = cdns_uart_readl(CDNS_UART_MR_OFFSET); + mode_reg = readl(port->membase + CDNS_UART_MR_OFFSET); /* Handling Data Size */ switch (termios->c_cflag & CSIZE) { @@ -741,7 +740,7 @@ static void cdns_uart_set_termios(struct uart_port *port, cval |= CDNS_UART_MR_PARITY_NONE; } cval |= mode_reg & 1; - cdns_uart_writel(cval, CDNS_UART_MR_OFFSET); + writel(cval, port->membase + CDNS_UART_MR_OFFSET); spin_unlock_irqrestore(&port->lock, flags); } @@ -762,52 +761,53 @@ static int cdns_uart_startup(struct uart_port *port) return retval; /* Disable the TX and RX */ - cdns_uart_writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS, - CDNS_UART_CR_OFFSET); + writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS, + port->membase + CDNS_UART_CR_OFFSET); /* Set the Control Register with TX/RX Enable, TX/RX Reset, * no break chars. */ - cdns_uart_writel(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST, - CDNS_UART_CR_OFFSET); + writel(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST, + port->membase + CDNS_UART_CR_OFFSET); - status = cdns_uart_readl(CDNS_UART_CR_OFFSET); + status = readl(port->membase + CDNS_UART_CR_OFFSET); /* Clear the RX disable and TX disable bits and then set the TX enable * bit and RX enable bit to enable the transmitter and receiver. */ - cdns_uart_writel((status & ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS)) + writel((status & ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS)) | (CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN | - CDNS_UART_CR_STOPBRK), CDNS_UART_CR_OFFSET); + CDNS_UART_CR_STOPBRK), + port->membase + CDNS_UART_CR_OFFSET); /* Set the Mode Register with normal mode,8 data bits,1 stop bit, * no parity. */ - cdns_uart_writel(CDNS_UART_MR_CHMODE_NORM | CDNS_UART_MR_STOPMODE_1_BIT + writel(CDNS_UART_MR_CHMODE_NORM | CDNS_UART_MR_STOPMODE_1_BIT | CDNS_UART_MR_PARITY_NONE | CDNS_UART_MR_CHARLEN_8_BIT, - CDNS_UART_MR_OFFSET); + port->membase + CDNS_UART_MR_OFFSET); /* * Set the RX FIFO Trigger level to use most of the FIFO, but it * can be tuned with a module parameter */ - cdns_uart_writel(rx_trigger_level, CDNS_UART_RXWM_OFFSET); + writel(rx_trigger_level, port->membase + CDNS_UART_RXWM_OFFSET); /* * Receive Timeout register is enabled but it * can be tuned with a module parameter */ - cdns_uart_writel(rx_timeout, CDNS_UART_RXTOUT_OFFSET); + writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET); /* Clear out any pending interrupts before enabling them */ - cdns_uart_writel(cdns_uart_readl(CDNS_UART_ISR_OFFSET), - CDNS_UART_ISR_OFFSET); + writel(readl(port->membase + CDNS_UART_ISR_OFFSET), + port->membase + CDNS_UART_ISR_OFFSET); /* Set the Interrupt Registers with desired interrupts */ - cdns_uart_writel(CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_PARITY | + writel(CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_PARITY | CDNS_UART_IXR_FRAMING | CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_RXTRIG | CDNS_UART_IXR_TOUT, - CDNS_UART_IER_OFFSET); + port->membase + CDNS_UART_IER_OFFSET); return retval; } @@ -821,12 +821,12 @@ static void cdns_uart_shutdown(struct uart_port *port) int status; /* Disable interrupts */ - status = cdns_uart_readl(CDNS_UART_IMR_OFFSET); - cdns_uart_writel(status, CDNS_UART_IDR_OFFSET); + status = readl(port->membase + CDNS_UART_IMR_OFFSET); + writel(status, port->membase + CDNS_UART_IDR_OFFSET); /* Disable the TX and RX */ - cdns_uart_writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS, - CDNS_UART_CR_OFFSET); + writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS, + port->membase + CDNS_UART_CR_OFFSET); free_irq(port->irq, port); } @@ -928,7 +928,7 @@ static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) { u32 val; - val = cdns_uart_readl(CDNS_UART_MODEMCR_OFFSET); + val = readl(port->membase + CDNS_UART_MODEMCR_OFFSET); val &= ~(CDNS_UART_MODEMCR_RTS | CDNS_UART_MODEMCR_DTR); @@ -937,7 +937,7 @@ static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) if (mctrl & TIOCM_DTR) val |= CDNS_UART_MODEMCR_DTR; - cdns_uart_writel(val, CDNS_UART_MODEMCR_OFFSET); + writel(val, port->membase + CDNS_UART_MODEMCR_OFFSET); } #ifdef CONFIG_CONSOLE_POLL @@ -947,17 +947,18 @@ static int cdns_uart_poll_get_char(struct uart_port *port) int c; /* Disable all interrupts */ - imr = cdns_uart_readl(CDNS_UART_IMR_OFFSET); - cdns_uart_writel(imr, CDNS_UART_IDR_OFFSET); + imr = readl(port->membase + CDNS_UART_IMR_OFFSET); + writel(imr, port->membase + CDNS_UART_IDR_OFFSET); /* Check if FIFO is empty */ - if (cdns_uart_readl(CDNS_UART_SR_OFFSET) & CDNS_UART_SR_RXEMPTY) + if (readl(port->membase + CDNS_UART_SR_OFFSET) & CDNS_UART_SR_RXEMPTY) c = NO_POLL_CHAR; else /* Read a character */ - c = (unsigned char) cdns_uart_readl(CDNS_UART_FIFO_OFFSET); + c = (unsigned char) readl( + port->membase + CDNS_UART_FIFO_OFFSET); /* Enable interrupts */ - cdns_uart_writel(imr, CDNS_UART_IER_OFFSET); + writel(imr, port->membase + CDNS_UART_IER_OFFSET); return c; } @@ -967,22 +968,24 @@ static void cdns_uart_poll_put_char(struct uart_port *port, unsigned char c) u32 imr; /* Disable all interrupts */ - imr = cdns_uart_readl(CDNS_UART_IMR_OFFSET); - cdns_uart_writel(imr, CDNS_UART_IDR_OFFSET); + imr = readl(port->membase + CDNS_UART_IMR_OFFSET); + writel(imr, port->membase + CDNS_UART_IDR_OFFSET); /* Wait until FIFO is empty */ - while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) & CDNS_UART_SR_TXEMPTY)) + while (!(readl(port->membase + CDNS_UART_SR_OFFSET) & + CDNS_UART_SR_TXEMPTY)) cpu_relax(); /* Write a character */ - cdns_uart_writel(c, CDNS_UART_FIFO_OFFSET); + writel(c, port->membase + CDNS_UART_FIFO_OFFSET); /* Wait until FIFO is empty */ - while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) & CDNS_UART_SR_TXEMPTY)) + while (!(readl(port->membase + CDNS_UART_SR_OFFSET) & + CDNS_UART_SR_TXEMPTY)) cpu_relax(); /* Enable interrupts */ - cdns_uart_writel(imr, CDNS_UART_IER_OFFSET); + writel(imr, port->membase + CDNS_UART_IER_OFFSET); return; } @@ -1010,7 +1013,7 @@ static struct uart_ops cdns_uart_ops = { #endif }; -static struct uart_port cdns_uart_port[2]; +static struct uart_port cdns_uart_port[CDNS_UART_NR_PORTS]; /** * cdns_uart_get_port - Configure the port from platform device resource info @@ -1038,7 +1041,6 @@ static struct uart_port *cdns_uart_get_port(int id) /* At this point, we've got an empty uart_port struct, initialize it */ spin_lock_init(&port->lock); port->membase = NULL; - port->iobase = 1; /* mark port in use */ port->irq = 0; port->type = PORT_UNKNOWN; port->iotype = UPIO_MEM32; @@ -1057,8 +1059,8 @@ static struct uart_port *cdns_uart_get_port(int id) */ static void cdns_uart_console_wait_tx(struct uart_port *port) { - while ((cdns_uart_readl(CDNS_UART_SR_OFFSET) & CDNS_UART_SR_TXEMPTY) - != CDNS_UART_SR_TXEMPTY) + while (!(readl(port->membase + CDNS_UART_SR_OFFSET) & + CDNS_UART_SR_TXEMPTY)) barrier(); } @@ -1070,10 +1072,11 @@ static void cdns_uart_console_wait_tx(struct uart_port *port) static void cdns_uart_console_putchar(struct uart_port *port, int ch) { cdns_uart_console_wait_tx(port); - cdns_uart_writel(ch, CDNS_UART_FIFO_OFFSET); + writel(ch, port->membase + CDNS_UART_FIFO_OFFSET); } -static void cdns_early_write(struct console *con, const char *s, unsigned n) +static void __init cdns_early_write(struct console *con, const char *s, + unsigned n) { struct earlycon_device *dev = con->data; @@ -1112,24 +1115,24 @@ static void cdns_uart_console_write(struct console *co, const char *s, spin_lock_irqsave(&port->lock, flags); /* save and disable interrupt */ - imr = cdns_uart_readl(CDNS_UART_IMR_OFFSET); - cdns_uart_writel(imr, CDNS_UART_IDR_OFFSET); + imr = readl(port->membase + CDNS_UART_IMR_OFFSET); + writel(imr, port->membase + CDNS_UART_IDR_OFFSET); /* * Make sure that the tx part is enabled. Set the TX enable bit and * clear the TX disable bit to enable the transmitter. */ - ctrl = cdns_uart_readl(CDNS_UART_CR_OFFSET); - cdns_uart_writel((ctrl & ~CDNS_UART_CR_TX_DIS) | CDNS_UART_CR_TX_EN, - CDNS_UART_CR_OFFSET); + ctrl = readl(port->membase + CDNS_UART_CR_OFFSET); + writel((ctrl & ~CDNS_UART_CR_TX_DIS) | CDNS_UART_CR_TX_EN, + port->membase + CDNS_UART_CR_OFFSET); uart_console_write(port, s, count, cdns_uart_console_putchar); cdns_uart_console_wait_tx(port); - cdns_uart_writel(ctrl, CDNS_UART_CR_OFFSET); + writel(ctrl, port->membase + CDNS_UART_CR_OFFSET); /* restore interrupt state */ - cdns_uart_writel(imr, CDNS_UART_IER_OFFSET); + writel(imr, port->membase + CDNS_UART_IER_OFFSET); if (locked) spin_unlock_irqrestore(&port->lock, flags); @@ -1153,8 +1156,9 @@ static int __init cdns_uart_console_setup(struct console *co, char *options) if (co->index < 0 || co->index >= CDNS_UART_NR_PORTS) return -EINVAL; - if (!port->mapbase) { - pr_debug("console on ttyPS%i not present\n", co->index); + if (!port->membase) { + pr_debug("console on " CDNS_UART_TTY_NAME "%i not present\n", + co->index); return -ENODEV; } @@ -1240,13 +1244,14 @@ static int cdns_uart_suspend(struct device *device) spin_lock_irqsave(&port->lock, flags); /* Empty the receive FIFO 1st before making changes */ - while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) & + while (!(readl(port->membase + CDNS_UART_SR_OFFSET) & CDNS_UART_SR_RXEMPTY)) - cdns_uart_readl(CDNS_UART_FIFO_OFFSET); + readl(port->membase + CDNS_UART_FIFO_OFFSET); /* set RX trigger level to 1 */ - cdns_uart_writel(1, CDNS_UART_RXWM_OFFSET); + writel(1, port->membase + CDNS_UART_RXWM_OFFSET); /* disable RX timeout interrups */ - cdns_uart_writel(CDNS_UART_IXR_TOUT, CDNS_UART_IDR_OFFSET); + writel(CDNS_UART_IXR_TOUT, + port->membase + CDNS_UART_IDR_OFFSET); spin_unlock_irqrestore(&port->lock, flags); } @@ -1285,28 +1290,30 @@ static int cdns_uart_resume(struct device *device) spin_lock_irqsave(&port->lock, flags); /* Set TX/RX Reset */ - ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); + ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET); ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST; - cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); - while (cdns_uart_readl(CDNS_UART_CR_OFFSET) & + writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET); + while (readl(port->membase + CDNS_UART_CR_OFFSET) & (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST)) cpu_relax(); /* restore rx timeout value */ - cdns_uart_writel(rx_timeout, CDNS_UART_RXTOUT_OFFSET); + writel(rx_timeout, port->membase + CDNS_UART_RXTOUT_OFFSET); /* Enable Tx/Rx */ - ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); + ctrl_reg = readl(port->membase + CDNS_UART_CR_OFFSET); ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS); ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN; - cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); + writel(ctrl_reg, port->membase + CDNS_UART_CR_OFFSET); spin_unlock_irqrestore(&port->lock, flags); } else { spin_lock_irqsave(&port->lock, flags); /* restore original rx trigger level */ - cdns_uart_writel(rx_trigger_level, CDNS_UART_RXWM_OFFSET); + writel(rx_trigger_level, + port->membase + CDNS_UART_RXWM_OFFSET); /* enable RX timeout interrupt */ - cdns_uart_writel(CDNS_UART_IXR_TOUT, CDNS_UART_IER_OFFSET); + writel(CDNS_UART_IXR_TOUT, + port->membase + CDNS_UART_IER_OFFSET); spin_unlock_irqrestore(&port->lock, flags); } @@ -1325,9 +1332,9 @@ static SIMPLE_DEV_PM_OPS(cdns_uart_dev_pm_ops, cdns_uart_suspend, */ static int cdns_uart_probe(struct platform_device *pdev) { - int rc, id; + int rc, id, irq; struct uart_port *port; - struct resource *res, *res2; + struct resource *res; struct cdns_uart *cdns_uart_data; cdns_uart_data = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_data), @@ -1374,9 +1381,9 @@ static int cdns_uart_probe(struct platform_device *pdev) goto err_out_clk_disable; } - res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res2) { - rc = -ENODEV; + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + rc = -ENXIO; goto err_out_clk_disable; } @@ -1405,7 +1412,7 @@ static int cdns_uart_probe(struct platform_device *pdev) * and triggers invocation of the config_port() entry point. */ port->mapbase = res->start; - port->irq = res2->start; + port->irq = irq; port->dev = &pdev->dev; port->uartclk = clk_get_rate(cdns_uart_data->uartclk); port->private_data = cdns_uart_data; @@ -1458,7 +1465,7 @@ static int cdns_uart_remove(struct platform_device *pdev) } /* Match table for of_platform binding */ -static struct of_device_id cdns_uart_of_match[] = { +static const struct of_device_id cdns_uart_of_match[] = { { .compatible = "xlnx,xuartps", }, { .compatible = "cdns,uart-r1p8", }, {} diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index b7991707ffc0..2fac7123b274 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -4410,7 +4410,8 @@ static void synclink_cleanup(void) printk("Unloading %s: %s\n", driver_name, driver_version); if (serial_driver) { - if ((rc = tty_unregister_driver(serial_driver))) + rc = tty_unregister_driver(serial_driver); + if (rc) printk("%s(%d) failed to unregister tty driver err=%d\n", __FILE__,__LINE__,rc); put_tty_driver(serial_driver); @@ -7751,7 +7752,8 @@ static int hdlcdev_open(struct net_device *dev) printk("%s:hdlcdev_open(%s)\n",__FILE__,dev->name); /* generic HDLC layer open processing */ - if ((rc = hdlc_open(dev))) + rc = hdlc_open(dev); + if (rc) return rc; /* arbitrate between network and tty opens */ @@ -8018,7 +8020,8 @@ static int hdlcdev_init(struct mgsl_struct *info) /* allocate and initialize network and HDLC layer objects */ - if (!(dev = alloc_hdlcdev(info))) { + dev = alloc_hdlcdev(info); + if (!dev) { printk(KERN_ERR "%s:hdlc device allocation failure\n",__FILE__); return -ENOMEM; } @@ -8039,7 +8042,8 @@ static int hdlcdev_init(struct mgsl_struct *info) hdlc->xmit = hdlcdev_xmit; /* register objects with HDLC layer */ - if ((rc = register_hdlc_device(dev))) { + rc = register_hdlc_device(dev); + if (rc) { printk(KERN_WARNING "%s:unable to register hdlc device\n",__FILE__); free_netdev(dev); return rc; @@ -8075,7 +8079,8 @@ static int synclink_init_one (struct pci_dev *dev, return -EIO; } - if (!(info = mgsl_allocate_device())) { + info = mgsl_allocate_device(); + if (!info) { printk("can't allocate device instance data.\n"); return -EIO; } diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index 0e8c39b6ccd4..0ea8eee00178 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -1539,7 +1539,8 @@ static int hdlcdev_open(struct net_device *dev) DBGINFO(("%s hdlcdev_open\n", dev->name)); /* generic HDLC layer open processing */ - if ((rc = hdlc_open(dev))) + rc = hdlc_open(dev); + if (rc) return rc; /* arbitrate between network and tty opens */ @@ -1803,7 +1804,8 @@ static int hdlcdev_init(struct slgt_info *info) /* allocate and initialize network and HDLC layer objects */ - if (!(dev = alloc_hdlcdev(info))) { + dev = alloc_hdlcdev(info); + if (!dev) { printk(KERN_ERR "%s hdlc device alloc failure\n", info->device_name); return -ENOMEM; } @@ -1824,7 +1826,8 @@ static int hdlcdev_init(struct slgt_info *info) hdlc->xmit = hdlcdev_xmit; /* register objects with HDLC layer */ - if ((rc = register_hdlc_device(dev))) { + rc = register_hdlc_device(dev); + if (rc) { printk(KERN_WARNING "%s:unable to register hdlc device\n",__FILE__); free_netdev(dev); return rc; @@ -1879,7 +1882,8 @@ static void rx_async(struct slgt_info *info) stat = 0; - if ((status = *(p+1) & (BIT1 + BIT0))) { + status = *(p + 1) & (BIT1 + BIT0); + if (status) { if (status & BIT1) icount->parity++; else if (status & BIT0) @@ -3755,7 +3759,8 @@ static void slgt_cleanup(void) if (serial_driver) { for (info=slgt_device_list ; info != NULL ; info=info->next_device) tty_unregister_device(serial_driver, info->line); - if ((rc = tty_unregister_driver(serial_driver))) + rc = tty_unregister_driver(serial_driver); + if (rc) DBGERR(("tty_unregister_driver error=%d\n", rc)); put_tty_driver(serial_driver); } diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index c3f90910fed9..08633a8139ff 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -1655,7 +1655,8 @@ static int hdlcdev_open(struct net_device *dev) printk("%s:hdlcdev_open(%s)\n",__FILE__,dev->name); /* generic HDLC layer open processing */ - if ((rc = hdlc_open(dev))) + rc = hdlc_open(dev); + if (rc) return rc; /* arbitrate between network and tty opens */ @@ -1922,7 +1923,8 @@ static int hdlcdev_init(SLMP_INFO *info) /* allocate and initialize network and HDLC layer objects */ - if (!(dev = alloc_hdlcdev(info))) { + dev = alloc_hdlcdev(info); + if (!dev) { printk(KERN_ERR "%s:hdlc device allocation failure\n",__FILE__); return -ENOMEM; } @@ -1943,7 +1945,8 @@ static int hdlcdev_init(SLMP_INFO *info) hdlc->xmit = hdlcdev_xmit; /* register objects with HDLC layer */ - if ((rc = register_hdlc_device(dev))) { + rc = register_hdlc_device(dev); + if (rc) { printk(KERN_WARNING "%s:unable to register hdlc device\n",__FILE__); free_netdev(dev); return rc; @@ -3920,7 +3923,8 @@ static void synclinkmp_cleanup(void) printk("Unloading %s %s\n", driver_name, driver_version); if (serial_driver) { - if ((rc = tty_unregister_driver(serial_driver))) + rc = tty_unregister_driver(serial_driver); + if (rc) printk("%s(%d) failed to unregister tty driver err=%d\n", __FILE__,__LINE__,rc); put_tty_driver(serial_driver); diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index b21881e39d28..b5b427888b24 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -272,6 +272,7 @@ static struct sysrq_key_op sysrq_showregs_op = { static void sysrq_handle_showstate(int key) { show_state(); + show_workqueue_state(); } static struct sysrq_key_op sysrq_showstate_op = { .handler = sysrq_handle_showstate, @@ -352,9 +353,11 @@ static struct sysrq_key_op sysrq_term_op = { static void moom_callback(struct work_struct *ignored) { + mutex_lock(&oom_lock); if (!out_of_memory(node_zonelist(first_memory_node, GFP_KERNEL), GFP_KERNEL, 0, NULL, true)) pr_info("OOM request ignored because killer is disabled\n"); + mutex_unlock(&oom_lock); } static DECLARE_WORK(moom_work, moom_callback); @@ -459,6 +462,7 @@ static struct sysrq_key_op *sysrq_key_table[36] = { /* v: May be registered for frame buffer console restore */ NULL, /* v */ &sysrq_showstate_blocked_op, /* w */ + /* x: May be registered on mips for TLB dump */ /* x: May be registered on ppc/powerpc for xmon */ /* x: May be registered on sparc64 for global PMU dump */ NULL, /* x */ @@ -984,7 +988,7 @@ static int sysrq_reset_seq_param_set(const char *buffer, return 0; } -static struct kernel_param_ops param_ops_sysrq_reset_seq = { +static const struct kernel_param_ops param_ops_sysrq_reset_seq = { .get = param_get_ushort, .set = sysrq_reset_seq_param_set, }; diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 75661641f5fe..4cf263d7dffc 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -37,6 +37,28 @@ #define TTY_BUFFER_PAGE (((PAGE_SIZE - sizeof(struct tty_buffer)) / 2) & ~0xFF) +/* + * If all tty flip buffers have been processed by flush_to_ldisc() or + * dropped by tty_buffer_flush(), check if the linked pty has been closed. + * If so, wake the reader/poll to process + */ +static inline void check_other_closed(struct tty_struct *tty) +{ + unsigned long flags, old; + + /* transition from TTY_OTHER_CLOSED => TTY_OTHER_DONE must be atomic */ + for (flags = ACCESS_ONCE(tty->flags); + test_bit(TTY_OTHER_CLOSED, &flags); + ) { + old = flags; + __set_bit(TTY_OTHER_DONE, &flags); + flags = cmpxchg(&tty->flags, old, flags); + if (old == flags) { + wake_up_interruptible(&tty->read_wait); + break; + } + } +} /** * tty_buffer_lock_exclusive - gain exclusive access to buffer @@ -229,6 +251,8 @@ void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld) if (ld && ld->ops->flush_buffer) ld->ops->flush_buffer(tty); + check_other_closed(tty); + atomic_dec(&buf->priority); mutex_unlock(&buf->lock); } @@ -262,7 +286,8 @@ static int __tty_buffer_request_room(struct tty_port *port, size_t size, change = (b->flags & TTYB_NORMAL) && (~flags & TTYB_NORMAL); if (change || left < size) { /* This is the slow path - looking for new buffers to use */ - if ((n = tty_buffer_alloc(port, size)) != NULL) { + n = tty_buffer_alloc(port, size); + if (n != NULL) { n->flags = flags; buf->tail = n; b->commit = b->used; @@ -471,8 +496,10 @@ static void flush_to_ldisc(struct work_struct *work) smp_rmb(); count = head->commit - head->read; if (!count) { - if (next == NULL) + if (next == NULL) { + check_other_closed(tty); break; + } buf->head = next; tty_buffer_free(port, head); continue; @@ -489,19 +516,6 @@ static void flush_to_ldisc(struct work_struct *work) } /** - * tty_flush_to_ldisc - * @tty: tty to push - * - * Push the terminal flip buffers to the line discipline. - * - * Must not be called from IRQ context. - */ -void tty_flush_to_ldisc(struct tty_struct *tty) -{ - flush_work(&tty->port->buf.work); -} - -/** * tty_flip_buffer_push - terminal * @port: tty port to push * diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 2bb4dfc02873..57fc6ee12332 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -235,7 +235,6 @@ static void tty_del_file(struct file *file) /** * tty_name - return tty naming * @tty: tty structure - * @buf: buffer for output * * Convert a tty structure into a name. The name reflects the kernel * naming policy and if udev is in use may not reflect user space @@ -243,13 +242,11 @@ static void tty_del_file(struct file *file) * Locking: none */ -char *tty_name(struct tty_struct *tty, char *buf) +const char *tty_name(const struct tty_struct *tty) { if (!tty) /* Hmm. NULL pointer. That's fun. */ - strcpy(buf, "NULL tty"); - else - strcpy(buf, tty->name); - return buf; + return "NULL tty"; + return tty->name; } EXPORT_SYMBOL(tty_name); @@ -770,8 +767,7 @@ static void do_tty_hangup(struct work_struct *work) void tty_hangup(struct tty_struct *tty) { #ifdef TTY_DEBUG_HANGUP - char buf[64]; - printk(KERN_DEBUG "%s hangup...\n", tty_name(tty, buf)); + printk(KERN_DEBUG "%s hangup...\n", tty_name(tty)); #endif schedule_work(&tty->hangup_work); } @@ -790,9 +786,7 @@ EXPORT_SYMBOL(tty_hangup); void tty_vhangup(struct tty_struct *tty) { #ifdef TTY_DEBUG_HANGUP - char buf[64]; - - printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf)); + printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty)); #endif __tty_hangup(tty, 0); } @@ -831,9 +825,7 @@ void tty_vhangup_self(void) static void tty_vhangup_session(struct tty_struct *tty) { #ifdef TTY_DEBUG_HANGUP - char buf[64]; - - printk(KERN_DEBUG "%s vhangup session...\n", tty_name(tty, buf)); + printk(KERN_DEBUG "%s vhangup session...\n", tty_name(tty)); #endif __tty_hangup(tty, 1); } @@ -1025,11 +1017,17 @@ void start_tty(struct tty_struct *tty) } EXPORT_SYMBOL(start_tty); -/* We limit tty time update visibility to every 8 seconds or so. */ static void tty_update_time(struct timespec *time) { unsigned long sec = get_seconds(); - if (abs(sec - time->tv_sec) & ~7) + + /* + * We only care if the two values differ in anything other than the + * lower three bits (i.e every 8 seconds). If so, then we can update + * the time of the tty device, otherwise it could be construded as a + * security leak to let userspace know the exact timing of the tty. + */ + if ((sec ^ time->tv_sec) & ~7) time->tv_sec = sec; } @@ -1763,7 +1761,6 @@ int tty_release(struct inode *inode, struct file *filp) struct tty_struct *o_tty = NULL; int do_sleep, final; int idx; - char buf[64]; long timeout = 0; int once = 1; @@ -1787,7 +1784,7 @@ int tty_release(struct inode *inode, struct file *filp) #ifdef TTY_DEBUG_HANGUP printk(KERN_DEBUG "%s: %s (tty count=%d)...\n", __func__, - tty_name(tty, buf), tty->count); + tty_name(tty), tty->count); #endif if (tty->ops->close) @@ -1838,7 +1835,7 @@ int tty_release(struct inode *inode, struct file *filp) if (once) { once = 0; printk(KERN_WARNING "%s: %s: read/write wait queue active!\n", - __func__, tty_name(tty, buf)); + __func__, tty_name(tty)); } schedule_timeout_killable(timeout); if (timeout < 120 * HZ) @@ -1850,13 +1847,13 @@ int tty_release(struct inode *inode, struct file *filp) if (o_tty) { if (--o_tty->count < 0) { printk(KERN_WARNING "%s: bad pty slave count (%d) for %s\n", - __func__, o_tty->count, tty_name(o_tty, buf)); + __func__, o_tty->count, tty_name(o_tty)); o_tty->count = 0; } } if (--tty->count < 0) { printk(KERN_WARNING "%s: bad tty->count (%d) for %s\n", - __func__, tty->count, tty_name(tty, buf)); + __func__, tty->count, tty_name(tty)); tty->count = 0; } @@ -1899,7 +1896,7 @@ int tty_release(struct inode *inode, struct file *filp) return 0; #ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "%s: %s: final close\n", __func__, tty_name(tty, buf)); + printk(KERN_DEBUG "%s: %s: final close\n", __func__, tty_name(tty)); #endif /* * Ask the line discipline code to release its structures @@ -1910,7 +1907,8 @@ int tty_release(struct inode *inode, struct file *filp) tty_flush_works(tty); #ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "%s: %s: freeing structure...\n", __func__, tty_name(tty, buf)); + printk(KERN_DEBUG "%s: %s: freeing structure...\n", __func__, + tty_name(tty)); #endif /* * The release_tty function takes care of the details of clearing @@ -3593,6 +3591,13 @@ static ssize_t show_cons_active(struct device *dev, } static DEVICE_ATTR(active, S_IRUGO, show_cons_active, NULL); +static struct attribute *cons_dev_attrs[] = { + &dev_attr_active.attr, + NULL +}; + +ATTRIBUTE_GROUPS(cons_dev); + static struct device *consdev; void console_sysfs_notify(void) @@ -3617,12 +3622,11 @@ int __init tty_init(void) if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0) panic("Couldn't register /dev/console driver\n"); - consdev = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL, - "console"); + consdev = device_create_with_groups(tty_class, NULL, + MKDEV(TTYAUX_MAJOR, 1), NULL, + cons_dev_groups, "console"); if (IS_ERR(consdev)) consdev = NULL; - else - WARN_ON(device_create_file(consdev, &dev_attr_active) < 0); #ifdef CONFIG_VT vty_init(&console_fops); diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index 632fc8152061..5232fb60b0b1 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -211,9 +211,7 @@ int tty_unthrottle_safe(struct tty_struct *tty) void tty_wait_until_sent(struct tty_struct *tty, long timeout) { #ifdef TTY_DEBUG_WAIT_UNTIL_SENT - char buf[64]; - - printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty, buf)); + printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty)); #endif if (!timeout) timeout = MAX_SCHEDULE_TIMEOUT; @@ -536,7 +534,7 @@ EXPORT_SYMBOL(tty_termios_hw_change); * Locking: termios_rwsem */ -static int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios) +int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios) { struct ktermios old_termios; struct tty_ldisc *ld; @@ -569,6 +567,7 @@ static int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios) up_write(&tty->termios_rwsem); return 0; } +EXPORT_SYMBOL_GPL(tty_set_termios); /** * set_termios - set termios values for a tty diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 3737f55272d2..c07fb5d9bcf9 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -22,9 +22,8 @@ #undef LDISC_DEBUG_HANGUP #ifdef LDISC_DEBUG_HANGUP -#define tty_ldisc_debug(tty, f, args...) ({ \ - char __b[64]; \ - printk(KERN_DEBUG "%s: %s: " f, __func__, tty_name(tty, __b), ##args); \ +#define tty_ldisc_debug(tty, f, args...) ({ \ + printk(KERN_DEBUG "%s: %s: " f, __func__, tty_name(tty), ##args); \ }) #else #define tty_ldisc_debug(tty, f, args...) @@ -483,7 +482,6 @@ static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld) static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old) { - char buf[64]; struct tty_ldisc *new_ldisc; int r; @@ -504,7 +502,7 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old) if (r < 0) panic("Couldn't open N_TTY ldisc for " "%s --- error %d.", - tty_name(tty, buf), r); + tty_name(tty), r); } } diff --git a/drivers/tty/tty_ldsem.c b/drivers/tty/tty_ldsem.c index 0ffb0cbe2823..ad7eba5ca380 100644 --- a/drivers/tty/tty_ldsem.c +++ b/drivers/tty/tty_ldsem.c @@ -299,7 +299,8 @@ down_write_failed(struct ld_semaphore *sem, long count, long timeout) timeout = schedule_timeout(timeout); raw_spin_lock_irq(&sem->wait_lock); set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if ((locked = writer_trylock(sem))) + locked = writer_trylock(sem); + if (locked) break; } diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 59b25e039968..c8c91f0476a2 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -261,19 +261,22 @@ u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode) int m; if (glyph < 0 || glyph >= MAX_GLYPH) return 0; - else if (!(p = *conp->vc_uni_pagedir_loc)) - return glyph; - else if (use_unicode) { - if (!p->inverse_trans_unicode) + else { + p = *conp->vc_uni_pagedir_loc; + if (!p) return glyph; - else - return p->inverse_trans_unicode[glyph]; - } else { - m = inv_translate[conp->vc_num]; - if (!p->inverse_translations[m]) - return glyph; - else - return p->inverse_translations[m][glyph]; + else if (use_unicode) { + if (!p->inverse_trans_unicode) + return glyph; + else + return p->inverse_trans_unicode[glyph]; + } else { + m = inv_translate[conp->vc_num]; + if (!p->inverse_translations[m]) + return glyph; + else + return p->inverse_translations[m][glyph]; + } } } EXPORT_SYMBOL_GPL(inverse_translate); @@ -397,7 +400,8 @@ static void con_release_unimap(struct uni_pagedir *p) if (p == dflt) dflt = NULL; for (i = 0; i < 32; i++) { - if ((p1 = p->uni_pgdir[i]) != NULL) { + p1 = p->uni_pgdir[i]; + if (p1 != NULL) { for (j = 0; j < 32; j++) kfree(p1[j]); kfree(p1); @@ -473,14 +477,16 @@ con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos) int i, n; u16 **p1, *p2; - if (!(p1 = p->uni_pgdir[n = unicode >> 11])) { + p1 = p->uni_pgdir[n = unicode >> 11]; + if (!p1) { p1 = p->uni_pgdir[n] = kmalloc(32*sizeof(u16 *), GFP_KERNEL); if (!p1) return -ENOMEM; for (i = 0; i < 32; i++) p1[i] = NULL; } - if (!(p2 = p1[n = (unicode >> 6) & 0x1f])) { + p2 = p1[n = (unicode >> 6) & 0x1f]; + if (!p2) { p2 = p1[n] = kmalloc(64*sizeof(u16), GFP_KERNEL); if (!p2) return -ENOMEM; memset(p2, 0xff, 64*sizeof(u16)); /* No glyphs for the characters (yet) */ @@ -569,10 +575,12 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) * entries from "p" (old) to "q" (new). */ l = 0; /* unicode value */ - for (i = 0; i < 32; i++) - if ((p1 = p->uni_pgdir[i])) - for (j = 0; j < 32; j++) - if ((p2 = p1[j])) { + for (i = 0; i < 32; i++) { + p1 = p->uni_pgdir[i]; + if (p1) + for (j = 0; j < 32; j++) { + p2 = p1[j]; + if (p2) { for (k = 0; k < 64; k++, l++) if (p2[k] != 0xffff) { /* @@ -593,9 +601,11 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) /* Account for row of 64 empty entries */ l += 64; } + } else /* Account for empty table */ l += 32 * 64; + } /* * Finished copying font table, set vc_uni_pagedir to new table @@ -735,10 +745,12 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni ect = 0; if (*vc->vc_uni_pagedir_loc) { p = *vc->vc_uni_pagedir_loc; - for (i = 0; i < 32; i++) - if ((p1 = p->uni_pgdir[i])) - for (j = 0; j < 32; j++) - if ((p2 = *(p1++))) + for (i = 0; i < 32; i++) { + p1 = p->uni_pgdir[i]; + if (p1) + for (j = 0; j < 32; j++) { + p2 = *(p1++); + if (p2) for (k = 0; k < 64; k++) { if (*p2 < MAX_GLYPH && ect++ < ct) { __put_user((u_short)((i<<11)+(j<<6)+k), @@ -749,6 +761,8 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni } p2++; } + } + } } __put_user(ect, uct); console_unlock(); diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 6e00572cbeb9..8fe52989b380 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -108,6 +108,7 @@ #define CON_DRIVER_FLAG_MODULE 1 #define CON_DRIVER_FLAG_INIT 2 #define CON_DRIVER_FLAG_ATTR 4 +#define CON_DRIVER_FLAG_ZOMBIE 8 struct con_driver { const struct consw *con; @@ -135,6 +136,7 @@ const struct consw *conswitchp; */ #define DEFAULT_BELL_PITCH 750 #define DEFAULT_BELL_DURATION (HZ/8) +#define DEFAULT_CURSOR_BLINK_MS 200 struct vc vc_cons [MAX_NR_CONSOLES]; @@ -153,6 +155,7 @@ static int set_vesa_blanking(char __user *p); static void set_cursor(struct vc_data *vc); static void hide_cursor(struct vc_data *vc); static void console_callback(struct work_struct *ignored); +static void con_driver_unregister_callback(struct work_struct *ignored); static void blank_screen_t(unsigned long dummy); static void set_palette(struct vc_data *vc); @@ -182,6 +185,7 @@ static int blankinterval = 10*60; core_param(consoleblank, blankinterval, int, 0444); static DECLARE_WORK(console_work, console_callback); +static DECLARE_WORK(con_driver_unregister_work, con_driver_unregister_callback); /* * fg_console is the current virtual console, @@ -1237,7 +1241,7 @@ static void default_attr(struct vc_data *vc) struct rgb { u8 r; u8 g; u8 b; }; -struct rgb rgb_from_256(int i) +static struct rgb rgb_from_256(int i) { struct rgb c; if (i < 8) { /* Standard colours. */ @@ -1573,7 +1577,7 @@ static void setterm_command(struct vc_data *vc) case 11: /* set bell duration in msec */ if (vc->vc_npar >= 1) vc->vc_bell_duration = (vc->vc_par[1] < 2000) ? - vc->vc_par[1] * HZ / 1000 : 0; + msecs_to_jiffies(vc->vc_par[1]) : 0; else vc->vc_bell_duration = DEFAULT_BELL_DURATION; break; @@ -1590,6 +1594,13 @@ static void setterm_command(struct vc_data *vc) case 15: /* activate the previous console */ set_console(last_console); break; + case 16: /* set cursor blink duration in msec */ + if (vc->vc_npar >= 1 && vc->vc_par[1] >= 50 && + vc->vc_par[1] <= USHRT_MAX) + vc->vc_cur_blink_ms = vc->vc_par[1]; + else + vc->vc_cur_blink_ms = DEFAULT_CURSOR_BLINK_MS; + break; } } @@ -1717,6 +1728,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear) vc->vc_bell_pitch = DEFAULT_BELL_PITCH; vc->vc_bell_duration = DEFAULT_BELL_DURATION; + vc->vc_cur_blink_ms = DEFAULT_CURSOR_BLINK_MS; gotoxy(vc, 0, 0); save_cur(vc); @@ -3041,17 +3053,24 @@ static ssize_t show_tty_active(struct device *dev, } static DEVICE_ATTR(active, S_IRUGO, show_tty_active, NULL); +static struct attribute *vt_dev_attrs[] = { + &dev_attr_active.attr, + NULL +}; + +ATTRIBUTE_GROUPS(vt_dev); + int __init vty_init(const struct file_operations *console_fops) { cdev_init(&vc0_cdev, console_fops); if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) || register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0) panic("Couldn't register /dev/tty0 driver\n"); - tty0dev = device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0"); + tty0dev = device_create_with_groups(tty_class, NULL, + MKDEV(TTY_MAJOR, 0), NULL, + vt_dev_groups, "tty0"); if (IS_ERR(tty0dev)) tty0dev = NULL; - else - WARN_ON(device_create_file(tty0dev, &dev_attr_active) < 0); vcs_init(); @@ -3185,22 +3204,6 @@ err: #ifdef CONFIG_VT_HW_CONSOLE_BINDING -static int con_is_graphics(const struct consw *csw, int first, int last) -{ - int i, retval = 0; - - for (i = first; i <= last; i++) { - struct vc_data *vc = vc_cons[i].d; - - if (vc && vc->vc_mode == KD_GRAPHICS) { - retval = 1; - break; - } - } - - return retval; -} - /* unlocked version of unbind_con_driver() */ int do_unbind_con_driver(const struct consw *csw, int first, int last, int deflt) { @@ -3286,8 +3289,7 @@ static int vt_bind(struct con_driver *con) const struct consw *defcsw = NULL, *csw = NULL; int i, more = 1, first = -1, last = -1, deflt = 0; - if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) || - con_is_graphics(con->con, con->first, con->last)) + if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE)) goto err; csw = con->con; @@ -3338,8 +3340,7 @@ static int vt_unbind(struct con_driver *con) int i, more = 1, first = -1, last = -1, deflt = 0; int ret; - if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) || - con_is_graphics(con->con, con->first, con->last)) + if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE)) goto err; csw = con->con; @@ -3423,42 +3424,26 @@ static ssize_t show_name(struct device *dev, struct device_attribute *attr, } -static struct device_attribute device_attrs[] = { - __ATTR(bind, S_IRUGO|S_IWUSR, show_bind, store_bind), - __ATTR(name, S_IRUGO, show_name, NULL), +static DEVICE_ATTR(bind, S_IRUGO|S_IWUSR, show_bind, store_bind); +static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); + +static struct attribute *con_dev_attrs[] = { + &dev_attr_bind.attr, + &dev_attr_name.attr, + NULL }; +ATTRIBUTE_GROUPS(con_dev); + static int vtconsole_init_device(struct con_driver *con) { - int i; - int error = 0; - con->flag |= CON_DRIVER_FLAG_ATTR; - dev_set_drvdata(con->dev, con); - for (i = 0; i < ARRAY_SIZE(device_attrs); i++) { - error = device_create_file(con->dev, &device_attrs[i]); - if (error) - break; - } - - if (error) { - while (--i >= 0) - device_remove_file(con->dev, &device_attrs[i]); - con->flag &= ~CON_DRIVER_FLAG_ATTR; - } - - return error; + return 0; } static void vtconsole_deinit_device(struct con_driver *con) { - int i; - - if (con->flag & CON_DRIVER_FLAG_ATTR) { - for (i = 0; i < ARRAY_SIZE(device_attrs); i++) - device_remove_file(con->dev, &device_attrs[i]); - con->flag &= ~CON_DRIVER_FLAG_ATTR; - } + con->flag &= ~CON_DRIVER_FLAG_ATTR; } /** @@ -3605,7 +3590,8 @@ static int do_register_con_driver(const struct consw *csw, int first, int last) for (i = 0; i < MAX_NR_CON_DRIVER; i++) { con_driver = ®istered_con_driver[i]; - if (con_driver->con == NULL) { + if (con_driver->con == NULL && + !(con_driver->flag & CON_DRIVER_FLAG_ZOMBIE)) { con_driver->con = csw; con_driver->desc = desc; con_driver->node = i; @@ -3621,11 +3607,11 @@ static int do_register_con_driver(const struct consw *csw, int first, int last) if (retval) goto err; - con_driver->dev = device_create(vtconsole_class, NULL, - MKDEV(0, con_driver->node), - NULL, "vtcon%i", - con_driver->node); - + con_driver->dev = + device_create_with_groups(vtconsole_class, NULL, + MKDEV(0, con_driver->node), + con_driver, con_dev_groups, + "vtcon%i", con_driver->node); if (IS_ERR(con_driver->dev)) { printk(KERN_WARNING "Unable to create device for %s; " "errno = %ld\n", con_driver->desc, @@ -3667,16 +3653,20 @@ int do_unregister_con_driver(const struct consw *csw) struct con_driver *con_driver = ®istered_con_driver[i]; if (con_driver->con == csw) { - vtconsole_deinit_device(con_driver); - device_destroy(vtconsole_class, - MKDEV(0, con_driver->node)); + /* + * Defer the removal of the sysfs entries since that + * will acquire the kernfs s_active lock and we can't + * acquire this lock while holding the console lock: + * the unbind sysfs entry imposes already the opposite + * order. Reset con already here to prevent any later + * lookup to succeed and mark this slot as zombie, so + * it won't get reused until we complete the removal + * in the deferred work. + */ con_driver->con = NULL; - con_driver->desc = NULL; - con_driver->dev = NULL; - con_driver->node = 0; - con_driver->flag = 0; - con_driver->first = 0; - con_driver->last = 0; + con_driver->flag = CON_DRIVER_FLAG_ZOMBIE; + schedule_work(&con_driver_unregister_work); + return 0; } } @@ -3685,6 +3675,39 @@ int do_unregister_con_driver(const struct consw *csw) } EXPORT_SYMBOL_GPL(do_unregister_con_driver); +static void con_driver_unregister_callback(struct work_struct *ignored) +{ + int i; + + console_lock(); + + for (i = 0; i < MAX_NR_CON_DRIVER; i++) { + struct con_driver *con_driver = ®istered_con_driver[i]; + + if (!(con_driver->flag & CON_DRIVER_FLAG_ZOMBIE)) + continue; + + console_unlock(); + + vtconsole_deinit_device(con_driver); + device_destroy(vtconsole_class, MKDEV(0, con_driver->node)); + + console_lock(); + + if (WARN_ON_ONCE(con_driver->con)) + con_driver->con = NULL; + con_driver->desc = NULL; + con_driver->dev = NULL; + con_driver->node = 0; + WARN_ON_ONCE(con_driver->flag != CON_DRIVER_FLAG_ZOMBIE); + con_driver->flag = 0; + con_driver->first = 0; + con_driver->last = 0; + } + + console_unlock(); +} + /* * If we support more console drivers, this function is used * when a driver wants to take over some existing consoles @@ -3739,10 +3762,11 @@ static int __init vtconsole_class_init(void) struct con_driver *con = ®istered_con_driver[i]; if (con->con && !con->dev) { - con->dev = device_create(vtconsole_class, NULL, - MKDEV(0, con->node), - NULL, "vtcon%i", - con->node); + con->dev = + device_create_with_groups(vtconsole_class, NULL, + MKDEV(0, con->node), + con, con_dev_groups, + "vtcon%i", con->node); if (IS_ERR(con->dev)) { printk(KERN_WARNING "Unable to create " diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 2bd78e2ac8ec..97d5a74558a3 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -388,7 +388,7 @@ int vt_ioctl(struct tty_struct *tty, * Generate the tone for the appropriate number of ticks. * If the time is zero, turn off sound ourselves. */ - ticks = HZ * ((arg >> 16) & 0xffff) / 1000; + ticks = msecs_to_jiffies((arg >> 16) & 0xffff); count = ticks ? (arg & 0xffff) : 0; if (count) count = PIT_TICK_RATE / count; |