diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 6ef205fd7c97..782e9072407b 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -1094,6 +1094,12 @@ the framebuffer, pass the 'ram' option so that it is mapped with the correct attributes. + linflex, + Use early console provided by Freescale LinFlex UART + serial driver for NXP S32V234 SoCs. A valid base + address must be provided, and the serial port must + already be setup and configured. + earlyprintk= [X86,SH,ARM,M68k,S390] earlyprintk=vga earlyprintk=sclp diff --git a/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.txt b/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.txt new file mode 100644 index 000000000000..f1bbe0826be5 --- /dev/null +++ b/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.txt @@ -0,0 +1,22 @@ +* Freescale LINFlexD UART + +The LINFlexD controller implements several LIN protocol versions, as well as +support for full-duplex UART communication through 8-bit and 9-bit frames. + +See chapter 47 ("LINFlexD") in the reference manual[1]. + +Required properties: +- compatible : + - "fsl,s32v234-linflexuart" for LINFlexD configured in UART mode, which + is compatible with the one integrated on S32V234 SoC +- reg : Address and length of the register set for the device +- interrupts : Should contain uart interrupt + +Example: +uart0: serial@40053000 { + compatible = "fsl,s32v234-linflexuart"; + reg = <0x0 0x40053000 0x0 0x1000>; + interrupts = <0 59 4>; +}; + +[1] https://www.nxp.com/webapp/Download?colCode=S32V234RM diff --git a/Documentation/devicetree/bindings/serial/nvidia,tegra20-hsuart.txt b/Documentation/devicetree/bindings/serial/nvidia,tegra20-hsuart.txt index d7edf732eb7f..f709304036c2 100644 --- a/Documentation/devicetree/bindings/serial/nvidia,tegra20-hsuart.txt +++ b/Documentation/devicetree/bindings/serial/nvidia,tegra20-hsuart.txt @@ -1,7 +1,12 @@ NVIDIA Tegra20/Tegra30 high speed (DMA based) UART controller driver. Required properties: -- compatible : should be "nvidia,tegra30-hsuart", "nvidia,tegra20-hsuart". +- compatible : should be, + "nvidia,tegra20-hsuart" for Tegra20, + "nvidia,tegra30-hsuart" for Tegra30, + "nvidia,tegra186-hsuart" for Tegra186, + "nvidia,tegra194-hsuart" for Tegra194. + - reg: Should contain UART controller registers location and length. - interrupts: Should contain UART controller interrupts. - clocks: Must contain one entry, for the module clock. @@ -19,6 +24,37 @@ Required properties: Optional properties: - nvidia,enable-modem-interrupt: Enable modem interrupts. Should be enable only if all 8 lines of UART controller are pinmuxed. +- nvidia,adjust-baud-rates: List of entries providing percentage of baud rate + adjustment within a range. + Each entry contains sets of 3 values. Range low/high and adjusted rate. + + When baud rate set on controller falls within the range mentioned in this + field, baud rate will be adjusted by percentage mentioned here. + Ex: <9600 115200 200> + Increase baud rate by 2% when set baud rate falls within range 9600 to 115200 + +Baud Rate tolerance: + Standard UART devices are expected to have tolerance for baud rate error by + -4 to +4 %. All Tegra devices till Tegra210 had this support. However, + Tegra186 chip has a known hardware issue. UART Rx baud rate tolerance level + is 0% to +4% in 1-stop config. Otherwise, the received data will have + corruption/invalid framing errors. Parker errata suggests adjusting baud + rate to be higher than the deviations observed in Tx. + + Tx deviation of connected device can be captured over scope (or noted from + its spec) for valid range and Tegra baud rate has to be set above actual + Tx baud rate observed. To do this we use nvidia,adjust-baud-rates + + As an example, consider there is deviation observed in Tx for baud rates as + listed below. + 0 to 9600 has 1% deviation + 9600 to 115200 2% deviation + This slight deviation is expcted and Tegra UART is expected to handle it. Due + to the issue stated above, baud rate on Tegra UART should be set equal to or + above deviation observed for avoiding frame errors. + Property should be set like this + nvidia,adjust-baud-rates = <0 9600 100>, + <9600 115200 200>; Example: @@ -33,4 +69,5 @@ serial@70006000 { reset-names = "serial"; dmas = <&apbdma 8>, <&apbdma 8>; dma-names = "rx", "tx"; + nvidia,adjust-baud-rates = <1000000 4000000 136>; /* 1.36% shift */ }; diff --git a/Documentation/devicetree/bindings/serial/sifive-serial.txt b/Documentation/devicetree/bindings/serial/sifive-serial.txt deleted file mode 100644 index c86b1e524159..000000000000 --- a/Documentation/devicetree/bindings/serial/sifive-serial.txt +++ /dev/null @@ -1,33 +0,0 @@ -SiFive asynchronous serial interface (UART) - -Required properties: - -- compatible: should be something similar to - "sifive,-uart" for the UART as integrated - on a particular chip, and "sifive,uart" for the - general UART IP block programming model. Supported - compatible strings as of the date of this writing are: - "sifive,fu540-c000-uart" for the SiFive UART v0 as - integrated onto the SiFive FU540 chip, or "sifive,uart0" - for the SiFive UART v0 IP block with no chip integration - tweaks (if any) -- reg: address and length of the register space -- interrupts: Should contain the UART interrupt identifier -- clocks: Should contain a clock identifier for the UART's parent clock - - -UART HDL that corresponds to the IP block version numbers can be found -here: - -https://github.com/sifive/sifive-blocks/tree/master/src/main/scala/devices/uart - - -Example: - -uart0: serial@10010000 { - compatible = "sifive,fu540-c000-uart", "sifive,uart0"; - interrupt-parent = <&plic0>; - interrupts = <80>; - reg = <0x0 0x10010000 0x0 0x1000>; - clocks = <&prci PRCI_CLK_TLCLK>; -}; diff --git a/Documentation/devicetree/bindings/serial/sifive-serial.yaml b/Documentation/devicetree/bindings/serial/sifive-serial.yaml new file mode 100644 index 000000000000..e8d3aeda1202 --- /dev/null +++ b/Documentation/devicetree/bindings/serial/sifive-serial.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/serial/sifive-serial.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: SiFive asynchronous serial interface (UART) + +maintainers: + - Pragnesh Patel + - Paul Walmsley + - Palmer Dabbelt + +allOf: + - $ref: /schemas/serial.yaml# + +properties: + compatible: + items: + - const: sifive,fu540-c000-uart + - const: sifive,uart0 + + description: + Should be something similar to "sifive,-uart" + for the UART as integrated on a particular chip, + and "sifive,uart" for the general UART IP + block programming model. + + UART HDL that corresponds to the IP block version + numbers can be found here - + + https://github.com/sifive/sifive-blocks/tree/master/src/main/scala/devices/uart + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks + +additionalProperties: false + +examples: + - | + #include + serial@10010000 { + compatible = "sifive,fu540-c000-uart", "sifive,uart0"; + interrupt-parent = <&plic0>; + interrupts = <80>; + reg = <0x0 0x10010000 0x0 0x1000>; + clocks = <&prci PRCI_CLK_TLCLK>; + }; + +... diff --git a/Documentation/devicetree/bindings/serial/st,stm32-usart.txt b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt index a6b19485c9dc..8620f7fcbd50 100644 --- a/Documentation/devicetree/bindings/serial/st,stm32-usart.txt +++ b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt @@ -20,6 +20,11 @@ Optional properties: linux,rs485-enabled-at-boot-time: see rs485.txt. - dmas: phandle(s) to DMA controller node(s). Refer to stm32-dma.txt - dma-names: "rx" and/or "tx" +- wakeup-source: bool flag to indicate this device has wakeup capabilities +- interrupt-names, if optional wake-up interrupt is used, should be: + - "event": the name for the interrupt line of the USART instance + - "wakeup" the name for the optional wake-up interrupt + Examples: usart4: serial@40004c00 { diff --git a/Documentation/driver-api/serial/n_gsm.rst b/Documentation/driver-api/serial/n_gsm.rst index f3ad9fd26408..286e7ff4d2d9 100644 --- a/Documentation/driver-api/serial/n_gsm.rst +++ b/Documentation/driver-api/serial/n_gsm.rst @@ -18,18 +18,22 @@ How to use it 2. switch the serial line to using the n_gsm line discipline by using TIOCSETD ioctl, 3. configure the mux using GSMIOC_GETCONF / GSMIOC_SETCONF ioctl, +4. obtain base gsmtty number for the used serial port, Major parts of the initialization program : (a good starting point is util-linux-ng/sys-utils/ldattach.c):: + #include + #include #include - #define N_GSM0710 21 /* GSM 0710 Mux */ + #include #define DEFAULT_SPEED B115200 #define SERIAL_PORT /dev/ttyS0 int ldisc = N_GSM0710; struct gsm_config c; struct termios configuration; + uint32_t first; /* open the serial port connected to the modem */ fd = open(SERIAL_PORT, O_RDWR | O_NOCTTY | O_NDELAY); @@ -58,21 +62,14 @@ Major parts of the initialization program : c.mtu = 127; /* set the new configuration */ ioctl(fd, GSMIOC_SETCONF, &c); + /* get first gsmtty device node */ + ioctl(fd, GSMIOC_GETFIRST, &first); + printf("first muxed line: /dev/gsmtty%i\n", first); /* and wait for ever to keep the line discipline enabled */ daemon(0,0); pause(); -4. create the devices corresponding to the "virtual" serial ports (take care, - each modem has its configuration and some DLC have dedicated functions, - for example GPS), starting with minor 1 (DLC0 is reserved for the management - of the mux):: - - MAJOR=`cat /proc/devices |grep gsmtty | awk '{print $1}` - for i in `seq 1 4`; do - mknod /dev/ttygsm$i c $MAJOR $i - done - 5. use these devices as plain serial ports. for example, it's possible: diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c index 461fd8a24278..60d5d985113c 100644 --- a/drivers/parport/parport_serial.c +++ b/drivers/parport/parport_serial.c @@ -61,7 +61,10 @@ enum parport_pc_pci_cards { wch_ch382_0s1p, wch_ch382_2s1p, brainboxes_5s1p, - sunix_2s1p, + sunix_4008a, + sunix_5069a, + sunix_5079a, + sunix_5099a, }; /* each element directly indexed from enum list, above */ @@ -151,7 +154,10 @@ static struct parport_pc_pci cards[] = { /* wch_ch382_0s1p*/ { 1, { { 2, -1}, } }, /* wch_ch382_2s1p*/ { 1, { { 2, -1}, } }, /* brainboxes_5s1p */ { 1, { { 3, -1 }, } }, - /* sunix_2s1p */ { 1, { { 3, -1 }, } }, + /* sunix_4008a */ { 1, { { 1, 2 }, } }, + /* sunix_5069a */ { 1, { { 1, 2 }, } }, + /* sunix_5079a */ { 1, { { 1, 2 }, } }, + /* sunix_5099a */ { 1, { { 1, 2 }, } }, }; static struct pci_device_id parport_serial_pci_tbl[] = { @@ -261,13 +267,15 @@ static struct pci_device_id parport_serial_pci_tbl[] = { { PCI_VENDOR_ID_INTASHIELD, 0x4100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_5s1p }, - /* - * More SUNIX variations. At least one of these has part number - * '5079A but subdevice 0x102. That board reports 0x0708 as - * its PCI Class. - */ + /* Sunix boards */ { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, PCI_VENDOR_ID_SUNIX, - 0x0102, 0, 0, sunix_2s1p }, + 0x0100, 0, 0, sunix_4008a }, + { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, PCI_VENDOR_ID_SUNIX, + 0x0101, 0, 0, sunix_5069a }, + { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, PCI_VENDOR_ID_SUNIX, + 0x0102, 0, 0, sunix_5079a }, + { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, PCI_VENDOR_ID_SUNIX, + 0x0104, 0, 0, sunix_5099a }, { 0, } /* terminate list */ }; @@ -516,11 +524,23 @@ static struct pciserial_board pci_parport_serial_boards[] = { .base_baud = 921600, .uart_offset = 8, }, - [sunix_2s1p] = { - .flags = FL_BASE0|FL_BASE_BARS, + [sunix_4008a] = { + .num_ports = 0, + }, + [sunix_5069a] = { + .num_ports = 1, + .base_baud = 921600, + .uart_offset = 0x8, + }, + [sunix_5079a] = { .num_ports = 2, - .base_baud = 921600, - .uart_offset = 8, + .base_baud = 921600, + .uart_offset = 0x8, + }, + [sunix_5099a] = { + .num_ports = 4, + .base_baud = 921600, + .uart_offset = 0x8, }, }; diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index 5fb214e67d73..ee0604cd9c6b 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -871,8 +871,8 @@ static void hvcs_set_pi(struct hvcs_partner_info *pi, struct hvcs_struct *hvcsd) hvcsd->p_partition_ID = pi->partition_ID; /* copy the null-term char too */ - strlcpy(&hvcsd->p_location_code[0], - &pi->location_code[0], sizeof(hvcsd->p_location_code)); + strlcpy(hvcsd->p_location_code, pi->location_code, + sizeof(hvcsd->p_location_code)); } /* diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c index e04a43e89f6b..fc38f96475bf 100644 --- a/drivers/tty/isicom.c +++ b/drivers/tty/isicom.c @@ -553,7 +553,6 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id) tty = tty_port_tty_get(&port->port); if (tty == NULL) { - word_count = byte_count >> 1; while (byte_count > 1) { inw(base); byte_count -= 2; diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index c4e16b31f9ab..36a3eb4ad4c5 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -1716,7 +1716,7 @@ static void gsm_dlci_release(struct gsm_dlci *dlci) gsm_destroy_network(dlci); mutex_unlock(&dlci->mutex); - tty_vhangup(tty); + tty_hangup(tty); tty_port_tty_set(&dlci->port, NULL); tty_kref_put(tty); @@ -2171,6 +2171,16 @@ static inline void mux_put(struct gsm_mux *gsm) kref_put(&gsm->ref, gsm_free_muxr); } +static inline unsigned int mux_num_to_base(struct gsm_mux *gsm) +{ + return gsm->num * NUM_DLCI; +} + +static inline unsigned int mux_line_to_num(unsigned int line) +{ + return line / NUM_DLCI; +} + /** * gsm_alloc_mux - allocate a mux * @@ -2351,7 +2361,8 @@ static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len) static int gsmld_attach_gsm(struct tty_struct *tty, struct gsm_mux *gsm) { - int ret, i, base; + unsigned int base; + int ret, i; gsm->tty = tty_kref_get(tty); gsm->output = gsmld_output; @@ -2361,7 +2372,7 @@ static int gsmld_attach_gsm(struct tty_struct *tty, struct gsm_mux *gsm) else { /* Don't register device 0 - this is the control channel and not a usable tty interface */ - base = gsm->num << 6; /* Base for this MUX */ + base = mux_num_to_base(gsm); /* Base for this MUX */ for (i = 1; i < NUM_DLCI; i++) tty_register_device(gsm_tty_driver, base + i, NULL); } @@ -2379,8 +2390,8 @@ static int gsmld_attach_gsm(struct tty_struct *tty, struct gsm_mux *gsm) static void gsmld_detach_gsm(struct tty_struct *tty, struct gsm_mux *gsm) { + unsigned int base = mux_num_to_base(gsm); /* Base for this MUX */ int i; - int base = gsm->num << 6; /* Base for this MUX */ WARN_ON(tty != gsm->tty); for (i = 1; i < NUM_DLCI; i++) @@ -2602,6 +2613,7 @@ static int gsmld_ioctl(struct tty_struct *tty, struct file *file, { struct gsm_config c; struct gsm_mux *gsm = tty->disc_data; + unsigned int base; switch (cmd) { case GSMIOC_GETCONF: @@ -2613,6 +2625,9 @@ static int gsmld_ioctl(struct tty_struct *tty, struct file *file, if (copy_from_user(&c, (void *)arg, sizeof(c))) return -EFAULT; return gsm_config(gsm, &c); + case GSMIOC_GETFIRST: + base = mux_num_to_base(gsm); + return put_user(base + 1, (__u32 __user *)arg); default: return n_tty_ioctl_helper(tty, file, cmd, arg); } @@ -2908,7 +2923,7 @@ static int gsmtty_install(struct tty_driver *driver, struct tty_struct *tty) struct gsm_mux *gsm; struct gsm_dlci *dlci; unsigned int line = tty->index; - unsigned int mux = line >> 6; + unsigned int mux = mux_line_to_num(line); bool alloc = false; int ret; diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c index 3214e22e79f3..ed99948f3b7f 100644 --- a/drivers/tty/nozomi.c +++ b/drivers/tty/nozomi.c @@ -1282,7 +1282,7 @@ static void nozomi_setup_private_data(struct nozomi *dc) static ssize_t card_type_show(struct device *dev, struct device_attribute *attr, char *buf) { - const struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev)); + const struct nozomi *dc = dev_get_drvdata(dev); return sprintf(buf, "%d\n", dc->card_type); } @@ -1291,7 +1291,7 @@ static DEVICE_ATTR_RO(card_type); static ssize_t open_ttys_show(struct device *dev, struct device_attribute *attr, char *buf) { - const struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev)); + const struct nozomi *dc = dev_get_drvdata(dev); return sprintf(buf, "%u\n", dc->open_ttys); } diff --git a/drivers/tty/serial/8250/8250_bcm2835aux.c b/drivers/tty/serial/8250/8250_bcm2835aux.c index bd53661103eb..8ce700c1a7fc 100644 --- a/drivers/tty/serial/8250/8250_bcm2835aux.c +++ b/drivers/tty/serial/8250/8250_bcm2835aux.c @@ -56,10 +56,8 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev) /* get the interrupt */ ret = platform_get_irq(pdev, 0); - if (ret < 0) { - dev_err(&pdev->dev, "irq not found - %i", ret); + if (ret < 0) return ret; - } data->uart.port.irq = ret; /* map the main registers */ diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index df3bcc0b2d74..e682390ce0de 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -1026,10 +1026,8 @@ int serial8250_register_8250_port(struct uart_8250_port *up) if (!has_acpi_companion(uart->port.dev)) { gpios = mctrl_gpio_init(&uart->port, 0); if (IS_ERR(gpios)) { - if (PTR_ERR(gpios) != -ENOSYS) { - ret = PTR_ERR(gpios); - goto out_unlock; - } + ret = PTR_ERR(gpios); + goto out_unlock; } else { uart->gpios = gpios; } diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 284e8d052fc3..1c72fdc2dd37 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -27,66 +27,36 @@ #include -#include "8250.h" +#include "8250_dwlib.h" /* Offsets for the DesignWare specific registers */ #define DW_UART_USR 0x1f /* UART Status Register */ -#define DW_UART_DLF 0xc0 /* Divisor Latch Fraction Register */ -#define DW_UART_CPR 0xf4 /* Component Parameter Register */ -#define DW_UART_UCV 0xf8 /* UART Component Version */ - -/* Component Parameter Register bits */ -#define DW_UART_CPR_ABP_DATA_WIDTH (3 << 0) -#define DW_UART_CPR_AFCE_MODE (1 << 4) -#define DW_UART_CPR_THRE_MODE (1 << 5) -#define DW_UART_CPR_SIR_MODE (1 << 6) -#define DW_UART_CPR_SIR_LP_MODE (1 << 7) -#define DW_UART_CPR_ADDITIONAL_FEATURES (1 << 8) -#define DW_UART_CPR_FIFO_ACCESS (1 << 9) -#define DW_UART_CPR_FIFO_STAT (1 << 10) -#define DW_UART_CPR_SHADOW (1 << 11) -#define DW_UART_CPR_ENCODED_PARMS (1 << 12) -#define DW_UART_CPR_DMA_EXTRA (1 << 13) -#define DW_UART_CPR_FIFO_MODE (0xff << 16) -/* Helper for fifo size calculation */ -#define DW_UART_CPR_FIFO_SIZE(a) (((a >> 16) & 0xff) * 16) /* DesignWare specific register fields */ #define DW_UART_MCR_SIRE BIT(6) struct dw8250_data { + struct dw8250_port_data data; + u8 usr_reg; - u8 dlf_size; - int line; int msr_mask_on; int msr_mask_off; struct clk *clk; struct clk *pclk; struct reset_control *rst; - struct uart_8250_dma dma; unsigned int skip_autocfg:1; unsigned int uart_16550_compatible:1; }; -static inline u32 dw8250_readl_ext(struct uart_port *p, int offset) +static inline struct dw8250_data *to_dw8250_data(struct dw8250_port_data *data) { - if (p->iotype == UPIO_MEM32BE) - return ioread32be(p->membase + offset); - return readl(p->membase + offset); -} - -static inline void dw8250_writel_ext(struct uart_port *p, int offset, u32 reg) -{ - if (p->iotype == UPIO_MEM32BE) - iowrite32be(reg, p->membase + offset); - else - writel(reg, p->membase + offset); + return container_of(data, struct dw8250_data, data); } static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value) { - struct dw8250_data *d = p->private_data; + struct dw8250_data *d = to_dw8250_data(p->private_data); /* Override any modem control signals if needed */ if (offset == UART_MSR) { @@ -160,7 +130,7 @@ static void dw8250_tx_wait_empty(struct uart_port *p) static void dw8250_serial_out38x(struct uart_port *p, int offset, int value) { - struct dw8250_data *d = p->private_data; + struct dw8250_data *d = to_dw8250_data(p->private_data); /* Allow the TX to drain before we reconfigure */ if (offset == UART_LCR) @@ -175,7 +145,7 @@ static void dw8250_serial_out38x(struct uart_port *p, int offset, int value) static void dw8250_serial_out(struct uart_port *p, int offset, int value) { - struct dw8250_data *d = p->private_data; + struct dw8250_data *d = to_dw8250_data(p->private_data); writeb(value, p->membase + (offset << p->regshift)); @@ -202,7 +172,7 @@ static unsigned int dw8250_serial_inq(struct uart_port *p, int offset) static void dw8250_serial_outq(struct uart_port *p, int offset, int value) { - struct dw8250_data *d = p->private_data; + struct dw8250_data *d = to_dw8250_data(p->private_data); value &= 0xff; __raw_writeq(value, p->membase + (offset << p->regshift)); @@ -216,7 +186,7 @@ static void dw8250_serial_outq(struct uart_port *p, int offset, int value) static void dw8250_serial_out32(struct uart_port *p, int offset, int value) { - struct dw8250_data *d = p->private_data; + struct dw8250_data *d = to_dw8250_data(p->private_data); writel(value, p->membase + (offset << p->regshift)); @@ -233,7 +203,7 @@ static unsigned int dw8250_serial_in32(struct uart_port *p, int offset) static void dw8250_serial_out32be(struct uart_port *p, int offset, int value) { - struct dw8250_data *d = p->private_data; + struct dw8250_data *d = to_dw8250_data(p->private_data); iowrite32be(value, p->membase + (offset << p->regshift)); @@ -252,7 +222,7 @@ static unsigned int dw8250_serial_in32be(struct uart_port *p, int offset) static int dw8250_handle_irq(struct uart_port *p) { struct uart_8250_port *up = up_to_u8250p(p); - struct dw8250_data *d = p->private_data; + struct dw8250_data *d = to_dw8250_data(p->private_data); unsigned int iir = p->serial_in(p, UART_IIR); unsigned int status; unsigned long flags; @@ -306,7 +276,7 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios, struct ktermios *old) { unsigned int baud = tty_termios_baud_rate(termios); - struct dw8250_data *d = p->private_data; + struct dw8250_data *d = to_dw8250_data(p->private_data); long rate; int ret; @@ -368,37 +338,6 @@ static bool dw8250_idma_filter(struct dma_chan *chan, void *param) return param == chan->device->dev; } -/* - * divisor = div(I) + div(F) - * "I" means integer, "F" means fractional - * quot = div(I) = clk / (16 * baud) - * frac = div(F) * 2^dlf_size - * - * let rem = clk % (16 * baud) - * we have: div(F) * (16 * baud) = rem - * so frac = 2^dlf_size * rem / (16 * baud) = (rem << dlf_size) / (16 * baud) - */ -static unsigned int dw8250_get_divisor(struct uart_port *p, - unsigned int baud, - unsigned int *frac) -{ - unsigned int quot, rem, base_baud = baud * 16; - struct dw8250_data *d = p->private_data; - - quot = p->uartclk / base_baud; - rem = p->uartclk % base_baud; - *frac = DIV_ROUND_CLOSEST(rem << d->dlf_size, base_baud); - - return quot; -} - -static void dw8250_set_divisor(struct uart_port *p, unsigned int baud, - unsigned int quot, unsigned int quot_frac) -{ - dw8250_writel_ext(p, DW_UART_DLF, quot_frac); - serial8250_do_set_divisor(p, baud, quot, quot_frac); -} - static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data) { if (p->dev->of_node) { @@ -437,65 +376,18 @@ static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data) /* Platforms with iDMA 64-bit */ if (platform_get_resource_byname(to_platform_device(p->dev), IORESOURCE_MEM, "lpss_priv")) { - data->dma.rx_param = p->dev->parent; - data->dma.tx_param = p->dev->parent; - data->dma.fn = dw8250_idma_filter; + data->data.dma.rx_param = p->dev->parent; + data->data.dma.tx_param = p->dev->parent; + data->data.dma.fn = dw8250_idma_filter; } } -static void dw8250_setup_port(struct uart_port *p) -{ - struct uart_8250_port *up = up_to_u8250p(p); - u32 reg; - - /* - * If the Component Version Register returns zero, we know that - * ADDITIONAL_FEATURES are not enabled. No need to go any further. - */ - reg = dw8250_readl_ext(p, DW_UART_UCV); - if (!reg) - return; - - dev_dbg(p->dev, "Designware UART version %c.%c%c\n", - (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff); - - dw8250_writel_ext(p, DW_UART_DLF, ~0U); - reg = dw8250_readl_ext(p, DW_UART_DLF); - dw8250_writel_ext(p, DW_UART_DLF, 0); - - if (reg) { - struct dw8250_data *d = p->private_data; - - d->dlf_size = fls(reg); - p->get_divisor = dw8250_get_divisor; - p->set_divisor = dw8250_set_divisor; - } - - reg = dw8250_readl_ext(p, DW_UART_CPR); - if (!reg) - return; - - /* Select the type based on fifo */ - if (reg & DW_UART_CPR_FIFO_MODE) { - p->type = PORT_16550A; - p->flags |= UPF_FIXED_TYPE; - p->fifosize = DW_UART_CPR_FIFO_SIZE(reg); - up->capabilities = UART_CAP_FIFO; - } - - if (reg & DW_UART_CPR_AFCE_MODE) - up->capabilities |= UART_CAP_AFE; - - if (reg & DW_UART_CPR_SIR_MODE) - up->capabilities |= UART_CAP_IRDA; -} - static int dw8250_probe(struct platform_device *pdev) { - struct uart_8250_port uart = {}; + struct uart_8250_port uart = {}, *up = &uart; struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); int irq = platform_get_irq(pdev, 0); - struct uart_port *p = &uart.port; + struct uart_port *p = &up->port; struct device *dev = &pdev->dev; struct dw8250_data *data; int err; @@ -534,9 +426,9 @@ static int dw8250_probe(struct platform_device *pdev) if (!data) return -ENOMEM; - data->dma.fn = dw8250_fallback_dma_filter; + data->data.dma.fn = dw8250_fallback_dma_filter; data->usr_reg = DW_UART_USR; - p->private_data = data; + p->private_data = &data->data; data->uart_16550_compatible = device_property_read_bool(dev, "snps,uart-16550-compatible"); @@ -632,14 +524,14 @@ static int dw8250_probe(struct platform_device *pdev) /* If we have a valid fifosize, try hooking up DMA */ if (p->fifosize) { - data->dma.rxconf.src_maxburst = p->fifosize / 4; - data->dma.txconf.dst_maxburst = p->fifosize / 4; - uart.dma = &data->dma; + data->data.dma.rxconf.src_maxburst = p->fifosize / 4; + data->data.dma.txconf.dst_maxburst = p->fifosize / 4; + up->dma = &data->data.dma; } - data->line = serial8250_register_8250_port(&uart); - if (data->line < 0) { - err = data->line; + data->data.line = serial8250_register_8250_port(up); + if (data->data.line < 0) { + err = data->data.line; goto err_reset; } @@ -667,10 +559,11 @@ err_clk: static int dw8250_remove(struct platform_device *pdev) { struct dw8250_data *data = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; - pm_runtime_get_sync(&pdev->dev); + pm_runtime_get_sync(dev); - serial8250_unregister_port(data->line); + serial8250_unregister_port(data->data.line); reset_control_assert(data->rst); @@ -680,8 +573,8 @@ static int dw8250_remove(struct platform_device *pdev) if (!IS_ERR(data->clk)) clk_disable_unprepare(data->clk); - pm_runtime_disable(&pdev->dev); - pm_runtime_put_noidle(&pdev->dev); + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); return 0; } @@ -691,7 +584,7 @@ static int dw8250_suspend(struct device *dev) { struct dw8250_data *data = dev_get_drvdata(dev); - serial8250_suspend_port(data->line); + serial8250_suspend_port(data->data.line); return 0; } @@ -700,7 +593,7 @@ static int dw8250_resume(struct device *dev) { struct dw8250_data *data = dev_get_drvdata(dev); - serial8250_resume_port(data->line); + serial8250_resume_port(data->data.line); return 0; } diff --git a/drivers/tty/serial/8250/8250_dwlib.c b/drivers/tty/serial/8250/8250_dwlib.c new file mode 100644 index 000000000000..6d6a78eead3e --- /dev/null +++ b/drivers/tty/serial/8250/8250_dwlib.c @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Synopsys DesignWare 8250 library. */ + +#include +#include +#include +#include +#include +#include + +#include "8250_dwlib.h" + +/* Offsets for the DesignWare specific registers */ +#define DW_UART_DLF 0xc0 /* Divisor Latch Fraction Register */ +#define DW_UART_CPR 0xf4 /* Component Parameter Register */ +#define DW_UART_UCV 0xf8 /* UART Component Version */ + +/* Component Parameter Register bits */ +#define DW_UART_CPR_ABP_DATA_WIDTH (3 << 0) +#define DW_UART_CPR_AFCE_MODE (1 << 4) +#define DW_UART_CPR_THRE_MODE (1 << 5) +#define DW_UART_CPR_SIR_MODE (1 << 6) +#define DW_UART_CPR_SIR_LP_MODE (1 << 7) +#define DW_UART_CPR_ADDITIONAL_FEATURES (1 << 8) +#define DW_UART_CPR_FIFO_ACCESS (1 << 9) +#define DW_UART_CPR_FIFO_STAT (1 << 10) +#define DW_UART_CPR_SHADOW (1 << 11) +#define DW_UART_CPR_ENCODED_PARMS (1 << 12) +#define DW_UART_CPR_DMA_EXTRA (1 << 13) +#define DW_UART_CPR_FIFO_MODE (0xff << 16) + +/* Helper for FIFO size calculation */ +#define DW_UART_CPR_FIFO_SIZE(a) (((a >> 16) & 0xff) * 16) + +static inline u32 dw8250_readl_ext(struct uart_port *p, int offset) +{ + if (p->iotype == UPIO_MEM32BE) + return ioread32be(p->membase + offset); + return readl(p->membase + offset); +} + +static inline void dw8250_writel_ext(struct uart_port *p, int offset, u32 reg) +{ + if (p->iotype == UPIO_MEM32BE) + iowrite32be(reg, p->membase + offset); + else + writel(reg, p->membase + offset); +} + +/* + * divisor = div(I) + div(F) + * "I" means integer, "F" means fractional + * quot = div(I) = clk / (16 * baud) + * frac = div(F) * 2^dlf_size + * + * let rem = clk % (16 * baud) + * we have: div(F) * (16 * baud) = rem + * so frac = 2^dlf_size * rem / (16 * baud) = (rem << dlf_size) / (16 * baud) + */ +static unsigned int dw8250_get_divisor(struct uart_port *p, unsigned int baud, + unsigned int *frac) +{ + unsigned int quot, rem, base_baud = baud * 16; + struct dw8250_port_data *d = p->private_data; + + quot = p->uartclk / base_baud; + rem = p->uartclk % base_baud; + *frac = DIV_ROUND_CLOSEST(rem << d->dlf_size, base_baud); + + return quot; +} + +static void dw8250_set_divisor(struct uart_port *p, unsigned int baud, + unsigned int quot, unsigned int quot_frac) +{ + dw8250_writel_ext(p, DW_UART_DLF, quot_frac); + serial8250_do_set_divisor(p, baud, quot, quot_frac); +} + +void dw8250_setup_port(struct uart_port *p) +{ + struct uart_8250_port *up = up_to_u8250p(p); + u32 reg; + + /* + * If the Component Version Register returns zero, we know that + * ADDITIONAL_FEATURES are not enabled. No need to go any further. + */ + reg = dw8250_readl_ext(p, DW_UART_UCV); + if (!reg) + return; + + dev_dbg(p->dev, "Designware UART version %c.%c%c\n", + (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff); + + dw8250_writel_ext(p, DW_UART_DLF, ~0U); + reg = dw8250_readl_ext(p, DW_UART_DLF); + dw8250_writel_ext(p, DW_UART_DLF, 0); + + if (reg) { + struct dw8250_port_data *d = p->private_data; + + d->dlf_size = fls(reg); + p->get_divisor = dw8250_get_divisor; + p->set_divisor = dw8250_set_divisor; + } + + reg = dw8250_readl_ext(p, DW_UART_CPR); + if (!reg) + return; + + /* Select the type based on FIFO */ + if (reg & DW_UART_CPR_FIFO_MODE) { + p->type = PORT_16550A; + p->flags |= UPF_FIXED_TYPE; + p->fifosize = DW_UART_CPR_FIFO_SIZE(reg); + up->capabilities = UART_CAP_FIFO; + } + + if (reg & DW_UART_CPR_AFCE_MODE) + up->capabilities |= UART_CAP_AFE; + + if (reg & DW_UART_CPR_SIR_MODE) + up->capabilities |= UART_CAP_IRDA; +} +EXPORT_SYMBOL_GPL(dw8250_setup_port); diff --git a/drivers/tty/serial/8250/8250_dwlib.h b/drivers/tty/serial/8250/8250_dwlib.h new file mode 100644 index 000000000000..87a4db2a8aba --- /dev/null +++ b/drivers/tty/serial/8250/8250_dwlib.h @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Synopsys DesignWare 8250 library header file. */ + +#include + +#include "8250.h" + +struct dw8250_port_data { + /* Port properties */ + int line; + + /* DMA operations */ + struct uart_8250_dma dma; + + /* Hardware configuration */ + u8 dlf_size; +}; + +void dw8250_setup_port(struct uart_port *p); diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index edd6dfe055bf..597eb9d16f21 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -19,6 +19,7 @@ #include #include #include +#include #include @@ -36,6 +37,8 @@ #define UART_EXAR_INT0 0x80 #define UART_EXAR_8XMODE 0x88 /* 8X sampling rate select */ +#define UART_EXAR_SLEEP 0x8b /* Sleep mode */ +#define UART_EXAR_DVID 0x8d /* Device identification */ #define UART_EXAR_FCTR 0x08 /* Feature Control Register */ #define UART_FCTR_EXAR_IRDA 0x10 /* IrDa data encode select */ @@ -127,18 +130,95 @@ struct exar8250 { int line[0]; }; +static void exar_pm(struct uart_port *port, unsigned int state, unsigned int old) +{ + /* + * Exar UARTs have a SLEEP register that enables or disables each UART + * to enter sleep mode separately. On the XR17V35x the register + * is accessible to each UART at the UART_EXAR_SLEEP offset, but + * the UART channel may only write to the corresponding bit. + */ + serial_port_out(port, UART_EXAR_SLEEP, state ? 0xff : 0); +} + +/* + * XR17V35x UARTs have an extra fractional divisor register (DLD) + * Calculate divisor with extra 4-bit fractional portion + */ +static unsigned int xr17v35x_get_divisor(struct uart_port *p, unsigned int baud, + unsigned int *frac) +{ + unsigned int quot_16; + + quot_16 = DIV_ROUND_CLOSEST(p->uartclk, baud); + *frac = quot_16 & 0x0f; + + return quot_16 >> 4; +} + +static void xr17v35x_set_divisor(struct uart_port *p, unsigned int baud, + unsigned int quot, unsigned int quot_frac) +{ + serial8250_do_set_divisor(p, baud, quot, quot_frac); + + /* Preserve bits not related to baudrate; DLD[7:4]. */ + quot_frac |= serial_port_in(p, 0x2) & 0xf0; + serial_port_out(p, 0x2, quot_frac); +} + +static void exar_shutdown(struct uart_port *port) +{ + unsigned char lsr; + bool tx_complete = 0; + struct uart_8250_port *up = up_to_u8250p(port); + struct circ_buf *xmit = &port->state->xmit; + int i = 0; + + do { + lsr = serial_in(up, UART_LSR); + if (lsr & (UART_LSR_TEMT | UART_LSR_THRE)) + tx_complete = 1; + else + tx_complete = 0; + usleep_range(1000, 1100); + } while (!uart_circ_empty(xmit) && !tx_complete && i++ < 1000); + + serial8250_do_shutdown(port); +} + static int default_setup(struct exar8250 *priv, struct pci_dev *pcidev, int idx, unsigned int offset, struct uart_8250_port *port) { const struct exar8250_board *board = priv->board; unsigned int bar = 0; + unsigned char status; port->port.iotype = UPIO_MEM; port->port.mapbase = pci_resource_start(pcidev, bar) + offset; port->port.membase = priv->virt + offset; port->port.regshift = board->reg_shift; + /* + * XR17V35x UARTs have an extra divisor register, DLD that gets enabled + * with when DLAB is set which will cause the device to incorrectly match + * and assign port type to PORT_16650. The EFR for this UART is found + * at offset 0x09. Instead check the Deice ID (DVID) register + * for a 2, 4 or 8 port UART. + */ + status = readb(port->port.membase + UART_EXAR_DVID); + if (status == 0x82 || status == 0x84 || status == 0x88) { + port->port.type = PORT_XR17V35X; + + port->port.get_divisor = xr17v35x_get_divisor; + port->port.set_divisor = xr17v35x_set_divisor; + } else { + port->port.type = PORT_XR17D15X; + } + + port->port.pm = exar_pm; + port->port.shutdown = exar_shutdown; + return 0; } @@ -434,6 +514,16 @@ static void pci_xr17v35x_exit(struct pci_dev *pcidev) port->port.private_data = NULL; } +static inline void exar_misc_clear(struct exar8250 *priv) +{ + /* Clear all PCI interrupts by reading INT0. No effect on IIR */ + readb(priv->virt + UART_EXAR_INT0); + + /* Clear INT0 for Expansion Interface slave ports, too */ + if (priv->board->num_ports > 8) + readb(priv->virt + 0x2000 + UART_EXAR_INT0); +} + /* * These Exar UARTs have an extra interrupt indicator that could fire for a * few interrupts that are not presented/cleared through IIR. One of which is @@ -445,14 +535,7 @@ static void pci_xr17v35x_exit(struct pci_dev *pcidev) */ static irqreturn_t exar_misc_handler(int irq, void *data) { - struct exar8250 *priv = data; - - /* Clear all PCI interrupts by reading INT0. No effect on IIR */ - readb(priv->virt + UART_EXAR_INT0); - - /* Clear INT0 for Expansion Interface slave ports, too */ - if (priv->board->num_ports > 8) - readb(priv->virt + 0x2000 + UART_EXAR_INT0); + exar_misc_clear(data); return IRQ_HANDLED; } @@ -478,9 +561,7 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) nr_ports = board->num_ports ? board->num_ports : pcidev->device & 0x0f; - priv = devm_kzalloc(&pcidev->dev, sizeof(*priv) + - sizeof(unsigned int) * nr_ports, - GFP_KERNEL); + priv = devm_kzalloc(&pcidev->dev, struct_size(priv, line, nr_ports), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -496,8 +577,7 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) return rc; memset(&uart, 0, sizeof(uart)); - uart.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ - | UPF_EXAR_EFR; + uart.port.flags = UPF_SHARE_IRQ | UPF_EXAR_EFR | UPF_FIXED_TYPE | UPF_FIXED_PORT; uart.port.irq = pci_irq_vector(pcidev, 0); uart.port.dev = &pcidev->dev; @@ -506,6 +586,9 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) if (rc) return rc; + /* Clear interrupts */ + exar_misc_clear(priv); + for (i = 0; i < nr_ports && i < maxnr; i++) { rc = board->setup(priv, pcidev, &uart, i); if (rc) { @@ -561,10 +644,11 @@ static int __maybe_unused exar_suspend(struct device *dev) static int __maybe_unused exar_resume(struct device *dev) { - struct pci_dev *pcidev = to_pci_dev(dev); - struct exar8250 *priv = pci_get_drvdata(pcidev); + struct exar8250 *priv = dev_get_drvdata(dev); unsigned int i; + exar_misc_clear(priv); + for (i = 0; i < priv->nr; i++) if (priv->line[i] >= 0) serial8250_resume_port(priv->line[i]); diff --git a/drivers/tty/serial/8250/8250_lpc18xx.c b/drivers/tty/serial/8250/8250_lpc18xx.c index eddf119374e1..570e25d6f37e 100644 --- a/drivers/tty/serial/8250/8250_lpc18xx.c +++ b/drivers/tty/serial/8250/8250_lpc18xx.c @@ -106,10 +106,8 @@ static int lpc18xx_serial_probe(struct platform_device *pdev) int irq, ret; irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "irq not found"); + if (irq < 0) return irq; - } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { diff --git a/drivers/tty/serial/8250/8250_lpss.c b/drivers/tty/serial/8250/8250_lpss.c index 53ca9ba6ab4b..5f72ef3ea574 100644 --- a/drivers/tty/serial/8250/8250_lpss.c +++ b/drivers/tty/serial/8250/8250_lpss.c @@ -14,7 +14,7 @@ #include #include -#include "8250.h" +#include "8250_dwlib.h" #define PCI_DEVICE_ID_INTEL_QRK_UARTx 0x0936 @@ -24,6 +24,13 @@ #define PCI_DEVICE_ID_INTEL_BSW_UART1 0x228a #define PCI_DEVICE_ID_INTEL_BSW_UART2 0x228c +#define PCI_DEVICE_ID_INTEL_EHL_UART0 0x4b96 +#define PCI_DEVICE_ID_INTEL_EHL_UART1 0x4b97 +#define PCI_DEVICE_ID_INTEL_EHL_UART2 0x4b98 +#define PCI_DEVICE_ID_INTEL_EHL_UART3 0x4b99 +#define PCI_DEVICE_ID_INTEL_EHL_UART4 0x4b9a +#define PCI_DEVICE_ID_INTEL_EHL_UART5 0x4b9b + #define PCI_DEVICE_ID_INTEL_BDW_UART1 0x9ce3 #define PCI_DEVICE_ID_INTEL_BDW_UART2 0x9ce4 @@ -48,21 +55,25 @@ struct lpss8250_board { }; struct lpss8250 { - int line; + struct dw8250_port_data data; struct lpss8250_board *board; /* DMA parameters */ - struct uart_8250_dma dma; struct dw_dma_chip dma_chip; struct dw_dma_slave dma_param; u8 dma_maxburst; }; +static inline struct lpss8250 *to_lpss8250(struct dw8250_port_data *data) +{ + return container_of(data, struct lpss8250, data); +} + static void byt_set_termios(struct uart_port *p, struct ktermios *termios, struct ktermios *old) { unsigned int baud = tty_termios_baud_rate(termios); - struct lpss8250 *lpss = p->private_data; + struct lpss8250 *lpss = to_lpss8250(p->private_data); unsigned long fref = lpss->board->freq, fuart = baud * 16; unsigned long w = BIT(15) - 1; unsigned long m, n; @@ -109,7 +120,6 @@ static unsigned int byt_get_mctrl(struct uart_port *port) static int byt_serial_setup(struct lpss8250 *lpss, struct uart_port *port) { struct dw_dma_slave *param = &lpss->dma_param; - struct uart_8250_port *up = up_to_u8250p(port); struct pci_dev *pdev = to_pci_dev(port->dev); unsigned int dma_devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0); struct pci_dev *dma_dev = pci_get_slot(pdev->bus, dma_devfn); @@ -135,10 +145,6 @@ static int byt_serial_setup(struct lpss8250 *lpss, struct uart_port *port) param->m_master = 0; param->p_master = 1; - /* TODO: Detect FIFO size automaticaly for DesignWare 8250 */ - port->fifosize = 64; - up->tx_loadsz = 64; - lpss->dma_maxburst = 16; port->set_termios = byt_set_termios; @@ -163,16 +169,19 @@ static const struct dw_dma_platform_data qrk_serial_dma_pdata = { static void qrk_serial_setup_dma(struct lpss8250 *lpss, struct uart_port *port) { - struct uart_8250_dma *dma = &lpss->dma; + struct uart_8250_dma *dma = &lpss->data.dma; struct dw_dma_chip *chip = &lpss->dma_chip; struct dw_dma_slave *param = &lpss->dma_param; struct pci_dev *pdev = to_pci_dev(port->dev); int ret; + chip->pdata = &qrk_serial_dma_pdata; chip->dev = &pdev->dev; + chip->id = pdev->devfn; chip->irq = pci_irq_vector(pdev, 0); chip->regs = pci_ioremap_bar(pdev, 1); - chip->pdata = &qrk_serial_dma_pdata; + if (!chip->regs) + return; /* Falling back to PIO mode if DMA probing fails */ ret = dw_dma_probe(chip); @@ -195,11 +204,15 @@ static void qrk_serial_setup_dma(struct lpss8250 *lpss, struct uart_port *port) static void qrk_serial_exit_dma(struct lpss8250 *lpss) { + struct dw_dma_chip *chip = &lpss->dma_chip; struct dw_dma_slave *param = &lpss->dma_param; if (!param->dma_dev) return; - dw_dma_remove(&lpss->dma_chip); + + dw_dma_remove(chip); + + pci_iounmap(to_pci_dev(chip->dev), chip->regs); } #else /* CONFIG_SERIAL_8250_DMA */ static void qrk_serial_setup_dma(struct lpss8250 *lpss, struct uart_port *port) {} @@ -241,7 +254,7 @@ static bool lpss8250_dma_filter(struct dma_chan *chan, void *param) static int lpss8250_dma_setup(struct lpss8250 *lpss, struct uart_8250_port *port) { - struct uart_8250_dma *dma = &lpss->dma; + struct uart_8250_dma *dma = &lpss->data.dma; struct dw_dma_slave *rx_param, *tx_param; struct device *dev = port->port.dev; @@ -290,7 +303,7 @@ static int lpss8250_probe(struct pci_dev *pdev, const struct pci_device_id *id) uart.port.dev = &pdev->dev; uart.port.irq = pdev->irq; - uart.port.private_data = lpss; + uart.port.private_data = &lpss->data; uart.port.type = PORT_16550A; uart.port.iotype = UPIO_MEM; uart.port.regshift = 2; @@ -306,6 +319,8 @@ static int lpss8250_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) return ret; + dw8250_setup_port(&uart.port); + ret = lpss8250_dma_setup(lpss, &uart); if (ret) goto err_exit; @@ -314,7 +329,7 @@ static int lpss8250_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret < 0) goto err_exit; - lpss->line = ret; + lpss->data.line = ret; pci_set_drvdata(pdev, lpss); return 0; @@ -329,7 +344,7 @@ static void lpss8250_remove(struct pci_dev *pdev) { struct lpss8250 *lpss = pci_get_drvdata(pdev); - serial8250_unregister_port(lpss->line); + serial8250_unregister_port(lpss->data.line); if (lpss->board->exit) lpss->board->exit(lpss); @@ -341,6 +356,11 @@ static const struct lpss8250_board byt_board = { .setup = byt_serial_setup, }; +static const struct lpss8250_board ehl_board = { + .freq = 200000000, + .base_baud = 12500000, +}; + static const struct lpss8250_board qrk_board = { .freq = 44236800, .base_baud = 2764800, @@ -348,17 +368,21 @@ static const struct lpss8250_board qrk_board = { .exit = qrk_serial_exit, }; -#define LPSS_DEVICE(id, board) { PCI_VDEVICE(INTEL, id), (kernel_ulong_t)&board } - static const struct pci_device_id pci_ids[] = { - LPSS_DEVICE(PCI_DEVICE_ID_INTEL_QRK_UARTx, qrk_board), - LPSS_DEVICE(PCI_DEVICE_ID_INTEL_BYT_UART1, byt_board), - LPSS_DEVICE(PCI_DEVICE_ID_INTEL_BYT_UART2, byt_board), - LPSS_DEVICE(PCI_DEVICE_ID_INTEL_BSW_UART1, byt_board), - LPSS_DEVICE(PCI_DEVICE_ID_INTEL_BSW_UART2, byt_board), - LPSS_DEVICE(PCI_DEVICE_ID_INTEL_BDW_UART1, byt_board), - LPSS_DEVICE(PCI_DEVICE_ID_INTEL_BDW_UART2, byt_board), - { }, + { PCI_DEVICE_DATA(INTEL, QRK_UARTx, &qrk_board) }, + { PCI_DEVICE_DATA(INTEL, EHL_UART0, &ehl_board) }, + { PCI_DEVICE_DATA(INTEL, EHL_UART1, &ehl_board) }, + { PCI_DEVICE_DATA(INTEL, EHL_UART2, &ehl_board) }, + { PCI_DEVICE_DATA(INTEL, EHL_UART3, &ehl_board) }, + { PCI_DEVICE_DATA(INTEL, EHL_UART4, &ehl_board) }, + { PCI_DEVICE_DATA(INTEL, EHL_UART5, &ehl_board) }, + { PCI_DEVICE_DATA(INTEL, BYT_UART1, &byt_board) }, + { PCI_DEVICE_DATA(INTEL, BYT_UART2, &byt_board) }, + { PCI_DEVICE_DATA(INTEL, BSW_UART1, &byt_board) }, + { PCI_DEVICE_DATA(INTEL, BSW_UART2, &byt_board) }, + { PCI_DEVICE_DATA(INTEL, BDW_UART1, &byt_board) }, + { PCI_DEVICE_DATA(INTEL, BDW_UART2, &byt_board) }, + { } }; MODULE_DEVICE_TABLE(pci, pci_ids); diff --git a/drivers/tty/serial/8250/8250_moxa.c b/drivers/tty/serial/8250/8250_moxa.c deleted file mode 100644 index 1ee4cd94d4fa..000000000000 --- a/drivers/tty/serial/8250/8250_moxa.c +++ /dev/null @@ -1,155 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * 8250_moxa.c - MOXA Smartio/Industio MUE multiport serial driver. - * - * Author: Mathieu OTHACEHE - */ - -#include -#include - -#include "8250.h" - -#define PCI_DEVICE_ID_MOXA_CP102E 0x1024 -#define PCI_DEVICE_ID_MOXA_CP102EL 0x1025 -#define PCI_DEVICE_ID_MOXA_CP104EL_A 0x1045 -#define PCI_DEVICE_ID_MOXA_CP114EL 0x1144 -#define PCI_DEVICE_ID_MOXA_CP116E_A_A 0x1160 -#define PCI_DEVICE_ID_MOXA_CP116E_A_B 0x1161 -#define PCI_DEVICE_ID_MOXA_CP118EL_A 0x1182 -#define PCI_DEVICE_ID_MOXA_CP118E_A_I 0x1183 -#define PCI_DEVICE_ID_MOXA_CP132EL 0x1322 -#define PCI_DEVICE_ID_MOXA_CP134EL_A 0x1342 -#define PCI_DEVICE_ID_MOXA_CP138E_A 0x1381 -#define PCI_DEVICE_ID_MOXA_CP168EL_A 0x1683 - -#define MOXA_BASE_BAUD 921600 -#define MOXA_UART_OFFSET 0x200 -#define MOXA_BASE_BAR 1 - -struct moxa8250_board { - unsigned int num_ports; - int line[0]; -}; - -enum { - moxa8250_2p = 0, - moxa8250_4p, - moxa8250_8p -}; - -static struct moxa8250_board moxa8250_boards[] = { - [moxa8250_2p] = { .num_ports = 2}, - [moxa8250_4p] = { .num_ports = 4}, - [moxa8250_8p] = { .num_ports = 8}, -}; - -static int moxa8250_probe(struct pci_dev *pdev, const struct pci_device_id *id) -{ - struct uart_8250_port uart; - struct moxa8250_board *brd; - void __iomem *ioaddr; - resource_size_t baseaddr; - unsigned int i, nr_ports; - unsigned int offset; - int ret; - - brd = &moxa8250_boards[id->driver_data]; - nr_ports = brd->num_ports; - - ret = pcim_enable_device(pdev); - if (ret) - return ret; - - brd = devm_kzalloc(&pdev->dev, sizeof(struct moxa8250_board) + - sizeof(unsigned int) * nr_ports, GFP_KERNEL); - if (!brd) - return -ENOMEM; - brd->num_ports = nr_ports; - - memset(&uart, 0, sizeof(struct uart_8250_port)); - - uart.port.dev = &pdev->dev; - uart.port.irq = pdev->irq; - uart.port.uartclk = MOXA_BASE_BAUD * 16; - uart.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ; - - baseaddr = pci_resource_start(pdev, MOXA_BASE_BAR); - ioaddr = pcim_iomap(pdev, MOXA_BASE_BAR, 0); - if (!ioaddr) - return -ENOMEM; - - for (i = 0; i < nr_ports; i++) { - - /* - * MOXA Smartio MUE boards with 4 ports have - * a different offset for port #3 - */ - if (nr_ports == 4 && i == 3) - offset = 7 * MOXA_UART_OFFSET; - else - offset = i * MOXA_UART_OFFSET; - - uart.port.iotype = UPIO_MEM; - uart.port.iobase = 0; - uart.port.mapbase = baseaddr + offset; - uart.port.membase = ioaddr + offset; - uart.port.regshift = 0; - - dev_dbg(&pdev->dev, "Setup PCI port: port %lx, irq %d, type %d\n", - uart.port.iobase, uart.port.irq, uart.port.iotype); - - brd->line[i] = serial8250_register_8250_port(&uart); - if (brd->line[i] < 0) { - dev_err(&pdev->dev, - "Couldn't register serial port %lx, irq %d, type %d, error %d\n", - uart.port.iobase, uart.port.irq, - uart.port.iotype, brd->line[i]); - break; - } - } - - pci_set_drvdata(pdev, brd); - return 0; -} - -static void moxa8250_remove(struct pci_dev *pdev) -{ - struct moxa8250_board *brd = pci_get_drvdata(pdev); - unsigned int i; - - for (i = 0; i < brd->num_ports; i++) - serial8250_unregister_port(brd->line[i]); -} - -#define MOXA_DEVICE(id, data) { PCI_VDEVICE(MOXA, id), (kernel_ulong_t)data } - -static const struct pci_device_id pci_ids[] = { - MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP102E, moxa8250_2p), - MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP102EL, moxa8250_2p), - MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP104EL_A, moxa8250_4p), - MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP114EL, moxa8250_4p), - MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP116E_A_A, moxa8250_8p), - MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP116E_A_B, moxa8250_8p), - MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP118EL_A, moxa8250_8p), - MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP118E_A_I, moxa8250_8p), - MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP132EL, moxa8250_2p), - MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP134EL_A, moxa8250_4p), - MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP138E_A, moxa8250_8p), - MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP168EL_A, moxa8250_8p), - {0} -}; -MODULE_DEVICE_TABLE(pci, pci_ids); - -static struct pci_driver moxa8250_pci_driver = { - .name = "8250_moxa", - .id_table = pci_ids, - .probe = moxa8250_probe, - .remove = moxa8250_remove, -}; - -module_pci_driver(moxa8250_pci_driver); - -MODULE_AUTHOR("Mathieu OTHACEHE"); -MODULE_DESCRIPTION("MOXA SmartIO MUE driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 3ef65cbd2478..c68e2b3a1634 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -1234,7 +1234,16 @@ static int omap8250_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, true); pm_runtime_use_autosuspend(&pdev->dev); - pm_runtime_set_autosuspend_delay(&pdev->dev, -1); + + /* + * Disable runtime PM until autosuspend delay unless specifically + * enabled by the user via sysfs. This is the historic way to + * prevent an unsafe default policy with lossy characters on wake-up. + * For serdev devices this is not needed, the policy can be managed by + * the serdev driver. + */ + if (!of_get_available_child_count(pdev->dev.of_node)) + pm_runtime_set_autosuspend_delay(&pdev->dev, -1); pm_runtime_irq_safe(&pdev->dev); pm_runtime_enable(&pdev->dev); diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 7f740b37700b..6adbadd6a56a 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -43,6 +43,11 @@ struct pci_serial_quirk { void (*exit)(struct pci_dev *dev); }; +struct f815xxa_data { + spinlock_t lock; + int idx; +}; + #define PCI_NUM_BAR_RESOURCES 6 struct serial_private { @@ -53,6 +58,16 @@ struct serial_private { int line[0]; }; +static const struct pci_device_id pci_use_msi[] = { + { PCI_DEVICE_SUB(PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900, + 0xA000, 0x1000) }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9912, + 0xA000, 0x1000) }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9922, + 0xA000, 0x1000) }, + { } +}; + static int pci_default_setup(struct serial_private*, const struct pciserial_board*, struct uart_8250_port *, int); @@ -730,8 +745,16 @@ static int pci_ni8430_init(struct pci_dev *dev) } /* UART Port Control Register */ -#define NI8430_PORTCON 0x0f -#define NI8430_PORTCON_TXVR_ENABLE (1 << 3) +#define NI16550_PCR_OFFSET 0x0f +#define NI16550_PCR_RS422 0x00 +#define NI16550_PCR_ECHO_RS485 0x01 +#define NI16550_PCR_DTR_RS485 0x02 +#define NI16550_PCR_AUTO_RS485 0x03 +#define NI16550_PCR_WIRE_MODE_MASK 0x03 +#define NI16550_PCR_TXVR_ENABLE_BIT BIT(3) +#define NI16550_PCR_RS485_TERMINATION_BIT BIT(6) +#define NI16550_ACR_DTR_AUTO_DTR (0x2 << 3) +#define NI16550_ACR_DTR_MANUAL_DTR (0x0 << 3) static int pci_ni8430_setup(struct serial_private *priv, @@ -753,14 +776,117 @@ pci_ni8430_setup(struct serial_private *priv, return -ENOMEM; /* enable the transceiver */ - writeb(readb(p + offset + NI8430_PORTCON) | NI8430_PORTCON_TXVR_ENABLE, - p + offset + NI8430_PORTCON); + writeb(readb(p + offset + NI16550_PCR_OFFSET) | NI16550_PCR_TXVR_ENABLE_BIT, + p + offset + NI16550_PCR_OFFSET); iounmap(p); return setup_port(priv, port, bar, offset, board->reg_shift); } +static int pci_ni8431_config_rs485(struct uart_port *port, + struct serial_rs485 *rs485) +{ + u8 pcr, acr; + struct uart_8250_port *up; + + up = container_of(port, struct uart_8250_port, port); + acr = up->acr; + pcr = port->serial_in(port, NI16550_PCR_OFFSET); + pcr &= ~NI16550_PCR_WIRE_MODE_MASK; + + if (rs485->flags & SER_RS485_ENABLED) { + /* RS-485 */ + if ((rs485->flags & SER_RS485_RX_DURING_TX) && + (rs485->flags & SER_RS485_RTS_ON_SEND)) { + dev_dbg(port->dev, "Invalid 2-wire mode\n"); + return -EINVAL; + } + + if (rs485->flags & SER_RS485_RX_DURING_TX) { + /* Echo */ + dev_vdbg(port->dev, "2-wire DTR with echo\n"); + pcr |= NI16550_PCR_ECHO_RS485; + acr |= NI16550_ACR_DTR_MANUAL_DTR; + } else { + /* Auto or DTR */ + if (rs485->flags & SER_RS485_RTS_ON_SEND) { + /* Auto */ + dev_vdbg(port->dev, "2-wire Auto\n"); + pcr |= NI16550_PCR_AUTO_RS485; + acr |= NI16550_ACR_DTR_AUTO_DTR; + } else { + /* DTR-controlled */ + /* No Echo */ + dev_vdbg(port->dev, "2-wire DTR no echo\n"); + pcr |= NI16550_PCR_DTR_RS485; + acr |= NI16550_ACR_DTR_MANUAL_DTR; + } + } + } else { + /* RS-422 */ + dev_vdbg(port->dev, "4-wire\n"); + pcr |= NI16550_PCR_RS422; + acr |= NI16550_ACR_DTR_MANUAL_DTR; + } + + dev_dbg(port->dev, "write pcr: 0x%08x\n", pcr); + port->serial_out(port, NI16550_PCR_OFFSET, pcr); + + up->acr = acr; + port->serial_out(port, UART_SCR, UART_ACR); + port->serial_out(port, UART_ICR, up->acr); + + /* Update the cache. */ + port->rs485 = *rs485; + + return 0; +} + +static int pci_ni8431_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *uart, int idx) +{ + u8 pcr, acr; + struct pci_dev *dev = priv->dev; + void __iomem *addr; + unsigned int bar, offset = board->first_offset; + + if (idx >= board->num_ports) + return 1; + + bar = FL_GET_BASE(board->flags); + offset += idx * board->uart_offset; + + addr = pci_ioremap_bar(dev, bar); + if (!addr) + return -ENOMEM; + + /* enable the transceiver */ + writeb(readb(addr + NI16550_PCR_OFFSET) | NI16550_PCR_TXVR_ENABLE_BIT, + addr + NI16550_PCR_OFFSET); + + pcr = readb(addr + NI16550_PCR_OFFSET); + pcr &= ~NI16550_PCR_WIRE_MODE_MASK; + + /* set wire mode to default RS-422 */ + pcr |= NI16550_PCR_RS422; + acr = NI16550_ACR_DTR_MANUAL_DTR; + + /* write port configuration to register */ + writeb(pcr, addr + NI16550_PCR_OFFSET); + + /* access and write to UART acr register */ + writeb(UART_ACR, addr + UART_SCR); + writeb(acr, addr + UART_ICR); + + uart->port.rs485_config = &pci_ni8431_config_rs485; + + iounmap(addr); + + return setup_port(priv, uart, bar, offset, board->reg_shift); +} + static int pci_netmos_9900_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) @@ -1596,6 +1722,77 @@ static int pci_fintek_init(struct pci_dev *dev) return max_port; } +static void f815xxa_mem_serial_out(struct uart_port *p, int offset, int value) +{ + struct f815xxa_data *data = p->private_data; + unsigned long flags; + + spin_lock_irqsave(&data->lock, flags); + writeb(value, p->membase + offset); + readb(p->membase + UART_SCR); /* Dummy read for flush pcie tx queue */ + spin_unlock_irqrestore(&data->lock, flags); +} + +static int pci_fintek_f815xxa_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) +{ + struct pci_dev *pdev = priv->dev; + struct f815xxa_data *data; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->idx = idx; + spin_lock_init(&data->lock); + + port->port.private_data = data; + port->port.iotype = UPIO_MEM; + port->port.flags |= UPF_IOREMAP; + port->port.mapbase = pci_resource_start(pdev, 0) + 8 * idx; + port->port.serial_out = f815xxa_mem_serial_out; + + return 0; +} + +static int pci_fintek_f815xxa_init(struct pci_dev *dev) +{ + u32 max_port, i; + int config_base; + + if (!(pci_resource_flags(dev, 0) & IORESOURCE_MEM)) + return -ENODEV; + + switch (dev->device) { + case 0x1204: /* 4 ports */ + case 0x1208: /* 8 ports */ + max_port = dev->device & 0xff; + break; + case 0x1212: /* 12 ports */ + max_port = 12; + break; + default: + return -EINVAL; + } + + /* Set to mmio decode */ + pci_write_config_byte(dev, 0x209, 0x40); + + for (i = 0; i < max_port; ++i) { + /* UART0 configuration offset start from 0x2A0 */ + config_base = 0x2A0 + 0x08 * i; + + /* Select 128-byte FIFO and 8x FIFO threshold */ + pci_write_config_byte(dev, config_base + 0x01, 0x33); + + /* Enable UART I/O port */ + pci_write_config_byte(dev, config_base + 0, 0x01); + } + + return max_port; +} + static int skip_tx_en_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) @@ -1692,6 +1889,46 @@ pci_wch_ch38x_setup(struct serial_private *priv, return pci_default_setup(priv, board, port, idx); } +static int +pci_sunix_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) +{ + int bar; + int offset; + + port->port.flags |= UPF_FIXED_TYPE; + port->port.type = PORT_SUNIX; + + if (idx < 4) { + bar = 0; + offset = idx * board->uart_offset; + } else { + bar = 1; + idx -= 4; + idx = div_s64_rem(idx, 4, &offset); + offset = idx * 64 + offset * board->uart_offset; + } + + return setup_port(priv, port, bar, offset, 0); +} + +static int +pci_moxa_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) +{ + unsigned int bar = FL_GET_BASE(board->flags); + int offset; + + if (board->num_ports == 4 && idx == 3) + offset = 7 * board->uart_offset; + else + offset = idx * board->uart_offset; + + return setup_port(priv, port, bar, offset, 0); +} + #define PCI_VENDOR_ID_SBSMODULARIO 0x124B #define PCI_SUBVENDOR_ID_SBSMODULARIO 0x124B #define PCI_DEVICE_ID_OCTPRO 0x0001 @@ -1786,7 +2023,28 @@ pci_wch_ch38x_setup(struct serial_private *priv, #define PCI_DEVICE_ID_ACCESIO_PCIE_COM_8SM 0x10E9 #define PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM 0x11D8 +#define PCIE_DEVICE_ID_NI_PXIE8430_2328 0x74C2 +#define PCIE_DEVICE_ID_NI_PXIE8430_23216 0x74C1 +#define PCI_DEVICE_ID_NI_PXI8431_4852 0x7081 +#define PCI_DEVICE_ID_NI_PXI8431_4854 0x70DE +#define PCI_DEVICE_ID_NI_PXI8431_4858 0x70E3 +#define PCI_DEVICE_ID_NI_PXI8433_4852 0x70E9 +#define PCI_DEVICE_ID_NI_PXI8433_4854 0x70ED +#define PCIE_DEVICE_ID_NI_PXIE8431_4858 0x74C4 +#define PCIE_DEVICE_ID_NI_PXIE8431_48516 0x74C3 +#define PCI_DEVICE_ID_MOXA_CP102E 0x1024 +#define PCI_DEVICE_ID_MOXA_CP102EL 0x1025 +#define PCI_DEVICE_ID_MOXA_CP104EL_A 0x1045 +#define PCI_DEVICE_ID_MOXA_CP114EL 0x1144 +#define PCI_DEVICE_ID_MOXA_CP116E_A_A 0x1160 +#define PCI_DEVICE_ID_MOXA_CP116E_A_B 0x1161 +#define PCI_DEVICE_ID_MOXA_CP118EL_A 0x1182 +#define PCI_DEVICE_ID_MOXA_CP118E_A_I 0x1183 +#define PCI_DEVICE_ID_MOXA_CP132EL 0x1322 +#define PCI_DEVICE_ID_MOXA_CP134EL_A 0x1342 +#define PCI_DEVICE_ID_MOXA_CP138E_A 0x1381 +#define PCI_DEVICE_ID_MOXA_CP168EL_A 0x1683 /* Unknown vendors/cards - this should not be in linux/pci_ids.h */ #define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584 @@ -2011,6 +2269,87 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .setup = pci_ni8430_setup, .exit = pci_ni8430_exit, }, + { + .vendor = PCI_VENDOR_ID_NI, + .device = PCIE_DEVICE_ID_NI_PXIE8430_2328, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_ni8430_init, + .setup = pci_ni8430_setup, + .exit = pci_ni8430_exit, + }, + { + .vendor = PCI_VENDOR_ID_NI, + .device = PCIE_DEVICE_ID_NI_PXIE8430_23216, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_ni8430_init, + .setup = pci_ni8430_setup, + .exit = pci_ni8430_exit, + }, + { + .vendor = PCI_VENDOR_ID_NI, + .device = PCI_DEVICE_ID_NI_PXI8431_4852, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_ni8430_init, + .setup = pci_ni8431_setup, + .exit = pci_ni8430_exit, + }, + { + .vendor = PCI_VENDOR_ID_NI, + .device = PCI_DEVICE_ID_NI_PXI8431_4854, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_ni8430_init, + .setup = pci_ni8431_setup, + .exit = pci_ni8430_exit, + }, + { + .vendor = PCI_VENDOR_ID_NI, + .device = PCI_DEVICE_ID_NI_PXI8431_4858, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_ni8430_init, + .setup = pci_ni8431_setup, + .exit = pci_ni8430_exit, + }, + { + .vendor = PCI_VENDOR_ID_NI, + .device = PCI_DEVICE_ID_NI_PXI8433_4852, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_ni8430_init, + .setup = pci_ni8431_setup, + .exit = pci_ni8430_exit, + }, + { + .vendor = PCI_VENDOR_ID_NI, + .device = PCI_DEVICE_ID_NI_PXI8433_4854, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_ni8430_init, + .setup = pci_ni8431_setup, + .exit = pci_ni8430_exit, + }, + { + .vendor = PCI_VENDOR_ID_NI, + .device = PCIE_DEVICE_ID_NI_PXIE8431_4858, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_ni8430_init, + .setup = pci_ni8431_setup, + .exit = pci_ni8430_exit, + }, + { + .vendor = PCI_VENDOR_ID_NI, + .device = PCIE_DEVICE_ID_NI_PXIE8431_48516, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_ni8430_init, + .setup = pci_ni8431_setup, + .exit = pci_ni8430_exit, + }, /* Quatech */ { .vendor = PCI_VENDOR_ID_QUATECH, @@ -2289,21 +2628,14 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .setup = pci_timedia_setup, }, /* - * SUNIX (Timedia) cards - * Do not "probe" for these cards as there is at least one combination - * card that should be handled by parport_pc that doesn't match the - * rule in pci_timedia_probe. - * It is part number is MIO5079A but its subdevice ID is 0x0102. - * There are some boards with part number SER5037AL that report - * subdevice ID 0x0002. + * Sunix PCI serial boards */ { .vendor = PCI_VENDOR_ID_SUNIX, .device = PCI_DEVICE_ID_SUNIX_1999, .subvendor = PCI_VENDOR_ID_SUNIX, .subdevice = PCI_ANY_ID, - .init = pci_timedia_init, - .setup = pci_timedia_setup, + .setup = pci_sunix_setup, }, /* * Xircom cards @@ -2563,6 +2895,40 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .setup = pci_fintek_setup, .init = pci_fintek_init, }, + /* + * MOXA + */ + { + .vendor = PCI_VENDOR_ID_MOXA, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_moxa_setup, + }, + { + .vendor = 0x1c29, + .device = 0x1204, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_fintek_f815xxa_setup, + .init = pci_fintek_f815xxa_init, + }, + { + .vendor = 0x1c29, + .device = 0x1208, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_fintek_f815xxa_setup, + .init = pci_fintek_f815xxa_init, + }, + { + .vendor = 0x1c29, + .device = 0x1212, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_fintek_f815xxa_setup, + .init = pci_fintek_f815xxa_init, + }, /* * Default "match everything" terminator entry @@ -2740,6 +3106,13 @@ enum pci_board_num_t { pbn_ni8430_4, pbn_ni8430_8, pbn_ni8430_16, + pbn_ni8430_pxie_8, + pbn_ni8430_pxie_16, + pbn_ni8431_2, + pbn_ni8431_4, + pbn_ni8431_8, + pbn_ni8431_pxie_8, + pbn_ni8431_pxie_16, pbn_ADDIDATA_PCIe_1_3906250, pbn_ADDIDATA_PCIe_2_3906250, pbn_ADDIDATA_PCIe_4_3906250, @@ -2751,12 +3124,23 @@ enum pci_board_num_t { pbn_fintek_4, pbn_fintek_8, pbn_fintek_12, + pbn_fintek_F81504A, + pbn_fintek_F81508A, + pbn_fintek_F81512A, pbn_wch382_2, pbn_wch384_4, pbn_pericom_PI7C9X7951, pbn_pericom_PI7C9X7952, pbn_pericom_PI7C9X7954, pbn_pericom_PI7C9X7958, + pbn_sunix_pci_1s, + pbn_sunix_pci_2s, + pbn_sunix_pci_4s, + pbn_sunix_pci_8s, + pbn_sunix_pci_16s, + pbn_moxa8250_2p, + pbn_moxa8250_4p, + pbn_moxa8250_8p, }; /* @@ -3381,6 +3765,55 @@ static struct pciserial_board pci_boards[] = { .uart_offset = 0x10, .first_offset = 0x800, }, + [pbn_ni8430_pxie_16] = { + .flags = FL_BASE0, + .num_ports = 16, + .base_baud = 3125000, + .uart_offset = 0x10, + .first_offset = 0x800, + }, + [pbn_ni8430_pxie_8] = { + .flags = FL_BASE0, + .num_ports = 8, + .base_baud = 3125000, + .uart_offset = 0x10, + .first_offset = 0x800, + }, + [pbn_ni8431_8] = { + .flags = FL_BASE0, + .num_ports = 8, + .base_baud = 3686400, + .uart_offset = 0x10, + .first_offset = 0x800, + }, + [pbn_ni8431_4] = { + .flags = FL_BASE0, + .num_ports = 4, + .base_baud = 3686400, + .uart_offset = 0x10, + .first_offset = 0x800, + }, + [pbn_ni8431_2] = { + .flags = FL_BASE0, + .num_ports = 2, + .base_baud = 3686400, + .uart_offset = 0x10, + .first_offset = 0x800, + }, + [pbn_ni8431_pxie_16] = { + .flags = FL_BASE0, + .num_ports = 16, + .base_baud = 3125000, + .uart_offset = 0x10, + .first_offset = 0x800, + }, + [pbn_ni8431_pxie_8] = { + .flags = FL_BASE0, + .num_ports = 8, + .base_baud = 3125000, + .uart_offset = 0x10, + .first_offset = 0x800, + }, /* * ADDI-DATA GmbH PCI-Express communication cards */ @@ -3453,6 +3886,21 @@ static struct pciserial_board pci_boards[] = { .base_baud = 115200, .first_offset = 0x40, }, + [pbn_fintek_F81504A] = { + .num_ports = 4, + .uart_offset = 8, + .base_baud = 115200, + }, + [pbn_fintek_F81508A] = { + .num_ports = 8, + .uart_offset = 8, + .base_baud = 115200, + }, + [pbn_fintek_F81512A] = { + .num_ports = 12, + .uart_offset = 8, + .base_baud = 115200, + }, [pbn_wch382_2] = { .flags = FL_BASE0, .num_ports = 2, @@ -3494,6 +3942,49 @@ static struct pciserial_board pci_boards[] = { .base_baud = 921600, .uart_offset = 0x8, }, + [pbn_sunix_pci_1s] = { + .num_ports = 1, + .base_baud = 921600, + .uart_offset = 0x8, + }, + [pbn_sunix_pci_2s] = { + .num_ports = 2, + .base_baud = 921600, + .uart_offset = 0x8, + }, + [pbn_sunix_pci_4s] = { + .num_ports = 4, + .base_baud = 921600, + .uart_offset = 0x8, + }, + [pbn_sunix_pci_8s] = { + .num_ports = 8, + .base_baud = 921600, + .uart_offset = 0x8, + }, + [pbn_sunix_pci_16s] = { + .num_ports = 16, + .base_baud = 921600, + .uart_offset = 0x8, + }, + [pbn_moxa8250_2p] = { + .flags = FL_BASE1, + .num_ports = 2, + .base_baud = 921600, + .uart_offset = 0x200, + }, + [pbn_moxa8250_4p] = { + .flags = FL_BASE1, + .num_ports = 4, + .base_baud = 921600, + .uart_offset = 0x200, + }, + [pbn_moxa8250_8p] = { + .flags = FL_BASE1, + .num_ports = 8, + .base_baud = 921600, + .uart_offset = 0x200, + }, }; static const struct pci_device_id blacklist[] = { @@ -3507,20 +3998,6 @@ static const struct pci_device_id blacklist[] = { { PCI_DEVICE(0x4348, 0x5053), }, /* WCH CH353 1S1P */ { PCI_DEVICE(0x1c00, 0x3250), }, /* WCH CH382 2S1P */ - /* Moxa Smartio MUE boards handled by 8250_moxa */ - { PCI_VDEVICE(MOXA, 0x1024), }, - { PCI_VDEVICE(MOXA, 0x1025), }, - { PCI_VDEVICE(MOXA, 0x1045), }, - { PCI_VDEVICE(MOXA, 0x1144), }, - { PCI_VDEVICE(MOXA, 0x1160), }, - { PCI_VDEVICE(MOXA, 0x1161), }, - { PCI_VDEVICE(MOXA, 0x1182), }, - { PCI_VDEVICE(MOXA, 0x1183), }, - { PCI_VDEVICE(MOXA, 0x1322), }, - { PCI_VDEVICE(MOXA, 0x1342), }, - { PCI_VDEVICE(MOXA, 0x1381), }, - { PCI_VDEVICE(MOXA, 0x1683), }, - /* Intel platforms with MID UART */ { PCI_VDEVICE(INTEL, 0x081b), }, { PCI_VDEVICE(INTEL, 0x081c), }, @@ -3688,7 +4165,22 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board) memset(&uart, 0, sizeof(uart)); uart.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ; uart.port.uartclk = board->base_baud * 16; - uart.port.irq = get_pci_irq(dev, board); + + if (pci_match_id(pci_use_msi, dev)) { + dev_dbg(&dev->dev, "Using MSI(-X) interrupts\n"); + pci_set_master(dev); + rc = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_ALL_TYPES); + } else { + dev_dbg(&dev->dev, "Using legacy interrupts\n"); + rc = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_LEGACY); + } + if (rc < 0) { + kfree(priv); + priv = ERR_PTR(rc); + goto err_deinit; + } + + uart.port.irq = pci_irq_vector(dev, 0); uart.port.dev = &dev->dev; for (i = 0; i < nr_ports; i++) { @@ -3859,8 +4351,7 @@ static void pciserial_remove_one(struct pci_dev *dev) #ifdef CONFIG_PM_SLEEP static int pciserial_suspend_one(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct serial_private *priv = pci_get_drvdata(pdev); + struct serial_private *priv = dev_get_drvdata(dev); if (priv) pciserial_suspend_ports(priv); @@ -4532,17 +5023,29 @@ static const struct pci_device_id serial_pci_tbl[] = { pbn_b0_bt_1_921600 }, /* - * SUNIX (TIMEDIA) + * Sunix PCI serial boards */ { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, - PCI_VENDOR_ID_SUNIX, PCI_ANY_ID, - PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xffff00, - pbn_b0_bt_1_921600 }, - + PCI_VENDOR_ID_SUNIX, 0x0001, 0, 0, + pbn_sunix_pci_1s }, { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, - PCI_VENDOR_ID_SUNIX, PCI_ANY_ID, - PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00, - pbn_b0_bt_1_921600 }, + PCI_VENDOR_ID_SUNIX, 0x0002, 0, 0, + pbn_sunix_pci_2s }, + { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, + PCI_VENDOR_ID_SUNIX, 0x0004, 0, 0, + pbn_sunix_pci_4s }, + { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, + PCI_VENDOR_ID_SUNIX, 0x0084, 0, 0, + pbn_sunix_pci_4s }, + { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, + PCI_VENDOR_ID_SUNIX, 0x0008, 0, 0, + pbn_sunix_pci_8s }, + { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, + PCI_VENDOR_ID_SUNIX, 0x0088, 0, 0, + pbn_sunix_pci_8s }, + { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, + PCI_VENDOR_ID_SUNIX, 0x0010, 0, 0, + pbn_sunix_pci_16s }, /* * AFAVLAB serial card, from Harald Welte @@ -5064,6 +5567,73 @@ static const struct pci_device_id serial_pci_tbl[] = { { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8432_2324, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_ni8430_4 }, + { PCI_VENDOR_ID_NI, PCIE_DEVICE_ID_NI_PXIE8430_2328, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_ni8430_pxie_8 }, + { PCI_VENDOR_ID_NI, PCIE_DEVICE_ID_NI_PXIE8430_23216, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_ni8430_pxie_16 }, + { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8431_4852, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_ni8431_2 }, + { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8431_4854, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_ni8431_4 }, + { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8431_4858, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_ni8431_8 }, + { PCI_VENDOR_ID_NI, PCIE_DEVICE_ID_NI_PXIE8431_4858, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_ni8431_pxie_8 }, + { PCI_VENDOR_ID_NI, PCIE_DEVICE_ID_NI_PXIE8431_48516, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_ni8431_pxie_16 }, + { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8433_4852, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_ni8431_2 }, + { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8433_4854, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_ni8431_4 }, + + /* + * MOXA + */ + { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102E, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_moxa8250_2p }, + { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102EL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_moxa8250_2p }, + { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104EL_A, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_moxa8250_4p }, + { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP114EL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_moxa8250_4p }, + { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP116E_A_A, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_moxa8250_8p }, + { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP116E_A_B, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_moxa8250_8p }, + { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP118EL_A, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_moxa8250_8p }, + { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP118E_A_I, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_moxa8250_8p }, + { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP132EL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_moxa8250_2p }, + { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP134EL_A, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_moxa8250_4p }, + { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP138E_A, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_moxa8250_8p }, + { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP168EL_A, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_moxa8250_8p }, /* * ADDI-DATA GmbH communication cards @@ -5292,6 +5862,9 @@ static const struct pci_device_id serial_pci_tbl[] = { { PCI_DEVICE(0x1c29, 0x1104), .driver_data = pbn_fintek_4 }, { PCI_DEVICE(0x1c29, 0x1108), .driver_data = pbn_fintek_8 }, { PCI_DEVICE(0x1c29, 0x1112), .driver_data = pbn_fintek_12 }, + { PCI_DEVICE(0x1c29, 0x1204), .driver_data = pbn_fintek_F81504A }, + { PCI_DEVICE(0x1c29, 0x1208), .driver_data = pbn_fintek_F81508A }, + { PCI_DEVICE(0x1c29, 0x1212), .driver_data = pbn_fintek_F81512A }, /* MKS Tenta SCOM-080x serial cards */ { PCI_DEVICE(0x1601, 0x0800), .driver_data = pbn_b0_4_1250000 }, diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c index dfca33141fcc..de90d681b64c 100644 --- a/drivers/tty/serial/8250/8250_pnp.c +++ b/drivers/tty/serial/8250/8250_pnp.c @@ -498,10 +498,9 @@ static void serial_pnp_remove(struct pnp_dev *dev) serial8250_unregister_port(line - 1); } -#ifdef CONFIG_PM -static int serial_pnp_suspend(struct pnp_dev *dev, pm_message_t state) +static int __maybe_unused serial_pnp_suspend(struct device *dev) { - long line = (long)pnp_get_drvdata(dev); + long line = (long)dev_get_drvdata(dev); if (!line) return -ENODEV; @@ -509,26 +508,25 @@ static int serial_pnp_suspend(struct pnp_dev *dev, pm_message_t state) return 0; } -static int serial_pnp_resume(struct pnp_dev *dev) +static int __maybe_unused serial_pnp_resume(struct device *dev) { - long line = (long)pnp_get_drvdata(dev); + long line = (long)dev_get_drvdata(dev); if (!line) return -ENODEV; serial8250_resume_port(line - 1); return 0; } -#else -#define serial_pnp_suspend NULL -#define serial_pnp_resume NULL -#endif /* CONFIG_PM */ + +static SIMPLE_DEV_PM_OPS(serial_pnp_pm_ops, serial_pnp_suspend, serial_pnp_resume); static struct pnp_driver serial_pnp_driver = { .name = "serial", .probe = serial_pnp_probe, .remove = serial_pnp_remove, - .suspend = serial_pnp_suspend, - .resume = serial_pnp_resume, + .driver = { + .pm = &serial_pnp_pm_ops, + }, .id_table = pnp_dev_table, }; diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index c1cec808571b..8407166610ce 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -40,13 +40,6 @@ #include "8250.h" -/* - * These are definitions for the Exar XR17V35X and XR17(C|D)15X - */ -#define UART_EXAR_INT0 0x80 -#define UART_EXAR_SLEEP 0x8b /* Sleep mode */ -#define UART_EXAR_DVID 0x8d /* Device identification */ - /* Nuvoton NPCM timeout register */ #define UART_NPCM_TOR 7 #define UART_NPCM_TOIE BIT(7) /* Timeout Interrupt Enable */ @@ -308,6 +301,14 @@ static const struct serial8250_config uart_config[] = { .rxtrig_bytes = {1, 4, 8, 14}, .flags = UART_CAP_FIFO, }, + [PORT_SUNIX] = { + .name = "Sunix", + .fifo_size = 128, + .tx_loadsz = 128, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .rxtrig_bytes = {1, 32, 64, 112}, + .flags = UART_CAP_FIFO | UART_CAP_SLEEP, + }, }; /* Uart divisor latch read */ @@ -709,19 +710,8 @@ EXPORT_SYMBOL_GPL(serial8250_rpm_put_tx); static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) { unsigned char lcr = 0, efr = 0; - /* - * Exar UARTs have a SLEEP register that enables or disables - * each UART to enter sleep mode separately. On the XR17V35x the - * register is accessible to each UART at the UART_EXAR_SLEEP - * offset but the UART channel may only write to the corresponding - * bit. - */ + serial8250_rpm_get(p); - if ((p->port.type == PORT_XR17V35X) || - (p->port.type == PORT_XR17D15X)) { - serial_out(p, UART_EXAR_SLEEP, sleep ? 0xff : 0); - goto out; - } if (p->capabilities & UART_CAP_SLEEP) { if (p->capabilities & UART_CAP_EFR) { @@ -738,7 +728,7 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) serial_out(p, UART_LCR, lcr); } } -out: + serial8250_rpm_put(p); } @@ -1011,27 +1001,6 @@ static void autoconfig_16550a(struct uart_8250_port *up) up->port.type = PORT_16550A; up->capabilities |= UART_CAP_FIFO; - /* - * XR17V35x UARTs have an extra divisor register, DLD - * that gets enabled with when DLAB is set which will - * cause the device to incorrectly match and assign - * port type to PORT_16650. The EFR for this UART is - * found at offset 0x09. Instead check the Deice ID (DVID) - * register for a 2, 4 or 8 port UART. - */ - if (up->port.flags & UPF_EXAR_EFR) { - status1 = serial_in(up, UART_EXAR_DVID); - if (status1 == 0x82 || status1 == 0x84 || status1 == 0x88) { - DEBUG_AUTOCONF("Exar XR17V35x "); - up->port.type = PORT_XR17V35X; - up->capabilities |= UART_CAP_AFE | UART_CAP_EFR | - UART_CAP_SLEEP; - - return; - } - - } - /* * Check for presence of the EFR when DLAB is set. * Only ST16C650V1 UARTs pass this test. @@ -1170,18 +1139,6 @@ static void autoconfig_16550a(struct uart_8250_port *up) } serial_out(up, UART_IER, iersave); - /* - * Exar uarts have EFR in a weird location - */ - if (up->port.flags & UPF_EXAR_EFR) { - DEBUG_AUTOCONF("Exar XR17D15x "); - up->port.type = PORT_XR17D15X; - up->capabilities |= UART_CAP_AFE | UART_CAP_EFR | - UART_CAP_SLEEP; - - return; - } - /* * We distinguish between 16550A and U6 16550A by counting * how many bytes are in the FIFO. @@ -2184,8 +2141,6 @@ int serial8250_do_startup(struct uart_port *port) serial_port_in(port, UART_RX); serial_port_in(port, UART_IIR); serial_port_in(port, UART_MSR); - if ((port->type == PORT_XR17V35X) || (port->type == PORT_XR17D15X)) - serial_port_in(port, UART_EXAR_INT0); /* * At this point, there's no way the LSR could still be 0xff; @@ -2343,8 +2298,6 @@ dont_test_tx_en: serial_port_in(port, UART_RX); serial_port_in(port, UART_IIR); serial_port_in(port, UART_MSR); - if ((port->type == PORT_XR17V35X) || (port->type == PORT_XR17D15X)) - serial_port_in(port, UART_EXAR_INT0); up->lsr_saved_flags = 0; up->msr_saved_flags = 0; @@ -2453,23 +2406,6 @@ static void serial8250_shutdown(struct uart_port *port) serial8250_do_shutdown(port); } -/* - * XR17V35x UARTs have an extra fractional divisor register (DLD) - * Calculate divisor with extra 4-bit fractional portion - */ -static unsigned int xr17v35x_get_divisor(struct uart_8250_port *up, - unsigned int baud, - unsigned int *frac) -{ - struct uart_port *port = &up->port; - unsigned int quot_16; - - quot_16 = DIV_ROUND_CLOSEST(port->uartclk, baud); - *frac = quot_16 & 0x0f; - - return quot_16 >> 4; -} - /* Nuvoton NPCM UARTs have a custom divisor calculation */ static unsigned int npcm_get_divisor(struct uart_8250_port *up, unsigned int baud) @@ -2497,8 +2433,6 @@ static unsigned int serial8250_do_get_divisor(struct uart_port *port, else if ((port->flags & UPF_MAGIC_MULTIPLIER) && baud == (port->uartclk/8)) quot = 0x8002; - else if (up->port.type == PORT_XR17V35X) - quot = xr17v35x_get_divisor(up, baud, frac); else if (up->port.type == PORT_NPCM) quot = npcm_get_divisor(up, baud); else @@ -2585,13 +2519,6 @@ void serial8250_do_set_divisor(struct uart_port *port, unsigned int baud, serial_port_out(port, UART_LCR, up->lcr | UART_LCR_DLAB); serial_dl_write(up, quot); - - /* XR17V35x UARTs have an extra fractional divisor register (DLD) */ - if (up->port.type == PORT_XR17V35X) { - /* Preserve bits not related to baudrate; DLD[7:4]. */ - quot_frac |= serial_port_in(port, 0x2) & 0xf0; - serial_port_out(port, 0x2, quot_frac); - } } EXPORT_SYMBOL_GPL(serial8250_do_set_divisor); diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c index 164ba133437a..e0b73a5402db 100644 --- a/drivers/tty/serial/8250/8250_uniphier.c +++ b/drivers/tty/serial/8250/8250_uniphier.c @@ -176,10 +176,8 @@ static int uniphier_uart_probe(struct platform_device *pdev) return -ENOMEM; irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(dev, "failed to get IRQ number\n"); + if (irq < 0) return irq; - } priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index 509f6a3bb9ff..7ef60f8b6e2c 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -314,6 +314,9 @@ config SERIAL_8250_RSA If you don't have such card, or if unsure, say N. +config SERIAL_8250_DWLIB + bool + config SERIAL_8250_ACORN tristate "Acorn expansion card serial port support" depends on ARCH_ACORN && SERIAL_8250 @@ -354,6 +357,7 @@ config SERIAL_8250_FSL config SERIAL_8250_DW tristate "Support for Synopsys DesignWare 8250 quirks" depends on SERIAL_8250 + select SERIAL_8250_DWLIB help Selecting this option will enable handling of the extra features present in the Synopsys DesignWare APB UART. @@ -440,6 +444,7 @@ config SERIAL_8250_LPSS default SERIAL_8250 depends on SERIAL_8250 && PCI depends on X86 || COMPILE_TEST + select SERIAL_8250_DWLIB select DW_DMAC_CORE if SERIAL_8250_DMA select DW_DMAC_PCI if (SERIAL_8250_DMA && X86_INTEL_LPSS) select RATIONAL @@ -463,16 +468,6 @@ config SERIAL_8250_MID present on the UART found on Intel Medfield SOC and various other Intel platforms. -config SERIAL_8250_MOXA - tristate "MOXA SmartIO MUE support" - depends on SERIAL_8250 && PCI - help - Say Y here if you have a Moxa SmartIO MUE multiport serial card. - If unsure, say N. - - This driver can also be built as a module. The module will be called - 8250_moxa. If you want to do that, say M here. - config SERIAL_8250_PXA tristate "PXA serial port support" depends on SERIAL_8250 diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile index 18751bc63a84..08c1d8117506 100644 --- a/drivers/tty/serial/8250/Makefile +++ b/drivers/tty/serial/8250/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_SERIAL_8250) += 8250.o 8250_base.o 8250-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o 8250_base-y := 8250_port.o 8250_base-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o +8250_base-$(CONFIG_SERIAL_8250_DWLIB) += 8250_dwlib.o 8250_base-$(CONFIG_SERIAL_8250_FINTEK) += 8250_fintek.o obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o @@ -34,7 +35,6 @@ obj-$(CONFIG_SERIAL_8250_UNIPHIER) += 8250_uniphier.o obj-$(CONFIG_SERIAL_8250_INGENIC) += 8250_ingenic.o obj-$(CONFIG_SERIAL_8250_LPSS) += 8250_lpss.o obj-$(CONFIG_SERIAL_8250_MID) += 8250_mid.o -obj-$(CONFIG_SERIAL_8250_MOXA) += 8250_moxa.o obj-$(CONFIG_SERIAL_8250_PXA) += 8250_pxa.o obj-$(CONFIG_SERIAL_OF_PLATFORM) += 8250_of.o diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 514169eb1859..4789b5d62f63 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -197,23 +197,6 @@ config SERIAL_KGDB_NMI If unsure, say N. -config SERIAL_KS8695 - bool "Micrel KS8695 (Centaur) serial port support" - depends on ARCH_KS8695 - select SERIAL_CORE - help - This selects the Micrel Centaur KS8695 UART. Say Y here. - -config SERIAL_KS8695_CONSOLE - bool "Support for console on KS8695 (Centaur) serial port" - depends on SERIAL_KS8695=y - select SERIAL_CORE_CONSOLE - help - Say Y here if you wish to use a KS8695 (Centaur) UART as the - system console (the system console is the device which - receives all kernel messages and warnings and which allows - logins in single user mode). - config SERIAL_MESON tristate "Meson serial port support" depends on ARCH_MESON @@ -1407,6 +1390,22 @@ config SERIAL_FSL_LPUART_CONSOLE If you have enabled the lpuart serial port on the Freescale SoCs, you can make it the console by answering Y to this option. +config SERIAL_FSL_LINFLEXUART + tristate "Freescale linflexuart serial port support" + depends on PRINTK + select SERIAL_CORE + help + Support for the on-chip linflexuart on some Freescale SOCs. + +config SERIAL_FSL_LINFLEXUART_CONSOLE + bool "Console on Freescale linflexuart serial port" + depends on SERIAL_FSL_LINFLEXUART=y + select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON + help + If you have enabled the linflexuart serial port on the Freescale + SoCs, you can make it the console by answering Y to this option. + config SERIAL_CONEXANT_DIGICOLOR tristate "Conexant Digicolor CX92xxx USART serial port support" depends on OF diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index d2f44879384e..863f47056539 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -56,7 +56,6 @@ obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o obj-$(CONFIG_SERIAL_MSM) += msm_serial.o obj-$(CONFIG_SERIAL_QCOM_GENI) += qcom_geni_serial.o -obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o obj-$(CONFIG_SERIAL_ST_ASC) += st-asc.o @@ -78,6 +77,7 @@ obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o obj-$(CONFIG_SERIAL_ARC) += arc_uart.o obj-$(CONFIG_SERIAL_RP2) += rp2.o obj-$(CONFIG_SERIAL_FSL_LPUART) += fsl_lpuart.o +obj-$(CONFIG_SERIAL_FSL_LINFLEXUART) += fsl_linflexuart.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 diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 5921a33b2a07..3a7d1a66f79c 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -2718,11 +2718,8 @@ static int sbsa_uart_probe(struct platform_device *pdev) return -ENOMEM; ret = platform_get_irq(pdev, 0); - if (ret < 0) { - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "cannot obtain irq\n"); + if (ret < 0) return ret; - } uap->port.irq = ret; #ifdef CONFIG_ACPI_SPCR_TABLE diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 0b4f36905321..a8dc8af83f39 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -294,50 +294,6 @@ static void atmel_tasklet_schedule(struct atmel_uart_port *atmel_port, tasklet_schedule(t); } -static unsigned int atmel_get_lines_status(struct uart_port *port) -{ - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - unsigned int status, ret = 0; - - status = atmel_uart_readl(port, ATMEL_US_CSR); - - mctrl_gpio_get(atmel_port->gpios, &ret); - - if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios, - UART_GPIO_CTS))) { - if (ret & TIOCM_CTS) - status &= ~ATMEL_US_CTS; - else - status |= ATMEL_US_CTS; - } - - if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios, - UART_GPIO_DSR))) { - if (ret & TIOCM_DSR) - status &= ~ATMEL_US_DSR; - else - status |= ATMEL_US_DSR; - } - - if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios, - UART_GPIO_RI))) { - if (ret & TIOCM_RI) - status &= ~ATMEL_US_RI; - else - status |= ATMEL_US_RI; - } - - if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios, - UART_GPIO_DCD))) { - if (ret & TIOCM_CD) - status &= ~ATMEL_US_DCD; - else - status |= ATMEL_US_DCD; - } - - return status; -} - /* Enable or disable the rs485 support */ static int atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf) @@ -1400,7 +1356,6 @@ atmel_handle_transmit(struct uart_port *port, unsigned int pending) atmel_port->hd_start_rx = false; atmel_start_rx(port); - return; } atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx); @@ -1454,7 +1409,7 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id) spin_lock(&atmel_port->lock_suspended); do { - status = atmel_get_lines_status(port); + status = atmel_uart_readl(port, ATMEL_US_CSR); mask = atmel_uart_readl(port, ATMEL_US_IMR); pending = status & mask; if (!pending) @@ -2003,7 +1958,7 @@ static int atmel_startup(struct uart_port *port) } /* Save current CSR for comparison in atmel_tasklet_func() */ - atmel_port->irq_status_prev = atmel_get_lines_status(port); + atmel_port->irq_status_prev = atmel_uart_readl(port, ATMEL_US_CSR); /* * Finally, enable the serial port @@ -2888,7 +2843,7 @@ static int atmel_serial_probe(struct platform_device *pdev) struct atmel_uart_port *atmel_port; struct device_node *np = pdev->dev.parent->of_node; void *data; - int ret = -ENODEV; + int ret; bool rs485_enabled; BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1)); diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c new file mode 100644 index 000000000000..68d74f2b5106 --- /dev/null +++ b/drivers/tty/serial/fsl_linflexuart.c @@ -0,0 +1,937 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Freescale linflexuart serial port driver + * + * Copyright 2012-2016 Freescale Semiconductor, Inc. + * Copyright 2017-2018 NXP + */ + +#if defined(CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE) && \ + defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* All registers are 32-bit width */ + +#define LINCR1 0x0000 /* LIN control register */ +#define LINIER 0x0004 /* LIN interrupt enable register */ +#define LINSR 0x0008 /* LIN status register */ +#define LINESR 0x000C /* LIN error status register */ +#define UARTCR 0x0010 /* UART mode control register */ +#define UARTSR 0x0014 /* UART mode status register */ +#define LINTCSR 0x0018 /* LIN timeout control status register */ +#define LINOCR 0x001C /* LIN output compare register */ +#define LINTOCR 0x0020 /* LIN timeout control register */ +#define LINFBRR 0x0024 /* LIN fractional baud rate register */ +#define LINIBRR 0x0028 /* LIN integer baud rate register */ +#define LINCFR 0x002C /* LIN checksum field register */ +#define LINCR2 0x0030 /* LIN control register 2 */ +#define BIDR 0x0034 /* Buffer identifier register */ +#define BDRL 0x0038 /* Buffer data register least significant */ +#define BDRM 0x003C /* Buffer data register most significant */ +#define IFER 0x0040 /* Identifier filter enable register */ +#define IFMI 0x0044 /* Identifier filter match index */ +#define IFMR 0x0048 /* Identifier filter mode register */ +#define GCR 0x004C /* Global control register */ +#define UARTPTO 0x0050 /* UART preset timeout register */ +#define UARTCTO 0x0054 /* UART current timeout register */ + +/* + * Register field definitions + */ + +#define LINFLEXD_LINCR1_INIT BIT(0) +#define LINFLEXD_LINCR1_MME BIT(4) +#define LINFLEXD_LINCR1_BF BIT(7) + +#define LINFLEXD_LINSR_LINS_INITMODE BIT(12) +#define LINFLEXD_LINSR_LINS_MASK (0xF << 12) + +#define LINFLEXD_LINIER_SZIE BIT(15) +#define LINFLEXD_LINIER_OCIE BIT(14) +#define LINFLEXD_LINIER_BEIE BIT(13) +#define LINFLEXD_LINIER_CEIE BIT(12) +#define LINFLEXD_LINIER_HEIE BIT(11) +#define LINFLEXD_LINIER_FEIE BIT(8) +#define LINFLEXD_LINIER_BOIE BIT(7) +#define LINFLEXD_LINIER_LSIE BIT(6) +#define LINFLEXD_LINIER_WUIE BIT(5) +#define LINFLEXD_LINIER_DBFIE BIT(4) +#define LINFLEXD_LINIER_DBEIETOIE BIT(3) +#define LINFLEXD_LINIER_DRIE BIT(2) +#define LINFLEXD_LINIER_DTIE BIT(1) +#define LINFLEXD_LINIER_HRIE BIT(0) + +#define LINFLEXD_UARTCR_OSR_MASK (0xF << 24) +#define LINFLEXD_UARTCR_OSR(uartcr) (((uartcr) \ + & LINFLEXD_UARTCR_OSR_MASK) >> 24) + +#define LINFLEXD_UARTCR_ROSE BIT(23) + +#define LINFLEXD_UARTCR_RFBM BIT(9) +#define LINFLEXD_UARTCR_TFBM BIT(8) +#define LINFLEXD_UARTCR_WL1 BIT(7) +#define LINFLEXD_UARTCR_PC1 BIT(6) + +#define LINFLEXD_UARTCR_RXEN BIT(5) +#define LINFLEXD_UARTCR_TXEN BIT(4) +#define LINFLEXD_UARTCR_PC0 BIT(3) + +#define LINFLEXD_UARTCR_PCE BIT(2) +#define LINFLEXD_UARTCR_WL0 BIT(1) +#define LINFLEXD_UARTCR_UART BIT(0) + +#define LINFLEXD_UARTSR_SZF BIT(15) +#define LINFLEXD_UARTSR_OCF BIT(14) +#define LINFLEXD_UARTSR_PE3 BIT(13) +#define LINFLEXD_UARTSR_PE2 BIT(12) +#define LINFLEXD_UARTSR_PE1 BIT(11) +#define LINFLEXD_UARTSR_PE0 BIT(10) +#define LINFLEXD_UARTSR_RMB BIT(9) +#define LINFLEXD_UARTSR_FEF BIT(8) +#define LINFLEXD_UARTSR_BOF BIT(7) +#define LINFLEXD_UARTSR_RPS BIT(6) +#define LINFLEXD_UARTSR_WUF BIT(5) +#define LINFLEXD_UARTSR_4 BIT(4) + +#define LINFLEXD_UARTSR_TO BIT(3) + +#define LINFLEXD_UARTSR_DRFRFE BIT(2) +#define LINFLEXD_UARTSR_DTFTFF BIT(1) +#define LINFLEXD_UARTSR_NF BIT(0) +#define LINFLEXD_UARTSR_PE (LINFLEXD_UARTSR_PE0 |\ + LINFLEXD_UARTSR_PE1 |\ + LINFLEXD_UARTSR_PE2 |\ + LINFLEXD_UARTSR_PE3) + +#define LINFLEX_LDIV_MULTIPLIER (16) + +#define DRIVER_NAME "fsl-linflexuart" +#define DEV_NAME "ttyLF" +#define UART_NR 4 + +#define EARLYCON_BUFFER_INITIAL_CAP 8 + +#define PREINIT_DELAY 2000 /* us */ + +static const struct of_device_id linflex_dt_ids[] = { + { + .compatible = "fsl,s32v234-linflexuart", + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, linflex_dt_ids); + +#ifdef CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE +static struct uart_port *earlycon_port; +static bool linflex_earlycon_same_instance; +static DEFINE_SPINLOCK(init_lock); +static bool during_init; + +static struct { + char *content; + unsigned int len, cap; +} earlycon_buf; +#endif + +static void linflex_stop_tx(struct uart_port *port) +{ + unsigned long ier; + + ier = readl(port->membase + LINIER); + ier &= ~(LINFLEXD_LINIER_DTIE); + writel(ier, port->membase + LINIER); +} + +static void linflex_stop_rx(struct uart_port *port) +{ + unsigned long ier; + + ier = readl(port->membase + LINIER); + writel(ier & ~LINFLEXD_LINIER_DRIE, port->membase + LINIER); +} + +static inline void linflex_transmit_buffer(struct uart_port *sport) +{ + struct circ_buf *xmit = &sport->state->xmit; + unsigned char c; + unsigned long status; + + while (!uart_circ_empty(xmit)) { + c = xmit->buf[xmit->tail]; + writeb(c, sport->membase + BDRL); + + /* Waiting for data transmission completed. */ + while (((status = readl(sport->membase + UARTSR)) & + LINFLEXD_UARTSR_DTFTFF) != + LINFLEXD_UARTSR_DTFTFF) + ; + + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + sport->icount.tx++; + + writel(status | LINFLEXD_UARTSR_DTFTFF, + sport->membase + UARTSR); + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(sport); + + if (uart_circ_empty(xmit)) + linflex_stop_tx(sport); +} + +static void linflex_start_tx(struct uart_port *port) +{ + unsigned long ier; + + linflex_transmit_buffer(port); + ier = readl(port->membase + LINIER); + writel(ier | LINFLEXD_LINIER_DTIE, port->membase + LINIER); +} + +static irqreturn_t linflex_txint(int irq, void *dev_id) +{ + struct uart_port *sport = dev_id; + struct circ_buf *xmit = &sport->state->xmit; + unsigned long flags; + unsigned long status; + + spin_lock_irqsave(&sport->lock, flags); + + if (sport->x_char) { + writeb(sport->x_char, sport->membase + BDRL); + + /* waiting for data transmission completed */ + while (((status = readl(sport->membase + UARTSR)) & + LINFLEXD_UARTSR_DTFTFF) != LINFLEXD_UARTSR_DTFTFF) + ; + + writel(status | LINFLEXD_UARTSR_DTFTFF, + sport->membase + UARTSR); + + goto out; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(sport)) { + linflex_stop_tx(sport); + goto out; + } + + linflex_transmit_buffer(sport); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(sport); + +out: + spin_unlock_irqrestore(&sport->lock, flags); + return IRQ_HANDLED; +} + +static irqreturn_t linflex_rxint(int irq, void *dev_id) +{ + struct uart_port *sport = dev_id; + unsigned int flg; + struct tty_port *port = &sport->state->port; + unsigned long flags, status; + unsigned char rx; + + spin_lock_irqsave(&sport->lock, flags); + + status = readl(sport->membase + UARTSR); + while (status & LINFLEXD_UARTSR_RMB) { + rx = readb(sport->membase + BDRM); + flg = TTY_NORMAL; + sport->icount.rx++; + + if (status & (LINFLEXD_UARTSR_BOF | LINFLEXD_UARTSR_SZF | + LINFLEXD_UARTSR_FEF | LINFLEXD_UARTSR_PE)) { + if (status & LINFLEXD_UARTSR_SZF) + status |= LINFLEXD_UARTSR_SZF; + if (status & LINFLEXD_UARTSR_BOF) + status |= LINFLEXD_UARTSR_BOF; + if (status & LINFLEXD_UARTSR_FEF) + status |= LINFLEXD_UARTSR_FEF; + if (status & LINFLEXD_UARTSR_PE) + status |= LINFLEXD_UARTSR_PE; + } + + writel(status | LINFLEXD_UARTSR_RMB | LINFLEXD_UARTSR_DRFRFE, + sport->membase + UARTSR); + status = readl(sport->membase + UARTSR); + + if (uart_handle_sysrq_char(sport, (unsigned char)rx)) + continue; + +#ifdef SUPPORT_SYSRQ + sport->sysrq = 0; +#endif + tty_insert_flip_char(port, rx, flg); + } + + spin_unlock_irqrestore(&sport->lock, flags); + + tty_flip_buffer_push(port); + + return IRQ_HANDLED; +} + +static irqreturn_t linflex_int(int irq, void *dev_id) +{ + struct uart_port *sport = dev_id; + unsigned long status; + + status = readl(sport->membase + UARTSR); + + if (status & LINFLEXD_UARTSR_DRFRFE) + linflex_rxint(irq, dev_id); + if (status & LINFLEXD_UARTSR_DTFTFF) + linflex_txint(irq, dev_id); + + return IRQ_HANDLED; +} + +/* return TIOCSER_TEMT when transmitter is not busy */ +static unsigned int linflex_tx_empty(struct uart_port *port) +{ + unsigned long status; + + status = readl(port->membase + UARTSR) & LINFLEXD_UARTSR_DTFTFF; + + return status ? TIOCSER_TEMT : 0; +} + +static unsigned int linflex_get_mctrl(struct uart_port *port) +{ + return 0; +} + +static void linflex_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +} + +static void linflex_break_ctl(struct uart_port *port, int break_state) +{ +} + +static void linflex_setup_watermark(struct uart_port *sport) +{ + unsigned long cr, ier, cr1; + + /* Disable transmission/reception */ + ier = readl(sport->membase + LINIER); + ier &= ~(LINFLEXD_LINIER_DRIE | LINFLEXD_LINIER_DTIE); + writel(ier, sport->membase + LINIER); + + cr = readl(sport->membase + UARTCR); + cr &= ~(LINFLEXD_UARTCR_RXEN | LINFLEXD_UARTCR_TXEN); + writel(cr, sport->membase + UARTCR); + + /* Enter initialization mode by setting INIT bit */ + + /* set the Linflex in master mode and activate by-pass filter */ + cr1 = LINFLEXD_LINCR1_BF | LINFLEXD_LINCR1_MME + | LINFLEXD_LINCR1_INIT; + writel(cr1, sport->membase + LINCR1); + + /* wait for init mode entry */ + while ((readl(sport->membase + LINSR) + & LINFLEXD_LINSR_LINS_MASK) + != LINFLEXD_LINSR_LINS_INITMODE) + ; + + /* + * UART = 0x1; - Linflex working in UART mode + * TXEN = 0x1; - Enable transmission of data now + * RXEn = 0x1; - Receiver enabled + * WL0 = 0x1; - 8 bit data + * PCE = 0x0; - No parity + */ + + /* set UART bit to allow writing other bits */ + writel(LINFLEXD_UARTCR_UART, sport->membase + UARTCR); + + cr = (LINFLEXD_UARTCR_RXEN | LINFLEXD_UARTCR_TXEN | + LINFLEXD_UARTCR_WL0 | LINFLEXD_UARTCR_UART); + + writel(cr, sport->membase + UARTCR); + + cr1 &= ~(LINFLEXD_LINCR1_INIT); + + writel(cr1, sport->membase + LINCR1); + + ier = readl(sport->membase + LINIER); + ier |= LINFLEXD_LINIER_DRIE; + ier |= LINFLEXD_LINIER_DTIE; + + writel(ier, sport->membase + LINIER); +} + +static int linflex_startup(struct uart_port *port) +{ + int ret = 0; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + + linflex_setup_watermark(port); + + spin_unlock_irqrestore(&port->lock, flags); + + ret = devm_request_irq(port->dev, port->irq, linflex_int, 0, + DRIVER_NAME, port); + + return ret; +} + +static void linflex_shutdown(struct uart_port *port) +{ + unsigned long ier; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + + /* disable interrupts */ + ier = readl(port->membase + LINIER); + ier &= ~(LINFLEXD_LINIER_DRIE | LINFLEXD_LINIER_DTIE); + writel(ier, port->membase + LINIER); + + spin_unlock_irqrestore(&port->lock, flags); + + devm_free_irq(port->dev, port->irq, port); +} + +static void +linflex_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + unsigned long flags; + unsigned long cr, old_cr, cr1; + unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; + + cr = readl(port->membase + UARTCR); + old_cr = cr; + + /* Enter initialization mode by setting INIT bit */ + cr1 = readl(port->membase + LINCR1); + cr1 |= LINFLEXD_LINCR1_INIT; + writel(cr1, port->membase + LINCR1); + + /* wait for init mode entry */ + while ((readl(port->membase + LINSR) + & LINFLEXD_LINSR_LINS_MASK) + != LINFLEXD_LINSR_LINS_INITMODE) + ; + + /* + * only support CS8 and CS7, and for CS7 must enable PE. + * supported mode: + * - (7,e/o,1) + * - (8,n,1) + * - (8,e/o,1) + */ + /* enter the UART into configuration mode */ + + while ((termios->c_cflag & CSIZE) != CS8 && + (termios->c_cflag & CSIZE) != CS7) { + termios->c_cflag &= ~CSIZE; + termios->c_cflag |= old_csize; + old_csize = CS8; + } + + if ((termios->c_cflag & CSIZE) == CS7) { + /* Word length: WL1WL0:00 */ + cr = old_cr & ~LINFLEXD_UARTCR_WL1 & ~LINFLEXD_UARTCR_WL0; + } + + if ((termios->c_cflag & CSIZE) == CS8) { + /* Word length: WL1WL0:01 */ + cr = (old_cr | LINFLEXD_UARTCR_WL0) & ~LINFLEXD_UARTCR_WL1; + } + + if (termios->c_cflag & CMSPAR) { + if ((termios->c_cflag & CSIZE) != CS8) { + termios->c_cflag &= ~CSIZE; + termios->c_cflag |= CS8; + } + /* has a space/sticky bit */ + cr |= LINFLEXD_UARTCR_WL0; + } + + if (termios->c_cflag & CSTOPB) + termios->c_cflag &= ~CSTOPB; + + /* parity must be enabled when CS7 to match 8-bits format */ + if ((termios->c_cflag & CSIZE) == CS7) + termios->c_cflag |= PARENB; + + if ((termios->c_cflag & PARENB)) { + cr |= LINFLEXD_UARTCR_PCE; + if (termios->c_cflag & PARODD) + cr = (cr | LINFLEXD_UARTCR_PC0) & + (~LINFLEXD_UARTCR_PC1); + else + cr = cr & (~LINFLEXD_UARTCR_PC1 & + ~LINFLEXD_UARTCR_PC0); + } else { + cr &= ~LINFLEXD_UARTCR_PCE; + } + + spin_lock_irqsave(&port->lock, flags); + + port->read_status_mask = 0; + + if (termios->c_iflag & INPCK) + port->read_status_mask |= (LINFLEXD_UARTSR_FEF | + LINFLEXD_UARTSR_PE0 | + LINFLEXD_UARTSR_PE1 | + LINFLEXD_UARTSR_PE2 | + LINFLEXD_UARTSR_PE3); + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) + port->read_status_mask |= LINFLEXD_UARTSR_FEF; + + /* characters to ignore */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= LINFLEXD_UARTSR_PE; + if (termios->c_iflag & IGNBRK) { + port->ignore_status_mask |= LINFLEXD_UARTSR_PE; + /* + * if we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= LINFLEXD_UARTSR_BOF; + } + + writel(cr, port->membase + UARTCR); + + cr1 &= ~(LINFLEXD_LINCR1_INIT); + + writel(cr1, port->membase + LINCR1); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *linflex_type(struct uart_port *port) +{ + return "FSL_LINFLEX"; +} + +static void linflex_release_port(struct uart_port *port) +{ + /* nothing to do */ +} + +static int linflex_request_port(struct uart_port *port) +{ + return 0; +} + +/* configure/auto-configure the port */ +static void linflex_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) + port->type = PORT_LINFLEXUART; +} + +static const struct uart_ops linflex_pops = { + .tx_empty = linflex_tx_empty, + .set_mctrl = linflex_set_mctrl, + .get_mctrl = linflex_get_mctrl, + .stop_tx = linflex_stop_tx, + .start_tx = linflex_start_tx, + .stop_rx = linflex_stop_rx, + .break_ctl = linflex_break_ctl, + .startup = linflex_startup, + .shutdown = linflex_shutdown, + .set_termios = linflex_set_termios, + .type = linflex_type, + .request_port = linflex_request_port, + .release_port = linflex_release_port, + .config_port = linflex_config_port, +}; + +static struct uart_port *linflex_ports[UART_NR]; + +#ifdef CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE +static void linflex_console_putchar(struct uart_port *port, int ch) +{ + unsigned long cr; + + cr = readl(port->membase + UARTCR); + + writeb(ch, port->membase + BDRL); + + if (!(cr & LINFLEXD_UARTCR_TFBM)) + while ((readl(port->membase + UARTSR) & + LINFLEXD_UARTSR_DTFTFF) + != LINFLEXD_UARTSR_DTFTFF) + ; + else + while (readl(port->membase + UARTSR) & + LINFLEXD_UARTSR_DTFTFF) + ; + + if (!(cr & LINFLEXD_UARTCR_TFBM)) { + writel((readl(port->membase + UARTSR) | + LINFLEXD_UARTSR_DTFTFF), + port->membase + UARTSR); + } +} + +static void linflex_earlycon_putchar(struct uart_port *port, int ch) +{ + unsigned long flags; + char *ret; + + if (!linflex_earlycon_same_instance) { + linflex_console_putchar(port, ch); + return; + } + + spin_lock_irqsave(&init_lock, flags); + if (!during_init) + goto outside_init; + + if (earlycon_buf.len >= 1 << CONFIG_LOG_BUF_SHIFT) + goto init_release; + + if (!earlycon_buf.cap) { + earlycon_buf.content = kmalloc(EARLYCON_BUFFER_INITIAL_CAP, + GFP_ATOMIC); + earlycon_buf.cap = earlycon_buf.content ? + EARLYCON_BUFFER_INITIAL_CAP : 0; + } else if (earlycon_buf.len == earlycon_buf.cap) { + ret = krealloc(earlycon_buf.content, earlycon_buf.cap << 1, + GFP_ATOMIC); + if (ret) { + earlycon_buf.content = ret; + earlycon_buf.cap <<= 1; + } + } + + if (earlycon_buf.len < earlycon_buf.cap) + earlycon_buf.content[earlycon_buf.len++] = ch; + + goto init_release; + +outside_init: + linflex_console_putchar(port, ch); +init_release: + spin_unlock_irqrestore(&init_lock, flags); +} + +static void linflex_string_write(struct uart_port *sport, const char *s, + unsigned int count) +{ + unsigned long cr, ier = 0; + + ier = readl(sport->membase + LINIER); + linflex_stop_tx(sport); + + cr = readl(sport->membase + UARTCR); + cr |= (LINFLEXD_UARTCR_TXEN); + writel(cr, sport->membase + UARTCR); + + uart_console_write(sport, s, count, linflex_console_putchar); + + writel(ier, sport->membase + LINIER); +} + +static void +linflex_console_write(struct console *co, const char *s, unsigned int count) +{ + struct uart_port *sport = linflex_ports[co->index]; + unsigned long flags; + int locked = 1; + + if (sport->sysrq) + locked = 0; + else if (oops_in_progress) + locked = spin_trylock_irqsave(&sport->lock, flags); + else + spin_lock_irqsave(&sport->lock, flags); + + linflex_string_write(sport, s, count); + + if (locked) + spin_unlock_irqrestore(&sport->lock, flags); +} + +/* + * if the port was already initialised (eg, by a boot loader), + * try to determine the current setup. + */ +static void __init +linflex_console_get_options(struct uart_port *sport, int *parity, int *bits) +{ + unsigned long cr; + + cr = readl(sport->membase + UARTCR); + cr &= LINFLEXD_UARTCR_RXEN | LINFLEXD_UARTCR_TXEN; + + if (!cr) + return; + + /* ok, the port was enabled */ + + *parity = 'n'; + if (cr & LINFLEXD_UARTCR_PCE) { + if (cr & LINFLEXD_UARTCR_PC0) + *parity = 'o'; + else + *parity = 'e'; + } + + if ((cr & LINFLEXD_UARTCR_WL0) && ((cr & LINFLEXD_UARTCR_WL1) == 0)) { + if (cr & LINFLEXD_UARTCR_PCE) + *bits = 9; + else + *bits = 8; + } +} + +static int __init linflex_console_setup(struct console *co, char *options) +{ + struct uart_port *sport; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + int ret; + int i; + unsigned long flags; + /* + * check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (co->index == -1 || co->index >= ARRAY_SIZE(linflex_ports)) + co->index = 0; + + sport = linflex_ports[co->index]; + if (!sport) + return -ENODEV; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else + linflex_console_get_options(sport, &parity, &bits); + + if (earlycon_port && sport->mapbase == earlycon_port->mapbase) { + linflex_earlycon_same_instance = true; + + spin_lock_irqsave(&init_lock, flags); + during_init = true; + spin_unlock_irqrestore(&init_lock, flags); + + /* Workaround for character loss or output of many invalid + * characters, when INIT mode is entered shortly after a + * character has just been printed. + */ + udelay(PREINIT_DELAY); + } + + linflex_setup_watermark(sport); + + ret = uart_set_options(sport, co, baud, parity, bits, flow); + + if (!linflex_earlycon_same_instance) + goto done; + + spin_lock_irqsave(&init_lock, flags); + + /* Emptying buffer */ + if (earlycon_buf.len) { + for (i = 0; i < earlycon_buf.len; i++) + linflex_console_putchar(earlycon_port, + earlycon_buf.content[i]); + + kfree(earlycon_buf.content); + earlycon_buf.len = 0; + } + + during_init = false; + spin_unlock_irqrestore(&init_lock, flags); + +done: + return ret; +} + +static struct uart_driver linflex_reg; +static struct console linflex_console = { + .name = DEV_NAME, + .write = linflex_console_write, + .device = uart_console_device, + .setup = linflex_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &linflex_reg, +}; + +static void linflex_earlycon_write(struct console *con, const char *s, + unsigned int n) +{ + struct earlycon_device *dev = con->data; + + uart_console_write(&dev->port, s, n, linflex_earlycon_putchar); +} + +static int __init linflex_early_console_setup(struct earlycon_device *device, + const char *options) +{ + if (!device->port.membase) + return -ENODEV; + + device->con->write = linflex_earlycon_write; + earlycon_port = &device->port; + + return 0; +} + +OF_EARLYCON_DECLARE(linflex, "fsl,s32v234-linflexuart", + linflex_early_console_setup); + +#define LINFLEX_CONSOLE (&linflex_console) +#else +#define LINFLEX_CONSOLE NULL +#endif + +static struct uart_driver linflex_reg = { + .owner = THIS_MODULE, + .driver_name = DRIVER_NAME, + .dev_name = DEV_NAME, + .nr = ARRAY_SIZE(linflex_ports), + .cons = LINFLEX_CONSOLE, +}; + +static int linflex_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct uart_port *sport; + struct resource *res; + int ret; + + sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL); + if (!sport) + return -ENOMEM; + + ret = of_alias_get_id(np, "serial"); + if (ret < 0) { + dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret); + return ret; + } + if (ret >= UART_NR) { + dev_err(&pdev->dev, "driver limited to %d serial ports\n", + UART_NR); + return -ENOMEM; + } + + sport->line = ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + sport->mapbase = res->start; + sport->membase = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(sport->membase)) + return PTR_ERR(sport->membase); + + sport->dev = &pdev->dev; + sport->type = PORT_LINFLEXUART; + sport->iotype = UPIO_MEM; + sport->irq = platform_get_irq(pdev, 0); + sport->ops = &linflex_pops; + sport->flags = UPF_BOOT_AUTOCONF; + + linflex_ports[sport->line] = sport; + + platform_set_drvdata(pdev, sport); + + ret = uart_add_one_port(&linflex_reg, sport); + if (ret) + return ret; + + return 0; +} + +static int linflex_remove(struct platform_device *pdev) +{ + struct uart_port *sport = platform_get_drvdata(pdev); + + uart_remove_one_port(&linflex_reg, sport); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int linflex_suspend(struct device *dev) +{ + struct uart_port *sport = dev_get_drvdata(dev); + + uart_suspend_port(&linflex_reg, sport); + + return 0; +} + +static int linflex_resume(struct device *dev) +{ + struct uart_port *sport = dev_get_drvdata(dev); + + uart_resume_port(&linflex_reg, sport); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(linflex_pm_ops, linflex_suspend, linflex_resume); + +static struct platform_driver linflex_driver = { + .probe = linflex_probe, + .remove = linflex_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = linflex_dt_ids, + .pm = &linflex_pm_ops, + }, +}; + +static int __init linflex_serial_init(void) +{ + int ret; + + ret = uart_register_driver(&linflex_reg); + if (ret) + return ret; + + ret = platform_driver_register(&linflex_driver); + if (ret) + uart_unregister_driver(&linflex_reg); + + return ret; +} + +static void __exit linflex_serial_exit(void) +{ + platform_driver_unregister(&linflex_driver); + uart_unregister_driver(&linflex_reg); +} + +module_init(linflex_serial_init); +module_exit(linflex_serial_exit); + +MODULE_DESCRIPTION("Freescale linflex serial port driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 92dad2b4ec36..3e17bb8a0b16 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -214,6 +214,7 @@ #define UARTFIFO_TXSIZE_OFF 4 #define UARTFIFO_RXFE 0x00000008 #define UARTFIFO_RXSIZE_OFF 0 +#define UARTFIFO_DEPTH(x) (0x1 << ((x) ? ((x) + 1) : 0)) #define UARTWATER_COUNT_MASK 0xff #define UARTWATER_TXCNT_OFF 8 @@ -451,6 +452,11 @@ static void lpuart_dma_tx(struct lpuart_port *sport) dma_async_issue_pending(sport->dma_tx_chan); } +static bool lpuart_stopped_or_empty(struct uart_port *port) +{ + return uart_circ_empty(&port->state->xmit) || uart_tx_stopped(port); +} + static void lpuart_dma_tx_complete(void *arg) { struct lpuart_port *sport = arg; @@ -478,7 +484,7 @@ static void lpuart_dma_tx_complete(void *arg) spin_lock_irqsave(&sport->port.lock, flags); - if (!uart_circ_empty(xmit) && !uart_tx_stopped(&sport->port)) + if (!lpuart_stopped_or_empty(&sport->port)) lpuart_dma_tx(sport); spin_unlock_irqrestore(&sport->port.lock, flags); @@ -517,9 +523,16 @@ static int lpuart_dma_tx_request(struct uart_port *port) return 0; } +static bool lpuart_is_32(struct lpuart_port *sport) +{ + return sport->port.iotype == UPIO_MEM32 || + sport->port.iotype == UPIO_MEM32BE; +} + static void lpuart_flush_buffer(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); + u32 val; if (sport->lpuart_dma_tx_use) { if (sport->dma_tx_in_progress) { @@ -529,6 +542,30 @@ static void lpuart_flush_buffer(struct uart_port *port) } dmaengine_terminate_all(sport->dma_tx_chan); } + + if (lpuart_is_32(sport)) { + val = lpuart32_read(&sport->port, UARTFIFO); + val |= UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH; + lpuart32_write(&sport->port, val, UARTFIFO); + } else { + val = readb(sport->port.membase + UARTPFIFO); + val |= UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH; + writeb(val, sport->port.membase + UARTCFIFO); + } +} + +static void lpuart_wait_bit_set(struct uart_port *port, unsigned int offset, + u8 bit) +{ + while (!(readb(port->membase + offset) & bit)) + cpu_relax(); +} + +static void lpuart32_wait_bit_set(struct uart_port *port, unsigned int offset, + u32 bit) +{ + while (!(lpuart32_read(port, offset) & bit)) + cpu_relax(); } #if defined(CONFIG_CONSOLE_POLL) @@ -574,9 +611,7 @@ static int lpuart_poll_init(struct uart_port *port) static void lpuart_poll_put_char(struct uart_port *port, unsigned char c) { /* drain */ - while (!(readb(port->membase + UARTSR1) & UARTSR1_TDRE)) - barrier(); - + lpuart_wait_bit_set(port, UARTSR1, UARTSR1_TDRE); writeb(c, port->membase + UARTDR); } @@ -599,26 +634,26 @@ static int lpuart32_poll_init(struct uart_port *port) spin_lock_irqsave(&sport->port.lock, flags); /* Disable Rx & Tx */ - writel(0, sport->port.membase + UARTCTRL); + lpuart32_write(&sport->port, UARTCTRL, 0); - temp = readl(sport->port.membase + UARTFIFO); + temp = lpuart32_read(&sport->port, UARTFIFO); /* Enable Rx and Tx FIFO */ - writel(temp | UARTFIFO_RXFE | UARTFIFO_TXFE, - sport->port.membase + UARTFIFO); + lpuart32_write(&sport->port, UARTFIFO, + temp | UARTFIFO_RXFE | UARTFIFO_TXFE); /* flush Tx and Rx FIFO */ - writel(UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH, - sport->port.membase + UARTFIFO); + lpuart32_write(&sport->port, UARTFIFO, + UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH); /* explicitly clear RDRF */ - if (readl(sport->port.membase + UARTSTAT) & UARTSTAT_RDRF) { - readl(sport->port.membase + UARTDATA); - writel(UARTFIFO_RXUF, sport->port.membase + UARTFIFO); + if (lpuart32_read(&sport->port, UARTSTAT) & UARTSTAT_RDRF) { + lpuart32_read(&sport->port, UARTDATA); + lpuart32_write(&sport->port, UARTFIFO, UARTFIFO_RXUF); } /* Enable Rx and Tx */ - writel(UARTCTRL_RE | UARTCTRL_TE, sport->port.membase + UARTCTRL); + lpuart32_write(&sport->port, UARTCTRL, UARTCTRL_RE | UARTCTRL_TE); spin_unlock_irqrestore(&sport->port.lock, flags); return 0; @@ -626,18 +661,16 @@ static int lpuart32_poll_init(struct uart_port *port) static void lpuart32_poll_put_char(struct uart_port *port, unsigned char c) { - while (!(readl(port->membase + UARTSTAT) & UARTSTAT_TDRE)) - barrier(); - - writel(c, port->membase + UARTDATA); + lpuart32_wait_bit_set(port, UARTSTAT, UARTSTAT_TDRE); + lpuart32_write(port, UARTDATA, c); } static int lpuart32_poll_get_char(struct uart_port *port) { - if (!(readl(port->membase + UARTSTAT) & UARTSTAT_RDRF)) + if (!(lpuart32_read(port, UARTSTAT) & UARTSTAT_RDRF)) return NO_POLL_CHAR; - return readl(port->membase + UARTDATA); + return lpuart32_read(port, UARTDATA); } #endif @@ -645,6 +678,18 @@ static inline void lpuart_transmit_buffer(struct lpuart_port *sport) { struct circ_buf *xmit = &sport->port.state->xmit; + if (sport->port.x_char) { + writeb(sport->port.x_char, sport->port.membase + UARTDR); + sport->port.icount.tx++; + sport->port.x_char = 0; + return; + } + + if (lpuart_stopped_or_empty(&sport->port)) { + lpuart_stop_tx(&sport->port); + return; + } + while (!uart_circ_empty(xmit) && (readb(sport->port.membase + UARTTCFIFO) < sport->txfifo_size)) { writeb(xmit->buf[xmit->tail], sport->port.membase + UARTDR); @@ -664,6 +709,18 @@ static inline void lpuart32_transmit_buffer(struct lpuart_port *sport) struct circ_buf *xmit = &sport->port.state->xmit; unsigned long txcnt; + if (sport->port.x_char) { + lpuart32_write(&sport->port, sport->port.x_char, UARTDATA); + sport->port.icount.tx++; + sport->port.x_char = 0; + return; + } + + if (lpuart_stopped_or_empty(&sport->port)) { + lpuart32_stop_tx(&sport->port); + return; + } + txcnt = lpuart32_read(&sport->port, UARTWATER); txcnt = txcnt >> UARTWATER_TXCNT_OFF; txcnt &= UARTWATER_COUNT_MASK; @@ -687,14 +744,13 @@ static void lpuart_start_tx(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); - struct circ_buf *xmit = &sport->port.state->xmit; unsigned char temp; temp = readb(port->membase + UARTCR2); writeb(temp | UARTCR2_TIE, port->membase + UARTCR2); if (sport->lpuart_dma_tx_use) { - if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) + if (!lpuart_stopped_or_empty(port)) lpuart_dma_tx(sport); } else { if (readb(port->membase + UARTSR1) & UARTSR1_TDRE) @@ -705,11 +761,10 @@ static void lpuart_start_tx(struct uart_port *port) static void lpuart32_start_tx(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); - struct circ_buf *xmit = &sport->port.state->xmit; unsigned long temp; if (sport->lpuart_dma_tx_use) { - if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) + if (!lpuart_stopped_or_empty(port)) lpuart_dma_tx(sport); } else { temp = lpuart32_read(port, UARTCTRL); @@ -753,52 +808,18 @@ static unsigned int lpuart32_tx_empty(struct uart_port *port) return 0; } -static bool lpuart_is_32(struct lpuart_port *sport) +static void lpuart_txint(struct lpuart_port *sport) { - return sport->port.iotype == UPIO_MEM32 || - sport->port.iotype == UPIO_MEM32BE; -} - -static irqreturn_t lpuart_txint(int irq, void *dev_id) -{ - struct lpuart_port *sport = dev_id; - struct circ_buf *xmit = &sport->port.state->xmit; unsigned long flags; spin_lock_irqsave(&sport->port.lock, flags); - if (sport->port.x_char) { - if (lpuart_is_32(sport)) - lpuart32_write(&sport->port, sport->port.x_char, UARTDATA); - else - writeb(sport->port.x_char, sport->port.membase + UARTDR); - goto out; - } - - if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) { - if (lpuart_is_32(sport)) - lpuart32_stop_tx(&sport->port); - else - lpuart_stop_tx(&sport->port); - goto out; - } - - if (lpuart_is_32(sport)) - lpuart32_transmit_buffer(sport); - else - lpuart_transmit_buffer(sport); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&sport->port); - -out: + lpuart_transmit_buffer(sport); spin_unlock_irqrestore(&sport->port.lock, flags); - return IRQ_HANDLED; } -static irqreturn_t lpuart_rxint(int irq, void *dev_id) +static void lpuart_rxint(struct lpuart_port *sport) { - struct lpuart_port *sport = dev_id; - unsigned int flg, ignored = 0; + unsigned int flg, ignored = 0, overrun = 0; struct tty_port *port = &sport->port.state->port; unsigned long flags; unsigned char rx, sr; @@ -825,7 +846,7 @@ static irqreturn_t lpuart_rxint(int irq, void *dev_id) sport->port.icount.frame++; if (sr & UARTSR1_OR) - sport->port.icount.overrun++; + overrun++; if (sr & sport->port.ignore_status_mask) { if (++ignored > 100) @@ -852,15 +873,33 @@ static irqreturn_t lpuart_rxint(int irq, void *dev_id) } out: + if (overrun) { + sport->port.icount.overrun += overrun; + + /* + * Overruns cause FIFO pointers to become missaligned. + * Flushing the receive FIFO reinitializes the pointers. + */ + writeb(UARTCFIFO_RXFLUSH, sport->port.membase + UARTCFIFO); + writeb(UARTSFIFO_RXOF, sport->port.membase + UARTSFIFO); + } + spin_unlock_irqrestore(&sport->port.lock, flags); tty_flip_buffer_push(port); - return IRQ_HANDLED; } -static irqreturn_t lpuart32_rxint(int irq, void *dev_id) +static void lpuart32_txint(struct lpuart_port *sport) +{ + unsigned long flags; + + spin_lock_irqsave(&sport->port.lock, flags); + lpuart32_transmit_buffer(sport); + spin_unlock_irqrestore(&sport->port.lock, flags); +} + +static void lpuart32_rxint(struct lpuart_port *sport) { - struct lpuart_port *sport = dev_id; unsigned int flg, ignored = 0; struct tty_port *port = &sport->port.state->port; unsigned long flags; @@ -919,7 +958,6 @@ out: spin_unlock_irqrestore(&sport->port.lock, flags); tty_flip_buffer_push(port); - return IRQ_HANDLED; } static irqreturn_t lpuart_int(int irq, void *dev_id) @@ -929,11 +967,11 @@ static irqreturn_t lpuart_int(int irq, void *dev_id) sts = readb(sport->port.membase + UARTSR1); - if (sts & UARTSR1_RDRF) - lpuart_rxint(irq, dev_id); + if (sts & UARTSR1_RDRF && !sport->lpuart_dma_rx_use) + lpuart_rxint(sport); - if (sts & UARTSR1_TDRE) - lpuart_txint(irq, dev_id); + if (sts & UARTSR1_TDRE && !sport->lpuart_dma_tx_use) + lpuart_txint(sport); return IRQ_HANDLED; } @@ -948,10 +986,10 @@ static irqreturn_t lpuart32_int(int irq, void *dev_id) rxcount = rxcount >> UARTWATER_RXCNT_OFF; if ((sts & UARTSTAT_RDRF || rxcount > 0) && !sport->lpuart_dma_rx_use) - lpuart32_rxint(irq, dev_id); + lpuart32_rxint(sport); if ((sts & UARTSTAT_TDRE) && !sport->lpuart_dma_tx_use) - lpuart_txint(irq, dev_id); + lpuart32_txint(sport); lpuart32_write(&sport->port, sts, UARTSTAT); return IRQ_HANDLED; @@ -982,6 +1020,13 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) unsigned char sr = readb(sport->port.membase + UARTSR1); if (sr & (UARTSR1_PE | UARTSR1_FE)) { + unsigned char cr2; + + /* Disable receiver during this operation... */ + cr2 = readb(sport->port.membase + UARTCR2); + cr2 &= ~UARTCR2_RE; + writeb(cr2, sport->port.membase + UARTCR2); + /* Read DR to clear the error flags */ readb(sport->port.membase + UARTDR); @@ -989,6 +1034,25 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) sport->port.icount.parity++; else if (sr & UARTSR1_FE) sport->port.icount.frame++; + /* + * At this point parity/framing error is + * cleared However, since the DMA already read + * the data register and we had to read it + * again after reading the status register to + * properly clear the flags, the FIFO actually + * underflowed... This requires a clearing of + * the FIFO... + */ + if (readb(sport->port.membase + UARTSFIFO) & + UARTSFIFO_RXUF) { + writeb(UARTSFIFO_RXUF, + sport->port.membase + UARTSFIFO); + writeb(UARTCFIFO_RXFLUSH, + sport->port.membase + UARTCFIFO); + } + + cr2 |= UARTCR2_RE; + writeb(cr2, sport->port.membase + UARTCR2); } } @@ -1097,12 +1161,11 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport) if (sport->rx_dma_rng_buf_len < 16) sport->rx_dma_rng_buf_len = 16; - ring->buf = kmalloc(sport->rx_dma_rng_buf_len, GFP_ATOMIC); + ring->buf = kzalloc(sport->rx_dma_rng_buf_len, GFP_ATOMIC); if (!ring->buf) return -ENOMEM; sg_init_one(&sport->rx_sgl, ring->buf, sport->rx_dma_rng_buf_len); - sg_set_buf(&sport->rx_sgl, ring->buf, sport->rx_dma_rng_buf_len); nent = dma_map_sg(sport->port.dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE); if (!nent) { @@ -1340,6 +1403,17 @@ static void lpuart_setup_watermark(struct lpuart_port *sport) writeb(cr2_saved, sport->port.membase + UARTCR2); } +static void lpuart_setup_watermark_enable(struct lpuart_port *sport) +{ + unsigned char cr2; + + lpuart_setup_watermark(sport); + + cr2 = readb(sport->port.membase + UARTCR2); + cr2 |= UARTCR2_RIE | UARTCR2_RE | UARTCR2_TE; + writeb(cr2, sport->port.membase + UARTCR2); +} + static void lpuart32_setup_watermark(struct lpuart_port *sport) { unsigned long val, ctrl; @@ -1365,89 +1439,46 @@ static void lpuart32_setup_watermark(struct lpuart_port *sport) lpuart32_write(&sport->port, ctrl_saved, UARTCTRL); } -static void rx_dma_timer_init(struct lpuart_port *sport) +static void lpuart32_setup_watermark_enable(struct lpuart_port *sport) { - timer_setup(&sport->lpuart_timer, lpuart_timer_func, 0); - sport->lpuart_timer.expires = jiffies + sport->dma_rx_timeout; - add_timer(&sport->lpuart_timer); -} - -static int lpuart_startup(struct uart_port *port) -{ - struct lpuart_port *sport = container_of(port, struct lpuart_port, port); - unsigned long flags; - unsigned char temp; - - /* determine FIFO size and enable FIFO mode */ - temp = readb(sport->port.membase + UARTPFIFO); - - sport->txfifo_size = 0x1 << (((temp >> UARTPFIFO_TXSIZE_OFF) & - UARTPFIFO_FIFOSIZE_MASK) + 1); - - sport->port.fifosize = sport->txfifo_size; - - sport->rxfifo_size = 0x1 << (((temp >> UARTPFIFO_RXSIZE_OFF) & - UARTPFIFO_FIFOSIZE_MASK) + 1); - - spin_lock_irqsave(&sport->port.lock, flags); - - lpuart_setup_watermark(sport); - - temp = readb(sport->port.membase + UARTCR2); - temp |= (UARTCR2_RIE | UARTCR2_TIE | UARTCR2_RE | UARTCR2_TE); - writeb(temp, sport->port.membase + UARTCR2); - - if (sport->dma_rx_chan && !lpuart_start_rx_dma(sport)) { - /* set Rx DMA timeout */ - sport->dma_rx_timeout = msecs_to_jiffies(DMA_RX_TIMEOUT); - if (!sport->dma_rx_timeout) - sport->dma_rx_timeout = 1; - - sport->lpuart_dma_rx_use = true; - rx_dma_timer_init(sport); - } else { - sport->lpuart_dma_rx_use = false; - } - - if (sport->dma_tx_chan && !lpuart_dma_tx_request(port)) { - init_waitqueue_head(&sport->dma_wait); - sport->lpuart_dma_tx_use = true; - temp = readb(port->membase + UARTCR5); - writeb(temp | UARTCR5_TDMAS, port->membase + UARTCR5); - } else { - sport->lpuart_dma_tx_use = false; - } - - spin_unlock_irqrestore(&sport->port.lock, flags); - - return 0; -} - -static int lpuart32_startup(struct uart_port *port) -{ - struct lpuart_port *sport = container_of(port, struct lpuart_port, port); - unsigned long flags; - unsigned long temp; - - /* determine FIFO size */ - temp = lpuart32_read(&sport->port, UARTFIFO); - - sport->txfifo_size = 0x1 << (((temp >> UARTFIFO_TXSIZE_OFF) & - UARTFIFO_FIFOSIZE_MASK) - 1); - - sport->port.fifosize = sport->txfifo_size; - - sport->rxfifo_size = 0x1 << (((temp >> UARTFIFO_RXSIZE_OFF) & - UARTFIFO_FIFOSIZE_MASK) - 1); - - spin_lock_irqsave(&sport->port.lock, flags); + u32 temp; lpuart32_setup_watermark(sport); temp = lpuart32_read(&sport->port, UARTCTRL); temp |= UARTCTRL_RE | UARTCTRL_TE | UARTCTRL_ILIE; lpuart32_write(&sport->port, temp, UARTCTRL); +} +static void rx_dma_timer_init(struct lpuart_port *sport) +{ + timer_setup(&sport->lpuart_timer, lpuart_timer_func, 0); + sport->lpuart_timer.expires = jiffies + sport->dma_rx_timeout; + add_timer(&sport->lpuart_timer); +} + +static void lpuart_tx_dma_startup(struct lpuart_port *sport) +{ + u32 uartbaud; + + if (sport->dma_tx_chan && !lpuart_dma_tx_request(&sport->port)) { + init_waitqueue_head(&sport->dma_wait); + sport->lpuart_dma_tx_use = true; + if (lpuart_is_32(sport)) { + uartbaud = lpuart32_read(&sport->port, UARTBAUD); + lpuart32_write(&sport->port, + uartbaud | UARTBAUD_TDMAE, UARTBAUD); + } else { + writeb(readb(sport->port.membase + UARTCR5) | + UARTCR5_TDMAS, sport->port.membase + UARTCR5); + } + } else { + sport->lpuart_dma_tx_use = false; + } +} + +static void lpuart_rx_dma_startup(struct lpuart_port *sport) +{ if (sport->dma_rx_chan && !lpuart_start_rx_dma(sport)) { /* set Rx DMA timeout */ sport->dma_rx_timeout = msecs_to_jiffies(DMA_RX_TIMEOUT); @@ -1459,15 +1490,39 @@ static int lpuart32_startup(struct uart_port *port) } else { sport->lpuart_dma_rx_use = false; } +} - if (sport->dma_tx_chan && !lpuart_dma_tx_request(port)) { - init_waitqueue_head(&sport->dma_wait); - sport->lpuart_dma_tx_use = true; - temp = lpuart32_read(&sport->port, UARTBAUD); - lpuart32_write(&sport->port, temp | UARTBAUD_TDMAE, UARTBAUD); - } else { - sport->lpuart_dma_tx_use = false; - } +static int lpuart_startup(struct uart_port *port) +{ + struct lpuart_port *sport = container_of(port, struct lpuart_port, port); + unsigned long flags; + unsigned char temp; + + /* determine FIFO size and enable FIFO mode */ + temp = readb(sport->port.membase + UARTPFIFO); + + sport->txfifo_size = UARTFIFO_DEPTH((temp >> UARTPFIFO_TXSIZE_OFF) & + UARTPFIFO_FIFOSIZE_MASK); + sport->port.fifosize = sport->txfifo_size; + + sport->rxfifo_size = UARTFIFO_DEPTH((temp >> UARTPFIFO_RXSIZE_OFF) & + UARTPFIFO_FIFOSIZE_MASK); + + spin_lock_irqsave(&sport->port.lock, flags); + + lpuart_setup_watermark_enable(sport); + + lpuart_rx_dma_startup(sport); + lpuart_tx_dma_startup(sport); + + spin_unlock_irqrestore(&sport->port.lock, flags); + + return 0; +} + +static void lpuart32_configure(struct lpuart_port *sport) +{ + unsigned long temp; if (sport->lpuart_dma_rx_use) { /* RXWATER must be 0 */ @@ -1481,11 +1536,54 @@ static int lpuart32_startup(struct uart_port *port) if (!sport->lpuart_dma_tx_use) temp |= UARTCTRL_TIE; lpuart32_write(&sport->port, temp, UARTCTRL); +} + +static int lpuart32_startup(struct uart_port *port) +{ + struct lpuart_port *sport = container_of(port, struct lpuart_port, port); + unsigned long flags; + unsigned long temp; + + /* determine FIFO size */ + temp = lpuart32_read(&sport->port, UARTFIFO); + + sport->txfifo_size = UARTFIFO_DEPTH((temp >> UARTFIFO_TXSIZE_OFF) & + UARTFIFO_FIFOSIZE_MASK); + sport->port.fifosize = sport->txfifo_size; + + sport->rxfifo_size = UARTFIFO_DEPTH((temp >> UARTFIFO_RXSIZE_OFF) & + UARTFIFO_FIFOSIZE_MASK); + + spin_lock_irqsave(&sport->port.lock, flags); + + lpuart32_setup_watermark_enable(sport); + + + lpuart_rx_dma_startup(sport); + lpuart_tx_dma_startup(sport); + + lpuart32_configure(sport); spin_unlock_irqrestore(&sport->port.lock, flags); return 0; } +static void lpuart_dma_shutdown(struct lpuart_port *sport) +{ + if (sport->lpuart_dma_rx_use) { + del_timer_sync(&sport->lpuart_timer); + lpuart_dma_rx_free(&sport->port); + } + + if (sport->lpuart_dma_tx_use) { + if (wait_event_interruptible(sport->dma_wait, + !sport->dma_tx_in_progress) != false) { + sport->dma_tx_in_progress = false; + dmaengine_terminate_all(sport->dma_tx_chan); + } + } +} + static void lpuart_shutdown(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); @@ -1502,20 +1600,7 @@ static void lpuart_shutdown(struct uart_port *port) spin_unlock_irqrestore(&port->lock, flags); - if (sport->lpuart_dma_rx_use) { - del_timer_sync(&sport->lpuart_timer); - lpuart_dma_rx_free(&sport->port); - } - - if (sport->lpuart_dma_tx_use) { - if (wait_event_interruptible(sport->dma_wait, - !sport->dma_tx_in_progress) != false) { - sport->dma_tx_in_progress = false; - dmaengine_terminate_all(sport->dma_tx_chan); - } - - lpuart_stop_tx(port); - } + lpuart_dma_shutdown(sport); } static void lpuart32_shutdown(struct uart_port *port) @@ -1535,20 +1620,7 @@ static void lpuart32_shutdown(struct uart_port *port) spin_unlock_irqrestore(&port->lock, flags); - if (sport->lpuart_dma_rx_use) { - del_timer_sync(&sport->lpuart_timer); - lpuart_dma_rx_free(&sport->port); - } - - if (sport->lpuart_dma_tx_use) { - if (wait_event_interruptible(sport->dma_wait, - !sport->dma_tx_in_progress)) { - sport->dma_tx_in_progress = false; - dmaengine_terminate_all(sport->dma_tx_chan); - } - - lpuart32_stop_tx(port); - } + lpuart_dma_shutdown(sport); } static void @@ -1602,21 +1674,18 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, if (sport->port.rs485.flags & SER_RS485_ENABLED) termios->c_cflag &= ~CRTSCTS; - if (termios->c_cflag & CRTSCTS) { - modem |= (UARTMODEM_RXRTSE | UARTMODEM_TXCTSE); - } else { - termios->c_cflag &= ~CRTSCTS; + if (termios->c_cflag & CRTSCTS) + modem |= UARTMODEM_RXRTSE | UARTMODEM_TXCTSE; + else modem &= ~(UARTMODEM_RXRTSE | UARTMODEM_TXCTSE); - } - if (termios->c_cflag & CSTOPB) - termios->c_cflag &= ~CSTOPB; + termios->c_cflag &= ~CSTOPB; /* parity must be enabled when CS7 to match 8-bits format */ if ((termios->c_cflag & CSIZE) == CS7) termios->c_cflag |= PARENB; - if ((termios->c_cflag & PARENB)) { + if (termios->c_cflag & PARENB) { if (termios->c_cflag & CMSPAR) { cr1 &= ~UARTCR1_PE; if (termios->c_cflag & PARODD) @@ -1655,7 +1724,7 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, sport->port.read_status_mask = 0; if (termios->c_iflag & INPCK) - sport->port.read_status_mask |= (UARTSR1_FE | UARTSR1_PE); + sport->port.read_status_mask |= UARTSR1_FE | UARTSR1_PE; if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) sport->port.read_status_mask |= UARTSR1_FE; @@ -1677,8 +1746,7 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, uart_update_timeout(port, termios->c_cflag, baud); /* wait transmit engin complete */ - while (!(readb(sport->port.membase + UARTSR1) & UARTSR1_TC)) - barrier(); + lpuart_wait_bit_set(&sport->port, UARTSR1, UARTSR1_TC); /* disable transmit and receive */ writeb(old_cr2 & ~(UARTCR2_TE | UARTCR2_RE), @@ -1769,7 +1837,7 @@ lpuart32_serial_setbrg(struct lpuart_port *sport, unsigned int baudrate) tmp |= UARTBAUD_BOTHEDGE; tmp &= ~(UARTBAUD_OSR_MASK << UARTBAUD_OSR_SHIFT); - tmp |= (((osr-1) & UARTBAUD_OSR_MASK) << UARTBAUD_OSR_SHIFT); + tmp |= ((osr-1) & UARTBAUD_OSR_MASK) << UARTBAUD_OSR_SHIFT; tmp &= ~UARTBAUD_SBR_MASK; tmp |= sbr & UARTBAUD_SBR_MASK; @@ -1822,7 +1890,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, } if (termios->c_cflag & CRTSCTS) { - modem |= (UARTMODEM_RXRTSE | UARTMODEM_TXCTSE); + modem |= UARTMODEM_RXRTSE | UARTMODEM_TXCTSE; } else { termios->c_cflag &= ~CRTSCTS; modem &= ~(UARTMODEM_RXRTSE | UARTMODEM_TXCTSE); @@ -1871,7 +1939,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, sport->port.read_status_mask = 0; if (termios->c_iflag & INPCK) - sport->port.read_status_mask |= (UARTSTAT_FE | UARTSTAT_PE); + sport->port.read_status_mask |= UARTSTAT_FE | UARTSTAT_PE; if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) sport->port.read_status_mask |= UARTSTAT_FE; @@ -1893,8 +1961,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, uart_update_timeout(port, termios->c_cflag, baud); /* wait transmit engin complete */ - while (!(lpuart32_read(&sport->port, UARTSTAT) & UARTSTAT_TC)) - barrier(); + lpuart32_wait_bit_set(&sport->port, UARTSTAT, UARTSTAT_TC); /* disable transmit and receive */ lpuart32_write(&sport->port, old_ctrl & ~(UARTCTRL_TE | UARTCTRL_RE), @@ -2009,17 +2076,13 @@ static struct lpuart_port *lpuart_ports[UART_NR]; #ifdef CONFIG_SERIAL_FSL_LPUART_CONSOLE static void lpuart_console_putchar(struct uart_port *port, int ch) { - while (!(readb(port->membase + UARTSR1) & UARTSR1_TDRE)) - barrier(); - + lpuart_wait_bit_set(port, UARTSR1, UARTSR1_TDRE); writeb(ch, port->membase + UARTDR); } static void lpuart32_console_putchar(struct uart_port *port, int ch) { - while (!(lpuart32_read(port, UARTSTAT) & UARTSTAT_TDRE)) - barrier(); - + lpuart32_wait_bit_set(port, UARTSTAT, UARTSTAT_TDRE); lpuart32_write(port, ch, UARTDATA); } @@ -2038,15 +2101,14 @@ lpuart_console_write(struct console *co, const char *s, unsigned int count) /* first save CR2 and then disable interrupts */ cr2 = old_cr2 = readb(sport->port.membase + UARTCR2); - cr2 |= (UARTCR2_TE | UARTCR2_RE); + cr2 |= UARTCR2_TE | UARTCR2_RE; cr2 &= ~(UARTCR2_TIE | UARTCR2_TCIE | UARTCR2_RIE); writeb(cr2, sport->port.membase + UARTCR2); uart_console_write(&sport->port, s, count, lpuart_console_putchar); /* wait for transmitter finish complete and restore CR2 */ - while (!(readb(sport->port.membase + UARTSR1) & UARTSR1_TC)) - barrier(); + lpuart_wait_bit_set(&sport->port, UARTSR1, UARTSR1_TC); writeb(old_cr2, sport->port.membase + UARTCR2); @@ -2069,15 +2131,14 @@ lpuart32_console_write(struct console *co, const char *s, unsigned int count) /* first save CR2 and then disable interrupts */ cr = old_cr = lpuart32_read(&sport->port, UARTCTRL); - cr |= (UARTCTRL_TE | UARTCTRL_RE); + cr |= UARTCTRL_TE | UARTCTRL_RE; cr &= ~(UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_RIE); lpuart32_write(&sport->port, cr, UARTCTRL); uart_console_write(&sport->port, s, count, lpuart32_console_putchar); /* wait for transmitter finish complete and restore CR2 */ - while (!(lpuart32_read(&sport->port, UARTSTAT) & UARTSTAT_TC)) - barrier(); + lpuart32_wait_bit_set(&sport->port, UARTSTAT, UARTSTAT_TC); lpuart32_write(&sport->port, old_cr, UARTCTRL); @@ -2288,6 +2349,7 @@ static int __init lpuart32_imx_early_console_setup(struct earlycon_device *devic OF_EARLYCON_DECLARE(lpuart, "fsl,vf610-lpuart", lpuart_early_console_setup); OF_EARLYCON_DECLARE(lpuart32, "fsl,ls1021a-lpuart", lpuart32_early_console_setup); OF_EARLYCON_DECLARE(lpuart32, "fsl,imx7ulp-lpuart", lpuart32_imx_early_console_setup); +OF_EARLYCON_DECLARE(lpuart32, "fsl,imx8qxp-lpuart", lpuart32_imx_early_console_setup); EARLYCON_DECLARE(lpuart, lpuart_early_console_setup); EARLYCON_DECLARE(lpuart32, lpuart32_early_console_setup); @@ -2320,8 +2382,6 @@ static int lpuart_probe(struct platform_device *pdev) if (!sport) return -ENOMEM; - pdev->dev.coherent_dma_mask = 0; - ret = of_alias_get_id(np, "serial"); if (ret < 0) { ret = ida_simple_get(&fsl_lpuart_ida, 0, UART_NR, GFP_KERNEL); @@ -2346,10 +2406,8 @@ static int lpuart_probe(struct platform_device *pdev) sport->port.type = PORT_LPUART; sport->devtype = sdata->devtype; ret = platform_get_irq(pdev, 0); - if (ret < 0) { - dev_err(&pdev->dev, "cannot obtain irq\n"); + if (ret < 0) return ret; - } sport->port.irq = ret; sport->port.iotype = sdata->iotype; if (lpuart_is_32(sport)) @@ -2514,22 +2572,14 @@ static int lpuart_resume(struct device *dev) { struct lpuart_port *sport = dev_get_drvdata(dev); bool irq_wake = irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq)); - unsigned long temp; if (sport->port.suspended && !irq_wake) lpuart_enable_clks(sport); - if (lpuart_is_32(sport)) { - lpuart32_setup_watermark(sport); - temp = lpuart32_read(&sport->port, UARTCTRL); - temp |= UARTCTRL_RE | UARTCTRL_TE | UARTCTRL_ILIE; - lpuart32_write(&sport->port, temp, UARTCTRL); - } else { - lpuart_setup_watermark(sport); - temp = readb(sport->port.membase + UARTCR2); - temp |= (UARTCR2_RIE | UARTCR2_TIE | UARTCR2_RE | UARTCR2_TE); - writeb(temp, sport->port.membase + UARTCR2); - } + if (lpuart_is_32(sport)) + lpuart32_setup_watermark_enable(sport); + else + lpuart_setup_watermark_enable(sport); if (sport->lpuart_dma_rx_use) { if (irq_wake) { @@ -2540,36 +2590,10 @@ static int lpuart_resume(struct device *dev) } } - if (sport->dma_tx_chan && !lpuart_dma_tx_request(&sport->port)) { - init_waitqueue_head(&sport->dma_wait); - sport->lpuart_dma_tx_use = true; - if (lpuart_is_32(sport)) { - temp = lpuart32_read(&sport->port, UARTBAUD); - lpuart32_write(&sport->port, - temp | UARTBAUD_TDMAE, UARTBAUD); - } else { - writeb(readb(sport->port.membase + UARTCR5) | - UARTCR5_TDMAS, sport->port.membase + UARTCR5); - } - } else { - sport->lpuart_dma_tx_use = false; - } + lpuart_tx_dma_startup(sport); - if (lpuart_is_32(sport)) { - if (sport->lpuart_dma_rx_use) { - /* RXWATER must be 0 */ - temp = lpuart32_read(&sport->port, UARTWATER); - temp &= ~(UARTWATER_WATER_MASK << - UARTWATER_RXWATER_OFF); - lpuart32_write(&sport->port, temp, UARTWATER); - } - temp = lpuart32_read(&sport->port, UARTCTRL); - if (!sport->lpuart_dma_rx_use) - temp |= UARTCTRL_RIE; - if (!sport->lpuart_dma_tx_use) - temp |= UARTCTRL_TIE; - lpuart32_write(&sport->port, temp, UARTCTRL); - } + if (lpuart_is_32(sport)) + lpuart32_configure(sport); uart_resume_port(&lpuart_reg, &sport->port); diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c index ad374f7c476d..624f3d541c68 100644 --- a/drivers/tty/serial/icom.c +++ b/drivers/tty/serial/icom.c @@ -207,8 +207,6 @@ static int get_port_memory(struct icom_port *icom_port) return -ENOMEM; } - memset(icom_port->statStg, 0, 4096); - /* FODs: Frame Out Descriptor Queue, this is a FIFO queue that indicates that frames are to be transmitted */ diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 57d6e6ba556e..87c58f9f6390 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -402,12 +402,6 @@ static void imx_uart_rts_inactive(struct imx_port *sport, u32 *ucr2) mctrl_gpio_set(sport->gpios, sport->port.mctrl); } -/* called with port.lock taken and irqs caller dependent */ -static void imx_uart_rts_auto(struct imx_port *sport, u32 *ucr2) -{ - *ucr2 |= UCR2_CTSC; -} - /* called with port.lock taken and irqs off */ static void imx_uart_start_rx(struct uart_port *port) { @@ -445,7 +439,7 @@ static void imx_uart_stop_tx(struct uart_port *port) return; ucr1 = imx_uart_readl(sport, UCR1); - imx_uart_writel(sport, ucr1 & ~UCR1_TXMPTYEN, UCR1); + imx_uart_writel(sport, ucr1 & ~UCR1_TRDYEN, UCR1); /* in rs485 mode disable transmitter if shifter is empty */ if (port->rs485.flags & SER_RS485_ENABLED && @@ -523,7 +517,7 @@ static inline void imx_uart_transmit_buffer(struct imx_port *sport) * and the TX IRQ is disabled. **/ ucr1 = imx_uart_readl(sport, UCR1); - ucr1 &= ~UCR1_TXMPTYEN; + ucr1 &= ~UCR1_TRDYEN; if (sport->dma_is_txing) { ucr1 |= UCR1_TXDMAEN; imx_uart_writel(sport, ucr1, UCR1); @@ -685,7 +679,7 @@ static void imx_uart_start_tx(struct uart_port *port) if (!sport->dma_is_enabled) { ucr1 = imx_uart_readl(sport, UCR1); - imx_uart_writel(sport, ucr1 | UCR1_TXMPTYEN, UCR1); + imx_uart_writel(sport, ucr1 | UCR1_TRDYEN, UCR1); } if (sport->dma_is_enabled) { @@ -694,7 +688,7 @@ static void imx_uart_start_tx(struct uart_port *port) * disable TX DMA to let TX interrupt to send X-char */ ucr1 = imx_uart_readl(sport, UCR1); ucr1 &= ~UCR1_TXDMAEN; - ucr1 |= UCR1_TXMPTYEN; + ucr1 |= UCR1_TRDYEN; imx_uart_writel(sport, ucr1, UCR1); return; } @@ -880,7 +874,7 @@ static irqreturn_t imx_uart_int(int irq, void *dev_id) usr1 &= ~USR1_RRDY; if ((ucr2 & UCR2_ATEN) == 0) usr1 &= ~USR1_AGTIM; - if ((ucr1 & UCR1_TXMPTYEN) == 0) + if ((ucr1 & UCR1_TRDYEN) == 0) usr1 &= ~USR1_TRDY; if ((ucr4 & UCR4_TCEN) == 0) usr2 &= ~USR2_TXDC; @@ -969,10 +963,22 @@ static void imx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) if (!(port->rs485.flags & SER_RS485_ENABLED)) { u32 ucr2; + /* + * Turn off autoRTS if RTS is lowered and restore autoRTS + * setting if RTS is raised. + */ ucr2 = imx_uart_readl(sport, UCR2); ucr2 &= ~(UCR2_CTS | UCR2_CTSC); - if (mctrl & TIOCM_RTS) - ucr2 |= UCR2_CTS | UCR2_CTSC; + if (mctrl & TIOCM_RTS) { + ucr2 |= UCR2_CTS; + /* + * UCR2_IRTS is unset if and only if the port is + * configured for CRTSCTS, so we use inverted UCR2_IRTS + * to get the state to restore to. + */ + if (!(ucr2 & UCR2_IRTS)) + ucr2 |= UCR2_CTSC; + } imx_uart_writel(sport, ucr2, UCR2); } @@ -1468,7 +1474,7 @@ static void imx_uart_shutdown(struct uart_port *port) spin_lock_irqsave(&sport->port.lock, flags); ucr1 = imx_uart_readl(sport, UCR1); - ucr1 &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN | UCR1_RXDMAEN | UCR1_ATDMAEN); + ucr1 &= ~(UCR1_TRDYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN | UCR1_RXDMAEN | UCR1_ATDMAEN); imx_uart_writel(sport, ucr1, UCR1); spin_unlock_irqrestore(&sport->port.lock, flags); @@ -1535,11 +1541,11 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios, { struct imx_port *sport = (struct imx_port *)port; unsigned long flags; - u32 ucr2, old_ucr1, old_ucr2, ufcr; + u32 ucr2, old_ucr2, ufcr; unsigned int baud, quot; unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; unsigned long div; - unsigned long num, denom; + unsigned long num, denom, old_ubir, old_ubmr; uint64_t tdiv64; /* @@ -1587,8 +1593,14 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios, else imx_uart_rts_inactive(sport, &ucr2); - } else if (termios->c_cflag & CRTSCTS) - imx_uart_rts_auto(sport, &ucr2); + } else if (termios->c_cflag & CRTSCTS) { + /* + * Only let receiver control RTS output if we were not requested + * to have RTS inactive (which then should take precedence). + */ + if (ucr2 & UCR2_CTS) + ucr2 |= UCR2_CTSC; + } if (termios->c_cflag & CRTSCTS) ucr2 &= ~UCR2_IRTS; @@ -1631,21 +1643,6 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios, */ uart_update_timeout(port, termios->c_cflag, baud); - /* - * disable interrupts and drain transmitter - */ - old_ucr1 = imx_uart_readl(sport, UCR1); - imx_uart_writel(sport, - old_ucr1 & ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN), - UCR1); - imx_uart_writel(sport, old_ucr2 & ~UCR2_ATEN, UCR2); - - while (!(imx_uart_readl(sport, USR2) & USR2_TXDC)) - barrier(); - - /* then, disable everything */ - imx_uart_writel(sport, old_ucr2 & ~(UCR2_TXEN | UCR2_RXEN | UCR2_ATEN), UCR2); - /* custom-baudrate handling */ div = sport->port.uartclk / (baud * 16); if (baud == 38400 && quot != div) @@ -1673,15 +1670,26 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios, ufcr = (ufcr & (~UFCR_RFDIV)) | UFCR_RFDIV_REG(div); imx_uart_writel(sport, ufcr, UFCR); - imx_uart_writel(sport, num, UBIR); - imx_uart_writel(sport, denom, UBMR); + /* + * Two registers below should always be written both and in this + * particular order. One consequence is that we need to check if any of + * them changes and then update both. We do need the check for change + * as even writing the same values seem to "restart" + * transmission/receiving logic in the hardware, that leads to data + * breakage even when rate doesn't in fact change. E.g., user switches + * RTS/CTS handshake and suddenly gets broken bytes. + */ + old_ubir = imx_uart_readl(sport, UBIR); + old_ubmr = imx_uart_readl(sport, UBMR); + if (old_ubir != num || old_ubmr != denom) { + imx_uart_writel(sport, num, UBIR); + imx_uart_writel(sport, denom, UBMR); + } if (!imx_uart_is_imx1(sport)) imx_uart_writel(sport, sport->port.uartclk / div / 1000, IMX21_ONEMS); - imx_uart_writel(sport, old_ucr1, UCR1); - imx_uart_writel(sport, ucr2, UCR2); if (UART_ENABLE_MS(&sport->port, termios->c_cflag)) @@ -1770,7 +1778,7 @@ static int imx_uart_poll_init(struct uart_port *port) ucr1 |= IMX1_UCR1_UARTCLKEN; ucr1 |= UCR1_UARTEN; - ucr1 &= ~(UCR1_TXMPTYEN | UCR1_RTSDEN | UCR1_RRDYEN); + ucr1 &= ~(UCR1_TRDYEN | UCR1_RTSDEN | UCR1_RRDYEN); ucr2 |= UCR2_RXEN; ucr2 &= ~UCR2_ATEN; @@ -1930,7 +1938,7 @@ imx_uart_console_write(struct console *co, const char *s, unsigned int count) if (imx_uart_is_imx1(sport)) ucr1 |= IMX1_UCR1_UARTCLKEN; ucr1 |= UCR1_UARTEN; - ucr1 &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN); + ucr1 &= ~(UCR1_TRDYEN | UCR1_RRDYEN | UCR1_RTSDEN); imx_uart_writel(sport, ucr1, UCR1); @@ -2286,7 +2294,7 @@ static int imx_uart_probe(struct platform_device *pdev) /* Disable interrupts before requesting them */ ucr1 = imx_uart_readl(sport, UCR1); ucr1 &= ~(UCR1_ADEN | UCR1_TRDYEN | UCR1_IDEN | UCR1_RRDYEN | - UCR1_TXMPTYEN | UCR1_RTSDEN); + UCR1_TRDYEN | UCR1_RTSDEN); imx_uart_writel(sport, ucr1, UCR1); if (!imx_uart_is_imx1(sport) && sport->dte_mode) { diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c index 9de9f0f239a1..fcbea43dc334 100644 --- a/drivers/tty/serial/lantiq.c +++ b/drivers/tty/serial/lantiq.c @@ -57,6 +57,7 @@ #define ASC_IRNCR_TIR 0x1 #define ASC_IRNCR_RIR 0x2 #define ASC_IRNCR_EIR 0x4 +#define ASC_IRNCR_MASK GENMASK(2, 0) #define ASCOPT_CSIZE 0x3 #define TXFIFO_FL 1 @@ -99,7 +100,12 @@ static void lqasc_tx_chars(struct uart_port *port); static struct ltq_uart_port *lqasc_port[MAXPORTS]; static struct uart_driver lqasc_reg; -static DEFINE_SPINLOCK(ltq_asc_lock); + +struct ltq_soc_data { + int (*fetch_irq)(struct device *dev, struct ltq_uart_port *ltq_port); + int (*request_irq)(struct uart_port *port); + void (*free_irq)(struct uart_port *port); +}; struct ltq_uart_port { struct uart_port port; @@ -110,6 +116,10 @@ struct ltq_uart_port { unsigned int tx_irq; unsigned int rx_irq; unsigned int err_irq; + unsigned int common_irq; + spinlock_t lock; /* exclusive access for multi core */ + + const struct ltq_soc_data *soc; }; static inline void asc_update_bits(u32 clear, u32 set, void __iomem *reg) @@ -135,9 +145,11 @@ static void lqasc_start_tx(struct uart_port *port) { unsigned long flags; - spin_lock_irqsave(<q_asc_lock, flags); + struct ltq_uart_port *ltq_port = to_ltq_uart_port(port); + + spin_lock_irqsave(<q_port->lock, flags); lqasc_tx_chars(port); - spin_unlock_irqrestore(<q_asc_lock, flags); + spin_unlock_irqrestore(<q_port->lock, flags); return; } @@ -245,9 +257,11 @@ lqasc_tx_int(int irq, void *_port) { unsigned long flags; struct uart_port *port = (struct uart_port *)_port; - spin_lock_irqsave(<q_asc_lock, flags); + struct ltq_uart_port *ltq_port = to_ltq_uart_port(port); + + spin_lock_irqsave(<q_port->lock, flags); __raw_writel(ASC_IRNCR_TIR, port->membase + LTQ_ASC_IRNCR); - spin_unlock_irqrestore(<q_asc_lock, flags); + spin_unlock_irqrestore(<q_port->lock, flags); lqasc_start_tx(port); return IRQ_HANDLED; } @@ -257,11 +271,13 @@ lqasc_err_int(int irq, void *_port) { unsigned long flags; struct uart_port *port = (struct uart_port *)_port; - spin_lock_irqsave(<q_asc_lock, flags); + struct ltq_uart_port *ltq_port = to_ltq_uart_port(port); + + spin_lock_irqsave(<q_port->lock, flags); /* clear any pending interrupts */ asc_update_bits(0, ASCWHBSTATE_CLRPE | ASCWHBSTATE_CLRFE | ASCWHBSTATE_CLRROE, port->membase + LTQ_ASC_WHBSTATE); - spin_unlock_irqrestore(<q_asc_lock, flags); + spin_unlock_irqrestore(<q_port->lock, flags); return IRQ_HANDLED; } @@ -270,10 +286,37 @@ lqasc_rx_int(int irq, void *_port) { unsigned long flags; struct uart_port *port = (struct uart_port *)_port; - spin_lock_irqsave(<q_asc_lock, flags); + struct ltq_uart_port *ltq_port = to_ltq_uart_port(port); + + spin_lock_irqsave(<q_port->lock, flags); __raw_writel(ASC_IRNCR_RIR, port->membase + LTQ_ASC_IRNCR); lqasc_rx_chars(port); - spin_unlock_irqrestore(<q_asc_lock, flags); + spin_unlock_irqrestore(<q_port->lock, flags); + return IRQ_HANDLED; +} + +static irqreturn_t lqasc_irq(int irq, void *p) +{ + unsigned long flags; + u32 stat; + struct uart_port *port = p; + struct ltq_uart_port *ltq_port = to_ltq_uart_port(port); + + spin_lock_irqsave(<q_port->lock, flags); + stat = readl(port->membase + LTQ_ASC_IRNCR); + spin_unlock_irqrestore(<q_port->lock, flags); + if (!(stat & ASC_IRNCR_MASK)) + return IRQ_NONE; + + if (stat & ASC_IRNCR_TIR) + lqasc_tx_int(irq, p); + + if (stat & ASC_IRNCR_RIR) + lqasc_rx_int(irq, p); + + if (stat & ASC_IRNCR_EIR) + lqasc_err_int(irq, p); + return IRQ_HANDLED; } @@ -307,11 +350,13 @@ lqasc_startup(struct uart_port *port) { struct ltq_uart_port *ltq_port = to_ltq_uart_port(port); int retval; + unsigned long flags; if (!IS_ERR(ltq_port->clk)) clk_prepare_enable(ltq_port->clk); port->uartclk = clk_get_rate(ltq_port->freqclk); + spin_lock_irqsave(<q_port->lock, flags); asc_update_bits(ASCCLC_DISS | ASCCLC_RMCMASK, (1 << ASCCLC_RMCOFFSET), port->membase + LTQ_ASC_CLC); @@ -331,35 +376,14 @@ lqasc_startup(struct uart_port *port) asc_update_bits(0, ASCCON_M_8ASYNC | ASCCON_FEN | ASCCON_TOEN | ASCCON_ROEN, port->membase + LTQ_ASC_CON); - retval = request_irq(ltq_port->tx_irq, lqasc_tx_int, - 0, "asc_tx", port); - if (retval) { - pr_err("failed to request lqasc_tx_int\n"); + spin_unlock_irqrestore(<q_port->lock, flags); + + retval = ltq_port->soc->request_irq(port); + if (retval) return retval; - } - - retval = request_irq(ltq_port->rx_irq, lqasc_rx_int, - 0, "asc_rx", port); - if (retval) { - pr_err("failed to request lqasc_rx_int\n"); - goto err1; - } - - retval = request_irq(ltq_port->err_irq, lqasc_err_int, - 0, "asc_err", port); - if (retval) { - pr_err("failed to request lqasc_err_int\n"); - goto err2; - } __raw_writel(ASC_IRNREN_RX | ASC_IRNREN_ERR | ASC_IRNREN_TX, port->membase + LTQ_ASC_IRNREN); - return 0; - -err2: - free_irq(ltq_port->rx_irq, port); -err1: - free_irq(ltq_port->tx_irq, port); return retval; } @@ -367,15 +391,17 @@ static void lqasc_shutdown(struct uart_port *port) { struct ltq_uart_port *ltq_port = to_ltq_uart_port(port); - free_irq(ltq_port->tx_irq, port); - free_irq(ltq_port->rx_irq, port); - free_irq(ltq_port->err_irq, port); + unsigned long flags; + ltq_port->soc->free_irq(port); + + spin_lock_irqsave(<q_port->lock, flags); __raw_writel(0, port->membase + LTQ_ASC_CON); asc_update_bits(ASCRXFCON_RXFEN, ASCRXFCON_RXFFLU, port->membase + LTQ_ASC_RXFCON); asc_update_bits(ASCTXFCON_TXFEN, ASCTXFCON_TXFFLU, port->membase + LTQ_ASC_TXFCON); + spin_unlock_irqrestore(<q_port->lock, flags); if (!IS_ERR(ltq_port->clk)) clk_disable_unprepare(ltq_port->clk); } @@ -390,6 +416,7 @@ lqasc_set_termios(struct uart_port *port, unsigned int baud; unsigned int con = 0; unsigned long flags; + struct ltq_uart_port *ltq_port = to_ltq_uart_port(port); cflag = new->c_cflag; iflag = new->c_iflag; @@ -443,7 +470,7 @@ lqasc_set_termios(struct uart_port *port, /* set error signals - framing, parity and overrun, enable receiver */ con |= ASCCON_FEN | ASCCON_TOEN | ASCCON_ROEN; - spin_lock_irqsave(<q_asc_lock, flags); + spin_lock_irqsave(<q_port->lock, flags); /* set up CON */ asc_update_bits(0, con, port->membase + LTQ_ASC_CON); @@ -471,7 +498,7 @@ lqasc_set_termios(struct uart_port *port, /* enable rx */ __raw_writel(ASCWHBSTATE_SETREN, port->membase + LTQ_ASC_WHBSTATE); - spin_unlock_irqrestore(<q_asc_lock, flags); + spin_unlock_irqrestore(<q_port->lock, flags); /* Don't rewrite B0 */ if (tty_termios_baud_rate(new)) @@ -589,17 +616,14 @@ lqasc_console_putchar(struct uart_port *port, int ch) static void lqasc_serial_port_write(struct uart_port *port, const char *s, u_int count) { - unsigned long flags; - - spin_lock_irqsave(<q_asc_lock, flags); uart_console_write(port, s, count, lqasc_console_putchar); - spin_unlock_irqrestore(<q_asc_lock, flags); } static void lqasc_console_write(struct console *co, const char *s, u_int count) { struct ltq_uart_port *ltq_port; + unsigned long flags; if (co->index >= MAXPORTS) return; @@ -608,7 +632,9 @@ lqasc_console_write(struct console *co, const char *s, u_int count) if (!ltq_port) return; + spin_lock_irqsave(<q_port->lock, flags); lqasc_serial_port_write(<q_port->port, s, count); + spin_unlock_irqrestore(<q_port->lock, flags); } static int __init @@ -677,7 +703,8 @@ lqasc_serial_early_console_setup(struct earlycon_device *device, device->con->write = lqasc_serial_early_console_write; return 0; } -OF_EARLYCON_DECLARE(lantiq, DRVNAME, lqasc_serial_early_console_setup); +OF_EARLYCON_DECLARE(lantiq, "lantiq,asc", lqasc_serial_early_console_setup); +OF_EARLYCON_DECLARE(lantiq, "intel,lgm-asc", lqasc_serial_early_console_setup); static struct uart_driver lqasc_reg = { .owner = THIS_MODULE, @@ -689,24 +716,134 @@ static struct uart_driver lqasc_reg = { .cons = &lqasc_console, }; +static int fetch_irq_lantiq(struct device *dev, struct ltq_uart_port *ltq_port) +{ + struct uart_port *port = <q_port->port; + struct resource irqres[3]; + int ret; + + ret = of_irq_to_resource_table(dev->of_node, irqres, 3); + if (ret != 3) { + dev_err(dev, + "failed to get IRQs for serial port\n"); + return -ENODEV; + } + ltq_port->tx_irq = irqres[0].start; + ltq_port->rx_irq = irqres[1].start; + ltq_port->err_irq = irqres[2].start; + port->irq = irqres[0].start; + + return 0; +} + +static int request_irq_lantiq(struct uart_port *port) +{ + struct ltq_uart_port *ltq_port = to_ltq_uart_port(port); + int retval; + + retval = request_irq(ltq_port->tx_irq, lqasc_tx_int, + 0, "asc_tx", port); + if (retval) { + dev_err(port->dev, "failed to request asc_tx\n"); + return retval; + } + + retval = request_irq(ltq_port->rx_irq, lqasc_rx_int, + 0, "asc_rx", port); + if (retval) { + dev_err(port->dev, "failed to request asc_rx\n"); + goto err1; + } + + retval = request_irq(ltq_port->err_irq, lqasc_err_int, + 0, "asc_err", port); + if (retval) { + dev_err(port->dev, "failed to request asc_err\n"); + goto err2; + } + return 0; + +err2: + free_irq(ltq_port->rx_irq, port); +err1: + free_irq(ltq_port->tx_irq, port); + return retval; +} + +static void free_irq_lantiq(struct uart_port *port) +{ + struct ltq_uart_port *ltq_port = to_ltq_uart_port(port); + + free_irq(ltq_port->tx_irq, port); + free_irq(ltq_port->rx_irq, port); + free_irq(ltq_port->err_irq, port); +} + +static int fetch_irq_intel(struct device *dev, struct ltq_uart_port *ltq_port) +{ + struct uart_port *port = <q_port->port; + int ret; + + ret = of_irq_get(dev->of_node, 0); + if (ret < 0) { + dev_err(dev, "failed to fetch IRQ for serial port\n"); + return ret; + } + ltq_port->common_irq = ret; + port->irq = ret; + + return 0; +} + +static int request_irq_intel(struct uart_port *port) +{ + struct ltq_uart_port *ltq_port = to_ltq_uart_port(port); + int retval; + + retval = request_irq(ltq_port->common_irq, lqasc_irq, 0, + "asc_irq", port); + if (retval) + dev_err(port->dev, "failed to request asc_irq\n"); + + return retval; +} + +static void free_irq_intel(struct uart_port *port) +{ + struct ltq_uart_port *ltq_port = to_ltq_uart_port(port); + + free_irq(ltq_port->common_irq, port); +} + static int __init lqasc_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; struct ltq_uart_port *ltq_port; struct uart_port *port; - struct resource *mmres, irqres[3]; + struct resource *mmres; int line; int ret; mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ret = of_irq_to_resource_table(node, irqres, 3); - if (!mmres || (ret != 3)) { + if (!mmres) { dev_err(&pdev->dev, - "failed to get memory/irq for serial port\n"); + "failed to get memory for serial port\n"); return -ENODEV; } + ltq_port = devm_kzalloc(&pdev->dev, sizeof(struct ltq_uart_port), + GFP_KERNEL); + if (!ltq_port) + return -ENOMEM; + + port = <q_port->port; + + ltq_port->soc = of_device_get_match_data(&pdev->dev); + ret = ltq_port->soc->fetch_irq(&pdev->dev, ltq_port); + if (ret) + return ret; + /* get serial id */ line = of_alias_get_id(node, "serial"); if (line < 0) { @@ -727,13 +864,6 @@ lqasc_probe(struct platform_device *pdev) return -EBUSY; } - ltq_port = devm_kzalloc(&pdev->dev, sizeof(struct ltq_uart_port), - GFP_KERNEL); - if (!ltq_port) - return -ENOMEM; - - port = <q_port->port; - port->iotype = SERIAL_IO_MEM; port->flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP; port->ops = &lqasc_pops; @@ -742,7 +872,6 @@ lqasc_probe(struct platform_device *pdev) port->line = line; port->dev = &pdev->dev; /* unused, just to be backward-compatible */ - port->irq = irqres[0].start; port->mapbase = mmres->start; if (IS_ENABLED(CONFIG_LANTIQ) && !IS_ENABLED(CONFIG_COMMON_CLK)) @@ -762,10 +891,7 @@ lqasc_probe(struct platform_device *pdev) else ltq_port->clk = devm_clk_get(&pdev->dev, "asc"); - ltq_port->tx_irq = irqres[0].start; - ltq_port->rx_irq = irqres[1].start; - ltq_port->err_irq = irqres[2].start; - + spin_lock_init(<q_port->lock); lqasc_port[line] = ltq_port; platform_set_drvdata(pdev, ltq_port); @@ -774,8 +900,21 @@ lqasc_probe(struct platform_device *pdev) return ret; } +static const struct ltq_soc_data soc_data_lantiq = { + .fetch_irq = fetch_irq_lantiq, + .request_irq = request_irq_lantiq, + .free_irq = free_irq_lantiq, +}; + +static const struct ltq_soc_data soc_data_intel = { + .fetch_irq = fetch_irq_intel, + .request_irq = request_irq_intel, + .free_irq = free_irq_intel, +}; + static const struct of_device_id ltq_asc_match[] = { - { .compatible = DRVNAME }, + { .compatible = "lantiq,asc", .data = &soc_data_lantiq }, + { .compatible = "intel,lgm-asc", .data = &soc_data_intel }, {}, }; diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c index d3843f722182..9a836dcac157 100644 --- a/drivers/tty/serial/lpc32xx_hs.c +++ b/drivers/tty/serial/lpc32xx_hs.c @@ -658,11 +658,8 @@ static int serial_hs_lpc32xx_probe(struct platform_device *pdev) p->port.membase = NULL; ret = platform_get_irq(pdev, 0); - if (ret < 0) { - dev_err(&pdev->dev, "Error getting irq for HS UART port %d\n", - uarts_registered); + if (ret < 0) return ret; - } p->port.irq = ret; p->port.iotype = UPIO_MEM32; diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index e6c48a99bd85..8434bd5a8ec7 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -689,7 +689,7 @@ static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen) * tail. */ uart_insert_char(port, sts, MAX310X_LSR_RXOVR_BIT, - one->rx_buf[rxlen], flag); + one->rx_buf[rxlen-1], flag); } else { if (unlikely(rxlen >= port->fifosize)) { @@ -955,17 +955,43 @@ static void max310x_set_termios(struct uart_port *port, /* Configure flow control */ max310x_port_write(port, MAX310X_XON1_REG, termios->c_cc[VSTART]); max310x_port_write(port, MAX310X_XOFF1_REG, termios->c_cc[VSTOP]); - if (termios->c_cflag & CRTSCTS) + + /* Disable transmitter before enabling AutoCTS or auto transmitter + * flow control + */ + if (termios->c_cflag & CRTSCTS || termios->c_iflag & IXOFF) { + max310x_port_update(port, MAX310X_MODE1_REG, + MAX310X_MODE1_TXDIS_BIT, + MAX310X_MODE1_TXDIS_BIT); + } + + port->status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF); + + if (termios->c_cflag & CRTSCTS) { + /* Enable AUTORTS and AUTOCTS */ + port->status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS; flow |= MAX310X_FLOWCTRL_AUTOCTS_BIT | MAX310X_FLOWCTRL_AUTORTS_BIT; + } if (termios->c_iflag & IXON) flow |= MAX310X_FLOWCTRL_SWFLOW3_BIT | MAX310X_FLOWCTRL_SWFLOWEN_BIT; - if (termios->c_iflag & IXOFF) + if (termios->c_iflag & IXOFF) { + port->status |= UPSTAT_AUTOXOFF; flow |= MAX310X_FLOWCTRL_SWFLOW1_BIT | MAX310X_FLOWCTRL_SWFLOWEN_BIT; + } max310x_port_write(port, MAX310X_FLOWCTRL_REG, flow); + /* Enable transmitter after disabling AutoCTS and auto transmitter + * flow control + */ + if (!(termios->c_cflag & CRTSCTS) && !(termios->c_iflag & IXOFF)) { + max310x_port_update(port, MAX310X_MODE1_REG, + MAX310X_MODE1_TXDIS_BIT, + 0); + } + /* Get baud rate generator configuration */ baud = uart_get_baud_rate(port, termios, old, port->uartclk / 16 / 0xffff, diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c index 7e7b1559fa36..c12a12556339 100644 --- a/drivers/tty/serial/mvebu-uart.c +++ b/drivers/tty/serial/mvebu-uart.c @@ -884,10 +884,8 @@ static int mvebu_uart_probe(struct platform_device *pdev) if (platform_irq_count(pdev) == 1) { /* Old bindings: no name on the single unamed UART0 IRQ */ irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "unable to get UART IRQ\n"); + if (irq < 0) return irq; - } mvuart->irq[UART_IRQ_SUM] = irq; } else { @@ -897,18 +895,14 @@ static int mvebu_uart_probe(struct platform_device *pdev) * uart-sum of UART0 port. */ irq = platform_get_irq_byname(pdev, "uart-rx"); - if (irq < 0) { - dev_err(&pdev->dev, "unable to get 'uart-rx' IRQ\n"); + if (irq < 0) return irq; - } mvuart->irq[UART_RX_IRQ] = irq; irq = platform_get_irq_byname(pdev, "uart-tx"); - if (irq < 0) { - dev_err(&pdev->dev, "unable to get 'uart-tx' IRQ\n"); + if (irq < 0) return irq; - } mvuart->irq[UART_TX_IRQ] = irq; } diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index 4c188f4079b3..e34525970682 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -969,10 +969,8 @@ err_out: } -#define RTS_AT_AUART() IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(s->gpios, \ - UART_GPIO_RTS)) -#define CTS_AT_AUART() IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(s->gpios, \ - UART_GPIO_CTS)) +#define RTS_AT_AUART() !mctrl_gpio_to_gpiod(s->gpios, UART_GPIO_RTS) +#define CTS_AT_AUART() !mctrl_gpio_to_gpiod(s->gpios, UART_GPIO_CTS) static void mxs_auart_settermios(struct uart_port *u, struct ktermios *termios, struct ktermios *old) diff --git a/drivers/tty/serial/owl-uart.c b/drivers/tty/serial/owl-uart.c index 29a6dc6a8d23..03963af77b15 100644 --- a/drivers/tty/serial/owl-uart.c +++ b/drivers/tty/serial/owl-uart.c @@ -662,10 +662,8 @@ static int owl_uart_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "could not get irq\n"); + if (irq < 0) return irq; - } if (owl_uart_ports[pdev->id]) { dev_err(&pdev->dev, "port %d already allocated\n", pdev->id); diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index 35e5f9c5d5be..14c6306bc462 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -198,10 +198,8 @@ static int qcom_geni_serial_request_port(struct uart_port *uport) { struct platform_device *pdev = to_platform_device(uport->dev); struct qcom_geni_serial_port *port = to_dev_port(uport, uport); - struct resource *res; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - uport->membase = devm_ioremap_resource(&pdev->dev, res); + uport->membase = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(uport->membase)) return PTR_ERR(uport->membase); port->se.base = uport->membase; @@ -920,12 +918,13 @@ static unsigned long get_clk_cfg(unsigned long clk_freq) return 0; } -static unsigned long get_clk_div_rate(unsigned int baud, unsigned int *clk_div) +static unsigned long get_clk_div_rate(unsigned int baud, + unsigned int sampling_rate, unsigned int *clk_div) { unsigned long ser_clk; unsigned long desired_clk; - desired_clk = baud * UART_OVERSAMPLING; + desired_clk = baud * sampling_rate; ser_clk = get_clk_cfg(desired_clk); if (!ser_clk) { pr_err("%s: Can't find matching DFS entry for baud %d\n", @@ -951,12 +950,20 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport, u32 ser_clk_cfg; struct qcom_geni_serial_port *port = to_dev_port(uport, uport); unsigned long clk_rate; + u32 ver, sampling_rate; qcom_geni_serial_stop_rx(uport); /* baud rate */ baud = uart_get_baud_rate(uport, termios, old, 300, 4000000); port->baud = baud; - clk_rate = get_clk_div_rate(baud, &clk_div); + + sampling_rate = UART_OVERSAMPLING; + /* Sampling rate is halved for IP versions >= 2.5 */ + ver = geni_se_get_qup_hw_version(&port->se); + if (GENI_SE_VERSION_MAJOR(ver) >= 2 && GENI_SE_VERSION_MINOR(ver) >= 5) + sampling_rate /= 2; + + clk_rate = get_clk_div_rate(baud, sampling_rate, &clk_div); if (!clk_rate) goto out_restart_rx; @@ -1291,10 +1298,8 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) port->tx_fifo_width = DEF_FIFO_WIDTH_BITS; irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "Failed to get IRQ %d\n", irq); + if (irq < 0) return irq; - } uport->irq = irq; uport->private_data = drv; diff --git a/drivers/tty/serial/rda-uart.c b/drivers/tty/serial/rda-uart.c index 284623eefaeb..c1b0d7662ef9 100644 --- a/drivers/tty/serial/rda-uart.c +++ b/drivers/tty/serial/rda-uart.c @@ -735,10 +735,8 @@ static int rda_uart_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "could not get irq\n"); + if (irq < 0) return irq; - } if (rda_uart_ports[pdev->id]) { dev_err(&pdev->dev, "port %d already allocated\n", pdev->id); diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c index 68a24a14f6b7..d2b77aae42ae 100644 --- a/drivers/tty/serial/sccnxp.c +++ b/drivers/tty/serial/sccnxp.c @@ -961,7 +961,6 @@ static int sccnxp_probe(struct platform_device *pdev) if (!s->poll) { s->irq = platform_get_irq(pdev, 0); if (s->irq < 0) { - dev_err(&pdev->dev, "Missing irq resource data\n"); ret = -ENXIO; goto err_out; } diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c index d5269aaaf9b2..2f599515c133 100644 --- a/drivers/tty/serial/serial-tegra.c +++ b/drivers/tty/serial/serial-tegra.c @@ -4,7 +4,7 @@ * * High-speed serial driver for NVIDIA Tegra SoCs * - * Copyright (c) 2012-2013, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2012-2019, NVIDIA CORPORATION. All rights reserved. * * Author: Laxman Dewangan */ @@ -62,7 +62,7 @@ #define TEGRA_UART_TX_TRIG_4B 0x20 #define TEGRA_UART_TX_TRIG_1B 0x30 -#define TEGRA_UART_MAXIMUM 5 +#define TEGRA_UART_MAXIMUM 8 /* Default UART setting when started: 115200 no parity, stop, 8 data bits */ #define TEGRA_UART_DEFAULT_BAUD 115200 @@ -72,6 +72,8 @@ #define TEGRA_TX_PIO 1 #define TEGRA_TX_DMA 2 +#define TEGRA_UART_FCR_IIR_FIFO_EN 0x40 + /** * tegra_uart_chip_data: SOC specific data. * @@ -84,6 +86,17 @@ struct tegra_uart_chip_data { bool tx_fifo_full_status; bool allow_txfifo_reset_fifo_mode; bool support_clk_src_div; + bool fifo_mode_enable_status; + int uart_max_port; + int max_dma_burst_bytes; + int error_tolerance_low_range; + int error_tolerance_high_range; +}; + +struct tegra_baud_tolerance { + u32 lower_range_baud; + u32 upper_range_baud; + s32 tolerance; }; struct tegra_uart_port { @@ -122,10 +135,18 @@ struct tegra_uart_port { dma_cookie_t rx_cookie; unsigned int tx_bytes_requested; unsigned int rx_bytes_requested; + struct tegra_baud_tolerance *baud_tolerance; + int n_adjustable_baud_rates; + int required_rate; + int configured_rate; + bool use_rx_pio; + bool use_tx_pio; }; static void tegra_uart_start_next_tx(struct tegra_uart_port *tup); static int tegra_uart_start_rx_dma(struct tegra_uart_port *tup); +static void tegra_uart_dma_channel_free(struct tegra_uart_port *tup, + bool dma_to_memory); static inline unsigned long tegra_uart_read(struct tegra_uart_port *tup, unsigned long reg) @@ -192,16 +213,34 @@ static void set_dtr(struct tegra_uart_port *tup, bool active) } } +static void set_loopbk(struct tegra_uart_port *tup, bool active) +{ + unsigned long mcr = tup->mcr_shadow; + + if (active) + mcr |= UART_MCR_LOOP; + else + mcr &= ~UART_MCR_LOOP; + + if (mcr != tup->mcr_shadow) { + tegra_uart_write(tup, mcr, UART_MCR); + tup->mcr_shadow = mcr; + } +} + static void tegra_uart_set_mctrl(struct uart_port *u, unsigned int mctrl) { struct tegra_uart_port *tup = to_tegra_uport(u); - int dtr_enable; + int enable; tup->rts_active = !!(mctrl & TIOCM_RTS); set_rts(tup, tup->rts_active); - dtr_enable = !!(mctrl & TIOCM_DTR); - set_dtr(tup, dtr_enable); + enable = !!(mctrl & TIOCM_DTR); + set_dtr(tup, enable); + + enable = !!(mctrl & TIOCM_LOOP); + set_loopbk(tup, enable); } static void tegra_uart_break_ctl(struct uart_port *u, int break_ctl) @@ -243,9 +282,28 @@ static void tegra_uart_wait_sym_time(struct tegra_uart_port *tup, tup->current_baud)); } +static int tegra_uart_wait_fifo_mode_enabled(struct tegra_uart_port *tup) +{ + unsigned long iir; + unsigned int tmout = 100; + + do { + iir = tegra_uart_read(tup, UART_IIR); + if (iir & TEGRA_UART_FCR_IIR_FIFO_EN) + return 0; + udelay(1); + } while (--tmout); + + return -ETIMEDOUT; +} + static void tegra_uart_fifo_reset(struct tegra_uart_port *tup, u8 fcr_bits) { unsigned long fcr = tup->fcr_shadow; + unsigned int lsr, tmout = 10000; + + if (tup->rts_active) + set_rts(tup, false); if (tup->cdata->allow_txfifo_reset_fifo_mode) { fcr |= fcr_bits & (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); @@ -258,6 +316,8 @@ static void tegra_uart_fifo_reset(struct tegra_uart_port *tup, u8 fcr_bits) tegra_uart_write(tup, fcr, UART_FCR); fcr |= UART_FCR_ENABLE_FIFO; tegra_uart_write(tup, fcr, UART_FCR); + if (tup->cdata->fifo_mode_enable_status) + tegra_uart_wait_fifo_mode_enabled(tup); } /* Dummy read to ensure the write is posted */ @@ -269,6 +329,47 @@ static void tegra_uart_fifo_reset(struct tegra_uart_port *tup, u8 fcr_bits) * to propagate, otherwise data could be lost. */ tegra_uart_wait_cycle_time(tup, 32); + + do { + lsr = tegra_uart_read(tup, UART_LSR); + if ((lsr | UART_LSR_TEMT) && !(lsr & UART_LSR_DR)) + break; + udelay(1); + } while (--tmout); + + if (tup->rts_active) + set_rts(tup, true); +} + +static long tegra_get_tolerance_rate(struct tegra_uart_port *tup, + unsigned int baud, long rate) +{ + int i; + + for (i = 0; i < tup->n_adjustable_baud_rates; ++i) { + if (baud >= tup->baud_tolerance[i].lower_range_baud && + baud <= tup->baud_tolerance[i].upper_range_baud) + return (rate + (rate * + tup->baud_tolerance[i].tolerance) / 10000); + } + + return rate; +} + +static int tegra_check_rate_in_range(struct tegra_uart_port *tup) +{ + long diff; + + diff = ((long)(tup->configured_rate - tup->required_rate) * 10000) + / tup->required_rate; + if (diff < (tup->cdata->error_tolerance_low_range * 100) || + diff > (tup->cdata->error_tolerance_high_range * 100)) { + dev_err(tup->uport.dev, + "configured baud rate is out of range by %ld", diff); + return -EIO; + } + + return 0; } static int tegra_set_baudrate(struct tegra_uart_port *tup, unsigned int baud) @@ -276,6 +377,7 @@ static int tegra_set_baudrate(struct tegra_uart_port *tup, unsigned int baud) unsigned long rate; unsigned int divisor; unsigned long lcr; + unsigned long flags; int ret; if (tup->current_baud == baud) @@ -283,18 +385,28 @@ static int tegra_set_baudrate(struct tegra_uart_port *tup, unsigned int baud) if (tup->cdata->support_clk_src_div) { rate = baud * 16; + tup->required_rate = rate; + + if (tup->n_adjustable_baud_rates) + rate = tegra_get_tolerance_rate(tup, baud, rate); + ret = clk_set_rate(tup->uart_clk, rate); if (ret < 0) { dev_err(tup->uport.dev, "clk_set_rate() failed for rate %lu\n", rate); return ret; } + tup->configured_rate = clk_get_rate(tup->uart_clk); divisor = 1; + ret = tegra_check_rate_in_range(tup); + if (ret < 0) + return ret; } else { rate = clk_get_rate(tup->uart_clk); divisor = DIV_ROUND_CLOSEST(rate, baud * 16); } + spin_lock_irqsave(&tup->uport.lock, flags); lcr = tup->lcr_shadow; lcr |= UART_LCR_DLAB; tegra_uart_write(tup, lcr, UART_LCR); @@ -307,6 +419,7 @@ static int tegra_set_baudrate(struct tegra_uart_port *tup, unsigned int baud) /* Dummy read to ensure the write is posted */ tegra_uart_read(tup, UART_SCR); + spin_unlock_irqrestore(&tup->uport.lock, flags); tup->current_baud = baud; @@ -336,13 +449,21 @@ static char tegra_uart_decode_rx_error(struct tegra_uart_port *tup, tup->uport.icount.frame++; dev_err(tup->uport.dev, "Got frame errors\n"); } else if (lsr & UART_LSR_BI) { - dev_err(tup->uport.dev, "Got Break\n"); - tup->uport.icount.brk++; - /* If FIFO read error without any data, reset Rx FIFO */ + /* + * Break error + * If FIFO read error without any data, reset Rx FIFO + */ if (!(lsr & UART_LSR_DR) && (lsr & UART_LSR_FIFOE)) tegra_uart_fifo_reset(tup, UART_FCR_CLEAR_RCVR); + if (tup->uport.ignore_status_mask & UART_LSR_BI) + return TTY_BREAK; + flag = TTY_BREAK; + tup->uport.icount.brk++; + dev_dbg(tup->uport.dev, "Got Break\n"); } + uart_insert_char(&tup->uport, lsr, UART_LSR_OE, 0, flag); } + return flag; } @@ -440,12 +561,15 @@ static void tegra_uart_start_next_tx(struct tegra_uart_port *tup) unsigned long count; struct circ_buf *xmit = &tup->uport.state->xmit; + if (!tup->current_baud) + return; + tail = (unsigned long)&xmit->buf[xmit->tail]; count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); if (!count) return; - if (count < TEGRA_UART_MIN_DMA) + if (tup->use_tx_pio || count < TEGRA_UART_MIN_DMA) tegra_uart_start_pio_tx(tup, count); else if (BYTES_TO_ALIGN(tail) > 0) tegra_uart_start_pio_tx(tup, BYTES_TO_ALIGN(tail)); @@ -521,11 +645,17 @@ static void tegra_uart_handle_rx_pio(struct tegra_uart_port *tup, break; flag = tegra_uart_decode_rx_error(tup, lsr); + if (flag != TTY_NORMAL) + continue; + ch = (unsigned char) tegra_uart_read(tup, UART_RX); tup->uport.icount.rx++; if (!uart_handle_sysrq_char(&tup->uport, ch) && tty) tty_insert_flip_char(tty, ch, flag); + + if (tup->uport.ignore_status_mask & UART_LSR_DR) + continue; } while (1); } @@ -544,6 +674,10 @@ static void tegra_uart_copy_rx_to_tty(struct tegra_uart_port *tup, dev_err(tup->uport.dev, "No tty port\n"); return; } + + if (tup->uport.ignore_status_mask & UART_LSR_DR) + return; + dma_sync_single_for_cpu(tup->uport.dev, tup->rx_dma_buf_phys, TEGRA_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE); copied = tty_insert_flip_string(tty, @@ -668,6 +802,18 @@ static void tegra_uart_handle_modem_signal_change(struct uart_port *u) uart_handle_cts_change(&tup->uport, msr & UART_MSR_CTS); } +static void do_handle_rx_pio(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; + + tegra_uart_handle_rx_pio(tup, port); + if (tty) { + tty_flip_buffer_push(port); + tty_kref_put(tty); + } +} + static irqreturn_t tegra_uart_isr(int irq, void *data) { struct tegra_uart_port *tup = data; @@ -681,7 +827,7 @@ static irqreturn_t tegra_uart_isr(int irq, void *data) while (1) { iir = tegra_uart_read(tup, UART_IIR); if (iir & UART_IIR_NO_INT) { - if (is_rx_int) { + if (!tup->use_rx_pio && is_rx_int) { tegra_uart_handle_rx_dma(tup); if (tup->rx_in_progress) { ier = tup->ier_shadow; @@ -709,7 +855,7 @@ static irqreturn_t tegra_uart_isr(int irq, void *data) case 4: /* End of data */ case 6: /* Rx timeout */ case 2: /* Receive */ - if (!is_rx_int) { + if (!tup->use_rx_pio && !is_rx_int) { is_rx_int = true; /* Disable Rx interrupts */ ier = tup->ier_shadow; @@ -719,6 +865,8 @@ static irqreturn_t tegra_uart_isr(int irq, void *data) UART_IER_RTOIE | TEGRA_UART_IER_EORD); tup->ier_shadow = ier; tegra_uart_write(tup, ier, UART_IER); + } else { + do_handle_rx_pio(tup); } break; @@ -737,6 +885,7 @@ static irqreturn_t tegra_uart_isr(int irq, void *data) static void tegra_uart_stop_rx(struct uart_port *u) { struct tegra_uart_port *tup = to_tegra_uport(u); + struct tty_port *port = &tup->uport.state->port; struct dma_tx_state state; unsigned long ier; @@ -754,9 +903,13 @@ static void tegra_uart_stop_rx(struct uart_port *u) tup->ier_shadow = ier; tegra_uart_write(tup, ier, UART_IER); tup->rx_in_progress = 0; - dmaengine_terminate_all(tup->rx_dma_chan); - dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state); - tegra_uart_rx_buffer_push(tup, state.residue); + if (tup->rx_dma_chan && !tup->use_rx_pio) { + dmaengine_terminate_all(tup->rx_dma_chan); + dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state); + tegra_uart_rx_buffer_push(tup, state.residue); + } else { + tegra_uart_handle_rx_pio(tup, port); + } } static void tegra_uart_hw_deinit(struct tegra_uart_port *tup) @@ -804,6 +957,14 @@ static void tegra_uart_hw_deinit(struct tegra_uart_port *tup) tup->current_baud = 0; spin_unlock_irqrestore(&tup->uport.lock, flags); + tup->rx_in_progress = 0; + tup->tx_in_progress = 0; + + if (!tup->use_rx_pio) + tegra_uart_dma_channel_free(tup, true); + if (!tup->use_tx_pio) + tegra_uart_dma_channel_free(tup, false); + clk_disable_unprepare(tup->uart_clk); } @@ -846,35 +1007,60 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup) * programmed in the DMA registers. */ tup->fcr_shadow = UART_FCR_ENABLE_FIFO; - tup->fcr_shadow |= UART_FCR_R_TRIG_01; + + if (tup->use_rx_pio) { + tup->fcr_shadow |= UART_FCR_R_TRIG_11; + } else { + if (tup->cdata->max_dma_burst_bytes == 8) + tup->fcr_shadow |= UART_FCR_R_TRIG_10; + else + tup->fcr_shadow |= UART_FCR_R_TRIG_01; + } + 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); + if (tup->cdata->fifo_mode_enable_status) { + ret = tegra_uart_wait_fifo_mode_enabled(tup); + dev_err(tup->uport.dev, "FIFO mode not enabled\n"); + if (ret < 0) + return ret; + } else { + /* + * 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 * enqueued */ - tup->lcr_shadow = TEGRA_UART_DEFAULT_LSR; - tegra_set_baudrate(tup, TEGRA_UART_DEFAULT_BAUD); - tup->fcr_shadow |= UART_FCR_DMA_SELECT; - tegra_uart_write(tup, tup->fcr_shadow, UART_FCR); - - ret = tegra_uart_start_rx_dma(tup); + ret = tegra_set_baudrate(tup, TEGRA_UART_DEFAULT_BAUD); if (ret < 0) { - dev_err(tup->uport.dev, "Not able to start Rx DMA\n"); + dev_err(tup->uport.dev, "Failed to set baud rate\n"); return ret; } + if (!tup->use_rx_pio) { + tup->lcr_shadow = TEGRA_UART_DEFAULT_LSR; + tup->fcr_shadow |= UART_FCR_DMA_SELECT; + tegra_uart_write(tup, tup->fcr_shadow, UART_FCR); + + ret = tegra_uart_start_rx_dma(tup); + if (ret < 0) { + dev_err(tup->uport.dev, "Not able to start Rx DMA\n"); + return ret; + } + } else { + tegra_uart_write(tup, tup->fcr_shadow, UART_FCR); + } tup->rx_in_progress = 1; /* @@ -895,7 +1081,12 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup) * both the EORD as well as RX_TIMEOUT - SW sees RX_TIMEOUT first * then the EORD. */ - tup->ier_shadow = UART_IER_RLSI | UART_IER_RTOIE | TEGRA_UART_IER_EORD; + if (!tup->use_rx_pio) + tup->ier_shadow = UART_IER_RLSI | UART_IER_RTOIE | + TEGRA_UART_IER_EORD; + else + tup->ier_shadow = UART_IER_RLSI | UART_IER_RTOIE | UART_IER_RDI; + tegra_uart_write(tup, tup->ier_shadow, UART_IER); return 0; } @@ -952,7 +1143,7 @@ static int tegra_uart_dma_channel_allocate(struct tegra_uart_port *tup, } dma_sconfig.src_addr = tup->uport.mapbase; dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; - dma_sconfig.src_maxburst = 4; + dma_sconfig.src_maxburst = tup->cdata->max_dma_burst_bytes; tup->rx_dma_chan = dma_chan; tup->rx_dma_buf_virt = dma_buf; tup->rx_dma_buf_phys = dma_phys; @@ -990,16 +1181,22 @@ static int tegra_uart_startup(struct uart_port *u) struct tegra_uart_port *tup = to_tegra_uport(u); int ret; - ret = tegra_uart_dma_channel_allocate(tup, false); - if (ret < 0) { - dev_err(u->dev, "Tx Dma allocation failed, err = %d\n", ret); - return ret; + if (!tup->use_tx_pio) { + ret = tegra_uart_dma_channel_allocate(tup, false); + if (ret < 0) { + dev_err(u->dev, "Tx Dma allocation failed, err = %d\n", + ret); + return ret; + } } - ret = tegra_uart_dma_channel_allocate(tup, true); - if (ret < 0) { - dev_err(u->dev, "Rx Dma allocation failed, err = %d\n", ret); - goto fail_rx_dma; + if (!tup->use_rx_pio) { + ret = tegra_uart_dma_channel_allocate(tup, true); + if (ret < 0) { + dev_err(u->dev, "Rx Dma allocation failed, err = %d\n", + ret); + goto fail_rx_dma; + } } ret = tegra_uart_hw_init(tup); @@ -1017,9 +1214,11 @@ static int tegra_uart_startup(struct uart_port *u) return 0; fail_hw_init: - tegra_uart_dma_channel_free(tup, true); + if (!tup->use_rx_pio) + tegra_uart_dma_channel_free(tup, true); fail_rx_dma: - tegra_uart_dma_channel_free(tup, false); + if (!tup->use_tx_pio) + tegra_uart_dma_channel_free(tup, false); return ret; } @@ -1041,12 +1240,6 @@ static void tegra_uart_shutdown(struct uart_port *u) struct tegra_uart_port *tup = to_tegra_uport(u); tegra_uart_hw_deinit(tup); - - tup->rx_in_progress = 0; - tup->tx_in_progress = 0; - - tegra_uart_dma_channel_free(tup, true); - tegra_uart_dma_channel_free(tup, false); free_irq(u->irq, tup); } @@ -1071,6 +1264,7 @@ static void tegra_uart_set_termios(struct uart_port *u, struct clk *parent_clk = clk_get_parent(tup->uart_clk); unsigned long parent_clk_rate = clk_get_rate(parent_clk); int max_divider = (tup->cdata->support_clk_src_div) ? 0x7FFF : 0xFFFF; + int ret; max_divider *= 16; spin_lock_irqsave(&u->lock, flags); @@ -1143,7 +1337,11 @@ static void tegra_uart_set_termios(struct uart_port *u, parent_clk_rate/max_divider, parent_clk_rate/16); spin_unlock_irqrestore(&u->lock, flags); - tegra_set_baudrate(tup, baud); + ret = tegra_set_baudrate(tup, baud); + if (ret < 0) { + dev_err(tup->uport.dev, "Failed to set baud rate\n"); + return; + } if (tty_termios_baud_rate(termios)) tty_termios_encode_baud_rate(termios, baud, baud); spin_lock_irqsave(&u->lock, flags); @@ -1172,6 +1370,13 @@ static void tegra_uart_set_termios(struct uart_port *u, tegra_uart_write(tup, tup->ier_shadow, UART_IER); tegra_uart_read(tup, UART_IER); + tup->uport.ignore_status_mask = 0; + /* Ignore all characters if CREAD is not set */ + if ((termios->c_cflag & CREAD) == 0) + tup->uport.ignore_status_mask |= UART_LSR_DR; + if (termios->c_iflag & IGNBRK) + tup->uport.ignore_status_mask |= UART_LSR_BI; + spin_unlock_irqrestore(&u->lock, flags); } @@ -1211,6 +1416,11 @@ static int tegra_uart_parse_dt(struct platform_device *pdev, { struct device_node *np = pdev->dev.of_node; int port; + int ret; + int index; + u32 pval; + int count; + int n_entries; port = of_alias_get_id(np, "serial"); if (port < 0) { @@ -1221,6 +1431,54 @@ static int tegra_uart_parse_dt(struct platform_device *pdev, tup->enable_modem_interrupt = of_property_read_bool(np, "nvidia,enable-modem-interrupt"); + + index = of_property_match_string(np, "dma-names", "rx"); + if (index < 0) { + tup->use_rx_pio = true; + dev_info(&pdev->dev, "RX in PIO mode\n"); + } + index = of_property_match_string(np, "dma-names", "tx"); + if (index < 0) { + tup->use_tx_pio = true; + dev_info(&pdev->dev, "TX in PIO mode\n"); + } + + n_entries = of_property_count_u32_elems(np, "nvidia,adjust-baud-rates"); + if (n_entries > 0) { + tup->n_adjustable_baud_rates = n_entries / 3; + tup->baud_tolerance = + devm_kzalloc(&pdev->dev, (tup->n_adjustable_baud_rates) * + sizeof(*tup->baud_tolerance), GFP_KERNEL); + if (!tup->baud_tolerance) + return -ENOMEM; + for (count = 0, index = 0; count < n_entries; count += 3, + index++) { + ret = + of_property_read_u32_index(np, + "nvidia,adjust-baud-rates", + count, &pval); + if (!ret) + tup->baud_tolerance[index].lower_range_baud = + pval; + ret = + of_property_read_u32_index(np, + "nvidia,adjust-baud-rates", + count + 1, &pval); + if (!ret) + tup->baud_tolerance[index].upper_range_baud = + pval; + ret = + of_property_read_u32_index(np, + "nvidia,adjust-baud-rates", + count + 2, &pval); + if (!ret) + tup->baud_tolerance[index].tolerance = + (s32)pval; + } + } else { + tup->n_adjustable_baud_rates = 0; + } + return 0; } @@ -1228,12 +1486,44 @@ static struct tegra_uart_chip_data tegra20_uart_chip_data = { .tx_fifo_full_status = false, .allow_txfifo_reset_fifo_mode = true, .support_clk_src_div = false, + .fifo_mode_enable_status = false, + .uart_max_port = 5, + .max_dma_burst_bytes = 4, + .error_tolerance_low_range = 0, + .error_tolerance_high_range = 4, }; static struct tegra_uart_chip_data tegra30_uart_chip_data = { .tx_fifo_full_status = true, .allow_txfifo_reset_fifo_mode = false, .support_clk_src_div = true, + .fifo_mode_enable_status = false, + .uart_max_port = 5, + .max_dma_burst_bytes = 4, + .error_tolerance_low_range = 0, + .error_tolerance_high_range = 4, +}; + +static struct tegra_uart_chip_data tegra186_uart_chip_data = { + .tx_fifo_full_status = true, + .allow_txfifo_reset_fifo_mode = false, + .support_clk_src_div = true, + .fifo_mode_enable_status = true, + .uart_max_port = 8, + .max_dma_burst_bytes = 8, + .error_tolerance_low_range = 0, + .error_tolerance_high_range = 4, +}; + +static struct tegra_uart_chip_data tegra194_uart_chip_data = { + .tx_fifo_full_status = true, + .allow_txfifo_reset_fifo_mode = false, + .support_clk_src_div = true, + .fifo_mode_enable_status = true, + .uart_max_port = 8, + .max_dma_burst_bytes = 8, + .error_tolerance_low_range = -2, + .error_tolerance_high_range = 2, }; static const struct of_device_id tegra_uart_of_match[] = { @@ -1243,6 +1533,12 @@ static const struct of_device_id tegra_uart_of_match[] = { }, { .compatible = "nvidia,tegra20-hsuart", .data = &tegra20_uart_chip_data, + }, { + .compatible = "nvidia,tegra186-hsuart", + .data = &tegra186_uart_chip_data, + }, { + .compatible = "nvidia,tegra194-hsuart", + .data = &tegra194_uart_chip_data, }, { }, }; @@ -1307,10 +1603,8 @@ static int tegra_uart_probe(struct platform_device *pdev) u->iotype = UPIO_MEM32; ret = platform_get_irq(pdev, 0); - if (ret < 0) { - dev_err(&pdev->dev, "Couldn't get IRQ\n"); + if (ret < 0) return ret; - } u->irq = ret; u->regshift = 2; ret = uart_add_one_port(&tegra_uart_driver, u); @@ -1365,11 +1659,22 @@ static struct platform_driver tegra_uart_platform_driver = { static int __init tegra_uart_init(void) { int ret; + struct device_node *node; + const struct of_device_id *match = NULL; + const struct tegra_uart_chip_data *cdata = NULL; + + node = of_find_matching_node(NULL, tegra_uart_of_match); + if (node) + match = of_match_node(tegra_uart_of_match, node); + if (match) + cdata = match->data; + if (cdata) + tegra_uart_driver.nr = cdata->uart_max_port; ret = uart_register_driver(&tegra_uart_driver); if (ret < 0) { pr_err("Could not register %s driver\n", - tegra_uart_driver.driver_name); + tegra_uart_driver.driver_name); return ret; } diff --git a/drivers/tty/serial/serial_ks8695.c b/drivers/tty/serial/serial_ks8695.c deleted file mode 100644 index b461d791188c..000000000000 --- a/drivers/tty/serial/serial_ks8695.c +++ /dev/null @@ -1,698 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Driver for KS8695 serial ports - * - * Based on drivers/serial/serial_amba.c, by Kam Lee. - * - * Copyright 2002-2005 Micrel Inc. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#if defined(CONFIG_SERIAL_KS8695_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include - - -#define SERIAL_KS8695_MAJOR 204 -#define SERIAL_KS8695_MINOR 16 -#define SERIAL_KS8695_DEVNAME "ttyAM" - -#define SERIAL_KS8695_NR 1 - -/* - * Access macros for the KS8695 UART - */ -#define UART_GET_CHAR(p) (__raw_readl((p)->membase + KS8695_URRB) & 0xFF) -#define UART_PUT_CHAR(p, c) __raw_writel((c), (p)->membase + KS8695_URTH) -#define UART_GET_FCR(p) __raw_readl((p)->membase + KS8695_URFC) -#define UART_PUT_FCR(p, c) __raw_writel((c), (p)->membase + KS8695_URFC) -#define UART_GET_MSR(p) __raw_readl((p)->membase + KS8695_URMS) -#define UART_GET_LSR(p) __raw_readl((p)->membase + KS8695_URLS) -#define UART_GET_LCR(p) __raw_readl((p)->membase + KS8695_URLC) -#define UART_PUT_LCR(p, c) __raw_writel((c), (p)->membase + KS8695_URLC) -#define UART_GET_MCR(p) __raw_readl((p)->membase + KS8695_URMC) -#define UART_PUT_MCR(p, c) __raw_writel((c), (p)->membase + KS8695_URMC) -#define UART_GET_BRDR(p) __raw_readl((p)->membase + KS8695_URBD) -#define UART_PUT_BRDR(p, c) __raw_writel((c), (p)->membase + KS8695_URBD) - -#define KS8695_CLR_TX_INT() __raw_writel(1 << KS8695_IRQ_UART_TX, KS8695_IRQ_VA + KS8695_INTST) - -#define UART_DUMMY_LSR_RX 0x100 -#define UART_PORT_SIZE (KS8695_USR - KS8695_URRB + 4) - -static inline int tx_enabled(struct uart_port *port) -{ - return port->unused[0] & 1; -} - -static inline int rx_enabled(struct uart_port *port) -{ - return port->unused[0] & 2; -} - -static inline int ms_enabled(struct uart_port *port) -{ - return port->unused[0] & 4; -} - -static inline void ms_enable(struct uart_port *port, int enabled) -{ - if(enabled) - port->unused[0] |= 4; - else - port->unused[0] &= ~4; -} - -static inline void rx_enable(struct uart_port *port, int enabled) -{ - if(enabled) - port->unused[0] |= 2; - else - port->unused[0] &= ~2; -} - -static inline void tx_enable(struct uart_port *port, int enabled) -{ - if(enabled) - port->unused[0] |= 1; - else - port->unused[0] &= ~1; -} - - -#ifdef SUPPORT_SYSRQ -static struct console ks8695_console; -#endif - -static void ks8695uart_stop_tx(struct uart_port *port) -{ - if (tx_enabled(port)) { - /* use disable_irq_nosync() and not disable_irq() to avoid self - * imposed deadlock by not waiting for irq handler to end, - * since this ks8695uart_stop_tx() is called from interrupt context. - */ - disable_irq_nosync(KS8695_IRQ_UART_TX); - tx_enable(port, 0); - } -} - -static void ks8695uart_start_tx(struct uart_port *port) -{ - if (!tx_enabled(port)) { - enable_irq(KS8695_IRQ_UART_TX); - tx_enable(port, 1); - } -} - -static void ks8695uart_stop_rx(struct uart_port *port) -{ - if (rx_enabled(port)) { - disable_irq(KS8695_IRQ_UART_RX); - rx_enable(port, 0); - } -} - -static void ks8695uart_enable_ms(struct uart_port *port) -{ - if (!ms_enabled(port)) { - enable_irq(KS8695_IRQ_UART_MODEM_STATUS); - ms_enable(port,1); - } -} - -static void ks8695uart_disable_ms(struct uart_port *port) -{ - if (ms_enabled(port)) { - disable_irq(KS8695_IRQ_UART_MODEM_STATUS); - ms_enable(port,0); - } -} - -static irqreturn_t ks8695uart_rx_chars(int irq, void *dev_id) -{ - struct uart_port *port = dev_id; - unsigned int status, ch, lsr, flg, max_count = 256; - - status = UART_GET_LSR(port); /* clears pending LSR interrupts */ - while ((status & URLS_URDR) && max_count--) { - ch = UART_GET_CHAR(port); - flg = TTY_NORMAL; - - port->icount.rx++; - - /* - * Note that the error handling code is - * out of the main execution path - */ - lsr = UART_GET_LSR(port) | UART_DUMMY_LSR_RX; - if (unlikely(lsr & (URLS_URBI | URLS_URPE | URLS_URFE | URLS_URROE))) { - if (lsr & URLS_URBI) { - lsr &= ~(URLS_URFE | URLS_URPE); - port->icount.brk++; - if (uart_handle_break(port)) - goto ignore_char; - } - if (lsr & URLS_URPE) - port->icount.parity++; - if (lsr & URLS_URFE) - port->icount.frame++; - if (lsr & URLS_URROE) - port->icount.overrun++; - - lsr &= port->read_status_mask; - - if (lsr & URLS_URBI) - flg = TTY_BREAK; - else if (lsr & URLS_URPE) - flg = TTY_PARITY; - else if (lsr & URLS_URFE) - flg = TTY_FRAME; - } - - if (uart_handle_sysrq_char(port, ch)) - goto ignore_char; - - uart_insert_char(port, lsr, URLS_URROE, ch, flg); - -ignore_char: - status = UART_GET_LSR(port); - } - tty_flip_buffer_push(&port->state->port); - - return IRQ_HANDLED; -} - - -static irqreturn_t ks8695uart_tx_chars(int irq, void *dev_id) -{ - struct uart_port *port = dev_id; - struct circ_buf *xmit = &port->state->xmit; - unsigned int count; - - if (port->x_char) { - KS8695_CLR_TX_INT(); - UART_PUT_CHAR(port, port->x_char); - port->icount.tx++; - port->x_char = 0; - return IRQ_HANDLED; - } - - if (uart_tx_stopped(port) || uart_circ_empty(xmit)) { - ks8695uart_stop_tx(port); - return IRQ_HANDLED; - } - - count = 16; /* fifo size */ - while (!uart_circ_empty(xmit) && (count-- > 0)) { - KS8695_CLR_TX_INT(); - UART_PUT_CHAR(port, xmit->buf[xmit->tail]); - - 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)) - ks8695uart_stop_tx(port); - - return IRQ_HANDLED; -} - -static irqreturn_t ks8695uart_modem_status(int irq, void *dev_id) -{ - struct uart_port *port = dev_id; - unsigned int status; - - /* - * clear modem interrupt by reading MSR - */ - status = UART_GET_MSR(port); - - if (status & URMS_URDDCD) - uart_handle_dcd_change(port, status & URMS_URDDCD); - - if (status & URMS_URDDST) - port->icount.dsr++; - - if (status & URMS_URDCTS) - uart_handle_cts_change(port, status & URMS_URDCTS); - - if (status & URMS_URTERI) - port->icount.rng++; - - wake_up_interruptible(&port->state->port.delta_msr_wait); - - return IRQ_HANDLED; -} - -static unsigned int ks8695uart_tx_empty(struct uart_port *port) -{ - return (UART_GET_LSR(port) & URLS_URTE) ? TIOCSER_TEMT : 0; -} - -static unsigned int ks8695uart_get_mctrl(struct uart_port *port) -{ - unsigned int result = 0; - unsigned int status; - - status = UART_GET_MSR(port); - if (status & URMS_URDCD) - result |= TIOCM_CAR; - if (status & URMS_URDSR) - result |= TIOCM_DSR; - if (status & URMS_URCTS) - result |= TIOCM_CTS; - if (status & URMS_URRI) - result |= TIOCM_RI; - - return result; -} - -static void ks8695uart_set_mctrl(struct uart_port *port, u_int mctrl) -{ - unsigned int mcr; - - mcr = UART_GET_MCR(port); - if (mctrl & TIOCM_RTS) - mcr |= URMC_URRTS; - else - mcr &= ~URMC_URRTS; - - if (mctrl & TIOCM_DTR) - mcr |= URMC_URDTR; - else - mcr &= ~URMC_URDTR; - - UART_PUT_MCR(port, mcr); -} - -static void ks8695uart_break_ctl(struct uart_port *port, int break_state) -{ - unsigned int lcr; - - lcr = UART_GET_LCR(port); - - if (break_state == -1) - lcr |= URLC_URSBC; - else - lcr &= ~URLC_URSBC; - - UART_PUT_LCR(port, lcr); -} - -static int ks8695uart_startup(struct uart_port *port) -{ - int retval; - - irq_modify_status(KS8695_IRQ_UART_TX, IRQ_NOREQUEST, IRQ_NOAUTOEN); - tx_enable(port, 0); - rx_enable(port, 1); - ms_enable(port, 1); - - /* - * Allocate the IRQ - */ - retval = request_irq(KS8695_IRQ_UART_TX, ks8695uart_tx_chars, 0, "UART TX", port); - if (retval) - goto err_tx; - - retval = request_irq(KS8695_IRQ_UART_RX, ks8695uart_rx_chars, 0, "UART RX", port); - if (retval) - goto err_rx; - - retval = request_irq(KS8695_IRQ_UART_LINE_STATUS, ks8695uart_rx_chars, 0, "UART LineStatus", port); - if (retval) - goto err_ls; - - retval = request_irq(KS8695_IRQ_UART_MODEM_STATUS, ks8695uart_modem_status, 0, "UART ModemStatus", port); - if (retval) - goto err_ms; - - return 0; - -err_ms: - free_irq(KS8695_IRQ_UART_LINE_STATUS, port); -err_ls: - free_irq(KS8695_IRQ_UART_RX, port); -err_rx: - free_irq(KS8695_IRQ_UART_TX, port); -err_tx: - return retval; -} - -static void ks8695uart_shutdown(struct uart_port *port) -{ - /* - * Free the interrupt - */ - free_irq(KS8695_IRQ_UART_RX, port); - free_irq(KS8695_IRQ_UART_TX, port); - free_irq(KS8695_IRQ_UART_MODEM_STATUS, port); - free_irq(KS8695_IRQ_UART_LINE_STATUS, port); - - /* disable break condition and fifos */ - UART_PUT_LCR(port, UART_GET_LCR(port) & ~URLC_URSBC); - UART_PUT_FCR(port, UART_GET_FCR(port) & ~URFC_URFE); -} - -static void ks8695uart_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) -{ - unsigned int lcr, fcr = 0; - unsigned long flags; - unsigned int baud, quot; - - /* - * Ask the core to calculate the divisor for us. - */ - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); - quot = uart_get_divisor(port, baud); - - switch (termios->c_cflag & CSIZE) { - case CS5: - lcr = URCL_5; - break; - case CS6: - lcr = URCL_6; - break; - case CS7: - lcr = URCL_7; - break; - default: - lcr = URCL_8; - break; - } - - /* stop bits */ - if (termios->c_cflag & CSTOPB) - lcr |= URLC_URSB; - - /* parity */ - if (termios->c_cflag & PARENB) { - if (termios->c_cflag & CMSPAR) { /* Mark or Space parity */ - if (termios->c_cflag & PARODD) - lcr |= URPE_MARK; - else - lcr |= URPE_SPACE; - } - else if (termios->c_cflag & PARODD) - lcr |= URPE_ODD; - else - lcr |= URPE_EVEN; - } - - if (port->fifosize > 1) - fcr = URFC_URFRT_8 | URFC_URTFR | URFC_URRFR | URFC_URFE; - - spin_lock_irqsave(&port->lock, flags); - - /* - * Update the per-port timeout. - */ - uart_update_timeout(port, termios->c_cflag, baud); - - port->read_status_mask = URLS_URROE; - if (termios->c_iflag & INPCK) - port->read_status_mask |= (URLS_URFE | URLS_URPE); - if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) - port->read_status_mask |= URLS_URBI; - - /* - * Characters to ignore - */ - port->ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= (URLS_URFE | URLS_URPE); - if (termios->c_iflag & IGNBRK) { - port->ignore_status_mask |= URLS_URBI; - /* - * If we're ignoring parity and break indicators, - * ignore overruns too (for real raw support). - */ - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= URLS_URROE; - } - - /* - * Ignore all characters if CREAD is not set. - */ - if ((termios->c_cflag & CREAD) == 0) - port->ignore_status_mask |= UART_DUMMY_LSR_RX; - - /* first, disable everything */ - if (UART_ENABLE_MS(port, termios->c_cflag)) - ks8695uart_enable_ms(port); - else - ks8695uart_disable_ms(port); - - /* Set baud rate */ - UART_PUT_BRDR(port, quot); - - UART_PUT_LCR(port, lcr); - UART_PUT_FCR(port, fcr); - - spin_unlock_irqrestore(&port->lock, flags); -} - -static const char *ks8695uart_type(struct uart_port *port) -{ - return port->type == PORT_KS8695 ? "KS8695" : NULL; -} - -/* - * Release the memory region(s) being used by 'port' - */ -static void ks8695uart_release_port(struct uart_port *port) -{ - release_mem_region(port->mapbase, UART_PORT_SIZE); -} - -/* - * Request the memory region(s) being used by 'port' - */ -static int ks8695uart_request_port(struct uart_port *port) -{ - return request_mem_region(port->mapbase, UART_PORT_SIZE, - "serial_ks8695") != NULL ? 0 : -EBUSY; -} - -/* - * Configure/autoconfigure the port. - */ -static void ks8695uart_config_port(struct uart_port *port, int flags) -{ - if (flags & UART_CONFIG_TYPE) { - port->type = PORT_KS8695; - ks8695uart_request_port(port); - } -} - -/* - * verify the new serial_struct (for TIOCSSERIAL). - */ -static int ks8695uart_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - int ret = 0; - - if (ser->type != PORT_UNKNOWN && ser->type != PORT_KS8695) - ret = -EINVAL; - if (ser->irq != port->irq) - ret = -EINVAL; - if (ser->baud_base < 9600) - ret = -EINVAL; - return ret; -} - -static struct uart_ops ks8695uart_pops = { - .tx_empty = ks8695uart_tx_empty, - .set_mctrl = ks8695uart_set_mctrl, - .get_mctrl = ks8695uart_get_mctrl, - .stop_tx = ks8695uart_stop_tx, - .start_tx = ks8695uart_start_tx, - .stop_rx = ks8695uart_stop_rx, - .enable_ms = ks8695uart_enable_ms, - .break_ctl = ks8695uart_break_ctl, - .startup = ks8695uart_startup, - .shutdown = ks8695uart_shutdown, - .set_termios = ks8695uart_set_termios, - .type = ks8695uart_type, - .release_port = ks8695uart_release_port, - .request_port = ks8695uart_request_port, - .config_port = ks8695uart_config_port, - .verify_port = ks8695uart_verify_port, -}; - -static struct uart_port ks8695uart_ports[SERIAL_KS8695_NR] = { - { - .membase = KS8695_UART_VA, - .mapbase = KS8695_UART_PA, - .iotype = SERIAL_IO_MEM, - .irq = KS8695_IRQ_UART_TX, - .uartclk = KS8695_CLOCK_RATE * 16, - .fifosize = 16, - .ops = &ks8695uart_pops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - } -}; - -#ifdef CONFIG_SERIAL_KS8695_CONSOLE -static void ks8695_console_putchar(struct uart_port *port, int ch) -{ - while (!(UART_GET_LSR(port) & URLS_URTHRE)) - barrier(); - - UART_PUT_CHAR(port, ch); -} - -static void ks8695_console_write(struct console *co, const char *s, u_int count) -{ - struct uart_port *port = ks8695uart_ports + co->index; - - uart_console_write(port, s, count, ks8695_console_putchar); -} - -static void __init ks8695_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits) -{ - unsigned int lcr; - - lcr = UART_GET_LCR(port); - - switch (lcr & URLC_PARITY) { - case URPE_ODD: - *parity = 'o'; - break; - case URPE_EVEN: - *parity = 'e'; - break; - default: - *parity = 'n'; - } - - switch (lcr & URLC_URCL) { - case URCL_5: - *bits = 5; - break; - case URCL_6: - *bits = 6; - break; - case URCL_7: - *bits = 7; - break; - default: - *bits = 8; - } - - *baud = port->uartclk / (UART_GET_BRDR(port) & 0x0FFF); - *baud /= 16; - *baud &= 0xFFFFFFF0; -} - -static int __init ks8695_console_setup(struct console *co, char *options) -{ - struct uart_port *port; - int baud = 115200; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - /* - * Check whether an invalid uart number has been specified, and - * if so, search for the first available port that does have - * console support. - */ - port = uart_get_console(ks8695uart_ports, SERIAL_KS8695_NR, co); - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - else - ks8695_console_get_options(port, &baud, &parity, &bits); - - return uart_set_options(port, co, baud, parity, bits, flow); -} - -static struct uart_driver ks8695_reg; - -static struct console ks8695_console = { - .name = SERIAL_KS8695_DEVNAME, - .write = ks8695_console_write, - .device = uart_console_device, - .setup = ks8695_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &ks8695_reg, -}; - -static int __init ks8695_console_init(void) -{ - add_preferred_console(SERIAL_KS8695_DEVNAME, 0, NULL); - register_console(&ks8695_console); - return 0; -} - -console_initcall(ks8695_console_init); - -#define KS8695_CONSOLE &ks8695_console -#else -#define KS8695_CONSOLE NULL -#endif - -static struct uart_driver ks8695_reg = { - .owner = THIS_MODULE, - .driver_name = "serial_ks8695", - .dev_name = SERIAL_KS8695_DEVNAME, - .major = SERIAL_KS8695_MAJOR, - .minor = SERIAL_KS8695_MINOR, - .nr = SERIAL_KS8695_NR, - .cons = KS8695_CONSOLE, -}; - -static int __init ks8695uart_init(void) -{ - int i, ret; - - printk(KERN_INFO "Serial: Micrel KS8695 UART driver\n"); - - ret = uart_register_driver(&ks8695_reg); - if (ret) - return ret; - - for (i = 0; i < SERIAL_KS8695_NR; i++) - uart_add_one_port(&ks8695_reg, &ks8695uart_ports[0]); - - return 0; -} - -static void __exit ks8695uart_exit(void) -{ - int i; - - for (i = 0; i < SERIAL_KS8695_NR; i++) - uart_remove_one_port(&ks8695_reg, &ks8695uart_ports[0]); - uart_unregister_driver(&ks8695_reg); -} - -module_init(ks8695uart_init); -module_exit(ks8695uart_exit); - -MODULE_DESCRIPTION("KS8695 serial port driver"); -MODULE_AUTHOR("Micrel Inc."); -MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c index 2b400189be91..d9074303c88e 100644 --- a/drivers/tty/serial/serial_mctrl_gpio.c +++ b/drivers/tty/serial/serial_mctrl_gpio.c @@ -27,16 +27,21 @@ struct mctrl_gpios { static const struct { const char *name; unsigned int mctrl; - bool dir_out; + enum gpiod_flags flags; } mctrl_gpios_desc[UART_GPIO_MAX] = { - { "cts", TIOCM_CTS, false, }, - { "dsr", TIOCM_DSR, false, }, - { "dcd", TIOCM_CD, false, }, - { "rng", TIOCM_RNG, false, }, - { "rts", TIOCM_RTS, true, }, - { "dtr", TIOCM_DTR, true, }, + { "cts", TIOCM_CTS, GPIOD_IN, }, + { "dsr", TIOCM_DSR, GPIOD_IN, }, + { "dcd", TIOCM_CD, GPIOD_IN, }, + { "rng", TIOCM_RNG, GPIOD_IN, }, + { "rts", TIOCM_RTS, GPIOD_OUT_LOW, }, + { "dtr", TIOCM_DTR, GPIOD_OUT_LOW, }, }; +static bool mctrl_gpio_flags_is_dir_out(unsigned int idx) +{ + return mctrl_gpios_desc[idx].flags & GPIOD_FLAGS_BIT_DIR_OUT; +} + void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl) { enum mctrl_gpio_idx i; @@ -48,7 +53,7 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl) return; for (i = 0; i < UART_GPIO_MAX; i++) - if (gpios->gpio[i] && mctrl_gpios_desc[i].dir_out) { + if (gpios->gpio[i] && mctrl_gpio_flags_is_dir_out(i)) { desc_array[count] = gpios->gpio[i]; __assign_bit(count, values, mctrl & mctrl_gpios_desc[i].mctrl); @@ -73,7 +78,7 @@ unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl) return *mctrl; for (i = 0; i < UART_GPIO_MAX; i++) { - if (gpios->gpio[i] && !mctrl_gpios_desc[i].dir_out) { + if (gpios->gpio[i] && !mctrl_gpio_flags_is_dir_out(i)) { if (gpiod_get_value(gpios->gpio[i])) *mctrl |= mctrl_gpios_desc[i].mctrl; else @@ -94,7 +99,7 @@ mctrl_gpio_get_outputs(struct mctrl_gpios *gpios, unsigned int *mctrl) return *mctrl; for (i = 0; i < UART_GPIO_MAX; i++) { - if (gpios->gpio[i] && mctrl_gpios_desc[i].dir_out) { + if (gpios->gpio[i] && mctrl_gpio_flags_is_dir_out(i)) { if (gpiod_get_value(gpios->gpio[i])) *mctrl |= mctrl_gpios_desc[i].mctrl; else @@ -116,7 +121,6 @@ struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, unsigned int idx) return ERR_PTR(-ENOMEM); for (i = 0; i < UART_GPIO_MAX; i++) { - enum gpiod_flags flags; char *gpio_str; bool present; @@ -131,15 +135,11 @@ struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, unsigned int idx) if (!present) continue; - if (mctrl_gpios_desc[i].dir_out) - flags = GPIOD_OUT_LOW; - else - flags = GPIOD_IN; - gpios->gpio[i] = devm_gpiod_get_index_optional(dev, mctrl_gpios_desc[i].name, - idx, flags); + idx, + mctrl_gpios_desc[i].flags); if (IS_ERR(gpios->gpio[i])) return ERR_CAST(gpios->gpio[i]); @@ -200,7 +200,7 @@ struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx) for (i = 0; i < UART_GPIO_MAX; ++i) { int ret; - if (!gpios->gpio[i] || mctrl_gpios_desc[i].dir_out) + if (!gpios->gpio[i] || mctrl_gpio_flags_is_dir_out(i)) continue; ret = gpiod_to_irq(gpios->gpio[i]); diff --git a/drivers/tty/serial/serial_mctrl_gpio.h b/drivers/tty/serial/serial_mctrl_gpio.h index b7d3cca48ede..1b2ff503b2c2 100644 --- a/drivers/tty/serial/serial_mctrl_gpio.h +++ b/drivers/tty/serial/serial_mctrl_gpio.h @@ -114,19 +114,19 @@ static inline struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios, enum mctrl_gpio_idx gidx) { - return ERR_PTR(-ENOSYS); + return NULL; } static inline struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx) { - return ERR_PTR(-ENOSYS); + return NULL; } static inline struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, unsigned int idx) { - return ERR_PTR(-ENOSYS); + return NULL; } static inline diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index d18c680aa64b..4e754a4850e6 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1092,9 +1092,8 @@ static void rx_fifo_timer_fn(struct timer_list *t) scif_set_rtrg(port, 1); } -static ssize_t rx_trigger_show(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t rx_fifo_trigger_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct uart_port *port = dev_get_drvdata(dev); struct sci_port *sci = to_sci_port(port); @@ -1102,10 +1101,9 @@ static ssize_t rx_trigger_show(struct device *dev, return sprintf(buf, "%d\n", sci->rx_trigger); } -static ssize_t rx_trigger_store(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t count) +static ssize_t rx_fifo_trigger_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct uart_port *port = dev_get_drvdata(dev); struct sci_port *sci = to_sci_port(port); @@ -1123,7 +1121,7 @@ static ssize_t rx_trigger_store(struct device *dev, return count; } -static DEVICE_ATTR(rx_fifo_trigger, 0644, rx_trigger_show, rx_trigger_store); +static DEVICE_ATTR_RW(rx_fifo_trigger); static ssize_t rx_fifo_timeout_show(struct device *dev, struct device_attribute *attr, @@ -2101,12 +2099,12 @@ static unsigned int sci_get_mctrl(struct uart_port *port) if (s->autorts) { if (sci_get_cts(port)) mctrl |= TIOCM_CTS; - } else if (IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(gpios, UART_GPIO_CTS))) { + } else if (!mctrl_gpio_to_gpiod(gpios, UART_GPIO_CTS)) { mctrl |= TIOCM_CTS; } - if (IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(gpios, UART_GPIO_DSR))) + if (!mctrl_gpio_to_gpiod(gpios, UART_GPIO_DSR)) mctrl |= TIOCM_DSR; - if (IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(gpios, UART_GPIO_DCD))) + if (!mctrl_gpio_to_gpiod(gpios, UART_GPIO_DCD)) mctrl |= TIOCM_CAR; return mctrl; @@ -3152,14 +3150,10 @@ static int sci_remove(struct platform_device *dev) sci_cleanup_single(port); - if (port->port.fifosize > 1) { - sysfs_remove_file(&dev->dev.kobj, - &dev_attr_rx_fifo_trigger.attr); - } - if (type == PORT_SCIFA || type == PORT_SCIFB || type == PORT_HSCIF) { - sysfs_remove_file(&dev->dev.kobj, - &dev_attr_rx_fifo_timeout.attr); - } + if (port->port.fifosize > 1) + device_remove_file(&dev->dev, &dev_attr_rx_fifo_trigger); + if (type == PORT_SCIFA || type == PORT_SCIFB || type == PORT_HSCIF) + device_remove_file(&dev->dev, &dev_attr_rx_fifo_timeout); return 0; } @@ -3287,14 +3281,12 @@ static int sci_probe_single(struct platform_device *dev, return ret; sciport->gpios = mctrl_gpio_init(&sciport->port, 0); - if (IS_ERR(sciport->gpios) && PTR_ERR(sciport->gpios) != -ENOSYS) + if (IS_ERR(sciport->gpios)) return PTR_ERR(sciport->gpios); if (sciport->has_rtscts) { - if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(sciport->gpios, - UART_GPIO_CTS)) || - !IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(sciport->gpios, - UART_GPIO_RTS))) { + if (mctrl_gpio_to_gpiod(sciport->gpios, UART_GPIO_CTS) || + mctrl_gpio_to_gpiod(sciport->gpios, UART_GPIO_RTS)) { dev_err(&dev->dev, "Conflicting RTS/CTS config\n"); return -EINVAL; } @@ -3347,19 +3339,17 @@ static int sci_probe(struct platform_device *dev) return ret; if (sp->port.fifosize > 1) { - ret = sysfs_create_file(&dev->dev.kobj, - &dev_attr_rx_fifo_trigger.attr); + ret = device_create_file(&dev->dev, &dev_attr_rx_fifo_trigger); if (ret) return ret; } if (sp->port.type == PORT_SCIFA || sp->port.type == PORT_SCIFB || sp->port.type == PORT_HSCIF) { - ret = sysfs_create_file(&dev->dev.kobj, - &dev_attr_rx_fifo_timeout.attr); + ret = device_create_file(&dev->dev, &dev_attr_rx_fifo_timeout); if (ret) { if (sp->port.fifosize > 1) { - sysfs_remove_file(&dev->dev.kobj, - &dev_attr_rx_fifo_trigger.attr); + device_remove_file(&dev->dev, + &dev_attr_rx_fifo_trigger); } return ret; } diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c index be4687814353..d5f81b98e4d7 100644 --- a/drivers/tty/serial/sifive.c +++ b/drivers/tty/serial/sifive.c @@ -896,10 +896,8 @@ static int sifive_serial_probe(struct platform_device *pdev) int irq, id, r; irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "could not acquire interrupt\n"); + if (irq < 0) return -EPROBE_DEFER; - } mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(&pdev->dev, mem); diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c index 73d71a4e6c0c..771d11196523 100644 --- a/drivers/tty/serial/sprd_serial.c +++ b/drivers/tty/serial/sprd_serial.c @@ -79,6 +79,7 @@ /* control register 1 */ #define SPRD_CTL1 0x001C #define SPRD_DMA_EN BIT(15) +#define SPRD_LOOPBACK_EN BIT(14) #define RX_HW_FLOW_CTL_THLD BIT(6) #define RX_HW_FLOW_CTL_EN BIT(7) #define TX_HW_FLOW_CTL_EN BIT(8) @@ -164,7 +165,14 @@ static unsigned int sprd_get_mctrl(struct uart_port *port) static void sprd_set_mctrl(struct uart_port *port, unsigned int mctrl) { - /* nothing to do */ + u32 val = serial_in(port, SPRD_CTL1); + + if (mctrl & TIOCM_LOOP) + val |= SPRD_LOOPBACK_EN; + else + val &= ~SPRD_LOOPBACK_EN; + + serial_out(port, SPRD_CTL1, val); } static void sprd_stop_rx(struct uart_port *port) @@ -609,7 +617,7 @@ static inline void sprd_rx(struct uart_port *port) if (lsr & (SPRD_LSR_BI | SPRD_LSR_PE | SPRD_LSR_FE | SPRD_LSR_OE)) - if (handle_lsr_errors(port, &lsr, &flag)) + if (handle_lsr_errors(port, &flag, &lsr)) continue; if (uart_handle_sysrq_char(port, ch)) continue; @@ -975,7 +983,7 @@ static void sprd_console_write(struct console *co, const char *s, static int __init sprd_console_setup(struct console *co, char *options) { - struct uart_port *port; + struct sprd_uart_port *sprd_uart_port; int baud = 115200; int bits = 8; int parity = 'n'; @@ -984,15 +992,17 @@ static int __init sprd_console_setup(struct console *co, char *options) if (co->index >= UART_NR_MAX || co->index < 0) co->index = 0; - port = &sprd_port[co->index]->port; - if (port == NULL) { + sprd_uart_port = sprd_port[co->index]; + if (!sprd_uart_port || !sprd_uart_port->port.membase) { pr_info("serial port %d not yet initialized\n", co->index); return -ENODEV; } + if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); - return uart_set_options(port, co, baud, parity, bits, flow); + return uart_set_options(&sprd_uart_port->port, co, baud, + parity, bits, flow); } static struct uart_driver sprd_uart_driver; @@ -1006,6 +1016,13 @@ static struct console sprd_console = { .data = &sprd_uart_driver, }; +static int __init sprd_serial_console_init(void) +{ + register_console(&sprd_console); + return 0; +} +console_initcall(sprd_serial_console_init); + #define SPRD_CONSOLE (&sprd_console) /* Support for earlycon */ @@ -1094,6 +1111,16 @@ static int sprd_remove(struct platform_device *dev) return 0; } +static bool sprd_uart_is_console(struct uart_port *uport) +{ + struct console *cons = sprd_uart_driver.cons; + + if (cons && cons->index >= 0 && cons->index == uport->line) + return true; + + return false; +} + static int sprd_clk_init(struct uart_port *uport) { struct clk *clk_uart, *clk_parent; @@ -1120,10 +1147,17 @@ static int sprd_clk_init(struct uart_port *uport) u->clk = devm_clk_get(uport->dev, "enable"); if (IS_ERR(u->clk)) { - if (PTR_ERR(u->clk) != -EPROBE_DEFER) - dev_err(uport->dev, "uart%d can't get enable clock\n", - uport->line); - return PTR_ERR(u->clk); + if (PTR_ERR(u->clk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + dev_warn(uport->dev, "uart%d can't get enable clock\n", + uport->line); + + /* To keep console alive even if the error occurred */ + if (!sprd_uart_is_console(uport)) + return PTR_ERR(u->clk); + + u->clk = NULL; } return 0; @@ -1173,10 +1207,8 @@ static int sprd_probe(struct platform_device *pdev) up->mapbase = res->start; irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "not provide irq resource: %d\n", irq); + if (irq < 0) return irq; - } up->irq = irq; /* diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 24a2261f879a..df90747ee3a8 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -881,13 +882,13 @@ static void stm32_pm(struct uart_port *port, unsigned int state, switch (state) { case UART_PM_STATE_ON: - clk_prepare_enable(stm32port->clk); + pm_runtime_get_sync(port->dev); break; case UART_PM_STATE_OFF: spin_lock_irqsave(&port->lock, flags); stm32_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); spin_unlock_irqrestore(&port->lock, flags); - clk_disable_unprepare(stm32port->clk); + pm_runtime_put_sync(port->dev); break; } } @@ -927,11 +928,8 @@ static int stm32_init_port(struct stm32_port *stm32port, port->fifosize = stm32port->info->cfg.fifosize; ret = platform_get_irq(pdev, 0); - if (ret <= 0) { - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "Can't get event IRQ: %d\n", ret); - return ret ? ret : -ENODEV; - } + if (ret <= 0) + return ret ? : -ENODEV; port->irq = ret; port->rs485_config = stm32_config_rs485; @@ -940,14 +938,8 @@ static int stm32_init_port(struct stm32_port *stm32port, if (stm32port->info->cfg.has_wakeup) { stm32port->wakeirq = platform_get_irq(pdev, 1); - if (stm32port->wakeirq <= 0 && stm32port->wakeirq != -ENXIO) { - if (stm32port->wakeirq != -EPROBE_DEFER) - dev_err(&pdev->dev, - "Can't get event wake IRQ: %d\n", - stm32port->wakeirq); - return stm32port->wakeirq ? stm32port->wakeirq : - -ENODEV; - } + if (stm32port->wakeirq <= 0 && stm32port->wakeirq != -ENXIO) + return stm32port->wakeirq ? : -ENODEV; } stm32port->fifoen = stm32port->info->cfg.has_fifo; @@ -1185,6 +1177,11 @@ static int stm32_serial_probe(struct platform_device *pdev) platform_set_drvdata(pdev, &stm32port->port); + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + pm_runtime_put_sync(&pdev->dev); + return 0; err_wirq: @@ -1206,6 +1203,9 @@ static int stm32_serial_remove(struct platform_device *pdev) struct uart_port *port = platform_get_drvdata(pdev); struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + int err; + + pm_runtime_get_sync(&pdev->dev); stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAR); @@ -1234,7 +1234,12 @@ static int stm32_serial_remove(struct platform_device *pdev) clk_disable_unprepare(stm32_port->clk); - return uart_remove_one_port(&stm32_usart_driver, port); + err = uart_remove_one_port(&stm32_usart_driver, port); + + pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + + return err; } @@ -1337,8 +1342,8 @@ static struct uart_driver stm32_usart_driver = { .cons = STM32_SERIAL_CONSOLE, }; -#ifdef CONFIG_PM_SLEEP -static void stm32_serial_enable_wakeup(struct uart_port *port, bool enable) +static void __maybe_unused stm32_serial_enable_wakeup(struct uart_port *port, + bool enable) { struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; @@ -1362,7 +1367,7 @@ static void stm32_serial_enable_wakeup(struct uart_port *port, bool enable) } } -static int stm32_serial_suspend(struct device *dev) +static int __maybe_unused stm32_serial_suspend(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); @@ -1373,21 +1378,46 @@ static int stm32_serial_suspend(struct device *dev) else stm32_serial_enable_wakeup(port, false); + pinctrl_pm_select_sleep_state(dev); + return 0; } -static int stm32_serial_resume(struct device *dev) +static int __maybe_unused stm32_serial_resume(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); + pinctrl_pm_select_default_state(dev); + if (device_may_wakeup(dev)) stm32_serial_enable_wakeup(port, false); return uart_resume_port(&stm32_usart_driver, port); } -#endif /* CONFIG_PM_SLEEP */ + +static int __maybe_unused stm32_serial_runtime_suspend(struct device *dev) +{ + struct uart_port *port = dev_get_drvdata(dev); + struct stm32_port *stm32port = container_of(port, + struct stm32_port, port); + + clk_disable_unprepare(stm32port->clk); + + return 0; +} + +static int __maybe_unused stm32_serial_runtime_resume(struct device *dev) +{ + struct uart_port *port = dev_get_drvdata(dev); + struct stm32_port *stm32port = container_of(port, + struct stm32_port, port); + + return clk_prepare_enable(stm32port->clk); +} static const struct dev_pm_ops stm32_serial_pm_ops = { + SET_RUNTIME_PM_OPS(stm32_serial_runtime_suspend, + stm32_serial_runtime_resume, NULL) SET_SYSTEM_SLEEP_PM_OPS(stm32_serial_suspend, stm32_serial_resume) }; diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index f145946f659b..da4563aaaf5c 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -1194,7 +1194,7 @@ static void cdns_uart_console_write(struct console *co, const char *s, unsigned int count) { struct uart_port *port = console_port; - unsigned long flags; + unsigned long flags = 0; unsigned int imr, ctrl; int locked = 1; diff --git a/include/uapi/linux/gsmmux.h b/include/uapi/linux/gsmmux.h index 101d3c469acb..cb8693b39cb7 100644 --- a/include/uapi/linux/gsmmux.h +++ b/include/uapi/linux/gsmmux.h @@ -37,5 +37,7 @@ struct gsm_netconfig { #define GSMIOC_ENABLE_NET _IOW('G', 2, struct gsm_netconfig) #define GSMIOC_DISABLE_NET _IO('G', 3) +/* get the base tty number for a configured gsmmux tty */ +#define GSMIOC_GETFIRST _IOR('G', 4, __u32) #endif diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h index 3cc3af1c2ee1..0f4f87a6fd54 100644 --- a/include/uapi/linux/serial_core.h +++ b/include/uapi/linux/serial_core.h @@ -161,9 +161,6 @@ /* Blackfin bf5xx */ #define PORT_BFIN 75 -/* Micrel KS8695 */ -#define PORT_KS8695 76 - /* Broadcom SB1250, etc. SOC */ #define PORT_SB1250_DUART 77 @@ -290,4 +287,10 @@ /* SiFive UART */ #define PORT_SIFIVE_V0 120 +/* Sunix UART */ +#define PORT_SUNIX 121 + +/* Freescale Linflex UART */ +#define PORT_LINFLEXUART 121 + #endif /* _UAPILINUX_SERIAL_CORE_H */