diff options
50 files changed, 1672 insertions, 772 deletions
diff --git a/Documentation/devicetree/bindings/serial/8250.txt b/Documentation/devicetree/bindings/serial/8250.txt index da50321da34d..3cba12f855b7 100644 --- a/Documentation/devicetree/bindings/serial/8250.txt +++ b/Documentation/devicetree/bindings/serial/8250.txt @@ -21,6 +21,7 @@ Required properties: - "altr,16550-FIFO128" - "fsl,16550-FIFO64" - "fsl,ns16550" + - "intel,xscale-uart" - "ti,da830-uart" - "aspeed,ast2400-vuart" - "aspeed,ast2500-vuart" diff --git a/Documentation/devicetree/bindings/serial/ingenic,uart.txt b/Documentation/devicetree/bindings/serial/ingenic,uart.txt index c3c6406d5cfe..24ed8769f4af 100644 --- a/Documentation/devicetree/bindings/serial/ingenic,uart.txt +++ b/Documentation/devicetree/bindings/serial/ingenic,uart.txt @@ -6,7 +6,8 @@ Required properties: - "ingenic,jz4760-uart", - "ingenic,jz4770-uart", - "ingenic,jz4775-uart", - - "ingenic,jz4780-uart". + - "ingenic,jz4780-uart", + - "ingenic,x1000-uart". - reg : offset and length of the register set for the device. - interrupts : should contain uart interrupt. - clocks : phandles to the module & baud clocks. diff --git a/Documentation/devicetree/bindings/serial/milbeaut-uart.txt b/Documentation/devicetree/bindings/serial/milbeaut-uart.txt new file mode 100644 index 000000000000..3d2fb1a7ba94 --- /dev/null +++ b/Documentation/devicetree/bindings/serial/milbeaut-uart.txt @@ -0,0 +1,21 @@ +Socionext Milbeaut UART controller + +Required properties: +- compatible: should be "socionext,milbeaut-usio-uart". +- reg: offset and length of the register set for the device. +- interrupts: two interrupts specifier. +- interrupt-names: should be "rx", "tx". +- clocks: phandle to the input clock. + +Optional properties: +- auto-flow-control: flow control enable. + +Example: + usio1: usio_uart@1e700010 { + compatible = "socionext,milbeaut-usio-uart"; + reg = <0x1e700010 0x10>; + interrupts = <0 141 0x4>, <0 149 0x4>; + interrupt-names = "rx", "tx"; + clocks = <&clk 2>; + auto-flow-control; + }; diff --git a/Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt b/Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt new file mode 100644 index 000000000000..085a8591accd --- /dev/null +++ b/Documentation/devicetree/bindings/serial/nvidia,tegra194-tcu.txt @@ -0,0 +1,35 @@ +NVIDIA Tegra Combined UART (TCU) + +The TCU is a system for sharing a hardware UART instance among multiple +systems within the Tegra SoC. It is implemented through a mailbox- +based protocol where each "virtual UART" has a pair of mailboxes, one +for transmitting and one for receiving, that is used to communicate +with the hardware implementing the TCU. + +Required properties: +- name : Should be tcu +- compatible + Array of strings + One of: + - "nvidia,tegra194-tcu" +- mbox-names: + "rx" - Mailbox for receiving data from hardware UART + "tx" - Mailbox for transmitting data to hardware UART +- mboxes: Mailboxes corresponding to the mbox-names. + +This node is a mailbox consumer. See the following files for details of +the mailbox subsystem, and the specifiers implemented by the relevant +provider(s): + +- .../mailbox/mailbox.txt +- .../mailbox/nvidia,tegra186-hsp.txt + +Example bindings: +----------------- + +tcu: tcu { + compatible = "nvidia,tegra194-tcu"; + mboxes = <&hsp_top0 TEGRA_HSP_MBOX_TYPE_SM 0>, + <&hsp_aon TEGRA_HSP_MBOX_TYPE_SM 1>; + mbox-names = "rx", "tx"; +}; diff --git a/Documentation/devicetree/bindings/serial/omap_serial.txt b/Documentation/devicetree/bindings/serial/omap_serial.txt index c35d5ece1156..0a9b5444f4e6 100644 --- a/Documentation/devicetree/bindings/serial/omap_serial.txt +++ b/Documentation/devicetree/bindings/serial/omap_serial.txt @@ -22,6 +22,8 @@ Optional properties: - dma-names : "rx" for receive channel, "tx" for transmit channel. - rs485-rts-delay, rs485-rx-during-tx, linux,rs485-enabled-at-boot-time: see rs485.txt - rs485-rts-active-high: drive RTS high when sending (default is low). +- clocks: phandle to the functional clock as per + Documentation/devicetree/bindings/clock/clock-bindings.txt Example: diff --git a/Documentation/devicetree/bindings/serial/pl011.txt b/Documentation/devicetree/bindings/serial/pl011.txt deleted file mode 100644 index 77863aefe9ef..000000000000 --- a/Documentation/devicetree/bindings/serial/pl011.txt +++ /dev/null @@ -1,51 +0,0 @@ -* ARM AMBA Primecell PL011 serial UART - -Required properties: -- compatible: must be "arm,primecell", "arm,pl011", "zte,zx296702-uart" -- reg: exactly one register range with length 0x1000 -- interrupts: exactly one interrupt specifier - -Optional properties: -- pinctrl: - When present, must have one state named "default", - and may contain a second name named "sleep". The former - state sets up pins for ordinary operation whereas - the latter state will put the associated pins to sleep - when the UART is unused -- clocks: - When present, the first clock listed must correspond to - the clock named UARTCLK on the IP block, i.e. the clock - to the external serial line, whereas the second clock - must correspond to the PCLK clocking the internal logic - of the block. Just listing one clock (the first one) is - deprecated. -- clock-names: - When present, the first clock listed must be named - "uartclk" and the second clock listed must be named - "apb_pclk" -- dmas: - When present, may have one or two dma channels. - The first one must be named "rx", the second one - must be named "tx". -- auto-poll: - Enables polling when using RX DMA. -- poll-rate-ms: - Rate at which poll occurs when auto-poll is set, - default 100ms. -- poll-timeout-ms: - Poll timeout when auto-poll is set, default - 3000ms. - -See also bindings/arm/primecell.txt - -Example: - -uart@80120000 { - compatible = "arm,pl011", "arm,primecell"; - reg = <0x80120000 0x1000>; - interrupts = <0 11 IRQ_TYPE_LEVEL_HIGH>; - dmas = <&dma 13 0 0x2>, <&dma 13 0 0x0>; - dma-names = "rx", "tx"; - clocks = <&foo_clk>, <&bar_clk>; - clock-names = "uartclk", "apb_pclk"; -}; diff --git a/Documentation/devicetree/bindings/serial/pl011.yaml b/Documentation/devicetree/bindings/serial/pl011.yaml new file mode 100644 index 000000000000..1a64d59152aa --- /dev/null +++ b/Documentation/devicetree/bindings/serial/pl011.yaml @@ -0,0 +1,126 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/serial/pl011.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ARM AMBA Primecell PL011 serial UART + +maintainers: + - Rob Herring <robh@kernel.org> + +allOf: + - $ref: /schemas/serial.yaml# + +# Need a custom select here or 'arm,primecell' will match on lots of nodes +select: + properties: + compatible: + contains: + enum: + - arm,pl011 + - zte,zx296702-uart + required: + - compatible + +properties: + compatible: + oneOf: + - items: + - const: arm,pl011 + - const: arm,primecell + - items: + - const: zte,zx296702-uart + - const: arm,primecell + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + pinctrl-0: true + pinctrl-1: true + + pinctrl-names: + description: + When present, must have one state named "default", + and may contain a second name named "sleep". The former + state sets up pins for ordinary operation whereas + the latter state will put the associated pins to sleep + when the UART is unused + minItems: 1 + items: + - const: default + - const: sleep + + clocks: + description: + When present, the first clock listed must correspond to + the clock named UARTCLK on the IP block, i.e. the clock + to the external serial line, whereas the second clock + must correspond to the PCLK clocking the internal logic + of the block. Just listing one clock (the first one) is + deprecated. + maxItems: 2 + + clock-names: + items: + - const: uartclk + - const: apb_pclk + + dmas: + minItems: 1 + maxItems: 2 + + dma-names: + minItems: 1 + items: + - const: rx + - const: tx + + auto-poll: + description: + Enables polling when using RX DMA. + type: boolean + + poll-rate-ms: + description: + Rate at which poll occurs when auto-poll is set. + default 100ms. + allOf: + - $ref: /schemas/types.yaml#/definitions/uint32 + - default: 100 + + poll-timeout-ms: + description: + Poll timeout when auto-poll is set, default + 3000ms. + allOf: + - $ref: /schemas/types.yaml#/definitions/uint32 + - default: 3000 + +required: + - compatible + - reg + - interrupts + +dependencies: + poll-rate-ms: [ auto-poll ] + poll-timeout-ms: [ auto-poll ] + +additionalProperties: false + +examples: + - | + serial@80120000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x80120000 0x1000>; + interrupts = <0 11 4>; + dmas = <&dma 13 0 0x2>, <&dma 13 0 0x0>; + dma-names = "rx", "tx"; + clocks = <&foo_clk>, <&bar_clk>; + clock-names = "uartclk", "apb_pclk"; + }; + +... diff --git a/Documentation/devicetree/bindings/serial/renesas,rzn1-uart.txt b/Documentation/devicetree/bindings/serial/renesas,rzn1-uart.txt deleted file mode 100644 index 8b9e0d4dc2e4..000000000000 --- a/Documentation/devicetree/bindings/serial/renesas,rzn1-uart.txt +++ /dev/null @@ -1,10 +0,0 @@ -Renesas RZ/N1 UART - -This controller is based on the Synopsys DesignWare ABP UART and inherits all -properties defined in snps-dw-apb-uart.txt except for the compatible property. - -Required properties: -- compatible : The device specific string followed by the generic RZ/N1 string. - Therefore it must be one of: - "renesas,r9a06g032-uart", "renesas,rzn1-uart" - "renesas,r9a06g033-uart", "renesas,rzn1-uart" diff --git a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt index 20232ad05d89..dd63151dc8b6 100644 --- a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt +++ b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt @@ -29,7 +29,9 @@ Required properties: - "renesas,scif-r8a774c0" for R8A774C0 (RZ/G2E) SCIF compatible UART. - "renesas,hscif-r8a774c0" for R8A774C0 (RZ/G2E) HSCIF compatible UART. - "renesas,scif-r8a7778" for R8A7778 (R-Car M1) SCIF compatible UART. + - "renesas,hscif-r8a7778" for R8A7778 (R-Car M1) HSCIF compatible UART. - "renesas,scif-r8a7779" for R8A7779 (R-Car H1) SCIF compatible UART. + - "renesas,hscif-r8a7779" for R8A7779 (R-Car H1) HSCIF compatible UART. - "renesas,scif-r8a7790" for R8A7790 (R-Car H2) SCIF compatible UART. - "renesas,scifa-r8a7790" for R8A7790 (R-Car H2) SCIFA compatible UART. - "renesas,scifb-r8a7790" for R8A7790 (R-Car H2) SCIFB compatible UART. diff --git a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt deleted file mode 100644 index 12bbe9f22560..000000000000 --- a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt +++ /dev/null @@ -1,76 +0,0 @@ -* Synopsys DesignWare ABP UART - -Required properties: -- compatible : "snps,dw-apb-uart" -- reg : offset and length of the register set for the device. -- interrupts : should contain uart interrupt. - -Clock handling: -The clock rate of the input clock needs to be supplied by one of -- clock-frequency : the input clock frequency for the UART. -- clocks : phandle to the input clock - -The supplying peripheral clock can also be handled, needing a second property -- clock-names: tuple listing input clock names. - Required elements: "baudclk", "apb_pclk" - -Optional properties: -- snps,uart-16550-compatible : reflects the value of UART_16550_COMPATIBLE - configuration parameter. Define this if your UART does not implement the busy - functionality. -- resets : phandle to the parent reset controller. -- reg-shift : quantity to shift the register offsets by. If this property is - not present then the register offsets are not shifted. -- reg-io-width : the size (in bytes) of the IO accesses that should be - performed on the device. If this property is not present then single byte - accesses are used. -- dcd-override : Override the DCD modem status signal. This signal will always - be reported as active instead of being obtained from the modem status - register. Define this if your serial port does not use this pin. -- dsr-override : Override the DTS modem status signal. This signal will always - be reported as active instead of being obtained from the modem status - register. Define this if your serial port does not use this pin. -- cts-override : Override the CTS modem status signal. This signal will always - be reported as active instead of being obtained from the modem status - register. Define this if your serial port does not use this pin. -- ri-override : Override the RI modem status signal. This signal will always be - reported as inactive instead of being obtained from the modem status register. - Define this if your serial port does not use this pin. - -Example: - - uart@80230000 { - compatible = "snps,dw-apb-uart"; - reg = <0x80230000 0x100>; - clock-frequency = <3686400>; - interrupts = <10>; - reg-shift = <2>; - reg-io-width = <4>; - dcd-override; - dsr-override; - cts-override; - ri-override; - }; - -Example with one clock: - - uart@80230000 { - compatible = "snps,dw-apb-uart"; - reg = <0x80230000 0x100>; - clocks = <&baudclk>; - interrupts = <10>; - reg-shift = <2>; - reg-io-width = <4>; - }; - -Example with two clocks: - - uart@80230000 { - compatible = "snps,dw-apb-uart"; - reg = <0x80230000 0x100>; - clocks = <&baudclk>, <&apb_pclk>; - clock-names = "baudclk", "apb_pclk"; - interrupts = <10>; - reg-shift = <2>; - reg-io-width = <4>; - }; diff --git a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml new file mode 100644 index 000000000000..b42002542690 --- /dev/null +++ b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml @@ -0,0 +1,140 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/serial/snps-dw-apb-uart.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Synopsys DesignWare ABP UART + +maintainers: + - Rob Herring <robh@kernel.org> + +allOf: + - $ref: /schemas/serial.yaml# + +properties: + compatible: + oneOf: + - items: + - enum: + - renesas,r9a06g032-uart + - renesas,r9a06g033-uart + - const: renesas,rzn1-uart + - items: + - enum: + - rockchip,px30-uart + - rockchip,rk3036-uart + - rockchip,rk3066-uart + - rockchip,rk3188-uart + - rockchip,rk3288-uart + - rockchip,rk3328-uart + - rockchip,rk3368-uart + - rockchip,rk3399-uart + - rockchip,rv1108-uart + - const: snps,dw-apb-uart + - items: + - enum: + - brcm,bcm11351-dw-apb-uart + - brcm,bcm21664-dw-apb-uart + - const: snps,dw-apb-uart + - const: snps,dw-apb-uart + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clock-frequency: true + + clocks: + minItems: 1 + maxItems: 2 + + clock-names: + items: + - const: baudclk + - const: apb_pclk + + snps,uart-16550-compatible: + description: reflects the value of UART_16550_COMPATIBLE configuration + parameter. Define this if your UART does not implement the busy functionality. + type: boolean + + resets: + maxItems: 1 + + reg-shift: true + + reg-io-width: true + + dcd-override: + description: Override the DCD modem status signal. This signal will + always be reported as active instead of being obtained from the modem + status register. Define this if your serial port does not use this + pin. + type: boolean + + dsr-override: + description: Override the DTS modem status signal. This signal will + always be reported as active instead of being obtained from the modem + status register. Define this if your serial port does not use this + pin. + type: boolean + + cts-override: + description: Override the CTS modem status signal. This signal will + always be reported as active instead of being obtained from the modem + status register. Define this if your serial port does not use this + pin. + type: boolean + + ri-override: + description: Override the RI modem status signal. This signal will always + be reported as inactive instead of being obtained from the modem status + register. Define this if your serial port does not use this pin. + type: boolean + +required: + - compatible + - reg + - interrupts + +examples: + - | + serial@80230000 { + compatible = "snps,dw-apb-uart"; + reg = <0x80230000 0x100>; + clock-frequency = <3686400>; + interrupts = <10>; + reg-shift = <2>; + reg-io-width = <4>; + dcd-override; + dsr-override; + cts-override; + ri-override; + }; + + - | + // Example with one clock: + serial@80230000 { + compatible = "snps,dw-apb-uart"; + reg = <0x80230000 0x100>; + clocks = <&baudclk>; + interrupts = <10>; + reg-shift = <2>; + reg-io-width = <4>; + }; + + - | + // Example with two clocks: + serial@80230000 { + compatible = "snps,dw-apb-uart"; + reg = <0x80230000 0x100>; + clocks = <&baudclk>, <&apb_pclk>; + clock-names = "baudclk", "apb_pclk"; + interrupts = <10>; + reg-shift = <2>; + reg-io-width = <4>; + }; +... diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index 0840d27381ea..e0a04bfc873e 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig @@ -441,4 +441,28 @@ config VCC depends on SUN_LDOMS help Support for Sun logical domain consoles. + +config LDISC_AUTOLOAD + bool "Automatically load TTY Line Disciplines" + default y + help + Historically the kernel has always automatically loaded any + line discipline that is in a kernel module when a user asks + for it to be loaded with the TIOCSETD ioctl, or through other + means. This is not always the best thing to do on systems + where you know you will not be using some of the more + "ancient" line disciplines, so prevent the kernel from doing + this unless the request is coming from a process with the + CAP_SYS_MODULE permissions. + + Say 'Y' here if you trust your userspace users to do the right + thing, or if you have only provided the line disciplines that + you know you will be using, or if you wish to continue to use + the traditional method of on-demand loading of these modules + by any user. + + This functionality can be changed at runtime with the + dev.tty.ldisc_autoload sysctl, this configuration option will + only set the default value of this functionality. + endif # TTY diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index dc43fa96c3de..5ef08905fe05 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c @@ -492,7 +492,7 @@ static void xencons_backend_changed(struct xenbus_device *dev, case XenbusStateClosed: if (dev->state == XenbusStateClosed) break; - /* Missed the backend's CLOSING state -- fallthrough */ + /* fall through - Missed the backend's CLOSING state. */ case XenbusStateClosing: xenbus_frontend_closed(dev); break; diff --git a/drivers/tty/ipwireless/hardware.c b/drivers/tty/ipwireless/hardware.c index b0baa4ce10f9..6bbf35682d53 100644 --- a/drivers/tty/ipwireless/hardware.c +++ b/drivers/tty/ipwireless/hardware.c @@ -1516,6 +1516,8 @@ static void ipw_send_setup_packet(struct ipw_hardware *hw) sizeof(struct ipw_setup_get_version_query_packet), ADDR_SETUP_PROT, TL_PROTOCOLID_SETUP, TL_SETUP_SIGNO_GET_VERSION_QRY); + if (!ver_packet) + return; ver_packet->header.length = sizeof(struct tl_setup_get_version_qry); /* diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 6f7da9a9d76f..c4e16b31f9ab 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -143,8 +143,8 @@ struct gsm_dlci { struct sk_buff *skb; /* Frame being sent */ struct sk_buff_head skb_list; /* Queued frames */ /* Data handling callback */ - void (*data)(struct gsm_dlci *dlci, u8 *data, int len); - void (*prev_data)(struct gsm_dlci *dlci, u8 *data, int len); + void (*data)(struct gsm_dlci *dlci, const u8 *data, int len); + void (*prev_data)(struct gsm_dlci *dlci, const u8 *data, int len); struct net_device *net; /* network interface, if created */ }; @@ -988,7 +988,7 @@ static void gsm_dlci_data_kick(struct gsm_dlci *dlci) * Encode up and queue a UI/UIH frame containing our response. */ -static void gsm_control_reply(struct gsm_mux *gsm, int cmd, u8 *data, +static void gsm_control_reply(struct gsm_mux *gsm, int cmd, const u8 *data, int dlen) { struct gsm_msg *msg; @@ -1073,14 +1073,14 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci, * and if need be stuff a break message down the tty. */ -static void gsm_control_modem(struct gsm_mux *gsm, u8 *data, int clen) +static void gsm_control_modem(struct gsm_mux *gsm, const u8 *data, int clen) { unsigned int addr = 0; unsigned int modem = 0; unsigned int brk = 0; struct gsm_dlci *dlci; int len = clen; - u8 *dp = data; + const u8 *dp = data; struct tty_struct *tty; while (gsm_read_ea(&addr, *dp++) == 0) { @@ -1134,13 +1134,13 @@ static void gsm_control_modem(struct gsm_mux *gsm, u8 *data, int clen) * this into the uplink tty if present */ -static void gsm_control_rls(struct gsm_mux *gsm, u8 *data, int clen) +static void gsm_control_rls(struct gsm_mux *gsm, const u8 *data, int clen) { struct tty_port *port; unsigned int addr = 0; u8 bits; int len = clen; - u8 *dp = data; + const u8 *dp = data; while (gsm_read_ea(&addr, *dp++) == 0) { len--; @@ -1189,7 +1189,7 @@ static void gsm_dlci_begin_close(struct gsm_dlci *dlci); */ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command, - u8 *data, int clen) + const u8 *data, int clen) { u8 buf[1]; unsigned long flags; @@ -1261,7 +1261,7 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command, */ static void gsm_control_response(struct gsm_mux *gsm, unsigned int command, - u8 *data, int clen) + const u8 *data, int clen) { struct gsm_control *ctrl; unsigned long flags; @@ -1553,7 +1553,7 @@ static void gsm_dlci_begin_close(struct gsm_dlci *dlci) * open we shovel the bits down it, if not we drop them. */ -static void gsm_dlci_data(struct gsm_dlci *dlci, u8 *data, int clen) +static void gsm_dlci_data(struct gsm_dlci *dlci, const u8 *data, int clen) { /* krefs .. */ struct tty_port *port = &dlci->port; @@ -1565,14 +1565,11 @@ static void gsm_dlci_data(struct gsm_dlci *dlci, u8 *data, int clen) pr_debug("%d bytes for tty\n", len); switch (dlci->adaption) { /* Unsupported types */ - /* Packetised interruptible data */ - case 4: + case 4: /* Packetised interruptible data */ break; - /* Packetised uininterruptible voice/data */ - case 3: + case 3: /* Packetised uininterruptible voice/data */ break; - /* Asynchronous serial with line state in each frame */ - case 2: + case 2: /* Asynchronous serial with line state in each frame */ while (gsm_read_ea(&modem, *data++) == 0) { len--; if (len == 0) @@ -1583,8 +1580,8 @@ static void gsm_dlci_data(struct gsm_dlci *dlci, u8 *data, int clen) gsm_process_modem(tty, dlci, modem, clen); tty_kref_put(tty); } - /* Line state will go via DLCI 0 controls only */ - case 1: + /* Fall through */ + case 1: /* Line state will go via DLCI 0 controls only */ default: tty_insert_flip_string(port, data, len); tty_flip_buffer_push(port); @@ -1603,7 +1600,7 @@ static void gsm_dlci_data(struct gsm_dlci *dlci, u8 *data, int clen) * and we divide up the work accordingly. */ -static void gsm_dlci_command(struct gsm_dlci *dlci, u8 *data, int len) +static void gsm_dlci_command(struct gsm_dlci *dlci, const u8 *data, int len) { /* See what command is involved */ unsigned int command = 0; @@ -1979,7 +1976,7 @@ static void gsm1_receive(struct gsm_mux *gsm, unsigned char c) gsm->address = 0; gsm->state = GSM_ADDRESS; gsm->fcs = INIT_FCS; - /* Drop through */ + /* Fall through */ case GSM_ADDRESS: /* Address continuation */ gsm->fcs = gsm_fcs_add(gsm->fcs, c); if (gsm_read_ea(&gsm->address, c)) @@ -2214,6 +2211,111 @@ static struct gsm_mux *gsm_alloc_mux(void) return gsm; } +static void gsm_copy_config_values(struct gsm_mux *gsm, + struct gsm_config *c) +{ + memset(c, 0, sizeof(*c)); + c->adaption = gsm->adaption; + c->encapsulation = gsm->encoding; + c->initiator = gsm->initiator; + c->t1 = gsm->t1; + c->t2 = gsm->t2; + c->t3 = 0; /* Not supported */ + c->n2 = gsm->n2; + if (gsm->ftype == UIH) + c->i = 1; + else + c->i = 2; + pr_debug("Ftype %d i %d\n", gsm->ftype, c->i); + c->mru = gsm->mru; + c->mtu = gsm->mtu; + c->k = 0; +} + +static int gsm_config(struct gsm_mux *gsm, struct gsm_config *c) +{ + int need_close = 0; + int need_restart = 0; + + /* Stuff we don't support yet - UI or I frame transport, windowing */ + if ((c->adaption != 1 && c->adaption != 2) || c->k) + return -EOPNOTSUPP; + /* Check the MRU/MTU range looks sane */ + if (c->mru > MAX_MRU || c->mtu > MAX_MTU || c->mru < 8 || c->mtu < 8) + return -EINVAL; + if (c->n2 < 3) + return -EINVAL; + if (c->encapsulation > 1) /* Basic, advanced, no I */ + return -EINVAL; + if (c->initiator > 1) + return -EINVAL; + if (c->i == 0 || c->i > 2) /* UIH and UI only */ + return -EINVAL; + /* + * See what is needed for reconfiguration + */ + + /* Timing fields */ + if (c->t1 != 0 && c->t1 != gsm->t1) + need_restart = 1; + if (c->t2 != 0 && c->t2 != gsm->t2) + need_restart = 1; + if (c->encapsulation != gsm->encoding) + need_restart = 1; + if (c->adaption != gsm->adaption) + need_restart = 1; + /* Requires care */ + if (c->initiator != gsm->initiator) + need_close = 1; + if (c->mru != gsm->mru) + need_restart = 1; + if (c->mtu != gsm->mtu) + need_restart = 1; + + /* + * Close down what is needed, restart and initiate the new + * configuration + */ + + if (need_close || need_restart) { + int ret; + + ret = gsm_disconnect(gsm); + + if (ret) + return ret; + } + if (need_restart) + gsm_cleanup_mux(gsm); + + gsm->initiator = c->initiator; + gsm->mru = c->mru; + gsm->mtu = c->mtu; + gsm->encoding = c->encapsulation; + gsm->adaption = c->adaption; + gsm->n2 = c->n2; + + if (c->i == 1) + gsm->ftype = UIH; + else if (c->i == 2) + gsm->ftype = UI; + + if (c->t1) + gsm->t1 = c->t1; + if (c->t2) + gsm->t2 = c->t2; + + /* + * FIXME: We need to separate activation/deactivation from adding + * and removing from the mux array + */ + if (need_restart) + gsm_activate_mux(gsm); + if (gsm->initiator && need_close) + gsm_dlci_begin_open(gsm->dlci[0]); + return 0; +} + /** * gsmld_output - write to link * @gsm: our mux @@ -2495,89 +2597,6 @@ static __poll_t gsmld_poll(struct tty_struct *tty, struct file *file, return mask; } -static int gsmld_config(struct tty_struct *tty, struct gsm_mux *gsm, - struct gsm_config *c) -{ - int need_close = 0; - int need_restart = 0; - - /* Stuff we don't support yet - UI or I frame transport, windowing */ - if ((c->adaption != 1 && c->adaption != 2) || c->k) - return -EOPNOTSUPP; - /* Check the MRU/MTU range looks sane */ - if (c->mru > MAX_MRU || c->mtu > MAX_MTU || c->mru < 8 || c->mtu < 8) - return -EINVAL; - if (c->n2 < 3) - return -EINVAL; - if (c->encapsulation > 1) /* Basic, advanced, no I */ - return -EINVAL; - if (c->initiator > 1) - return -EINVAL; - if (c->i == 0 || c->i > 2) /* UIH and UI only */ - return -EINVAL; - /* - * See what is needed for reconfiguration - */ - - /* Timing fields */ - if (c->t1 != 0 && c->t1 != gsm->t1) - need_restart = 1; - if (c->t2 != 0 && c->t2 != gsm->t2) - need_restart = 1; - if (c->encapsulation != gsm->encoding) - need_restart = 1; - if (c->adaption != gsm->adaption) - need_restart = 1; - /* Requires care */ - if (c->initiator != gsm->initiator) - need_close = 1; - if (c->mru != gsm->mru) - need_restart = 1; - if (c->mtu != gsm->mtu) - need_restart = 1; - - /* - * Close down what is needed, restart and initiate the new - * configuration - */ - - if (need_close || need_restart) { - int ret; - - ret = gsm_disconnect(gsm); - - if (ret) - return ret; - } - if (need_restart) - gsm_cleanup_mux(gsm); - - gsm->initiator = c->initiator; - gsm->mru = c->mru; - gsm->mtu = c->mtu; - gsm->encoding = c->encapsulation; - gsm->adaption = c->adaption; - gsm->n2 = c->n2; - - if (c->i == 1) - gsm->ftype = UIH; - else if (c->i == 2) - gsm->ftype = UI; - - if (c->t1) - gsm->t1 = c->t1; - if (c->t2) - gsm->t2 = c->t2; - - /* FIXME: We need to separate activation/deactivation from adding - and removing from the mux array */ - if (need_restart) - gsm_activate_mux(gsm); - if (gsm->initiator && need_close) - gsm_dlci_begin_open(gsm->dlci[0]); - return 0; -} - static int gsmld_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { @@ -2586,29 +2605,14 @@ static int gsmld_ioctl(struct tty_struct *tty, struct file *file, switch (cmd) { case GSMIOC_GETCONF: - memset(&c, 0, sizeof(c)); - c.adaption = gsm->adaption; - c.encapsulation = gsm->encoding; - c.initiator = gsm->initiator; - c.t1 = gsm->t1; - c.t2 = gsm->t2; - c.t3 = 0; /* Not supported */ - c.n2 = gsm->n2; - if (gsm->ftype == UIH) - c.i = 1; - else - c.i = 2; - pr_debug("Ftype %d i %d\n", gsm->ftype, c.i); - c.mru = gsm->mru; - c.mtu = gsm->mtu; - c.k = 0; + gsm_copy_config_values(gsm, &c); if (copy_to_user((void *)arg, &c, sizeof(c))) return -EFAULT; return 0; case GSMIOC_SETCONF: if (copy_from_user(&c, (void *)arg, sizeof(c))) return -EFAULT; - return gsmld_config(tty, gsm, &c); + return gsm_config(gsm, &c); default: return n_tty_ioctl_helper(tty, file, cmd, arg); } @@ -2695,7 +2699,7 @@ static void gsm_mux_net_tx_timeout(struct net_device *net) } static void gsm_mux_rx_netchar(struct gsm_dlci *dlci, - unsigned char *in_buf, int size) + const unsigned char *in_buf, int size) { struct net_device *net = dlci->net; struct sk_buff *skb; diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 8bdf42bc8fc8..e55c79eb6430 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -777,7 +777,7 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file, case TCOFLUSH: flush_tx_queue(tty); } - /* fall through to default */ + /* fall through - to default */ default: error = n_tty_ioctl_helper(tty, file, cmd, arg); diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 5dc9686697cf..9cdb0fa3c4bf 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -50,8 +50,10 @@ #include <linux/ratelimit.h> #include <linux/vmalloc.h> - -/* number of characters left in xmit buffer before select has we have room */ +/* + * Until this number of characters is queued in the xmit buffer, select will + * return "we have room for writes". + */ #define WAKEUP_CHARS 256 /* diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c index fed820e9ab9d..3214e22e79f3 100644 --- a/drivers/tty/nozomi.c +++ b/drivers/tty/nozomi.c @@ -1317,7 +1317,6 @@ static void remove_sysfs_files(struct nozomi *dc) static int nozomi_card_init(struct pci_dev *pdev, const struct pci_device_id *ent) { - resource_size_t start; int ret; struct nozomi *dc = NULL; int ndev_idx; @@ -1357,17 +1356,10 @@ static int nozomi_card_init(struct pci_dev *pdev, goto err_disable_device; } - start = pci_resource_start(dc->pdev, 0); - if (start == 0) { - dev_err(&pdev->dev, "No I/O address for card detected\n"); - ret = -ENODEV; - goto err_rel_regs; - } - /* Find out what card type it is */ nozomi_get_card_type(dc); - dc->base_addr = ioremap_nocache(start, dc->card_type); + dc->base_addr = pci_iomap(dc->pdev, 0, dc->card_type); if (!dc->base_addr) { dev_err(&pdev->dev, "Unable to map card MMIO\n"); ret = -ENODEV; diff --git a/drivers/tty/serdev/serdev-ttyport.c b/drivers/tty/serdev/serdev-ttyport.c index fa1672993b4c..d1cdd2ab8b4c 100644 --- a/drivers/tty/serdev/serdev-ttyport.c +++ b/drivers/tty/serdev/serdev-ttyport.c @@ -233,7 +233,7 @@ static int ttyport_get_tiocm(struct serdev_controller *ctrl) if (!tty->ops->tiocmget) return -ENOTSUPP; - return tty->driver->ops->tiocmget(tty); + return tty->ops->tiocmget(tty); } static int ttyport_set_tiocm(struct serdev_controller *ctrl, unsigned int set, unsigned int clear) @@ -244,7 +244,7 @@ static int ttyport_set_tiocm(struct serdev_controller *ctrl, unsigned int set, u if (!tty->ops->tiocmset) return -ENOTSUPP; - return tty->driver->ops->tiocmset(tty, set, clear); + return tty->ops->tiocmset(tty, set, clear); } static const struct serdev_controller_ops ctrl_ops = { diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c index 15a8c8dfa92b..424c07c5f629 100644 --- a/drivers/tty/serial/8250/8250_ingenic.c +++ b/drivers/tty/serial/8250/8250_ingenic.c @@ -129,22 +129,21 @@ static int __init ingenic_early_console_setup(struct earlycon_device *dev, return 0; } -EARLYCON_DECLARE(jz4740_uart, ingenic_early_console_setup); OF_EARLYCON_DECLARE(jz4740_uart, "ingenic,jz4740-uart", ingenic_early_console_setup); -EARLYCON_DECLARE(jz4770_uart, ingenic_early_console_setup); OF_EARLYCON_DECLARE(jz4770_uart, "ingenic,jz4770-uart", ingenic_early_console_setup); -EARLYCON_DECLARE(jz4775_uart, ingenic_early_console_setup); OF_EARLYCON_DECLARE(jz4775_uart, "ingenic,jz4775-uart", ingenic_early_console_setup); -EARLYCON_DECLARE(jz4780_uart, ingenic_early_console_setup); OF_EARLYCON_DECLARE(jz4780_uart, "ingenic,jz4780-uart", ingenic_early_console_setup); +OF_EARLYCON_DECLARE(x1000_uart, "ingenic,x1000-uart", + ingenic_early_console_setup); + static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value) { int ier; @@ -328,12 +327,18 @@ static const struct ingenic_uart_config jz4780_uart_config = { .fifosize = 64, }; +static const struct ingenic_uart_config x1000_uart_config = { + .tx_loadsz = 32, + .fifosize = 64, +}; + static const struct of_device_id of_match[] = { { .compatible = "ingenic,jz4740-uart", .data = &jz4740_uart_config }, { .compatible = "ingenic,jz4760-uart", .data = &jz4760_uart_config }, { .compatible = "ingenic,jz4770-uart", .data = &jz4760_uart_config }, { .compatible = "ingenic,jz4775-uart", .data = &jz4760_uart_config }, { .compatible = "ingenic,jz4780-uart", .data = &jz4780_uart_config }, + { .compatible = "ingenic,x1000-uart", .data = &x1000_uart_config }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, of_match); diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c index a1a85805d010..0277479c87e9 100644 --- a/drivers/tty/serial/8250/8250_of.c +++ b/drivers/tty/serial/8250/8250_of.c @@ -130,6 +130,10 @@ static int of_platform_serial_setup(struct platform_device *ofdev, port->flags |= UPF_IOREMAP; } + /* Compatibility with the deprecated pxa driver and 8250_pxa drivers. */ + if (of_device_is_compatible(np, "mrvl,mmp-uart")) + port->regshift = 2; + /* Check for registers offset within the devices address range */ if (of_property_read_u32(np, "reg-shift", &prop) == 0) port->regshift = prop; @@ -327,6 +331,7 @@ static const struct of_device_id of_platform_serial_table[] = { { .compatible = "nvidia,tegra20-uart", .data = (void *)PORT_TEGRA, }, { .compatible = "nxp,lpc3220-uart", .data = (void *)PORT_LPC3220, }, { .compatible = "ralink,rt2880-uart", .data = (void *)PORT_RT2880, }, + { .compatible = "intel,xscale-uart", .data = (void *)PORT_XSCALE, }, { .compatible = "altr,16550-FIFO32", .data = (void *)PORT_ALTR_16550_F32, }, { .compatible = "altr,16550-FIFO64", diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index ad7ba7d0f28d..0a8316632d75 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -12,6 +12,7 @@ #define SUPPORT_SYSRQ #endif +#include <linux/clk.h> #include <linux/device.h> #include <linux/io.h> #include <linux/module.h> @@ -1134,10 +1135,12 @@ static int omap8250_probe(struct platform_device *pdev) { struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + struct device_node *np = pdev->dev.of_node; struct omap8250_priv *priv; struct uart_8250_port up; int ret; void __iomem *membase; + const struct of_device_id *id; if (!regs || !irq) { dev_err(&pdev->dev, "missing registers or irq\n"); @@ -1194,27 +1197,31 @@ static int omap8250_probe(struct platform_device *pdev) up.port.unthrottle = omap_8250_unthrottle; up.port.rs485_config = omap_8250_rs485_config; - if (pdev->dev.of_node) { - const struct of_device_id *id; - - ret = of_alias_get_id(pdev->dev.of_node, "serial"); - - of_property_read_u32(pdev->dev.of_node, "clock-frequency", - &up.port.uartclk); - priv->wakeirq = irq_of_parse_and_map(pdev->dev.of_node, 1); - - id = of_match_device(of_match_ptr(omap8250_dt_ids), &pdev->dev); - if (id && id->data) - priv->habit |= *(u8 *)id->data; - } else { - ret = pdev->id; - } + ret = of_alias_get_id(np, "serial"); if (ret < 0) { - dev_err(&pdev->dev, "failed to get alias/pdev id\n"); + dev_err(&pdev->dev, "failed to get alias\n"); return ret; } up.port.line = ret; + if (of_property_read_u32(np, "clock-frequency", &up.port.uartclk)) { + struct clk *clk; + + clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(clk)) { + if (PTR_ERR(clk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + } else { + up.port.uartclk = clk_get_rate(clk); + } + } + + priv->wakeirq = irq_of_parse_and_map(np, 1); + + id = of_match_device(of_match_ptr(omap8250_dt_ids), &pdev->dev); + if (id && id->data) + priv->habit |= *(u8 *)id->data; + if (!up.port.uartclk) { up.port.uartclk = DEFAULT_CLK_SPEED; dev_warn(&pdev->dev, @@ -1242,25 +1249,23 @@ static int omap8250_probe(struct platform_device *pdev) omap_serial_fill_features_erratas(&up, priv); up.port.handle_irq = omap8250_no_handle_irq; #ifdef CONFIG_SERIAL_8250_DMA - if (pdev->dev.of_node) { - /* - * Oh DMA support. If there are no DMA properties in the DT then - * we will fall back to a generic DMA channel which does not - * really work here. To ensure that we do not get a generic DMA - * channel assigned, we have the the_no_dma_filter_fn() here. - * To avoid "failed to request DMA" messages we check for DMA - * properties in DT. - */ - ret = of_property_count_strings(pdev->dev.of_node, "dma-names"); - if (ret == 2) { - up.dma = &priv->omap8250_dma; - priv->omap8250_dma.fn = the_no_dma_filter_fn; - priv->omap8250_dma.tx_dma = omap_8250_tx_dma; - priv->omap8250_dma.rx_dma = omap_8250_rx_dma; - priv->omap8250_dma.rx_size = RX_TRIGGER; - priv->omap8250_dma.rxconf.src_maxburst = RX_TRIGGER; - priv->omap8250_dma.txconf.dst_maxburst = TX_TRIGGER; - } + /* + * Oh DMA support. If there are no DMA properties in the DT then + * we will fall back to a generic DMA channel which does not + * really work here. To ensure that we do not get a generic DMA + * channel assigned, we have the the_no_dma_filter_fn() here. + * To avoid "failed to request DMA" messages we check for DMA + * properties in DT. + */ + ret = of_property_count_strings(np, "dma-names"); + if (ret == 2) { + up.dma = &priv->omap8250_dma; + priv->omap8250_dma.fn = the_no_dma_filter_fn; + priv->omap8250_dma.tx_dma = omap_8250_tx_dma; + priv->omap8250_dma.rx_dma = omap_8250_rx_dma; + priv->omap8250_dma.rx_size = RX_TRIGGER; + priv->omap8250_dma.rxconf.src_maxburst = RX_TRIGGER; + priv->omap8250_dma.txconf.dst_maxburst = TX_TRIGGER; } #endif ret = serial8250_register_8250_port(&up); diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 48bd694a5fa1..df41397de478 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -2027,6 +2027,111 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .setup = pci_default_setup, .exit = pci_plx9050_exit, }, + { + .vendor = PCI_VENDOR_ID_ACCESIO, + .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SDB, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + { + .vendor = PCI_VENDOR_ID_ACCESIO, + .device = PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4S, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + { + .vendor = PCI_VENDOR_ID_ACCESIO, + .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4DB, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + { + .vendor = PCI_VENDOR_ID_ACCESIO, + .device = PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_4, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + { + .vendor = PCI_VENDOR_ID_ACCESIO, + .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SMDB, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + { + .vendor = PCI_VENDOR_ID_ACCESIO, + .device = PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4SM, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + { + .vendor = PCI_VENDOR_ID_ACCESIO, + .device = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_4, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + { + .vendor = PCI_VENDOR_ID_ACCESIO, + .device = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_4, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + { + .vendor = PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4S, + .device = PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_4, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + { + .vendor = PCI_VENDOR_ID_ACCESIO, + .device = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_4, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + { + .vendor = PCI_VENDOR_ID_ACCESIO, + .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM422_4, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + { + .vendor = PCI_VENDOR_ID_ACCESIO, + .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM485_4, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + { + .vendor = PCI_VENDOR_ID_ACCESIO, + .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + { + .vendor = PCI_VENDOR_ID_ACCESIO, + .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SM, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + { + .vendor = PCI_VENDOR_ID_ACCESIO, + .device = PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, /* * SBS Technologies, Inc., PMC-OCTALPRO 232 */ @@ -3375,6 +3480,9 @@ static const struct pci_device_id blacklist[] = { /* Exar devices */ { PCI_VDEVICE(EXAR, PCI_ANY_ID), }, { PCI_VDEVICE(COMMTECH, PCI_ANY_ID), }, + + /* End of the black list */ + { } }; static int serial_pci_is_class_communication(struct pci_dev *dev) @@ -3392,25 +3500,6 @@ static int serial_pci_is_class_communication(struct pci_dev *dev) return 0; } -static int serial_pci_is_blacklisted(struct pci_dev *dev) -{ - const struct pci_device_id *bldev; - - /* - * Do not access blacklisted devices that are known not to - * feature serial ports or are handled by other modules. - */ - for (bldev = blacklist; - bldev < blacklist + ARRAY_SIZE(blacklist); - bldev++) { - if (dev->vendor == bldev->vendor && - dev->device == bldev->device) - return -ENODEV; - } - - return 0; -} - /* * Given a complete unknown PCI device, try to use some heuristics to * guess what the configuration might be, based on the pitiful PCI @@ -3634,6 +3723,7 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) struct pci_serial_quirk *quirk; struct serial_private *priv; const struct pciserial_board *board; + const struct pci_device_id *exclude; struct pciserial_board tmp; int rc; @@ -3652,9 +3742,9 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) board = &pci_boards[ent->driver_data]; - rc = serial_pci_is_blacklisted(dev); - if (rc) - return rc; + exclude = pci_match_id(blacklist, dev); + if (exclude) + return -ENODEV; rc = pcim_enable_device(dev); pci_save_state(dev); @@ -4575,10 +4665,10 @@ static const struct pci_device_id serial_pci_tbl[] = { */ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_2SDB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, + pbn_pericom_PI7C9X7952 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM_2S, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, + pbn_pericom_PI7C9X7952 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SDB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_pericom_PI7C9X7954 }, @@ -4587,10 +4677,10 @@ static const struct pci_device_id serial_pci_tbl[] = { pbn_pericom_PI7C9X7954 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_2DB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, + pbn_pericom_PI7C9X7952 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, + pbn_pericom_PI7C9X7952 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4DB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_pericom_PI7C9X7954 }, @@ -4599,10 +4689,10 @@ static const struct pci_device_id serial_pci_tbl[] = { pbn_pericom_PI7C9X7954 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_2SMDB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, + pbn_pericom_PI7C9X7952 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM_2SM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, + pbn_pericom_PI7C9X7952 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SMDB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_pericom_PI7C9X7954 }, @@ -4611,13 +4701,13 @@ static const struct pci_device_id serial_pci_tbl[] = { pbn_pericom_PI7C9X7954 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, + pbn_pericom_PI7C9X7951 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, + pbn_pericom_PI7C9X7952 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, + pbn_pericom_PI7C9X7952 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_pericom_PI7C9X7954 }, @@ -4626,16 +4716,16 @@ static const struct pci_device_id serial_pci_tbl[] = { pbn_pericom_PI7C9X7954 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_2S, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, + pbn_pericom_PI7C9X7952 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4S, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_pericom_PI7C9X7954 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, + pbn_pericom_PI7C9X7952 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, + pbn_pericom_PI7C9X7952 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_pericom_PI7C9X7954 }, @@ -4644,13 +4734,13 @@ static const struct pci_device_id serial_pci_tbl[] = { pbn_pericom_PI7C9X7954 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_2SM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, + pbn_pericom_PI7C9X7952 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM422_4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7958 }, + pbn_pericom_PI7C9X7954 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM485_4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7958 }, + pbn_pericom_PI7C9X7954 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM422_8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_pericom_PI7C9X7958 }, @@ -4659,19 +4749,19 @@ static const struct pci_device_id serial_pci_tbl[] = { pbn_pericom_PI7C9X7958 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7958 }, + pbn_pericom_PI7C9X7954 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_pericom_PI7C9X7958 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7958 }, + pbn_pericom_PI7C9X7954 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_8SM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_pericom_PI7C9X7958 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7958 }, + pbn_pericom_PI7C9X7954 }, /* * Topic TP560 Data/Fax/Voice 56k modem (reported by Evan Clarke) */ diff --git a/drivers/tty/serial/8250/8250_pxa.c b/drivers/tty/serial/8250/8250_pxa.c index b9bcbe20a2be..c47188860e32 100644 --- a/drivers/tty/serial/8250/8250_pxa.c +++ b/drivers/tty/serial/8250/8250_pxa.c @@ -113,6 +113,10 @@ static int serial_pxa_probe(struct platform_device *pdev) if (ret) return ret; + ret = of_alias_get_id(pdev->dev.of_node, "serial"); + if (ret >= 0) + uart.port.line = ret; + uart.port.type = PORT_XSCALE; uart.port.iotype = UPIO_MEM32; uart.port.mapbase = mmres->start; diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 089a6f285d5e..72966bc0ac76 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -335,6 +335,28 @@ config SERIAL_TEGRA are enabled). This driver uses the APB DMA to achieve higher baudrate and better performance. +config SERIAL_TEGRA_TCU + tristate "NVIDIA Tegra Combined UART" + depends on ARCH_TEGRA && TEGRA_HSP_MBOX + select SERIAL_CORE + help + Support for the mailbox-based TCU (Tegra Combined UART) serial port. + TCU is a virtual serial port that allows multiplexing multiple data + streams into a single hardware serial port. + +config SERIAL_TEGRA_TCU_CONSOLE + bool "Support for console on a Tegra TCU serial port" + depends on SERIAL_TEGRA_TCU=y + select SERIAL_CORE_CONSOLE + default y + ---help--- + If you say Y here, it will be possible to use a the Tegra TCU 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). + + If unsure, say Y. + config SERIAL_MAX3100 tristate "MAX3100 support" depends on SPI diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 1511e8a9f856..40b702aaa85e 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -77,6 +77,7 @@ obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o obj-$(CONFIG_SERIAL_SIRFSOC) += sirfsoc_uart.o obj-$(CONFIG_SERIAL_TEGRA) += serial-tegra.o +obj-$(CONFIG_SERIAL_TEGRA_TCU) += tegra-tcu.o obj-$(CONFIG_SERIAL_AR933X) += ar933x_uart.o obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o obj-$(CONFIG_SERIAL_ARC) += arc_uart.o diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c index 98f193a83392..061590795680 100644 --- a/drivers/tty/serial/clps711x.c +++ b/drivers/tty/serial/clps711x.c @@ -442,14 +442,10 @@ static struct console clps711x_console = { static int uart_clps711x_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - int ret, index = np ? of_alias_get_id(np, "serial") : pdev->id; struct clps711x_port *s; struct resource *res; struct clk *uart_clk; - int irq; - - if (index < 0 || index >= UART_CLPS711X_NR) - return -EINVAL; + int irq, ret; s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL); if (!s) @@ -473,20 +469,11 @@ static int uart_clps711x_probe(struct platform_device *pdev) if (s->rx_irq < 0) return s->rx_irq; - if (!np) { - char syscon_name[9]; - - sprintf(syscon_name, "syscon.%i", index + 1); - s->syscon = syscon_regmap_lookup_by_pdevname(syscon_name); - if (IS_ERR(s->syscon)) - return PTR_ERR(s->syscon); - } else { - s->syscon = syscon_regmap_lookup_by_phandle(np, "syscon"); - if (IS_ERR(s->syscon)) - return PTR_ERR(s->syscon); - } + s->syscon = syscon_regmap_lookup_by_phandle(np, "syscon"); + if (IS_ERR(s->syscon)) + return PTR_ERR(s->syscon); - s->port.line = index; + s->port.line = of_alias_get_id(np, "serial"); s->port.dev = &pdev->dev; s->port.iotype = UPIO_MEM32; s->port.mapbase = res->start; diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index debdd1b9e01a..ea1c85e3b432 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -426,6 +426,17 @@ static void lpuart_dma_tx_complete(void *arg) spin_unlock_irqrestore(&sport->port.lock, flags); } +static dma_addr_t lpuart_dma_datareg_addr(struct lpuart_port *sport) +{ + switch (sport->port.iotype) { + case UPIO_MEM32: + return sport->port.mapbase + UARTDATA; + case UPIO_MEM32BE: + return sport->port.mapbase + UARTDATA + sizeof(u32) - 1; + } + return sport->port.mapbase + UARTDR; +} + static int lpuart_dma_tx_request(struct uart_port *port) { struct lpuart_port *sport = container_of(port, @@ -433,7 +444,7 @@ static int lpuart_dma_tx_request(struct uart_port *port) struct dma_slave_config dma_tx_sconfig = {}; int ret; - dma_tx_sconfig.dst_addr = sport->port.mapbase + UARTDR; + dma_tx_sconfig.dst_addr = lpuart_dma_datareg_addr(sport); dma_tx_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; dma_tx_sconfig.dst_maxburst = 1; dma_tx_sconfig.direction = DMA_MEM_TO_DEV; @@ -636,13 +647,19 @@ 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; - temp = lpuart32_read(port, UARTCTRL); - lpuart32_write(port, temp | UARTCTRL_TIE, UARTCTRL); + if (sport->lpuart_dma_tx_use) { + if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) + lpuart_dma_tx(sport); + } else { + temp = lpuart32_read(port, UARTCTRL); + lpuart32_write(port, temp | UARTCTRL_TIE, UARTCTRL); - if (lpuart32_read(port, UARTSTAT) & UARTSTAT_TDRE) - lpuart32_transmit_buffer(sport); + if (lpuart32_read(port, UARTSTAT) & UARTSTAT_TDRE) + lpuart32_transmit_buffer(sport); + } } /* return TIOCSER_TEMT when transmitter is not busy */ @@ -664,8 +681,18 @@ static unsigned int lpuart_tx_empty(struct uart_port *port) static unsigned int lpuart32_tx_empty(struct uart_port *port) { - return (lpuart32_read(port, UARTSTAT) & UARTSTAT_TC) ? - TIOCSER_TEMT : 0; + struct lpuart_port *sport = container_of(port, + struct lpuart_port, port); + unsigned long stat = lpuart32_read(port, UARTSTAT); + unsigned long sfifo = lpuart32_read(port, UARTFIFO); + + if (sport->dma_tx_in_progress) + return 0; + + if (stat & UARTSTAT_TC && sfifo & UARTFIFO_TXEMPT) + return TIOCSER_TEMT; + + return 0; } static bool lpuart_is_32(struct lpuart_port *sport) @@ -862,11 +889,10 @@ static irqreturn_t lpuart32_int(int irq, void *dev_id) rxcount = lpuart32_read(&sport->port, UARTWATER); rxcount = rxcount >> UARTWATER_RXCNT_OFF; - if (sts & UARTSTAT_RDRF || rxcount > 0) + if ((sts & UARTSTAT_RDRF || rxcount > 0) && !sport->lpuart_dma_rx_use) lpuart32_rxint(irq, dev_id); - if ((sts & UARTSTAT_TDRE) && - !(lpuart32_read(&sport->port, UARTBAUD) & UARTBAUD_TDMAE)) + if ((sts & UARTSTAT_TDRE) && !sport->lpuart_dma_tx_use) lpuart_txint(irq, dev_id); lpuart32_write(&sport->port, sts, UARTSTAT); @@ -881,18 +907,31 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) struct circ_buf *ring = &sport->rx_ring; unsigned long flags; int count = 0; - unsigned char sr; - sr = readb(sport->port.membase + UARTSR1); + if (lpuart_is_32(sport)) { + unsigned long sr = lpuart32_read(&sport->port, UARTSTAT); - if (sr & (UARTSR1_PE | UARTSR1_FE)) { - /* Read DR to clear the error flags */ - readb(sport->port.membase + UARTDR); + if (sr & (UARTSTAT_PE | UARTSTAT_FE)) { + /* Read DR to clear the error flags */ + lpuart32_read(&sport->port, UARTDATA); + + if (sr & UARTSTAT_PE) + sport->port.icount.parity++; + else if (sr & UARTSTAT_FE) + sport->port.icount.frame++; + } + } else { + unsigned char sr = readb(sport->port.membase + UARTSR1); - if (sr & UARTSR1_PE) - sport->port.icount.parity++; - else if (sr & UARTSR1_FE) - sport->port.icount.frame++; + if (sr & (UARTSR1_PE | UARTSR1_FE)) { + /* Read DR to clear the error flags */ + readb(sport->port.membase + UARTDR); + + if (sr & UARTSR1_PE) + sport->port.icount.parity++; + else if (sr & UARTSR1_FE) + sport->port.icount.frame++; + } } async_tx_ack(sport->dma_rx_desc); @@ -1015,7 +1054,7 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport) return -EINVAL; } - dma_rx_sconfig.src_addr = sport->port.mapbase + UARTDR; + dma_rx_sconfig.src_addr = lpuart_dma_datareg_addr(sport); dma_rx_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; dma_rx_sconfig.src_maxburst = 1; dma_rx_sconfig.direction = DMA_DEV_TO_MEM; @@ -1043,8 +1082,14 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport) sport->dma_rx_cookie = dmaengine_submit(sport->dma_rx_desc); dma_async_issue_pending(sport->dma_rx_chan); - writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_RDMAS, - sport->port.membase + UARTCR5); + if (lpuart_is_32(sport)) { + unsigned long temp = lpuart32_read(&sport->port, UARTBAUD); + + lpuart32_write(&sport->port, temp | UARTBAUD_RDMAE, UARTBAUD); + } else { + writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_RDMAS, + sport->port.membase + UARTCR5); + } return 0; } @@ -1334,6 +1379,8 @@ static int lpuart32_startup(struct uart_port *port) 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); @@ -1342,8 +1389,41 @@ static int lpuart32_startup(struct uart_port *port) lpuart32_setup_watermark(sport); temp = lpuart32_read(&sport->port, UARTCTRL); - temp |= (UARTCTRL_RIE | UARTCTRL_TIE | UARTCTRL_RE | UARTCTRL_TE); - temp |= UARTCTRL_ILIE; + temp |= UARTCTRL_RE | UARTCTRL_TE | UARTCTRL_ILIE; + lpuart32_write(&sport->port, temp, UARTCTRL); + + 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 = lpuart32_read(&sport->port, UARTBAUD); + lpuart32_write(&sport->port, temp | UARTBAUD_TDMAE, UARTBAUD); + } else { + sport->lpuart_dma_tx_use = false; + } + + 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); spin_unlock_irqrestore(&sport->port.lock, flags); @@ -1384,6 +1464,8 @@ static void lpuart_shutdown(struct uart_port *port) static void lpuart32_shutdown(struct uart_port *port) { + struct lpuart_port *sport = + container_of(port, struct lpuart_port, port); unsigned long temp; unsigned long flags; @@ -1396,6 +1478,21 @@ static void lpuart32_shutdown(struct uart_port *port) lpuart32_write(port, temp, UARTCTRL); 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); + } } static void @@ -1621,7 +1718,10 @@ lpuart32_serial_setbrg(struct lpuart_port *sport, unsigned int baudrate) tmp &= ~UARTBAUD_SBR_MASK; tmp |= sbr & UARTBAUD_SBR_MASK; - tmp &= ~(UARTBAUD_TDMAE | UARTBAUD_RDMAE); + if (!sport->lpuart_dma_rx_use) + tmp &= ~UARTBAUD_RDMAE; + if (!sport->lpuart_dma_tx_use) + tmp &= ~UARTBAUD_TDMAE; lpuart32_write(&sport->port, tmp, UARTBAUD); } @@ -1699,6 +1799,18 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, /* ask the core to calculate the divisor */ baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 4); + /* + * Need to update the Ring buffer length according to the selected + * baud rate and restart Rx DMA path. + * + * Since timer function acqures sport->port.lock, need to stop before + * acquring same lock because otherwise del_timer_sync() can deadlock. + */ + if (old && sport->lpuart_dma_rx_use) { + del_timer_sync(&sport->lpuart_timer); + lpuart_dma_rx_free(&sport->port); + } + spin_lock_irqsave(&sport->port.lock, flags); sport->port.read_status_mask = 0; @@ -1737,6 +1849,13 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, lpuart32_write(&sport->port, ctrl, UARTCTRL); /* restore control register */ + if (old && sport->lpuart_dma_rx_use) { + if (!lpuart_start_rx_dma(sport)) + rx_dma_timer_init(sport); + else + sport->lpuart_dma_rx_use = false; + } + spin_unlock_irqrestore(&sport->port.lock, flags); } @@ -2306,8 +2425,14 @@ static int lpuart_suspend(struct device *dev) } /* Disable Rx DMA to use UART port as wakeup source */ - writeb(readb(sport->port.membase + UARTCR5) & ~UARTCR5_RDMAS, - sport->port.membase + UARTCR5); + if (lpuart_is_32(sport)) { + temp = lpuart32_read(&sport->port, UARTBAUD); + lpuart32_write(&sport->port, temp & ~UARTBAUD_RDMAE, + UARTBAUD); + } else { + writeb(readb(sport->port.membase + UARTCR5) & + ~UARTCR5_RDMAS, sport->port.membase + UARTCR5); + } } if (sport->lpuart_dma_tx_use) { @@ -2333,8 +2458,7 @@ static int lpuart_resume(struct device *dev) if (lpuart_is_32(sport)) { lpuart32_setup_watermark(sport); temp = lpuart32_read(&sport->port, UARTCTRL); - temp |= (UARTCTRL_RIE | UARTCTRL_TIE | UARTCTRL_RE | - UARTCTRL_TE | UARTCTRL_ILIE); + temp |= UARTCTRL_RE | UARTCTRL_TE | UARTCTRL_ILIE; lpuart32_write(&sport->port, temp, UARTCTRL); } else { lpuart_setup_watermark(sport); @@ -2353,14 +2477,36 @@ 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; + 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; } + 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); + } + uart_resume_port(&lpuart_reg, &sport->port); return 0; diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c index d1d73261575b..f4e27d0ad947 100644 --- a/drivers/tty/serial/lpc32xx_hs.c +++ b/drivers/tty/serial/lpc32xx_hs.c @@ -151,6 +151,8 @@ static void lpc32xx_hsuart_console_write(struct console *co, const char *s, local_irq_restore(flags); } +static void lpc32xx_loopback_set(resource_size_t mapbase, int state); + static int __init lpc32xx_hsuart_console_setup(struct console *co, char *options) { @@ -170,6 +172,8 @@ static int __init lpc32xx_hsuart_console_setup(struct console *co, if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); + lpc32xx_loopback_set(port->mapbase, 0); /* get out of loopback mode */ + return uart_set_options(port, co, baud, parity, bits, flow); } diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 4f479841769a..f5bdde405627 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -248,6 +248,7 @@ struct max310x_devtype { char name[9]; int nr; + u8 mode1; int (*detect)(struct device *); void (*power)(struct uart_port *, int); }; @@ -410,6 +411,7 @@ static void max14830_power(struct uart_port *port, int on) static const struct max310x_devtype max3107_devtype = { .name = "MAX3107", .nr = 1, + .mode1 = MAX310X_MODE1_AUTOSLEEP_BIT | MAX310X_MODE1_IRQSEL_BIT, .detect = max3107_detect, .power = max310x_power, }; @@ -417,6 +419,7 @@ static const struct max310x_devtype max3107_devtype = { static const struct max310x_devtype max3108_devtype = { .name = "MAX3108", .nr = 1, + .mode1 = MAX310X_MODE1_AUTOSLEEP_BIT, .detect = max3108_detect, .power = max310x_power, }; @@ -424,6 +427,7 @@ static const struct max310x_devtype max3108_devtype = { static const struct max310x_devtype max3109_devtype = { .name = "MAX3109", .nr = 2, + .mode1 = MAX310X_MODE1_AUTOSLEEP_BIT, .detect = max3109_detect, .power = max310x_power, }; @@ -431,6 +435,7 @@ static const struct max310x_devtype max3109_devtype = { static const struct max310x_devtype max14830_devtype = { .name = "MAX14830", .nr = 4, + .mode1 = MAX310X_MODE1_IRQSEL_BIT, .detect = max14830_detect, .power = max14830_power, }; @@ -1197,8 +1202,7 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, return PTR_ERR(regmap); /* Alloc port structure */ - s = devm_kzalloc(dev, sizeof(*s) + - sizeof(struct max310x_one) * devtype->nr, GFP_KERNEL); + s = devm_kzalloc(dev, struct_size(s, p, devtype->nr), GFP_KERNEL); if (!s) { dev_err(dev, "Error allocating port structure\n"); return -ENOMEM; @@ -1258,9 +1262,8 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, MAX310X_BRGDIVLSB_REG + offs, &ret); } while (ret != 0x01); - regmap_update_bits(s->regmap, MAX310X_MODE1_REG + offs, - MAX310X_MODE1_AUTOSLEEP_BIT, - MAX310X_MODE1_AUTOSLEEP_BIT); + regmap_write(s->regmap, MAX310X_MODE1_REG + offs, + devtype->mode1); } uartclk = max310x_set_ref_clk(dev, s, freq, xtal); @@ -1294,10 +1297,6 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, max310x_port_write(&s->p[i].port, MAX310X_IRQEN_REG, 0); /* Clear IRQ status register */ max310x_port_read(&s->p[i].port, MAX310X_IRQSTS_REG); - /* Enable IRQ pin */ - max310x_port_update(&s->p[i].port, MAX310X_MODE1_REG, - MAX310X_MODE1_IRQSEL_BIT, - MAX310X_MODE1_IRQSEL_BIT); /* Initialize queue for start TX */ INIT_WORK(&s->p[i].tx_work, max310x_wq_proc); /* Initialize queue for changing LOOPBACK mode */ @@ -1467,10 +1466,10 @@ static int __init max310x_uart_init(void) return ret; #ifdef CONFIG_SPI_MASTER - spi_register_driver(&max310x_spi_driver); + ret = spi_register_driver(&max310x_spi_driver); #endif - return 0; + return ret; } module_init(max310x_uart_init); diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c index 8a842591b37c..fbc5bc022a39 100644 --- a/drivers/tty/serial/meson_uart.c +++ b/drivers/tty/serial/meson_uart.c @@ -72,7 +72,8 @@ #define AML_UART_BAUD_USE BIT(23) #define AML_UART_BAUD_XTAL BIT(24) -#define AML_UART_PORT_NUM 6 +#define AML_UART_PORT_NUM 12 +#define AML_UART_PORT_OFFSET 6 #define AML_UART_DEV_NAME "ttyAML" @@ -654,10 +655,20 @@ static int meson_uart_probe(struct platform_device *pdev) struct resource *res_mem, *res_irq; struct uart_port *port; int ret = 0; + int id = -1; if (pdev->dev.of_node) pdev->id = of_alias_get_id(pdev->dev.of_node, "serial"); + if (pdev->id < 0) { + for (id = AML_UART_PORT_OFFSET; id < AML_UART_PORT_NUM; id++) { + if (!meson_ports[id]) { + pdev->id = id; + break; + } + } + } + if (pdev->id < 0 || pdev->id >= AML_UART_PORT_NUM) return -EINVAL; diff --git a/drivers/tty/serial/mps2-uart.c b/drivers/tty/serial/mps2-uart.c index 9f8f63719126..587b42f754cb 100644 --- a/drivers/tty/serial/mps2-uart.c +++ b/drivers/tty/serial/mps2-uart.c @@ -22,6 +22,7 @@ #include <linux/serial_core.h> #include <linux/tty_flip.h> #include <linux/types.h> +#include <linux/idr.h> #define SERIAL_NAME "ttyMPS" #define DRIVER_NAME "mps2-uart" @@ -65,11 +66,14 @@ #define MPS2_MAX_PORTS 3 +#define UART_PORT_COMBINED_IRQ BIT(0) + struct mps2_uart_port { struct uart_port port; struct clk *clk; unsigned int tx_irq; unsigned int rx_irq; + unsigned int flags; }; static inline struct mps2_uart_port *to_mps2_port(struct uart_port *port) @@ -264,6 +268,20 @@ static irqreturn_t mps2_uart_oerrirq(int irq, void *data) return handled; } +static irqreturn_t mps2_uart_combinedirq(int irq, void *data) +{ + if (mps2_uart_rxirq(irq, data) == IRQ_HANDLED) + return IRQ_HANDLED; + + if (mps2_uart_txirq(irq, data) == IRQ_HANDLED) + return IRQ_HANDLED; + + if (mps2_uart_oerrirq(irq, data) == IRQ_HANDLED) + return IRQ_HANDLED; + + return IRQ_NONE; +} + static int mps2_uart_startup(struct uart_port *port) { struct mps2_uart_port *mps_port = to_mps2_port(port); @@ -274,26 +292,37 @@ static int mps2_uart_startup(struct uart_port *port) mps2_uart_write8(port, control, UARTn_CTRL); - ret = request_irq(mps_port->rx_irq, mps2_uart_rxirq, 0, - MAKE_NAME(-rx), mps_port); - if (ret) { - dev_err(port->dev, "failed to register rxirq (%d)\n", ret); - return ret; - } + if (mps_port->flags & UART_PORT_COMBINED_IRQ) { + ret = request_irq(port->irq, mps2_uart_combinedirq, 0, + MAKE_NAME(-combined), mps_port); - ret = request_irq(mps_port->tx_irq, mps2_uart_txirq, 0, - MAKE_NAME(-tx), mps_port); - if (ret) { - dev_err(port->dev, "failed to register txirq (%d)\n", ret); - goto err_free_rxirq; - } + if (ret) { + dev_err(port->dev, "failed to register combinedirq (%d)\n", ret); + return ret; + } + } else { + ret = request_irq(port->irq, mps2_uart_oerrirq, IRQF_SHARED, + MAKE_NAME(-overrun), mps_port); + + if (ret) { + dev_err(port->dev, "failed to register oerrirq (%d)\n", ret); + return ret; + } + + ret = request_irq(mps_port->rx_irq, mps2_uart_rxirq, 0, + MAKE_NAME(-rx), mps_port); + if (ret) { + dev_err(port->dev, "failed to register rxirq (%d)\n", ret); + goto err_free_oerrirq; + } - ret = request_irq(port->irq, mps2_uart_oerrirq, IRQF_SHARED, - MAKE_NAME(-overrun), mps_port); + ret = request_irq(mps_port->tx_irq, mps2_uart_txirq, 0, + MAKE_NAME(-tx), mps_port); + if (ret) { + dev_err(port->dev, "failed to register txirq (%d)\n", ret); + goto err_free_rxirq; + } - if (ret) { - dev_err(port->dev, "failed to register oerrirq (%d)\n", ret); - goto err_free_txirq; } control |= UARTn_CTRL_RX_GRP | UARTn_CTRL_TX_GRP; @@ -302,10 +331,10 @@ static int mps2_uart_startup(struct uart_port *port) return 0; -err_free_txirq: - free_irq(mps_port->tx_irq, mps_port); err_free_rxirq: free_irq(mps_port->rx_irq, mps_port); +err_free_oerrirq: + free_irq(port->irq, mps_port); return ret; } @@ -319,8 +348,11 @@ static void mps2_uart_shutdown(struct uart_port *port) mps2_uart_write8(port, control, UARTn_CTRL); - free_irq(mps_port->rx_irq, mps_port); - free_irq(mps_port->tx_irq, mps_port); + if (!(mps_port->flags & UART_PORT_COMBINED_IRQ)) { + free_irq(mps_port->rx_irq, mps_port); + free_irq(mps_port->tx_irq, mps_port); + } + free_irq(port->irq, mps_port); } @@ -397,7 +429,7 @@ static const struct uart_ops mps2_uart_pops = { .verify_port = mps2_uart_verify_port, }; -static struct mps2_uart_port mps2_uart_ports[MPS2_MAX_PORTS]; +static DEFINE_IDR(ports_idr); #ifdef CONFIG_SERIAL_MPS2_UART_CONSOLE static void mps2_uart_console_putchar(struct uart_port *port, int ch) @@ -410,7 +442,8 @@ static void mps2_uart_console_putchar(struct uart_port *port, int ch) static void mps2_uart_console_write(struct console *co, const char *s, unsigned int cnt) { - struct uart_port *port = &mps2_uart_ports[co->index].port; + struct mps2_uart_port *mps_port = idr_find(&ports_idr, co->index); + struct uart_port *port = &mps_port->port; uart_console_write(port, s, cnt, mps2_uart_console_putchar); } @@ -426,7 +459,10 @@ static int mps2_uart_console_setup(struct console *co, char *options) if (co->index < 0 || co->index >= MPS2_MAX_PORTS) return -ENODEV; - mps_port = &mps2_uart_ports[co->index]; + mps_port = idr_find(&ports_idr, co->index); + + if (!mps_port) + return -ENODEV; if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); @@ -487,27 +523,36 @@ static struct uart_driver mps2_uart_driver = { .cons = MPS2_SERIAL_CONSOLE, }; -static struct mps2_uart_port *mps2_of_get_port(struct platform_device *pdev) +static int mps2_of_get_port(struct platform_device *pdev, + struct mps2_uart_port *mps_port) { struct device_node *np = pdev->dev.of_node; int id; if (!np) - return NULL; + return -ENODEV; id = of_alias_get_id(np, "serial"); + if (id < 0) - id = 0; + id = idr_alloc_cyclic(&ports_idr, (void *)mps_port, 0, MPS2_MAX_PORTS, GFP_KERNEL); + else + id = idr_alloc(&ports_idr, (void *)mps_port, id, MPS2_MAX_PORTS, GFP_KERNEL); - if (WARN_ON(id >= MPS2_MAX_PORTS)) - return NULL; + if (id < 0) + return id; + + /* Only combined irq is presesnt */ + if (platform_irq_count(pdev) == 1) + mps_port->flags |= UART_PORT_COMBINED_IRQ; + + mps_port->port.line = id; - mps2_uart_ports[id].port.line = id; - return &mps2_uart_ports[id]; + return 0; } -static int mps2_init_port(struct mps2_uart_port *mps_port, - struct platform_device *pdev) +static int mps2_init_port(struct platform_device *pdev, + struct mps2_uart_port *mps_port) { struct resource *res; int ret; @@ -519,11 +564,6 @@ static int mps2_init_port(struct mps2_uart_port *mps_port, mps_port->port.mapbase = res->start; mps_port->port.mapsize = resource_size(res); - - mps_port->rx_irq = platform_get_irq(pdev, 0); - mps_port->tx_irq = platform_get_irq(pdev, 1); - mps_port->port.irq = platform_get_irq(pdev, 2); - mps_port->port.iotype = UPIO_MEM; mps_port->port.flags = UPF_BOOT_AUTOCONF; mps_port->port.fifosize = 1; @@ -542,6 +582,15 @@ static int mps2_init_port(struct mps2_uart_port *mps_port, clk_disable_unprepare(mps_port->clk); + + if (mps_port->flags & UART_PORT_COMBINED_IRQ) { + mps_port->port.irq = platform_get_irq(pdev, 0); + } else { + mps_port->rx_irq = platform_get_irq(pdev, 0); + mps_port->tx_irq = platform_get_irq(pdev, 1); + mps_port->port.irq = platform_get_irq(pdev, 2); + } + return ret; } @@ -550,11 +599,16 @@ static int mps2_serial_probe(struct platform_device *pdev) struct mps2_uart_port *mps_port; int ret; - mps_port = mps2_of_get_port(pdev); - if (!mps_port) - return -ENODEV; + mps_port = devm_kzalloc(&pdev->dev, sizeof(struct mps2_uart_port), GFP_KERNEL); + + if (!mps_port) + return -ENOMEM; + + ret = mps2_of_get_port(pdev, mps_port); + if (ret) + return ret; - ret = mps2_init_port(mps_port, pdev); + ret = mps2_init_port(pdev, mps_port); if (ret) return ret; diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 736b74fd6623..109096033bb1 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -1634,7 +1634,7 @@ static void msm_console_write(struct console *co, const char *s, __msm_console_write(port, s, count, msm_port->is_uartdm); } -static int __init msm_console_setup(struct console *co, char *options) +static int msm_console_setup(struct console *co, char *options) { struct uart_port *port; int baud = 115200; diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index 38016609c7fa..3bcec1c20219 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -89,7 +89,7 @@ #define DEF_FIFO_DEPTH_WORDS 16 #define DEF_TX_WM 2 #define DEF_FIFO_WIDTH_BITS 32 -#define UART_CONSOLE_RX_WM 2 +#define UART_RX_WM 2 #define MAX_LOOPBACK_CFG 3 #ifdef CONFIG_CONSOLE_POLL @@ -105,10 +105,6 @@ struct qcom_geni_serial_port { u32 tx_fifo_depth; u32 tx_fifo_width; u32 rx_fifo_depth; - u32 tx_wm; - u32 rx_wm; - u32 rx_rfr; - enum geni_se_xfer_mode xfer_mode; bool setup; int (*handle_rx)(struct uart_port *uport, u32 bytes, bool drop); unsigned int baud; @@ -228,7 +224,7 @@ static unsigned int qcom_geni_serial_get_mctrl(struct uart_port *uport) if (uart_console(uport)) { mctrl |= TIOCM_CTS; } else { - geni_ios = readl_relaxed(uport->membase + SE_GENI_IOS); + geni_ios = readl(uport->membase + SE_GENI_IOS); if (!(geni_ios & IO2_DATA_IN)) mctrl |= TIOCM_CTS; } @@ -246,7 +242,7 @@ static void qcom_geni_serial_set_mctrl(struct uart_port *uport, if (!(mctrl & TIOCM_RTS)) uart_manual_rfr = UART_MANUAL_RFR_EN | UART_RFR_NOT_READY; - writel_relaxed(uart_manual_rfr, uport->membase + SE_UART_MANUAL_RFR); + writel(uart_manual_rfr, uport->membase + SE_UART_MANUAL_RFR); } static const char *qcom_geni_serial_get_type(struct uart_port *uport) @@ -275,9 +271,6 @@ static bool qcom_geni_serial_poll_bit(struct uart_port *uport, unsigned int fifo_bits; unsigned long timeout_us = 20000; - /* Ensure polling is not re-ordered before the prior writes/reads */ - mb(); - if (uport->private_data) { port = to_dev_port(uport, uport); baud = port->baud; @@ -297,7 +290,7 @@ static bool qcom_geni_serial_poll_bit(struct uart_port *uport, */ timeout_us = DIV_ROUND_UP(timeout_us, 10) * 10; while (timeout_us) { - reg = readl_relaxed(uport->membase + offset); + reg = readl(uport->membase + offset); if ((bool)(reg & field) == set) return true; udelay(10); @@ -310,7 +303,7 @@ static void qcom_geni_serial_setup_tx(struct uart_port *uport, u32 xmit_size) { u32 m_cmd; - writel_relaxed(xmit_size, uport->membase + SE_UART_TX_TRANS_LEN); + writel(xmit_size, uport->membase + SE_UART_TX_TRANS_LEN); m_cmd = UART_START_TX << M_OPCODE_SHFT; writel(m_cmd, uport->membase + SE_GENI_M_CMD0); } @@ -323,13 +316,13 @@ static void qcom_geni_serial_poll_tx_done(struct uart_port *uport) done = qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, M_CMD_DONE_EN, true); if (!done) { - writel_relaxed(M_GENI_CMD_ABORT, uport->membase + + writel(M_GENI_CMD_ABORT, uport->membase + SE_GENI_M_CMD_CTRL_REG); irq_clear |= M_CMD_ABORT_EN; qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, M_CMD_ABORT_EN, true); } - writel_relaxed(irq_clear, uport->membase + SE_GENI_M_IRQ_CLEAR); + writel(irq_clear, uport->membase + SE_GENI_M_IRQ_CLEAR); } static void qcom_geni_serial_abort_rx(struct uart_port *uport) @@ -339,8 +332,8 @@ static void qcom_geni_serial_abort_rx(struct uart_port *uport) writel(S_GENI_CMD_ABORT, uport->membase + SE_GENI_S_CMD_CTRL_REG); qcom_geni_serial_poll_bit(uport, SE_GENI_S_CMD_CTRL_REG, S_GENI_CMD_ABORT, false); - writel_relaxed(irq_clear, uport->membase + SE_GENI_S_IRQ_CLEAR); - writel_relaxed(FORCE_DEFAULT, uport->membase + GENI_FORCE_DEFAULT_REG); + writel(irq_clear, uport->membase + SE_GENI_S_IRQ_CLEAR); + writel(FORCE_DEFAULT, uport->membase + GENI_FORCE_DEFAULT_REG); } #ifdef CONFIG_CONSOLE_POLL @@ -349,19 +342,13 @@ static int qcom_geni_serial_get_char(struct uart_port *uport) u32 rx_fifo; u32 status; - status = readl_relaxed(uport->membase + SE_GENI_M_IRQ_STATUS); - writel_relaxed(status, uport->membase + SE_GENI_M_IRQ_CLEAR); + status = readl(uport->membase + SE_GENI_M_IRQ_STATUS); + writel(status, uport->membase + SE_GENI_M_IRQ_CLEAR); - status = readl_relaxed(uport->membase + SE_GENI_S_IRQ_STATUS); - writel_relaxed(status, uport->membase + SE_GENI_S_IRQ_CLEAR); + status = readl(uport->membase + SE_GENI_S_IRQ_STATUS); + writel(status, uport->membase + SE_GENI_S_IRQ_CLEAR); - /* - * Ensure the writes to clear interrupts is not re-ordered after - * reading the data. - */ - mb(); - - status = readl_relaxed(uport->membase + SE_GENI_RX_FIFO_STATUS); + status = readl(uport->membase + SE_GENI_RX_FIFO_STATUS); if (!(status & RX_FIFO_WC_MSK)) return NO_POLL_CHAR; @@ -372,15 +359,12 @@ static int qcom_geni_serial_get_char(struct uart_port *uport) static void qcom_geni_serial_poll_put_char(struct uart_port *uport, unsigned char c) { - struct qcom_geni_serial_port *port = to_dev_port(uport, uport); - - writel_relaxed(port->tx_wm, uport->membase + SE_GENI_TX_WATERMARK_REG); + writel(DEF_TX_WM, uport->membase + SE_GENI_TX_WATERMARK_REG); qcom_geni_serial_setup_tx(uport, 1); WARN_ON(!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, M_TX_FIFO_WATERMARK_EN, true)); - writel_relaxed(c, uport->membase + SE_GENI_TX_FIFOn); - writel_relaxed(M_TX_FIFO_WATERMARK_EN, uport->membase + - SE_GENI_M_IRQ_CLEAR); + writel(c, uport->membase + SE_GENI_TX_FIFOn); + writel(M_TX_FIFO_WATERMARK_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); qcom_geni_serial_poll_tx_done(uport); } #endif @@ -388,7 +372,7 @@ static void qcom_geni_serial_poll_put_char(struct uart_port *uport, #ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE static void qcom_geni_serial_wr_char(struct uart_port *uport, int ch) { - writel_relaxed(ch, uport->membase + SE_GENI_TX_FIFOn); + writel(ch, uport->membase + SE_GENI_TX_FIFOn); } static void @@ -407,7 +391,7 @@ __qcom_geni_serial_console_write(struct uart_port *uport, const char *s, bytes_to_send++; } - writel_relaxed(DEF_TX_WM, uport->membase + SE_GENI_TX_WATERMARK_REG); + writel(DEF_TX_WM, uport->membase + SE_GENI_TX_WATERMARK_REG); qcom_geni_serial_setup_tx(uport, bytes_to_send); for (i = 0; i < count; ) { size_t chars_to_write = 0; @@ -425,7 +409,7 @@ __qcom_geni_serial_console_write(struct uart_port *uport, const char *s, chars_to_write = min_t(size_t, count - i, avail / 2); uart_console_write(uport, s + i, chars_to_write, qcom_geni_serial_wr_char); - writel_relaxed(M_TX_FIFO_WATERMARK_EN, uport->membase + + writel(M_TX_FIFO_WATERMARK_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); i += chars_to_write; } @@ -454,7 +438,7 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s, else spin_lock_irqsave(&uport->lock, flags); - geni_status = readl_relaxed(uport->membase + SE_GENI_STATUS); + geni_status = readl(uport->membase + SE_GENI_STATUS); /* Cancel the current write to log the fault */ if (!locked) { @@ -464,11 +448,10 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s, geni_se_abort_m_cmd(&port->se); qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, M_CMD_ABORT_EN, true); - writel_relaxed(M_CMD_ABORT_EN, uport->membase + + writel(M_CMD_ABORT_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); } - writel_relaxed(M_CMD_CANCEL_EN, uport->membase + - SE_GENI_M_IRQ_CLEAR); + writel(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); } else if ((geni_status & M_GENI_CMD_ACTIVE) && !port->tx_remaining) { /* * It seems we can't interrupt existing transfers if all data @@ -477,9 +460,8 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s, qcom_geni_serial_poll_tx_done(uport); if (uart_circ_chars_pending(&uport->state->xmit)) { - irq_en = readl_relaxed(uport->membase + - SE_GENI_M_IRQ_EN); - writel_relaxed(irq_en | M_TX_FIFO_WATERMARK_EN, + irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); + writel(irq_en | M_TX_FIFO_WATERMARK_EN, uport->membase + SE_GENI_M_IRQ_EN); } } @@ -567,29 +549,20 @@ static int handle_rx_uart(struct uart_port *uport, u32 bytes, bool drop) static void qcom_geni_serial_start_tx(struct uart_port *uport) { u32 irq_en; - struct qcom_geni_serial_port *port = to_dev_port(uport, uport); u32 status; - if (port->xfer_mode == GENI_SE_FIFO) { - /* - * readl ensures reading & writing of IRQ_EN register - * is not re-ordered before checking the status of the - * Serial Engine. - */ - status = readl(uport->membase + SE_GENI_STATUS); - if (status & M_GENI_CMD_ACTIVE) - return; + status = readl(uport->membase + SE_GENI_STATUS); + if (status & M_GENI_CMD_ACTIVE) + return; - if (!qcom_geni_serial_tx_empty(uport)) - return; + if (!qcom_geni_serial_tx_empty(uport)) + return; - irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN); - irq_en |= M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN; + irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); + irq_en |= M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN; - writel_relaxed(port->tx_wm, uport->membase + - SE_GENI_TX_WATERMARK_REG); - writel_relaxed(irq_en, uport->membase + SE_GENI_M_IRQ_EN); - } + writel(DEF_TX_WM, uport->membase + SE_GENI_TX_WATERMARK_REG); + writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN); } static void qcom_geni_serial_stop_tx(struct uart_port *uport) @@ -598,35 +571,24 @@ static void qcom_geni_serial_stop_tx(struct uart_port *uport) u32 status; struct qcom_geni_serial_port *port = to_dev_port(uport, uport); - irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN); - irq_en &= ~M_CMD_DONE_EN; - if (port->xfer_mode == GENI_SE_FIFO) { - irq_en &= ~M_TX_FIFO_WATERMARK_EN; - writel_relaxed(0, uport->membase + - SE_GENI_TX_WATERMARK_REG); - } - writel_relaxed(irq_en, uport->membase + SE_GENI_M_IRQ_EN); - status = readl_relaxed(uport->membase + SE_GENI_STATUS); + irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); + irq_en &= ~(M_CMD_DONE_EN | M_TX_FIFO_WATERMARK_EN); + writel(0, uport->membase + SE_GENI_TX_WATERMARK_REG); + writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN); + status = readl(uport->membase + SE_GENI_STATUS); /* Possible stop tx is called multiple times. */ if (!(status & M_GENI_CMD_ACTIVE)) return; - /* - * Ensure cancel command write is not re-ordered before checking - * the status of the Primary Sequencer. - */ - mb(); - geni_se_cancel_m_cmd(&port->se); if (!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, M_CMD_CANCEL_EN, true)) { geni_se_abort_m_cmd(&port->se); qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, M_CMD_ABORT_EN, true); - writel_relaxed(M_CMD_ABORT_EN, uport->membase + - SE_GENI_M_IRQ_CLEAR); + writel(M_CMD_ABORT_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); } - writel_relaxed(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); + writel(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); } static void qcom_geni_serial_start_rx(struct uart_port *uport) @@ -635,27 +597,19 @@ static void qcom_geni_serial_start_rx(struct uart_port *uport) u32 status; struct qcom_geni_serial_port *port = to_dev_port(uport, uport); - status = readl_relaxed(uport->membase + SE_GENI_STATUS); + status = readl(uport->membase + SE_GENI_STATUS); if (status & S_GENI_CMD_ACTIVE) qcom_geni_serial_stop_rx(uport); - /* - * Ensure setup command write is not re-ordered before checking - * the status of the Secondary Sequencer. - */ - mb(); - geni_se_setup_s_cmd(&port->se, UART_START_READ, 0); - if (port->xfer_mode == GENI_SE_FIFO) { - irq_en = readl_relaxed(uport->membase + SE_GENI_S_IRQ_EN); - irq_en |= S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN; - writel_relaxed(irq_en, uport->membase + SE_GENI_S_IRQ_EN); + irq_en = readl(uport->membase + SE_GENI_S_IRQ_EN); + irq_en |= S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN; + writel(irq_en, uport->membase + SE_GENI_S_IRQ_EN); - irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN); - irq_en |= M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN; - writel_relaxed(irq_en, uport->membase + SE_GENI_M_IRQ_EN); - } + irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); + irq_en |= M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN; + writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN); } static void qcom_geni_serial_stop_rx(struct uart_port *uport) @@ -665,32 +619,24 @@ static void qcom_geni_serial_stop_rx(struct uart_port *uport) struct qcom_geni_serial_port *port = to_dev_port(uport, uport); u32 irq_clear = S_CMD_DONE_EN; - if (port->xfer_mode == GENI_SE_FIFO) { - irq_en = readl_relaxed(uport->membase + SE_GENI_S_IRQ_EN); - irq_en &= ~(S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN); - writel_relaxed(irq_en, uport->membase + SE_GENI_S_IRQ_EN); + irq_en = readl(uport->membase + SE_GENI_S_IRQ_EN); + irq_en &= ~(S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN); + writel(irq_en, uport->membase + SE_GENI_S_IRQ_EN); - irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN); - irq_en &= ~(M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN); - writel_relaxed(irq_en, uport->membase + SE_GENI_M_IRQ_EN); - } + irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); + irq_en &= ~(M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN); + writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN); - status = readl_relaxed(uport->membase + SE_GENI_STATUS); + status = readl(uport->membase + SE_GENI_STATUS); /* Possible stop rx is called multiple times. */ if (!(status & S_GENI_CMD_ACTIVE)) return; - /* - * Ensure cancel command write is not re-ordered before checking - * the status of the Secondary Sequencer. - */ - mb(); - geni_se_cancel_s_cmd(&port->se); qcom_geni_serial_poll_bit(uport, SE_GENI_S_CMD_CTRL_REG, S_GENI_CMD_CANCEL, false); - status = readl_relaxed(uport->membase + SE_GENI_STATUS); - writel_relaxed(irq_clear, uport->membase + SE_GENI_S_IRQ_CLEAR); + status = readl(uport->membase + SE_GENI_STATUS); + writel(irq_clear, uport->membase + SE_GENI_S_IRQ_CLEAR); if (status & S_GENI_CMD_ACTIVE) qcom_geni_serial_abort_rx(uport); } @@ -704,7 +650,7 @@ static void qcom_geni_serial_handle_rx(struct uart_port *uport, bool drop) u32 total_bytes; struct qcom_geni_serial_port *port = to_dev_port(uport, uport); - status = readl_relaxed(uport->membase + SE_GENI_RX_FIFO_STATUS); + status = readl(uport->membase + SE_GENI_RX_FIFO_STATUS); word_cnt = status & RX_FIFO_WC_MSK; last_word_partial = status & RX_LAST; last_word_byte_cnt = (status & RX_LAST_BYTE_VALID_MSK) >> @@ -734,7 +680,7 @@ static void qcom_geni_serial_handle_tx(struct uart_port *uport, bool done, unsigned int chunk; int tail; - status = readl_relaxed(uport->membase + SE_GENI_TX_FIFO_STATUS); + status = readl(uport->membase + SE_GENI_TX_FIFO_STATUS); /* Complete the current tx command before taking newly added data */ if (active) @@ -760,9 +706,9 @@ static void qcom_geni_serial_handle_tx(struct uart_port *uport, bool done, qcom_geni_serial_setup_tx(uport, pending); port->tx_remaining = pending; - irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN); + irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); if (!(irq_en & M_TX_FIFO_WATERMARK_EN)) - writel_relaxed(irq_en | M_TX_FIFO_WATERMARK_EN, + writel(irq_en | M_TX_FIFO_WATERMARK_EN, uport->membase + SE_GENI_M_IRQ_EN); } @@ -795,14 +741,14 @@ static void qcom_geni_serial_handle_tx(struct uart_port *uport, bool done, * cleared it in qcom_geni_serial_isr it will have already reasserted * so we must clear it again here after our writes. */ - writel_relaxed(M_TX_FIFO_WATERMARK_EN, + writel(M_TX_FIFO_WATERMARK_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); out_write_wakeup: if (!port->tx_remaining) { - irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN); + irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); if (irq_en & M_TX_FIFO_WATERMARK_EN) - writel_relaxed(irq_en & ~M_TX_FIFO_WATERMARK_EN, + writel(irq_en & ~M_TX_FIFO_WATERMARK_EN, uport->membase + SE_GENI_M_IRQ_EN); } @@ -812,12 +758,12 @@ out_write_wakeup: static irqreturn_t qcom_geni_serial_isr(int isr, void *dev) { - unsigned int m_irq_status; - unsigned int s_irq_status; - unsigned int geni_status; + u32 m_irq_en; + u32 m_irq_status; + u32 s_irq_status; + u32 geni_status; struct uart_port *uport = dev; unsigned long flags; - unsigned int m_irq_en; bool drop_rx = false; struct tty_port *tport = &uport->state->port; struct qcom_geni_serial_port *port = to_dev_port(uport, uport); @@ -826,12 +772,12 @@ static irqreturn_t qcom_geni_serial_isr(int isr, void *dev) return IRQ_NONE; spin_lock_irqsave(&uport->lock, flags); - m_irq_status = readl_relaxed(uport->membase + SE_GENI_M_IRQ_STATUS); - s_irq_status = readl_relaxed(uport->membase + SE_GENI_S_IRQ_STATUS); - geni_status = readl_relaxed(uport->membase + SE_GENI_STATUS); - m_irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN); - writel_relaxed(m_irq_status, uport->membase + SE_GENI_M_IRQ_CLEAR); - writel_relaxed(s_irq_status, uport->membase + SE_GENI_S_IRQ_CLEAR); + m_irq_status = readl(uport->membase + SE_GENI_M_IRQ_STATUS); + s_irq_status = readl(uport->membase + SE_GENI_S_IRQ_STATUS); + geni_status = readl(uport->membase + SE_GENI_STATUS); + m_irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); + writel(m_irq_status, uport->membase + SE_GENI_M_IRQ_CLEAR); + writel(s_irq_status, uport->membase + SE_GENI_S_IRQ_CLEAR); if (WARN_ON(m_irq_status & M_ILLEGAL_CMD_EN)) goto out_unlock; @@ -877,17 +823,6 @@ static void get_tx_fifo_size(struct qcom_geni_serial_port *port) (port->tx_fifo_depth * port->tx_fifo_width) / BITS_PER_BYTE; } -static void set_rfr_wm(struct qcom_geni_serial_port *port) -{ - /* - * Set RFR (Flow off) to FIFO_DEPTH - 2. - * RX WM level at 10% RX_FIFO_DEPTH. - * TX WM level at 10% TX_FIFO_DEPTH. - */ - port->rx_rfr = port->rx_fifo_depth - 2; - port->rx_wm = UART_CONSOLE_RX_WM; - port->tx_wm = DEF_TX_WM; -} static void qcom_geni_serial_shutdown(struct uart_port *uport) { @@ -907,7 +842,7 @@ static void qcom_geni_serial_shutdown(struct uart_port *uport) static int qcom_geni_serial_port_setup(struct uart_port *uport) { struct qcom_geni_serial_port *port = to_dev_port(uport, uport); - unsigned int rxstale = DEFAULT_BITS_PER_CHAR * STALE_TIMEOUT; + u32 rxstale = DEFAULT_BITS_PER_CHAR * STALE_TIMEOUT; u32 proto; if (uart_console(uport)) { @@ -928,21 +863,19 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport) get_tx_fifo_size(port); - set_rfr_wm(port); - writel_relaxed(rxstale, uport->membase + SE_UART_RX_STALE_CNT); + writel(rxstale, uport->membase + SE_UART_RX_STALE_CNT); /* * Make an unconditional cancel on the main sequencer to reset * it else we could end up in data loss scenarios. */ - port->xfer_mode = GENI_SE_FIFO; if (uart_console(uport)) qcom_geni_serial_poll_tx_done(uport); geni_se_config_packing(&port->se, BITS_PER_BYTE, port->tx_bytes_pw, false, true, false); geni_se_config_packing(&port->se, BITS_PER_BYTE, port->rx_bytes_pw, false, false, true); - geni_se_init(&port->se, port->rx_wm, port->rx_rfr); - geni_se_select_mode(&port->se, port->xfer_mode); + geni_se_init(&port->se, UART_RX_WM, port->rx_fifo_depth - 2); + geni_se_select_mode(&port->se, GENI_SE_FIFO); if (!uart_console(uport)) { port->rx_fifo = devm_kcalloc(uport->dev, port->rx_fifo_depth, sizeof(u32), GFP_KERNEL); @@ -1008,14 +941,14 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport, struct ktermios *termios, struct ktermios *old) { unsigned int baud; - unsigned int bits_per_char; - unsigned int tx_trans_cfg; - unsigned int tx_parity_cfg; - unsigned int rx_trans_cfg; - unsigned int rx_parity_cfg; - unsigned int stop_bit_len; + u32 bits_per_char; + u32 tx_trans_cfg; + u32 tx_parity_cfg; + u32 rx_trans_cfg; + u32 rx_parity_cfg; + u32 stop_bit_len; unsigned int clk_div; - unsigned long ser_clk_cfg; + u32 ser_clk_cfg; struct qcom_geni_serial_port *port = to_dev_port(uport, uport); unsigned long clk_rate; @@ -1033,10 +966,10 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport, ser_clk_cfg |= clk_div << CLK_DIV_SHFT; /* parity */ - tx_trans_cfg = readl_relaxed(uport->membase + SE_UART_TX_TRANS_CFG); - tx_parity_cfg = readl_relaxed(uport->membase + SE_UART_TX_PARITY_CFG); - rx_trans_cfg = readl_relaxed(uport->membase + SE_UART_RX_TRANS_CFG); - rx_parity_cfg = readl_relaxed(uport->membase + SE_UART_RX_PARITY_CFG); + tx_trans_cfg = readl(uport->membase + SE_UART_TX_TRANS_CFG); + tx_parity_cfg = readl(uport->membase + SE_UART_TX_PARITY_CFG); + rx_trans_cfg = readl(uport->membase + SE_UART_RX_TRANS_CFG); + rx_parity_cfg = readl(uport->membase + SE_UART_RX_PARITY_CFG); if (termios->c_cflag & PARENB) { tx_trans_cfg |= UART_TX_PAR_EN; rx_trans_cfg |= UART_RX_PAR_EN; @@ -1092,17 +1025,17 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport, uart_update_timeout(uport, termios->c_cflag, baud); if (!uart_console(uport)) - writel_relaxed(port->loopback, + writel(port->loopback, uport->membase + SE_UART_LOOPBACK_CFG); - writel_relaxed(tx_trans_cfg, uport->membase + SE_UART_TX_TRANS_CFG); - writel_relaxed(tx_parity_cfg, uport->membase + SE_UART_TX_PARITY_CFG); - writel_relaxed(rx_trans_cfg, uport->membase + SE_UART_RX_TRANS_CFG); - writel_relaxed(rx_parity_cfg, uport->membase + SE_UART_RX_PARITY_CFG); - writel_relaxed(bits_per_char, uport->membase + SE_UART_TX_WORD_LEN); - writel_relaxed(bits_per_char, uport->membase + SE_UART_RX_WORD_LEN); - writel_relaxed(stop_bit_len, uport->membase + SE_UART_TX_STOP_BIT_LEN); - writel_relaxed(ser_clk_cfg, uport->membase + GENI_SER_M_CLK_CFG); - writel_relaxed(ser_clk_cfg, uport->membase + GENI_SER_S_CLK_CFG); + writel(tx_trans_cfg, uport->membase + SE_UART_TX_TRANS_CFG); + writel(tx_parity_cfg, uport->membase + SE_UART_TX_PARITY_CFG); + writel(rx_trans_cfg, uport->membase + SE_UART_RX_TRANS_CFG); + writel(rx_parity_cfg, uport->membase + SE_UART_RX_PARITY_CFG); + writel(bits_per_char, uport->membase + SE_UART_TX_WORD_LEN); + writel(bits_per_char, uport->membase + SE_UART_RX_WORD_LEN); + writel(stop_bit_len, uport->membase + SE_UART_TX_STOP_BIT_LEN); + writel(ser_clk_cfg, uport->membase + GENI_SER_M_CLK_CFG); + writel(ser_clk_cfg, uport->membase + GENI_SER_S_CLK_CFG); out_restart_rx: qcom_geni_serial_start_rx(uport); } @@ -1193,13 +1126,13 @@ static int __init qcom_geni_serial_earlycon_setup(struct earlycon_device *dev, geni_se_init(&se, DEF_FIFO_DEPTH_WORDS / 2, DEF_FIFO_DEPTH_WORDS - 2); geni_se_select_mode(&se, GENI_SE_FIFO); - writel_relaxed(tx_trans_cfg, uport->membase + SE_UART_TX_TRANS_CFG); - writel_relaxed(tx_parity_cfg, uport->membase + SE_UART_TX_PARITY_CFG); - writel_relaxed(rx_trans_cfg, uport->membase + SE_UART_RX_TRANS_CFG); - writel_relaxed(rx_parity_cfg, uport->membase + SE_UART_RX_PARITY_CFG); - writel_relaxed(bits_per_char, uport->membase + SE_UART_TX_WORD_LEN); - writel_relaxed(bits_per_char, uport->membase + SE_UART_RX_WORD_LEN); - writel_relaxed(stop_bit_len, uport->membase + SE_UART_TX_STOP_BIT_LEN); + writel(tx_trans_cfg, uport->membase + SE_UART_TX_TRANS_CFG); + writel(tx_parity_cfg, uport->membase + SE_UART_TX_PARITY_CFG); + writel(rx_trans_cfg, uport->membase + SE_UART_RX_TRANS_CFG); + writel(rx_parity_cfg, uport->membase + SE_UART_RX_PARITY_CFG); + writel(bits_per_char, uport->membase + SE_UART_TX_WORD_LEN); + writel(bits_per_char, uport->membase + SE_UART_RX_WORD_LEN); + writel(stop_bit_len, uport->membase + SE_UART_TX_STOP_BIT_LEN); dev->con->write = qcom_geni_serial_earlycon_write; dev->con->setup = NULL; diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 9fc3559f80d9..83fd51607741 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -1694,6 +1694,42 @@ s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port) } #endif +static int s3c24xx_serial_enable_baudclk(struct s3c24xx_uart_port *ourport) +{ + struct device *dev = ourport->port.dev; + struct s3c24xx_uart_info *info = ourport->info; + char clk_name[MAX_CLK_NAME_LENGTH]; + unsigned int clk_sel; + struct clk *clk; + int clk_num; + int ret; + + clk_sel = ourport->cfg->clk_sel ? : info->def_clk_sel; + for (clk_num = 0; clk_num < info->num_clks; clk_num++) { + if (!(clk_sel & (1 << clk_num))) + continue; + + sprintf(clk_name, "clk_uart_baud%d", clk_num); + clk = clk_get(dev, clk_name); + if (IS_ERR(clk)) + continue; + + ret = clk_prepare_enable(clk); + if (ret) { + clk_put(clk); + continue; + } + + ourport->baudclk = clk; + ourport->baudclk_rate = clk_get_rate(clk); + s3c24xx_serial_setsource(&ourport->port, clk_num); + + return 0; + } + + return -EINVAL; +} + /* s3c24xx_serial_init_port * * initialise a single serial port from the platform device given @@ -1788,6 +1824,10 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, goto err; } + ret = s3c24xx_serial_enable_baudclk(ourport); + if (ret) + pr_warn("uart: failed to enable baudclk\n"); + /* Keep all interrupts masked and cleared */ if (s3c24xx_serial_has_interrupt_mask(port)) { wr_regl(port, S3C64XX_UINTM, 0xf); @@ -1901,6 +1941,8 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) * and keeps the clock enabled in this case. */ clk_disable_unprepare(ourport->clk); + if (!IS_ERR(ourport->baudclk)) + clk_disable_unprepare(ourport->baudclk); ret = s3c24xx_serial_cpufreq_register(ourport); if (ret < 0) diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 268098681856..635178cf3eed 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -1187,9 +1187,7 @@ static int sc16is7xx_probe(struct device *dev, return PTR_ERR(regmap); /* Alloc port structure */ - s = devm_kzalloc(dev, sizeof(*s) + - sizeof(struct sc16is7xx_one) * devtype->nr_uart, - GFP_KERNEL); + s = devm_kzalloc(dev, struct_size(s, p, devtype->nr_uart), GFP_KERNEL); if (!s) { dev_err(dev, "Error allocating port structure\n"); return -ENOMEM; diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 556f50aa1b58..351843f847c0 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2844,7 +2844,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) */ tty_dev = tty_port_register_device_attr_serdev(port, drv->tty_driver, uport->line, uport->dev, port, uport->tty_groups); - if (likely(!IS_ERR(tty_dev))) { + if (!IS_ERR(tty_dev)) { device_set_wakeup_capable(tty_dev, 1); } else { dev_err(uport->dev, "Cannot register tty device on line %d\n", diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 64bbeb7d7e0c..060fcd42b6d5 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1243,12 +1243,22 @@ static int sci_dma_rx_find_active(struct sci_port *s) return -1; } -static void sci_rx_dma_release(struct sci_port *s) +static void sci_dma_rx_chan_invalidate(struct sci_port *s) +{ + unsigned int i; + + s->chan_rx = NULL; + for (i = 0; i < ARRAY_SIZE(s->cookie_rx); i++) + s->cookie_rx[i] = -EINVAL; + s->active_rx = 0; +} + +static void sci_dma_rx_release(struct sci_port *s) { struct dma_chan *chan = s->chan_rx_saved; - s->chan_rx_saved = s->chan_rx = NULL; - s->cookie_rx[0] = s->cookie_rx[1] = -EINVAL; + s->chan_rx_saved = NULL; + sci_dma_rx_chan_invalidate(s); dmaengine_terminate_sync(chan); dma_free_coherent(chan->device->dev, s->buf_len_rx * 2, s->rx_buf[0], sg_dma_address(&s->sg_rx[0])); @@ -1264,6 +1274,20 @@ static void start_hrtimer_us(struct hrtimer *hrt, unsigned long usec) hrtimer_start(hrt, t, HRTIMER_MODE_REL); } +static void sci_dma_rx_reenable_irq(struct sci_port *s) +{ + struct uart_port *port = &s->port; + u16 scr; + + /* Direct new serial port interrupts back to CPU */ + scr = serial_port_in(port, SCSCR); + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + scr &= ~SCSCR_RDRQE; + enable_irq(s->irqs[SCIx_RXI_IRQ]); + } + serial_port_out(port, SCSCR, scr | SCSCR_RIE); +} + static void sci_dma_rx_complete(void *arg) { struct sci_port *s = arg; @@ -1313,12 +1337,13 @@ fail: dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n"); /* Switch to PIO */ spin_lock_irqsave(&port->lock, flags); - s->chan_rx = NULL; - sci_start_rx(port); + dmaengine_terminate_async(chan); + sci_dma_rx_chan_invalidate(s); + sci_dma_rx_reenable_irq(s); spin_unlock_irqrestore(&port->lock, flags); } -static void sci_tx_dma_release(struct sci_port *s) +static void sci_dma_tx_release(struct sci_port *s) { struct dma_chan *chan = s->chan_tx_saved; @@ -1331,7 +1356,7 @@ static void sci_tx_dma_release(struct sci_port *s) dma_release_channel(chan); } -static int sci_submit_rx(struct sci_port *s, bool port_lock_held) +static int sci_dma_rx_submit(struct sci_port *s, bool port_lock_held) { struct dma_chan *chan = s->chan_rx; struct uart_port *port = &s->port; @@ -1367,17 +1392,14 @@ fail: spin_lock_irqsave(&port->lock, flags); if (i) dmaengine_terminate_async(chan); - for (i = 0; i < 2; i++) - s->cookie_rx[i] = -EINVAL; - s->active_rx = 0; - s->chan_rx = NULL; + sci_dma_rx_chan_invalidate(s); sci_start_rx(port); if (!port_lock_held) spin_unlock_irqrestore(&port->lock, flags); return -EAGAIN; } -static void work_fn_tx(struct work_struct *work) +static void sci_dma_tx_work_fn(struct work_struct *work) { struct sci_port *s = container_of(work, struct sci_port, work_tx); struct dma_async_tx_descriptor *desc; @@ -1436,7 +1458,7 @@ switch_to_pio: return; } -static enum hrtimer_restart rx_timer_fn(struct hrtimer *t) +static enum hrtimer_restart sci_dma_rx_timer_fn(struct hrtimer *t) { struct sci_port *s = container_of(t, struct sci_port, rx_timer); struct dma_chan *chan = s->chan_rx; @@ -1446,7 +1468,6 @@ static enum hrtimer_restart rx_timer_fn(struct hrtimer *t) unsigned long flags; unsigned int read; int active, count; - u16 scr; dev_dbg(port->dev, "DMA Rx timed out\n"); @@ -1494,15 +1515,9 @@ static enum hrtimer_restart rx_timer_fn(struct hrtimer *t) } if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) - sci_submit_rx(s, true); + sci_dma_rx_submit(s, true); - /* Direct new serial port interrupts back to CPU */ - scr = serial_port_in(port, SCSCR); - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - scr &= ~SCSCR_RDRQE; - enable_irq(s->irqs[SCIx_RXI_IRQ]); - } - serial_port_out(port, SCSCR, scr | SCSCR_RIE); + sci_dma_rx_reenable_irq(s); spin_unlock_irqrestore(&port->lock, flags); @@ -1580,7 +1595,7 @@ static void sci_request_dma(struct uart_port *port) __func__, UART_XMIT_SIZE, port->state->xmit.buf, &s->tx_dma_addr); - INIT_WORK(&s->work_tx, work_fn_tx); + INIT_WORK(&s->work_tx, sci_dma_tx_work_fn); s->chan_tx_saved = s->chan_tx = chan; } } @@ -1615,12 +1630,12 @@ static void sci_request_dma(struct uart_port *port) } hrtimer_init(&s->rx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - s->rx_timer.function = rx_timer_fn; + s->rx_timer.function = sci_dma_rx_timer_fn; s->chan_rx_saved = s->chan_rx = chan; if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) - sci_submit_rx(s, false); + sci_dma_rx_submit(s, false); } } @@ -1629,9 +1644,9 @@ static void sci_free_dma(struct uart_port *port) struct sci_port *s = to_sci_port(port); if (s->chan_tx_saved) - sci_tx_dma_release(s); + sci_dma_tx_release(s); if (s->chan_rx_saved) - sci_rx_dma_release(s); + sci_dma_rx_release(s); } static void sci_flush_buffer(struct uart_port *port) @@ -1669,7 +1684,7 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr) disable_irq_nosync(irq); scr |= SCSCR_RDRQE; } else { - if (sci_submit_rx(s, false) < 0) + if (sci_dma_rx_submit(s, false) < 0) goto handle_pio; scr &= ~SCSCR_RIE; diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c index 4287ca305b6b..1891a45ac05d 100644 --- a/drivers/tty/serial/sprd_serial.c +++ b/drivers/tty/serial/sprd_serial.c @@ -371,7 +371,7 @@ static void sprd_set_termios(struct uart_port *port, /* ask the core to calculate the divisor for us */ baud = uart_get_baud_rate(port, termios, old, 0, SPRD_BAUD_IO_LIMIT); - quot = (unsigned int)((port->uartclk + baud / 2) / baud); + quot = port->uartclk / baud; /* set data length */ switch (termios->c_cflag & CSIZE) { diff --git a/drivers/tty/serial/tegra-tcu.c b/drivers/tty/serial/tegra-tcu.c new file mode 100644 index 000000000000..aaf8748a6147 --- /dev/null +++ b/drivers/tty/serial/tegra-tcu.c @@ -0,0 +1,298 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. + */ + +#include <linux/console.h> +#include <linux/mailbox_client.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/serial.h> +#include <linux/serial_core.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> + +#define TCU_MBOX_BYTE(i, x) ((x) << (i * 8)) +#define TCU_MBOX_BYTE_V(x, i) (((x) >> (i * 8)) & 0xff) +#define TCU_MBOX_NUM_BYTES(x) ((x) << 24) +#define TCU_MBOX_NUM_BYTES_V(x) (((x) >> 24) & 0x3) + +struct tegra_tcu { + struct uart_driver driver; +#if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE) + struct console console; +#endif + struct uart_port port; + + struct mbox_client tx_client, rx_client; + struct mbox_chan *tx, *rx; +}; + +static unsigned int tegra_tcu_uart_tx_empty(struct uart_port *port) +{ + return TIOCSER_TEMT; +} + +static void tegra_tcu_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +} + +static unsigned int tegra_tcu_uart_get_mctrl(struct uart_port *port) +{ + return 0; +} + +static void tegra_tcu_uart_stop_tx(struct uart_port *port) +{ +} + +static void tegra_tcu_write_one(struct tegra_tcu *tcu, u32 value, + unsigned int count) +{ + void *msg; + + value |= TCU_MBOX_NUM_BYTES(count); + msg = (void *)(unsigned long)value; + mbox_send_message(tcu->tx, msg); + mbox_flush(tcu->tx, 1000); +} + +static void tegra_tcu_write(struct tegra_tcu *tcu, const char *s, + unsigned int count) +{ + unsigned int written = 0, i = 0; + bool insert_nl = false; + u32 value = 0; + + while (i < count) { + if (insert_nl) { + value |= TCU_MBOX_BYTE(written++, '\n'); + insert_nl = false; + i++; + } else if (s[i] == '\n') { + value |= TCU_MBOX_BYTE(written++, '\r'); + insert_nl = true; + } else { + value |= TCU_MBOX_BYTE(written++, s[i++]); + } + + if (written == 3) { + tegra_tcu_write_one(tcu, value, 3); + value = written = 0; + } + } + + if (written) + tegra_tcu_write_one(tcu, value, written); +} + +static void tegra_tcu_uart_start_tx(struct uart_port *port) +{ + struct tegra_tcu *tcu = port->private_data; + struct circ_buf *xmit = &port->state->xmit; + unsigned long count; + + for (;;) { + count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + if (!count) + break; + + tegra_tcu_write(tcu, &xmit->buf[xmit->tail], count); + xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); + } + + uart_write_wakeup(port); +} + +static void tegra_tcu_uart_stop_rx(struct uart_port *port) +{ +} + +static void tegra_tcu_uart_break_ctl(struct uart_port *port, int ctl) +{ +} + +static int tegra_tcu_uart_startup(struct uart_port *port) +{ + return 0; +} + +static void tegra_tcu_uart_shutdown(struct uart_port *port) +{ +} + +static void tegra_tcu_uart_set_termios(struct uart_port *port, + struct ktermios *new, + struct ktermios *old) +{ +} + +static const struct uart_ops tegra_tcu_uart_ops = { + .tx_empty = tegra_tcu_uart_tx_empty, + .set_mctrl = tegra_tcu_uart_set_mctrl, + .get_mctrl = tegra_tcu_uart_get_mctrl, + .stop_tx = tegra_tcu_uart_stop_tx, + .start_tx = tegra_tcu_uart_start_tx, + .stop_rx = tegra_tcu_uart_stop_rx, + .break_ctl = tegra_tcu_uart_break_ctl, + .startup = tegra_tcu_uart_startup, + .shutdown = tegra_tcu_uart_shutdown, + .set_termios = tegra_tcu_uart_set_termios, +}; + +#if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE) +static void tegra_tcu_console_write(struct console *cons, const char *s, + unsigned int count) +{ + struct tegra_tcu *tcu = container_of(cons, struct tegra_tcu, console); + + tegra_tcu_write(tcu, s, count); +} + +static int tegra_tcu_console_setup(struct console *cons, char *options) +{ + return 0; +} +#endif + +static void tegra_tcu_receive(struct mbox_client *cl, void *msg) +{ + struct tegra_tcu *tcu = container_of(cl, struct tegra_tcu, rx_client); + struct tty_port *port = &tcu->port.state->port; + u32 value = (u32)(unsigned long)msg; + unsigned int num_bytes, i; + + num_bytes = TCU_MBOX_NUM_BYTES_V(value); + + for (i = 0; i < num_bytes; i++) + tty_insert_flip_char(port, TCU_MBOX_BYTE_V(value, i), + TTY_NORMAL); + + tty_flip_buffer_push(port); +} + +static int tegra_tcu_probe(struct platform_device *pdev) +{ + struct uart_port *port; + struct tegra_tcu *tcu; + int err; + + tcu = devm_kzalloc(&pdev->dev, sizeof(*tcu), GFP_KERNEL); + if (!tcu) + return -ENOMEM; + + tcu->tx_client.dev = &pdev->dev; + tcu->rx_client.dev = &pdev->dev; + tcu->rx_client.rx_callback = tegra_tcu_receive; + + tcu->tx = mbox_request_channel_byname(&tcu->tx_client, "tx"); + if (IS_ERR(tcu->tx)) { + err = PTR_ERR(tcu->tx); + dev_err(&pdev->dev, "failed to get tx mailbox: %d\n", err); + return err; + } + + tcu->rx = mbox_request_channel_byname(&tcu->rx_client, "rx"); + if (IS_ERR(tcu->rx)) { + err = PTR_ERR(tcu->rx); + dev_err(&pdev->dev, "failed to get rx mailbox: %d\n", err); + goto free_tx; + } + +#if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE) + /* setup the console */ + strcpy(tcu->console.name, "ttyTCU"); + tcu->console.device = uart_console_device; + tcu->console.flags = CON_PRINTBUFFER | CON_ANYTIME; + tcu->console.index = -1; + tcu->console.write = tegra_tcu_console_write; + tcu->console.setup = tegra_tcu_console_setup; + tcu->console.data = &tcu->driver; +#endif + + /* setup the driver */ + tcu->driver.owner = THIS_MODULE; + tcu->driver.driver_name = "tegra-tcu"; + tcu->driver.dev_name = "ttyTCU"; +#if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE) + tcu->driver.cons = &tcu->console; +#endif + tcu->driver.nr = 1; + + err = uart_register_driver(&tcu->driver); + if (err) { + dev_err(&pdev->dev, "failed to register UART driver: %d\n", + err); + goto free_rx; + } + + /* setup the port */ + port = &tcu->port; + spin_lock_init(&port->lock); + port->dev = &pdev->dev; + port->type = PORT_TEGRA_TCU; + port->ops = &tegra_tcu_uart_ops; + port->fifosize = 1; + port->iotype = UPIO_MEM; + port->flags = UPF_BOOT_AUTOCONF; + port->private_data = tcu; + + err = uart_add_one_port(&tcu->driver, port); + if (err) { + dev_err(&pdev->dev, "failed to add UART port: %d\n", err); + goto unregister_uart; + } + + platform_set_drvdata(pdev, tcu); +#if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE) + register_console(&tcu->console); +#endif + + return 0; + +unregister_uart: + uart_unregister_driver(&tcu->driver); +free_rx: + mbox_free_channel(tcu->rx); +free_tx: + mbox_free_channel(tcu->tx); + + return err; +} + +static int tegra_tcu_remove(struct platform_device *pdev) +{ + struct tegra_tcu *tcu = platform_get_drvdata(pdev); + +#if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE) + unregister_console(&tcu->console); +#endif + uart_remove_one_port(&tcu->driver, &tcu->port); + uart_unregister_driver(&tcu->driver); + mbox_free_channel(tcu->rx); + mbox_free_channel(tcu->tx); + + return 0; +} + +static const struct of_device_id tegra_tcu_match[] = { + { .compatible = "nvidia,tegra194-tcu" }, + { } +}; + +static struct platform_driver tegra_tcu_driver = { + .driver = { + .name = "tegra-tcu", + .of_match_table = tegra_tcu_match, + }, + .probe = tegra_tcu_probe, + .remove = tegra_tcu_remove, +}; +module_platform_driver(tegra_tcu_driver); + +MODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("NVIDIA Tegra Combined UART driver"); diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index 094f2958cb2b..74089f5e5b53 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -364,7 +364,13 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id) cdns_uart_handle_tx(dev_id); isrstatus &= ~CDNS_UART_IXR_TXEMPTY; } - if (isrstatus & CDNS_UART_IXR_RXMASK) + + /* + * Skip RX processing if RX is disabled as RXEMPTY will never be set + * as read bytes will not be removed from the FIFO. + */ + if (isrstatus & CDNS_UART_IXR_RXMASK && + !(readl(port->membase + CDNS_UART_CR) & CDNS_UART_CR_RX_DIS)) cdns_uart_handle_rx(dev_id, isrstatus); spin_unlock(&port->lock); @@ -1547,27 +1553,33 @@ static int cdns_uart_probe(struct platform_device *pdev) } cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "pclk"); + if (PTR_ERR(cdns_uart_data->pclk) == -EPROBE_DEFER) { + rc = PTR_ERR(cdns_uart_data->pclk); + goto err_out_unregister_driver; + } + if (IS_ERR(cdns_uart_data->pclk)) { cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "aper_clk"); - if (!IS_ERR(cdns_uart_data->pclk)) - dev_err(&pdev->dev, "clock name 'aper_clk' is deprecated.\n"); + if (IS_ERR(cdns_uart_data->pclk)) { + rc = PTR_ERR(cdns_uart_data->pclk); + goto err_out_unregister_driver; + } + dev_err(&pdev->dev, "clock name 'aper_clk' is deprecated.\n"); } - if (IS_ERR(cdns_uart_data->pclk)) { - dev_err(&pdev->dev, "pclk clock not found.\n"); - rc = PTR_ERR(cdns_uart_data->pclk); + + cdns_uart_data->uartclk = devm_clk_get(&pdev->dev, "uart_clk"); + if (PTR_ERR(cdns_uart_data->uartclk) == -EPROBE_DEFER) { + rc = PTR_ERR(cdns_uart_data->uartclk); goto err_out_unregister_driver; } - cdns_uart_data->uartclk = devm_clk_get(&pdev->dev, "uart_clk"); if (IS_ERR(cdns_uart_data->uartclk)) { cdns_uart_data->uartclk = devm_clk_get(&pdev->dev, "ref_clk"); - if (!IS_ERR(cdns_uart_data->uartclk)) - dev_err(&pdev->dev, "clock name 'ref_clk' is deprecated.\n"); - } - if (IS_ERR(cdns_uart_data->uartclk)) { - dev_err(&pdev->dev, "uart_clk clock not found.\n"); - rc = PTR_ERR(cdns_uart_data->uartclk); - goto err_out_unregister_driver; + if (IS_ERR(cdns_uart_data->uartclk)) { + rc = PTR_ERR(cdns_uart_data->uartclk); + goto err_out_unregister_driver; + } + dev_err(&pdev->dev, "clock name 'ref_clk' is deprecated.\n"); } rc = clk_prepare_enable(cdns_uart_data->pclk); diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index d55c858d6058..84f26e43b229 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -4325,41 +4325,6 @@ static int mgsl_init_tty(void) return 0; } -/* enumerate user specified ISA adapters - */ -static void mgsl_enum_isa_devices(void) -{ - struct mgsl_struct *info; - int i; - - /* Check for user specified ISA devices */ - - for (i=0 ;(i < MAX_ISA_DEVICES) && io[i] && irq[i]; i++){ - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk("ISA device specified io=%04X,irq=%d,dma=%d\n", - io[i], irq[i], dma[i] ); - - info = mgsl_allocate_device(); - if ( !info ) { - /* error allocating device instance data */ - if ( debug_level >= DEBUG_LEVEL_ERROR ) - printk( "can't allocate device instance data.\n"); - continue; - } - - /* Copy user configuration info to device instance data */ - info->io_base = (unsigned int)io[i]; - info->irq_level = (unsigned int)irq[i]; - info->irq_level = irq_canonicalize(info->irq_level); - info->dma_level = (unsigned int)dma[i]; - info->bus_type = MGSL_BUS_TYPE_ISA; - info->io_addr_size = 16; - info->irq_flags = 0; - - mgsl_add_device( info ); - } -} - static void synclink_cleanup(void) { int rc; @@ -4403,7 +4368,6 @@ static int __init synclink_init(void) printk("%s %s\n", driver_name, driver_version); - mgsl_enum_isa_devices(); if ((rc = pci_register_driver(&synclink_pci_driver)) < 0) printk("%s:failed to register PCI driver, error=%d\n",__FILE__,rc); else @@ -5025,12 +4989,6 @@ static void usc_set_sdlc_mode( struct mgsl_struct *info ) info->mbre_bit = BIT8; outw( BIT8, info->io_base ); /* set Master Bus Enable (DCAR) */ - if (info->bus_type == MGSL_BUS_TYPE_ISA) { - /* Enable DMAEN (Port 7, Bit 14) */ - /* This connects the DMA request signal to the ISA bus */ - usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT15) & ~BIT14)); - } - /* DMA Control Register (DCR) * * <15..14> 10 Priority mode = Alternating Tx/Rx @@ -6007,12 +5965,6 @@ static void usc_set_async_mode( struct mgsl_struct *info ) usc_EnableMasterIrqBit( info ); - if (info->bus_type == MGSL_BUS_TYPE_ISA) { - /* Enable INTEN (Port 6, Bit12) */ - /* This connects the IRQ request signal to the ISA bus */ - usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT13) & ~BIT12)); - } - if (info->params.loopback) { info->loopback_bits = 0x300; outw(0x0300, info->io_base + CCAR); @@ -6107,12 +6059,6 @@ static void usc_set_sync_mode( struct mgsl_struct *info ) usc_loopback_frame( info ); usc_set_sdlc_mode( info ); - if (info->bus_type == MGSL_BUS_TYPE_ISA) { - /* Enable INTEN (Port 6, Bit12) */ - /* This connects the IRQ request signal to the ISA bus */ - usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT13) & ~BIT12)); - } - usc_enable_aux_clock(info, info->params.clock_speed); if (info->params.loopback) diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 1f03078ec352..fa0ce7dd9e24 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -539,7 +539,6 @@ void __handle_sysrq(int key, bool check_mask) */ orig_log_level = console_loglevel; console_loglevel = CONSOLE_LOGLEVEL_DEFAULT; - pr_info("SysRq : "); op_p = __sysrq_get_key_op(key); if (op_p) { @@ -548,14 +547,15 @@ void __handle_sysrq(int key, bool check_mask) * should not) and is the invoked operation enabled? */ if (!check_mask || sysrq_on_mask(op_p->enable_mask)) { - pr_cont("%s\n", op_p->action_msg); + pr_info("%s\n", op_p->action_msg); console_loglevel = orig_log_level; op_p->handler(key); } else { - pr_cont("This sysrq operation is disabled.\n"); + pr_info("This sysrq operation is disabled.\n"); + console_loglevel = orig_log_level; } } else { - pr_cont("HELP : "); + pr_info("HELP : "); /* Only print the help msg once per handler */ for (i = 0; i < ARRAY_SIZE(sysrq_key_table); i++) { if (sysrq_key_table[i]) { diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 77070c2d1240..ec145a59f199 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -26,7 +26,7 @@ * Byte threshold to limit memory consumption for flip buffers. * The actual memory limit is > 2x this amount. */ -#define TTYB_DEFAULT_MEM_LIMIT 65536 +#define TTYB_DEFAULT_MEM_LIMIT (640 * 1024UL) /* * We default to dicing tty buffer allocations to this many characters diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 21ffcce16927..5fa250157025 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -513,6 +513,8 @@ static const struct file_operations hung_up_tty_fops = { static DEFINE_SPINLOCK(redirect_lock); static struct file *redirect; +extern void tty_sysctl_init(void); + /** * tty_wakeup - request more data * @tty: terminal @@ -3483,6 +3485,7 @@ void console_sysfs_notify(void) */ int __init tty_init(void) { + tty_sysctl_init(); cdev_init(&tty_cdev, &tty_fops); if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0) diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 45eda69b150c..e38f104db174 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -156,6 +156,13 @@ static void put_ldops(struct tty_ldisc_ops *ldops) * takes tty_ldiscs_lock to guard against ldisc races */ +#if defined(CONFIG_LDISC_AUTOLOAD) + #define INITIAL_AUTOLOAD_STATE 1 +#else + #define INITIAL_AUTOLOAD_STATE 0 +#endif +static int tty_ldisc_autoload = INITIAL_AUTOLOAD_STATE; + static struct tty_ldisc *tty_ldisc_get(struct tty_struct *tty, int disc) { struct tty_ldisc *ld; @@ -170,6 +177,8 @@ static struct tty_ldisc *tty_ldisc_get(struct tty_struct *tty, int disc) */ ldops = get_ldops(disc); if (IS_ERR(ldops)) { + if (!capable(CAP_SYS_MODULE) && !tty_ldisc_autoload) + return ERR_PTR(-EPERM); request_module("tty-ldisc-%d", disc); ldops = get_ldops(disc); if (IS_ERR(ldops)) @@ -845,3 +854,41 @@ void tty_ldisc_deinit(struct tty_struct *tty) tty_ldisc_put(tty->ldisc); tty->ldisc = NULL; } + +static int zero; +static int one = 1; +static struct ctl_table tty_table[] = { + { + .procname = "ldisc_autoload", + .data = &tty_ldisc_autoload, + .maxlen = sizeof(tty_ldisc_autoload), + .mode = 0644, + .proc_handler = proc_dointvec, + .extra1 = &zero, + .extra2 = &one, + }, + { } +}; + +static struct ctl_table tty_dir_table[] = { + { + .procname = "tty", + .mode = 0555, + .child = tty_table, + }, + { } +}; + +static struct ctl_table tty_root_table[] = { + { + .procname = "dev", + .mode = 0555, + .child = tty_dir_table, + }, + { } +}; + +void tty_sysctl_init(void) +{ + register_sysctl_table(tty_root_table); +} diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c index 2384ea85ffaf..160f46115aaa 100644 --- a/drivers/tty/vt/vc_screen.c +++ b/drivers/tty/vt/vc_screen.c @@ -80,7 +80,7 @@ struct vcs_poll_data { struct notifier_block notifier; unsigned int cons_num; - bool seen_last_update; + int event; wait_queue_head_t waitq; struct fasync_struct *fasync; }; @@ -93,9 +93,18 @@ vcs_notifier(struct notifier_block *nb, unsigned long code, void *_param) struct vcs_poll_data *poll = container_of(nb, struct vcs_poll_data, notifier); int currcons = poll->cons_num; - - if (code != VT_UPDATE) + int fa_band; + + switch (code) { + case VT_UPDATE: + fa_band = POLL_PRI; + break; + case VT_DEALLOCATE: + fa_band = POLL_HUP; + break; + default: return NOTIFY_DONE; + } if (currcons == 0) currcons = fg_console; @@ -104,9 +113,9 @@ vcs_notifier(struct notifier_block *nb, unsigned long code, void *_param) if (currcons != vc->vc_num) return NOTIFY_DONE; - poll->seen_last_update = false; + poll->event = code; wake_up_interruptible(&poll->waitq); - kill_fasync(&poll->fasync, SIGIO, POLL_IN); + kill_fasync(&poll->fasync, SIGIO, fa_band); return NOTIFY_OK; } @@ -131,6 +140,15 @@ vcs_poll_data_get(struct file *file) poll->cons_num = console(file_inode(file)); init_waitqueue_head(&poll->waitq); poll->notifier.notifier_call = vcs_notifier; + /* + * In order not to lose any update event, we must pretend one might + * have occurred before we have a chance to register our notifier. + * This is also how user space has come to detect which kernels + * support POLLPRI on /dev/vcs* devices i.e. using poll() with + * POLLPRI and a zero timeout. + */ + poll->event = VT_UPDATE; + if (register_vt_notifier(&poll->notifier) != 0) { kfree(poll); return NULL; @@ -261,7 +279,7 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) poll = file->private_data; if (count && poll) - poll->seen_last_update = true; + poll->event = 0; read = 0; ret = 0; while (count) { @@ -335,8 +353,9 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) if (p < HEADER_SIZE) { size_t tmp_count; - con_buf0[0] = (char)vc->vc_rows; - con_buf0[1] = (char)vc->vc_cols; + /* clamp header values if they don't fit */ + con_buf0[0] = min(vc->vc_rows, 0xFFu); + con_buf0[1] = min(vc->vc_cols, 0xFFu); getconsxy(vc, con_buf0 + 2); con_buf_start += p; @@ -615,12 +634,21 @@ static __poll_t vcs_poll(struct file *file, poll_table *wait) { struct vcs_poll_data *poll = vcs_poll_data_get(file); - __poll_t ret = DEFAULT_POLLMASK|EPOLLERR|EPOLLPRI; + __poll_t ret = DEFAULT_POLLMASK|EPOLLERR; if (poll) { poll_wait(file, &poll->waitq, wait); - if (poll->seen_last_update) + switch (poll->event) { + case VT_UPDATE: + ret = DEFAULT_POLLMASK|EPOLLPRI; + break; + case VT_DEALLOCATE: + ret = DEFAULT_POLLMASK|EPOLLHUP|EPOLLERR; + break; + case 0: ret = DEFAULT_POLLMASK; + break; + } } return ret; } diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index bba75560d11e..d34984aa646d 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -935,8 +935,11 @@ static void flush_scrollback(struct vc_data *vc) { WARN_CONSOLE_UNLOCKED(); + set_origin(vc); if (vc->vc_sw->con_flush_scrollback) vc->vc_sw->con_flush_scrollback(vc); + else + vc->vc_sw->con_switch(vc); } /* @@ -1342,6 +1345,8 @@ struct vc_data *vc_deallocate(unsigned int currcons) * VT102 emulator */ +enum { EPecma = 0, EPdec, EPeq, EPgt, EPlt}; + #define set_kbd(vc, x) vt_set_kbd_mode_bit((vc)->vc_num, (x)) #define clr_kbd(vc, x) vt_clr_kbd_mode_bit((vc)->vc_num, (x)) #define is_kbd(vc, x) vt_get_kbd_mode_bit((vc)->vc_num, (x)) @@ -1503,8 +1508,10 @@ static void csi_J(struct vc_data *vc, int vpar) count = ((vc->vc_pos - vc->vc_origin) >> 1) + 1; start = (unsigned short *)vc->vc_origin; break; + case 3: /* include scrollback */ + flush_scrollback(vc); + /* fallthrough */ case 2: /* erase whole display */ - case 3: /* (and scrollback buffer later) */ vc_uniscr_clear_lines(vc, 0, vc->vc_rows); count = vc->vc_cols * vc->vc_rows; start = (unsigned short *)vc->vc_origin; @@ -1513,13 +1520,7 @@ static void csi_J(struct vc_data *vc, int vpar) return; } scr_memsetw(start, vc->vc_video_erase_char, 2 * count); - if (vpar == 3) { - set_origin(vc); - flush_scrollback(vc); - if (con_is_visible(vc)) - update_screen(vc); - } else if (con_should_update(vc)) - do_update_region(vc, (unsigned long) start, count); + update_region(vc, (unsigned long) start, count); vc->vc_need_wrap = 0; } @@ -1628,9 +1629,9 @@ static void rgb_background(struct vc_data *vc, const struct rgb *c) /* * ITU T.416 Higher colour modes. They break the usual properties of SGR codes - * and thus need to be detected and ignored by hand. Strictly speaking, that - * standard also wants : rather than ; as separators, contrary to ECMA-48, but - * no one produces such codes and almost no one accepts them. + * and thus need to be detected and ignored by hand. That standard also + * wants : rather than ; as separators but sequences containing : are currently + * completely ignored by the parser. * * Subcommands 3 (CMY) and 4 (CMYK) are so insane there's no point in * supporting them. @@ -1815,7 +1816,7 @@ static void set_mode(struct vc_data *vc, int on_off) int i; for (i = 0; i <= vc->vc_npar; i++) - if (vc->vc_ques) { + if (vc->vc_priv == EPdec) { switch(vc->vc_par[i]) { /* DEC private modes set/reset */ case 1: /* Cursor keys send ^[Ox/^[[x */ if (on_off) @@ -2022,7 +2023,7 @@ static void restore_cur(struct vc_data *vc) } enum { ESnormal, ESesc, ESsquare, ESgetpars, ESfunckey, - EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd, + EShash, ESsetG0, ESsetG1, ESpercent, EScsiignore, ESnonstd, ESpalette, ESosc }; /* console_lock is held (except via vc_init()) */ @@ -2031,7 +2032,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear) vc->vc_top = 0; vc->vc_bottom = vc->vc_rows; vc->vc_state = ESnormal; - vc->vc_ques = 0; + vc->vc_priv = EPecma; vc->vc_translate = set_translate(LAT1_MAP, vc); vc->vc_G0_charset = LAT1_MAP; vc->vc_G1_charset = GRAF_MAP; @@ -2112,6 +2113,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) lf(vc); if (!is_kbd(vc, lnm)) return; + /* fall through */ case 13: cr(vc); return; @@ -2234,9 +2236,22 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) vc->vc_state=ESfunckey; return; } - vc->vc_ques = (c == '?'); - if (vc->vc_ques) + switch (c) { + case '?': + vc->vc_priv = EPdec; + return; + case '>': + vc->vc_priv = EPgt; + return; + case '=': + vc->vc_priv = EPeq; return; + case '<': + vc->vc_priv = EPlt; + return; + } + vc->vc_priv = EPecma; + /* fall through */ case ESgetpars: if (c == ';' && vc->vc_npar < NPAR - 1) { vc->vc_npar++; @@ -2246,16 +2261,22 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) vc->vc_par[vc->vc_npar] += c - '0'; return; } + if (c >= 0x20 && c <= 0x3f) { /* 0x2x, 0x3a and 0x3c - 0x3f */ + vc->vc_state = EScsiignore; + return; + } vc->vc_state = ESnormal; switch(c) { case 'h': - set_mode(vc, 1); + if (vc->vc_priv <= EPdec) + set_mode(vc, 1); return; case 'l': - set_mode(vc, 0); + if (vc->vc_priv <= EPdec) + set_mode(vc, 0); return; case 'c': - if (vc->vc_ques) { + if (vc->vc_priv == EPdec) { if (vc->vc_par[0]) vc->vc_cursor_type = vc->vc_par[0] | (vc->vc_par[1] << 8) | (vc->vc_par[2] << 16); else @@ -2264,7 +2285,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) } break; case 'm': - if (vc->vc_ques) { + if (vc->vc_priv == EPdec) { clear_selection(); if (vc->vc_par[0]) vc->vc_complement_mask = vc->vc_par[0] << 8 | vc->vc_par[1]; @@ -2274,7 +2295,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) } break; case 'n': - if (!vc->vc_ques) { + if (vc->vc_priv == EPecma) { if (vc->vc_par[0] == 5) status_report(tty); else if (vc->vc_par[0] == 6) @@ -2282,8 +2303,8 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) } return; } - if (vc->vc_ques) { - vc->vc_ques = 0; + if (vc->vc_priv != EPecma) { + vc->vc_priv = EPecma; return; } switch(c) { @@ -2406,6 +2427,11 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) return; } return; + case EScsiignore: + if (c >= 20 && c <= 0x3f) + return; + vc->vc_state = ESnormal; + return; case ESpercent: vc->vc_state = ESnormal; switch (c) { @@ -4591,8 +4617,9 @@ EXPORT_SYMBOL_GPL(screen_pos); void getconsxy(struct vc_data *vc, unsigned char *p) { - p[0] = vc->vc_x; - p[1] = vc->vc_y; + /* clamp values if they don't fit */ + p[0] = min(vc->vc_x, 0xFFu); + p[1] = min(vc->vc_y, 0xFFu); } void putconsxy(struct vc_data *vc, unsigned char *p) diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h index ab137f97ecbd..ed798e114663 100644 --- a/include/linux/console_struct.h +++ b/include/linux/console_struct.h @@ -119,7 +119,7 @@ struct vc_data { unsigned int vc_s_blink : 1; unsigned int vc_s_reverse : 1; /* misc */ - unsigned int vc_ques : 1; + unsigned int vc_priv : 3; unsigned int vc_need_wrap : 1; unsigned int vc_can_do_color : 1; unsigned int vc_report_mouse : 2; diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h index df4a7534e239..6009ee2c2e99 100644 --- a/include/uapi/linux/serial_core.h +++ b/include/uapi/linux/serial_core.h @@ -79,6 +79,9 @@ /* Nuvoton UART */ #define PORT_NPCM 40 +/* NVIDIA Tegra Combined UART */ +#define PORT_TEGRA_TCU 41 + /* Intel EG20 */ #define PORT_PCH_8LINE 44 #define PORT_PCH_2LINE 45 |