TTY/Serial driver updates for 6.3-rc1

Here is the big set of serial and tty driver updates for 6.3-rc1.
 
 Once again, Jiri and Ilpo have done a number of core vt and tty/serial
 layer cleanups that were much needed and appreciated.  Other than that,
 it's just a bunch of little tty/serial driver updates:
   - qcom-geni-serial driver updates
   - liteuart driver updates
   - hvcs driver cleanups
   - n_gsm updates and additions for new features
   - more 8250 device support added
   - fpga/dfl update and additions
   - imx serial driver updates
   - fsl_lpuart updates
   - other tiny fixes and updates for serial drivers
 
 All of these have been in linux-next for a while with no reported
 problems.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCY/itAw8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ykJbQCfWv/J4ZElO108iHBU5mJCDagUDBgAnAtLLN6A
 SEAnnokGCDtA/BNIXeES
 =luRi
 -----END PGP SIGNATURE-----

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

Pull tty / serial driver updates from Greg KH:
 "Here is the big set of serial and tty driver updates for 6.3-rc1.

  Once again, Jiri and Ilpo have done a number of core vt and tty/serial
  layer cleanups that were much needed and appreciated. Other than that,
  it's just a bunch of little tty/serial driver updates:

   - qcom-geni-serial driver updates

   - liteuart driver updates

   - hvcs driver cleanups

   - n_gsm updates and additions for new features

   - more 8250 device support added

   - fpga/dfl update and additions

   - imx serial driver updates

   - fsl_lpuart updates

   - other tiny fixes and updates for serial drivers

  All of these have been in linux-next for a while with no reported
  problems"

* tag 'tty-6.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (143 commits)
  tty: n_gsm: add keep alive support
  serial: imx: remove a redundant check
  dt-bindings: serial: snps-dw-apb-uart: add dma & dma-names properties
  soc: qcom: geni-se: Move qcom-geni-se.h to linux/soc/qcom/geni-se.h
  tty: n_gsm: add TIOCMIWAIT support
  tty: n_gsm: add RING/CD control support
  tty: n_gsm: mark unusable ioctl structure fields accordingly
  serial: imx: get rid of registers shadowing
  serial: imx: refine local variables in rxint()
  serial: imx: stop using USR2 in FIFO reading loop
  serial: imx: remove redundant USR2 read from FIFO reading loop
  serial: imx: do not break from FIFO reading loop prematurely
  serial: imx: do not sysrq broken chars
  serial: imx: work-around for hardware RX flood
  serial: imx: factor-out common code to imx_uart_soft_reset()
  serial: 8250_pci1xxxx: Add power management functions to quad-uart driver
  serial: 8250_pci1xxxx: Add RS485 support to quad-uart driver
  serial: 8250_pci1xxxx: Add driver for quad-uart support
  serial: 8250_pci: Add serial8250_pci_setup_port definition in 8250_pcilib.c
  tty: pcn_uart: fix memory leak with using debugfs_lookup()
  ...
This commit is contained in:
Linus Torvalds 2023-02-24 12:17:14 -08:00
commit 17cd4d6f05
104 changed files with 2927 additions and 1302 deletions

View File

@ -1172,10 +1172,10 @@
specified, the serial port must already be setup and
configured.
uart[8250],io,<addr>[,options]
uart[8250],mmio,<addr>[,options]
uart[8250],mmio32,<addr>[,options]
uart[8250],mmio32be,<addr>[,options]
uart[8250],io,<addr>[,options[,uartclk]]
uart[8250],mmio,<addr>[,options[,uartclk]]
uart[8250],mmio32,<addr>[,options[,uartclk]]
uart[8250],mmio32be,<addr>[,options[,uartclk]]
uart[8250],0x<addr>[,options]
Start an early, polled-mode console on the 8250/16550
UART at the specified I/O port or MMIO address.
@ -1184,7 +1184,9 @@
If none of [io|mmio|mmio32|mmio32be], <addr> is assumed
to be equivalent to 'mmio'. 'options' are specified
in the same format described for "console=ttyS<n>"; if
unspecified, the h/w is not initialized.
unspecified, the h/w is not initialized. 'uartclk' is
the uart clock frequency; if unspecified, it is set
to 'BASE_BAUD' * 16.
pl011,<addr>
pl011,mmio32,<addr>

View File

@ -62,7 +62,6 @@ properties:
- const: mrvl,pxa-uart
- const: nuvoton,wpcm450-uart
- const: nuvoton,npcm750-uart
- const: nuvoton,npcm845-uart
- const: nvidia,tegra20-uart
- const: nxp,lpc3220-uart
- items:
@ -92,6 +91,10 @@ properties:
- enum:
- ns16550 # Deprecated, unless the FIFO really is broken
- ns16550a
- items:
- enum:
- nuvoton,npcm845-uart
- const: nuvoton,npcm750-uart
- items:
- enum:
- ralink,mt7620a-uart
@ -200,12 +203,13 @@ properties:
deprecated: true
aspeed,lpc-io-reg:
$ref: '/schemas/types.yaml#/definitions/uint32'
$ref: /schemas/types.yaml#/definitions/uint32-array
maxItems: 1
description: |
The VUART LPC address. Only applicable to aspeed,ast2500-vuart.
aspeed,lpc-interrupts:
$ref: "/schemas/types.yaml#/definitions/uint32-array"
$ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 2
maxItems: 2
description: |

View File

@ -70,11 +70,6 @@ properties:
dsr-gpios: true
rng-gpios: true
dcd-gpios: true
rs485-rts-delay: true
rs485-rts-active-low: true
rs485-rx-during-tx: true
rs485-rts-active-high: true
linux,rs485-enabled-at-boot-time: true
rts-gpio: true
power-domains: true
clock-frequency: true
@ -109,12 +104,12 @@ else:
examples:
- |
serial@49042000 {
compatible = "ti,omap3-uart";
reg = <0x49042000 0x400>;
interrupts = <80>;
dmas = <&sdma 81 &sdma 82>;
dma-names = "tx", "rx";
ti,hwmods = "uart4";
clock-frequency = <48000000>;
};
serial@49042000 {
compatible = "ti,omap3-uart";
reg = <0x49042000 0x400>;
interrupts = <80>;
dmas = <&sdma 81 &sdma 82>;
dma-names = "tx", "rx";
ti,hwmods = "uart4";
clock-frequency = <48000000>;
};

View File

@ -19,6 +19,9 @@ description: |
is active since power-on and does not need any clock gating and is usable
as very early serial console.
allOf:
- $ref: serial.yaml#
properties:
compatible:
oneOf:
@ -69,14 +72,14 @@ required:
- clocks
- clock-names
additionalProperties: false
unevaluatedProperties: false
examples:
- |
serial@84c0 {
compatible = "amlogic,meson-gx-uart";
reg = <0x84c0 0x14>;
interrupts = <26>;
clocks = <&xtal>, <&pclk>, <&xtal>;
clock-names = "xtal", "pclk", "baud";
compatible = "amlogic,meson-gx-uart";
reg = <0x84c0 0x14>;
interrupts = <26>;
clocks = <&xtal>, <&pclk>, <&xtal>;
clock-names = "xtal", "pclk", "baud";
};

View File

@ -9,9 +9,6 @@ title: Cadence UART Controller
maintainers:
- Michal Simek <michal.simek@xilinx.com>
allOf:
- $ref: /schemas/serial.yaml#
properties:
compatible:
oneOf:
@ -46,6 +43,9 @@ properties:
port does not use this pin.
type: boolean
power-domains:
maxItems: 1
required:
- compatible
- reg
@ -53,14 +53,25 @@ required:
- clocks
- clock-names
allOf:
- $ref: serial.yaml#
- if:
properties:
compatible:
contains:
const: cdns,uart-r1p8
then:
properties:
power-domains: false
unevaluatedProperties: false
examples:
- |
uart0: serial@e0000000 {
compatible = "xlnx,xuartps", "cdns,uart-r1p8";
clocks = <&clkc 23>, <&clkc 40>;
clock-names = "uart_clk", "pclk";
reg = <0xE0000000 0x1000>;
interrupts = <0 27 4>;
compatible = "xlnx,xuartps", "cdns,uart-r1p8";
clocks = <&clkc 23>, <&clkc 40>;
clock-names = "uart_clk", "pclk";
reg = <0xe0000000 0x1000>;
interrupts = <0 27 4>;
};

View File

@ -16,7 +16,7 @@ maintainers:
- Chester Lin <clin@suse.com>
allOf:
- $ref: "serial.yaml"
- $ref: serial.yaml#
properties:
compatible:

View File

@ -10,8 +10,8 @@ maintainers:
- Fabio Estevam <festevam@gmail.com>
allOf:
- $ref: "serial.yaml"
- $ref: "rs485.yaml"
- $ref: serial.yaml#
- $ref: rs485.yaml#
properties:
compatible:
@ -83,13 +83,6 @@ properties:
are sensible for most use cases. If you need low latency processing on
slow connections this needs to be configured appropriately.
uart-has-rtscts: true
rs485-rts-delay: true
rs485-rts-active-low: true
rs485-rx-during-tx: true
linux,rs485-enabled-at-boot-time: true
required:
- compatible
- reg

View File

@ -10,7 +10,8 @@ maintainers:
- Fugang Duan <fugang.duan@nxp.com>
allOf:
- $ref: "rs485.yaml"
- $ref: rs485.yaml#
- $ref: serial.yaml#
properties:
compatible:
@ -64,9 +65,6 @@ properties:
- const: rx
- const: tx
rs485-rts-active-low: true
linux,rs485-enabled-at-boot-time: true
required:
- compatible
- reg

View File

@ -10,7 +10,7 @@ maintainers:
- Fabio Estevam <festevam@gmail.com>
allOf:
- $ref: "serial.yaml"
- $ref: serial.yaml#
properties:
compatible:

View File

@ -10,6 +10,7 @@ maintainers:
- Rob Herring <robh@kernel.org>
allOf:
- $ref: /schemas/arm/primecell.yaml#
- $ref: serial.yaml#
# Need a custom select here or 'arm,primecell' will match on lots of nodes

View File

@ -1,25 +0,0 @@
* MSM Serial UART
The MSM serial UART hardware is designed for low-speed use cases where a
dma-engine isn't needed. From a software perspective it's mostly compatible
with the MSM serial UARTDM except that it only supports reading and writing one
character at a time.
Required properties:
- compatible: Should contain "qcom,msm-uart"
- reg: Should contain UART register location and length.
- interrupts: Should contain UART interrupt.
- clocks: Should contain the core clock.
- clock-names: Should be "core".
Example:
A uart device at 0xa9c00000 with interrupt 11.
serial@a9c00000 {
compatible = "qcom,msm-uart";
reg = <0xa9c00000 0x1000>;
interrupts = <11>;
clocks = <&uart_cxc>;
clock-names = "core";
};

View File

@ -0,0 +1,56 @@
# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/serial/qcom,msm-uart.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm MSM SoC Serial UART
maintainers:
- Bjorn Andersson <andersson@kernel.org>
- Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
description:
The MSM serial UART hardware is designed for low-speed use cases where a
dma-engine isn't needed. From a software perspective it's mostly compatible
with the MSM serial UARTDM except that it only supports reading and writing
one character at a time.
properties:
compatible:
const: qcom,msm-uart
clocks:
maxItems: 1
clock-names:
items:
- const: core
interrupts:
maxItems: 1
reg:
maxItems: 1
required:
- compatible
- clock-names
- clocks
- interrupts
- reg
unevaluatedProperties: false
allOf:
- $ref: /schemas/serial/serial.yaml#
examples:
- |
serial@a9c00000 {
compatible = "qcom,msm-uart";
reg = <0xa9c00000 0x1000>;
interrupts = <11>;
clocks = <&uart_cxc>;
clock-names = "core";
};

View File

@ -66,9 +66,9 @@ examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
uart0: serial@e1020000 {
compatible = "renesas,em-uart";
reg = <0xe1020000 0x38>;
interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&usia_u0_sclk>;
clock-names = "sclk";
compatible = "renesas,em-uart";
reg = <0xe1020000 0x38>;
interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&usia_u0_sclk>;
clock-names = "sclk";
};

View File

@ -131,20 +131,20 @@ examples:
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/power/r8a7795-sysc.h>
aliases {
serial1 = &hscif1;
serial1 = &hscif1;
};
hscif1: serial@e6550000 {
compatible = "renesas,hscif-r8a7795", "renesas,rcar-gen3-hscif",
"renesas,hscif";
reg = <0xe6550000 96>;
interrupts = <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 519>, <&cpg CPG_CORE R8A7795_CLK_S3D1>,
<&scif_clk>;
clock-names = "fck", "brg_int", "scif_clk";
dmas = <&dmac1 0x33>, <&dmac1 0x32>, <&dmac2 0x33>, <&dmac2 0x32>;
dma-names = "tx", "rx", "tx", "rx";
power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
resets = <&cpg 519>;
uart-has-rtscts;
compatible = "renesas,hscif-r8a7795", "renesas,rcar-gen3-hscif",
"renesas,hscif";
reg = <0xe6550000 96>;
interrupts = <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 519>, <&cpg CPG_CORE R8A7795_CLK_S3D1>,
<&scif_clk>;
clock-names = "fck", "brg_int", "scif_clk";
dmas = <&dmac1 0x33>, <&dmac1 0x32>, <&dmac2 0x33>, <&dmac2 0x32>;
dma-names = "tx", "rx", "tx", "rx";
power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
resets = <&cpg 519>;
uart-has-rtscts;
};

View File

@ -91,19 +91,19 @@ examples:
#include <dt-bindings/interrupt-controller/arm-gic.h>
aliases {
serial0 = &sci0;
serial0 = &sci0;
};
sci0: serial@1004d000 {
compatible = "renesas,r9a07g044-sci", "renesas,sci";
reg = <0x1004d000 0x400>;
interrupts = <GIC_SPI 405 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 406 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 407 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 408 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "eri", "rxi", "txi", "tei";
clocks = <&cpg CPG_MOD R9A07G044_SCI0_CLKP>;
clock-names = "fck";
power-domains = <&cpg>;
resets = <&cpg R9A07G044_SCI0_RST>;
compatible = "renesas,r9a07g044-sci", "renesas,sci";
reg = <0x1004d000 0x400>;
interrupts = <GIC_SPI 405 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 406 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 407 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 408 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "eri", "rxi", "txi", "tei";
clocks = <&cpg CPG_MOD R9A07G044_SCI0_CLKP>;
clock-names = "fck";
power-domains = <&cpg>;
resets = <&cpg R9A07G044_SCI0_RST>;
};

View File

@ -180,19 +180,19 @@ examples:
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/power/r8a7791-sysc.h>
aliases {
serial0 = &scif0;
serial0 = &scif0;
};
scif0: serial@e6e60000 {
compatible = "renesas,scif-r8a7791", "renesas,rcar-gen2-scif",
"renesas,scif";
reg = <0xe6e60000 64>;
interrupts = <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 721>, <&cpg CPG_CORE R8A7791_CLK_ZS>,
<&scif_clk>;
clock-names = "fck", "brg_int", "scif_clk";
dmas = <&dmac0 0x29>, <&dmac0 0x2a>, <&dmac1 0x29>, <&dmac1 0x2a>;
dma-names = "tx", "rx", "tx", "rx";
power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
resets = <&cpg 721>;
compatible = "renesas,scif-r8a7791", "renesas,rcar-gen2-scif",
"renesas,scif";
reg = <0xe6e60000 64>;
interrupts = <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 721>, <&cpg CPG_CORE R8A7791_CLK_ZS>,
<&scif_clk>;
clock-names = "fck", "brg_int", "scif_clk";
dmas = <&dmac0 0x29>, <&dmac0 0x2a>, <&dmac1 0x29>, <&dmac1 0x2a>;
dma-names = "tx", "rx", "tx", "rx";
power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
resets = <&cpg 721>;
};

View File

@ -95,18 +95,18 @@ examples:
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/power/r8a7790-sysc.h>
aliases {
serial0 = &scifa0;
serial0 = &scifa0;
};
scifa0: serial@e6c40000 {
compatible = "renesas,scifa-r8a7790", "renesas,rcar-gen2-scifa",
"renesas,scifa";
reg = <0xe6c40000 64>;
interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 204>;
clock-names = "fck";
power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
resets = <&cpg 204>;
dmas = <&dmac0 0x21>, <&dmac0 0x22>, <&dmac1 0x21>, <&dmac1 0x22>;
dma-names = "tx", "rx", "tx", "rx";
compatible = "renesas,scifa-r8a7790", "renesas,rcar-gen2-scifa",
"renesas,scifa";
reg = <0xe6c40000 64>;
interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 204>;
clock-names = "fck";
power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
resets = <&cpg 204>;
dmas = <&dmac0 0x21>, <&dmac0 0x22>, <&dmac1 0x21>, <&dmac1 0x22>;
dma-names = "tx", "rx", "tx", "rx";
};

View File

@ -94,10 +94,10 @@ examples:
#include <dt-bindings/clock/r8a7740-clock.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
scifb: serial@e6c30000 {
compatible = "renesas,scifb-r8a7740", "renesas,scifb";
reg = <0xe6c30000 0x100>;
interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp2_clks R8A7740_CLK_SCIFB>;
clock-names = "fck";
power-domains = <&pd_a3sp>;
compatible = "renesas,scifb-r8a7740", "renesas,scifb";
reg = <0xe6c30000 0x100>;
interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp2_clks R8A7740_CLK_SCIFB>;
clock-names = "fck";
power-domains = <&pd_a3sp>;
};

View File

@ -51,6 +51,12 @@ properties:
description: GPIO pin to enable RS485 bus termination.
maxItems: 1
rs485-rx-during-tx-gpios:
description: Output GPIO pin that sets the state of rs485-rx-during-tx. This
signal can be used to control the RX part of an RS485 transceiver. Thereby
the active state enables RX during TX.
maxItems: 1
additionalProperties: true
...

View File

@ -141,13 +141,13 @@ additionalProperties: true
examples:
- |
serial@1234 {
compatible = "ns16550a";
reg = <0x1234 0x20>;
interrupts = <1>;
compatible = "ns16550a";
reg = <0x1234 0x20>;
interrupts = <1>;
bluetooth {
compatible = "brcm,bcm4330-bt";
interrupt-parent = <&gpio>;
interrupts = <10>;
};
bluetooth {
compatible = "brcm,bcm4330-bt";
interrupt-parent = <&gpio>;
interrupts = <10>;
};
};

View File

@ -53,13 +53,13 @@ unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/sifive-fu540-prci.h>
serial@10010000 {
#include <dt-bindings/clock/sifive-fu540-prci.h>
serial@10010000 {
compatible = "sifive,fu540-c000-uart", "sifive,uart0";
interrupt-parent = <&plic0>;
interrupts = <80>;
reg = <0x10010000 0x1000>;
clocks = <&prci FU540_PRCI_CLK_TLCLK>;
};
};
...

View File

@ -67,6 +67,14 @@ properties:
- const: baudclk
- const: apb_pclk
dmas:
minItems: 2
dma-names:
items:
- const: rx
- const: tx
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.

View File

@ -35,8 +35,6 @@ properties:
description: enable hardware flow control (deprecated)
$ref: /schemas/types.yaml#/definitions/flag
uart-has-rtscts: true
rx-tx-swap: true
dmas:
@ -60,11 +58,6 @@ properties:
wakeup-source: true
rs485-rts-delay: true
rs485-rts-active-low: true
linux,rs485-enabled-at-boot-time: true
rs485-rx-during-tx: true
rx-threshold:
description:
If value is set to 1, RX FIFO threshold is disabled.

View File

@ -63,7 +63,7 @@ required:
- xlnx,use-parity
allOf:
- $ref: /schemas/serial.yaml#
- $ref: serial.yaml#
- if:
properties:
xlnx,use-parity:
@ -76,7 +76,7 @@ unevaluatedProperties: false
examples:
- |
serial@800c0000 {
serial@800c0000 {
compatible = "xlnx,xps-uartlite-1.00.a";
reg = <0x800c0000 0x10000>;
interrupts = <0x0 0x6e 0x1>;
@ -84,5 +84,5 @@ examples:
current-speed = <115200>;
xlnx,data-bits = <8>;
xlnx,use-parity = <0>;
};
};
...

View File

@ -25,6 +25,8 @@ Config Initiator
#. Switch the serial line to using the n_gsm line discipline by using
``TIOCSETD`` ioctl.
#. Configure the mux using ``GSMIOC_GETCONF_EXT``/``GSMIOC_SETCONF_EXT`` ioctl if needed.
#. Configure the mux using ``GSMIOC_GETCONF``/``GSMIOC_SETCONF`` ioctl.
#. Obtain base gsmtty number for the used serial port.
@ -42,6 +44,7 @@ Config Initiator
int ldisc = N_GSM0710;
struct gsm_config c;
struct gsm_config_ext ce;
struct termios configuration;
uint32_t first;
@ -62,6 +65,12 @@ Config Initiator
/* use n_gsm line discipline */
ioctl(fd, TIOCSETD, &ldisc);
/* get n_gsm extended configuration */
ioctl(fd, GSMIOC_GETCONF_EXT, &ce);
/* use keep-alive once every 5s for modem connection supervision */
ce.keep_alive = 500;
/* set the new extended configuration */
ioctl(fd, GSMIOC_SETCONF_EXT, &ce);
/* get n_gsm configuration */
ioctl(fd, GSMIOC_GETCONF, &c);
/* we are initiator and need encoding 0 (basic) */
@ -106,6 +115,9 @@ Config Requester
#. Switch the serial line to using the *n_gsm* line discipline by using
``TIOCSETD`` ioctl.
#. Configure the mux using ``GSMIOC_GETCONF_EXT``/``GSMIOC_SETCONF_EXT``
ioctl if needed.
#. Configure the mux using ``GSMIOC_GETCONF``/``GSMIOC_SETCONF`` ioctl.
#. Obtain base gsmtty number for the used serial port::
@ -119,6 +131,7 @@ Config Requester
int ldisc = N_GSM0710;
struct gsm_config c;
struct gsm_config_ext ce;
struct termios configuration;
uint32_t first;
@ -132,6 +145,12 @@ Config Requester
/* use n_gsm line discipline */
ioctl(fd, TIOCSETD, &ldisc);
/* get n_gsm extended configuration */
ioctl(fd, GSMIOC_GETCONF_EXT, &ce);
/* use keep-alive once every 5s for peer connection supervision */
ce.keep_alive = 500;
/* set the new extended configuration */
ioctl(fd, GSMIOC_SETCONF_EXT, &ce);
/* get n_gsm configuration */
ioctl(fd, GSMIOC_GETCONF, &c);
/* we are requester and need encoding 0 (basic) */

View File

@ -75,6 +75,125 @@ convenient for software to locate each feature by walking through this list,
and can be implemented in register regions of any FPGA device.
Device Feature Header - Version 0
=================================
Version 0 (DFHv0) is the original version of the Device Feature Header.
All multi-byte quantities in DFHv0 are little-endian.
The format of DFHv0 is shown below::
+-----------------------------------------------------------------------+
|63 Type 60|59 DFH VER 52|51 Rsvd 41|40 EOL|39 Next 16|15 REV 12|11 ID 0| 0x00
+-----------------------------------------------------------------------+
|63 GUID_L 0| 0x08
+-----------------------------------------------------------------------+
|63 GUID_H 0| 0x10
+-----------------------------------------------------------------------+
- Offset 0x00
* Type - The type of DFH (e.g. FME, AFU, or private feature).
* DFH VER - The version of the DFH.
* Rsvd - Currently unused.
* EOL - Set if the DFH is the end of the Device Feature List (DFL).
* Next - The offset in bytes of the next DFH in the DFL from the DFH start,
and the start of a DFH must be aligned to an 8 byte boundary.
If EOL is set, Next is the size of MMIO of the last feature in the list.
* REV - The revision of the feature associated with this header.
* ID - The feature ID if Type is private feature.
- Offset 0x08
* GUID_L - Least significant 64 bits of a 128-bit Globally Unique Identifier
(present only if Type is FME or AFU).
- Offset 0x10
* GUID_H - Most significant 64 bits of a 128-bit Globally Unique Identifier
(present only if Type is FME or AFU).
Device Feature Header - Version 1
=================================
Version 1 (DFHv1) of the Device Feature Header adds the following functionality:
* Provides a standardized mechanism for features to describe
parameters/capabilities to software.
* Standardize the use of a GUID for all DFHv1 types.
* Decouples the DFH location from the register space of the feature itself.
All multi-byte quantities in DFHv1 are little-endian.
The format of Version 1 of the Device Feature Header (DFH) is shown below::
+-----------------------------------------------------------------------+
|63 Type 60|59 DFH VER 52|51 Rsvd 41|40 EOL|39 Next 16|15 REV 12|11 ID 0| 0x00
+-----------------------------------------------------------------------+
|63 GUID_L 0| 0x08
+-----------------------------------------------------------------------+
|63 GUID_H 0| 0x10
+-----------------------------------------------------------------------+
|63 Reg Address/Offset 1| Rel 0| 0x18
+-----------------------------------------------------------------------+
|63 Reg Size 32|Params 31|30 Group 16|15 Instance 0| 0x20
+-----------------------------------------------------------------------+
|63 Next 35|34RSV33|EOP32|31 Param Version 16|15 Param ID 0| 0x28
+-----------------------------------------------------------------------+
|63 Parameter Data 0| 0x30
+-----------------------------------------------------------------------+
...
+-----------------------------------------------------------------------+
|63 Next 35|34RSV33|EOP32|31 Param Version 16|15 Param ID 0|
+-----------------------------------------------------------------------+
|63 Parameter Data 0|
+-----------------------------------------------------------------------+
- Offset 0x00
* Type - The type of DFH (e.g. FME, AFU, or private feature).
* DFH VER - The version of the DFH.
* Rsvd - Currently unused.
* EOL - Set if the DFH is the end of the Device Feature List (DFL).
* Next - The offset in bytes of the next DFH in the DFL from the DFH start,
and the start of a DFH must be aligned to an 8 byte boundary.
If EOL is set, Next is the size of MMIO of the last feature in the list.
* REV - The revision of the feature associated with this header.
* ID - The feature ID if Type is private feature.
- Offset 0x08
* GUID_L - Least significant 64 bits of a 128-bit Globally Unique Identifier.
- Offset 0x10
* GUID_H - Most significant 64 bits of a 128-bit Globally Unique Identifier.
- Offset 0x18
* Reg Address/Offset - If Rel bit is set, then the value is the high 63 bits
of a 16-bit aligned absolute address of the feature's registers. Otherwise
the value is the offset from the start of the DFH of the feature's registers.
- Offset 0x20
* Reg Size - Size of feature's register set in bytes.
* Params - Set if DFH has a list of parameter blocks.
* Group - Id of group if feature is part of a group.
* Instance - Id of feature instance within a group.
- Offset 0x28 if feature has parameters
* Next - Offset to the next parameter block in 8 byte words. If EOP set,
size in 8 byte words of last parameter.
* Param Version - Version of Param ID.
* Param ID - ID of parameter.
- Offset 0x30
* Parameter Data - Parameter data whose size and format is defined by
version and ID of the parameter.
FIU - FME (FPGA Management Engine)
==================================
The FPGA Management Engine performs reconfiguration and other infrastructure

View File

@ -13703,6 +13703,13 @@ L: linux-i2c@vger.kernel.org
S: Maintained
F: drivers/i2c/busses/i2c-mchp-pci1xxxx.c
MICROCHIP PCIe UART DRIVER
M: Kumaravel Thiagarajan <kumaravel.thiagarajan@microchip.com>
M: Tharun Kumar P <tharunkumar.pasumarthi@microchip.com>
L: linux-serial@vger.kernel.org
S: Maintained
F: drivers/tty/serial/8250/8250_pci1xxxx.c
MICROCHIP PWM DRIVER
M: Claudiu Beznea <claudiu.beznea@microchip.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)

View File

@ -0,0 +1,30 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2012 ARM Ltd.
* Author: Marc Zyngier <marc.zyngier@arm.com>
*
* Adapted for ARM and earlycon:
* Copyright (C) 2014 Linaro Ltd.
* Author: Rob Herring <robh@kernel.org>
*/
#ifndef _ARM_SEMIHOST_H_
#define _ARM_SEMIHOST_H_
#ifdef CONFIG_THUMB2_KERNEL
#define SEMIHOST_SWI "0xab"
#else
#define SEMIHOST_SWI "0x123456"
#endif
struct uart_port;
static inline void smh_putc(struct uart_port *port, unsigned char c)
{
asm volatile("mov r1, %0\n"
"mov r0, #3\n"
"svc " SEMIHOST_SWI "\n"
: : "r" (&c) : "r0", "r1", "memory");
}
#endif /* _ARM_SEMIHOST_H_ */

View File

@ -0,0 +1,24 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2012 ARM Ltd.
* Author: Marc Zyngier <marc.zyngier@arm.com>
*
* Adapted for ARM and earlycon:
* Copyright (C) 2014 Linaro Ltd.
* Author: Rob Herring <robh@kernel.org>
*/
#ifndef _ARM64_SEMIHOST_H_
#define _ARM64_SEMIHOST_H_
struct uart_port;
static inline void smh_putc(struct uart_port *port, unsigned char c)
{
asm volatile("mov x1, %0\n"
"mov x0, #3\n"
"hlt 0xf000\n"
: : "r" (&c) : "x0", "x1", "memory");
}
#endif /* _ARM64_SEMIHOST_H_ */

View File

@ -0,0 +1,26 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2022 tinylab.org
* Author: Bin Meng <bmeng@tinylab.org>
*/
#ifndef _RISCV_SEMIHOST_H_
#define _RISCV_SEMIHOST_H_
struct uart_port;
static inline void smh_putc(struct uart_port *port, unsigned char c)
{
asm volatile("addi a1, %0, 0\n"
"addi a0, zero, 3\n"
".balign 16\n"
".option push\n"
".option norvc\n"
"slli zero, zero, 0x1f\n"
"ebreak\n"
"srai zero, zero, 0x7\n"
".option pop\n"
: : "r" (&c) : "a0", "a1", "memory");
}
#endif /* _RISCV_SEMIHOST_H_ */

View File

@ -377,8 +377,8 @@ static void async_mode(MGSLPC_INFO *info);
static void tx_timeout(struct timer_list *t);
static int carrier_raised(struct tty_port *port);
static void dtr_rts(struct tty_port *port, int onoff);
static bool carrier_raised(struct tty_port *port);
static void dtr_rts(struct tty_port *port, bool active);
#if SYNCLINK_GENERIC_HDLC
#define dev_to_port(D) (dev_to_hdlc(D)->priv)
@ -1309,7 +1309,7 @@ static int startup(MGSLPC_INFO * info, struct tty_struct *tty)
if (tty)
clear_bit(TTY_IO_ERROR, &tty->flags);
tty_port_set_initialized(&info->port, 1);
tty_port_set_initialized(&info->port, true);
return 0;
}
@ -1359,7 +1359,7 @@ static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty)
if (tty)
set_bit(TTY_IO_ERROR, &tty->flags);
tty_port_set_initialized(&info->port, 0);
tty_port_set_initialized(&info->port, false);
}
static void mgslpc_program_hw(MGSLPC_INFO *info, struct tty_struct *tty)
@ -2430,7 +2430,7 @@ static void mgslpc_hangup(struct tty_struct *tty)
tty_port_hangup(&info->port);
}
static int carrier_raised(struct tty_port *port)
static bool carrier_raised(struct tty_port *port)
{
MGSLPC_INFO *info = container_of(port, MGSLPC_INFO, port);
unsigned long flags;
@ -2439,18 +2439,16 @@ static int carrier_raised(struct tty_port *port)
get_signals(info);
spin_unlock_irqrestore(&info->lock, flags);
if (info->serial_signals & SerialSignal_DCD)
return 1;
return 0;
return info->serial_signals & SerialSignal_DCD;
}
static void dtr_rts(struct tty_port *port, int onoff)
static void dtr_rts(struct tty_port *port, bool active)
{
MGSLPC_INFO *info = container_of(port, MGSLPC_INFO, port);
unsigned long flags;
spin_lock_irqsave(&info->lock, flags);
if (onoff)
if (active)
info->serial_signals |= SerialSignal_RTS | SerialSignal_DTR;
else
info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR);

View File

@ -13,6 +13,7 @@
#include <linux/dfl.h>
#include <linux/fpga-dfl.h>
#include <linux/module.h>
#include <linux/overflow.h>
#include <linux/uaccess.h>
#include "dfl.h"
@ -342,6 +343,8 @@ static void release_dfl_dev(struct device *dev)
if (ddev->mmio_res.parent)
release_resource(&ddev->mmio_res);
kfree(ddev->params);
ida_free(&dfl_device_ida, ddev->id);
kfree(ddev->irqs);
kfree(ddev);
@ -380,7 +383,16 @@ dfl_dev_add(struct dfl_feature_platform_data *pdata,
ddev->type = feature_dev_id_type(pdev);
ddev->feature_id = feature->id;
ddev->revision = feature->revision;
ddev->dfh_version = feature->dfh_version;
ddev->cdev = pdata->dfl_cdev;
if (feature->param_size) {
ddev->params = kmemdup(feature->params, feature->param_size, GFP_KERNEL);
if (!ddev->params) {
ret = -ENOMEM;
goto put_dev;
}
ddev->param_size = feature->param_size;
}
/* add mmio resource */
parent_res = &pdev->resource[feature->resource_index];
@ -708,20 +720,27 @@ struct build_feature_devs_info {
* struct dfl_feature_info - sub feature info collected during feature dev build
*
* @fid: id of this sub feature.
* @revision: revision of this sub feature
* @dfh_version: version of Device Feature Header (DFH)
* @mmio_res: mmio resource of this sub feature.
* @ioaddr: mapped base address of mmio resource.
* @node: node in sub_features linked list.
* @irq_base: start of irq index in this sub feature.
* @nr_irqs: number of irqs of this sub feature.
* @param_size: size DFH parameters.
* @params: DFH parameter data.
*/
struct dfl_feature_info {
u16 fid;
u8 revision;
u8 dfh_version;
struct resource mmio_res;
void __iomem *ioaddr;
struct list_head node;
unsigned int irq_base;
unsigned int nr_irqs;
unsigned int param_size;
u64 params[];
};
static void dfl_fpga_cdev_add_port_dev(struct dfl_fpga_cdev *cdev,
@ -797,7 +816,17 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
feature->dev = fdev;
feature->id = finfo->fid;
feature->revision = finfo->revision;
feature->dfh_version = finfo->dfh_version;
if (finfo->param_size) {
feature->params = devm_kmemdup(binfo->dev,
finfo->params, finfo->param_size,
GFP_KERNEL);
if (!feature->params)
return -ENOMEM;
feature->param_size = finfo->param_size;
}
/*
* the FIU header feature has some fundamental functions (sriov
* set, port enable/disable) needed for the dfl bus device and
@ -934,56 +963,115 @@ static u16 feature_id(u64 value)
return 0;
}
static u64 *find_param(u64 *params, resource_size_t max, int param_id)
{
u64 *end = params + max / sizeof(u64);
u64 v, next;
while (params < end) {
v = *params;
if (param_id == FIELD_GET(DFHv1_PARAM_HDR_ID, v))
return params;
if (FIELD_GET(DFHv1_PARAM_HDR_NEXT_EOP, v))
break;
next = FIELD_GET(DFHv1_PARAM_HDR_NEXT_OFFSET, v);
params += next;
}
return NULL;
}
/**
* dfh_find_param() - find parameter block for the given parameter id
* @dfl_dev: dfl device
* @param_id: id of dfl parameter
* @psize: destination to store size of parameter data in bytes
*
* Return: pointer to start of parameter data, PTR_ERR otherwise.
*/
void *dfh_find_param(struct dfl_device *dfl_dev, int param_id, size_t *psize)
{
u64 *phdr = find_param(dfl_dev->params, dfl_dev->param_size, param_id);
if (!phdr)
return ERR_PTR(-ENOENT);
if (psize)
*psize = (FIELD_GET(DFHv1_PARAM_HDR_NEXT_OFFSET, *phdr) - 1) * sizeof(u64);
return phdr + 1;
}
EXPORT_SYMBOL_GPL(dfh_find_param);
static int parse_feature_irqs(struct build_feature_devs_info *binfo,
resource_size_t ofst, u16 fid,
unsigned int *irq_base, unsigned int *nr_irqs)
resource_size_t ofst, struct dfl_feature_info *finfo)
{
void __iomem *base = binfo->ioaddr + ofst;
unsigned int i, ibase, inr = 0;
void *params = finfo->params;
enum dfl_id_type type;
u16 fid = finfo->fid;
int virq;
u64 *p;
u64 v;
type = feature_dev_id_type(binfo->feature_dev);
switch (finfo->dfh_version) {
case 0:
/*
* DFHv0 only provides MMIO resource information for each feature
* in the DFL header. There is no generic interrupt information.
* Instead, features with interrupt functionality provide
* the information in feature specific registers.
*/
type = feature_dev_id_type(binfo->feature_dev);
if (type == PORT_ID) {
switch (fid) {
case PORT_FEATURE_ID_UINT:
v = readq(base + PORT_UINT_CAP);
ibase = FIELD_GET(PORT_UINT_CAP_FST_VECT, v);
inr = FIELD_GET(PORT_UINT_CAP_INT_NUM, v);
break;
case PORT_FEATURE_ID_ERROR:
v = readq(base + PORT_ERROR_CAP);
ibase = FIELD_GET(PORT_ERROR_CAP_INT_VECT, v);
inr = FIELD_GET(PORT_ERROR_CAP_SUPP_INT, v);
break;
}
} else if (type == FME_ID) {
switch (fid) {
case FME_FEATURE_ID_GLOBAL_ERR:
v = readq(base + FME_ERROR_CAP);
ibase = FIELD_GET(FME_ERROR_CAP_INT_VECT, v);
inr = FIELD_GET(FME_ERROR_CAP_SUPP_INT, v);
break;
}
}
break;
/*
* Ideally DFL framework should only read info from DFL header, but
* current version DFL only provides mmio resources information for
* each feature in DFL Header, no field for interrupt resources.
* Interrupt resource information is provided by specific mmio
* registers of each private feature which supports interrupt. So in
* order to parse and assign irq resources, DFL framework has to look
* into specific capability registers of these private features.
*
* Once future DFL version supports generic interrupt resource
* information in common DFL headers, the generic interrupt parsing
* code will be added. But in order to be compatible to old version
* DFL, the driver may still fall back to these quirks.
*/
if (type == PORT_ID) {
switch (fid) {
case PORT_FEATURE_ID_UINT:
v = readq(base + PORT_UINT_CAP);
ibase = FIELD_GET(PORT_UINT_CAP_FST_VECT, v);
inr = FIELD_GET(PORT_UINT_CAP_INT_NUM, v);
case 1:
/*
* DFHv1 provides interrupt resource information in DFHv1
* parameter blocks.
*/
p = find_param(params, finfo->param_size, DFHv1_PARAM_ID_MSI_X);
if (!p)
break;
case PORT_FEATURE_ID_ERROR:
v = readq(base + PORT_ERROR_CAP);
ibase = FIELD_GET(PORT_ERROR_CAP_INT_VECT, v);
inr = FIELD_GET(PORT_ERROR_CAP_SUPP_INT, v);
break;
}
} else if (type == FME_ID) {
if (fid == FME_FEATURE_ID_GLOBAL_ERR) {
v = readq(base + FME_ERROR_CAP);
ibase = FIELD_GET(FME_ERROR_CAP_INT_VECT, v);
inr = FIELD_GET(FME_ERROR_CAP_SUPP_INT, v);
}
p++;
ibase = FIELD_GET(DFHv1_PARAM_MSI_X_STARTV, *p);
inr = FIELD_GET(DFHv1_PARAM_MSI_X_NUMV, *p);
break;
default:
dev_warn(binfo->dev, "unexpected DFH version %d\n", finfo->dfh_version);
break;
}
if (!inr) {
*irq_base = 0;
*nr_irqs = 0;
finfo->irq_base = 0;
finfo->nr_irqs = 0;
return 0;
}
@ -1006,12 +1094,37 @@ static int parse_feature_irqs(struct build_feature_devs_info *binfo,
}
}
*irq_base = ibase;
*nr_irqs = inr;
finfo->irq_base = ibase;
finfo->nr_irqs = inr;
return 0;
}
static int dfh_get_param_size(void __iomem *dfh_base, resource_size_t max)
{
int size = 0;
u64 v, next;
if (!FIELD_GET(DFHv1_CSR_SIZE_GRP_HAS_PARAMS,
readq(dfh_base + DFHv1_CSR_SIZE_GRP)))
return 0;
while (size + DFHv1_PARAM_HDR < max) {
v = readq(dfh_base + DFHv1_PARAM_HDR + size);
next = FIELD_GET(DFHv1_PARAM_HDR_NEXT_OFFSET, v);
if (!next)
return -EINVAL;
size += next * sizeof(u64);
if (FIELD_GET(DFHv1_PARAM_HDR_NEXT_EOP, v))
return size;
}
return -ENOENT;
}
/*
* when create sub feature instances, for private features, it doesn't need
* to provide resource size and feature id as they could be read from DFH
@ -1023,39 +1136,69 @@ static int
create_feature_instance(struct build_feature_devs_info *binfo,
resource_size_t ofst, resource_size_t size, u16 fid)
{
unsigned int irq_base, nr_irqs;
struct dfl_feature_info *finfo;
resource_size_t start, end;
int dfh_psize = 0;
u8 revision = 0;
u64 v, addr_off;
u8 dfh_ver = 0;
int ret;
u64 v;
if (fid != FEATURE_ID_AFU) {
v = readq(binfo->ioaddr + ofst);
revision = FIELD_GET(DFH_REVISION, v);
dfh_ver = FIELD_GET(DFH_VERSION, v);
/* read feature size and id if inputs are invalid */
size = size ? size : feature_size(v);
fid = fid ? fid : feature_id(v);
if (dfh_ver == 1) {
dfh_psize = dfh_get_param_size(binfo->ioaddr + ofst, size);
if (dfh_psize < 0) {
dev_err(binfo->dev,
"failed to read size of DFHv1 parameters %d\n",
dfh_psize);
return dfh_psize;
}
dev_dbg(binfo->dev, "dfhv1_psize %d\n", dfh_psize);
}
}
if (binfo->len - ofst < size)
return -EINVAL;
ret = parse_feature_irqs(binfo, ofst, fid, &irq_base, &nr_irqs);
if (ret)
return ret;
finfo = kzalloc(sizeof(*finfo), GFP_KERNEL);
finfo = kzalloc(struct_size(finfo, params, dfh_psize / sizeof(u64)), GFP_KERNEL);
if (!finfo)
return -ENOMEM;
memcpy_fromio(finfo->params, binfo->ioaddr + ofst + DFHv1_PARAM_HDR, dfh_psize);
finfo->param_size = dfh_psize;
finfo->fid = fid;
finfo->revision = revision;
finfo->mmio_res.start = binfo->start + ofst;
finfo->mmio_res.end = finfo->mmio_res.start + size - 1;
finfo->dfh_version = dfh_ver;
if (dfh_ver == 1) {
v = readq(binfo->ioaddr + ofst + DFHv1_CSR_ADDR);
addr_off = FIELD_GET(DFHv1_CSR_ADDR_MASK, v);
if (FIELD_GET(DFHv1_CSR_ADDR_REL, v))
start = addr_off << 1;
else
start = binfo->start + ofst + addr_off;
v = readq(binfo->ioaddr + ofst + DFHv1_CSR_SIZE_GRP);
end = start + FIELD_GET(DFHv1_CSR_SIZE_GRP_SIZE, v) - 1;
} else {
start = binfo->start + ofst;
end = start + size - 1;
}
finfo->mmio_res.flags = IORESOURCE_MEM;
finfo->irq_base = irq_base;
finfo->nr_irqs = nr_irqs;
finfo->mmio_res.start = start;
finfo->mmio_res.end = end;
ret = parse_feature_irqs(binfo, ofst, finfo);
if (ret) {
kfree(finfo);
return ret;
}
list_add_tail(&finfo->node, &binfo->sub_features);
binfo->feature_num++;

View File

@ -74,11 +74,47 @@
#define DFH_REVISION GENMASK_ULL(15, 12) /* Feature revision */
#define DFH_NEXT_HDR_OFST GENMASK_ULL(39, 16) /* Offset to next DFH */
#define DFH_EOL BIT_ULL(40) /* End of list */
#define DFH_VERSION GENMASK_ULL(59, 52) /* DFH version */
#define DFH_TYPE GENMASK_ULL(63, 60) /* Feature type */
#define DFH_TYPE_AFU 1
#define DFH_TYPE_PRIVATE 3
#define DFH_TYPE_FIU 4
/*
* DFHv1 Register Offset definitons
* In DHFv1, DFH + GUID + CSR_START + CSR_SIZE_GROUP + PARAM_HDR + PARAM_DATA
* as common header registers
*/
#define DFHv1_CSR_ADDR 0x18 /* CSR Register start address */
#define DFHv1_CSR_SIZE_GRP 0x20 /* Size of Reg Block and Group/tag */
#define DFHv1_PARAM_HDR 0x28 /* Optional First Param header */
/*
* CSR Rel Bit, 1'b0 = relative (offset from feature DFH start),
* 1'b1 = absolute (ARM or other non-PCIe use)
*/
#define DFHv1_CSR_ADDR_REL BIT_ULL(0)
/* CSR Header Register Bit Definitions */
#define DFHv1_CSR_ADDR_MASK GENMASK_ULL(63, 1) /* 63:1 of CSR address */
/* CSR SIZE Goup Register Bit Definitions */
#define DFHv1_CSR_SIZE_GRP_INSTANCE_ID GENMASK_ULL(15, 0) /* Enumeration instantiated IP */
#define DFHv1_CSR_SIZE_GRP_GROUPING_ID GENMASK_ULL(30, 16) /* Group Features/interfaces */
#define DFHv1_CSR_SIZE_GRP_HAS_PARAMS BIT_ULL(31) /* Presence of Parameters */
#define DFHv1_CSR_SIZE_GRP_SIZE GENMASK_ULL(63, 32) /* Size of CSR Block in bytes */
/* PARAM Header Register Bit Definitions */
#define DFHv1_PARAM_HDR_ID GENMASK_ULL(15, 0) /* Id of this Param */
#define DFHv1_PARAM_HDR_VER GENMASK_ULL(31, 16) /* Version Param */
#define DFHv1_PARAM_HDR_NEXT_OFFSET GENMASK_ULL(63, 35) /* Offset of next Param */
#define DFHv1_PARAM_HDR_NEXT_EOP BIT_ULL(32)
#define DFHv1_PARAM_DATA 0x08 /* Offset of Param data from Param header */
#define DFHv1_PARAM_ID_MSI_X 0x1
#define DFHv1_PARAM_MSI_X_NUMV GENMASK_ULL(63, 32)
#define DFHv1_PARAM_MSI_X_STARTV GENMASK_ULL(31, 0)
/* Next AFU Register Bitfield */
#define NEXT_AFU_NEXT_DFH_OFST GENMASK_ULL(23, 0) /* Offset to next AFU */
@ -231,6 +267,7 @@ struct dfl_feature_irq_ctx {
*
* @dev: ptr to pdev of the feature device which has the sub feature.
* @id: sub feature id.
* @revision: revisition of the instance of a feature.
* @resource_index: each sub feature has one mmio resource for its registers.
* this index is used to find its mmio resource from the
* feature dev (platform device)'s resources.
@ -240,6 +277,9 @@ struct dfl_feature_irq_ctx {
* @ops: ops of this sub feature.
* @ddev: ptr to the dfl device of this sub feature.
* @priv: priv data of this feature.
* @dfh_version: version of the DFH
* @param_size: size of dfh parameters
* @params: point to memory copy of dfh parameters
*/
struct dfl_feature {
struct platform_device *dev;
@ -252,6 +292,9 @@ struct dfl_feature {
const struct dfl_feature_ops *ops;
struct dfl_device *ddev;
void *priv;
u8 dfh_version;
unsigned int param_size;
void *params;
};
#define FEATURE_DEV_ID_UNUSED (-1)

View File

@ -14,7 +14,7 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/qcom-geni-se.h>
#include <linux/soc/qcom/geni-se.h>
#include <linux/spinlock.h>
#define SE_I2C_TX_TRANS_LEN 0x26c

View File

@ -647,7 +647,7 @@ static void ipoctal_hangup(struct tty_struct *tty)
tty_port_hangup(&channel->tty_port);
ipoctal_reset_channel(channel);
tty_port_set_initialized(&channel->tty_port, 0);
tty_port_set_initialized(&channel->tty_port, false);
wake_up_interruptible(&channel->tty_port.open_wait);
}
@ -659,7 +659,7 @@ static void ipoctal_shutdown(struct tty_struct *tty)
return;
ipoctal_reset_channel(channel);
tty_port_set_initialized(&channel->tty_port, 0);
tty_port_set_initialized(&channel->tty_port, false);
}
static void ipoctal_cleanup(struct tty_struct *tty)

View File

@ -526,7 +526,7 @@ static void sdio_uart_irq(struct sdio_func *func)
port->in_sdio_uart_irq = NULL;
}
static int uart_carrier_raised(struct tty_port *tport)
static bool uart_carrier_raised(struct tty_port *tport)
{
struct sdio_uart_port *port =
container_of(tport, struct sdio_uart_port, port);
@ -535,28 +535,27 @@ static int uart_carrier_raised(struct tty_port *tport)
return 1;
ret = sdio_uart_get_mctrl(port);
sdio_uart_release_func(port);
if (ret & TIOCM_CAR)
return 1;
return 0;
return ret & TIOCM_CAR;
}
/**
* uart_dtr_rts - port helper to set uart signals
* @tport: tty port to be updated
* @onoff: set to turn on DTR/RTS
* @active: set to turn on DTR/RTS
*
* Called by the tty port helpers when the modem signals need to be
* adjusted during an open, close and hangup.
*/
static void uart_dtr_rts(struct tty_port *tport, int onoff)
static void uart_dtr_rts(struct tty_port *tport, bool active)
{
struct sdio_uart_port *port =
container_of(tport, struct sdio_uart_port, port);
int ret = sdio_uart_claim_func(port);
if (ret)
return;
if (onoff == 0)
if (!active)
sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
else
sdio_uart_set_mctrl(port, TIOCM_DTR | TIOCM_RTS);

View File

@ -13,7 +13,7 @@
#include <linux/pps_kernel.h>
#include <linux/bug.h>
static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status)
static void pps_tty_dcd_change(struct tty_struct *tty, bool active)
{
struct pps_device *pps;
struct pps_event_time ts;
@ -29,11 +29,11 @@ static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status)
return;
/* Now do the PPS event report */
pps_event(pps, &ts, status ? PPS_CAPTUREASSERT :
pps_event(pps, &ts, active ? PPS_CAPTUREASSERT :
PPS_CAPTURECLEAR, NULL);
dev_dbg(pps->dev, "PPS %s at %lu\n",
status ? "assert" : "clear", jiffies);
active ? "assert" : "clear", jiffies);
}
static int (*alias_n_tty_open)(struct tty_struct *tty);

View File

@ -629,7 +629,7 @@ static int raw3215_startup(struct raw3215_info *raw)
if (tty_port_initialized(&raw->port))
return 0;
raw->line_pos = 0;
tty_port_set_initialized(&raw->port, 1);
tty_port_set_initialized(&raw->port, true);
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
raw3215_try_io(raw);
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
@ -659,7 +659,7 @@ static void raw3215_shutdown(struct raw3215_info *raw)
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
remove_wait_queue(&raw->empty_wait, &wait);
set_current_state(TASK_RUNNING);
tty_port_set_initialized(&raw->port, 1);
tty_port_set_initialized(&raw->port, true);
}
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
}

View File

@ -14,7 +14,7 @@
#include <linux/of_platform.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/qcom-geni-se.h>
#include <linux/soc/qcom/geni-se.h>
/**
* DOC: Overview

View File

@ -12,7 +12,7 @@
#include <linux/platform_device.h>
#include <linux/pm_opp.h>
#include <linux/pm_runtime.h>
#include <linux/qcom-geni-se.h>
#include <linux/soc/qcom/geni-se.h>
#include <linux/spi/spi.h>
#include <linux/spinlock.h>

View File

@ -701,7 +701,7 @@ static int gb_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
return -ENOIOCTLCMD;
}
static void gb_tty_dtr_rts(struct tty_port *port, int on)
static void gb_tty_dtr_rts(struct tty_port *port, bool active)
{
struct gb_tty *gb_tty;
u8 newctrl;
@ -709,7 +709,7 @@ static void gb_tty_dtr_rts(struct tty_port *port, int on)
gb_tty = container_of(port, struct gb_tty, port);
newctrl = gb_tty->ctrlout;
if (on)
if (active)
newctrl |= (GB_UART_CTRL_DTR | GB_UART_CTRL_RTS);
else
newctrl &= ~(GB_UART_CTRL_DTR | GB_UART_CTRL_RTS);

View File

@ -502,7 +502,7 @@ static int startup(struct tty_struct *tty, struct serial_state *info)
*/
change_speed(tty, info, NULL);
tty_port_set_initialized(port, 1);
tty_port_set_initialized(port, true);
local_irq_restore(flags);
return 0;
@ -556,7 +556,7 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info)
set_bit(TTY_IO_ERROR, &tty->flags);
tty_port_set_initialized(&info->tport, 0);
tty_port_set_initialized(&info->tport, false);
local_irq_restore(flags);
}
@ -1329,7 +1329,7 @@ static void rs_hangup(struct tty_struct *tty)
rs_flush_buffer(tty);
shutdown(tty, info);
info->tport.count = 0;
tty_port_set_active(&info->tport, 0);
tty_port_set_active(&info->tport, false);
info->tport.tty = NULL;
wake_up_interruptible(&info->tport.open_wait);
}
@ -1454,18 +1454,18 @@ static const struct tty_operations serial_ops = {
.proc_show = rs_proc_show,
};
static int amiga_carrier_raised(struct tty_port *port)
static bool amiga_carrier_raised(struct tty_port *port)
{
return !(ciab.pra & SER_DCD);
}
static void amiga_dtr_rts(struct tty_port *port, int raise)
static void amiga_dtr_rts(struct tty_port *port, bool active)
{
struct serial_state *info = container_of(port, struct serial_state,
tport);
unsigned long flags;
if (raise)
if (active)
info->MCR |= SER_DTR|SER_RTS;
else
info->MCR &= ~(SER_DTR|SER_RTS);

View File

@ -376,7 +376,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
/* We are ready... raise DTR/RTS */
if (C_BAUD(tty))
if (hp->ops->dtr_rts)
hp->ops->dtr_rts(hp, 1);
hp->ops->dtr_rts(hp, true);
tty_port_set_initialized(&hp->port, true);
}
@ -406,7 +406,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
if (C_HUPCL(tty))
if (hp->ops->dtr_rts)
hp->ops->dtr_rts(hp, 0);
hp->ops->dtr_rts(hp, false);
if (hp->ops->notifier_del)
hp->ops->notifier_del(hp, hp->data);

View File

@ -66,7 +66,7 @@ struct hv_ops {
int (*tiocmset)(struct hvc_struct *hp, unsigned int set, unsigned int clear);
/* Callbacks to handle tty ports */
void (*dtr_rts)(struct hvc_struct *hp, int raise);
void (*dtr_rts)(struct hvc_struct *hp, bool active);
};
/* Register a vterm and a slot index for use as a console (console_init) */

View File

@ -658,13 +658,13 @@ static void hvc_iucv_notifier_hangup(struct hvc_struct *hp, int id)
/**
* hvc_iucv_dtr_rts() - HVC notifier for handling DTR/RTS
* @hp: Pointer the HVC device (struct hvc_struct)
* @raise: Non-zero to raise or zero to lower DTR/RTS lines
* @active: True to raise or false to lower DTR/RTS lines
*
* This routine notifies the HVC back-end to raise or lower DTR/RTS
* lines. Raising DTR/RTS is ignored. Lowering DTR/RTS indicates to
* drop the IUCV connection (similar to hang up the modem).
*/
static void hvc_iucv_dtr_rts(struct hvc_struct *hp, int raise)
static void hvc_iucv_dtr_rts(struct hvc_struct *hp, bool active)
{
struct hvc_iucv_private *priv;
struct iucv_path *path;
@ -672,7 +672,7 @@ static void hvc_iucv_dtr_rts(struct hvc_struct *hp, int raise)
/* Raising the DTR/RTS is ignored as IUCV connections can be
* established at any times.
*/
if (raise)
if (active)
return;
priv = hvc_iucv_get_private(hp->vtermno);

View File

@ -52,6 +52,7 @@
#include <linux/device.h>
#include <linux/init.h>
#include <linux/completion.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/kref.h>
@ -285,6 +286,7 @@ struct hvcs_struct {
char p_location_code[HVCS_CLC_LENGTH + 1]; /* CLC + Null Term */
struct list_head next; /* list management */
struct vio_dev *vdev;
struct completion *destroyed;
};
static LIST_HEAD(hvcs_structs);
@ -432,7 +434,7 @@ static ssize_t hvcs_index_show(struct device *dev, struct device_attribute *attr
static DEVICE_ATTR(index, S_IRUGO, hvcs_index_show, NULL);
static struct attribute *hvcs_attrs[] = {
static struct attribute *hvcs_dev_attrs[] = {
&dev_attr_partner_vtys.attr,
&dev_attr_partner_clcs.attr,
&dev_attr_current_vty.attr,
@ -441,9 +443,7 @@ static struct attribute *hvcs_attrs[] = {
NULL,
};
static struct attribute_group hvcs_attr_group = {
.attrs = hvcs_attrs,
};
ATTRIBUTE_GROUPS(hvcs_dev);
static ssize_t rescan_show(struct device_driver *ddp, char *buf)
{
@ -468,6 +468,13 @@ static ssize_t rescan_store(struct device_driver *ddp, const char * buf,
static DRIVER_ATTR_RW(rescan);
static struct attribute *hvcs_attrs[] = {
&driver_attr_rescan.attr,
NULL,
};
ATTRIBUTE_GROUPS(hvcs);
static void hvcs_kick(void)
{
hvcs_kicked = 1;
@ -658,11 +665,13 @@ static void hvcs_destruct_port(struct tty_port *p)
{
struct hvcs_struct *hvcsd = container_of(p, struct hvcs_struct, port);
struct vio_dev *vdev;
struct completion *comp;
unsigned long flags;
spin_lock(&hvcs_structs_lock);
spin_lock_irqsave(&hvcsd->lock, flags);
comp = hvcsd->destroyed;
/* the list_del poisons the pointers */
list_del(&(hvcsd->next));
@ -682,15 +691,16 @@ static void hvcs_destruct_port(struct tty_port *p)
hvcsd->p_unit_address = 0;
hvcsd->p_partition_ID = 0;
hvcsd->destroyed = NULL;
hvcs_return_index(hvcsd->index);
memset(&hvcsd->p_location_code[0], 0x00, HVCS_CLC_LENGTH + 1);
spin_unlock_irqrestore(&hvcsd->lock, flags);
spin_unlock(&hvcs_structs_lock);
sysfs_remove_group(&vdev->dev.kobj, &hvcs_attr_group);
kfree(hvcsd);
if (comp)
complete(comp);
}
static const struct tty_port_operations hvcs_port_ops = {
@ -721,7 +731,6 @@ static int hvcs_probe(
{
struct hvcs_struct *hvcsd;
int index, rc;
int retval;
if (!dev || !id) {
printk(KERN_ERR "HVCS: probed with invalid parameter.\n");
@ -778,13 +787,6 @@ static int hvcs_probe(
list_add_tail(&(hvcsd->next), &hvcs_structs);
spin_unlock(&hvcs_structs_lock);
retval = sysfs_create_group(&dev->dev.kobj, &hvcs_attr_group);
if (retval) {
printk(KERN_ERR "HVCS: Can't create sysfs attrs for vty-server@%X\n",
hvcsd->vdev->unit_address);
return retval;
}
printk(KERN_INFO "HVCS: vty-server@%X added to the vio bus.\n", dev->unit_address);
/*
@ -797,6 +799,7 @@ static int hvcs_probe(
static void hvcs_remove(struct vio_dev *dev)
{
struct hvcs_struct *hvcsd = dev_get_drvdata(&dev->dev);
DECLARE_COMPLETION_ONSTACK(comp);
unsigned long flags;
struct tty_struct *tty;
@ -804,24 +807,22 @@ static void hvcs_remove(struct vio_dev *dev)
spin_lock_irqsave(&hvcsd->lock, flags);
tty = hvcsd->port.tty;
hvcsd->destroyed = &comp;
tty = tty_port_tty_get(&hvcsd->port);
spin_unlock_irqrestore(&hvcsd->lock, flags);
/*
* Let the last holder of this object cause it to be removed, which
* would probably be tty_hangup below.
*/
tty_port_put(&hvcsd->port);
/*
* The hangup is a scheduled function which will auto chain call
* hvcs_hangup. The tty should always be valid at this time unless a
* The tty should always be valid at this time unless a
* simultaneous tty close already cleaned up the hvcs_struct.
*/
if (tty)
tty_hangup(tty);
if (tty) {
tty_vhangup(tty);
tty_kref_put(tty);
}
tty_port_put(&hvcsd->port);
wait_for_completion(&comp);
printk(KERN_INFO "HVCS: vty-server@%X removed from the"
" vio bus.\n", dev->unit_address);
};
@ -831,6 +832,10 @@ static struct vio_driver hvcs_vio_driver = {
.probe = hvcs_probe,
.remove = hvcs_remove,
.name = hvcs_driver_name,
.driver = {
.groups = hvcs_groups,
.dev_groups = hvcs_dev_groups,
},
};
/* Only called from hvcs_get_pi please */
@ -1171,7 +1176,10 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
hvcsd = tty->driver_data;
spin_lock_irqsave(&hvcsd->lock, flags);
if (--hvcsd->port.count == 0) {
if (hvcsd->port.count == 0) {
spin_unlock_irqrestore(&hvcsd->lock, flags);
return;
} else if (--hvcsd->port.count == 0) {
vio_disable_interrupts(hvcsd->vdev);
@ -1215,12 +1223,9 @@ static void hvcs_hangup(struct tty_struct * tty)
{
struct hvcs_struct *hvcsd = tty->driver_data;
unsigned long flags;
int temp_open_count;
int irq;
spin_lock_irqsave(&hvcsd->lock, flags);
/* Preserve this so that we know how many kref refs to put */
temp_open_count = hvcsd->port.count;
/*
* Don't kref put inside the spinlock because the destruction
@ -1230,11 +1235,7 @@ static void hvcs_hangup(struct tty_struct * tty)
vio_disable_interrupts(hvcsd->vdev);
hvcsd->todo_mask = 0;
/* I don't think the tty needs the hvcs_struct pointer after a hangup */
tty->driver_data = NULL;
hvcsd->port.tty = NULL;
hvcsd->port.count = 0;
/* This will drop any buffered data on the floor which is OK in a hangup
@ -1247,21 +1248,6 @@ static void hvcs_hangup(struct tty_struct * tty)
spin_unlock_irqrestore(&hvcsd->lock, flags);
free_irq(irq, hvcsd);
/*
* We need to kref_put() for every open_count we have since the
* tty_hangup() function doesn't invoke a close per open connection on a
* non-console device.
*/
while(temp_open_count) {
--temp_open_count;
/*
* The final put will trigger destruction of the hvcs_struct.
* NOTE: If this hangup was signaled from user space then the
* final put will never happen.
*/
tty_port_put(&hvcsd->port);
}
}
/*
@ -1525,13 +1511,6 @@ static int __init hvcs_module_init(void)
pr_info("HVCS: Driver registered.\n");
/* This needs to be done AFTER the vio_register_driver() call or else
* the kobjects won't be initialized properly.
*/
rc = driver_create_file(&(hvcs_vio_driver.driver), &driver_attr_rescan);
if (rc)
pr_warn("HVCS: Failed to create rescan file (err %d)\n", rc);
return 0;
}
@ -1556,8 +1535,6 @@ static void __exit hvcs_module_exit(void)
hvcs_pi_buff = NULL;
spin_unlock(&hvcs_pi_lock);
driver_remove_file(&hvcs_vio_driver.driver, &driver_attr_rescan);
tty_unregister_driver(hvcs_tty_driver);
hvcs_free_index_list();

View File

@ -501,16 +501,16 @@ static int moxa_tiocmset(struct tty_struct *tty,
static void moxa_poll(struct timer_list *);
static void moxa_set_tty_param(struct tty_struct *, const struct ktermios *);
static void moxa_shutdown(struct tty_port *);
static int moxa_carrier_raised(struct tty_port *);
static void moxa_dtr_rts(struct tty_port *, int);
static bool moxa_carrier_raised(struct tty_port *);
static void moxa_dtr_rts(struct tty_port *, bool);
/*
* moxa board interface functions:
*/
static void MoxaPortEnable(struct moxa_port *);
static void MoxaPortDisable(struct moxa_port *);
static int MoxaPortSetTermio(struct moxa_port *, struct ktermios *, speed_t);
static int MoxaPortGetLineOut(struct moxa_port *, int *, int *);
static void MoxaPortLineCtrl(struct moxa_port *, int, int);
static int MoxaPortGetLineOut(struct moxa_port *, bool *, bool *);
static void MoxaPortLineCtrl(struct moxa_port *, bool, bool);
static void MoxaPortFlowCtrl(struct moxa_port *, int, int, int, int, int);
static int MoxaPortLineStatus(struct moxa_port *);
static void MoxaPortFlushData(struct moxa_port *, int);
@ -1432,7 +1432,7 @@ static void moxa_shutdown(struct tty_port *port)
MoxaPortFlushData(ch, 2);
}
static int moxa_carrier_raised(struct tty_port *port)
static bool moxa_carrier_raised(struct tty_port *port)
{
struct moxa_port *ch = container_of(port, struct moxa_port, port);
int dcd;
@ -1443,10 +1443,10 @@ static int moxa_carrier_raised(struct tty_port *port)
return dcd;
}
static void moxa_dtr_rts(struct tty_port *port, int onoff)
static void moxa_dtr_rts(struct tty_port *port, bool active)
{
struct moxa_port *ch = container_of(port, struct moxa_port, port);
MoxaPortLineCtrl(ch, onoff, onoff);
MoxaPortLineCtrl(ch, active, active);
}
@ -1481,10 +1481,10 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
if (!tty_port_initialized(&ch->port)) {
ch->statusflags = 0;
moxa_set_tty_param(tty, &tty->termios);
MoxaPortLineCtrl(ch, 1, 1);
MoxaPortLineCtrl(ch, true, true);
MoxaPortEnable(ch);
MoxaSetFifo(ch, ch->type == PORT_16550A);
tty_port_set_initialized(&ch->port, 1);
tty_port_set_initialized(&ch->port, true);
}
mutex_unlock(&ch->port.mutex);
mutex_unlock(&moxa_openlock);
@ -1557,19 +1557,21 @@ static unsigned int moxa_chars_in_buffer(struct tty_struct *tty)
static int moxa_tiocmget(struct tty_struct *tty)
{
struct moxa_port *ch = tty->driver_data;
int flag = 0, dtr, rts;
bool dtr_active, rts_active;
int flag = 0;
int status;
MoxaPortGetLineOut(ch, &dtr, &rts);
if (dtr)
MoxaPortGetLineOut(ch, &dtr_active, &rts_active);
if (dtr_active)
flag |= TIOCM_DTR;
if (rts)
if (rts_active)
flag |= TIOCM_RTS;
dtr = MoxaPortLineStatus(ch);
if (dtr & 1)
status = MoxaPortLineStatus(ch);
if (status & 1)
flag |= TIOCM_CTS;
if (dtr & 2)
if (status & 2)
flag |= TIOCM_DSR;
if (dtr & 4)
if (status & 4)
flag |= TIOCM_CD;
return flag;
}
@ -1577,8 +1579,8 @@ static int moxa_tiocmget(struct tty_struct *tty)
static int moxa_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear)
{
bool dtr_active, rts_active;
struct moxa_port *ch;
int dtr, rts;
mutex_lock(&moxa_openlock);
ch = tty->driver_data;
@ -1587,16 +1589,16 @@ static int moxa_tiocmset(struct tty_struct *tty,
return -EINVAL;
}
MoxaPortGetLineOut(ch, &dtr, &rts);
MoxaPortGetLineOut(ch, &dtr_active, &rts_active);
if (set & TIOCM_RTS)
rts = 1;
rts_active = true;
if (set & TIOCM_DTR)
dtr = 1;
dtr_active = true;
if (clear & TIOCM_RTS)
rts = 0;
rts_active = false;
if (clear & TIOCM_DTR)
dtr = 0;
MoxaPortLineCtrl(ch, dtr, rts);
dtr_active = false;
MoxaPortLineCtrl(ch, dtr_active, rts_active);
mutex_unlock(&moxa_openlock);
return 0;
}
@ -1664,8 +1666,8 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
u16 __iomem *ip)
{
struct tty_struct *tty = tty_port_tty_get(&p->port);
bool inited = tty_port_initialized(&p->port);
void __iomem *ofsAddr;
unsigned int inited = tty_port_initialized(&p->port);
u16 intr;
if (tty) {
@ -1877,12 +1879,12 @@ static void MoxaPortFlushData(struct moxa_port *port, int mode)
*
* Function 13: Get the DTR/RTS state of this port.
* Syntax:
* int MoxaPortGetLineOut(int port, int *dtrState, int *rtsState);
* int MoxaPortGetLineOut(int port, bool *dtrState, bool *rtsState);
* int port : port number (0 - 127)
* int * dtrState : pointer to INT to receive the current DTR
* bool * dtr_active : pointer to bool to receive the current DTR
* state. (if NULL, this function will not
* write to this address)
* int * rtsState : pointer to INT to receive the current RTS
* bool * rts_active : pointer to bool to receive the current RTS
* state. (if NULL, this function will not
* write to this address)
*
@ -1892,10 +1894,10 @@ static void MoxaPortFlushData(struct moxa_port *port, int mode)
*
* Function 14: Setting the DTR/RTS output state of this port.
* Syntax:
* void MoxaPortLineCtrl(int port, int dtrState, int rtsState);
* void MoxaPortLineCtrl(int port, bool dtrState, bool rtsState);
* int port : port number (0 - 127)
* int dtrState : DTR output state (0: off, 1: on)
* int rtsState : RTS output state (0: off, 1: on)
* bool dtr_active : DTR output state
* bool rts_active : RTS output state
*
*
* Function 15: Setting the flow control of this port.
@ -2103,24 +2105,24 @@ static int MoxaPortSetTermio(struct moxa_port *port, struct ktermios *termio,
return baud;
}
static int MoxaPortGetLineOut(struct moxa_port *port, int *dtrState,
int *rtsState)
static int MoxaPortGetLineOut(struct moxa_port *port, bool *dtr_active,
bool *rts_active)
{
if (dtrState)
*dtrState = !!(port->lineCtrl & DTR_ON);
if (rtsState)
*rtsState = !!(port->lineCtrl & RTS_ON);
if (dtr_active)
*dtr_active = port->lineCtrl & DTR_ON;
if (rts_active)
*rts_active = port->lineCtrl & RTS_ON;
return 0;
}
static void MoxaPortLineCtrl(struct moxa_port *port, int dtr, int rts)
static void MoxaPortLineCtrl(struct moxa_port *port, bool dtr_active, bool rts_active)
{
u8 mode = 0;
if (dtr)
if (dtr_active)
mode |= DTR_ON;
if (rts)
if (rts_active)
mode |= RTS_ON;
port->lineCtrl = mode;
moxafunc(port->tableAddr, FC_LineControl, mode);

View File

@ -458,13 +458,14 @@ static void __mxser_stop_tx(struct mxser_port *info)
outb(info->IER, info->ioaddr + UART_IER);
}
static int mxser_carrier_raised(struct tty_port *port)
static bool mxser_carrier_raised(struct tty_port *port)
{
struct mxser_port *mp = container_of(port, struct mxser_port, port);
return (inb(mp->ioaddr + UART_MSR) & UART_MSR_DCD)?1:0;
return inb(mp->ioaddr + UART_MSR) & UART_MSR_DCD;
}
static void mxser_dtr_rts(struct tty_port *port, int on)
static void mxser_dtr_rts(struct tty_port *port, bool active)
{
struct mxser_port *mp = container_of(port, struct mxser_port, port);
unsigned long flags;
@ -472,7 +473,7 @@ static void mxser_dtr_rts(struct tty_port *port, int on)
spin_lock_irqsave(&mp->slock, flags);
mcr = inb(mp->ioaddr + UART_MCR);
if (on)
if (active)
mcr |= UART_MCR_DTR | UART_MCR_RTS;
else
mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
@ -1063,7 +1064,7 @@ static int mxser_set_serial_info(struct tty_struct *tty,
} else {
retval = mxser_activate(port, tty);
if (retval == 0)
tty_port_set_initialized(port, 1);
tty_port_set_initialized(port, true);
}
mutex_unlock(&port->mutex);
return retval;

View File

@ -318,6 +318,11 @@ struct gsm_mux {
struct gsm_control *pending_cmd;/* Our current pending command */
spinlock_t control_lock; /* Protects the pending command */
/* Keep-alive */
struct timer_list ka_timer; /* Keep-alive response timer */
u8 ka_num; /* Keep-alive match pattern */
signed int ka_retries; /* Keep-alive retry counter, -1 if not yet initialized */
/* Configuration */
int adaption; /* 1 or 2 supported */
u8 ftype; /* UI or UIH */
@ -325,6 +330,7 @@ struct gsm_mux {
unsigned int t3; /* Power wake-up timer in seconds. */
int n2; /* Retry count */
u8 k; /* Window size */
u32 keep_alive; /* Control channel keep-alive in 10ms */
/* Statistics (not currently exposed) */
unsigned long bad_fcs;
@ -540,6 +546,11 @@ static u8 gsm_encode_modem(const struct gsm_dlci *dlci)
modembits |= MDM_IC;
if (dlci->modem_tx & TIOCM_CD || dlci->gsm->initiator)
modembits |= MDM_DV;
/* special mappings for passive side to operate as UE */
if (dlci->modem_tx & TIOCM_OUT1)
modembits |= MDM_IC;
if (dlci->modem_tx & TIOCM_OUT2)
modembits |= MDM_DV;
return modembits;
}
@ -1531,6 +1542,7 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
if (brk & 0x01)
tty_insert_flip_char(&dlci->port, 0, TTY_BREAK);
dlci->modem_rx = mlines;
wake_up_interruptible(&dlci->gsm->event);
}
/**
@ -1897,11 +1909,13 @@ static void gsm_control_response(struct gsm_mux *gsm, unsigned int command,
const u8 *data, int clen)
{
struct gsm_control *ctrl;
struct gsm_dlci *dlci;
unsigned long flags;
spin_lock_irqsave(&gsm->control_lock, flags);
ctrl = gsm->pending_cmd;
dlci = gsm->dlci[0];
command |= 1;
/* Does the reply match our command */
if (ctrl != NULL && (command == ctrl->cmd || command == CMD_NSC)) {
@ -1916,6 +1930,53 @@ static void gsm_control_response(struct gsm_mux *gsm, unsigned int command,
/* Or did we receive the PN response to our PN command */
} else if (command == CMD_PN) {
gsm_control_negotiation(gsm, 0, data, clen);
/* Or did we receive the TEST response to our TEST command */
} else if (command == CMD_TEST && clen == 1 && *data == gsm->ka_num) {
gsm->ka_retries = -1; /* trigger new keep-alive message */
if (dlci && !dlci->dead)
mod_timer(&gsm->ka_timer, jiffies + gsm->keep_alive * HZ / 100);
}
spin_unlock_irqrestore(&gsm->control_lock, flags);
}
/**
* gsm_control_keep_alive - check timeout or start keep-alive
* @t: timer contained in our gsm object
*
* Called off the keep-alive timer expiry signaling that our link
* partner is not responding anymore. Link will be closed.
* This is also called to startup our timer.
*/
static void gsm_control_keep_alive(struct timer_list *t)
{
struct gsm_mux *gsm = from_timer(gsm, t, ka_timer);
unsigned long flags;
spin_lock_irqsave(&gsm->control_lock, flags);
if (gsm->ka_num && gsm->ka_retries == 0) {
/* Keep-alive expired -> close the link */
if (debug & DBG_ERRORS)
pr_debug("%s keep-alive timed out\n", __func__);
spin_unlock_irqrestore(&gsm->control_lock, flags);
if (gsm->dlci[0])
gsm_dlci_begin_close(gsm->dlci[0]);
return;
} else if (gsm->keep_alive && gsm->dlci[0] && !gsm->dlci[0]->dead) {
if (gsm->ka_retries > 0) {
/* T2 expired for keep-alive -> resend */
gsm->ka_retries--;
} else {
/* Start keep-alive timer */
gsm->ka_num++;
if (!gsm->ka_num)
gsm->ka_num++;
gsm->ka_retries = (signed int)gsm->n2;
}
gsm_control_command(gsm, CMD_TEST, &gsm->ka_num,
sizeof(gsm->ka_num));
mod_timer(&gsm->ka_timer,
jiffies + gsm->t2 * HZ / 100);
}
spin_unlock_irqrestore(&gsm->control_lock, flags);
}
@ -2059,14 +2120,16 @@ static void gsm_dlci_close(struct gsm_dlci *dlci)
tty_port_tty_hangup(&dlci->port, false);
gsm_dlci_clear_queues(dlci->gsm, dlci);
/* Ensure that gsmtty_open() can return. */
tty_port_set_initialized(&dlci->port, 0);
tty_port_set_initialized(&dlci->port, false);
wake_up_interruptible(&dlci->port.open_wait);
} else
} else {
del_timer(&dlci->gsm->ka_timer);
dlci->gsm->dead = true;
}
/* A DLCI 0 close is a MUX termination so we need to kick that
back to userspace somehow */
gsm_dlci_data_kick(dlci);
wake_up(&dlci->gsm->event);
wake_up_all(&dlci->gsm->event);
}
/**
@ -2078,6 +2141,8 @@ static void gsm_dlci_close(struct gsm_dlci *dlci)
static void gsm_dlci_open(struct gsm_dlci *dlci)
{
struct gsm_mux *gsm = dlci->gsm;
/* Note that SABM UA .. SABM UA first UA lost can mean that we go
open -> open */
del_timer(&dlci->t1);
@ -2087,8 +2152,15 @@ static void gsm_dlci_open(struct gsm_dlci *dlci)
if (debug & DBG_ERRORS)
pr_debug("DLCI %d goes open.\n", dlci->addr);
/* Send current modem state */
if (dlci->addr)
if (dlci->addr) {
gsm_modem_update(dlci, 0);
} else {
/* Start keep-alive control */
gsm->ka_num = 0;
gsm->ka_retries = -1;
mod_timer(&gsm->ka_timer,
jiffies + gsm->keep_alive * HZ / 100);
}
gsm_dlci_data_kick(dlci);
wake_up(&dlci->gsm->event);
}
@ -2267,6 +2339,7 @@ static void gsm_dlci_begin_close(struct gsm_dlci *dlci)
dlci->state = DLCI_CLOSING;
gsm_command(dlci->gsm, dlci->addr, DISC|PF);
mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
wake_up_interruptible(&gsm->event);
}
/**
@ -2840,6 +2913,7 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm, bool disc)
/* Finish outstanding timers, making sure they are done */
del_timer_sync(&gsm->kick_timer);
del_timer_sync(&gsm->t2_timer);
del_timer_sync(&gsm->ka_timer);
/* Finish writing to ldisc */
flush_work(&gsm->tx_work);
@ -2987,6 +3061,7 @@ static struct gsm_mux *gsm_alloc_mux(void)
INIT_LIST_HEAD(&gsm->tx_data_list);
timer_setup(&gsm->kick_timer, gsm_kick_timer, 0);
timer_setup(&gsm->t2_timer, gsm_control_retransmit, 0);
timer_setup(&gsm->ka_timer, gsm_control_keep_alive, 0);
INIT_WORK(&gsm->tx_work, gsmld_write_task);
init_waitqueue_head(&gsm->event);
spin_lock_init(&gsm->control_lock);
@ -3003,6 +3078,7 @@ static struct gsm_mux *gsm_alloc_mux(void)
gsm->mru = 64; /* Default to encoding 1 so these should be 64 */
gsm->mtu = 64;
gsm->dead = true; /* Avoid early tty opens */
gsm->keep_alive = 0; /* Disabled */
/* Store the instance to the mux array or abort if no space is
* available.
@ -3138,6 +3214,29 @@ static int gsm_config(struct gsm_mux *gsm, struct gsm_config *c)
return 0;
}
static void gsm_copy_config_ext_values(struct gsm_mux *gsm,
struct gsm_config_ext *ce)
{
memset(ce, 0, sizeof(*ce));
ce->keep_alive = gsm->keep_alive;
}
static int gsm_config_ext(struct gsm_mux *gsm, struct gsm_config_ext *ce)
{
unsigned int i;
/*
* Check that userspace doesn't put stuff in here to prevent breakages
* in the future.
*/
for (i = 0; i < ARRAY_SIZE(ce->reserved); i++)
if (ce->reserved[i])
return -EINVAL;
gsm->keep_alive = ce->keep_alive;
return 0;
}
/**
* gsmld_output - write to link
* @gsm: our mux
@ -3456,6 +3555,7 @@ static int gsmld_ioctl(struct tty_struct *tty, unsigned int cmd,
unsigned long arg)
{
struct gsm_config c;
struct gsm_config_ext ce;
struct gsm_mux *gsm = tty->disc_data;
unsigned int base;
@ -3472,6 +3572,15 @@ static int gsmld_ioctl(struct tty_struct *tty, unsigned int cmd,
case GSMIOC_GETFIRST:
base = mux_num_to_base(gsm);
return put_user(base + 1, (__u32 __user *)arg);
case GSMIOC_GETCONF_EXT:
gsm_copy_config_ext_values(gsm, &ce);
if (copy_to_user((void __user *)arg, &ce, sizeof(ce)))
return -EFAULT;
return 0;
case GSMIOC_SETCONF_EXT:
if (copy_from_user(&ce, (void __user *)arg, sizeof(ce)))
return -EFAULT;
return gsm_config_ext(gsm, &ce);
default:
return n_tty_ioctl_helper(tty, cmd, arg);
}
@ -3770,16 +3879,43 @@ static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk)
return -EPROTONOSUPPORT;
}
static int gsm_carrier_raised(struct tty_port *port)
/**
* gsm_wait_modem_change - wait for modem status line change
* @dlci: channel
* @mask: modem status line bits
*
* The function returns if:
* - any given modem status line bit changed
* - the wait event function got interrupted (e.g. by a signal)
* - the underlying DLCI was closed
* - the underlying ldisc device was removed
*/
static int gsm_wait_modem_change(struct gsm_dlci *dlci, u32 mask)
{
struct gsm_mux *gsm = dlci->gsm;
u32 old = dlci->modem_rx;
int ret;
ret = wait_event_interruptible(gsm->event, gsm->dead ||
dlci->state != DLCI_OPEN ||
(old ^ dlci->modem_rx) & mask);
if (gsm->dead)
return -ENODEV;
if (dlci->state != DLCI_OPEN)
return -EL2NSYNC;
return ret;
}
static bool gsm_carrier_raised(struct tty_port *port)
{
struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port);
struct gsm_mux *gsm = dlci->gsm;
/* Not yet open so no carrier info */
if (dlci->state != DLCI_OPEN)
return 0;
return false;
if (debug & DBG_CD_ON)
return 1;
return true;
/*
* Basic mode with control channel in ADM mode may not respond
@ -3787,16 +3923,16 @@ static int gsm_carrier_raised(struct tty_port *port)
*/
if (gsm->encoding == GSM_BASIC_OPT &&
gsm->dlci[0]->mode == DLCI_MODE_ADM && !dlci->modem_rx)
return 1;
return true;
return dlci->modem_rx & TIOCM_CD;
}
static void gsm_dtr_rts(struct tty_port *port, int onoff)
static void gsm_dtr_rts(struct tty_port *port, bool active)
{
struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port);
unsigned int modem_tx = dlci->modem_tx;
if (onoff)
if (active)
modem_tx |= TIOCM_DTR | TIOCM_RTS;
else
modem_tx &= ~(TIOCM_DTR | TIOCM_RTS);
@ -3880,7 +4016,7 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp)
dlci->modem_rx = 0;
/* We could in theory open and close before we wait - eg if we get
a DM straight back. This is ok as that will have caused a hangup */
tty_port_set_initialized(port, 1);
tty_port_set_initialized(port, true);
/* Start sending off SABM messages */
if (gsm->initiator)
gsm_dlci_begin_open(dlci);
@ -4029,6 +4165,8 @@ static int gsmtty_ioctl(struct tty_struct *tty,
gsm_destroy_network(dlci);
mutex_unlock(&dlci->mutex);
return 0;
case TIOCMIWAIT:
return gsm_wait_modem_change(dlci, (u32)arg);
default:
return -ENOIOCTLCMD;
}

View File

@ -0,0 +1,167 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Driver for FPGA UART
*
* Copyright (C) 2022 Intel Corporation.
*
* Authors:
* Ananda Ravuri <ananda.ravuri@intel.com>
* Matthew Gerlach <matthew.gerlach@linux.intel.com>
*/
#include <linux/bitfield.h>
#include <linux/device.h>
#include <linux/dfl.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/types.h>
#include <linux/serial.h>
#include <linux/serial_8250.h>
#define DFHv1_PARAM_ID_CLK_FRQ 0x2
#define DFHv1_PARAM_ID_FIFO_LEN 0x3
#define DFHv1_PARAM_ID_REG_LAYOUT 0x4
#define DFHv1_PARAM_REG_LAYOUT_WIDTH GENMASK_ULL(63, 32)
#define DFHv1_PARAM_REG_LAYOUT_SHIFT GENMASK_ULL(31, 0)
struct dfl_uart {
int line;
};
static int dfh_get_u64_param_val(struct dfl_device *dfl_dev, int param_id, u64 *pval)
{
size_t psize;
u64 *p;
p = dfh_find_param(dfl_dev, param_id, &psize);
if (IS_ERR(p))
return PTR_ERR(p);
if (psize != sizeof(*pval))
return -EINVAL;
*pval = *p;
return 0;
}
static int dfl_uart_get_params(struct dfl_device *dfl_dev, struct uart_8250_port *uart)
{
struct device *dev = &dfl_dev->dev;
u64 fifo_len, clk_freq, reg_layout;
u32 reg_width;
int ret;
ret = dfh_get_u64_param_val(dfl_dev, DFHv1_PARAM_ID_CLK_FRQ, &clk_freq);
if (ret)
return dev_err_probe(dev, ret, "missing CLK_FRQ param\n");
uart->port.uartclk = clk_freq;
ret = dfh_get_u64_param_val(dfl_dev, DFHv1_PARAM_ID_FIFO_LEN, &fifo_len);
if (ret)
return dev_err_probe(dev, ret, "missing FIFO_LEN param\n");
switch (fifo_len) {
case 32:
uart->port.type = PORT_ALTR_16550_F32;
break;
case 64:
uart->port.type = PORT_ALTR_16550_F64;
break;
case 128:
uart->port.type = PORT_ALTR_16550_F128;
break;
default:
return dev_err_probe(dev, -EINVAL, "unsupported FIFO_LEN %llu\n", fifo_len);
}
ret = dfh_get_u64_param_val(dfl_dev, DFHv1_PARAM_ID_REG_LAYOUT, &reg_layout);
if (ret)
return dev_err_probe(dev, ret, "missing REG_LAYOUT param\n");
uart->port.regshift = FIELD_GET(DFHv1_PARAM_REG_LAYOUT_SHIFT, reg_layout);
reg_width = FIELD_GET(DFHv1_PARAM_REG_LAYOUT_WIDTH, reg_layout);
switch (reg_width) {
case 4:
uart->port.iotype = UPIO_MEM32;
break;
case 2:
uart->port.iotype = UPIO_MEM16;
break;
default:
return dev_err_probe(dev, -EINVAL, "unsupported reg-width %u\n", reg_width);
}
return 0;
}
static int dfl_uart_probe(struct dfl_device *dfl_dev)
{
struct device *dev = &dfl_dev->dev;
struct uart_8250_port uart = { };
struct dfl_uart *dfluart;
int ret;
uart.port.flags = UPF_IOREMAP;
uart.port.mapbase = dfl_dev->mmio_res.start;
uart.port.mapsize = resource_size(&dfl_dev->mmio_res);
ret = dfl_uart_get_params(dfl_dev, &uart);
if (ret < 0)
return dev_err_probe(dev, ret, "failed uart feature walk\n");
if (dfl_dev->num_irqs == 1)
uart.port.irq = dfl_dev->irqs[0];
dfluart = devm_kzalloc(dev, sizeof(*dfluart), GFP_KERNEL);
if (!dfluart)
return -ENOMEM;
dfluart->line = serial8250_register_8250_port(&uart);
if (dfluart->line < 0)
return dev_err_probe(dev, dfluart->line, "unable to register 8250 port.\n");
dev_set_drvdata(dev, dfluart);
return 0;
}
static void dfl_uart_remove(struct dfl_device *dfl_dev)
{
struct dfl_uart *dfluart = dev_get_drvdata(&dfl_dev->dev);
serial8250_unregister_port(dfluart->line);
}
#define FME_FEATURE_ID_UART 0x24
static const struct dfl_device_id dfl_uart_ids[] = {
{ FME_ID, FME_FEATURE_ID_UART },
{ }
};
MODULE_DEVICE_TABLE(dfl, dfl_uart_ids);
static struct dfl_driver dfl_uart_driver = {
.drv = {
.name = "dfl-uart",
},
.id_table = dfl_uart_ids,
.probe = dfl_uart_probe,
.remove = dfl_uart_remove,
};
module_dfl_driver(dfl_uart_driver);
MODULE_DESCRIPTION("DFL Intel UART driver");
MODULE_AUTHOR("Intel Corporation");
MODULE_LICENSE("GPL");

View File

@ -136,11 +136,11 @@ static void __init init_port(struct earlycon_device *device)
unsigned char c;
unsigned int ier;
serial8250_early_out(port, UART_LCR, 0x3); /* 8n1 */
serial8250_early_out(port, UART_LCR, UART_LCR_WLEN8); /* 8n1 */
ier = serial8250_early_in(port, UART_IER);
serial8250_early_out(port, UART_IER, ier & UART_IER_UUE); /* no interrupt */
serial8250_early_out(port, UART_FCR, 0); /* no fifo */
serial8250_early_out(port, UART_MCR, 0x3); /* DTR + RTS */
serial8250_early_out(port, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
if (port->uartclk) {
divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * device->baud);

View File

@ -24,6 +24,7 @@
#include <asm/io.h>
#include "8250.h"
#include "8250_pcilib.h"
/*
* init function returns:
@ -89,28 +90,7 @@ static int
setup_port(struct serial_private *priv, struct uart_8250_port *port,
u8 bar, unsigned int offset, int regshift)
{
struct pci_dev *dev = priv->dev;
if (bar >= PCI_STD_NUM_BARS)
return -EINVAL;
if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) {
if (!pcim_iomap(dev, bar, 0) && !pcim_iomap_table(dev))
return -ENOMEM;
port->port.iotype = UPIO_MEM;
port->port.iobase = 0;
port->port.mapbase = pci_resource_start(dev, bar) + offset;
port->port.membase = pcim_iomap_table(dev)[bar] + offset;
port->port.regshift = regshift;
} else {
port->port.iotype = UPIO_PORT;
port->port.iobase = pci_resource_start(dev, bar) + offset;
port->port.mapbase = 0;
port->port.membase = NULL;
port->port.regshift = 0;
}
return 0;
return serial8250_pci_setup_port(priv->dev, port, bar, offset, regshift);
}
/*
@ -5757,3 +5737,4 @@ module_pci_driver(serial_pci_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Generic 8250/16x50 PCI serial probe module");
MODULE_DEVICE_TABLE(pci, serial_pci_tbl);
MODULE_IMPORT_NS(SERIAL_8250_PCI);

View File

@ -0,0 +1,494 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Probe module for 8250/16550-type MCHP PCI serial ports.
*
* Based on drivers/tty/serial/8250/8250_pci.c,
*
* Copyright (C) 2022 Microchip Technology Inc., All Rights Reserved.
*/
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/serial_core.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/units.h>
#include <linux/tty.h>
#include <asm/byteorder.h>
#include "8250.h"
#include "8250_pcilib.h"
#define PCI_DEVICE_ID_EFAR_PCI12000 0xa002
#define PCI_DEVICE_ID_EFAR_PCI11010 0xa012
#define PCI_DEVICE_ID_EFAR_PCI11101 0xa022
#define PCI_DEVICE_ID_EFAR_PCI11400 0xa032
#define PCI_DEVICE_ID_EFAR_PCI11414 0xa042
#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_4p 0x0001
#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p012 0x0002
#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p013 0x0003
#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p023 0x0004
#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p123 0x0005
#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p01 0x0006
#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p02 0x0007
#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p03 0x0008
#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p12 0x0009
#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p13 0x000a
#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p23 0x000b
#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p0 0x000c
#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p1 0x000d
#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p2 0x000e
#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p3 0x000f
#define PCI_SUBDEVICE_ID_EFAR_PCI12000 PCI_DEVICE_ID_EFAR_PCI12000
#define PCI_SUBDEVICE_ID_EFAR_PCI11010 PCI_DEVICE_ID_EFAR_PCI11010
#define PCI_SUBDEVICE_ID_EFAR_PCI11101 PCI_DEVICE_ID_EFAR_PCI11101
#define PCI_SUBDEVICE_ID_EFAR_PCI11400 PCI_DEVICE_ID_EFAR_PCI11400
#define PCI_SUBDEVICE_ID_EFAR_PCI11414 PCI_DEVICE_ID_EFAR_PCI11414
#define UART_ACTV_REG 0x11
#define UART_BLOCK_SET_ACTIVE BIT(0)
#define UART_PCI_CTRL_REG 0x80
#define UART_PCI_CTRL_SET_MULTIPLE_MSI BIT(4)
#define UART_PCI_CTRL_D3_CLK_ENABLE BIT(0)
#define ADCL_CFG_REG 0x40
#define ADCL_CFG_POL_SEL BIT(2)
#define ADCL_CFG_PIN_SEL BIT(1)
#define ADCL_CFG_EN BIT(0)
#define UART_BIT_SAMPLE_CNT 16
#define BAUD_CLOCK_DIV_INT_MSK GENMASK(31, 8)
#define ADCL_CFG_RTS_DELAY_MASK GENMASK(11, 8)
#define UART_CLOCK_DEFAULT (62500 * HZ_PER_KHZ)
#define UART_WAKE_REG 0x8C
#define UART_WAKE_MASK_REG 0x90
#define UART_WAKE_N_PIN BIT(2)
#define UART_WAKE_NCTS BIT(1)
#define UART_WAKE_INT BIT(0)
#define UART_WAKE_SRCS \
(UART_WAKE_N_PIN | UART_WAKE_NCTS | UART_WAKE_INT)
#define UART_BAUD_CLK_DIVISOR_REG 0x54
#define UART_RESET_REG 0x94
#define UART_RESET_D3_RESET_DISABLE BIT(16)
#define MAX_PORTS 4
#define PORT_OFFSET 0x100
static const int logical_to_physical_port_idx[][MAX_PORTS] = {
{0, 1, 2, 3}, /* PCI12000, PCI11010, PCI11101, PCI11400, PCI11414 */
{0, 1, 2, 3}, /* PCI4p */
{0, 1, 2, -1}, /* PCI3p012 */
{0, 1, 3, -1}, /* PCI3p013 */
{0, 2, 3, -1}, /* PCI3p023 */
{1, 2, 3, -1}, /* PCI3p123 */
{0, 1, -1, -1}, /* PCI2p01 */
{0, 2, -1, -1}, /* PCI2p02 */
{0, 3, -1, -1}, /* PCI2p03 */
{1, 2, -1, -1}, /* PCI2p12 */
{1, 3, -1, -1}, /* PCI2p13 */
{2, 3, -1, -1}, /* PCI2p23 */
{0, -1, -1, -1}, /* PCI1p0 */
{1, -1, -1, -1}, /* PCI1p1 */
{2, -1, -1, -1}, /* PCI1p2 */
{3, -1, -1, -1}, /* PCI1p3 */
};
struct pci1xxxx_8250 {
unsigned int nr;
void __iomem *membase;
int line[];
};
static int pci1xxxx_get_num_ports(struct pci_dev *dev)
{
switch (dev->subsystem_device) {
case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p0:
case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p1:
case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p2:
case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p3:
case PCI_SUBDEVICE_ID_EFAR_PCI12000:
case PCI_SUBDEVICE_ID_EFAR_PCI11010:
case PCI_SUBDEVICE_ID_EFAR_PCI11101:
case PCI_SUBDEVICE_ID_EFAR_PCI11400:
default:
return 1;
case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p01:
case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p02:
case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p03:
case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p12:
case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p13:
case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p23:
return 2;
case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p012:
case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p123:
case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p013:
case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p023:
return 3;
case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_4p:
case PCI_SUBDEVICE_ID_EFAR_PCI11414:
return 4;
}
}
static unsigned int pci1xxxx_get_divisor(struct uart_port *port,
unsigned int baud, unsigned int *frac)
{
unsigned int quot;
/*
* Calculate baud rate sampling period in nanoseconds.
* Fractional part x denotes x/255 parts of a nanosecond.
*/
quot = NSEC_PER_SEC / (baud * UART_BIT_SAMPLE_CNT);
*frac = (NSEC_PER_SEC - quot * baud * UART_BIT_SAMPLE_CNT) *
255 / UART_BIT_SAMPLE_CNT / baud;
return quot;
}
static void pci1xxxx_set_divisor(struct uart_port *port, unsigned int baud,
unsigned int quot, unsigned int frac)
{
writel(FIELD_PREP(BAUD_CLOCK_DIV_INT_MSK, quot) | frac,
port->membase + UART_BAUD_CLK_DIVISOR_REG);
}
static int pci1xxxx_rs485_config(struct uart_port *port,
struct ktermios *termios,
struct serial_rs485 *rs485)
{
u32 delay_in_baud_periods;
u32 baud_period_in_ns;
u32 mode_cfg = 0;
u32 clock_div;
/*
* pci1xxxx's uart hardware supports only RTS delay after
* Tx and in units of bit times to a maximum of 15
*/
if (rs485->flags & SER_RS485_ENABLED) {
mode_cfg = ADCL_CFG_EN | ADCL_CFG_PIN_SEL;
if (!(rs485->flags & SER_RS485_RTS_ON_SEND))
mode_cfg |= ADCL_CFG_POL_SEL;
if (rs485->delay_rts_after_send) {
clock_div = readl(port->membase + UART_BAUD_CLK_DIVISOR_REG);
baud_period_in_ns =
FIELD_GET(BAUD_CLOCK_DIV_INT_MSK, clock_div) *
UART_BIT_SAMPLE_CNT;
delay_in_baud_periods =
rs485->delay_rts_after_send * NSEC_PER_MSEC /
baud_period_in_ns;
delay_in_baud_periods =
min_t(u32, delay_in_baud_periods,
FIELD_MAX(ADCL_CFG_RTS_DELAY_MASK));
mode_cfg |= FIELD_PREP(ADCL_CFG_RTS_DELAY_MASK,
delay_in_baud_periods);
rs485->delay_rts_after_send =
baud_period_in_ns * delay_in_baud_periods /
NSEC_PER_MSEC;
}
}
writel(mode_cfg, port->membase + ADCL_CFG_REG);
return 0;
}
static const struct serial_rs485 pci1xxxx_rs485_supported = {
.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
SER_RS485_RTS_AFTER_SEND,
.delay_rts_after_send = 1,
/* Delay RTS before send is not supported */
};
static bool pci1xxxx_port_suspend(int line)
{
struct uart_8250_port *up = serial8250_get_port(line);
struct uart_port *port = &up->port;
struct tty_port *tport = &port->state->port;
unsigned long flags;
bool ret = false;
u8 wakeup_mask;
mutex_lock(&tport->mutex);
if (port->suspended == 0 && port->dev) {
wakeup_mask = readb(up->port.membase + UART_WAKE_MASK_REG);
spin_lock_irqsave(&port->lock, flags);
port->mctrl &= ~TIOCM_OUT2;
port->ops->set_mctrl(port, port->mctrl);
spin_unlock_irqrestore(&port->lock, flags);
ret = (wakeup_mask & UART_WAKE_SRCS) != UART_WAKE_SRCS;
}
writeb(UART_WAKE_SRCS, port->membase + UART_WAKE_REG);
mutex_unlock(&tport->mutex);
return ret;
}
static void pci1xxxx_port_resume(int line)
{
struct uart_8250_port *up = serial8250_get_port(line);
struct uart_port *port = &up->port;
struct tty_port *tport = &port->state->port;
unsigned long flags;
mutex_lock(&tport->mutex);
writeb(UART_BLOCK_SET_ACTIVE, port->membase + UART_ACTV_REG);
writeb(UART_WAKE_SRCS, port->membase + UART_WAKE_REG);
if (port->suspended == 0) {
spin_lock_irqsave(&port->lock, flags);
port->mctrl |= TIOCM_OUT2;
port->ops->set_mctrl(port, port->mctrl);
spin_unlock_irqrestore(&port->lock, flags);
}
mutex_unlock(&tport->mutex);
}
static int pci1xxxx_suspend(struct device *dev)
{
struct pci1xxxx_8250 *priv = dev_get_drvdata(dev);
struct pci_dev *pcidev = to_pci_dev(dev);
bool wakeup = false;
unsigned int data;
void __iomem *p;
int i;
for (i = 0; i < priv->nr; i++) {
if (priv->line[i] >= 0) {
serial8250_suspend_port(priv->line[i]);
wakeup |= pci1xxxx_port_suspend(priv->line[i]);
}
}
p = pci_ioremap_bar(pcidev, 0);
if (!p) {
dev_err(dev, "remapping of bar 0 memory failed");
return -ENOMEM;
}
data = readl(p + UART_RESET_REG);
writel(data | UART_RESET_D3_RESET_DISABLE, p + UART_RESET_REG);
if (wakeup)
writeb(UART_PCI_CTRL_D3_CLK_ENABLE, p + UART_PCI_CTRL_REG);
iounmap(p);
device_set_wakeup_enable(dev, true);
pci_wake_from_d3(pcidev, true);
return 0;
}
static int pci1xxxx_resume(struct device *dev)
{
struct pci1xxxx_8250 *priv = dev_get_drvdata(dev);
struct pci_dev *pcidev = to_pci_dev(dev);
unsigned int data;
void __iomem *p;
int i;
p = pci_ioremap_bar(pcidev, 0);
if (!p) {
dev_err(dev, "remapping of bar 0 memory failed");
return -ENOMEM;
}
data = readl(p + UART_RESET_REG);
writel(data & ~UART_RESET_D3_RESET_DISABLE, p + UART_RESET_REG);
iounmap(p);
for (i = 0; i < priv->nr; i++) {
if (priv->line[i] >= 0) {
pci1xxxx_port_resume(priv->line[i]);
serial8250_resume_port(priv->line[i]);
}
}
return 0;
}
static int pci1xxxx_setup(struct pci_dev *pdev,
struct uart_8250_port *port, int port_idx)
{
int ret;
port->port.flags |= UPF_FIXED_TYPE | UPF_SKIP_TEST;
port->port.type = PORT_MCHP16550A;
port->port.set_termios = serial8250_do_set_termios;
port->port.get_divisor = pci1xxxx_get_divisor;
port->port.set_divisor = pci1xxxx_set_divisor;
port->port.rs485_config = pci1xxxx_rs485_config;
port->port.rs485_supported = pci1xxxx_rs485_supported;
ret = serial8250_pci_setup_port(pdev, port, 0, PORT_OFFSET * port_idx, 0);
if (ret < 0)
return ret;
writeb(UART_BLOCK_SET_ACTIVE, port->port.membase + UART_ACTV_REG);
writeb(UART_WAKE_SRCS, port->port.membase + UART_WAKE_REG);
writeb(UART_WAKE_N_PIN, port->port.membase + UART_WAKE_MASK_REG);
return 0;
}
static unsigned int pci1xxxx_get_max_port(int subsys_dev)
{
unsigned int i = MAX_PORTS;
if (subsys_dev < ARRAY_SIZE(logical_to_physical_port_idx))
while (i--) {
if (logical_to_physical_port_idx[subsys_dev][i] != -1)
return logical_to_physical_port_idx[subsys_dev][i] + 1;
}
if (subsys_dev == PCI_SUBDEVICE_ID_EFAR_PCI11414)
return 4;
return 1;
}
static int pci1xxxx_logical_to_physical_port_translate(int subsys_dev, int port)
{
if (subsys_dev < ARRAY_SIZE(logical_to_physical_port_idx))
return logical_to_physical_port_idx[subsys_dev][port];
return logical_to_physical_port_idx[0][port];
}
static int pci1xxxx_serial_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
struct device *dev = &pdev->dev;
struct pci1xxxx_8250 *priv;
struct uart_8250_port uart;
unsigned int max_vec_reqd;
unsigned int nr_ports, i;
int num_vectors;
int subsys_dev;
int port_idx;
int rc;
rc = pcim_enable_device(pdev);
if (rc)
return rc;
nr_ports = pci1xxxx_get_num_ports(pdev);
priv = devm_kzalloc(dev, struct_size(priv, line, nr_ports), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->membase = pci_ioremap_bar(pdev, 0);
if (!priv->membase)
return -ENOMEM;
pci_set_master(pdev);
priv->nr = nr_ports;
subsys_dev = pdev->subsystem_device;
max_vec_reqd = pci1xxxx_get_max_port(subsys_dev);
num_vectors = pci_alloc_irq_vectors(pdev, 1, max_vec_reqd, PCI_IRQ_ALL_TYPES);
if (num_vectors < 0) {
pci_iounmap(pdev, priv->membase);
return num_vectors;
}
memset(&uart, 0, sizeof(uart));
uart.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT;
uart.port.uartclk = UART_CLOCK_DEFAULT;
uart.port.dev = dev;
if (num_vectors == max_vec_reqd)
writeb(UART_PCI_CTRL_SET_MULTIPLE_MSI, priv->membase + UART_PCI_CTRL_REG);
for (i = 0; i < nr_ports; i++) {
priv->line[i] = -ENODEV;
port_idx = pci1xxxx_logical_to_physical_port_translate(subsys_dev, i);
if (num_vectors == max_vec_reqd)
uart.port.irq = pci_irq_vector(pdev, port_idx);
else
uart.port.irq = pci_irq_vector(pdev, 0);
rc = pci1xxxx_setup(pdev, &uart, port_idx);
if (rc) {
dev_warn(dev, "Failed to setup port %u\n", i);
continue;
}
priv->line[i] = serial8250_register_8250_port(&uart);
if (priv->line[i] < 0) {
dev_warn(dev,
"Couldn't register serial port %lx, irq %d, type %d, error %d\n",
uart.port.iobase, uart.port.irq, uart.port.iotype,
priv->line[i]);
}
}
pci_set_drvdata(pdev, priv);
return 0;
}
static void pci1xxxx_serial_remove(struct pci_dev *dev)
{
struct pci1xxxx_8250 *priv = pci_get_drvdata(dev);
unsigned int i;
for (i = 0; i < priv->nr; i++) {
if (priv->line[i] >= 0)
serial8250_unregister_port(priv->line[i]);
}
pci_free_irq_vectors(dev);
pci_iounmap(dev, priv->membase);
}
static DEFINE_SIMPLE_DEV_PM_OPS(pci1xxxx_pm_ops, pci1xxxx_suspend, pci1xxxx_resume);
static const struct pci_device_id pci1xxxx_pci_tbl[] = {
{ PCI_VDEVICE(EFAR, PCI_DEVICE_ID_EFAR_PCI11010) },
{ PCI_VDEVICE(EFAR, PCI_DEVICE_ID_EFAR_PCI11101) },
{ PCI_VDEVICE(EFAR, PCI_DEVICE_ID_EFAR_PCI11400) },
{ PCI_VDEVICE(EFAR, PCI_DEVICE_ID_EFAR_PCI11414) },
{ PCI_VDEVICE(EFAR, PCI_DEVICE_ID_EFAR_PCI12000) },
{}
};
MODULE_DEVICE_TABLE(pci, pci1xxxx_pci_tbl);
static struct pci_driver pci1xxxx_pci_driver = {
.name = "pci1xxxx serial",
.probe = pci1xxxx_serial_probe,
.remove = pci1xxxx_serial_remove,
.driver = {
.pm = pm_sleep_ptr(&pci1xxxx_pm_ops),
},
.id_table = pci1xxxx_pci_tbl,
};
module_pci_driver(pci1xxxx_pci_driver);
static_assert((ARRAY_SIZE(logical_to_physical_port_idx) == PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p3 + 1));
MODULE_IMPORT_NS(SERIAL_8250_PCI);
MODULE_DESCRIPTION("Microchip Technology Inc. PCIe to UART module");
MODULE_AUTHOR("Kumaravel Thiagarajan <kumaravel.thiagarajan@microchip.com>");
MODULE_AUTHOR("Tharun Kumar P <tharunkumar.pasumarthi@microchip.com>");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,40 @@
// SPDX-License-Identifier: GPL-2.0
/*
* 8250 PCI library.
*
* Copyright (C) 2001 Russell King, All Rights Reserved.
*/
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/types.h>
#include "8250.h"
#include "8250_pcilib.h"
int serial8250_pci_setup_port(struct pci_dev *dev, struct uart_8250_port *port,
u8 bar, unsigned int offset, int regshift)
{
if (bar >= PCI_STD_NUM_BARS)
return -EINVAL;
if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) {
if (!pcim_iomap(dev, bar, 0) && !pcim_iomap_table(dev))
return -ENOMEM;
port->port.iotype = UPIO_MEM;
port->port.iobase = 0;
port->port.mapbase = pci_resource_start(dev, bar) + offset;
port->port.membase = pcim_iomap_table(dev)[bar] + offset;
port->port.regshift = regshift;
} else {
port->port.iotype = UPIO_PORT;
port->port.iobase = pci_resource_start(dev, bar) + offset;
port->port.mapbase = 0;
port->port.membase = NULL;
port->port.regshift = 0;
}
return 0;
}
EXPORT_SYMBOL_NS_GPL(serial8250_pci_setup_port, SERIAL_8250_PCI);
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,15 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* 8250 PCI library header file.
*
* Copyright (C) 2001 Russell King, All Rights Reserved.
*/
#include <linux/types.h>
struct pci_dev;
struct uart_8250_port;
int serial8250_pci_setup_port(struct pci_dev *dev, struct uart_8250_port *port, u8 bar,
unsigned int offset, int regshift);

View File

@ -313,6 +313,14 @@ static const struct serial8250_config uart_config[] = {
.rxtrig_bytes = {1, 4, 8, 14},
.flags = UART_CAP_FIFO,
},
[PORT_MCHP16550A] = {
.name = "MCHP16550A",
.fifo_size = 256,
.tx_loadsz = 256,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01,
.rxtrig_bytes = {2, 66, 130, 194},
.flags = UART_CAP_FIFO,
},
};
/* Uart divisor latch read */
@ -1050,11 +1058,12 @@ static void autoconfig_16550a(struct uart_8250_port *up)
serial_out(up, UART_LCR, 0);
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
UART_FCR7_64BYTE);
status1 = serial_in(up, UART_IIR) >> 5;
status1 = serial_in(up, UART_IIR) & (UART_IIR_64BYTE_FIFO |
UART_IIR_FIFO_ENABLED);
serial_out(up, UART_FCR, 0);
serial_out(up, UART_LCR, 0);
if (status1 == 7)
if (status1 == (UART_IIR_64BYTE_FIFO | UART_IIR_FIFO_ENABLED))
up->port.type = PORT_16550A_FSL64;
else
DEBUG_AUTOCONF("Motorola 8xxx DUART ");
@ -1122,17 +1131,20 @@ static void autoconfig_16550a(struct uart_8250_port *up)
*/
serial_out(up, UART_LCR, 0);
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
status1 = serial_in(up, UART_IIR) >> 5;
status1 = serial_in(up, UART_IIR) & (UART_IIR_64BYTE_FIFO | UART_IIR_FIFO_ENABLED);
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
status2 = serial_in(up, UART_IIR) >> 5;
status2 = serial_in(up, UART_IIR) & (UART_IIR_64BYTE_FIFO | UART_IIR_FIFO_ENABLED);
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
serial_out(up, UART_LCR, 0);
DEBUG_AUTOCONF("iir1=%d iir2=%d ", status1, status2);
if (status1 == 6 && status2 == 7) {
if (status1 == UART_IIR_FIFO_ENABLED_16550A &&
status2 == (UART_IIR_64BYTE_FIFO | UART_IIR_FIFO_ENABLED_16550A)) {
up->port.type = PORT_16750;
up->capabilities |= UART_CAP_AFE | UART_CAP_SLEEP;
return;
@ -1236,14 +1248,14 @@ static void autoconfig(struct uart_8250_port *up)
* Mask out IER[7:4] bits for test as some UARTs (e.g. TL
* 16C754B) allow only to modify them if an EFR bit is set.
*/
scratch2 = serial_in(up, UART_IER) & 0x0f;
serial_out(up, UART_IER, 0x0F);
scratch2 = serial_in(up, UART_IER) & UART_IER_ALL_INTR;
serial_out(up, UART_IER, UART_IER_ALL_INTR);
#ifdef __i386__
outb(0, 0x080);
#endif
scratch3 = serial_in(up, UART_IER) & 0x0f;
scratch3 = serial_in(up, UART_IER) & UART_IER_ALL_INTR;
serial_out(up, UART_IER, scratch);
if (scratch2 != 0 || scratch3 != 0x0F) {
if (scratch2 != 0 || scratch3 != UART_IER_ALL_INTR) {
/*
* We failed; there's nothing here
*/
@ -1267,10 +1279,10 @@ static void autoconfig(struct uart_8250_port *up)
* that conflicts with COM 1-4 --- we hope!
*/
if (!(port->flags & UPF_SKIP_TEST)) {
serial8250_out_MCR(up, UART_MCR_LOOP | 0x0A);
status1 = serial_in(up, UART_MSR) & 0xF0;
serial8250_out_MCR(up, UART_MCR_LOOP | UART_MCR_OUT2 | UART_MCR_RTS);
status1 = serial_in(up, UART_MSR) & UART_MSR_STATUS_BITS;
serial8250_out_MCR(up, save_mcr);
if (status1 != 0x90) {
if (status1 != (UART_MSR_DCD | UART_MSR_CTS)) {
spin_unlock_irqrestore(&port->lock, flags);
DEBUG_AUTOCONF("LOOP test failed (%02x) ",
status1);
@ -1293,22 +1305,19 @@ static void autoconfig(struct uart_8250_port *up)
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
/* Assign this as it is to truncate any bits above 7. */
scratch = serial_in(up, UART_IIR);
switch (scratch >> 6) {
case 0:
switch (serial_in(up, UART_IIR) & UART_IIR_FIFO_ENABLED) {
case UART_IIR_FIFO_ENABLED_8250:
autoconfig_8250(up);
break;
case 1:
port->type = PORT_UNKNOWN;
break;
case 2:
case UART_IIR_FIFO_ENABLED_16550:
port->type = PORT_16550;
break;
case 3:
case UART_IIR_FIFO_ENABLED_16550A:
autoconfig_16550a(up);
break;
default:
port->type = PORT_UNKNOWN;
break;
}
#ifdef CONFIG_SERIAL_8250_RSA
@ -1394,7 +1403,7 @@ static void autoconfig_irq(struct uart_8250_port *up)
serial8250_out_MCR(up,
UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
}
serial_out(up, UART_IER, 0x0f); /* enable all intrs */
serial_out(up, UART_IER, UART_IER_ALL_INTR);
serial_in(up, UART_LSR);
serial_in(up, UART_RX);
serial_in(up, UART_IIR);
@ -1511,8 +1520,6 @@ static inline void __stop_tx(struct uart_8250_port *p)
u16 lsr = serial_lsr_in(p);
u64 stop_delay = 0;
p->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
if (!(lsr & UART_LSR_THRE))
return;
/*

View File

@ -129,9 +129,13 @@ config SERIAL_8250_DMA
This builds DMA support that can be used with 8250/16650
compatible UART controllers that support DMA signaling.
config SERIAL_8250_PCILIB
bool
config SERIAL_8250_PCI
tristate "8250/16550 PCI device support"
depends on SERIAL_8250 && PCI
select SERIAL_8250_PCILIB
default SERIAL_8250
help
This builds standard PCI serial support. You may be able to
@ -291,6 +295,17 @@ config SERIAL_8250_HUB6
To compile this driver as a module, choose M here: the module
will be called 8250_hub6.
config SERIAL_8250_PCI1XXXX
tristate "Microchip 8250 based serial port"
depends on SERIAL_8250 && PCI
select SERIAL_8250_PCILIB
default SERIAL_8250
help
Select this option if you have a setup with Microchip PCIe
Switch with serial port enabled and wish to enable 8250
serial driver for the serial interface. This driver support
will ensure to support baud rates upto 1.5Mpbs.
#
# Misc. options/drivers.
#
@ -370,6 +385,18 @@ config SERIAL_8250_FSL
erratum for Freescale 16550 UARTs in the 8250 driver. It also
enables support for ACPI enumeration.
config SERIAL_8250_DFL
tristate "DFL bus driver for Altera 16550 UART"
depends on SERIAL_8250 && FPGA_DFL
help
This option enables support for a Device Feature List (DFL) bus
driver for the Altera 16550 UART. One or more Altera 16550 UARTs
can be instantiated in a FPGA and then be discovered during
enumeration of the DFL bus.
To compile this driver as a module, chose M here: the
module will be called 8250_dfl.
config SERIAL_8250_DW
tristate "Support for Synopsys DesignWare 8250 quirks"
depends on SERIAL_8250

View File

@ -12,6 +12,7 @@ obj-$(CONFIG_SERIAL_8250) += 8250.o 8250_base.o
8250_base-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o
8250_base-$(CONFIG_SERIAL_8250_DWLIB) += 8250_dwlib.o
8250_base-$(CONFIG_SERIAL_8250_FINTEK) += 8250_fintek.o
8250_base-$(CONFIG_SERIAL_8250_PCILIB) += 8250_pcilib.o
obj-$(CONFIG_SERIAL_8250_PARISC) += 8250_parisc.o
obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o
obj-$(CONFIG_SERIAL_8250_EXAR) += 8250_exar.o
@ -26,8 +27,10 @@ obj-$(CONFIG_SERIAL_8250_ACCENT) += 8250_accent.o
obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o
obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o
obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
obj-$(CONFIG_SERIAL_8250_PCI1XXXX) += 8250_pci1xxxx.o
obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o
obj-$(CONFIG_SERIAL_8250_MEN_MCB) += 8250_men_mcb.o
obj-$(CONFIG_SERIAL_8250_DFL) += 8250_dfl.o
obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o
obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o
obj-$(CONFIG_SERIAL_8250_IOC3) += 8250_ioc3.o

View File

@ -73,17 +73,17 @@ config SERIAL_AMBA_PL011_CONSOLE
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
config SERIAL_EARLYCON_ARM_SEMIHOST
bool "Early console using ARM semihosting"
depends on ARM64 || ARM
config SERIAL_EARLYCON_SEMIHOST
bool "Early console using Arm compatible semihosting"
depends on ARM64 || ARM || RISCV
select SERIAL_CORE
select SERIAL_CORE_CONSOLE
select SERIAL_EARLYCON
help
Support for early debug console using ARM semihosting. This enables
the console before standard serial driver is probed. This is enabled
with "earlycon=smh" on the kernel command line. The console is
enabled when early_param is processed.
Support for early debug console using Arm compatible semihosting.
This enables the console before standard serial driver is probed.
This is enabled with "earlycon=smh" on the kernel command line.
The console is enabled when early_param is processed.
config SERIAL_EARLYCON_RISCV_SBI
bool "Early console using RISC-V SBI"
@ -1507,7 +1507,7 @@ config SERIAL_MILBEAUT_USIO_CONSOLE
config SERIAL_LITEUART
tristate "LiteUART serial port support"
depends on HAS_IOMEM
depends on OF || COMPILE_TEST
depends on OF
depends on LITEX || COMPILE_TEST
select SERIAL_CORE
help

View File

@ -6,7 +6,7 @@
obj-$(CONFIG_SERIAL_CORE) += serial_core.o
obj-$(CONFIG_SERIAL_EARLYCON) += earlycon.o
obj-$(CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST) += earlycon-arm-semihost.o
obj-$(CONFIG_SERIAL_EARLYCON_SEMIHOST) += earlycon-semihost.o
obj-$(CONFIG_SERIAL_EARLYCON_RISCV_SBI) += earlycon-riscv-sbi.o
# These Sparc drivers have to appear before others such as 8250

View File

@ -11,30 +11,7 @@
#include <linux/console.h>
#include <linux/init.h>
#include <linux/serial_core.h>
#ifdef CONFIG_THUMB2_KERNEL
#define SEMIHOST_SWI "0xab"
#else
#define SEMIHOST_SWI "0x123456"
#endif
/*
* Semihosting-based debug console
*/
static void smh_putc(struct uart_port *port, unsigned char c)
{
#ifdef CONFIG_ARM64
asm volatile("mov x1, %0\n"
"mov x0, #3\n"
"hlt 0xf000\n"
: : "r" (&c) : "x0", "x1", "memory");
#else
asm volatile("mov r1, %0\n"
"mov r0, #3\n"
"svc " SEMIHOST_SWI "\n"
: : "r" (&c) : "r0", "r1", "memory");
#endif
}
#include <asm/semihost.h>
static void smh_write(struct console *con, const char *s, unsigned n)
{

View File

@ -120,7 +120,13 @@ static int __init parse_options(struct earlycon_device *device, char *options)
}
if (options) {
char *uartclk;
device->baud = simple_strtoul(options, NULL, 0);
uartclk = strchr(options, ',');
if (uartclk && kstrtouint(uartclk + 1, 0, &port->uartclk) < 0)
pr_warn("[%s] unsupported earlycon uart clkrate option\n",
options);
length = min(strcspn(options, " ") + 1,
(size_t)(sizeof(device->options)));
strscpy(device->options, options, length);
@ -139,7 +145,8 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match)
buf = NULL;
spin_lock_init(&port->lock);
port->uartclk = BASE_BAUD * 16;
if (!port->uartclk)
port->uartclk = BASE_BAUD * 16;
if (port->mapbase)
port->membase = earlycon_map(port->mapbase, 64);

View File

@ -5,6 +5,8 @@
* Copyright 2012-2014 Freescale Semiconductor, Inc.
*/
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/console.h>
#include <linux/delay.h>
@ -181,7 +183,7 @@
#define UARTCTRL_SBK 0x00010000
#define UARTCTRL_MA1IE 0x00008000
#define UARTCTRL_MA2IE 0x00004000
#define UARTCTRL_IDLECFG 0x00000100
#define UARTCTRL_IDLECFG GENMASK(10, 8)
#define UARTCTRL_LOOPS 0x00000080
#define UARTCTRL_DOZEEN 0x00000040
#define UARTCTRL_RSRC 0x00000020
@ -199,6 +201,7 @@
#define UARTDATA_MASK 0x3ff
#define UARTMODIR_IREN 0x00020000
#define UARTMODIR_RTSWATER GENMASK(10, 8)
#define UARTMODIR_TXCTSSRC 0x00000020
#define UARTMODIR_TXCTSC 0x00000010
#define UARTMODIR_RXRTSE 0x00000008
@ -212,6 +215,7 @@
#define UARTFIFO_RXUF 0x00010000
#define UARTFIFO_TXFLUSH 0x00008000
#define UARTFIFO_RXFLUSH 0x00004000
#define UARTFIFO_RXIDEN GENMASK(12, 10)
#define UARTFIFO_TXOFE 0x00000200
#define UARTFIFO_RXUFE 0x00000100
#define UARTFIFO_TXFE 0x00000080
@ -238,7 +242,7 @@
#define DRIVER_NAME "fsl-lpuart"
#define DEV_NAME "ttyLP"
#define UART_NR 6
#define UART_NR 8
/* IMX lpuart has four extra unused regs located at the beginning */
#define IMX_REG_OFF 0x10
@ -248,6 +252,7 @@ enum lpuart_type {
LS1021A_LPUART,
LS1028A_LPUART,
IMX7ULP_LPUART,
IMX8ULP_LPUART,
IMX8QXP_LPUART,
IMXRT1050_LPUART,
};
@ -260,6 +265,7 @@ struct lpuart_port {
unsigned int txfifo_size;
unsigned int rxfifo_size;
u8 rx_watermark;
bool lpuart_dma_tx_use;
bool lpuart_dma_rx_use;
struct dma_chan *dma_tx_chan;
@ -286,38 +292,52 @@ struct lpuart_soc_data {
enum lpuart_type devtype;
char iotype;
u8 reg_off;
u8 rx_watermark;
};
static const struct lpuart_soc_data vf_data = {
.devtype = VF610_LPUART,
.iotype = UPIO_MEM,
.rx_watermark = 1,
};
static const struct lpuart_soc_data ls1021a_data = {
.devtype = LS1021A_LPUART,
.iotype = UPIO_MEM32BE,
.rx_watermark = 1,
};
static const struct lpuart_soc_data ls1028a_data = {
.devtype = LS1028A_LPUART,
.iotype = UPIO_MEM32,
.rx_watermark = 1,
};
static struct lpuart_soc_data imx7ulp_data = {
.devtype = IMX7ULP_LPUART,
.iotype = UPIO_MEM32,
.reg_off = IMX_REG_OFF,
.rx_watermark = 1,
};
static struct lpuart_soc_data imx8ulp_data = {
.devtype = IMX8ULP_LPUART,
.iotype = UPIO_MEM32,
.reg_off = IMX_REG_OFF,
.rx_watermark = 3,
};
static struct lpuart_soc_data imx8qxp_data = {
.devtype = IMX8QXP_LPUART,
.iotype = UPIO_MEM32,
.reg_off = IMX_REG_OFF,
.rx_watermark = 31,
};
static struct lpuart_soc_data imxrt1050_data = {
.devtype = IMXRT1050_LPUART,
.iotype = UPIO_MEM32,
.reg_off = IMX_REG_OFF,
.rx_watermark = 1,
};
static const struct of_device_id lpuart_dt_ids[] = {
@ -325,6 +345,7 @@ static const struct of_device_id lpuart_dt_ids[] = {
{ .compatible = "fsl,ls1021a-lpuart", .data = &ls1021a_data, },
{ .compatible = "fsl,ls1028a-lpuart", .data = &ls1028a_data, },
{ .compatible = "fsl,imx7ulp-lpuart", .data = &imx7ulp_data, },
{ .compatible = "fsl,imx8ulp-lpuart", .data = &imx8ulp_data, },
{ .compatible = "fsl,imx8qxp-lpuart", .data = &imx8qxp_data, },
{ .compatible = "fsl,imxrt1050-lpuart", .data = &imxrt1050_data},
{ /* sentinel */ }
@ -345,6 +366,11 @@ static inline bool is_imx7ulp_lpuart(struct lpuart_port *sport)
return sport->devtype == IMX7ULP_LPUART;
}
static inline bool is_imx8ulp_lpuart(struct lpuart_port *sport)
{
return sport->devtype == IMX8ULP_LPUART;
}
static inline bool is_imx8qxp_lpuart(struct lpuart_port *sport)
{
return sport->devtype == IMX8QXP_LPUART;
@ -1387,9 +1413,9 @@ static int lpuart32_config_rs485(struct uart_port *port, struct ktermios *termio
* Note: UART is assumed to be active high.
*/
if (rs485->flags & SER_RS485_RTS_ON_SEND)
modem &= ~UARTMODEM_TXRTSPOL;
else if (rs485->flags & SER_RS485_RTS_AFTER_SEND)
modem |= UARTMODEM_TXRTSPOL;
else if (rs485->flags & SER_RS485_RTS_AFTER_SEND)
modem &= ~UARTMODEM_TXRTSPOL;
}
lpuart32_write(&sport->port, modem, UARTMODIR);
@ -1462,12 +1488,32 @@ static void lpuart_break_ctl(struct uart_port *port, int break_state)
static void lpuart32_break_ctl(struct uart_port *port, int break_state)
{
unsigned long temp;
unsigned long temp, modem;
struct tty_struct *tty;
unsigned int cflag = 0;
tty = tty_port_tty_get(&port->state->port);
if (tty) {
cflag = tty->termios.c_cflag;
tty_kref_put(tty);
}
temp = lpuart32_read(port, UARTCTRL) & ~UARTCTRL_SBK;
modem = lpuart32_read(port, UARTMODIR);
if (break_state != 0)
if (break_state != 0) {
temp |= UARTCTRL_SBK;
/*
* LPUART CTS has higher priority than SBK, need to disable CTS before
* asserting SBK to avoid any interference if flow control is enabled.
*/
if (cflag & CRTSCTS && modem & UARTMODIR_TXCTSE)
lpuart32_write(port, modem & ~UARTMODIR_TXCTSE, UARTMODIR);
} else {
/* Re-enable the CTS when break off. */
if (cflag & CRTSCTS && !(modem & UARTMODIR_TXCTSE))
lpuart32_write(port, modem | UARTMODIR_TXCTSE, UARTMODIR);
}
lpuart32_write(port, temp, UARTCTRL);
}
@ -1497,8 +1543,10 @@ static void lpuart_setup_watermark(struct lpuart_port *sport)
writeb(UARTSFIFO_RXUF, sport->port.membase + UARTSFIFO);
}
if (uart_console(&sport->port))
sport->rx_watermark = 1;
writeb(0, sport->port.membase + UARTTWFIFO);
writeb(1, sport->port.membase + UARTRWFIFO);
writeb(sport->rx_watermark, sport->port.membase + UARTRWFIFO);
/* Restore cr2 */
writeb(cr2_saved, sport->port.membase + UARTCR2);
@ -1523,19 +1571,30 @@ static void lpuart32_setup_watermark(struct lpuart_port *sport)
ctrl = lpuart32_read(&sport->port, UARTCTRL);
ctrl_saved = ctrl;
ctrl &= ~(UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_TE |
UARTCTRL_RIE | UARTCTRL_RE);
UARTCTRL_RIE | UARTCTRL_RE | UARTCTRL_ILIE);
lpuart32_write(&sport->port, ctrl, UARTCTRL);
/* enable FIFO mode */
val = lpuart32_read(&sport->port, UARTFIFO);
val |= UARTFIFO_TXFE | UARTFIFO_RXFE;
val |= UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH;
val |= FIELD_PREP(UARTFIFO_RXIDEN, 0x3);
lpuart32_write(&sport->port, val, UARTFIFO);
/* set the watermark */
val = (0x1 << UARTWATER_RXWATER_OFF) | (0x0 << UARTWATER_TXWATER_OFF);
if (uart_console(&sport->port))
sport->rx_watermark = 1;
val = (sport->rx_watermark << UARTWATER_RXWATER_OFF) |
(0x0 << UARTWATER_TXWATER_OFF);
lpuart32_write(&sport->port, val, UARTWATER);
/* set RTS watermark */
if (!uart_console(&sport->port)) {
val = lpuart32_read(&sport->port, UARTMODIR);
val |= FIELD_PREP(UARTMODIR_RTSWATER, sport->rxfifo_size >> 1);
lpuart32_write(&sport->port, val, UARTMODIR);
}
/* Restore cr2 */
lpuart32_write(&sport->port, ctrl_saved, UARTCTRL);
}
@ -1547,7 +1606,8 @@ static void lpuart32_setup_watermark_enable(struct lpuart_port *sport)
lpuart32_setup_watermark(sport);
temp = lpuart32_read(&sport->port, UARTCTRL);
temp |= UARTCTRL_RE | UARTCTRL_TE | UARTCTRL_ILIE;
temp |= UARTCTRL_RE | UARTCTRL_TE;
temp |= FIELD_PREP(UARTCTRL_IDLECFG, 0x7);
lpuart32_write(&sport->port, temp, UARTCTRL);
}
@ -1679,19 +1739,23 @@ static int lpuart_startup(struct uart_port *port)
return 0;
}
static void lpuart32_hw_disable(struct lpuart_port *sport)
{
unsigned long temp;
temp = lpuart32_read(&sport->port, UARTCTRL);
temp &= ~(UARTCTRL_RIE | UARTCTRL_ILIE | UARTCTRL_RE |
UARTCTRL_TIE | UARTCTRL_TE);
lpuart32_write(&sport->port, temp, UARTCTRL);
}
static void lpuart32_configure(struct lpuart_port *sport)
{
unsigned long temp;
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;
temp |= UARTCTRL_RIE | UARTCTRL_ILIE;
if (!sport->lpuart_dma_tx_use)
temp |= UARTCTRL_TIE;
lpuart32_write(&sport->port, temp, UARTCTRL);
@ -1703,11 +1767,12 @@ static void lpuart32_hw_setup(struct lpuart_port *sport)
spin_lock_irqsave(&sport->port.lock, flags);
lpuart32_setup_watermark_enable(sport);
lpuart32_hw_disable(sport);
lpuart_rx_dma_startup(sport);
lpuart_tx_dma_startup(sport);
lpuart32_setup_watermark_enable(sport);
lpuart32_configure(sport);
spin_unlock_irqrestore(&sport->port.lock, flags);
@ -1796,10 +1861,19 @@ static void lpuart32_shutdown(struct uart_port *port)
spin_lock_irqsave(&port->lock, flags);
/* disable Rx/Tx and interrupts */
/* clear status */
temp = lpuart32_read(&sport->port, UARTSTAT);
lpuart32_write(&sport->port, temp, UARTSTAT);
/* disable Rx/Tx DMA */
temp = lpuart32_read(port, UARTBAUD);
temp &= ~(UARTBAUD_TDMAE | UARTBAUD_RDMAE);
lpuart32_write(port, temp, UARTBAUD);
/* disable Rx/Tx and interrupts and break condition */
temp = lpuart32_read(port, UARTCTRL);
temp &= ~(UARTCTRL_TE | UARTCTRL_RE |
UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_RIE);
temp &= ~(UARTCTRL_TE | UARTCTRL_RE | UARTCTRL_ILIE |
UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_RIE | UARTCTRL_SBK);
lpuart32_write(port, temp, UARTCTRL);
spin_unlock_irqrestore(&port->lock, flags);
@ -2631,7 +2705,7 @@ static int lpuart_global_reset(struct lpuart_port *sport)
return ret;
}
if (is_imx7ulp_lpuart(sport) || is_imx8qxp_lpuart(sport)) {
if (is_imx7ulp_lpuart(sport) || is_imx8ulp_lpuart(sport) || is_imx8qxp_lpuart(sport)) {
/*
* If the transmitter is used by earlycon, wait for transmit engine to
* complete and then reset.
@ -2688,6 +2762,7 @@ static int lpuart_probe(struct platform_device *pdev)
sport->port.dev = &pdev->dev;
sport->port.type = PORT_LPUART;
sport->devtype = sdata->devtype;
sport->rx_watermark = sdata->rx_watermark;
ret = platform_get_irq(pdev, 0);
if (ret < 0)
return ret;

View File

@ -210,12 +210,8 @@ struct imx_port {
struct mctrl_gpios *gpios;
/* shadow registers */
unsigned int ucr1;
unsigned int ucr2;
unsigned int ucr3;
unsigned int ucr4;
unsigned int ufcr;
/* counter to stop 0xff flood */
int idle_counter;
/* DMA fields */
unsigned int dma_is_enabled:1;
@ -273,59 +269,14 @@ static const struct of_device_id imx_uart_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, imx_uart_dt_ids);
static void imx_uart_writel(struct imx_port *sport, u32 val, u32 offset)
static inline void imx_uart_writel(struct imx_port *sport, u32 val, u32 offset)
{
switch (offset) {
case UCR1:
sport->ucr1 = val;
break;
case UCR2:
sport->ucr2 = val;
break;
case UCR3:
sport->ucr3 = val;
break;
case UCR4:
sport->ucr4 = val;
break;
case UFCR:
sport->ufcr = val;
break;
default:
break;
}
writel(val, sport->port.membase + offset);
}
static u32 imx_uart_readl(struct imx_port *sport, u32 offset)
static inline u32 imx_uart_readl(struct imx_port *sport, u32 offset)
{
switch (offset) {
case UCR1:
return sport->ucr1;
break;
case UCR2:
/*
* UCR2_SRST is the only bit in the cached registers that might
* differ from the value that was last written. As it only
* automatically becomes one after being cleared, reread
* conditionally.
*/
if (!(sport->ucr2 & UCR2_SRST))
sport->ucr2 = readl(sport->port.membase + offset);
return sport->ucr2;
break;
case UCR3:
return sport->ucr3;
break;
case UCR4:
return sport->ucr4;
break;
case UFCR:
return sport->ufcr;
break;
default:
return readl(sport->port.membase + offset);
}
return readl(sport->port.membase + offset);
}
static inline unsigned imx_uart_uts_reg(struct imx_port *sport)
@ -397,6 +348,41 @@ static void start_hrtimer_ms(struct hrtimer *hrt, unsigned long msec)
hrtimer_start(hrt, ms_to_ktime(msec), HRTIMER_MODE_REL);
}
/* called with port.lock taken and irqs off */
static void imx_uart_soft_reset(struct imx_port *sport)
{
int i = 10;
u32 ucr2, ubir, ubmr, uts;
/*
* According to the Reference Manual description of the UART SRST bit:
*
* "Reset the transmit and receive state machines,
* all FIFOs and register USR1, USR2, UBIR, UBMR, UBRC, URXD, UTXD
* and UTS[6-3]".
*
* We don't need to restore the old values from USR1, USR2, URXD and
* UTXD. UBRC is read only, so only save/restore the other three
* registers.
*/
ubir = imx_uart_readl(sport, UBIR);
ubmr = imx_uart_readl(sport, UBMR);
uts = imx_uart_readl(sport, IMX21_UTS);
ucr2 = imx_uart_readl(sport, UCR2);
imx_uart_writel(sport, ucr2 & ~UCR2_SRST, UCR2);
while (!(imx_uart_readl(sport, UCR2) & UCR2_SRST) && (--i > 0))
udelay(1);
/* Restore the registers */
imx_uart_writel(sport, ubir, UBIR);
imx_uart_writel(sport, ubmr, UBMR);
imx_uart_writel(sport, uts, IMX21_UTS);
sport->idle_counter = 0;
}
/* called with port.lock taken and irqs off */
static void imx_uart_start_rx(struct uart_port *port)
{
@ -476,7 +462,8 @@ static void imx_uart_stop_tx(struct uart_port *port)
imx_uart_rts_inactive(sport, &ucr2);
imx_uart_writel(sport, ucr2, UCR2);
imx_uart_start_rx(port);
if (!port->rs485_rx_during_tx_gpio)
imx_uart_start_rx(port);
sport->tx_state = OFF;
}
@ -705,7 +692,8 @@ static void imx_uart_start_tx(struct uart_port *port)
imx_uart_rts_inactive(sport, &ucr2);
imx_uart_writel(sport, ucr2, UCR2);
if (!(port->rs485.flags & SER_RS485_RX_DURING_TX))
if (!(port->rs485.flags & SER_RS485_RX_DURING_TX) &&
!port->rs485_rx_during_tx_gpio)
imx_uart_stop_rx(port);
sport->tx_state = WAIT_AFTER_RTS;
@ -771,7 +759,7 @@ static irqreturn_t __imx_uart_rtsint(int irq, void *dev_id)
imx_uart_writel(sport, USR1_RTSD, USR1);
usr1 = imx_uart_readl(sport, USR1) & USR1_RTSS;
uart_handle_cts_change(&sport->port, !!usr1);
uart_handle_cts_change(&sport->port, usr1);
wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
return IRQ_HANDLED;
@ -801,33 +789,73 @@ static irqreturn_t imx_uart_txint(int irq, void *dev_id)
return IRQ_HANDLED;
}
/* Check if hardware Rx flood is in progress, and issue soft reset to stop it.
* This is to be called from Rx ISRs only when some bytes were actually
* received.
*
* A way to reproduce the flood (checked on iMX6SX) is: open iMX UART at 9600
* 8N1, and from external source send 0xf0 char at 115200 8N1. In about 90% of
* cases this starts a flood of "receiving" of 0xff characters by the iMX6 UART
* that is terminated by any activity on RxD line, or could be stopped by
* issuing soft reset to the UART (just stop/start of RX does not help). Note
* that what we do here is sending isolated start bit about 2.4 times shorter
* than it is to be on UART configured baud rate.
*/
static void imx_uart_check_flood(struct imx_port *sport, u32 usr2)
{
/* To detect hardware 0xff flood we monitor RxD line between RX
* interrupts to isolate "receiving" of char(s) with no activity
* on RxD line, that'd never happen on actual data transfers.
*
* We use USR2_WAKE bit to check for activity on RxD line, but we have a
* race here if we clear USR2_WAKE when receiving of a char is in
* progress, so we might get RX interrupt later with USR2_WAKE bit
* cleared. Note though that as we don't try to clear USR2_WAKE when we
* detected no activity, this race may hide actual activity only once.
*
* Yet another case where receive interrupt may occur without RxD
* activity is expiration of aging timer, so we consider this as well.
*
* We use 'idle_counter' to ensure that we got at least so many RX
* interrupts without any detected activity on RxD line. 2 cases
* described plus 1 to be on the safe side gives us a margin of 3,
* below. In practice I was not able to produce a false positive to
* induce soft reset at regular data transfers even using 1 as the
* margin, so 3 is actually very strong.
*
* We count interrupts, not chars in 'idle-counter' for simplicity.
*/
if (usr2 & USR2_WAKE) {
imx_uart_writel(sport, USR2_WAKE, USR2);
sport->idle_counter = 0;
} else if (++sport->idle_counter > 3) {
dev_warn(sport->port.dev, "RX flood detected: soft reset.");
imx_uart_soft_reset(sport); /* also clears 'sport->idle_counter' */
}
}
static irqreturn_t __imx_uart_rxint(int irq, void *dev_id)
{
struct imx_port *sport = dev_id;
unsigned int rx, flg, ignored = 0;
struct tty_port *port = &sport->port.state->port;
u32 usr2, rx;
while (imx_uart_readl(sport, USR2) & USR2_RDR) {
u32 usr2;
/* If we received something, check for 0xff flood */
usr2 = imx_uart_readl(sport, USR2);
if (usr2 & USR2_RDR)
imx_uart_check_flood(sport, usr2);
flg = TTY_NORMAL;
while ((rx = imx_uart_readl(sport, URXD0)) & URXD_CHARRDY) {
unsigned int flg = TTY_NORMAL;
sport->port.icount.rx++;
rx = imx_uart_readl(sport, URXD0);
usr2 = imx_uart_readl(sport, USR2);
if (usr2 & USR2_BRCD) {
imx_uart_writel(sport, USR2_BRCD, USR2);
if (uart_handle_break(&sport->port))
continue;
}
if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx))
continue;
if (unlikely(rx & URXD_ERR)) {
if (rx & URXD_BRK)
if (rx & URXD_BRK) {
sport->port.icount.brk++;
if (uart_handle_break(&sport->port))
continue;
}
else if (rx & URXD_PRERR)
sport->port.icount.parity++;
else if (rx & URXD_FRMERR)
@ -835,11 +863,8 @@ static irqreturn_t __imx_uart_rxint(int irq, void *dev_id)
if (rx & URXD_OVRRUN)
sport->port.icount.overrun++;
if (rx & sport->port.ignore_status_mask) {
if (++ignored > 100)
goto out;
if (rx & sport->port.ignore_status_mask)
continue;
}
rx &= (sport->port.read_status_mask | 0xFF);
@ -853,16 +878,17 @@ static irqreturn_t __imx_uart_rxint(int irq, void *dev_id)
flg = TTY_OVERRUN;
sport->port.sysrq = 0;
} else if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx)) {
continue;
}
if (sport->port.ignore_status_mask & URXD_DUMMY_READ)
goto out;
continue;
if (tty_insert_flip_char(port, rx, flg) == 0)
sport->port.icount.buf_overrun++;
}
out:
tty_flip_buffer_push(port);
return IRQ_HANDLED;
@ -1147,55 +1173,62 @@ static void imx_uart_dma_rx_callback(void *data)
status = dmaengine_tx_status(chan, sport->rx_cookie, &state);
if (status == DMA_ERROR) {
spin_lock(&sport->port.lock);
imx_uart_clear_rx_errors(sport);
spin_unlock(&sport->port.lock);
return;
}
if (!(sport->port.ignore_status_mask & URXD_DUMMY_READ)) {
/*
* The state-residue variable represents the empty space
* relative to the entire buffer. Taking this in consideration
* the head is always calculated base on the buffer total
* length - DMA transaction residue. The UART script from the
* SDMA firmware will jump to the next buffer descriptor,
* once a DMA transaction if finalized (IMX53 RM - A.4.1.2.4).
* Taking this in consideration the tail is always at the
* beginning of the buffer descriptor that contains the head.
*/
/*
* The state-residue variable represents the empty space
* relative to the entire buffer. Taking this in consideration
* the head is always calculated base on the buffer total
* length - DMA transaction residue. The UART script from the
* SDMA firmware will jump to the next buffer descriptor,
* once a DMA transaction if finalized (IMX53 RM - A.4.1.2.4).
* Taking this in consideration the tail is always at the
* beginning of the buffer descriptor that contains the head.
*/
/* Calculate the head */
rx_ring->head = sg_dma_len(sgl) - state.residue;
/* Calculate the head */
rx_ring->head = sg_dma_len(sgl) - state.residue;
/* Calculate the tail. */
bd_size = sg_dma_len(sgl) / sport->rx_periods;
rx_ring->tail = ((rx_ring->head-1) / bd_size) * bd_size;
/* Calculate the tail. */
bd_size = sg_dma_len(sgl) / sport->rx_periods;
rx_ring->tail = ((rx_ring->head-1) / bd_size) * bd_size;
if (rx_ring->head <= sg_dma_len(sgl) &&
rx_ring->head > rx_ring->tail) {
if (rx_ring->head <= sg_dma_len(sgl) &&
rx_ring->head > rx_ring->tail) {
/* Move data from tail to head */
r_bytes = rx_ring->head - rx_ring->tail;
/* Move data from tail to head */
r_bytes = rx_ring->head - rx_ring->tail;
/* If we received something, check for 0xff flood */
spin_lock(&sport->port.lock);
imx_uart_check_flood(sport, imx_uart_readl(sport, USR2));
spin_unlock(&sport->port.lock);
if (!(sport->port.ignore_status_mask & URXD_DUMMY_READ)) {
/* CPU claims ownership of RX DMA buffer */
dma_sync_sg_for_cpu(sport->port.dev, sgl, 1,
DMA_FROM_DEVICE);
DMA_FROM_DEVICE);
w_bytes = tty_insert_flip_string(port,
sport->rx_buf + rx_ring->tail, r_bytes);
sport->rx_buf + rx_ring->tail, r_bytes);
/* UART retrieves ownership of RX DMA buffer */
dma_sync_sg_for_device(sport->port.dev, sgl, 1,
DMA_FROM_DEVICE);
DMA_FROM_DEVICE);
if (w_bytes != r_bytes)
sport->port.icount.buf_overrun++;
sport->port.icount.rx += w_bytes;
} else {
WARN_ON(rx_ring->head > sg_dma_len(sgl));
WARN_ON(rx_ring->head <= rx_ring->tail);
}
} else {
WARN_ON(rx_ring->head > sg_dma_len(sgl));
WARN_ON(rx_ring->head <= rx_ring->tail);
}
if (w_bytes) {
@ -1271,6 +1304,8 @@ static void imx_uart_clear_rx_errors(struct imx_port *sport)
imx_uart_writel(sport, USR2_ORE, USR2);
}
sport->idle_counter = 0;
}
#define TXTL_DEFAULT 2 /* reset default */
@ -1398,7 +1433,7 @@ static void imx_uart_disable_dma(struct imx_port *sport)
static int imx_uart_startup(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
int retval, i;
int retval;
unsigned long flags;
int dma_is_inited = 0;
u32 ucr1, ucr2, ucr3, ucr4, uts;
@ -1430,15 +1465,9 @@ static int imx_uart_startup(struct uart_port *port)
dma_is_inited = 1;
spin_lock_irqsave(&sport->port.lock, flags);
/* Reset fifo's and state machines */
i = 100;
ucr2 = imx_uart_readl(sport, UCR2);
ucr2 &= ~UCR2_SRST;
imx_uart_writel(sport, ucr2, UCR2);
while (!(imx_uart_readl(sport, UCR2) & UCR2_SRST) && (--i > 0))
udelay(1);
imx_uart_soft_reset(sport);
/*
* Finally, clear and enable interrupts
@ -1564,7 +1593,8 @@ static void imx_uart_shutdown(struct uart_port *port)
spin_lock_irqsave(&sport->port.lock, flags);
ucr1 = imx_uart_readl(sport, UCR1);
ucr1 &= ~(UCR1_TRDYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_RXDMAEN | UCR1_ATDMAEN);
ucr1 &= ~(UCR1_TRDYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_RXDMAEN |
UCR1_ATDMAEN | UCR1_SNDBRK);
/* See SER_RS485_ENABLED/UTS_LOOP comment in imx_uart_probe() */
if (port->rs485.flags & SER_RS485_ENABLED &&
port->rs485.flags & SER_RS485_RTS_ON_SEND &&
@ -1593,8 +1623,6 @@ static void imx_uart_flush_buffer(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
struct scatterlist *sgl = &sport->tx_sgl[0];
u32 ucr2;
int i = 100, ubir, ubmr, uts;
if (!sport->dma_chan_tx)
return;
@ -1612,32 +1640,8 @@ static void imx_uart_flush_buffer(struct uart_port *port)
sport->dma_is_txing = 0;
}
/*
* According to the Reference Manual description of the UART SRST bit:
*
* "Reset the transmit and receive state machines,
* all FIFOs and register USR1, USR2, UBIR, UBMR, UBRC, URXD, UTXD
* and UTS[6-3]".
*
* We don't need to restore the old values from USR1, USR2, URXD and
* UTXD. UBRC is read only, so only save/restore the other three
* registers.
*/
ubir = imx_uart_readl(sport, UBIR);
ubmr = imx_uart_readl(sport, UBMR);
uts = imx_uart_readl(sport, IMX21_UTS);
imx_uart_soft_reset(sport);
ucr2 = imx_uart_readl(sport, UCR2);
ucr2 &= ~UCR2_SRST;
imx_uart_writel(sport, ucr2, UCR2);
while (!(imx_uart_readl(sport, UCR2) & UCR2_SRST) && (--i > 0))
udelay(1);
/* Restore the registers */
imx_uart_writel(sport, ubir, UBIR);
imx_uart_writel(sport, ubmr, UBMR);
imx_uart_writel(sport, uts, IMX21_UTS);
}
static void
@ -1955,6 +1959,10 @@ static int imx_uart_rs485_config(struct uart_port *port, struct ktermios *termio
rs485conf->flags & SER_RS485_RX_DURING_TX)
imx_uart_start_rx(port);
if (port->rs485_rx_during_tx_gpio)
gpiod_set_value_cansleep(port->rs485_rx_during_tx_gpio,
!!(rs485conf->flags & SER_RS485_RX_DURING_TX));
return 0;
}
@ -2340,13 +2348,6 @@ static int imx_uart_probe(struct platform_device *pdev)
return ret;
}
/* initialize shadow register values */
sport->ucr1 = readl(sport->port.membase + UCR1);
sport->ucr2 = readl(sport->port.membase + UCR2);
sport->ucr3 = readl(sport->port.membase + UCR3);
sport->ucr4 = readl(sport->port.membase + UCR4);
sport->ufcr = readl(sport->port.membase + UFCR);
ret = uart_get_rs485_mode(&sport->port);
if (ret) {
clk_disable_unprepare(sport->clk_ipg);
@ -2374,6 +2375,11 @@ static int imx_uart_probe(struct platform_device *pdev)
ucr1 &= ~(UCR1_ADEN | UCR1_TRDYEN | UCR1_IDEN | UCR1_RRDYEN | UCR1_RTSDEN);
imx_uart_writel(sport, ucr1, UCR1);
/* Disable Ageing Timer interrupt */
ucr2 = imx_uart_readl(sport, UCR2);
ucr2 &= ~UCR2_ATEN;
imx_uart_writel(sport, ucr2, UCR2);
/*
* In case RS485 is enabled without GPIO RTS control, the UART IP
* is used to control CTS signal. Keep both the UART and Receiver

View File

@ -5,7 +5,9 @@
* Copyright (C) 2019-2020 Antmicro <www.antmicro.com>
*/
#include <linux/bits.h>
#include <linux/console.h>
#include <linux/interrupt.h>
#include <linux/litex.h>
#include <linux/module.h>
#include <linux/of.h>
@ -38,13 +40,13 @@
#define OFF_EV_ENABLE 0x14
/* events */
#define EV_TX 0x1
#define EV_RX 0x2
#define EV_TX BIT(0)
#define EV_RX BIT(1)
struct liteuart_port {
struct uart_port port;
struct timer_list timer;
u32 id;
u8 irq_reg;
};
#define to_liteuart_port(port) container_of(port, struct liteuart_port, port)
@ -57,7 +59,7 @@ static struct console liteuart_console;
static struct uart_driver liteuart_driver = {
.owner = THIS_MODULE,
.driver_name = "liteuart",
.driver_name = KBUILD_MODNAME,
.dev_name = "ttyLXU",
.major = 0,
.minor = 0,
@ -67,38 +69,95 @@ static struct uart_driver liteuart_driver = {
#endif
};
static void liteuart_timer(struct timer_list *t)
static void liteuart_update_irq_reg(struct uart_port *port, bool set, u8 mask)
{
struct liteuart_port *uart = from_timer(uart, t, timer);
struct uart_port *port = &uart->port;
unsigned char __iomem *membase = port->membase;
unsigned int flg = TTY_NORMAL;
int ch;
unsigned long status;
struct liteuart_port *uart = to_liteuart_port(port);
while ((status = !litex_read8(membase + OFF_RXEMPTY)) == 1) {
if (set)
uart->irq_reg |= mask;
else
uart->irq_reg &= ~mask;
if (port->irq)
litex_write8(port->membase + OFF_EV_ENABLE, uart->irq_reg);
}
static void liteuart_stop_tx(struct uart_port *port)
{
liteuart_update_irq_reg(port, false, EV_TX);
}
static void liteuart_start_tx(struct uart_port *port)
{
liteuart_update_irq_reg(port, true, EV_TX);
}
static void liteuart_stop_rx(struct uart_port *port)
{
struct liteuart_port *uart = to_liteuart_port(port);
/* just delete timer */
del_timer(&uart->timer);
}
static void liteuart_rx_chars(struct uart_port *port)
{
unsigned char __iomem *membase = port->membase;
u8 ch;
while (!litex_read8(membase + OFF_RXEMPTY)) {
ch = litex_read8(membase + OFF_RXTX);
port->icount.rx++;
/* necessary for RXEMPTY to refresh its value */
litex_write8(membase + OFF_EV_PENDING, EV_TX | EV_RX);
litex_write8(membase + OFF_EV_PENDING, EV_RX);
/* no overflow bits in status */
if (!(uart_handle_sysrq_char(port, ch)))
uart_insert_char(port, status, 0, ch, flg);
tty_flip_buffer_push(&port->state->port);
uart_insert_char(port, 1, 0, ch, TTY_NORMAL);
}
mod_timer(&uart->timer, jiffies + uart_poll_timeout(port));
tty_flip_buffer_push(&port->state->port);
}
static void liteuart_putchar(struct uart_port *port, unsigned char ch)
static void liteuart_tx_chars(struct uart_port *port)
{
while (litex_read8(port->membase + OFF_TXFULL))
cpu_relax();
u8 ch;
litex_write8(port->membase + OFF_RXTX, ch);
uart_port_tx(port, ch,
!litex_read8(port->membase + OFF_TXFULL),
litex_write8(port->membase + OFF_RXTX, ch));
}
static irqreturn_t liteuart_interrupt(int irq, void *data)
{
struct liteuart_port *uart = data;
struct uart_port *port = &uart->port;
unsigned long flags;
u8 isr;
/*
* if polling, the context would be "in_serving_softirq", so use
* irq[save|restore] spin_lock variants to cover all possibilities
*/
spin_lock_irqsave(&port->lock, flags);
isr = litex_read8(port->membase + OFF_EV_PENDING) & uart->irq_reg;
if (isr & EV_RX)
liteuart_rx_chars(port);
if (isr & EV_TX)
liteuart_tx_chars(port);
spin_unlock_irqrestore(&port->lock, flags);
return IRQ_RETVAL(isr);
}
static void liteuart_timer(struct timer_list *t)
{
struct liteuart_port *uart = from_timer(uart, t, timer);
struct uart_port *port = &uart->port;
liteuart_interrupt(0, port);
mod_timer(&uart->timer, jiffies + uart_poll_timeout(port));
}
static unsigned int liteuart_tx_empty(struct uart_port *port)
@ -120,60 +179,49 @@ static unsigned int liteuart_get_mctrl(struct uart_port *port)
return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
}
static void liteuart_stop_tx(struct uart_port *port)
{
}
static void liteuart_start_tx(struct uart_port *port)
{
struct circ_buf *xmit = &port->state->xmit;
unsigned char ch;
if (unlikely(port->x_char)) {
litex_write8(port->membase + OFF_RXTX, port->x_char);
port->icount.tx++;
port->x_char = 0;
} else if (!uart_circ_empty(xmit)) {
while (xmit->head != xmit->tail) {
ch = xmit->buf[xmit->tail];
uart_xmit_advance(port, 1);
liteuart_putchar(port, ch);
}
}
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
}
static void liteuart_stop_rx(struct uart_port *port)
{
struct liteuart_port *uart = to_liteuart_port(port);
/* just delete timer */
del_timer(&uart->timer);
}
static void liteuart_break_ctl(struct uart_port *port, int break_state)
{
/* LiteUART doesn't support sending break signal */
}
static int liteuart_startup(struct uart_port *port)
{
struct liteuart_port *uart = to_liteuart_port(port);
unsigned long flags;
int ret;
/* disable events */
litex_write8(port->membase + OFF_EV_ENABLE, 0);
if (port->irq) {
ret = request_irq(port->irq, liteuart_interrupt, 0,
KBUILD_MODNAME, uart);
if (ret) {
dev_warn(port->dev,
"line %d irq %d failed: switch to polling\n",
port->line, port->irq);
port->irq = 0;
}
}
/* prepare timer for polling */
timer_setup(&uart->timer, liteuart_timer, 0);
mod_timer(&uart->timer, jiffies + uart_poll_timeout(port));
spin_lock_irqsave(&port->lock, flags);
/* only enabling rx irqs during startup */
liteuart_update_irq_reg(port, true, EV_RX);
spin_unlock_irqrestore(&port->lock, flags);
if (!port->irq) {
timer_setup(&uart->timer, liteuart_timer, 0);
mod_timer(&uart->timer, jiffies + uart_poll_timeout(port));
}
return 0;
}
static void liteuart_shutdown(struct uart_port *port)
{
struct liteuart_port *uart = to_liteuart_port(port);
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
liteuart_update_irq_reg(port, false, EV_RX | EV_TX);
spin_unlock_irqrestore(&port->lock, flags);
if (port->irq)
free_irq(port->irq, port);
else
del_timer_sync(&uart->timer);
}
static void liteuart_set_termios(struct uart_port *port, struct ktermios *new,
@ -196,15 +244,6 @@ static const char *liteuart_type(struct uart_port *port)
return "liteuart";
}
static void liteuart_release_port(struct uart_port *port)
{
}
static int liteuart_request_port(struct uart_port *port)
{
return 0;
}
static void liteuart_config_port(struct uart_port *port, int flags)
{
/*
@ -231,13 +270,10 @@ static const struct uart_ops liteuart_ops = {
.stop_tx = liteuart_stop_tx,
.start_tx = liteuart_start_tx,
.stop_rx = liteuart_stop_rx,
.break_ctl = liteuart_break_ctl,
.startup = liteuart_startup,
.shutdown = liteuart_shutdown,
.set_termios = liteuart_set_termios,
.type = liteuart_type,
.release_port = liteuart_release_port,
.request_port = liteuart_request_port,
.config_port = liteuart_config_port,
.verify_port = liteuart_verify_port,
};
@ -249,6 +285,23 @@ static int liteuart_probe(struct platform_device *pdev)
struct xa_limit limit;
int dev_id, ret;
uart = devm_kzalloc(&pdev->dev, sizeof(struct liteuart_port), GFP_KERNEL);
if (!uart)
return -ENOMEM;
port = &uart->port;
/* get membase */
port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(port->membase))
return PTR_ERR(port->membase);
ret = platform_get_irq_optional(pdev, 0);
if (ret < 0 && ret != -ENXIO)
return ret;
if (ret > 0)
port->irq = ret;
/* look for aliases; auto-enumerate for free index if not found */
dev_id = of_alias_get_id(pdev->dev.of_node, "serial");
if (dev_id < 0)
@ -256,32 +309,16 @@ static int liteuart_probe(struct platform_device *pdev)
else
limit = XA_LIMIT(dev_id, dev_id);
uart = devm_kzalloc(&pdev->dev, sizeof(struct liteuart_port), GFP_KERNEL);
if (!uart)
return -ENOMEM;
ret = xa_alloc(&liteuart_array, &dev_id, uart, limit, GFP_KERNEL);
if (ret)
return ret;
uart->id = dev_id;
port = &uart->port;
/* get membase */
port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(port->membase)) {
ret = PTR_ERR(port->membase);
goto err_erase_id;
}
/* values not from device tree */
port->dev = &pdev->dev;
port->iotype = UPIO_MEM;
port->flags = UPF_BOOT_AUTOCONF;
port->ops = &liteuart_ops;
port->regshift = 2;
port->fifosize = 16;
port->iobase = 1;
port->type = PORT_UNKNOWN;
port->line = dev_id;
spin_lock_init(&port->lock);
@ -295,7 +332,7 @@ static int liteuart_probe(struct platform_device *pdev)
return 0;
err_erase_id:
xa_erase(&liteuart_array, uart->id);
xa_erase(&liteuart_array, dev_id);
return ret;
}
@ -303,10 +340,10 @@ static int liteuart_probe(struct platform_device *pdev)
static int liteuart_remove(struct platform_device *pdev)
{
struct uart_port *port = platform_get_drvdata(pdev);
struct liteuart_port *uart = to_liteuart_port(port);
unsigned int line = port->line;
uart_remove_one_port(&liteuart_driver, port);
xa_erase(&liteuart_array, uart->id);
xa_erase(&liteuart_array, line);
return 0;
}
@ -321,13 +358,21 @@ static struct platform_driver liteuart_platform_driver = {
.probe = liteuart_probe,
.remove = liteuart_remove,
.driver = {
.name = "liteuart",
.name = KBUILD_MODNAME,
.of_match_table = liteuart_of_match,
},
};
#ifdef CONFIG_SERIAL_LITEUART_CONSOLE
static void liteuart_putchar(struct uart_port *port, unsigned char ch)
{
while (litex_read8(port->membase + OFF_TXFULL))
cpu_relax();
litex_write8(port->membase + OFF_RXTX, ch);
}
static void liteuart_console_write(struct console *co, const char *s,
unsigned int count)
{
@ -367,7 +412,7 @@ static int liteuart_console_setup(struct console *co, char *options)
}
static struct console liteuart_console = {
.name = "liteuart",
.name = KBUILD_MODNAME,
.write = liteuart_console_write,
.device = uart_console_device,
.setup = liteuart_console_setup,
@ -415,12 +460,10 @@ static int __init liteuart_init(void)
return res;
res = platform_driver_register(&liteuart_platform_driver);
if (res) {
if (res)
uart_unregister_driver(&liteuart_driver);
return res;
}
return 0;
return res;
}
static void __exit liteuart_exit(void)

View File

@ -247,7 +247,7 @@ static int max3100_handlerx(struct max3100_port *s, u16 rx)
cts = (rx & MAX3100_CTS) > 0;
if (s->cts != cts) {
s->cts = cts;
uart_handle_cts_change(&s->port, cts ? TIOCM_CTS : 0);
uart_handle_cts_change(&s->port, cts);
}
return ret;

View File

@ -819,8 +819,7 @@ static irqreturn_t max310x_port_irq(struct max310x_port *s, int portno)
if (ists & MAX310X_IRQ_CTS_BIT) {
lsr = max310x_port_read(port, MAX310X_LSR_IRQSTS_REG);
uart_handle_cts_change(port,
!!(lsr & MAX310X_LSR_CTS_BIT));
uart_handle_cts_change(port, lsr & MAX310X_LSR_CTS_BIT);
}
if (rxlen)
max310x_handle_rx(port, rxlen);

View File

@ -1120,6 +1120,7 @@ msm_find_best_baud(struct uart_port *port, unsigned int baud,
static int msm_set_baud_rate(struct uart_port *port, unsigned int baud,
unsigned long *saved_flags)
__must_hold(&port->lock)
{
unsigned int rxstale, watermark, mask;
struct msm_port *msm_port = to_msm_port(port);

View File

@ -1775,7 +1775,7 @@ static void pch_uart_exit_port(struct eg20t_port *priv)
char name[32];
snprintf(name, sizeof(name), "uart%d_regs", priv->port.line);
debugfs_remove(debugfs_lookup(name, NULL));
debugfs_lookup_and_remove(name, NULL);
uart_remove_one_port(&pch_uart_driver, &priv->port);
free_page((unsigned long)priv->rxbuf.buf);
}

View File

@ -889,6 +889,8 @@ static int pic32_uart_probe(struct platform_device *pdev)
sport->irq_rx = irq_of_parse_and_map(np, 1);
sport->irq_tx = irq_of_parse_and_map(np, 2);
sport->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(sport->clk))
return PTR_ERR(sport->clk);
sport->dev = &pdev->dev;
/* Hardware flow control: gpios

File diff suppressed because it is too large Load Diff

View File

@ -1423,25 +1423,6 @@ static int sc16is7xx_probe(struct device *dev,
}
sched_set_fifo(s->kworker_task);
#ifdef CONFIG_GPIOLIB
if (devtype->nr_gpio) {
/* Setup GPIO cotroller */
s->gpio.owner = THIS_MODULE;
s->gpio.parent = dev;
s->gpio.label = dev_name(dev);
s->gpio.direction_input = sc16is7xx_gpio_direction_input;
s->gpio.get = sc16is7xx_gpio_get;
s->gpio.direction_output = sc16is7xx_gpio_direction_output;
s->gpio.set = sc16is7xx_gpio_set;
s->gpio.base = -1;
s->gpio.ngpio = devtype->nr_gpio;
s->gpio.can_sleep = 1;
ret = gpiochip_add_data(&s->gpio, s);
if (ret)
goto out_thread;
}
#endif
/* reset device, purging any pending irq / data */
regmap_write(s->regmap, SC16IS7XX_IOCONTROL_REG << SC16IS7XX_REG_SHIFT,
SC16IS7XX_IOCONTROL_SRESET_BIT);
@ -1518,6 +1499,25 @@ static int sc16is7xx_probe(struct device *dev,
s->p[u].irda_mode = true;
}
#ifdef CONFIG_GPIOLIB
if (devtype->nr_gpio) {
/* Setup GPIO cotroller */
s->gpio.owner = THIS_MODULE;
s->gpio.parent = dev;
s->gpio.label = dev_name(dev);
s->gpio.direction_input = sc16is7xx_gpio_direction_input;
s->gpio.get = sc16is7xx_gpio_get;
s->gpio.direction_output = sc16is7xx_gpio_direction_output;
s->gpio.set = sc16is7xx_gpio_set;
s->gpio.base = -1;
s->gpio.ngpio = devtype->nr_gpio;
s->gpio.can_sleep = 1;
ret = gpiochip_add_data(&s->gpio, s);
if (ret)
goto out_thread;
}
#endif
/*
* Setup interrupt. We first try to acquire the IRQ line as level IRQ.
* If that succeeds, we can allow sharing the interrupt as well.
@ -1537,18 +1537,19 @@ static int sc16is7xx_probe(struct device *dev,
if (!ret)
return 0;
out_ports:
for (i--; i >= 0; i--) {
uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port);
clear_bit(s->p[i].port.line, &sc16is7xx_lines);
}
#ifdef CONFIG_GPIOLIB
if (devtype->nr_gpio)
gpiochip_remove(&s->gpio);
out_thread:
#endif
out_ports:
for (i--; i >= 0; i--) {
uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port);
clear_bit(s->p[i].port.line, &sc16is7xx_lines);
}
kthread_stop(s->kworker_task);
out_clk:

View File

@ -913,23 +913,13 @@ static int sccnxp_probe(struct platform_device *pdev)
} else if (PTR_ERR(s->regulator) == -EPROBE_DEFER)
return -EPROBE_DEFER;
clk = devm_clk_get(&pdev->dev, NULL);
clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
if (ret == -EPROBE_DEFER)
goto err_out;
uartclk = 0;
} else {
ret = clk_prepare_enable(clk);
if (ret)
goto err_out;
ret = devm_add_action_or_reset(&pdev->dev,
(void(*)(void *))clk_disable_unprepare,
clk);
if (ret)
goto err_out;
uartclk = clk_get_rate(clk);
}

View File

@ -1046,6 +1046,7 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup)
if (tup->cdata->fifo_mode_enable_status) {
ret = tegra_uart_wait_fifo_mode_enabled(tup);
if (ret < 0) {
clk_disable_unprepare(tup->uart_clk);
dev_err(tup->uport.dev,
"Failed to enable FIFO mode: %d\n", ret);
return ret;
@ -1067,6 +1068,7 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup)
*/
ret = tegra_set_baudrate(tup, TEGRA_UART_DEFAULT_BAUD);
if (ret < 0) {
clk_disable_unprepare(tup->uart_clk);
dev_err(tup->uport.dev, "Failed to set baud rate\n");
return ret;
}
@ -1226,10 +1228,13 @@ static int tegra_uart_startup(struct uart_port *u)
dev_name(u->dev), tup);
if (ret < 0) {
dev_err(u->dev, "Failed to register ISR for IRQ %d\n", u->irq);
goto fail_hw_init;
goto fail_request_irq;
}
return 0;
fail_request_irq:
/* tup->uart_clk is already enabled in tegra_uart_hw_init */
clk_disable_unprepare(tup->uart_clk);
fail_hw_init:
if (!tup->use_rx_pio)
tegra_uart_dma_channel_free(tup, true);

View File

@ -169,9 +169,9 @@ uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
#define uart_set_mctrl(port, set) uart_update_mctrl(port, set, 0)
#define uart_clear_mctrl(port, clear) uart_update_mctrl(port, 0, clear)
static void uart_port_dtr_rts(struct uart_port *uport, int raise)
static void uart_port_dtr_rts(struct uart_port *uport, bool active)
{
if (raise)
if (active)
uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
else
uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
@ -182,7 +182,7 @@ static void uart_port_dtr_rts(struct uart_port *uport, int raise)
* will be serialised by the per-port mutex.
*/
static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
int init_hw)
bool init_hw)
{
struct uart_port *uport = uart_port_check(state);
unsigned long flags;
@ -239,7 +239,7 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
* port is open and ready to respond.
*/
if (init_hw && C_BAUD(tty))
uart_port_dtr_rts(uport, 1);
uart_port_dtr_rts(uport, true);
}
/*
@ -254,7 +254,7 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
}
static int uart_startup(struct tty_struct *tty, struct uart_state *state,
int init_hw)
bool init_hw)
{
struct tty_port *port = &state->port;
int retval;
@ -290,7 +290,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
set_bit(TTY_IO_ERROR, &tty->flags);
if (tty_port_initialized(port)) {
tty_port_set_initialized(port, 0);
tty_port_set_initialized(port, false);
/*
* Turn off DTR and RTS early.
@ -302,7 +302,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
}
if (!tty || C_HUPCL(tty))
uart_port_dtr_rts(uport, 0);
uart_port_dtr_rts(uport, false);
uart_port_shutdown(port);
}
@ -312,7 +312,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
* a DCD drop (hangup) at just the right time. Clear suspended bit so
* we don't try to resume a port that has been shutdown.
*/
tty_port_set_suspended(port, 0);
tty_port_set_suspended(port, false);
/*
* Do not free() the transmit buffer page under the port lock since
@ -997,7 +997,7 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
uart_change_speed(tty, state, NULL);
}
} else {
retval = uart_startup(tty, state, 1);
retval = uart_startup(tty, state, true);
if (retval == 0)
tty_port_set_initialized(port, true);
if (retval > 0)
@ -1165,7 +1165,7 @@ static int uart_do_autoconfig(struct tty_struct *tty, struct uart_state *state)
*/
uport->ops->config_port(uport, flags);
ret = uart_startup(tty, state, 1);
ret = uart_startup(tty, state, true);
if (ret == 0)
tty_port_set_initialized(port, true);
if (ret > 0)
@ -1725,7 +1725,7 @@ static void uart_tty_port_shutdown(struct tty_port *port)
* a DCD drop (hangup) at just the right time. Clear suspended bit so
* we don't try to resume a port that has been shutdown.
*/
tty_port_set_suspended(port, 0);
tty_port_set_suspended(port, false);
/*
* Free the transmit buffer.
@ -1827,7 +1827,7 @@ static void uart_hangup(struct tty_struct *tty)
spin_lock_irqsave(&port->lock, flags);
port->count = 0;
spin_unlock_irqrestore(&port->lock, flags);
tty_port_set_active(port, 0);
tty_port_set_active(port, false);
tty_port_tty_set(port, NULL);
if (uport && !uart_console(uport))
uart_change_pm(state, UART_PM_STATE_OFF);
@ -1861,7 +1861,7 @@ static void uart_port_shutdown(struct tty_port *port)
}
}
static int uart_carrier_raised(struct tty_port *port)
static bool uart_carrier_raised(struct tty_port *port)
{
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport;
@ -1875,18 +1875,17 @@ static int uart_carrier_raised(struct tty_port *port)
* continue and not sleep
*/
if (WARN_ON(!uport))
return 1;
return true;
spin_lock_irq(&uport->lock);
uart_enable_ms(uport);
mctrl = uport->ops->get_mctrl(uport);
spin_unlock_irq(&uport->lock);
uart_port_deref(uport);
if (mctrl & TIOCM_CAR)
return 1;
return 0;
return mctrl & TIOCM_CAR;
}
static void uart_dtr_rts(struct tty_port *port, int raise)
static void uart_dtr_rts(struct tty_port *port, bool active)
{
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport;
@ -1894,7 +1893,7 @@ static void uart_dtr_rts(struct tty_port *port, int raise)
uport = uart_port_ref(state);
if (!uport)
return;
uart_port_dtr_rts(uport, raise);
uart_port_dtr_rts(uport, active);
uart_port_deref(uport);
}
@ -1943,9 +1942,9 @@ static int uart_port_activate(struct tty_port *port, struct tty_struct *tty)
/*
* Start up the serial port.
*/
ret = uart_startup(tty, state, 0);
ret = uart_startup(tty, state, false);
if (ret > 0)
tty_port_set_active(port, 1);
tty_port_set_active(port, true);
return ret;
}
@ -2349,8 +2348,8 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
int tries;
unsigned int mctrl;
tty_port_set_suspended(port, 1);
tty_port_set_initialized(port, 0);
tty_port_set_suspended(port, true);
tty_port_set_initialized(port, false);
spin_lock_irq(&uport->lock);
ops->stop_tx(uport);
@ -2461,7 +2460,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
uart_rs485_config(uport);
ops->start_tx(uport);
spin_unlock_irq(&uport->lock);
tty_port_set_initialized(port, 1);
tty_port_set_initialized(port, true);
} else {
/*
* Failed to resume - maybe hardware went away?
@ -2472,7 +2471,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
}
}
tty_port_set_suspended(port, 0);
tty_port_set_suspended(port, false);
}
mutex_unlock(&port->mutex);
@ -3258,11 +3257,11 @@ EXPORT_SYMBOL(uart_match_port);
/**
* uart_handle_dcd_change - handle a change of carrier detect state
* @uport: uart_port structure for the open port
* @status: new carrier detect status, nonzero if active
* @active: new carrier detect status
*
* Caller must hold uport->lock.
*/
void uart_handle_dcd_change(struct uart_port *uport, unsigned int status)
void uart_handle_dcd_change(struct uart_port *uport, bool active)
{
struct tty_port *port = &uport->state->port;
struct tty_struct *tty = port->tty;
@ -3274,7 +3273,7 @@ void uart_handle_dcd_change(struct uart_port *uport, unsigned int status)
ld = tty_ldisc_ref(tty);
if (ld) {
if (ld->ops->dcd_change)
ld->ops->dcd_change(tty, status);
ld->ops->dcd_change(tty, active);
tty_ldisc_deref(ld);
}
}
@ -3282,7 +3281,7 @@ void uart_handle_dcd_change(struct uart_port *uport, unsigned int status)
uport->icount.dcd++;
if (uart_dcd_enabled(uport)) {
if (status)
if (active)
wake_up_interruptible(&port->open_wait);
else if (tty)
tty_hangup(tty);
@ -3293,11 +3292,11 @@ EXPORT_SYMBOL_GPL(uart_handle_dcd_change);
/**
* uart_handle_cts_change - handle a change of clear-to-send state
* @uport: uart_port structure for the open port
* @status: new clear to send status, nonzero if active
* @active: new clear-to-send status
*
* Caller must hold uport->lock.
*/
void uart_handle_cts_change(struct uart_port *uport, unsigned int status)
void uart_handle_cts_change(struct uart_port *uport, bool active)
{
lockdep_assert_held_once(&uport->lock);
@ -3305,13 +3304,13 @@ void uart_handle_cts_change(struct uart_port *uport, unsigned int status)
if (uart_softcts_mode(uport)) {
if (uport->hw_stopped) {
if (status) {
if (active) {
uport->hw_stopped = 0;
uport->ops->start_tx(uport);
uart_write_wakeup(uport);
}
} else {
if (!status) {
if (!active) {
uport->hw_stopped = 1;
uport->ops->stop_tx(uport);
}
@ -3415,6 +3414,7 @@ int uart_get_rs485_mode(struct uart_port *port)
struct device *dev = port->dev;
u32 rs485_delay[2];
int ret;
int rx_during_tx_gpio_flag;
ret = device_property_read_u32_array(dev, "rs485-rts-delay",
rs485_delay, 2);
@ -3463,6 +3463,17 @@ int uart_get_rs485_mode(struct uart_port *port)
if (port->rs485_term_gpio)
port->rs485_supported.flags |= SER_RS485_TERMINATE_BUS;
rx_during_tx_gpio_flag = (rs485conf->flags & SER_RS485_RX_DURING_TX) ?
GPIOD_OUT_HIGH : GPIOD_OUT_LOW;
port->rs485_rx_during_tx_gpio = devm_gpiod_get_optional(dev,
"rs485-rx-during-tx",
rx_during_tx_gpio_flag);
if (IS_ERR(port->rs485_rx_during_tx_gpio)) {
ret = PTR_ERR(port->rs485_rx_during_tx_gpio);
port->rs485_rx_during_tx_gpio = NULL;
return dev_err_probe(dev, ret, "Cannot get rs485-rx-during-tx-gpios\n");
}
return 0;
}
EXPORT_SYMBOL_GPL(uart_get_rs485_mode);

View File

@ -226,7 +226,11 @@ static int stm32_usart_config_rs485(struct uart_port *port, struct ktermios *ter
stm32_usart_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
rs485conf->flags |= SER_RS485_RX_DURING_TX;
if (port->rs485_rx_during_tx_gpio)
gpiod_set_value_cansleep(port->rs485_rx_during_tx_gpio,
!!(rs485conf->flags & SER_RS485_RX_DURING_TX));
else
rs485conf->flags |= SER_RS485_RX_DURING_TX;
if (rs485conf->flags & SER_RS485_ENABLED) {
cr1 = readl_relaxed(port->membase + ofs->cr1);

View File

@ -87,10 +87,10 @@ static int receive_chars_getchar(struct uart_port *port)
if (c == CON_HUP) {
hung_up = 1;
uart_handle_dcd_change(port, 0);
uart_handle_dcd_change(port, false);
} else if (hung_up) {
hung_up = 0;
uart_handle_dcd_change(port, 1);
uart_handle_dcd_change(port, true);
}
if (port->state == NULL) {
@ -133,7 +133,7 @@ static int receive_chars_read(struct uart_port *port)
bytes_read = 1;
} else if (stat == CON_HUP) {
hung_up = 1;
uart_handle_dcd_change(port, 0);
uart_handle_dcd_change(port, false);
continue;
} else {
/* HV_EWOULDBLOCK, etc. */
@ -143,7 +143,7 @@ static int receive_chars_read(struct uart_port *port)
if (hung_up) {
hung_up = 0;
uart_handle_dcd_change(port, 1);
uart_handle_dcd_change(port, true);
}
if (port->sysrq != 0 && *con_read_page) {

View File

@ -1468,6 +1468,8 @@ static int ucc_uart_remove(struct platform_device *ofdev)
uart_remove_one_port(&ucc_uart_driver, &qe_port->port);
of_node_put(qe_port->np);
kfree(qe_port);
return 0;

View File

@ -694,7 +694,7 @@ static void hangup(struct tty_struct *tty)
info->port.count = 0;
info->port.tty = NULL;
spin_unlock_irqrestore(&info->port.lock, flags);
tty_port_set_active(&info->port, 0);
tty_port_set_active(&info->port, false);
mutex_unlock(&info->port.mutex);
wake_up_interruptible(&info->port.open_wait);
@ -2354,7 +2354,7 @@ static int startup(struct slgt_info *info)
if (info->port.tty)
clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
tty_port_set_initialized(&info->port, 1);
tty_port_set_initialized(&info->port, true);
return 0;
}
@ -2401,7 +2401,7 @@ static void shutdown(struct slgt_info *info)
if (info->port.tty)
set_bit(TTY_IO_ERROR, &info->port.tty->flags);
tty_port_set_initialized(&info->port, 0);
tty_port_set_initialized(&info->port, false);
}
static void program_hw(struct slgt_info *info)
@ -3126,7 +3126,7 @@ static int tiocmset(struct tty_struct *tty,
return 0;
}
static int carrier_raised(struct tty_port *port)
static bool carrier_raised(struct tty_port *port)
{
unsigned long flags;
struct slgt_info *info = container_of(port, struct slgt_info, port);
@ -3134,16 +3134,17 @@ static int carrier_raised(struct tty_port *port)
spin_lock_irqsave(&info->lock,flags);
get_gtsignals(info);
spin_unlock_irqrestore(&info->lock,flags);
return (info->signals & SerialSignal_DCD) ? 1 : 0;
return info->signals & SerialSignal_DCD;
}
static void dtr_rts(struct tty_port *port, int on)
static void dtr_rts(struct tty_port *port, bool active)
{
unsigned long flags;
struct slgt_info *info = container_of(port, struct slgt_info, port);
spin_lock_irqsave(&info->lock,flags);
if (on)
if (active)
info->signals |= SerialSignal_RTS | SerialSignal_DTR;
else
info->signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
@ -3162,14 +3163,14 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
int retval;
bool do_clocal = false;
unsigned long flags;
int cd;
bool cd;
struct tty_port *port = &info->port;
DBGINFO(("%s block_til_ready\n", tty->driver->name));
if (filp->f_flags & O_NONBLOCK || tty_io_error(tty)) {
/* nonblock mode is set or port is not enabled */
tty_port_set_active(port, 1);
tty_port_set_active(port, true);
return 0;
}
@ -3226,7 +3227,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
port->blocked_open--;
if (!retval)
tty_port_set_active(port, 1);
tty_port_set_active(port, true);
DBGINFO(("%s block_til_ready ready, rc=%d\n", tty->driver->name, retval));
return retval;

View File

@ -1224,14 +1224,16 @@ static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,
{
struct tty_struct *tty;
if (driver->ops->lookup)
if (driver->ops->lookup) {
if (!file)
tty = ERR_PTR(-EIO);
else
tty = driver->ops->lookup(driver, file, idx);
else
} else {
if (idx >= driver->num)
return ERR_PTR(-EINVAL);
tty = driver->ttys[idx];
}
if (!IS_ERR(tty))
tty_kref_get(tty);
return tty;

View File

@ -270,13 +270,13 @@ EXPORT_SYMBOL(tty_termios_copy_hw);
* between the two termios structures, or a speed change is needed.
*/
int tty_termios_hw_change(const struct ktermios *a, const struct ktermios *b)
bool tty_termios_hw_change(const struct ktermios *a, const struct ktermios *b)
{
if (a->c_ispeed != b->c_ispeed || a->c_ospeed != b->c_ospeed)
return 1;
return true;
if ((a->c_cflag ^ b->c_cflag) & ~(HUPCL | CREAD | CLOCAL))
return 1;
return 0;
return true;
return false;
}
EXPORT_SYMBOL(tty_termios_hw_change);

View File

@ -367,7 +367,7 @@ static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty)
goto out;
if (tty_port_initialized(port)) {
tty_port_set_initialized(port, 0);
tty_port_set_initialized(port, false);
/*
* Drop DTR/RTS if HUPCL is set. This causes any attached
* modem to hang up the line.
@ -403,7 +403,7 @@ void tty_port_hangup(struct tty_port *port)
set_bit(TTY_IO_ERROR, &tty->flags);
port->tty = NULL;
spin_unlock_irqrestore(&port->lock, flags);
tty_port_set_active(port, 0);
tty_port_set_active(port, false);
tty_port_shutdown(port, tty);
tty_kref_put(tty);
wake_up_interruptible(&port->open_wait);
@ -444,10 +444,10 @@ EXPORT_SYMBOL_GPL(tty_port_tty_wakeup);
* to hide some internal details. This will eventually become entirely
* internal to the tty port.
*/
int tty_port_carrier_raised(struct tty_port *port)
bool tty_port_carrier_raised(struct tty_port *port)
{
if (port->ops->carrier_raised == NULL)
return 1;
return true;
return port->ops->carrier_raised(port);
}
EXPORT_SYMBOL(tty_port_carrier_raised);
@ -463,7 +463,7 @@ EXPORT_SYMBOL(tty_port_carrier_raised);
void tty_port_raise_dtr_rts(struct tty_port *port)
{
if (port->ops->dtr_rts)
port->ops->dtr_rts(port, 1);
port->ops->dtr_rts(port, true);
}
EXPORT_SYMBOL(tty_port_raise_dtr_rts);
@ -478,7 +478,7 @@ EXPORT_SYMBOL(tty_port_raise_dtr_rts);
void tty_port_lower_dtr_rts(struct tty_port *port)
{
if (port->ops->dtr_rts)
port->ops->dtr_rts(port, 0);
port->ops->dtr_rts(port, false);
}
EXPORT_SYMBOL(tty_port_lower_dtr_rts);
@ -518,14 +518,14 @@ int tty_port_block_til_ready(struct tty_port *port,
* the port has just hung up or is in another error state.
*/
if (tty_io_error(tty)) {
tty_port_set_active(port, 1);
tty_port_set_active(port, true);
return 0;
}
if (filp == NULL || (filp->f_flags & O_NONBLOCK)) {
/* Indicate we are open */
if (C_BAUD(tty))
tty_port_raise_dtr_rts(port);
tty_port_set_active(port, 1);
tty_port_set_active(port, true);
return 0;
}
@ -588,7 +588,7 @@ int tty_port_block_til_ready(struct tty_port *port,
port->blocked_open--;
spin_unlock_irqrestore(&port->lock, flags);
if (retval == 0)
tty_port_set_active(port, 1);
tty_port_set_active(port, true);
return retval;
}
EXPORT_SYMBOL(tty_port_block_til_ready);
@ -695,7 +695,7 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
wake_up_interruptible(&port->open_wait);
}
spin_unlock_irqrestore(&port->lock, flags);
tty_port_set_active(port, 0);
tty_port_set_active(port, false);
}
EXPORT_SYMBOL(tty_port_close_end);
@ -788,7 +788,7 @@ int tty_port_open(struct tty_port *port, struct tty_struct *tty,
return retval;
}
}
tty_port_set_initialized(port, 1);
tty_port_set_initialized(port, true);
}
mutex_unlock(&port->mutex);
return tty_port_block_til_ready(port, tty, filp);

View File

@ -316,73 +316,55 @@ void schedule_console_callback(void)
* Code to manage unicode-based screen buffers
*/
#ifdef NO_VC_UNI_SCREEN
/* this disables and optimizes related code away at compile time */
#define get_vc_uniscr(vc) NULL
#else
#define get_vc_uniscr(vc) vc->vc_uni_screen
#endif
#define VC_UNI_SCREEN_DEBUG 0
typedef uint32_t char32_t;
/*
* Our screen buffer is preceded by an array of line pointers so that
* scrolling only implies some pointer shuffling.
*/
struct uni_screen {
char32_t *lines[0];
};
static struct uni_screen *vc_uniscr_alloc(unsigned int cols, unsigned int rows)
static u32 **vc_uniscr_alloc(unsigned int cols, unsigned int rows)
{
struct uni_screen *uniscr;
u32 **uni_lines;
void *p;
unsigned int memsize, i;
unsigned int memsize, i, col_size = cols * sizeof(**uni_lines);
/* allocate everything in one go */
memsize = cols * rows * sizeof(char32_t);
memsize += rows * sizeof(char32_t *);
p = vzalloc(memsize);
if (!p)
memsize = col_size * rows;
memsize += rows * sizeof(*uni_lines);
uni_lines = vzalloc(memsize);
if (!uni_lines)
return NULL;
/* initial line pointers */
uniscr = p;
p = uniscr->lines + rows;
p = uni_lines + rows;
for (i = 0; i < rows; i++) {
uniscr->lines[i] = p;
p += cols * sizeof(char32_t);
uni_lines[i] = p;
p += col_size;
}
return uniscr;
return uni_lines;
}
static void vc_uniscr_free(struct uni_screen *uniscr)
static void vc_uniscr_free(u32 **uni_lines)
{
vfree(uniscr);
vfree(uni_lines);
}
static void vc_uniscr_set(struct vc_data *vc, struct uni_screen *new_uniscr)
static void vc_uniscr_set(struct vc_data *vc, u32 **new_uni_lines)
{
vc_uniscr_free(vc->vc_uni_screen);
vc->vc_uni_screen = new_uniscr;
vc_uniscr_free(vc->vc_uni_lines);
vc->vc_uni_lines = new_uni_lines;
}
static void vc_uniscr_putc(struct vc_data *vc, char32_t uc)
static void vc_uniscr_putc(struct vc_data *vc, u32 uc)
{
struct uni_screen *uniscr = get_vc_uniscr(vc);
if (uniscr)
uniscr->lines[vc->state.y][vc->state.x] = uc;
if (vc->vc_uni_lines)
vc->vc_uni_lines[vc->state.y][vc->state.x] = uc;
}
static void vc_uniscr_insert(struct vc_data *vc, unsigned int nr)
{
struct uni_screen *uniscr = get_vc_uniscr(vc);
if (uniscr) {
char32_t *ln = uniscr->lines[vc->state.y];
if (vc->vc_uni_lines) {
u32 *ln = vc->vc_uni_lines[vc->state.y];
unsigned int x = vc->state.x, cols = vc->vc_cols;
memmove(&ln[x + nr], &ln[x], (cols - x - nr) * sizeof(*ln));
@ -392,10 +374,8 @@ static void vc_uniscr_insert(struct vc_data *vc, unsigned int nr)
static void vc_uniscr_delete(struct vc_data *vc, unsigned int nr)
{
struct uni_screen *uniscr = get_vc_uniscr(vc);
if (uniscr) {
char32_t *ln = uniscr->lines[vc->state.y];
if (vc->vc_uni_lines) {
u32 *ln = vc->vc_uni_lines[vc->state.y];
unsigned int x = vc->state.x, cols = vc->vc_cols;
memcpy(&ln[x], &ln[x + nr], (cols - x - nr) * sizeof(*ln));
@ -406,86 +386,84 @@ static void vc_uniscr_delete(struct vc_data *vc, unsigned int nr)
static void vc_uniscr_clear_line(struct vc_data *vc, unsigned int x,
unsigned int nr)
{
struct uni_screen *uniscr = get_vc_uniscr(vc);
if (uniscr) {
char32_t *ln = uniscr->lines[vc->state.y];
memset32(&ln[x], ' ', nr);
}
if (vc->vc_uni_lines)
memset32(&vc->vc_uni_lines[vc->state.y][x], ' ', nr);
}
static void vc_uniscr_clear_lines(struct vc_data *vc, unsigned int y,
unsigned int nr)
{
struct uni_screen *uniscr = get_vc_uniscr(vc);
if (uniscr) {
unsigned int cols = vc->vc_cols;
if (vc->vc_uni_lines)
while (nr--)
memset32(uniscr->lines[y++], ' ', cols);
}
memset32(vc->vc_uni_lines[y++], ' ', vc->vc_cols);
}
static void vc_uniscr_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
enum con_scroll dir, unsigned int nr)
/* juggling array rotation algorithm (complexity O(N), size complexity O(1)) */
static void juggle_array(u32 **array, unsigned int size, unsigned int nr)
{
struct uni_screen *uniscr = get_vc_uniscr(vc);
unsigned int gcd_idx;
if (uniscr) {
unsigned int i, j, k, sz, d, clear;
for (gcd_idx = 0; gcd_idx < gcd(nr, size); gcd_idx++) {
u32 *gcd_idx_val = array[gcd_idx];
unsigned int dst_idx = gcd_idx;
sz = b - t;
clear = b - nr;
d = nr;
if (dir == SM_DOWN) {
clear = t;
d = sz - nr;
while (1) {
unsigned int src_idx = (dst_idx + nr) % size;
if (src_idx == gcd_idx)
break;
array[dst_idx] = array[src_idx];
dst_idx = src_idx;
}
for (i = 0; i < gcd(d, sz); i++) {
char32_t *tmp = uniscr->lines[t + i];
j = i;
while (1) {
k = j + d;
if (k >= sz)
k -= sz;
if (k == i)
break;
uniscr->lines[t + j] = uniscr->lines[t + k];
j = k;
}
uniscr->lines[t + j] = tmp;
}
vc_uniscr_clear_lines(vc, clear, nr);
array[dst_idx] = gcd_idx_val;
}
}
static void vc_uniscr_copy_area(struct uni_screen *dst,
static void vc_uniscr_scroll(struct vc_data *vc, unsigned int top,
unsigned int bottom, enum con_scroll dir,
unsigned int nr)
{
u32 **uni_lines = vc->vc_uni_lines;
unsigned int size = bottom - top;
if (!uni_lines)
return;
if (dir == SM_DOWN) {
juggle_array(&uni_lines[top], size, size - nr);
vc_uniscr_clear_lines(vc, top, nr);
} else {
juggle_array(&uni_lines[top], size, nr);
vc_uniscr_clear_lines(vc, bottom - nr, nr);
}
}
static void vc_uniscr_copy_area(u32 **dst_lines,
unsigned int dst_cols,
unsigned int dst_rows,
struct uni_screen *src,
u32 **src_lines,
unsigned int src_cols,
unsigned int src_top_row,
unsigned int src_bot_row)
{
unsigned int dst_row = 0;
if (!dst)
if (!dst_lines)
return;
while (src_top_row < src_bot_row) {
char32_t *src_line = src->lines[src_top_row];
char32_t *dst_line = dst->lines[dst_row];
u32 *src_line = src_lines[src_top_row];
u32 *dst_line = dst_lines[dst_row];
memcpy(dst_line, src_line, src_cols * sizeof(char32_t));
memcpy(dst_line, src_line, src_cols * sizeof(*src_line));
if (dst_cols - src_cols)
memset32(dst_line + src_cols, ' ', dst_cols - src_cols);
src_top_row++;
dst_row++;
}
while (dst_row < dst_rows) {
char32_t *dst_line = dst->lines[dst_row];
u32 *dst_line = dst_lines[dst_row];
memset32(dst_line, ' ', dst_cols);
dst_row++;
@ -500,23 +478,20 @@ static void vc_uniscr_copy_area(struct uni_screen *dst,
*/
int vc_uniscr_check(struct vc_data *vc)
{
struct uni_screen *uniscr;
u32 **uni_lines;
unsigned short *p;
int x, y, mask;
if (__is_defined(NO_VC_UNI_SCREEN))
return -EOPNOTSUPP;
WARN_CONSOLE_UNLOCKED();
if (!vc->vc_utf)
return -ENODATA;
if (vc->vc_uni_screen)
if (vc->vc_uni_lines)
return 0;
uniscr = vc_uniscr_alloc(vc->vc_cols, vc->vc_rows);
if (!uniscr)
uni_lines = vc_uniscr_alloc(vc->vc_cols, vc->vc_rows);
if (!uni_lines)
return -ENOMEM;
/*
@ -528,14 +503,15 @@ int vc_uniscr_check(struct vc_data *vc)
p = (unsigned short *)vc->vc_origin;
mask = vc->vc_hi_font_mask | 0xff;
for (y = 0; y < vc->vc_rows; y++) {
char32_t *line = uniscr->lines[y];
u32 *line = uni_lines[y];
for (x = 0; x < vc->vc_cols; x++) {
u16 glyph = scr_readw(p++) & mask;
line[x] = inverse_translate(vc, glyph, true);
}
}
vc->vc_uni_screen = uniscr;
vc->vc_uni_lines = uni_lines;
return 0;
}
@ -547,11 +523,12 @@ int vc_uniscr_check(struct vc_data *vc)
void vc_uniscr_copy_line(const struct vc_data *vc, void *dest, bool viewed,
unsigned int row, unsigned int col, unsigned int nr)
{
struct uni_screen *uniscr = get_vc_uniscr(vc);
u32 **uni_lines = vc->vc_uni_lines;
int offset = row * vc->vc_size_row + col * 2;
unsigned long pos;
BUG_ON(!uniscr);
if (WARN_ON_ONCE(!uni_lines))
return;
pos = (unsigned long)screenpos(vc, offset, viewed);
if (pos >= vc->vc_origin && pos < vc->vc_scr_end) {
@ -562,7 +539,7 @@ void vc_uniscr_copy_line(const struct vc_data *vc, void *dest, bool viewed,
*/
row = (pos - vc->vc_origin) / vc->vc_size_row;
col = ((pos - vc->vc_origin) % vc->vc_size_row) / 2;
memcpy(dest, &uniscr->lines[row][col], nr * sizeof(char32_t));
memcpy(dest, &uni_lines[row][col], nr * sizeof(u32));
} else {
/*
* Scrollback is active. For now let's simply backtranslate
@ -572,7 +549,7 @@ void vc_uniscr_copy_line(const struct vc_data *vc, void *dest, bool viewed,
*/
u16 *p = (u16 *)pos;
int mask = vc->vc_hi_font_mask | 0xff;
char32_t *uni_buf = dest;
u32 *uni_buf = dest;
while (nr--) {
u16 glyph = scr_readw(p++) & mask;
*uni_buf++ = inverse_translate(vc, glyph, true);
@ -580,64 +557,31 @@ void vc_uniscr_copy_line(const struct vc_data *vc, void *dest, bool viewed,
}
}
/* this is for validation and debugging only */
static void vc_uniscr_debug_check(struct vc_data *vc)
static void con_scroll(struct vc_data *vc, unsigned int top,
unsigned int bottom, enum con_scroll dir,
unsigned int nr)
{
struct uni_screen *uniscr = get_vc_uniscr(vc);
unsigned short *p;
int x, y, mask;
unsigned int rows = bottom - top;
u16 *clear, *dst, *src;
if (!VC_UNI_SCREEN_DEBUG || !uniscr)
if (top + nr >= bottom)
nr = rows - 1;
if (bottom > vc->vc_rows || top >= bottom || nr < 1)
return;
WARN_CONSOLE_UNLOCKED();
/*
* Make sure our unicode screen translates into the same glyphs
* as the actual screen. This is brutal indeed.
*/
p = (unsigned short *)vc->vc_origin;
mask = vc->vc_hi_font_mask | 0xff;
for (y = 0; y < vc->vc_rows; y++) {
char32_t *line = uniscr->lines[y];
for (x = 0; x < vc->vc_cols; x++) {
u16 glyph = scr_readw(p++) & mask;
char32_t uc = line[x];
int tc = conv_uni_to_pc(vc, uc);
if (tc == -4)
tc = conv_uni_to_pc(vc, 0xfffd);
if (tc == -4)
tc = conv_uni_to_pc(vc, '?');
if (tc != glyph)
pr_err_ratelimited(
"%s: mismatch at %d,%d: glyph=%#x tc=%#x\n",
__func__, x, y, glyph, tc);
}
}
}
static void con_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
enum con_scroll dir, unsigned int nr)
{
u16 *clear, *d, *s;
if (t + nr >= b)
nr = b - t - 1;
if (b > vc->vc_rows || t >= b || nr < 1)
return;
vc_uniscr_scroll(vc, t, b, dir, nr);
if (con_is_visible(vc) && vc->vc_sw->con_scroll(vc, t, b, dir, nr))
vc_uniscr_scroll(vc, top, bottom, dir, nr);
if (con_is_visible(vc) &&
vc->vc_sw->con_scroll(vc, top, bottom, dir, nr))
return;
s = clear = (u16 *)(vc->vc_origin + vc->vc_size_row * t);
d = (u16 *)(vc->vc_origin + vc->vc_size_row * (t + nr));
src = clear = (u16 *)(vc->vc_origin + vc->vc_size_row * top);
dst = (u16 *)(vc->vc_origin + vc->vc_size_row * (top + nr));
if (dir == SM_UP) {
clear = s + (b - t - nr) * vc->vc_cols;
swap(s, d);
clear = src + (rows - nr) * vc->vc_cols;
swap(src, dst);
}
scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row);
scr_memmovew(dst, src, (rows - nr) * vc->vc_size_row);
scr_memsetw(clear, vc->vc_video_erase_char, vc->vc_size_row * nr);
}
@ -1201,7 +1145,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
unsigned int new_cols, new_rows, new_row_size, new_screen_size;
unsigned int user;
unsigned short *oldscreen, *newscreen;
struct uni_screen *new_uniscr = NULL;
u32 **new_uniscr = NULL;
WARN_CONSOLE_UNLOCKED();
@ -1245,7 +1189,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
if (!newscreen)
return -ENOMEM;
if (get_vc_uniscr(vc)) {
if (vc->vc_uni_lines) {
new_uniscr = vc_uniscr_alloc(new_cols, new_rows);
if (!new_uniscr) {
kfree(newscreen);
@ -1297,7 +1241,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
end = old_origin + old_row_size * min(old_rows, new_rows);
vc_uniscr_copy_area(new_uniscr, new_cols, new_rows,
get_vc_uniscr(vc), rlth/2, first_copied_row,
vc->vc_uni_lines, rlth/2, first_copied_row,
min(old_rows, new_rows));
vc_uniscr_set(vc, new_uniscr);
@ -2959,7 +2903,6 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
goto rescan_last_byte;
}
con_flush(vc, &draw);
vc_uniscr_debug_check(vc);
console_conditional_schedule();
notify_update(vc);
console_unlock();
@ -3156,8 +3099,14 @@ static struct tty_driver *vt_console_device(struct console *c, int *index)
return console_driver;
}
static int vt_console_setup(struct console *co, char *options)
{
return co->index >= MAX_NR_CONSOLES ? -EINVAL : 0;
}
static struct console vt_console_driver = {
.name = "tty",
.setup = vt_console_setup,
.write = vt_console_print,
.device = vt_console_device,
.unblank = unblank_screen,
@ -4574,26 +4523,30 @@ void reset_palette(struct vc_data *vc)
/*
* Font switching
*
* Currently we only support fonts up to 32 pixels wide, at a maximum height
* of 32 pixels. Userspace fontdata is stored with 32 bytes (shorts/ints,
* depending on width) reserved for each character which is kinda wasty, but
* this is done in order to maintain compatibility with the EGA/VGA fonts. It
* is up to the actual low-level console-driver convert data into its favorite
* format (maybe we should add a `fontoffset' field to the `display'
* structure so we won't have to convert the fontdata all the time.
* Currently we only support fonts up to 128 pixels wide, at a maximum height
* of 128 pixels. Userspace fontdata may have to be stored with 32 bytes
* (shorts/ints, depending on width) reserved for each character which is
* kinda wasty, but this is done in order to maintain compatibility with the
* EGA/VGA fonts. It is up to the actual low-level console-driver convert data
* into its favorite format (maybe we should add a `fontoffset' field to the
* `display' structure so we won't have to convert the fontdata all the time.
* /Jes
*/
#define max_font_size 65536
#define max_font_width 64
#define max_font_height 128
#define max_font_glyphs 512
#define max_font_size (max_font_glyphs*max_font_width*max_font_height)
static int con_font_get(struct vc_data *vc, struct console_font_op *op)
{
struct console_font font;
int rc = -EINVAL;
int c;
unsigned int vpitch = op->op == KD_FONT_OP_GET_TALL ? op->height : 32;
if (op->data) {
font.data = kmalloc(max_font_size, GFP_KERNEL);
font.data = kvmalloc(max_font_size, GFP_KERNEL);
if (!font.data)
return -ENOMEM;
} else
@ -4603,7 +4556,7 @@ static int con_font_get(struct vc_data *vc, struct console_font_op *op)
if (vc->vc_mode != KD_TEXT)
rc = -EINVAL;
else if (vc->vc_sw->con_font_get)
rc = vc->vc_sw->con_font_get(vc, &font);
rc = vc->vc_sw->con_font_get(vc, &font, vpitch);
else
rc = -ENOSYS;
console_unlock();
@ -4611,7 +4564,7 @@ static int con_font_get(struct vc_data *vc, struct console_font_op *op)
if (rc)
goto out;
c = (font.width+7)/8 * 32 * font.charcount;
c = (font.width+7)/8 * vpitch * font.charcount;
if (op->data && font.charcount > op->charcount)
rc = -ENOSPC;
@ -4628,7 +4581,7 @@ static int con_font_get(struct vc_data *vc, struct console_font_op *op)
rc = -EFAULT;
out:
kfree(font.data);
kvfree(font.data);
return rc;
}
@ -4637,16 +4590,20 @@ static int con_font_set(struct vc_data *vc, struct console_font_op *op)
struct console_font font;
int rc = -EINVAL;
int size;
unsigned int vpitch = op->op == KD_FONT_OP_SET_TALL ? op->height : 32;
if (vc->vc_mode != KD_TEXT)
return -EINVAL;
if (!op->data)
return -EINVAL;
if (op->charcount > 512)
if (op->charcount > max_font_glyphs)
return -EINVAL;
if (op->width <= 0 || op->width > 32 || !op->height || op->height > 32)
if (op->width <= 0 || op->width > max_font_width || !op->height ||
op->height > max_font_height)
return -EINVAL;
size = (op->width+7)/8 * 32 * op->charcount;
if (vpitch < op->height)
return -EINVAL;
size = (op->width+7)/8 * vpitch * op->charcount;
if (size > max_font_size)
return -ENOSPC;
@ -4664,7 +4621,7 @@ static int con_font_set(struct vc_data *vc, struct console_font_op *op)
else if (vc->vc_sw->con_font_set) {
if (vc_is_sel(vc))
clear_selection();
rc = vc->vc_sw->con_font_set(vc, &font, op->flags);
rc = vc->vc_sw->con_font_set(vc, &font, vpitch, op->flags);
} else
rc = -ENOSYS;
console_unlock();
@ -4710,8 +4667,10 @@ int con_font_op(struct vc_data *vc, struct console_font_op *op)
{
switch (op->op) {
case KD_FONT_OP_SET:
case KD_FONT_OP_SET_TALL:
return con_font_set(vc, op);
case KD_FONT_OP_GET:
case KD_FONT_OP_GET_TALL:
return con_font_get(vc, op);
case KD_FONT_OP_SET_DEFAULT:
return con_font_default(vc, op);
@ -4740,10 +4699,11 @@ EXPORT_SYMBOL_GPL(screen_glyph);
u32 screen_glyph_unicode(const struct vc_data *vc, int n)
{
struct uni_screen *uniscr = get_vc_uniscr(vc);
u32 **uni_lines = vc->vc_uni_lines;
if (uni_lines)
return uni_lines[n / vc->vc_cols][n % vc->vc_cols];
if (uniscr)
return uniscr->lines[n / vc->vc_cols][n % vc->vc_cols];
return inverse_translate(vc, screen_glyph(vc, n * 2), true);
}
EXPORT_SYMBOL_GPL(screen_glyph_unicode);

View File

@ -651,13 +651,13 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
return tty_port_open(&acm->port, tty, filp);
}
static void acm_port_dtr_rts(struct tty_port *port, int raise)
static void acm_port_dtr_rts(struct tty_port *port, bool active)
{
struct acm *acm = container_of(port, struct acm, port);
int val;
int res;
if (raise)
if (active)
val = USB_CDC_CTRL_DTR | USB_CDC_CTRL_RTS;
else
val = 0;

View File

@ -169,7 +169,7 @@ static int usb_console_setup(struct console *co, char *options)
tty_save_termios(tty);
tty_kref_put(tty);
}
tty_port_set_initialized(&port->port, 1);
tty_port_set_initialized(&port->port, true);
}
/* Now that any required fake tty operations are completed restore
* the tty port count */

View File

@ -754,7 +754,7 @@ static struct usb_serial_driver *search_serial_device(
return NULL;
}
static int serial_port_carrier_raised(struct tty_port *port)
static bool serial_port_carrier_raised(struct tty_port *port)
{
struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);
struct usb_serial_driver *drv = p->serial->type;
@ -762,10 +762,10 @@ static int serial_port_carrier_raised(struct tty_port *port)
if (drv->carrier_raised)
return drv->carrier_raised(p);
/* No carrier control - don't block */
return 1;
return true;
}
static void serial_port_dtr_rts(struct tty_port *port, int on)
static void serial_port_dtr_rts(struct tty_port *port, bool on)
{
struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);
struct usb_serial_driver *drv = p->serial->type;

View File

@ -497,7 +497,7 @@ static int newport_blank(struct vc_data *c, int blank, int mode_switch)
return 1;
}
static int newport_set_font(int unit, struct console_font *op)
static int newport_set_font(int unit, struct console_font *op, unsigned int vpitch)
{
int w = op->width;
int h = op->height;
@ -507,7 +507,7 @@ static int newport_set_font(int unit, struct console_font *op)
/* ladis: when I grow up, there will be a day... and more sizes will
* be supported ;-) */
if ((w != 8) || (h != 16)
if ((w != 8) || (h != 16) || (vpitch != 32)
|| (op->charcount != 256 && op->charcount != 512))
return -EINVAL;
@ -569,9 +569,10 @@ static int newport_font_default(struct vc_data *vc, struct console_font *op, cha
return newport_set_def_font(vc->vc_num, op);
}
static int newport_font_set(struct vc_data *vc, struct console_font *font, unsigned flags)
static int newport_font_set(struct vc_data *vc, struct console_font *font,
unsigned int vpitch, unsigned int flags)
{
return newport_set_font(vc->vc_num, font);
return newport_set_font(vc->vc_num, font, vpitch);
}
static bool newport_scroll(struct vc_data *vc, unsigned int t, unsigned int b,

View File

@ -169,7 +169,8 @@ static int sticon_set_def_font(int unit, struct console_font *op)
return 0;
}
static int sticon_set_font(struct vc_data *vc, struct console_font *op)
static int sticon_set_font(struct vc_data *vc, struct console_font *op,
unsigned int vpitch)
{
struct sti_struct *sti = sticon_sti;
int vc_cols, vc_rows, vc_old_cols, vc_old_rows;
@ -181,7 +182,7 @@ static int sticon_set_font(struct vc_data *vc, struct console_font *op)
struct sti_cooked_font *cooked_font;
unsigned char *data = op->data, *p;
if ((w < 6) || (h < 6) || (w > 32) || (h > 32)
if ((w < 6) || (h < 6) || (w > 32) || (h > 32) || (vpitch != 32)
|| (op->charcount != 256 && op->charcount != 512))
return -EINVAL;
pitch = ALIGN(w, 8) / 8;
@ -267,9 +268,9 @@ static int sticon_font_default(struct vc_data *vc, struct console_font *op, char
}
static int sticon_font_set(struct vc_data *vc, struct console_font *font,
unsigned int flags)
unsigned int vpitch, unsigned int flags)
{
return sticon_set_font(vc, font);
return sticon_set_font(vc, font, vpitch);
}
static void sticon_init(struct vc_data *c, int init)

View File

@ -1029,7 +1029,7 @@ static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight)
}
static int vgacon_font_set(struct vc_data *c, struct console_font *font,
unsigned int flags)
unsigned int vpitch, unsigned int flags)
{
unsigned charcount = font->charcount;
int rc;
@ -1037,7 +1037,7 @@ static int vgacon_font_set(struct vc_data *c, struct console_font *font,
if (vga_video_type < VIDEO_TYPE_EGAM)
return -EINVAL;
if (font->width != VGA_FONTWIDTH ||
if (font->width != VGA_FONTWIDTH || font->height > 32 || vpitch != 32 ||
(charcount != 256 && charcount != 512))
return -EINVAL;
@ -1050,9 +1050,9 @@ static int vgacon_font_set(struct vc_data *c, struct console_font *font,
return rc;
}
static int vgacon_font_get(struct vc_data *c, struct console_font *font)
static int vgacon_font_get(struct vc_data *c, struct console_font *font, unsigned int vpitch)
{
if (vga_video_type < VIDEO_TYPE_EGAM)
if (vga_video_type < VIDEO_TYPE_EGAM || vpitch != 32)
return -EINVAL;
font->width = VGA_FONTWIDTH;

View File

@ -2266,7 +2266,7 @@ static int fbcon_debug_leave(struct vc_data *vc)
return 0;
}
static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
static int fbcon_get_font(struct vc_data *vc, struct console_font *font, unsigned int vpitch)
{
u8 *fontdata = vc->vc_font.data;
u8 *data = font->data;
@ -2274,6 +2274,8 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
font->width = vc->vc_font.width;
font->height = vc->vc_font.height;
if (font->height > vpitch)
return -ENOSPC;
font->charcount = vc->vc_hi_font_mask ? 512 : 256;
if (!font->data)
return 0;
@ -2285,8 +2287,8 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
for (i = 0; i < font->charcount; i++) {
memcpy(data, fontdata, j);
memset(data + j, 0, 32 - j);
data += 32;
memset(data + j, 0, vpitch - j);
data += vpitch;
fontdata += j;
}
} else if (font->width <= 16) {
@ -2296,8 +2298,8 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
for (i = 0; i < font->charcount; i++) {
memcpy(data, fontdata, j);
memset(data + j, 0, 64 - j);
data += 64;
memset(data + j, 0, 2*vpitch - j);
data += 2*vpitch;
fontdata += j;
}
} else if (font->width <= 24) {
@ -2311,8 +2313,8 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
*data++ = fontdata[2];
fontdata += sizeof(u32);
}
memset(data, 0, 3 * (32 - j));
data += 3 * (32 - j);
memset(data, 0, 3 * (vpitch - j));
data += 3 * (vpitch - j);
}
} else {
j = vc->vc_font.height * 4;
@ -2321,8 +2323,8 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
for (i = 0; i < font->charcount; i++) {
memcpy(data, fontdata, j);
memset(data + j, 0, 128 - j);
data += 128;
memset(data + j, 0, 4 * vpitch - j);
data += 4 * vpitch;
fontdata += j;
}
}
@ -2457,19 +2459,12 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
}
/*
* User asked to set font; we are guaranteed that
* a) width and height are in range 1..32
* b) charcount does not exceed 512
* but lets not assume that, since someone might someday want to use larger
* fonts. And charcount of 512 is small for unicode support.
*
* However, user space gives the font in 32 rows , regardless of
* actual font height. So a new API is needed if support for larger fonts
* is ever implemented.
* User asked to set font; we are guaranteed that charcount does not exceed 512
* but lets not assume that, since charcount of 512 is small for unicode support.
*/
static int fbcon_set_font(struct vc_data *vc, struct console_font *font,
unsigned int flags)
unsigned int vpitch, unsigned int flags)
{
struct fb_info *info = fbcon_info_from_console(vc->vc_num);
unsigned charcount = font->charcount;
@ -2515,7 +2510,7 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font,
FNTSIZE(new_data) = size;
REFCOUNT(new_data) = 0; /* usage counter */
for (i=0; i< charcount; i++) {
memcpy(new_data + i*h*pitch, data + i*32*pitch, h*pitch);
memcpy(new_data + i*h*pitch, data + i*vpitch*pitch, h*pitch);
}
/* Since linux has a nice crc32 function use it for counting font

View File

@ -60,8 +60,9 @@ struct consw {
int (*con_switch)(struct vc_data *vc);
int (*con_blank)(struct vc_data *vc, int blank, int mode_switch);
int (*con_font_set)(struct vc_data *vc, struct console_font *font,
unsigned int flags);
int (*con_font_get)(struct vc_data *vc, struct console_font *font);
unsigned int vpitch, unsigned int flags);
int (*con_font_get)(struct vc_data *vc, struct console_font *font,
unsigned int vpitch);
int (*con_font_default)(struct vc_data *vc,
struct console_font *font, char *name);
int (*con_resize)(struct vc_data *vc, unsigned int width,

View File

@ -18,7 +18,6 @@
#include <linux/workqueue.h>
struct uni_pagedict;
struct uni_screen;
#define NPAR 16
#define VC_TABSTOPS_COUNT 256U
@ -159,7 +158,7 @@ struct vc_data {
struct vc_data **vc_display_fg; /* [!] Ptr to var holding fg console for this display */
struct uni_pagedict *uni_pagedict;
struct uni_pagedict **uni_pagedict_loc; /* [!] Location of uni_pagedict variable for this console */
struct uni_screen *vc_uni_screen; /* unicode screen content */
u32 **vc_uni_lines; /* unicode screen content */
/* additional information is in vt_kern.h */
};

View File

@ -27,11 +27,15 @@ enum dfl_id_type {
* @id: id of the dfl device.
* @type: type of DFL FIU of the device. See enum dfl_id_type.
* @feature_id: feature identifier local to its DFL FIU type.
* @revision: revision of this dfl device feature.
* @mmio_res: mmio resource of this dfl device.
* @irqs: list of Linux IRQ numbers of this dfl device.
* @num_irqs: number of IRQs supported by this dfl device.
* @cdev: pointer to DFL FPGA container device this dfl device belongs to.
* @id_entry: matched id entry in dfl driver's id table.
* @dfh_version: version of DFH for the device
* @param_size: size of the block parameters in bytes
* @params: pointer to block of parameters copied memory
*/
struct dfl_device {
struct device dev;
@ -44,6 +48,9 @@ struct dfl_device {
unsigned int num_irqs;
struct dfl_fpga_cdev *cdev;
const struct dfl_device_id *id_entry;
u8 dfh_version;
unsigned int param_size;
void *params;
};
/**
@ -84,4 +91,5 @@ void dfl_driver_unregister(struct dfl_driver *dfl_drv);
module_driver(__dfl_driver, dfl_driver_register, \
dfl_driver_unregister)
void *dfh_find_param(struct dfl_device *dfl_dev, int param_id, size_t *pcount);
#endif /* __LINUX_DFL_H */

View File

@ -12,6 +12,11 @@
#include <uapi/linux/serial.h>
#include <uapi/linux/serial_reg.h>
#define UART_IER_ALL_INTR (UART_IER_MSI | \
UART_IER_RLSI | \
UART_IER_THRI | \
UART_IER_RDI)
/* Helper for dealing with UART_LCR_WLEN* defines */
#define UART_LCR_WLEN(x) ((x) - 5)
@ -23,6 +28,11 @@ static inline bool uart_lsr_tx_empty(u16 lsr)
return (lsr & UART_LSR_BOTH_EMPTY) == UART_LSR_BOTH_EMPTY;
}
#define UART_MSR_STATUS_BITS (UART_MSR_DCD | \
UART_MSR_RI | \
UART_MSR_DSR | \
UART_MSR_CTS)
/*
* Counters of the input lines (CTS, DSR, RI, CD) interrupts
*/

View File

@ -579,6 +579,7 @@ struct uart_port {
struct serial_rs485 rs485;
struct serial_rs485 rs485_supported; /* Supported mask for serial_rs485 */
struct gpio_desc *rs485_term_gpio; /* enable RS485 bus termination */
struct gpio_desc *rs485_rx_during_tx_gpio; /* Output GPIO that sets the state of RS485 RX during TX */
struct serial_iso7816 iso7816;
void *private_data; /* generic platform data pointer */
};
@ -781,7 +782,7 @@ static inline int uart_poll_timeout(struct uart_port *port)
struct earlycon_device {
struct console *con;
struct uart_port port;
char options[16]; /* e.g., 115200n8 */
char options[32]; /* e.g., 115200n8 */
unsigned int baud;
};
@ -896,10 +897,8 @@ static inline bool uart_softcts_mode(struct uart_port *uport)
* The following are helper functions for the low level drivers.
*/
extern void uart_handle_dcd_change(struct uart_port *uport,
unsigned int status);
extern void uart_handle_cts_change(struct uart_port *uport,
unsigned int status);
extern void uart_handle_dcd_change(struct uart_port *uport, bool active);
extern void uart_handle_cts_change(struct uart_port *uport, bool active);
extern void uart_insert_char(struct uart_port *port, unsigned int status,
unsigned int overrun, unsigned int ch, unsigned int flag);

View File

@ -103,6 +103,7 @@ struct geni_se {
#define SE_DMA_TX_FSM_RST 0xc58
#define SE_DMA_RX_IRQ_STAT 0xd40
#define SE_DMA_RX_IRQ_CLR 0xd44
#define SE_DMA_RX_LEN_IN 0xd54
#define SE_DMA_RX_FSM_RST 0xd58
#define SE_HW_PARAM_0 0xe24
#define SE_HW_PARAM_1 0xe28
@ -235,6 +236,8 @@ struct geni_se {
#define RX_SBE BIT(2)
#define RX_RESET_DONE BIT(3)
#define RX_FLUSH_DONE BIT(4)
#define RX_DMA_PARITY_ERR BIT(5)
#define RX_DMA_BREAK GENMASK(8, 7)
#define RX_GENI_GP_IRQ GENMASK(10, 5)
#define RX_GENI_CANCEL_IRQ BIT(11)
#define RX_GENI_GP_IRQ_EXT GENMASK(13, 12)

View File

@ -453,7 +453,7 @@ unsigned char tty_get_char_size(unsigned int cflag);
unsigned char tty_get_frame_size(unsigned int cflag);
void tty_termios_copy_hw(struct ktermios *new, const struct ktermios *old);
int tty_termios_hw_change(const struct ktermios *a, const struct ktermios *b);
bool tty_termios_hw_change(const struct ktermios *a, const struct ktermios *b);
int tty_set_termios(struct tty_struct *tty, struct ktermios *kt);
void tty_wakeup(struct tty_struct *tty);

View File

@ -170,7 +170,7 @@ int ldsem_down_write_nested(struct ld_semaphore *sem, int subclass,
* send, please arise a tasklet or workqueue to do the real data transfer.
* Do not send data in this hook, it may lead to a deadlock.
*
* @dcd_change: [DRV] ``void ()(struct tty_struct *tty, unsigned int status)``
* @dcd_change: [DRV] ``void ()(struct tty_struct *tty, bool active)``
*
* Tells the discipline that the DCD pin has changed its status. Used
* exclusively by the %N_PPS (Pulse-Per-Second) line discipline.
@ -238,7 +238,7 @@ struct tty_ldisc_ops {
void (*receive_buf)(struct tty_struct *tty, const unsigned char *cp,
const char *fp, int count);
void (*write_wakeup)(struct tty_struct *tty);
void (*dcd_change)(struct tty_struct *tty, unsigned int status);
void (*dcd_change)(struct tty_struct *tty, bool active);
int (*receive_buf2)(struct tty_struct *tty, const unsigned char *cp,
const char *fp, int count);
void (*lookahead_buf)(struct tty_struct *tty, const unsigned char *cp,

View File

@ -15,8 +15,8 @@ struct tty_struct;
/**
* struct tty_port_operations -- operations on tty_port
* @carrier_raised: return 1 if the carrier is raised on @port
* @dtr_rts: raise the DTR line if @raise is nonzero, otherwise lower DTR
* @carrier_raised: return true if the carrier is raised on @port
* @dtr_rts: raise the DTR line if @active is true, otherwise lower DTR
* @shutdown: called when the last close completes or a hangup finishes IFF the
* port was initialized. Do not use to free resources. Turn off the device
* only. Called under the port mutex to serialize against @activate and
@ -31,8 +31,8 @@ struct tty_struct;
* the port itself.
*/
struct tty_port_operations {
int (*carrier_raised)(struct tty_port *port);
void (*dtr_rts)(struct tty_port *port, int raise);
bool (*carrier_raised)(struct tty_port *port);
void (*dtr_rts)(struct tty_port *port, bool active);
void (*shutdown)(struct tty_port *port);
int (*activate)(struct tty_port *port, struct tty_struct *tty);
void (*destruct)(struct tty_port *port);
@ -230,7 +230,7 @@ static inline void tty_port_set_kopened(struct tty_port *port, bool val)
struct tty_struct *tty_port_tty_get(struct tty_port *port);
void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty);
int tty_port_carrier_raised(struct tty_port *port);
bool tty_port_carrier_raised(struct tty_port *port);
void tty_port_raise_dtr_rts(struct tty_port *port);
void tty_port_lower_dtr_rts(struct tty_port *port);
void tty_port_hangup(struct tty_port *port);

View File

@ -19,8 +19,7 @@ struct gsm_config
unsigned int mtu;
unsigned int k;
unsigned int i;
unsigned int unused[8]; /* Padding for expansion without
breaking stuff */
unsigned int unused[8]; /* Can not be used */
};
#define GSMIOC_GETCONF _IOR('G', 0, struct gsm_config)
@ -29,9 +28,9 @@ struct gsm_config
struct gsm_netconfig {
unsigned int adaption; /* Adaption to use in network mode */
unsigned short protocol;/* Protocol to use - only ETH_P_IP supported */
unsigned short unused2;
unsigned short unused2; /* Can not be used */
char if_name[IFNAMSIZ]; /* interface name format string */
__u8 unused[28]; /* For future use */
__u8 unused[28]; /* Can not be used */
};
#define GSMIOC_ENABLE_NET _IOW('G', 2, struct gsm_netconfig)
@ -40,4 +39,14 @@ struct gsm_netconfig {
/* get the base tty number for a configured gsmmux tty */
#define GSMIOC_GETFIRST _IOR('G', 4, __u32)
struct gsm_config_ext {
__u32 keep_alive; /* Control channel keep-alive in 1/100th of a
* second (0 to disable)
*/
__u32 reserved[7]; /* For future use, must be initialized to zero */
};
#define GSMIOC_GETCONF_EXT _IOR('G', 5, struct gsm_config_ext)
#define GSMIOC_SETCONF_EXT _IOW('G', 6, struct gsm_config_ext)
#endif

Some files were not shown because too many files have changed in this diff Show More