TTY / Serial driver changes for 5.19-rc1

Here is the big set of tty and serial driver updates for 5.19-rc1.
 
 Lots of tiny cleanups in here, the major stuff is:
 	- termbit cleanups and unification by Ilpo.  A much needed
 	  change that goes a long way to making things simpler for all
 	  of the different arches
 	- tty documentation cleanups and movements to their own place in
 	  the documentation tree
 	- old tty driver cleanups and fixes from Jiri to bring some
 	  existing drivers into the modern world
 	- RS485 cleanups and unifications to make it easier for
 	  individual drivers to support this mode instead of having to
 	  duplicate logic in each driver
 	- Lots of 8250 driver updates and additions
 	- new device id additions
 	- n_gsm continued fixes and cleanups
 	- other minor serial driver updates and cleanups
 
 All of these have been in linux-next for weeks with no reported issues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCYpndTg8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ykFegCgizjLDyOepr72zMDWWdp0bBTekz8AoMWODfJY
 vB8/kzu329DImJMFB8ET
 =rmv0
 -----END PGP SIGNATURE-----

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

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

  Lots of tiny cleanups in here, the major stuff is:

   - termbit cleanups and unification by Ilpo. A much needed change that
     goes a long way to making things simpler for all of the different
     arches

   - tty documentation cleanups and movements to their own place in the
     documentation tree

   - old tty driver cleanups and fixes from Jiri to bring some existing
     drivers into the modern world

   - RS485 cleanups and unifications to make it easier for individual
     drivers to support this mode instead of having to duplicate logic
     in each driver

   - Lots of 8250 driver updates and additions

   - new device id additions

   - n_gsm continued fixes and cleanups

   - other minor serial driver updates and cleanups

  All of these have been in linux-next for weeks with no reported issues"

* tag 'tty-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (166 commits)
  tty: Rework receive flow control char logic
  pcmcia: synclink_cs: Don't allow CS5-6
  serial: stm32-usart: Correct CSIZE, bits, and parity
  serial: st-asc: Sanitize CSIZE and correct PARENB for CS7
  serial: sifive: Sanitize CSIZE and c_iflag
  serial: sh-sci: Don't allow CS5-6
  serial: txx9: Don't allow CS5-6
  serial: rda-uart: Don't allow CS5-6
  serial: digicolor-usart: Don't allow CS5-6
  serial: uartlite: Fix BRKINT clearing
  serial: cpm_uart: Fix build error without CONFIG_SERIAL_CPM_CONSOLE
  serial: core: Do stop_rx in suspend path for console if console_suspend is disabled
  tty: serial: qcom-geni-serial: Remove uart frequency table. Instead, find suitable frequency with call to clk_round_rate.
  dt-bindings: serial: renesas,em-uart: Add RZ/V2M clock to access the registers
  serial: 8250_fintek: Check SER_RS485_RTS_* only with RS485
  Revert "serial: 8250_mtk: Make sure to select the right FEATURE_SEL"
  serial: msm_serial: disable interrupts in __msm_console_write()
  serial: meson: acquire port->lock in startup()
  serial: 8250_dw: Use dev_err_probe()
  serial: 8250_dw: Use devm_add_action_or_reset()
  ...
This commit is contained in:
Linus Torvalds 2022-06-03 11:08:40 -07:00
commit 932c2989b5
114 changed files with 3166 additions and 2453 deletions

View File

@ -23,7 +23,9 @@ properties:
- fsl,imx8qxp-lpuart
- fsl,imxrt1050-lpuart
- items:
- const: fsl,imx8ulp-lpuart
- enum:
- fsl,imx93-lpuart
- fsl,imx8ulp-lpuart
- const: fsl,imx7ulp-lpuart
- items:
- enum:

View File

@ -0,0 +1,86 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/serial/qcom,serial-geni-qcom.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: Qualcomm Geni based QUP UART interface
maintainers:
- Andy Gross <agross@kernel.org>
- Bjorn Andersson <bjorn.andersson@linaro.org>
allOf:
- $ref: /schemas/serial/serial.yaml#
properties:
compatible:
enum:
- qcom,geni-uart
- qcom,geni-debug-uart
clocks:
maxItems: 1
clock-names:
const: se
interconnects:
maxItems: 2
interconnect-names:
items:
- const: qup-core
- const: qup-config
interrupts:
minItems: 1
items:
- description: UART core irq
- description: Wakeup irq (RX GPIO)
operating-points-v2: true
pinctrl-0: true
pinctrl-1: true
pinctrl-names:
minItems: 1
items:
- const: default
- const: sleep
power-domains:
maxItems: 1
reg:
maxItems: 1
required:
- compatible
- clocks
- clock-names
- interrupts
- reg
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/qcom,gcc-sc7180.h>
#include <dt-bindings/interconnect/qcom,sc7180.h>
serial@a88000 {
compatible = "qcom,geni-uart";
reg = <0xa88000 0x7000>;
interrupts = <GIC_SPI 355 IRQ_TYPE_LEVEL_HIGH>;
clock-names = "se";
clocks = <&gcc GCC_QUPV3_WRAP0_S0_CLK>;
pinctrl-0 = <&qup_uart0_default>;
pinctrl-names = "default";
interconnects = <&qup_virt MASTER_QUP_CORE_0 0 &qup_virt SLAVE_QUP_CORE_0 0>,
<&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_QUP_0 0>;
interconnect-names = "qup-core", "qup-config";
};
...

View File

@ -9,12 +9,16 @@ title: Renesas EMMA Mobile UART Interface
maintainers:
- Magnus Damm <magnus.damm@gmail.com>
allOf:
- $ref: serial.yaml#
properties:
compatible:
const: renesas,em-uart
oneOf:
- items:
- enum:
- renesas,r9a09g011-uart # RZ/V2M
- const: renesas,em-uart # generic EMMA Mobile compatible UART
- items:
- const: renesas,em-uart # generic EMMA Mobile compatible UART
reg:
maxItems: 1
@ -23,10 +27,31 @@ properties:
maxItems: 1
clocks:
maxItems: 1
minItems: 1
items:
- description: UART functional clock
- description: Internal clock to access the registers
clock-names:
const: sclk
minItems: 1
items:
- const: sclk
- const: pclk
allOf:
- $ref: serial.yaml#
- if:
properties:
compatible:
contains:
const: renesas,r9a09g011-uart
then:
properties:
clocks:
minItems: 2
clock-names:
minItems: 2
required:
- compatible

View File

@ -51,10 +51,16 @@ properties:
- renesas,hscif-r8a77980 # R-Car V3H
- renesas,hscif-r8a77990 # R-Car E3
- renesas,hscif-r8a77995 # R-Car D3
- renesas,hscif-r8a779a0 # R-Car V3U
- const: renesas,rcar-gen3-hscif # R-Car Gen3 and RZ/G2
- const: renesas,hscif # generic HSCIF compatible UART
- items:
- enum:
- renesas,hscif-r8a779a0 # R-Car V3U
- renesas,hscif-r8a779g0 # R-Car V4H
- const: renesas,rcar-gen4-hscif # R-Car Gen4
- const: renesas,hscif # generic HSCIF compatible UART
reg:
maxItems: 1
@ -113,6 +119,7 @@ if:
enum:
- renesas,rcar-gen2-hscif
- renesas,rcar-gen3-hscif
- renesas,rcar-gen4-hscif
then:
required:
- resets

View File

@ -60,12 +60,12 @@ properties:
- renesas,scif-r8a77980 # R-Car V3H
- renesas,scif-r8a77990 # R-Car E3
- renesas,scif-r8a77995 # R-Car D3
- renesas,scif-r8a779a0 # R-Car V3U
- const: renesas,rcar-gen3-scif # R-Car Gen3 and RZ/G2
- const: renesas,scif # generic SCIF compatible UART
- items:
- enum:
- renesas,scif-r8a779a0 # R-Car V3U
- renesas,scif-r8a779f0 # R-Car S4-8
- const: renesas,rcar-gen4-scif # R-Car Gen4
- const: renesas,scif # generic SCIF compatible UART

View File

@ -33,6 +33,11 @@ properties:
description: drive RTS low when sending (default is high).
$ref: /schemas/types.yaml#/definitions/flag
rs485-rx-active-high:
description: Polarity of receiver enable signal (when separate from RTS).
True indicates active high (default is low).
$ref: /schemas/types.yaml#/definitions/flag
linux,rs485-enabled-at-boot-time:
description: enables the rs485 feature at boot time. It can be disabled
later with proper ioctl.

View File

@ -20,7 +20,10 @@ properties:
maxItems: 1
clocks:
minItems: 1
maxItems: 1
resets:
maxItems: 1
auto-flow-control:
description: enable automatic flow control support.

View File

@ -101,6 +101,7 @@ available subsections can be seen below.
surface_aggregator/index
switchtec
sync_file
tty/index
vfio-mediated-device
vfio
vfio-pci-device-specific-driver-acceptance

View File

@ -311,7 +311,7 @@ hardware.
This call must not sleep
set_ldisc(port,termios)
Notifier for discipline change. See Documentation/tty/tty_ldisc.rst.
Notifier for discipline change. See ../tty/tty_ldisc.rst.
Locking: caller holds tty_port->mutex

View File

@ -16,8 +16,6 @@ Serial drivers
.. toctree::
:maxdepth: 1
moxa-smartio
n_gsm
serial-iso7816
serial-rs485

View File

@ -1,159 +0,0 @@
==============================
GSM 0710 tty multiplexor HOWTO
==============================
This line discipline implements the GSM 07.10 multiplexing protocol
detailed in the following 3GPP document:
https://www.3gpp.org/ftp/Specs/archive/07_series/07.10/0710-720.zip
This document give some hints on how to use this driver with GPRS and 3G
modems connected to a physical serial port.
How to use it
-------------
1. config initiator
^^^^^^^^^^^^^^^^^^^^^
1.1 initialize the modem in 0710 mux mode (usually AT+CMUX= command) through
its serial port. Depending on the modem used, you can pass more or less
parameters to this command.
1.2 switch the serial line to using the n_gsm line discipline by using
TIOCSETD ioctl.
1.3 configure the mux using GSMIOC_GETCONF / GSMIOC_SETCONF ioctl.
1.4 obtain base gsmtty number for the used serial port.
Major parts of the initialization program :
(a good starting point is util-linux-ng/sys-utils/ldattach.c)::
#include <stdio.h>
#include <stdint.h>
#include <linux/gsmmux.h>
#include <linux/tty.h>
#define DEFAULT_SPEED B115200
#define SERIAL_PORT /dev/ttyS0
int ldisc = N_GSM0710;
struct gsm_config c;
struct termios configuration;
uint32_t first;
/* open the serial port connected to the modem */
fd = open(SERIAL_PORT, O_RDWR | O_NOCTTY | O_NDELAY);
/* configure the serial port : speed, flow control ... */
/* send the AT commands to switch the modem to CMUX mode
and check that it's successful (should return OK) */
write(fd, "AT+CMUX=0\r", 10);
/* experience showed that some modems need some time before
being able to answer to the first MUX packet so a delay
may be needed here in some case */
sleep(3);
/* use n_gsm line discipline */
ioctl(fd, TIOCSETD, &ldisc);
/* get n_gsm configuration */
ioctl(fd, GSMIOC_GETCONF, &c);
/* we are initiator and need encoding 0 (basic) */
c.initiator = 1;
c.encapsulation = 0;
/* our modem defaults to a maximum size of 127 bytes */
c.mru = 127;
c.mtu = 127;
/* set the new configuration */
ioctl(fd, GSMIOC_SETCONF, &c);
/* get first gsmtty device node */
ioctl(fd, GSMIOC_GETFIRST, &first);
printf("first muxed line: /dev/gsmtty%i\n", first);
/* and wait for ever to keep the line discipline enabled */
daemon(0,0);
pause();
1.5 use these devices as plain serial ports.
for example, it's possible:
- and to use gnokii to send / receive SMS on ttygsm1
- to use ppp to establish a datalink on ttygsm2
1.6 first close all virtual ports before closing the physical port.
Note that after closing the physical port the modem is still in multiplexing
mode. This may prevent a successful re-opening of the port later. To avoid
this situation either reset the modem if your hardware allows that or send
a disconnect command frame manually before initializing the multiplexing mode
for the second time. The byte sequence for the disconnect command frame is::
0xf9, 0x03, 0xef, 0x03, 0xc3, 0x16, 0xf9.
2. config requester
^^^^^^^^^^^^^^^^^^^^^
2.1 receive string "AT+CMUX= command" through its serial port,initialize
mux mode config
2.2 switch the serial line to using the n_gsm line discipline by using
TIOCSETD ioctl.
2.3 configure the mux using GSMIOC_GETCONF / GSMIOC_SETCONF ioctl.
2.4 obtain base gsmtty number for the used serial port::
#include <stdio.h>
#include <stdint.h>
#include <linux/gsmmux.h>
#include <linux/tty.h>
#define DEFAULT_SPEED B115200
#define SERIAL_PORT /dev/ttyS0
int ldisc = N_GSM0710;
struct gsm_config c;
struct termios configuration;
uint32_t first;
/* open the serial port */
fd = open(SERIAL_PORT, O_RDWR | O_NOCTTY | O_NDELAY);
/* configure the serial port : speed, flow control ... */
/* get serial data and check "AT+CMUX=command" parameter ... */
/* use n_gsm line discipline */
ioctl(fd, TIOCSETD, &ldisc);
/* get n_gsm configuration */
ioctl(fd, GSMIOC_GETCONF, &c);
/* we are requester and need encoding 0 (basic) */
c.initiator = 0;
c.encapsulation = 0;
/* our modem defaults to a maximum size of 127 bytes */
c.mru = 127;
c.mtu = 127;
/* set the new configuration */
ioctl(fd, GSMIOC_SETCONF, &c);
/* get first gsmtty device node */
ioctl(fd, GSMIOC_GETFIRST, &first);
printf("first muxed line: /dev/gsmtty%i\n", first);
/* and wait for ever to keep the line discipline enabled */
daemon(0,0);
pause();
Additional Documentation
------------------------
More practical details on the protocol and how it's supported by industrial
modems can be found in the following documents :
- http://www.telit.com/module/infopool/download.php?id=616
- http://www.u-blox.com/images/downloads/Product_Docs/LEON-G100-G200-MuxImplementation_ApplicationNote_%28GSM%20G1-CS-10002%29.pdf
- http://www.sierrawireless.com/Support/Downloads/AirPrime/WMP_Series/~/media/Support_Downloads/AirPrime/Application_notes/CMUX_Feature_Application_Note-Rev004.ashx
- http://wm.sim.com/sim/News/photo/2010721161442.pdf
11-03-08 - Eric Bénard - <eric@eukrea.com>

View File

@ -36,18 +36,16 @@ In-detail description of the named TTY structures is in separate documents:
tty_struct
tty_ldisc
tty_buffer
n_tty
tty_internals
Writing TTY Driver
==================
Before one starts writing a TTY driver, they must consider
:doc:`Serial <../driver-api/serial/driver>` and :doc:`USB Serial
<../usb/usb-serial>` layers
first. Drivers for serial devices can often use one of these specific layers to
implement a serial driver. Only special devices should be handled directly by
the TTY Layer. If you are about to write such a driver, read on.
:doc:`Serial <../serial/driver>` and :doc:`USB Serial <../../usb/usb-serial>`
layers first. Drivers for serial devices can often use one of these specific
layers to implement a serial driver. Only special devices should be handled
directly by the TTY Layer. If you are about to write such a driver, read on.
A *typical* sequence a TTY driver performs is as follows:
@ -61,3 +59,15 @@ A *typical* sequence a TTY driver performs is as follows:
Steps regarding driver, i.e. 1., 3., and 5. are described in detail in
:doc:`tty_driver`. For the other two (devices handling), look into
:doc:`tty_port`.
Other Documentation
===================
Miscellaneous documentation can be further found in these documents:
.. toctree::
:maxdepth: 2
moxa-smartio
n_gsm
n_tty

View File

@ -0,0 +1,153 @@
==============================
GSM 0710 tty multiplexor HOWTO
==============================
.. contents:: :local:
This line discipline implements the GSM 07.10 multiplexing protocol
detailed in the following 3GPP document:
https://www.3gpp.org/ftp/Specs/archive/07_series/07.10/0710-720.zip
This document give some hints on how to use this driver with GPRS and 3G
modems connected to a physical serial port.
How to use it
=============
Config Initiator
----------------
#. Initialize the modem in 0710 mux mode (usually ``AT+CMUX=`` command) through
its serial port. Depending on the modem used, you can pass more or less
parameters to this command.
#. Switch the serial line to using the n_gsm line discipline by using
``TIOCSETD`` ioctl.
#. Configure the mux using ``GSMIOC_GETCONF``/``GSMIOC_SETCONF`` ioctl.
#. Obtain base gsmtty number for the used serial port.
Major parts of the initialization program
(a good starting point is util-linux-ng/sys-utils/ldattach.c)::
#include <stdio.h>
#include <stdint.h>
#include <linux/gsmmux.h>
#include <linux/tty.h>
#define DEFAULT_SPEED B115200
#define SERIAL_PORT /dev/ttyS0
int ldisc = N_GSM0710;
struct gsm_config c;
struct termios configuration;
uint32_t first;
/* open the serial port connected to the modem */
fd = open(SERIAL_PORT, O_RDWR | O_NOCTTY | O_NDELAY);
/* configure the serial port : speed, flow control ... */
/* send the AT commands to switch the modem to CMUX mode
and check that it's successful (should return OK) */
write(fd, "AT+CMUX=0\r", 10);
/* experience showed that some modems need some time before
being able to answer to the first MUX packet so a delay
may be needed here in some case */
sleep(3);
/* use n_gsm line discipline */
ioctl(fd, TIOCSETD, &ldisc);
/* get n_gsm configuration */
ioctl(fd, GSMIOC_GETCONF, &c);
/* we are initiator and need encoding 0 (basic) */
c.initiator = 1;
c.encapsulation = 0;
/* our modem defaults to a maximum size of 127 bytes */
c.mru = 127;
c.mtu = 127;
/* set the new configuration */
ioctl(fd, GSMIOC_SETCONF, &c);
/* get first gsmtty device node */
ioctl(fd, GSMIOC_GETFIRST, &first);
printf("first muxed line: /dev/gsmtty%i\n", first);
/* and wait for ever to keep the line discipline enabled */
daemon(0,0);
pause();
#. Use these devices as plain serial ports.
For example, it's possible:
- to use *gnokii* to send / receive SMS on ``ttygsm1``
- to use *ppp* to establish a datalink on ``ttygsm2``
#. First close all virtual ports before closing the physical port.
Note that after closing the physical port the modem is still in multiplexing
mode. This may prevent a successful re-opening of the port later. To avoid
this situation either reset the modem if your hardware allows that or send
a disconnect command frame manually before initializing the multiplexing mode
for the second time. The byte sequence for the disconnect command frame is::
0xf9, 0x03, 0xef, 0x03, 0xc3, 0x16, 0xf9
Config Requester
----------------
#. Receive ``AT+CMUX=`` command through its serial port, initialize mux mode
config.
#. Switch the serial line to using the *n_gsm* line discipline by using
``TIOCSETD`` ioctl.
#. Configure the mux using ``GSMIOC_GETCONF``/``GSMIOC_SETCONF`` ioctl.
#. Obtain base gsmtty number for the used serial port::
#include <stdio.h>
#include <stdint.h>
#include <linux/gsmmux.h>
#include <linux/tty.h>
#define DEFAULT_SPEED B115200
#define SERIAL_PORT /dev/ttyS0
int ldisc = N_GSM0710;
struct gsm_config c;
struct termios configuration;
uint32_t first;
/* open the serial port */
fd = open(SERIAL_PORT, O_RDWR | O_NOCTTY | O_NDELAY);
/* configure the serial port : speed, flow control ... */
/* get serial data and check "AT+CMUX=command" parameter ... */
/* use n_gsm line discipline */
ioctl(fd, TIOCSETD, &ldisc);
/* get n_gsm configuration */
ioctl(fd, GSMIOC_GETCONF, &c);
/* we are requester and need encoding 0 (basic) */
c.initiator = 0;
c.encapsulation = 0;
/* our modem defaults to a maximum size of 127 bytes */
c.mru = 127;
c.mtu = 127;
/* set the new configuration */
ioctl(fd, GSMIOC_SETCONF, &c);
/* get first gsmtty device node */
ioctl(fd, GSMIOC_GETFIRST, &first);
printf("first muxed line: /dev/gsmtty%i\n", first);
/* and wait for ever to keep the line discipline enabled */
daemon(0,0);
pause();
11-03-08 - Eric Bénard - <eric@eukrea.com>

View File

@ -389,6 +389,31 @@ descriptors once the device is released.
See Documentation/firmware-guide/acpi/gpio-properties.rst for more information
about the _DSD binding related to GPIOs.
RS-485 support
==============
ACPI _DSD (Device Specific Data) can be used to describe RS-485 capability
of UART.
For example::
Device (DEV)
{
...
// ACPI 5.1 _DSD used for RS-485 capabilities
Name (_DSD, Package ()
{
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package ()
{
Package () {"rs485-rts-active-low", Zero},
Package () {"rs485-rx-active-high", Zero},
Package () {"rs485-rx-during-tx", Zero},
}
})
...
MFD devices
===========

View File

@ -136,7 +136,6 @@ needed).
misc-devices/index
scheduler/index
mhi/index
tty/index
peci/index
Architecture-agnostic documentation

View File

@ -25,6 +25,7 @@ fit into other categories.
isl29003
lis3lv02d
max6875
oxsemi-tornado
pci-endpoint-test
spear-pcie-gadget
uacce

View File

@ -0,0 +1,131 @@
.. SPDX-License-Identifier: GPL-2.0
====================================================================
Notes on Oxford Semiconductor PCIe (Tornado) 950 serial port devices
====================================================================
Oxford Semiconductor PCIe (Tornado) 950 serial port devices are driven
by a fixed 62.5MHz clock input derived from the 100MHz PCI Express clock.
The baud rate produced by the baud generator is obtained from this input
frequency by dividing it by the clock prescaler, which can be set to any
value from 1 to 63.875 in increments of 0.125, and then the usual 16-bit
divisor is used as with the original 8250, to divide the frequency by a
value from 1 to 65535. Finally a programmable oversampling rate is used
that can take any value from 4 to 16 to divide the frequency further and
determine the actual baud rate used. Baud rates from 15625000bps down
to 0.933bps can be obtained this way.
By default the oversampling rate is set to 16 and the clock prescaler is
set to 33.875, meaning that the frequency to be used as the reference
for the usual 16-bit divisor is 115313.653, which is close enough to the
frequency of 115200 used by the original 8250 for the same values to be
used for the divisor to obtain the requested baud rates by software that
is unaware of the extra clock controls available.
The oversampling rate is programmed with the TCR register and the clock
prescaler is programmed with the CPR/CPR2 register pair [OX200]_ [OX952]_
[OX954]_ [OX958]_. To switch away from the default value of 33.875 for
the prescaler the enhanced mode has to be explicitly enabled though, by
setting bit 4 of the EFR. In that mode setting bit 7 in the MCR enables
the prescaler or otherwise it is bypassed as if the value of 1 was used.
Additionally writing any value to CPR clears CPR2 for compatibility with
old software written for older conventional PCI Oxford Semiconductor
devices that do not have the extra prescaler's 9th bit in CPR2, so the
CPR/CPR2 register pair has to be programmed in the right order.
By using these parameters rates from 15625000bps down to 1bps can be
obtained, with either exact or highly-accurate actual bit rates for
standard and many non-standard rates.
Here are the figures for the standard and some non-standard baud rates
(including those quoted in Oxford Semiconductor documentation), giving
the requested rate (r), the actual rate yielded (a) and its deviation
from the requested rate (d), and the values of the oversampling rate
(tcr), the clock prescaler (cpr) and the divisor (div) produced by the
new ``get_divisor`` handler:
::
r: 15625000, a: 15625000.00, d: 0.0000%, tcr: 4, cpr: 1.000, div: 1
r: 12500000, a: 12500000.00, d: 0.0000%, tcr: 5, cpr: 1.000, div: 1
r: 10416666, a: 10416666.67, d: 0.0000%, tcr: 6, cpr: 1.000, div: 1
r: 8928571, a: 8928571.43, d: 0.0000%, tcr: 7, cpr: 1.000, div: 1
r: 7812500, a: 7812500.00, d: 0.0000%, tcr: 8, cpr: 1.000, div: 1
r: 4000000, a: 4000000.00, d: 0.0000%, tcr: 5, cpr: 3.125, div: 1
r: 3686400, a: 3676470.59, d: -0.2694%, tcr: 8, cpr: 2.125, div: 1
r: 3500000, a: 3496503.50, d: -0.0999%, tcr: 13, cpr: 1.375, div: 1
r: 3000000, a: 2976190.48, d: -0.7937%, tcr: 14, cpr: 1.500, div: 1
r: 2500000, a: 2500000.00, d: 0.0000%, tcr: 10, cpr: 2.500, div: 1
r: 2000000, a: 2000000.00, d: 0.0000%, tcr: 10, cpr: 3.125, div: 1
r: 1843200, a: 1838235.29, d: -0.2694%, tcr: 16, cpr: 2.125, div: 1
r: 1500000, a: 1492537.31, d: -0.4975%, tcr: 5, cpr: 8.375, div: 1
r: 1152000, a: 1152073.73, d: 0.0064%, tcr: 14, cpr: 3.875, div: 1
r: 921600, a: 919117.65, d: -0.2694%, tcr: 16, cpr: 2.125, div: 2
r: 576000, a: 576036.87, d: 0.0064%, tcr: 14, cpr: 3.875, div: 2
r: 460800, a: 460829.49, d: 0.0064%, tcr: 7, cpr: 3.875, div: 5
r: 230400, a: 230414.75, d: 0.0064%, tcr: 14, cpr: 3.875, div: 5
r: 115200, a: 115207.37, d: 0.0064%, tcr: 14, cpr: 1.250, div: 31
r: 57600, a: 57603.69, d: 0.0064%, tcr: 8, cpr: 3.875, div: 35
r: 38400, a: 38402.46, d: 0.0064%, tcr: 14, cpr: 3.875, div: 30
r: 19200, a: 19201.23, d: 0.0064%, tcr: 8, cpr: 3.875, div: 105
r: 9600, a: 9600.06, d: 0.0006%, tcr: 9, cpr: 1.125, div: 643
r: 4800, a: 4799.98, d: -0.0004%, tcr: 7, cpr: 2.875, div: 647
r: 2400, a: 2400.02, d: 0.0008%, tcr: 9, cpr: 2.250, div: 1286
r: 1200, a: 1200.00, d: 0.0000%, tcr: 14, cpr: 2.875, div: 1294
r: 300, a: 300.00, d: 0.0000%, tcr: 11, cpr: 2.625, div: 7215
r: 200, a: 200.00, d: 0.0000%, tcr: 16, cpr: 1.250, div: 15625
r: 150, a: 150.00, d: 0.0000%, tcr: 13, cpr: 2.250, div: 14245
r: 134, a: 134.00, d: 0.0000%, tcr: 11, cpr: 2.625, div: 16153
r: 110, a: 110.00, d: 0.0000%, tcr: 12, cpr: 1.000, div: 47348
r: 75, a: 75.00, d: 0.0000%, tcr: 4, cpr: 5.875, div: 35461
r: 50, a: 50.00, d: 0.0000%, tcr: 16, cpr: 1.250, div: 62500
r: 25, a: 25.00, d: 0.0000%, tcr: 16, cpr: 2.500, div: 62500
r: 4, a: 4.00, d: 0.0000%, tcr: 16, cpr: 20.000, div: 48828
r: 2, a: 2.00, d: 0.0000%, tcr: 16, cpr: 40.000, div: 48828
r: 1, a: 1.00, d: 0.0000%, tcr: 16, cpr: 63.875, div: 61154
With the baud base set to 15625000 and the unsigned 16-bit UART_DIV_MAX
limitation imposed by ``serial8250_get_baud_rate`` standard baud rates
below 300bps become unavailable in the regular way, e.g. the rate of
200bps requires the baud base to be divided by 78125 and that is beyond
the unsigned 16-bit range. The historic spd_cust feature can still be
used by encoding the values for, the prescaler, the oversampling rate
and the clock divisor (DLM/DLL) as follows to obtain such rates if so
required:
::
31 29 28 20 19 16 15 0
+-----+-----------------+-------+-------------------------------+
|0 0 0| CPR2:CPR | TCR | DLM:DLL |
+-----+-----------------+-------+-------------------------------+
Use a value such encoded for the ``custom_divisor`` field along with the
ASYNC_SPD_CUST flag set in the ``flags`` field in ``struct serial_struct``
passed with the TIOCSSERIAL ioctl(2), such as with the setserial(8)
utility and its ``divisor`` and ``spd_cust`` parameters, and then select
the baud rate of 38400bps. Note that the value of 0 in TCR sets the
oversampling rate to 16 and prescaler values below 1 in CPR2/CPR are
clamped by the driver to 1.
For example the value of 0x1f4004e2 will set CPR2/CPR, TCR and DLM/DLL
respectively to 0x1f4, 0x0 and 0x04e2, choosing the prescaler value,
the oversampling rate and the clock divisor of 62.500, 16 and 1250
respectively. These parameters will set the baud rate for the serial
port to 62500000 / 62.500 / 1250 / 16 = 50bps.
Maciej W. Rozycki <macro@orcam.me.uk>
.. [OX200] "OXPCIe200 PCI Express Multi-Port Bridge", Oxford Semiconductor,
Inc., DS-0045, 10 Nov 2008, Section "950 Mode", pp. 64-65
.. [OX952] "OXPCIe952 PCI Express Bridge to Dual Serial & Parallel Port",
Oxford Semiconductor, Inc., DS-0046, Mar 06 08, Section "950 Mode",
p. 20
.. [OX954] "OXPCIe954 PCI Express Bridge to Quad Serial Port", Oxford
Semiconductor, Inc., DS-0047, Feb 08, Section "950 Mode", p. 20
.. [OX958] "OXPCIe958 PCI Express Bridge to Octal Serial Port", Oxford
Semiconductor, Inc., DS-0048, Feb 08, Section "950 Mode", p. 20

View File

@ -13411,7 +13411,7 @@ F: drivers/net/phy/motorcomm.c
MOXA SMARTIO/INDUSTIO/INTELLIO SERIAL CARD
M: Jiri Slaby <jirislaby@kernel.org>
S: Maintained
F: Documentation/driver-api/serial/moxa-smartio.rst
F: Documentation/driver-api/tty/moxa-smartio.rst
F: drivers/tty/mxser.*
MR800 AVERMEDIA USB FM RADIO DRIVER

View File

@ -2,10 +2,8 @@
#ifndef _ALPHA_TERMBITS_H
#define _ALPHA_TERMBITS_H
#include <linux/posix_types.h>
#include <asm-generic/termbits-common.h>
typedef unsigned char cc_t;
typedef unsigned int speed_t;
typedef unsigned int tcflag_t;
/*
@ -53,76 +51,58 @@ struct ktermios {
};
/* c_cc characters */
#define VEOF 0
#define VEOL 1
#define VEOL2 2
#define VERASE 3
#define VWERASE 4
#define VKILL 5
#define VREPRINT 6
#define VSWTC 7
#define VINTR 8
#define VQUIT 9
#define VSUSP 10
#define VSTART 12
#define VSTOP 13
#define VLNEXT 14
#define VDISCARD 15
#define VMIN 16
#define VTIME 17
#define VEOF 0
#define VEOL 1
#define VEOL2 2
#define VERASE 3
#define VWERASE 4
#define VKILL 5
#define VREPRINT 6
#define VSWTC 7
#define VINTR 8
#define VQUIT 9
#define VSUSP 10
#define VSTART 12
#define VSTOP 13
#define VLNEXT 14
#define VDISCARD 15
#define VMIN 16
#define VTIME 17
/* c_iflag bits */
#define IGNBRK 0000001
#define BRKINT 0000002
#define IGNPAR 0000004
#define PARMRK 0000010
#define INPCK 0000020
#define ISTRIP 0000040
#define INLCR 0000100
#define IGNCR 0000200
#define ICRNL 0000400
#define IXON 0001000
#define IXOFF 0002000
#define IXANY 0004000
#define IUCLC 0010000
#define IMAXBEL 0020000
#define IUTF8 0040000
#define IXON 0x0200
#define IXOFF 0x0400
#define IUCLC 0x1000
#define IMAXBEL 0x2000
#define IUTF8 0x4000
/* c_oflag bits */
#define OPOST 0000001
#define ONLCR 0000002
#define OLCUC 0000004
#define OCRNL 0000010
#define ONOCR 0000020
#define ONLRET 0000040
#define OFILL 00000100
#define OFDEL 00000200
#define NLDLY 00001400
#define NL0 00000000
#define NL1 00000400
#define NL2 00001000
#define NL3 00001400
#define TABDLY 00006000
#define TAB0 00000000
#define TAB1 00002000
#define TAB2 00004000
#define TAB3 00006000
#define CRDLY 00030000
#define CR0 00000000
#define CR1 00010000
#define CR2 00020000
#define CR3 00030000
#define FFDLY 00040000
#define FF0 00000000
#define FF1 00040000
#define BSDLY 00100000
#define BS0 00000000
#define BS1 00100000
#define VTDLY 00200000
#define VT0 00000000
#define VT1 00200000
#define ONLCR 0x00002
#define OLCUC 0x00004
#define NLDLY 0x00300
#define NL0 0x00000
#define NL1 0x00100
#define NL2 0x00200
#define NL3 0x00300
#define TABDLY 0x00c00
#define TAB0 0x00000
#define TAB1 0x00400
#define TAB2 0x00800
#define TAB3 0x00c00
#define CRDLY 0x03000
#define CR0 0x00000
#define CR1 0x01000
#define CR2 0x02000
#define CR3 0x03000
#define FFDLY 0x04000
#define FF0 0x00000
#define FF1 0x04000
#define BSDLY 0x08000
#define BS0 0x00000
#define BS1 0x08000
#define VTDLY 0x10000
#define VT0 0x00000
#define VT1 0x10000
/*
* Should be equivalent to TAB3, see description of TAB3 in
* POSIX.1-2008, Ch. 11.2.3 "Output Modes"
@ -130,61 +110,36 @@ struct ktermios {
#define XTABS TAB3
/* c_cflag bit meaning */
#define CBAUD 0000037
#define B0 0000000 /* hang up */
#define B50 0000001
#define B75 0000002
#define B110 0000003
#define B134 0000004
#define B150 0000005
#define B200 0000006
#define B300 0000007
#define B600 0000010
#define B1200 0000011
#define B1800 0000012
#define B2400 0000013
#define B4800 0000014
#define B9600 0000015
#define B19200 0000016
#define B38400 0000017
#define EXTA B19200
#define EXTB B38400
#define CBAUDEX 0000000
#define B57600 00020
#define B115200 00021
#define B230400 00022
#define B460800 00023
#define B500000 00024
#define B576000 00025
#define B921600 00026
#define B1000000 00027
#define B1152000 00030
#define B1500000 00031
#define B2000000 00032
#define B2500000 00033
#define B3000000 00034
#define B3500000 00035
#define B4000000 00036
#define BOTHER 00037
#define CSIZE 00001400
#define CS5 00000000
#define CS6 00000400
#define CS7 00001000
#define CS8 00001400
#define CSTOPB 00002000
#define CREAD 00004000
#define PARENB 00010000
#define PARODD 00020000
#define HUPCL 00040000
#define CLOCAL 00100000
#define CMSPAR 010000000000 /* mark or space (stick) parity */
#define CRTSCTS 020000000000 /* flow control */
#define CIBAUD 07600000
#define IBSHIFT 16
#define CBAUD 0x0000001f
#define CBAUDEX 0x00000000
#define BOTHER 0x0000001f
#define B57600 0x00000010
#define B115200 0x00000011
#define B230400 0x00000012
#define B460800 0x00000013
#define B500000 0x00000014
#define B576000 0x00000015
#define B921600 0x00000016
#define B1000000 0x00000017
#define B1152000 0x00000018
#define B1500000 0x00000019
#define B2000000 0x0000001a
#define B2500000 0x0000001b
#define B3000000 0x0000001c
#define B3500000 0x0000001d
#define B4000000 0x0000001e
#define CSIZE 0x00000300
#define CS5 0x00000000
#define CS6 0x00000100
#define CS7 0x00000200
#define CS8 0x00000300
#define CSTOPB 0x00000400
#define CREAD 0x00000800
#define PARENB 0x00001000
#define PARODD 0x00002000
#define HUPCL 0x00004000
#define CLOCAL 0x00008000
#define CIBAUD 0x001f0000
/* c_lflag bits */
#define ISIG 0x00000080
@ -204,17 +159,6 @@ struct ktermios {
#define IEXTEN 0x00000400
#define EXTPROC 0x10000000
/* Values for the ACTION argument to `tcflow'. */
#define TCOOFF 0
#define TCOON 1
#define TCIOFF 2
#define TCION 3
/* Values for the QUEUE_SELECTOR argument to `tcflush'. */
#define TCIFLUSH 0
#define TCOFLUSH 1
#define TCIOFLUSH 2
/* Values for the OPTIONAL_ACTIONS argument to `tcsetattr'. */
#define TCSANOW 0
#define TCSADRAIN 1

View File

@ -11,11 +11,9 @@
#ifndef _ASM_TERMBITS_H
#define _ASM_TERMBITS_H
#include <linux/posix_types.h>
#include <asm-generic/termbits-common.h>
typedef unsigned char cc_t;
typedef unsigned int speed_t;
typedef unsigned int tcflag_t;
typedef unsigned int tcflag_t;
/*
* The ABI says nothing about NCC but seems to use NCCS as
@ -54,175 +52,126 @@ struct ktermios {
};
/* c_cc characters */
#define VINTR 0 /* Interrupt character [ISIG]. */
#define VQUIT 1 /* Quit character [ISIG]. */
#define VERASE 2 /* Erase character [ICANON]. */
#define VKILL 3 /* Kill-line character [ICANON]. */
#define VMIN 4 /* Minimum number of bytes read at once [!ICANON]. */
#define VTIME 5 /* Time-out value (tenths of a second) [!ICANON]. */
#define VEOL2 6 /* Second EOL character [ICANON]. */
#define VINTR 0 /* Interrupt character [ISIG] */
#define VQUIT 1 /* Quit character [ISIG] */
#define VERASE 2 /* Erase character [ICANON] */
#define VKILL 3 /* Kill-line character [ICANON] */
#define VMIN 4 /* Minimum number of bytes read at once [!ICANON] */
#define VTIME 5 /* Time-out value (tenths of a second) [!ICANON] */
#define VEOL2 6 /* Second EOL character [ICANON] */
#define VSWTC 7 /* ??? */
#define VSWTCH VSWTC
#define VSTART 8 /* Start (X-ON) character [IXON, IXOFF]. */
#define VSTOP 9 /* Stop (X-OFF) character [IXON, IXOFF]. */
#define VSUSP 10 /* Suspend character [ISIG]. */
#define VSTART 8 /* Start (X-ON) character [IXON, IXOFF] */
#define VSTOP 9 /* Stop (X-OFF) character [IXON, IXOFF] */
#define VSUSP 10 /* Suspend character [ISIG] */
#if 0
/*
* VDSUSP is not supported
*/
#define VDSUSP 11 /* Delayed suspend character [ISIG]. */
#define VDSUSP 11 /* Delayed suspend character [ISIG] */
#endif
#define VREPRINT 12 /* Reprint-line character [ICANON]. */
#define VDISCARD 13 /* Discard character [IEXTEN]. */
#define VWERASE 14 /* Word-erase character [ICANON]. */
#define VLNEXT 15 /* Literal-next character [IEXTEN]. */
#define VEOF 16 /* End-of-file character [ICANON]. */
#define VEOL 17 /* End-of-line character [ICANON]. */
#define VREPRINT 12 /* Reprint-line character [ICANON] */
#define VDISCARD 13 /* Discard character [IEXTEN] */
#define VWERASE 14 /* Word-erase character [ICANON] */
#define VLNEXT 15 /* Literal-next character [IEXTEN] */
#define VEOF 16 /* End-of-file character [ICANON] */
#define VEOL 17 /* End-of-line character [ICANON] */
/* c_iflag bits */
#define IGNBRK 0000001 /* Ignore break condition. */
#define BRKINT 0000002 /* Signal interrupt on break. */
#define IGNPAR 0000004 /* Ignore characters with parity errors. */
#define PARMRK 0000010 /* Mark parity and framing errors. */
#define INPCK 0000020 /* Enable input parity check. */
#define ISTRIP 0000040 /* Strip 8th bit off characters. */
#define INLCR 0000100 /* Map NL to CR on input. */
#define IGNCR 0000200 /* Ignore CR. */
#define ICRNL 0000400 /* Map CR to NL on input. */
#define IUCLC 0001000 /* Map upper case to lower case on input. */
#define IXON 0002000 /* Enable start/stop output control. */
#define IXANY 0004000 /* Any character will restart after stop. */
#define IXOFF 0010000 /* Enable start/stop input control. */
#define IMAXBEL 0020000 /* Ring bell when input queue is full. */
#define IUTF8 0040000 /* Input is UTF-8 */
#define IUCLC 0x0200 /* Map upper case to lower case on input */
#define IXON 0x0400 /* Enable start/stop output control */
#define IXOFF 0x1000 /* Enable start/stop input control */
#define IMAXBEL 0x2000 /* Ring bell when input queue is full */
#define IUTF8 0x4000 /* Input is UTF-8 */
/* c_oflag bits */
#define OPOST 0000001 /* Perform output processing. */
#define OLCUC 0000002 /* Map lower case to upper case on output. */
#define ONLCR 0000004 /* Map NL to CR-NL on output. */
#define OCRNL 0000010
#define ONOCR 0000020
#define ONLRET 0000040
#define OFILL 0000100
#define OFDEL 0000200
#define NLDLY 0000400
#define NL0 0000000
#define NL1 0000400
#define CRDLY 0003000
#define CR0 0000000
#define CR1 0001000
#define CR2 0002000
#define CR3 0003000
#define TABDLY 0014000
#define TAB0 0000000
#define TAB1 0004000
#define TAB2 0010000
#define TAB3 0014000
#define XTABS 0014000
#define BSDLY 0020000
#define BS0 0000000
#define BS1 0020000
#define VTDLY 0040000
#define VT0 0000000
#define VT1 0040000
#define FFDLY 0100000
#define FF0 0000000
#define FF1 0100000
#define OLCUC 0x00002 /* Map lower case to upper case on output */
#define ONLCR 0x00004 /* Map NL to CR-NL on output */
#define NLDLY 0x00100
#define NL0 0x00000
#define NL1 0x00100
#define CRDLY 0x00600
#define CR0 0x00000
#define CR1 0x00200
#define CR2 0x00400
#define CR3 0x00600
#define TABDLY 0x01800
#define TAB0 0x00000
#define TAB1 0x00800
#define TAB2 0x01000
#define TAB3 0x01800
#define XTABS 0x01800
#define BSDLY 0x02000
#define BS0 0x00000
#define BS1 0x02000
#define VTDLY 0x04000
#define VT0 0x00000
#define VT1 0x04000
#define FFDLY 0x08000
#define FF0 0x00000
#define FF1 0x08000
/*
#define PAGEOUT ???
#define WRAP ???
*/
/* c_cflag bit meaning */
#define CBAUD 0010017
#define B0 0000000 /* hang up */
#define B50 0000001
#define B75 0000002
#define B110 0000003
#define B134 0000004
#define B150 0000005
#define B200 0000006
#define B300 0000007
#define B600 0000010
#define B1200 0000011
#define B1800 0000012
#define B2400 0000013
#define B4800 0000014
#define B9600 0000015
#define B19200 0000016
#define B38400 0000017
#define EXTA B19200
#define EXTB B38400
#define CSIZE 0000060 /* Number of bits per byte (mask). */
#define CS5 0000000 /* 5 bits per byte. */
#define CS6 0000020 /* 6 bits per byte. */
#define CS7 0000040 /* 7 bits per byte. */
#define CS8 0000060 /* 8 bits per byte. */
#define CSTOPB 0000100 /* Two stop bits instead of one. */
#define CREAD 0000200 /* Enable receiver. */
#define PARENB 0000400 /* Parity enable. */
#define PARODD 0001000 /* Odd parity instead of even. */
#define HUPCL 0002000 /* Hang up on last close. */
#define CLOCAL 0004000 /* Ignore modem status lines. */
#define CBAUDEX 0010000
#define BOTHER 0010000
#define B57600 0010001
#define B115200 0010002
#define B230400 0010003
#define B460800 0010004
#define B500000 0010005
#define B576000 0010006
#define B921600 0010007
#define B1000000 0010010
#define B1152000 0010011
#define B1500000 0010012
#define B2000000 0010013
#define B2500000 0010014
#define B3000000 0010015
#define B3500000 0010016
#define B4000000 0010017
#define CIBAUD 002003600000 /* input baud rate */
#define CMSPAR 010000000000 /* mark or space (stick) parity */
#define CRTSCTS 020000000000 /* flow control */
#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */
#define CBAUD 0x0000100f
#define CSIZE 0x00000030 /* Number of bits per byte (mask) */
#define CS5 0x00000000 /* 5 bits per byte */
#define CS6 0x00000010 /* 6 bits per byte */
#define CS7 0x00000020 /* 7 bits per byte */
#define CS8 0x00000030 /* 8 bits per byte */
#define CSTOPB 0x00000040 /* Two stop bits instead of one */
#define CREAD 0x00000080 /* Enable receiver */
#define PARENB 0x00000100 /* Parity enable */
#define PARODD 0x00000200 /* Odd parity instead of even */
#define HUPCL 0x00000400 /* Hang up on last close */
#define CLOCAL 0x00000800 /* Ignore modem status lines */
#define CBAUDEX 0x00001000
#define BOTHER 0x00001000
#define B57600 0x00001001
#define B115200 0x00001002
#define B230400 0x00001003
#define B460800 0x00001004
#define B500000 0x00001005
#define B576000 0x00001006
#define B921600 0x00001007
#define B1000000 0x00001008
#define B1152000 0x00001009
#define B1500000 0x0000100a
#define B2000000 0x0000100b
#define B2500000 0x0000100c
#define B3000000 0x0000100d
#define B3500000 0x0000100e
#define B4000000 0x0000100f
#define CIBAUD 0x100f0000 /* input baud rate */
/* c_lflag bits */
#define ISIG 0000001 /* Enable signals. */
#define ICANON 0000002 /* Do erase and kill processing. */
#define XCASE 0000004
#define ECHO 0000010 /* Enable echo. */
#define ECHOE 0000020 /* Visual erase for ERASE. */
#define ECHOK 0000040 /* Echo NL after KILL. */
#define ECHONL 0000100 /* Echo NL even if ECHO is off. */
#define NOFLSH 0000200 /* Disable flush after interrupt. */
#define IEXTEN 0000400 /* Enable DISCARD and LNEXT. */
#define ECHOCTL 0001000 /* Echo control characters as ^X. */
#define ECHOPRT 0002000 /* Hardcopy visual erase. */
#define ECHOKE 0004000 /* Visual erase for KILL. */
#define FLUSHO 0020000
#define PENDIN 0040000 /* Retype pending input (state). */
#define TOSTOP 0100000 /* Send SIGTTOU for background output. */
#define ITOSTOP TOSTOP
#define EXTPROC 0200000 /* External processing on pty */
#define ISIG 0x00001 /* Enable signals */
#define ICANON 0x00002 /* Do erase and kill processing */
#define XCASE 0x00004
#define ECHO 0x00008 /* Enable echo */
#define ECHOE 0x00010 /* Visual erase for ERASE */
#define ECHOK 0x00020 /* Echo NL after KILL */
#define ECHONL 0x00040 /* Echo NL even if ECHO is off */
#define NOFLSH 0x00080 /* Disable flush after interrupt */
#define IEXTEN 0x00100 /* Enable DISCARD and LNEXT */
#define ECHOCTL 0x00200 /* Echo control characters as ^X */
#define ECHOPRT 0x00400 /* Hardcopy visual erase */
#define ECHOKE 0x00800 /* Visual erase for KILL */
#define FLUSHO 0x02000
#define PENDIN 0x04000 /* Retype pending input (state) */
#define TOSTOP 0x08000 /* Send SIGTTOU for background output */
#define ITOSTOP TOSTOP
#define EXTPROC 0x10000 /* External processing on pty */
/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */
/* tcflow() and TCXONC use these */
#define TCOOFF 0 /* Suspend output. */
#define TCOON 1 /* Restart suspended output. */
#define TCIOFF 2 /* Send a STOP character. */
#define TCION 3 /* Send a START character. */
/* tcflush() and TCFLSH use these */
#define TCIFLUSH 0 /* Discard data received but not yet read. */
#define TCOFLUSH 1 /* Discard data written but not yet sent. */
#define TCIOFLUSH 2 /* Discard all pending data. */
/* tcsetattr uses these */
#define TCSANOW TCSETS /* Change immediately. */
#define TCSADRAIN TCSETSW /* Change when pending output is written. */
#define TCSAFLUSH TCSETSF /* Flush pending input before changing. */
#define TCSANOW TCSETS /* Change immediately */
#define TCSADRAIN TCSETSW /* Change when pending output is written */
#define TCSAFLUSH TCSETSF /* Flush pending input before changing */
#endif /* _ASM_TERMBITS_H */

View File

@ -2,10 +2,8 @@
#ifndef __ARCH_PARISC_TERMBITS_H__
#define __ARCH_PARISC_TERMBITS_H__
#include <linux/posix_types.h>
#include <asm-generic/termbits-common.h>
typedef unsigned char cc_t;
typedef unsigned int speed_t;
typedef unsigned int tcflag_t;
#define NCCS 19
@ -41,158 +39,107 @@ struct ktermios {
};
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
#define VERASE 2
#define VKILL 3
#define VEOF 4
#define VTIME 5
#define VMIN 6
#define VSWTC 7
#define VSTART 8
#define VSTOP 9
#define VSUSP 10
#define VEOL 11
#define VREPRINT 12
#define VDISCARD 13
#define VWERASE 14
#define VLNEXT 15
#define VEOL2 16
#define VINTR 0
#define VQUIT 1
#define VERASE 2
#define VKILL 3
#define VEOF 4
#define VTIME 5
#define VMIN 6
#define VSWTC 7
#define VSTART 8
#define VSTOP 9
#define VSUSP 10
#define VEOL 11
#define VREPRINT 12
#define VDISCARD 13
#define VWERASE 14
#define VLNEXT 15
#define VEOL2 16
/* c_iflag bits */
#define IGNBRK 0000001
#define BRKINT 0000002
#define IGNPAR 0000004
#define PARMRK 0000010
#define INPCK 0000020
#define ISTRIP 0000040
#define INLCR 0000100
#define IGNCR 0000200
#define ICRNL 0000400
#define IUCLC 0001000
#define IXON 0002000
#define IXANY 0004000
#define IXOFF 0010000
#define IMAXBEL 0040000
#define IUTF8 0100000
#define IUCLC 0x0200
#define IXON 0x0400
#define IXOFF 0x1000
#define IMAXBEL 0x4000
#define IUTF8 0x8000
/* c_oflag bits */
#define OPOST 0000001
#define OLCUC 0000002
#define ONLCR 0000004
#define OCRNL 0000010
#define ONOCR 0000020
#define ONLRET 0000040
#define OFILL 0000100
#define OFDEL 0000200
#define NLDLY 0000400
#define NL0 0000000
#define NL1 0000400
#define CRDLY 0003000
#define CR0 0000000
#define CR1 0001000
#define CR2 0002000
#define CR3 0003000
#define TABDLY 0014000
#define TAB0 0000000
#define TAB1 0004000
#define TAB2 0010000
#define TAB3 0014000
#define XTABS 0014000
#define BSDLY 0020000
#define BS0 0000000
#define BS1 0020000
#define VTDLY 0040000
#define VT0 0000000
#define VT1 0040000
#define FFDLY 0100000
#define FF0 0000000
#define FF1 0100000
#define OLCUC 0x00002
#define ONLCR 0x00004
#define NLDLY 0x00100
#define NL0 0x00000
#define NL1 0x00100
#define CRDLY 0x00600
#define CR0 0x00000
#define CR1 0x00200
#define CR2 0x00400
#define CR3 0x00600
#define TABDLY 0x01800
#define TAB0 0x00000
#define TAB1 0x00800
#define TAB2 0x01000
#define TAB3 0x01800
#define XTABS 0x01800
#define BSDLY 0x02000
#define BS0 0x00000
#define BS1 0x02000
#define VTDLY 0x04000
#define VT0 0x00000
#define VT1 0x04000
#define FFDLY 0x08000
#define FF0 0x00000
#define FF1 0x08000
/* c_cflag bit meaning */
#define CBAUD 0010017
#define B0 0000000 /* hang up */
#define B50 0000001
#define B75 0000002
#define B110 0000003
#define B134 0000004
#define B150 0000005
#define B200 0000006
#define B300 0000007
#define B600 0000010
#define B1200 0000011
#define B1800 0000012
#define B2400 0000013
#define B4800 0000014
#define B9600 0000015
#define B19200 0000016
#define B38400 0000017
#define EXTA B19200
#define EXTB B38400
#define CSIZE 0000060
#define CS5 0000000
#define CS6 0000020
#define CS7 0000040
#define CS8 0000060
#define CSTOPB 0000100
#define CREAD 0000200
#define PARENB 0000400
#define PARODD 0001000
#define HUPCL 0002000
#define CLOCAL 0004000
#define CBAUDEX 0010000
#define BOTHER 0010000
#define B57600 0010001
#define B115200 0010002
#define B230400 0010003
#define B460800 0010004
#define B500000 0010005
#define B576000 0010006
#define B921600 0010007
#define B1000000 0010010
#define B1152000 0010011
#define B1500000 0010012
#define B2000000 0010013
#define B2500000 0010014
#define B3000000 0010015
#define B3500000 0010016
#define B4000000 0010017
#define CIBAUD 002003600000 /* input baud rate */
#define CMSPAR 010000000000 /* mark or space (stick) parity */
#define CRTSCTS 020000000000 /* flow control */
#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */
#define CBAUD 0x0000100f
#define CSIZE 0x00000030
#define CS5 0x00000000
#define CS6 0x00000010
#define CS7 0x00000020
#define CS8 0x00000030
#define CSTOPB 0x00000040
#define CREAD 0x00000080
#define PARENB 0x00000100
#define PARODD 0x00000200
#define HUPCL 0x00000400
#define CLOCAL 0x00000800
#define CBAUDEX 0x00001000
#define BOTHER 0x00001000
#define B57600 0x00001001
#define B115200 0x00001002
#define B230400 0x00001003
#define B460800 0x00001004
#define B500000 0x00001005
#define B576000 0x00001006
#define B921600 0x00001007
#define B1000000 0x00001008
#define B1152000 0x00001009
#define B1500000 0x0000100a
#define B2000000 0x0000100b
#define B2500000 0x0000100c
#define B3000000 0x0000100d
#define B3500000 0x0000100e
#define B4000000 0x0000100f
#define CIBAUD 0x100f0000 /* input baud rate */
/* c_lflag bits */
#define ISIG 0000001
#define ICANON 0000002
#define XCASE 0000004
#define ECHO 0000010
#define ECHOE 0000020
#define ECHOK 0000040
#define ECHONL 0000100
#define NOFLSH 0000200
#define TOSTOP 0000400
#define ECHOCTL 0001000
#define ECHOPRT 0002000
#define ECHOKE 0004000
#define FLUSHO 0010000
#define PENDIN 0040000
#define IEXTEN 0100000
#define EXTPROC 0200000
/* tcflow() and TCXONC use these */
#define TCOOFF 0
#define TCOON 1
#define TCIOFF 2
#define TCION 3
/* tcflush() and TCFLSH use these */
#define TCIFLUSH 0
#define TCOFLUSH 1
#define TCIOFLUSH 2
#define ISIG 0x00001
#define ICANON 0x00002
#define XCASE 0x00004
#define ECHO 0x00008
#define ECHOE 0x00010
#define ECHOK 0x00020
#define ECHONL 0x00040
#define NOFLSH 0x00080
#define TOSTOP 0x00100
#define ECHOCTL 0x00200
#define ECHOPRT 0x00400
#define ECHOKE 0x00800
#define FLUSHO 0x01000
#define PENDIN 0x04000
#define IEXTEN 0x08000
#define EXTPROC 0x10000
/* tcsetattr uses these */
#define TCSANOW 0

View File

@ -9,8 +9,8 @@
* 2 of the License, or (at your option) any later version.
*/
typedef unsigned char cc_t;
typedef unsigned int speed_t;
#include <asm-generic/termbits-common.h>
typedef unsigned int tcflag_t;
/*
@ -64,115 +64,72 @@ struct ktermios {
#define VDISCARD 16
/* c_iflag bits */
#define IGNBRK 0000001
#define BRKINT 0000002
#define IGNPAR 0000004
#define PARMRK 0000010
#define INPCK 0000020
#define ISTRIP 0000040
#define INLCR 0000100
#define IGNCR 0000200
#define ICRNL 0000400
#define IXON 0001000
#define IXOFF 0002000
#define IXANY 0004000
#define IUCLC 0010000
#define IMAXBEL 0020000
#define IUTF8 0040000
#define IXON 0x0200
#define IXOFF 0x0400
#define IUCLC 0x1000
#define IMAXBEL 0x2000
#define IUTF8 0x4000
/* c_oflag bits */
#define OPOST 0000001
#define ONLCR 0000002
#define OLCUC 0000004
#define OCRNL 0000010
#define ONOCR 0000020
#define ONLRET 0000040
#define OFILL 00000100
#define OFDEL 00000200
#define NLDLY 00001400
#define NL0 00000000
#define NL1 00000400
#define NL2 00001000
#define NL3 00001400
#define TABDLY 00006000
#define TAB0 00000000
#define TAB1 00002000
#define TAB2 00004000
#define TAB3 00006000
#define XTABS 00006000 /* required by POSIX to == TAB3 */
#define CRDLY 00030000
#define CR0 00000000
#define CR1 00010000
#define CR2 00020000
#define CR3 00030000
#define FFDLY 00040000
#define FF0 00000000
#define FF1 00040000
#define BSDLY 00100000
#define BS0 00000000
#define BS1 00100000
#define VTDLY 00200000
#define VT0 00000000
#define VT1 00200000
#define ONLCR 0x00002
#define OLCUC 0x00004
#define NLDLY 0x00300
#define NL0 0x00000
#define NL1 0x00100
#define NL2 0x00200
#define NL3 0x00300
#define TABDLY 0x00c00
#define TAB0 0x00000
#define TAB1 0x00400
#define TAB2 0x00800
#define TAB3 0x00c00
#define XTABS 0x00c00 /* required by POSIX to == TAB3 */
#define CRDLY 0x03000
#define CR0 0x00000
#define CR1 0x01000
#define CR2 0x02000
#define CR3 0x03000
#define FFDLY 0x04000
#define FF0 0x00000
#define FF1 0x04000
#define BSDLY 0x08000
#define BS0 0x00000
#define BS1 0x08000
#define VTDLY 0x10000
#define VT0 0x00000
#define VT1 0x10000
/* c_cflag bit meaning */
#define CBAUD 0000377
#define B0 0000000 /* hang up */
#define B50 0000001
#define B75 0000002
#define B110 0000003
#define B134 0000004
#define B150 0000005
#define B200 0000006
#define B300 0000007
#define B600 0000010
#define B1200 0000011
#define B1800 0000012
#define B2400 0000013
#define B4800 0000014
#define B9600 0000015
#define B19200 0000016
#define B38400 0000017
#define EXTA B19200
#define EXTB B38400
#define CBAUDEX 0000000
#define B57600 00020
#define B115200 00021
#define B230400 00022
#define B460800 00023
#define B500000 00024
#define B576000 00025
#define B921600 00026
#define B1000000 00027
#define B1152000 00030
#define B1500000 00031
#define B2000000 00032
#define B2500000 00033
#define B3000000 00034
#define B3500000 00035
#define B4000000 00036
#define BOTHER 00037
#define CIBAUD 077600000
#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */
#define CSIZE 00001400
#define CS5 00000000
#define CS6 00000400
#define CS7 00001000
#define CS8 00001400
#define CSTOPB 00002000
#define CREAD 00004000
#define PARENB 00010000
#define PARODD 00020000
#define HUPCL 00040000
#define CLOCAL 00100000
#define CMSPAR 010000000000 /* mark or space (stick) parity */
#define CRTSCTS 020000000000 /* flow control */
#define CBAUD 0x000000ff
#define CBAUDEX 0x00000000
#define BOTHER 0x0000001f
#define B57600 0x00000010
#define B115200 0x00000011
#define B230400 0x00000012
#define B460800 0x00000013
#define B500000 0x00000014
#define B576000 0x00000015
#define B921600 0x00000016
#define B1000000 0x00000017
#define B1152000 0x00000018
#define B1500000 0x00000019
#define B2000000 0x0000001a
#define B2500000 0x0000001b
#define B3000000 0x0000001c
#define B3500000 0x0000001d
#define B4000000 0x0000001e
#define CSIZE 0x00000300
#define CS5 0x00000000
#define CS6 0x00000100
#define CS7 0x00000200
#define CS8 0x00000300
#define CSTOPB 0x00000400
#define CREAD 0x00000800
#define PARENB 0x00001000
#define PARODD 0x00002000
#define HUPCL 0x00004000
#define CLOCAL 0x00008000
#define CIBAUD 0x00ff0000
/* c_lflag bits */
#define ISIG 0x00000080
@ -192,17 +149,6 @@ struct ktermios {
#define IEXTEN 0x00000400
#define EXTPROC 0x10000000
/* Values for the ACTION argument to `tcflow'. */
#define TCOOFF 0
#define TCOON 1
#define TCIOFF 2
#define TCION 3
/* Values for the QUEUE_SELECTOR argument to `tcflush'. */
#define TCIFLUSH 0
#define TCOFLUSH 1
#define TCIOFLUSH 2
/* Values for the OPTIONAL_ACTIONS argument to `tcsetattr'. */
#define TCSANOW 0
#define TCSADRAIN 1

View File

@ -2,15 +2,12 @@
#ifndef _UAPI_SPARC_TERMBITS_H
#define _UAPI_SPARC_TERMBITS_H
#include <linux/posix_types.h>
typedef unsigned char cc_t;
typedef unsigned int speed_t;
#include <asm-generic/termbits-common.h>
#if defined(__sparc__) && defined(__arch64__)
typedef unsigned int tcflag_t;
typedef unsigned int tcflag_t;
#else
typedef unsigned long tcflag_t;
typedef unsigned long tcflag_t;
#endif
#define NCC 8
@ -61,21 +58,19 @@ struct ktermios {
};
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
#define VERASE 2
#define VKILL 3
#define VEOF 4
#define VEOL 5
#define VEOL2 6
#define VSWTC 7
#define VSTART 8
#define VSTOP 9
#define VINTR 0
#define VQUIT 1
#define VERASE 2
#define VKILL 3
#define VEOF 4
#define VEOL 5
#define VEOL2 6
#define VSWTC 7
#define VSTART 8
#define VSTOP 9
#define VSUSP 10
#define VDSUSP 11 /* SunOS POSIX nicety I do believe... */
#define VDSUSP 11 /* SunOS POSIX nicety I do believe... */
#define VREPRINT 12
#define VDISCARD 13
#define VWERASE 14
@ -90,121 +85,83 @@ struct ktermios {
#endif
/* c_iflag bits */
#define IGNBRK 0x00000001
#define BRKINT 0x00000002
#define IGNPAR 0x00000004
#define PARMRK 0x00000008
#define INPCK 0x00000010
#define ISTRIP 0x00000020
#define INLCR 0x00000040
#define IGNCR 0x00000080
#define ICRNL 0x00000100
#define IUCLC 0x00000200
#define IXON 0x00000400
#define IXANY 0x00000800
#define IXOFF 0x00001000
#define IMAXBEL 0x00002000
#define IUTF8 0x00004000
#define IUCLC 0x0200
#define IXON 0x0400
#define IXOFF 0x1000
#define IMAXBEL 0x2000
#define IUTF8 0x4000
/* c_oflag bits */
#define OPOST 0x00000001
#define OLCUC 0x00000002
#define ONLCR 0x00000004
#define OCRNL 0x00000008
#define ONOCR 0x00000010
#define ONLRET 0x00000020
#define OFILL 0x00000040
#define OFDEL 0x00000080
#define NLDLY 0x00000100
#define NL0 0x00000000
#define NL1 0x00000100
#define CRDLY 0x00000600
#define CR0 0x00000000
#define CR1 0x00000200
#define CR2 0x00000400
#define CR3 0x00000600
#define TABDLY 0x00001800
#define TAB0 0x00000000
#define TAB1 0x00000800
#define TAB2 0x00001000
#define TAB3 0x00001800
#define XTABS 0x00001800
#define BSDLY 0x00002000
#define BS0 0x00000000
#define BS1 0x00002000
#define VTDLY 0x00004000
#define VT0 0x00000000
#define VT1 0x00004000
#define FFDLY 0x00008000
#define FF0 0x00000000
#define FF1 0x00008000
#define PAGEOUT 0x00010000 /* SUNOS specific */
#define WRAP 0x00020000 /* SUNOS specific */
#define OLCUC 0x00002
#define ONLCR 0x00004
#define NLDLY 0x00100
#define NL0 0x00000
#define NL1 0x00100
#define CRDLY 0x00600
#define CR0 0x00000
#define CR1 0x00200
#define CR2 0x00400
#define CR3 0x00600
#define TABDLY 0x01800
#define TAB0 0x00000
#define TAB1 0x00800
#define TAB2 0x01000
#define TAB3 0x01800
#define XTABS 0x01800
#define BSDLY 0x02000
#define BS0 0x00000
#define BS1 0x02000
#define VTDLY 0x04000
#define VT0 0x00000
#define VT1 0x04000
#define FFDLY 0x08000
#define FF0 0x00000
#define FF1 0x08000
#define PAGEOUT 0x10000 /* SUNOS specific */
#define WRAP 0x20000 /* SUNOS specific */
/* c_cflag bit meaning */
#define CBAUD 0x0000100f
#define B0 0x00000000 /* hang up */
#define B50 0x00000001
#define B75 0x00000002
#define B110 0x00000003
#define B134 0x00000004
#define B150 0x00000005
#define B200 0x00000006
#define B300 0x00000007
#define B600 0x00000008
#define B1200 0x00000009
#define B1800 0x0000000a
#define B2400 0x0000000b
#define B4800 0x0000000c
#define B9600 0x0000000d
#define B19200 0x0000000e
#define B38400 0x0000000f
#define EXTA B19200
#define EXTB B38400
#define CSIZE 0x00000030
#define CS5 0x00000000
#define CS6 0x00000010
#define CS7 0x00000020
#define CS8 0x00000030
#define CSTOPB 0x00000040
#define CREAD 0x00000080
#define PARENB 0x00000100
#define PARODD 0x00000200
#define HUPCL 0x00000400
#define CLOCAL 0x00000800
#define CBAUDEX 0x00001000
#define CBAUD 0x0000100f
#define CSIZE 0x00000030
#define CS5 0x00000000
#define CS6 0x00000010
#define CS7 0x00000020
#define CS8 0x00000030
#define CSTOPB 0x00000040
#define CREAD 0x00000080
#define PARENB 0x00000100
#define PARODD 0x00000200
#define HUPCL 0x00000400
#define CLOCAL 0x00000800
#define CBAUDEX 0x00001000
/* We'll never see these speeds with the Zilogs, but for completeness... */
#define BOTHER 0x00001000
#define B57600 0x00001001
#define B115200 0x00001002
#define B230400 0x00001003
#define B460800 0x00001004
#define BOTHER 0x00001000
#define B57600 0x00001001
#define B115200 0x00001002
#define B230400 0x00001003
#define B460800 0x00001004
/* This is what we can do with the Zilogs. */
#define B76800 0x00001005
#define B76800 0x00001005
/* This is what we can do with the SAB82532. */
#define B153600 0x00001006
#define B307200 0x00001007
#define B614400 0x00001008
#define B921600 0x00001009
#define B153600 0x00001006
#define B307200 0x00001007
#define B614400 0x00001008
#define B921600 0x00001009
/* And these are the rest... */
#define B500000 0x0000100a
#define B576000 0x0000100b
#define B1000000 0x0000100c
#define B1152000 0x0000100d
#define B1500000 0x0000100e
#define B2000000 0x0000100f
#define B500000 0x0000100a
#define B576000 0x0000100b
#define B1000000 0x0000100c
#define B1152000 0x0000100d
#define B1500000 0x0000100e
#define B2000000 0x0000100f
/* These have totally bogus values and nobody uses them
so far. Later on we'd have to use say 0x10000x and
adjust CBAUD constant and drivers accordingly.
#define B2500000 0x00001010
#define B3000000 0x00001011
#define B3500000 0x00001012
#define B4000000 0x00001013 */
#define CIBAUD 0x100f0000 /* input baud rate (not used) */
#define CMSPAR 0x40000000 /* mark or space (stick) parity */
#define CRTSCTS 0x80000000 /* flow control */
#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */
#define B2500000 0x00001010
#define B3000000 0x00001011
#define B3500000 0x00001012
#define B4000000 0x00001013 */
#define CIBAUD 0x100f0000 /* input baud rate (not used) */
/* c_lflag bits */
#define ISIG 0x00000001
@ -219,7 +176,7 @@ struct ktermios {
#define ECHOCTL 0x00000200
#define ECHOPRT 0x00000400
#define ECHOKE 0x00000800
#define DEFECHO 0x00001000 /* SUNOS thing, what is it? */
#define DEFECHO 0x00001000 /* SUNOS thing, what is it? */
#define FLUSHO 0x00002000
#define PENDIN 0x00004000
#define IEXTEN 0x00008000
@ -244,21 +201,9 @@ struct ktermios {
/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */
/* tcflow() and TCXONC use these */
#define TCOOFF 0
#define TCOON 1
#define TCIOFF 2
#define TCION 3
/* tcflush() and TCFLSH use these */
#define TCIFLUSH 0
#define TCOFLUSH 1
#define TCIOFLUSH 2
/* tcsetattr uses these */
#define TCSANOW 0
#define TCSADRAIN 1
#define TCSAFLUSH 2
#define TCSANOW 0
#define TCSADRAIN 1
#define TCSAFLUSH 2
#endif /* _UAPI_SPARC_TERMBITS_H */

View File

@ -18,7 +18,8 @@ config TTY_PRINTK
The feature is useful to inline user messages with kernel
messages.
In order to use this feature, you should output user messages
to /dev/ttyprintk or redirect console to this TTY.
to /dev/ttyprintk or redirect console to this TTY, or boot
the kernel with console=ttyprintk.
If unsure, say N.

View File

@ -1418,7 +1418,11 @@ static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty)
info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
/* byte size and parity */
if ((cflag & CSIZE) != CS8) {
cflag &= ~CSIZE;
cflag |= CS7;
tty->termios.c_cflag = cflag;
}
info->params.data_bits = tty_get_char_size(cflag);
if (cflag & CSTOPB)
@ -1432,10 +1436,8 @@ static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty)
info->params.parity = ASYNC_PARITY_ODD;
else
info->params.parity = ASYNC_PARITY_EVEN;
#ifdef CMSPAR
if (cflag & CMSPAR)
info->params.parity = ASYNC_PARITY_SPACE;
#endif
}
/* calculate number of jiffies to transmit a full

View File

@ -11,6 +11,7 @@
* of the boot process, for example.
*/
#include <linux/console.h>
#include <linux/device.h>
#include <linux/serial.h>
#include <linux/tty.h>
@ -163,6 +164,18 @@ static const struct tty_port_operations tpk_port_ops = {
static struct tty_driver *ttyprintk_driver;
static struct tty_driver *ttyprintk_console_device(struct console *c,
int *index)
{
*index = 0;
return ttyprintk_driver;
}
static struct console ttyprintk_console = {
.name = "ttyprintk",
.device = ttyprintk_console_device,
};
static int __init ttyprintk_init(void)
{
int ret;
@ -195,6 +208,8 @@ static int __init ttyprintk_init(void)
goto error;
}
register_console(&ttyprintk_console);
return 0;
error:
@ -205,6 +220,7 @@ error:
static void __exit ttyprintk_exit(void)
{
unregister_console(&ttyprintk_console);
tty_unregister_driver(ttyprintk_driver);
tty_driver_kref_put(ttyprintk_driver);
tty_port_destroy(&tpk_port.port);

View File

@ -588,10 +588,8 @@ static void change_speed(struct tty_struct *tty, struct serial_state *info,
}
if (!(cflag & PARODD))
cval |= UART_LCR_EPAR;
#ifdef CMSPAR
if (cflag & CMSPAR)
cval |= UART_LCR_SPAR;
#endif
/* Determine divisor based on baud rate */
baud = tty_get_baud_rate(tty);

View File

@ -405,6 +405,7 @@ static int goldfish_tty_probe(struct platform_device *pdev)
err_tty_register_device_failed:
free_irq(irq, qtty);
err_dec_line_count:
tty_port_destroy(&qtty->port);
goldfish_tty_current_line_count--;
if (goldfish_tty_current_line_count == 0)
goldfish_tty_delete_driver();
@ -426,6 +427,7 @@ static int goldfish_tty_remove(struct platform_device *pdev)
iounmap(qtty->base);
qtty->base = NULL;
free_irq(qtty->irq, pdev);
tty_port_destroy(&qtty->port);
goldfish_tty_current_line_count--;
if (goldfish_tty_current_line_count == 0)
goldfish_tty_delete_driver();

View File

@ -87,6 +87,25 @@ config HVC_DCC
driver. This console is used through a JTAG only on ARM. If you don't have
a JTAG then you probably don't want this option.
config HVC_DCC_SERIALIZE_SMP
bool "Use DCC only on CPU core 0"
depends on SMP && HVC_DCC
help
This is a DEBUG option to serialize all console input and output to CPU 0.
Some external debuggers, do not handle reads/writes from/to DCC on more
than one CPU core. Each core has its own DCC device registers, so when a
CPU core reads or writes from/to DCC, it only accesses its own DCC device.
Since kernel code can run on any CPU core, every time the kernel wants to
write to the console, it might write to a different DCC.
In SMP mode, external debuggers create multiple windows, and each window
shows the DCC output only from that core's DCC. The result is that
console output is either lost or scattered across windows.
Enable this option only if you are sure that you do not need features like
CPU hotplug to work. For example, during early chipset bringups without
debug serial console support. If unsure, say N.
config HVC_RISCV_SBI
bool "RISC-V SBI console support"
depends on RISCV_SBI_V01

View File

@ -1,10 +1,15 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2010, 2014 The Linux Foundation. All rights reserved. */
/* Copyright (c) 2010, 2014, 2022 The Linux Foundation. All rights reserved. */
#include <linux/console.h>
#include <linux/cpu.h>
#include <linux/cpumask.h>
#include <linux/init.h>
#include <linux/kfifo.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/smp.h>
#include <linux/spinlock.h>
#include <asm/dcc.h>
#include <asm/processor.h>
@ -15,6 +20,15 @@
#define DCC_STATUS_RX (1 << 30)
#define DCC_STATUS_TX (1 << 29)
#define DCC_INBUF_SIZE 128
#define DCC_OUTBUF_SIZE 1024
/* Lock to serialize access to DCC fifo */
static DEFINE_SPINLOCK(dcc_lock);
static DEFINE_KFIFO(inbuf, unsigned char, DCC_INBUF_SIZE);
static DEFINE_KFIFO(outbuf, unsigned char, DCC_OUTBUF_SIZE);
static void dcc_uart_console_putchar(struct uart_port *port, unsigned char ch)
{
while (__dcc_getstatus() & DCC_STATUS_TX)
@ -67,24 +81,176 @@ static int hvc_dcc_get_chars(uint32_t vt, char *buf, int count)
return i;
}
/*
* Check if the DCC is enabled. If CONFIG_HVC_DCC_SERIALIZE_SMP is enabled,
* then we assume then this function will be called first on core0. That way,
* dcc_core0_available will be true only if it's available on core0.
*/
static bool hvc_dcc_check(void)
{
unsigned long time = jiffies + (HZ / 10);
static bool dcc_core0_available;
/*
* If we're not on core 0, but we previously confirmed that DCC is
* active, then just return true.
*/
int cpu = get_cpu();
if (IS_ENABLED(CONFIG_HVC_DCC_SERIALIZE_SMP) && cpu && dcc_core0_available) {
put_cpu();
return true;
}
put_cpu();
/* Write a test character to check if it is handled */
__dcc_putchar('\n');
while (time_is_after_jiffies(time)) {
if (!(__dcc_getstatus() & DCC_STATUS_TX))
if (!(__dcc_getstatus() & DCC_STATUS_TX)) {
dcc_core0_available = true;
return true;
}
}
return false;
}
/*
* Workqueue function that writes the output FIFO to the DCC on core 0.
*/
static void dcc_put_work(struct work_struct *work)
{
unsigned char ch;
unsigned long irqflags;
spin_lock_irqsave(&dcc_lock, irqflags);
/* While there's data in the output FIFO, write it to the DCC */
while (kfifo_get(&outbuf, &ch))
hvc_dcc_put_chars(0, &ch, 1);
/* While we're at it, check for any input characters */
while (!kfifo_is_full(&inbuf)) {
if (!hvc_dcc_get_chars(0, &ch, 1))
break;
kfifo_put(&inbuf, ch);
}
spin_unlock_irqrestore(&dcc_lock, irqflags);
}
static DECLARE_WORK(dcc_pwork, dcc_put_work);
/*
* Workqueue function that reads characters from DCC and puts them into the
* input FIFO.
*/
static void dcc_get_work(struct work_struct *work)
{
unsigned char ch;
unsigned long irqflags;
/*
* Read characters from DCC and put them into the input FIFO, as
* long as there is room and we have characters to read.
*/
spin_lock_irqsave(&dcc_lock, irqflags);
while (!kfifo_is_full(&inbuf)) {
if (!hvc_dcc_get_chars(0, &ch, 1))
break;
kfifo_put(&inbuf, ch);
}
spin_unlock_irqrestore(&dcc_lock, irqflags);
}
static DECLARE_WORK(dcc_gwork, dcc_get_work);
/*
* Write characters directly to the DCC if we're on core 0 and the FIFO
* is empty, or write them to the FIFO if we're not.
*/
static int hvc_dcc0_put_chars(u32 vt, const char *buf, int count)
{
int len;
unsigned long irqflags;
if (!IS_ENABLED(CONFIG_HVC_DCC_SERIALIZE_SMP))
return hvc_dcc_put_chars(vt, buf, count);
spin_lock_irqsave(&dcc_lock, irqflags);
if (smp_processor_id() || (!kfifo_is_empty(&outbuf))) {
len = kfifo_in(&outbuf, buf, count);
spin_unlock_irqrestore(&dcc_lock, irqflags);
/*
* We just push data to the output FIFO, so schedule the
* workqueue that will actually write that data to DCC.
* CPU hotplug is disabled in dcc_init so CPU0 cannot be
* offlined after the cpu online check.
*/
if (cpu_online(0))
schedule_work_on(0, &dcc_pwork);
return len;
}
/*
* If we're already on core 0, and the FIFO is empty, then just
* write the data to DCC.
*/
len = hvc_dcc_put_chars(vt, buf, count);
spin_unlock_irqrestore(&dcc_lock, irqflags);
return len;
}
/*
* Read characters directly from the DCC if we're on core 0 and the FIFO
* is empty, or read them from the FIFO if we're not.
*/
static int hvc_dcc0_get_chars(u32 vt, char *buf, int count)
{
int len;
unsigned long irqflags;
if (!IS_ENABLED(CONFIG_HVC_DCC_SERIALIZE_SMP))
return hvc_dcc_get_chars(vt, buf, count);
spin_lock_irqsave(&dcc_lock, irqflags);
if (smp_processor_id() || (!kfifo_is_empty(&inbuf))) {
len = kfifo_out(&inbuf, buf, count);
spin_unlock_irqrestore(&dcc_lock, irqflags);
/*
* If the FIFO was empty, there may be characters in the DCC
* that we haven't read yet. Schedule a workqueue to fill
* the input FIFO, so that the next time this function is
* called, we'll have data. CPU hotplug is disabled in dcc_init
* so CPU0 cannot be offlined after the cpu online check.
*/
if (!len && cpu_online(0))
schedule_work_on(0, &dcc_gwork);
return len;
}
/*
* If we're already on core 0, and the FIFO is empty, then just
* read the data from DCC.
*/
len = hvc_dcc_get_chars(vt, buf, count);
spin_unlock_irqrestore(&dcc_lock, irqflags);
return len;
}
static const struct hv_ops hvc_dcc_get_put_ops = {
.get_chars = hvc_dcc_get_chars,
.put_chars = hvc_dcc_put_chars,
.get_chars = hvc_dcc0_get_chars,
.put_chars = hvc_dcc0_put_chars,
};
static int __init hvc_dcc_console_init(void)
@ -108,6 +274,26 @@ static int __init hvc_dcc_init(void)
if (!hvc_dcc_check())
return -ENODEV;
if (IS_ENABLED(CONFIG_HVC_DCC_SERIALIZE_SMP)) {
pr_warn("\n");
pr_warn("********************************************************************\n");
pr_warn("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **\n");
pr_warn("** **\n");
pr_warn("** HVC_DCC_SERIALIZE_SMP SUPPORT HAS BEEN ENABLED IN THIS KERNEL **\n");
pr_warn("** **\n");
pr_warn("** This means that this is a DEBUG kernel and unsafe for **\n");
pr_warn("** production use and has important feature like CPU hotplug **\n");
pr_warn("** disabled. **\n");
pr_warn("** **\n");
pr_warn("** If you see this message and you are not debugging the **\n");
pr_warn("** kernel, report this immediately to your vendor! **\n");
pr_warn("** **\n");
pr_warn("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **\n");
pr_warn("********************************************************************\n");
cpu_hotplug_disable();
}
p = hvc_alloc(0, 0, &hvc_dcc_get_put_ops, 128);
return PTR_ERR_OR_ZERO(p);

View File

@ -13,12 +13,12 @@
#include <linux/slab.h>
#include <linux/console.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/export.h>
#include <linux/interrupt.h>
#include <asm/hvconsole.h>
#include <asm/prom.h>
#include <asm/firmware.h>
#include <asm/hvsi.h>
#include <asm/udbg.h>
@ -342,9 +342,9 @@ void __init hvc_opal_init_early(void)
* path, so we hard wire it
*/
opal = of_find_node_by_path("/ibm,opal/consoles");
if (opal)
if (opal) {
pr_devel("hvc_opal: Found consoles in new location\n");
if (!opal) {
} else {
opal = of_find_node_by_path("/ibm,opal");
if (opal)
pr_devel("hvc_opal: "

View File

@ -28,10 +28,10 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/console.h>
#include <linux/of.h>
#include <asm/hvconsole.h>
#include <asm/vio.h>
#include <asm/prom.h>
#include <asm/hvsi.h>
#include <asm/udbg.h>
#include <asm/machdep.h>

View File

@ -581,10 +581,9 @@ static int hvcs_io(struct hvcs_struct *hvcsd)
spin_unlock_irqrestore(&hvcsd->lock, flags);
/* This is synch -- FIXME :js: it is not! */
if(got)
if (got)
tty_flip_buffer_push(&hvcsd->port);
if (!got) {
else {
/* Do this _after_ the flip_buffer_push */
spin_lock_irqsave(&hvcsd->lock, flags);
vio_enable_interrupts(hvcsd->vdev);

View File

@ -26,13 +26,13 @@
#include <linux/module.h>
#include <linux/major.h>
#include <linux/kernel.h>
#include <linux/of_irq.h>
#include <linux/spinlock.h>
#include <linux/sysrq.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <asm/hvcall.h>
#include <asm/hvconsole.h>
#include <asm/prom.h>
#include <linux/uaccess.h>
#include <asm/vio.h>
#include <asm/param.h>

View File

@ -528,7 +528,6 @@ static int mxser_set_baud(struct tty_struct *tty, speed_t newspd)
outb(quot >> 8, info->ioaddr + UART_DLM); /* MS of divisor */
outb(cval, info->ioaddr + UART_LCR); /* reset DLAB */
#ifdef BOTHER
if (C_BAUD(tty) == BOTHER) {
quot = MXSER_BAUD_BASE % newspd;
quot *= 8;
@ -539,9 +538,9 @@ static int mxser_set_baud(struct tty_struct *tty, speed_t newspd)
quot /= newspd;
mxser_set_must_enum_value(info->ioaddr, quot);
} else
#endif
} else {
mxser_set_must_enum_value(info->ioaddr, 0);
}
return 0;
}

View File

@ -444,6 +444,25 @@ static u8 gsm_encode_modem(const struct gsm_dlci *dlci)
return modembits;
}
static void gsm_hex_dump_bytes(const char *fname, const u8 *data,
unsigned long len)
{
char *prefix;
if (!fname) {
print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, data, len,
true);
return;
}
prefix = kasprintf(GFP_KERNEL, "%s: ", fname);
if (!prefix)
return;
print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_OFFSET, 16, 1, data, len,
true);
kfree(prefix);
}
/**
* gsm_print_packet - display a frame for debug
* @hdr: header to print before decode
@ -508,7 +527,7 @@ static void gsm_print_packet(const char *hdr, int addr, int cr,
else
pr_cont("(F)");
print_hex_dump_bytes("", DUMP_PREFIX_NONE, data, dlen);
gsm_hex_dump_bytes(NULL, data, dlen);
}
@ -698,9 +717,7 @@ static void gsm_data_kick(struct gsm_mux *gsm, struct gsm_dlci *dlci)
}
if (debug & 4)
print_hex_dump_bytes("gsm_data_kick: ",
DUMP_PREFIX_OFFSET,
gsm->txframe, len);
gsm_hex_dump_bytes(__func__, gsm->txframe, len);
if (gsmld_output(gsm, gsm->txframe, len) <= 0)
break;
/* FIXME: Can eliminate one SOF in many more cases */
@ -749,7 +766,7 @@ static void __gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg)
*--dp = msg->ctrl;
if (gsm->initiator)
*--dp = (msg->addr << 2) | 2 | EA;
*--dp = (msg->addr << 2) | CR | EA;
else
*--dp = (msg->addr << 2) | EA;
*fcs = gsm_fcs_add_block(INIT_FCS, dp , msg->data - dp);
@ -1907,10 +1924,6 @@ static void gsm_queue(struct gsm_mux *gsm)
case UI|PF:
case UIH:
case UIH|PF:
#if 0
if (cr)
goto invalid;
#endif
if (dlci == NULL || dlci->state != DLCI_OPEN) {
gsm_command(gsm, address, DM|PF);
return;
@ -2448,8 +2461,7 @@ static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len)
return -ENOSPC;
}
if (debug & 4)
print_hex_dump_bytes("gsmld_output: ", DUMP_PREFIX_OFFSET,
data, len);
gsm_hex_dump_bytes(__func__, data, len);
return gsm->tty->ops->write(gsm->tty, data, len);
}
@ -2525,8 +2537,7 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
char flags = TTY_NORMAL;
if (debug & 4)
print_hex_dump_bytes("gsmld_receive: ", DUMP_PREFIX_OFFSET,
cp, count);
gsm_hex_dump_bytes(__func__, cp, count);
for (; count; count--, cp++) {
if (fp)

View File

@ -1220,21 +1220,34 @@ n_tty_receive_signal_char(struct tty_struct *tty, int signal, unsigned char c)
process_echoes(tty);
}
static bool n_tty_is_char_flow_ctrl(struct tty_struct *tty, unsigned char c)
{
return c == START_CHAR(tty) || c == STOP_CHAR(tty);
}
/* Returns true if c is consumed as flow-control character */
static bool n_tty_receive_char_flow_ctrl(struct tty_struct *tty, unsigned char c)
{
if (!n_tty_is_char_flow_ctrl(tty, c))
return false;
if (c == START_CHAR(tty)) {
start_tty(tty);
process_echoes(tty);
return true;
}
/* STOP_CHAR */
stop_tty(tty);
return true;
}
static void n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
{
struct n_tty_data *ldata = tty->disc_data;
if (I_IXON(tty)) {
if (c == START_CHAR(tty)) {
start_tty(tty);
process_echoes(tty);
return;
}
if (c == STOP_CHAR(tty)) {
stop_tty(tty);
return;
}
}
if (I_IXON(tty) && n_tty_receive_char_flow_ctrl(tty, c))
return;
if (L_ISIG(tty)) {
if (c == INTR_CHAR(tty)) {
@ -1975,6 +1988,35 @@ static bool canon_copy_from_read_buf(struct tty_struct *tty,
return ldata->read_tail != canon_head;
}
/*
* If we finished a read at the exact location of an
* EOF (special EOL character that's a __DISABLED_CHAR)
* in the stream, silently eat the EOF.
*/
static void canon_skip_eof(struct tty_struct *tty)
{
struct n_tty_data *ldata = tty->disc_data;
size_t tail, canon_head;
canon_head = smp_load_acquire(&ldata->canon_head);
tail = ldata->read_tail;
// No data?
if (tail == canon_head)
return;
// See if the tail position is EOF in the circular buffer
tail &= (N_TTY_BUF_SIZE - 1);
if (!test_bit(tail, ldata->read_flags))
return;
if (read_buf(ldata, tail) != __DISABLED_CHAR)
return;
// Clear the EOL bit, skip the EOF char.
clear_bit(tail, ldata->read_flags);
smp_store_release(&ldata->read_tail, ldata->read_tail + 1);
}
/**
* job_control - check job control
* @tty: tty
@ -2045,7 +2087,14 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
*/
if (*cookie) {
if (ldata->icanon && !L_EXTPROC(tty)) {
if (canon_copy_from_read_buf(tty, &kb, &nr))
/*
* If we have filled the user buffer, see
* if we should skip an EOF character before
* releasing the lock and returning done.
*/
if (!nr)
canon_skip_eof(tty);
else if (canon_copy_from_read_buf(tty, &kb, &nr))
return kb - kbuf;
} else {
if (copy_from_read_buf(tty, &kb, &nr))

View File

@ -17,6 +17,8 @@
struct uart_8250_dma {
int (*tx_dma)(struct uart_8250_port *p);
int (*rx_dma)(struct uart_8250_port *p);
void (*prepare_tx_dma)(struct uart_8250_port *p);
void (*prepare_rx_dma)(struct uart_8250_port *p);
/* Filter function */
dma_filter_fn fn;
@ -83,6 +85,7 @@ struct serial8250_config {
#define UART_CAP_MINI BIT(17) /* Mini UART on BCM283X family lacks:
* STOP PARITY EPAR SPAR WLEN5 WLEN6
*/
#define UART_CAP_NOTEMT BIT(18) /* UART without interrupt on TEMT available */
#define UART_BUG_QUOT BIT(0) /* UART has buggy quot LSB */
#define UART_BUG_TXEN BIT(1) /* UART has buggy TX IIR status */
@ -120,6 +123,28 @@ static inline void serial_out(struct uart_8250_port *up, int offset, int value)
up->port.serial_out(&up->port, offset, value);
}
/*
* For the 16C950
*/
static void serial_icr_write(struct uart_8250_port *up, int offset, int value)
{
serial_out(up, UART_SCR, offset);
serial_out(up, UART_ICR, value);
}
static unsigned int __maybe_unused serial_icr_read(struct uart_8250_port *up,
int offset)
{
unsigned int value;
serial_icr_write(up, UART_ACR, up->acr | UART_ACR_ICRRD);
serial_out(up, UART_SCR, offset);
value = serial_in(up, UART_ICR);
serial_icr_write(up, UART_ACR, up->acr);
return value;
}
void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p);
static inline int serial_dl_read(struct uart_8250_port *up)
@ -302,6 +327,22 @@ extern int serial8250_rx_dma(struct uart_8250_port *);
extern void serial8250_rx_dma_flush(struct uart_8250_port *);
extern int serial8250_request_dma(struct uart_8250_port *);
extern void serial8250_release_dma(struct uart_8250_port *);
static inline void serial8250_do_prepare_tx_dma(struct uart_8250_port *p)
{
struct uart_8250_dma *dma = p->dma;
if (dma->prepare_tx_dma)
dma->prepare_tx_dma(p);
}
static inline void serial8250_do_prepare_rx_dma(struct uart_8250_port *p)
{
struct uart_8250_dma *dma = p->dma;
if (dma->prepare_rx_dma)
dma->prepare_rx_dma(p);
}
#else
static inline int serial8250_tx_dma(struct uart_8250_port *p)
{

View File

@ -429,6 +429,8 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
timer_setup(&vuart->unthrottle_timer, aspeed_vuart_unthrottle_exp, 0);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -EINVAL;
memset(&port, 0, sizeof(port));
port.port.private_data = vuart;

View File

@ -32,7 +32,6 @@
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/pm_runtime.h>
#include <linux/io.h>
#ifdef CONFIG_SPARC
#include <linux/sunserialcore.h>

View File

@ -34,7 +34,7 @@ static void __dma_tx_complete(void *param)
uart_write_wakeup(&p->port);
ret = serial8250_tx_dma(p);
if (ret)
if (ret || !dma->tx_running)
serial8250_set_THRI(p);
spin_unlock_irqrestore(&p->port.lock, flags);
@ -80,12 +80,13 @@ int serial8250_tx_dma(struct uart_8250_port *p)
if (uart_tx_stopped(&p->port) || uart_circ_empty(xmit)) {
/* We have been called from __dma_tx_complete() */
serial8250_rpm_put_tx(p);
return 0;
}
dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
serial8250_do_prepare_tx_dma(p);
desc = dmaengine_prep_slave_single(dma->txchan,
dma->tx_addr + xmit->tail,
dma->tx_size, DMA_MEM_TO_DEV,
@ -123,6 +124,8 @@ int serial8250_rx_dma(struct uart_8250_port *p)
if (dma->rx_running)
return 0;
serial8250_do_prepare_rx_dma(p);
desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr,
dma->rx_size, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);

View File

@ -12,13 +12,13 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/serial_8250.h>
#include <linux/serial_reg.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/workqueue.h>
#include <linux/notifier.h>
#include <linux/slab.h>
@ -33,30 +33,28 @@
/* Offsets for the DesignWare specific registers */
#define DW_UART_USR 0x1f /* UART Status Register */
#define DW_UART_DMASA 0xa8 /* DMA Software Ack */
#define OCTEON_UART_USR 0x27 /* UART Status Register */
#define RZN1_UART_TDMACR 0x10c /* DMA Control Register Transmit Mode */
#define RZN1_UART_RDMACR 0x110 /* DMA Control Register Receive Mode */
/* DesignWare specific register fields */
#define DW_UART_MCR_SIRE BIT(6)
struct dw8250_data {
struct dw8250_port_data data;
/* Renesas specific register fields */
#define RZN1_UART_xDMACR_DMA_EN BIT(0)
#define RZN1_UART_xDMACR_1_WORD_BURST (0 << 1)
#define RZN1_UART_xDMACR_4_WORD_BURST (1 << 1)
#define RZN1_UART_xDMACR_8_WORD_BURST (3 << 1)
#define RZN1_UART_xDMACR_BLK_SZ(x) ((x) << 3)
u8 usr_reg;
int msr_mask_on;
int msr_mask_off;
struct clk *clk;
struct clk *pclk;
struct notifier_block clk_notifier;
struct work_struct clk_work;
struct reset_control *rst;
unsigned int skip_autocfg:1;
unsigned int uart_16550_compatible:1;
};
static inline struct dw8250_data *to_dw8250_data(struct dw8250_port_data *data)
{
return container_of(data, struct dw8250_data, data);
}
/* Quirks */
#define DW_UART_QUIRK_OCTEON BIT(0)
#define DW_UART_QUIRK_ARMADA_38X BIT(1)
#define DW_UART_QUIRK_SKIP_SET_RATE BIT(2)
#define DW_UART_QUIRK_IS_DMA_FC BIT(3)
static inline struct dw8250_data *clk_to_dw8250_data(struct notifier_block *nb)
{
@ -238,6 +236,8 @@ static int dw8250_handle_irq(struct uart_port *p)
struct uart_8250_port *up = up_to_u8250p(p);
struct dw8250_data *d = to_dw8250_data(p->private_data);
unsigned int iir = p->serial_in(p, UART_IIR);
bool rx_timeout = (iir & 0x3f) == UART_IIR_RX_TIMEOUT;
unsigned int quirks = d->pdata->quirks;
unsigned int status;
unsigned long flags;
@ -251,7 +251,7 @@ static int dw8250_handle_irq(struct uart_port *p)
* This problem has only been observed so far when not in DMA mode
* so we limit the workaround only to non-DMA mode.
*/
if (!up->dma && ((iir & 0x3f) == UART_IIR_RX_TIMEOUT)) {
if (!up->dma && rx_timeout) {
spin_lock_irqsave(&p->lock, flags);
status = p->serial_in(p, UART_LSR);
@ -261,12 +261,21 @@ static int dw8250_handle_irq(struct uart_port *p)
spin_unlock_irqrestore(&p->lock, flags);
}
/* Manually stop the Rx DMA transfer when acting as flow controller */
if (quirks & DW_UART_QUIRK_IS_DMA_FC && up->dma && up->dma->rx_running && rx_timeout) {
status = p->serial_in(p, UART_LSR);
if (status & (UART_LSR_DR | UART_LSR_BI)) {
dw8250_writel_ext(p, RZN1_UART_RDMACR, 0);
dw8250_writel_ext(p, DW_UART_DMASA, 1);
}
}
if (serial8250_handle_irq(p, iir))
return 1;
if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
/* Clear the USR */
(void)p->serial_in(p, d->usr_reg);
(void)p->serial_in(p, d->pdata->usr_reg);
return 1;
}
@ -384,11 +393,48 @@ static bool dw8250_idma_filter(struct dma_chan *chan, void *param)
return param == chan->device->dev;
}
static u32 dw8250_rzn1_get_dmacr_burst(int max_burst)
{
if (max_burst >= 8)
return RZN1_UART_xDMACR_8_WORD_BURST;
else if (max_burst >= 4)
return RZN1_UART_xDMACR_4_WORD_BURST;
else
return RZN1_UART_xDMACR_1_WORD_BURST;
}
static void dw8250_prepare_tx_dma(struct uart_8250_port *p)
{
struct uart_port *up = &p->port;
struct uart_8250_dma *dma = p->dma;
u32 val;
dw8250_writel_ext(up, RZN1_UART_TDMACR, 0);
val = dw8250_rzn1_get_dmacr_burst(dma->txconf.dst_maxburst) |
RZN1_UART_xDMACR_BLK_SZ(dma->tx_size) |
RZN1_UART_xDMACR_DMA_EN;
dw8250_writel_ext(up, RZN1_UART_TDMACR, val);
}
static void dw8250_prepare_rx_dma(struct uart_8250_port *p)
{
struct uart_port *up = &p->port;
struct uart_8250_dma *dma = p->dma;
u32 val;
dw8250_writel_ext(up, RZN1_UART_RDMACR, 0);
val = dw8250_rzn1_get_dmacr_burst(dma->rxconf.src_maxburst) |
RZN1_UART_xDMACR_BLK_SZ(dma->rx_size) |
RZN1_UART_xDMACR_DMA_EN;
dw8250_writel_ext(up, RZN1_UART_RDMACR, val);
}
static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
{
struct device_node *np = p->dev->of_node;
if (np) {
unsigned int quirks = data->pdata->quirks;
int id;
/* get index of serial line, if found in DT aliases */
@ -396,12 +442,11 @@ static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
if (id >= 0)
p->line = id;
#ifdef CONFIG_64BIT
if (of_device_is_compatible(np, "cavium,octeon-3860-uart")) {
if (quirks & DW_UART_QUIRK_OCTEON) {
p->serial_in = dw8250_serial_inq;
p->serial_out = dw8250_serial_outq;
p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
p->type = PORT_OCTEON;
data->usr_reg = 0x27;
data->skip_autocfg = true;
}
#endif
@ -412,10 +457,16 @@ static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
p->serial_out = dw8250_serial_out32be;
}
if (of_device_is_compatible(np, "marvell,armada-38x-uart"))
if (quirks & DW_UART_QUIRK_ARMADA_38X)
p->serial_out = dw8250_serial_out38x;
if (of_device_is_compatible(np, "starfive,jh7100-uart"))
if (quirks & DW_UART_QUIRK_SKIP_SET_RATE)
p->set_termios = dw8250_do_set_termios;
if (quirks & DW_UART_QUIRK_IS_DMA_FC) {
data->data.dma.txconf.device_fc = 1;
data->data.dma.rxconf.device_fc = 1;
data->data.dma.prepare_tx_dma = dw8250_prepare_tx_dma;
data->data.dma.prepare_rx_dma = dw8250_prepare_rx_dma;
}
} else if (acpi_dev_present("APMC0D08", NULL, -1)) {
p->iotype = UPIO_MEM32;
@ -433,21 +484,30 @@ static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
}
}
static void dw8250_clk_disable_unprepare(void *data)
{
clk_disable_unprepare(data);
}
static void dw8250_reset_control_assert(void *data)
{
reset_control_assert(data);
}
static int dw8250_probe(struct platform_device *pdev)
{
struct uart_8250_port uart = {}, *up = &uart;
struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
struct uart_port *p = &up->port;
struct device *dev = &pdev->dev;
struct dw8250_data *data;
struct resource *regs;
int irq;
int err;
u32 val;
if (!regs) {
dev_err(dev, "no registers defined\n");
return -EINVAL;
}
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs)
return dev_err_probe(dev, -EINVAL, "no registers defined\n");
irq = platform_get_irq(pdev, 0);
if (irq < 0)
@ -476,7 +536,7 @@ static int dw8250_probe(struct platform_device *pdev)
return -ENOMEM;
data->data.dma.fn = dw8250_fallback_dma_filter;
data->usr_reg = DW_UART_USR;
data->pdata = device_get_match_data(p->dev);
p->private_data = &data->data;
data->uart_16550_compatible = device_property_read_bool(dev,
@ -532,37 +592,41 @@ static int dw8250_probe(struct platform_device *pdev)
err = clk_prepare_enable(data->clk);
if (err)
dev_warn(dev, "could not enable optional baudclk: %d\n", err);
return dev_err_probe(dev, err, "could not enable optional baudclk\n");
err = devm_add_action_or_reset(dev, dw8250_clk_disable_unprepare, data->clk);
if (err)
return err;
if (data->clk)
p->uartclk = clk_get_rate(data->clk);
/* If no clock rate is defined, fail. */
if (!p->uartclk) {
dev_err(dev, "clock rate not defined\n");
err = -EINVAL;
goto err_clk;
}
if (!p->uartclk)
return dev_err_probe(dev, -EINVAL, "clock rate not defined\n");
data->pclk = devm_clk_get_optional(dev, "apb_pclk");
if (IS_ERR(data->pclk)) {
err = PTR_ERR(data->pclk);
goto err_clk;
}
if (IS_ERR(data->pclk))
return PTR_ERR(data->pclk);
err = clk_prepare_enable(data->pclk);
if (err) {
dev_err(dev, "could not enable apb_pclk\n");
goto err_clk;
}
if (err)
return dev_err_probe(dev, err, "could not enable apb_pclk\n");
err = devm_add_action_or_reset(dev, dw8250_clk_disable_unprepare, data->pclk);
if (err)
return err;
data->rst = devm_reset_control_get_optional_exclusive(dev, NULL);
if (IS_ERR(data->rst)) {
err = PTR_ERR(data->rst);
goto err_pclk;
}
if (IS_ERR(data->rst))
return PTR_ERR(data->rst);
reset_control_deassert(data->rst);
err = devm_add_action_or_reset(dev, dw8250_reset_control_assert, data->rst);
if (err)
return err;
dw8250_quirks(p, data);
/* If the Busy Functionality is not implemented, don't handle it */
@ -580,10 +644,8 @@ static int dw8250_probe(struct platform_device *pdev)
}
data->data.line = serial8250_register_8250_port(up);
if (data->data.line < 0) {
err = data->data.line;
goto err_reset;
}
if (data->data.line < 0)
return data->data.line;
/*
* Some platforms may provide a reference clock shared between several
@ -593,9 +655,8 @@ static int dw8250_probe(struct platform_device *pdev)
if (data->clk) {
err = clk_notifier_register(data->clk, &data->clk_notifier);
if (err)
dev_warn(p->dev, "Failed to set the clock notifier\n");
else
queue_work(system_unbound_wq, &data->clk_work);
return dev_err_probe(dev, err, "Failed to set the clock notifier\n");
queue_work(system_unbound_wq, &data->clk_work);
}
platform_set_drvdata(pdev, data);
@ -604,17 +665,6 @@ static int dw8250_probe(struct platform_device *pdev)
pm_runtime_enable(dev);
return 0;
err_reset:
reset_control_assert(data->rst);
err_pclk:
clk_disable_unprepare(data->pclk);
err_clk:
clk_disable_unprepare(data->clk);
return err;
}
static int dw8250_remove(struct platform_device *pdev)
@ -632,12 +682,6 @@ static int dw8250_remove(struct platform_device *pdev)
serial8250_unregister_port(data->data.line);
reset_control_assert(data->rst);
clk_disable_unprepare(data->pclk);
clk_disable_unprepare(data->clk);
pm_runtime_disable(dev);
pm_runtime_put_noidle(dev);
@ -693,12 +737,37 @@ static const struct dev_pm_ops dw8250_pm_ops = {
SET_RUNTIME_PM_OPS(dw8250_runtime_suspend, dw8250_runtime_resume, NULL)
};
static const struct dw8250_platform_data dw8250_dw_apb = {
.usr_reg = DW_UART_USR,
};
static const struct dw8250_platform_data dw8250_octeon_3860_data = {
.usr_reg = OCTEON_UART_USR,
.quirks = DW_UART_QUIRK_OCTEON,
};
static const struct dw8250_platform_data dw8250_armada_38x_data = {
.usr_reg = DW_UART_USR,
.quirks = DW_UART_QUIRK_ARMADA_38X,
};
static const struct dw8250_platform_data dw8250_renesas_rzn1_data = {
.usr_reg = DW_UART_USR,
.cpr_val = 0x00012f32,
.quirks = DW_UART_QUIRK_IS_DMA_FC,
};
static const struct dw8250_platform_data dw8250_starfive_jh7100_data = {
.usr_reg = DW_UART_USR,
.quirks = DW_UART_QUIRK_SKIP_SET_RATE,
};
static const struct of_device_id dw8250_of_match[] = {
{ .compatible = "snps,dw-apb-uart" },
{ .compatible = "cavium,octeon-3860-uart" },
{ .compatible = "marvell,armada-38x-uart" },
{ .compatible = "renesas,rzn1-uart" },
{ .compatible = "starfive,jh7100-uart" },
{ .compatible = "snps,dw-apb-uart", .data = &dw8250_dw_apb },
{ .compatible = "cavium,octeon-3860-uart", .data = &dw8250_octeon_3860_data },
{ .compatible = "marvell,armada-38x-uart", .data = &dw8250_armada_38x_data },
{ .compatible = "renesas,rzn1-uart", .data = &dw8250_renesas_rzn1_data },
{ .compatible = "starfive,jh7100-uart", .data = &dw8250_starfive_jh7100_data },
{ /* Sentinel */ }
};
MODULE_DEVICE_TABLE(of, dw8250_of_match);

View File

@ -2,19 +2,32 @@
/* Synopsys DesignWare 8250 library. */
#include <linux/bitops.h>
#include <linux/bitfield.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/property.h>
#include <linux/serial_8250.h>
#include <linux/serial_core.h>
#include "8250_dwlib.h"
/* Offsets for the DesignWare specific registers */
#define DW_UART_TCR 0xac /* Transceiver Control Register (RS485) */
#define DW_UART_DE_EN 0xb0 /* Driver Output Enable Register */
#define DW_UART_RE_EN 0xb4 /* Receiver Output Enable Register */
#define DW_UART_DLF 0xc0 /* Divisor Latch Fraction Register */
#define DW_UART_CPR 0xf4 /* Component Parameter Register */
#define DW_UART_UCV 0xf8 /* UART Component Version */
/* Transceiver Control Register bits */
#define DW_UART_TCR_RS485_EN BIT(0)
#define DW_UART_TCR_RE_POL BIT(1)
#define DW_UART_TCR_DE_POL BIT(2)
#define DW_UART_TCR_XFER_MODE GENMASK(4, 3)
#define DW_UART_TCR_XFER_MODE_DE_DURING_RE FIELD_PREP(DW_UART_TCR_XFER_MODE, 0)
#define DW_UART_TCR_XFER_MODE_SW_DE_OR_RE FIELD_PREP(DW_UART_TCR_XFER_MODE, 1)
#define DW_UART_TCR_XFER_MODE_DE_OR_RE FIELD_PREP(DW_UART_TCR_XFER_MODE, 2)
/* Component Parameter Register bits */
#define DW_UART_CPR_ABP_DATA_WIDTH (3 << 0)
#define DW_UART_CPR_AFCE_MODE (1 << 4)
@ -32,21 +45,6 @@
/* Helper for FIFO size calculation */
#define DW_UART_CPR_FIFO_SIZE(a) (((a >> 16) & 0xff) * 16)
static inline u32 dw8250_readl_ext(struct uart_port *p, int offset)
{
if (p->iotype == UPIO_MEM32BE)
return ioread32be(p->membase + offset);
return readl(p->membase + offset);
}
static inline void dw8250_writel_ext(struct uart_port *p, int offset, u32 reg)
{
if (p->iotype == UPIO_MEM32BE)
iowrite32be(reg, p->membase + offset);
else
writel(reg, p->membase + offset);
}
/*
* divisor = div(I) + div(F)
* "I" means integer, "F" means fractional
@ -87,11 +85,87 @@ void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios, struct
}
EXPORT_SYMBOL_GPL(dw8250_do_set_termios);
static int dw8250_rs485_config(struct uart_port *p, struct serial_rs485 *rs485)
{
u32 tcr;
tcr = dw8250_readl_ext(p, DW_UART_TCR);
tcr &= ~DW_UART_TCR_XFER_MODE;
if (rs485->flags & SER_RS485_ENABLED) {
/* Clear unsupported flags. */
rs485->flags &= SER_RS485_ENABLED | SER_RS485_RX_DURING_TX |
SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND;
tcr |= DW_UART_TCR_RS485_EN;
if (rs485->flags & SER_RS485_RX_DURING_TX) {
tcr |= DW_UART_TCR_XFER_MODE_DE_DURING_RE;
} else {
/* HW does not support same DE level for tx and rx */
if (!(rs485->flags & SER_RS485_RTS_ON_SEND) ==
!(rs485->flags & SER_RS485_RTS_AFTER_SEND))
return -EINVAL;
tcr |= DW_UART_TCR_XFER_MODE_DE_OR_RE;
}
dw8250_writel_ext(p, DW_UART_DE_EN, 1);
dw8250_writel_ext(p, DW_UART_RE_EN, 1);
} else {
rs485->flags = 0;
tcr &= ~DW_UART_TCR_RS485_EN;
}
/* Reset to default polarity */
tcr |= DW_UART_TCR_DE_POL;
tcr &= ~DW_UART_TCR_RE_POL;
if (!(rs485->flags & SER_RS485_RTS_ON_SEND))
tcr &= ~DW_UART_TCR_DE_POL;
if (device_property_read_bool(p->dev, "rs485-rx-active-high"))
tcr |= DW_UART_TCR_RE_POL;
dw8250_writel_ext(p, DW_UART_TCR, tcr);
rs485->delay_rts_before_send = 0;
rs485->delay_rts_after_send = 0;
p->rs485 = *rs485;
return 0;
}
/*
* Tests if RE_EN register can have non-zero value to see if RS-485 HW support
* is present.
*/
static bool dw8250_detect_rs485_hw(struct uart_port *p)
{
u32 reg;
dw8250_writel_ext(p, DW_UART_RE_EN, 1);
reg = dw8250_readl_ext(p, DW_UART_RE_EN);
dw8250_writel_ext(p, DW_UART_RE_EN, 0);
return reg;
}
void dw8250_setup_port(struct uart_port *p)
{
struct dw8250_port_data *pd = p->private_data;
struct dw8250_data *data = to_dw8250_data(pd);
struct uart_8250_port *up = up_to_u8250p(p);
u32 reg;
pd->hw_rs485_support = dw8250_detect_rs485_hw(p);
if (pd->hw_rs485_support) {
p->rs485_config = dw8250_rs485_config;
} else {
p->rs485_config = serial8250_em485_config;
up->rs485_start_tx = serial8250_em485_start_tx;
up->rs485_stop_tx = serial8250_em485_stop_tx;
}
up->capabilities |= UART_CAP_NOTEMT;
/*
* If the Component Version Register returns zero, we know that
* ADDITIONAL_FEATURES are not enabled. No need to go any further.
@ -108,14 +182,16 @@ void dw8250_setup_port(struct uart_port *p)
dw8250_writel_ext(p, DW_UART_DLF, 0);
if (reg) {
struct dw8250_port_data *d = p->private_data;
d->dlf_size = fls(reg);
pd->dlf_size = fls(reg);
p->get_divisor = dw8250_get_divisor;
p->set_divisor = dw8250_set_divisor;
}
reg = dw8250_readl_ext(p, DW_UART_CPR);
if (!reg) {
reg = data->pdata->cpr_val;
dev_dbg(p->dev, "CPR is not available, using 0x%08x instead\n", reg);
}
if (!reg)
return;
@ -124,7 +200,7 @@ void dw8250_setup_port(struct uart_port *p)
p->type = PORT_16550A;
p->flags |= UPF_FIXED_TYPE;
p->fifosize = DW_UART_CPR_FIFO_SIZE(reg);
up->capabilities = UART_CAP_FIFO;
up->capabilities = UART_CAP_FIFO | UART_CAP_NOTEMT;
}
if (reg & DW_UART_CPR_AFCE_MODE)

View File

@ -1,10 +1,16 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/* Synopsys DesignWare 8250 library header file. */
#include <linux/io.h>
#include <linux/notifier.h>
#include <linux/types.h>
#include <linux/workqueue.h>
#include "8250.h"
struct clk;
struct reset_control;
struct dw8250_port_data {
/* Port properties */
int line;
@ -14,7 +20,52 @@ struct dw8250_port_data {
/* Hardware configuration */
u8 dlf_size;
/* RS485 variables */
bool hw_rs485_support;
};
struct dw8250_platform_data {
u8 usr_reg;
u32 cpr_val;
unsigned int quirks;
};
struct dw8250_data {
struct dw8250_port_data data;
const struct dw8250_platform_data *pdata;
int msr_mask_on;
int msr_mask_off;
struct clk *clk;
struct clk *pclk;
struct notifier_block clk_notifier;
struct work_struct clk_work;
struct reset_control *rst;
unsigned int skip_autocfg:1;
unsigned int uart_16550_compatible:1;
};
void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios, struct ktermios *old);
void dw8250_setup_port(struct uart_port *p);
static inline struct dw8250_data *to_dw8250_data(struct dw8250_port_data *data)
{
return container_of(data, struct dw8250_data, data);
}
static inline u32 dw8250_readl_ext(struct uart_port *p, int offset)
{
if (p->iotype == UPIO_MEM32BE)
return ioread32be(p->membase + offset);
return readl(p->membase + offset);
}
static inline void dw8250_writel_ext(struct uart_port *p, int offset, u32 reg)
{
if (p->iotype == UPIO_MEM32BE)
iowrite32be(reg, p->membase + offset);
else
writel(reg, p->membase + offset);
}

View File

@ -200,12 +200,12 @@ static int fintek_8250_rs485_config(struct uart_port *port,
if (!pdata)
return -EINVAL;
/* Hardware do not support same RTS level on send and receive */
if (!(rs485->flags & SER_RS485_RTS_ON_SEND) ==
!(rs485->flags & SER_RS485_RTS_AFTER_SEND))
return -EINVAL;
if (rs485->flags & SER_RS485_ENABLED) {
/* Hardware do not support same RTS level on send and receive */
if (!(rs485->flags & SER_RS485_RTS_ON_SEND) ==
!(rs485->flags & SER_RS485_RTS_AFTER_SEND))
return -EINVAL;
memset(rs485->padding, 0, sizeof(rs485->padding));
config |= RS485_URA;
} else {

View File

@ -54,9 +54,6 @@
#define MTK_UART_TX_TRIGGER 1
#define MTK_UART_RX_TRIGGER MTK_UART_RX_SIZE
#define MTK_UART_FEATURE_SEL 39 /* Feature Selection register */
#define MTK_UART_FEAT_NEWRMAP BIT(0) /* Use new register map */
#define MTK_UART_XON1 40 /* I/O: Xon character 1 */
#define MTK_UART_XOFF1 42 /* I/O: Xoff character 1 */
@ -575,10 +572,6 @@ static int mtk8250_probe(struct platform_device *pdev)
uart.dma = data->dma;
#endif
/* Set AP UART new register map */
writel(MTK_UART_FEAT_NEWRMAP, uart.port.membase +
(MTK_UART_FEATURE_SEL << uart.port.regshift));
/* Disable Rate Fix function */
writel(0x0, uart.port.membase +
(MTK_UART_RATE_FIX << uart.port.regshift));

View File

@ -326,6 +326,8 @@ static const struct of_device_id of_platform_serial_table[] = {
.data = (void *)PORT_ALTR_16550_F64, },
{ .compatible = "altr,16550-FIFO128",
.data = (void *)PORT_ALTR_16550_F128, },
{ .compatible = "fsl,16550-FIFO64",
.data = (void *)PORT_16550A_FSL64, },
{ .compatible = "mediatek,mtk-btif",
.data = (void *)PORT_MTK_BTIF, },
{ .compatible = "mrvl,mmp-uart",

View File

@ -11,6 +11,7 @@
#include <linux/pci.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/math.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/tty.h>
@ -994,41 +995,29 @@ static void pci_ite887x_exit(struct pci_dev *dev)
}
/*
* EndRun Technologies.
* Determine the number of ports available on the device.
* Oxford Semiconductor Inc.
* Check if an OxSemi device is part of the Tornado range of devices.
*/
#define PCI_VENDOR_ID_ENDRUN 0x7401
#define PCI_DEVICE_ID_ENDRUN_1588 0xe100
static int pci_endrun_init(struct pci_dev *dev)
static bool pci_oxsemi_tornado_p(struct pci_dev *dev)
{
u8 __iomem *p;
unsigned long deviceID;
unsigned int number_uarts = 0;
/* OxSemi Tornado devices are all 0xCxxx */
if (dev->vendor == PCI_VENDOR_ID_OXSEMI &&
(dev->device & 0xf000) != 0xc000)
return false;
/* EndRun device is all 0xexxx */
/* EndRun devices are all 0xExxx */
if (dev->vendor == PCI_VENDOR_ID_ENDRUN &&
(dev->device & 0xf000) != 0xe000)
return 0;
(dev->device & 0xf000) != 0xe000)
return false;
p = pci_iomap(dev, 0, 5);
if (p == NULL)
return -ENOMEM;
deviceID = ioread32(p);
/* EndRun device */
if (deviceID == 0x07000200) {
number_uarts = ioread8(p + 4);
pci_dbg(dev, "%d ports detected on EndRun PCI Express device\n", number_uarts);
}
pci_iounmap(dev, p);
return number_uarts;
return true;
}
/*
* Oxford Semiconductor Inc.
* Check that device is part of the Tornado range of devices, then determine
* the number of ports available on the device.
* Determine the number of ports available on a Tornado device.
*/
static int pci_oxsemi_tornado_init(struct pci_dev *dev)
{
@ -1036,9 +1025,7 @@ static int pci_oxsemi_tornado_init(struct pci_dev *dev)
unsigned long deviceID;
unsigned int number_uarts = 0;
/* OxSemi Tornado devices are all 0xCxxx */
if (dev->vendor == PCI_VENDOR_ID_OXSEMI &&
(dev->device & 0xF000) != 0xC000)
if (!pci_oxsemi_tornado_p(dev))
return 0;
p = pci_iomap(dev, 0, 5);
@ -1049,12 +1036,217 @@ static int pci_oxsemi_tornado_init(struct pci_dev *dev)
/* Tornado device */
if (deviceID == 0x07000200) {
number_uarts = ioread8(p + 4);
pci_dbg(dev, "%d ports detected on Oxford PCI Express device\n", number_uarts);
pci_dbg(dev, "%d ports detected on %s PCI Express device\n",
number_uarts,
dev->vendor == PCI_VENDOR_ID_ENDRUN ?
"EndRun" : "Oxford");
}
pci_iounmap(dev, p);
return number_uarts;
}
/* Tornado-specific constants for the TCR and CPR registers; see below. */
#define OXSEMI_TORNADO_TCR_MASK 0xf
#define OXSEMI_TORNADO_CPR_MASK 0x1ff
#define OXSEMI_TORNADO_CPR_MIN 0x008
#define OXSEMI_TORNADO_CPR_DEF 0x10f
/*
* Determine the oversampling rate, the clock prescaler, and the clock
* divisor for the requested baud rate. The clock rate is 62.5 MHz,
* which is four times the baud base, and the prescaler increments in
* steps of 1/8. Therefore to make calculations on integers we need
* to use a scaled clock rate, which is the baud base multiplied by 32
* (or our assumed UART clock rate multiplied by 2).
*
* The allowed oversampling rates are from 4 up to 16 inclusive (values
* from 0 to 3 inclusive map to 16). Likewise the clock prescaler allows
* values between 1.000 and 63.875 inclusive (operation for values from
* 0.000 to 0.875 has not been specified). The clock divisor is the usual
* unsigned 16-bit integer.
*
* For the most accurate baud rate we use a table of predetermined
* oversampling rates and clock prescalers that records all possible
* products of the two parameters in the range from 4 up to 255 inclusive,
* and additionally 335 for the 1500000bps rate, with the prescaler scaled
* by 8. The table is sorted by the decreasing value of the oversampling
* rate and ties are resolved by sorting by the decreasing value of the
* product. This way preference is given to higher oversampling rates.
*
* We iterate over the table and choose the product of an oversampling
* rate and a clock prescaler that gives the lowest integer division
* result deviation, or if an exact integer divider is found we stop
* looking for it right away. We do some fixup if the resulting clock
* divisor required would be out of its unsigned 16-bit integer range.
*
* Finally we abuse the supposed fractional part returned to encode the
* 4-bit value of the oversampling rate and the 9-bit value of the clock
* prescaler which will end up in the TCR and CPR/CPR2 registers.
*/
static unsigned int pci_oxsemi_tornado_get_divisor(struct uart_port *port,
unsigned int baud,
unsigned int *frac)
{
static u8 p[][2] = {
{ 16, 14, }, { 16, 13, }, { 16, 12, }, { 16, 11, },
{ 16, 10, }, { 16, 9, }, { 16, 8, }, { 15, 17, },
{ 15, 16, }, { 15, 15, }, { 15, 14, }, { 15, 13, },
{ 15, 12, }, { 15, 11, }, { 15, 10, }, { 15, 9, },
{ 15, 8, }, { 14, 18, }, { 14, 17, }, { 14, 14, },
{ 14, 13, }, { 14, 12, }, { 14, 11, }, { 14, 10, },
{ 14, 9, }, { 14, 8, }, { 13, 19, }, { 13, 18, },
{ 13, 17, }, { 13, 13, }, { 13, 12, }, { 13, 11, },
{ 13, 10, }, { 13, 9, }, { 13, 8, }, { 12, 19, },
{ 12, 18, }, { 12, 17, }, { 12, 11, }, { 12, 9, },
{ 12, 8, }, { 11, 23, }, { 11, 22, }, { 11, 21, },
{ 11, 20, }, { 11, 19, }, { 11, 18, }, { 11, 17, },
{ 11, 11, }, { 11, 10, }, { 11, 9, }, { 11, 8, },
{ 10, 25, }, { 10, 23, }, { 10, 20, }, { 10, 19, },
{ 10, 17, }, { 10, 10, }, { 10, 9, }, { 10, 8, },
{ 9, 27, }, { 9, 23, }, { 9, 21, }, { 9, 19, },
{ 9, 18, }, { 9, 17, }, { 9, 9, }, { 9, 8, },
{ 8, 31, }, { 8, 29, }, { 8, 23, }, { 8, 19, },
{ 8, 17, }, { 8, 8, }, { 7, 35, }, { 7, 31, },
{ 7, 29, }, { 7, 25, }, { 7, 23, }, { 7, 21, },
{ 7, 19, }, { 7, 17, }, { 7, 15, }, { 7, 14, },
{ 7, 13, }, { 7, 12, }, { 7, 11, }, { 7, 10, },
{ 7, 9, }, { 7, 8, }, { 6, 41, }, { 6, 37, },
{ 6, 31, }, { 6, 29, }, { 6, 23, }, { 6, 19, },
{ 6, 17, }, { 6, 13, }, { 6, 11, }, { 6, 10, },
{ 6, 9, }, { 6, 8, }, { 5, 67, }, { 5, 47, },
{ 5, 43, }, { 5, 41, }, { 5, 37, }, { 5, 31, },
{ 5, 29, }, { 5, 25, }, { 5, 23, }, { 5, 19, },
{ 5, 17, }, { 5, 15, }, { 5, 13, }, { 5, 11, },
{ 5, 10, }, { 5, 9, }, { 5, 8, }, { 4, 61, },
{ 4, 59, }, { 4, 53, }, { 4, 47, }, { 4, 43, },
{ 4, 41, }, { 4, 37, }, { 4, 31, }, { 4, 29, },
{ 4, 23, }, { 4, 19, }, { 4, 17, }, { 4, 13, },
{ 4, 9, }, { 4, 8, },
};
/* Scale the quotient for comparison to get the fractional part. */
const unsigned int quot_scale = 65536;
unsigned int sclk = port->uartclk * 2;
unsigned int sdiv = DIV_ROUND_CLOSEST(sclk, baud);
unsigned int best_squot;
unsigned int squot;
unsigned int quot;
u16 cpr;
u8 tcr;
int i;
/* Old custom speed handling. */
if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) {
unsigned int cust_div = port->custom_divisor;
quot = cust_div & UART_DIV_MAX;
tcr = (cust_div >> 16) & OXSEMI_TORNADO_TCR_MASK;
cpr = (cust_div >> 20) & OXSEMI_TORNADO_CPR_MASK;
if (cpr < OXSEMI_TORNADO_CPR_MIN)
cpr = OXSEMI_TORNADO_CPR_DEF;
} else {
best_squot = quot_scale;
for (i = 0; i < ARRAY_SIZE(p); i++) {
unsigned int spre;
unsigned int srem;
u8 cp;
u8 tc;
tc = p[i][0];
cp = p[i][1];
spre = tc * cp;
srem = sdiv % spre;
if (srem > spre / 2)
srem = spre - srem;
squot = DIV_ROUND_CLOSEST(srem * quot_scale, spre);
if (srem == 0) {
tcr = tc;
cpr = cp;
quot = sdiv / spre;
break;
} else if (squot < best_squot) {
best_squot = squot;
tcr = tc;
cpr = cp;
quot = DIV_ROUND_CLOSEST(sdiv, spre);
}
}
while (tcr <= (OXSEMI_TORNADO_TCR_MASK + 1) >> 1 &&
quot % 2 == 0) {
quot >>= 1;
tcr <<= 1;
}
while (quot > UART_DIV_MAX) {
if (tcr <= (OXSEMI_TORNADO_TCR_MASK + 1) >> 1) {
quot >>= 1;
tcr <<= 1;
} else if (cpr <= OXSEMI_TORNADO_CPR_MASK >> 1) {
quot >>= 1;
cpr <<= 1;
} else {
quot = quot * cpr / OXSEMI_TORNADO_CPR_MASK;
cpr = OXSEMI_TORNADO_CPR_MASK;
}
}
}
*frac = (cpr << 8) | (tcr & OXSEMI_TORNADO_TCR_MASK);
return quot;
}
/*
* Set the oversampling rate in the transmitter clock cycle register (TCR),
* the clock prescaler in the clock prescaler register (CPR and CPR2), and
* the clock divisor in the divisor latch (DLL and DLM). Note that for
* backwards compatibility any write to CPR clears CPR2 and therefore CPR
* has to be written first, followed by CPR2, which occupies the location
* of CKS used with earlier UART designs.
*/
static void pci_oxsemi_tornado_set_divisor(struct uart_port *port,
unsigned int baud,
unsigned int quot,
unsigned int quot_frac)
{
struct uart_8250_port *up = up_to_u8250p(port);
u8 cpr2 = quot_frac >> 16;
u8 cpr = quot_frac >> 8;
u8 tcr = quot_frac;
serial_icr_write(up, UART_TCR, tcr);
serial_icr_write(up, UART_CPR, cpr);
serial_icr_write(up, UART_CKS, cpr2);
serial8250_do_set_divisor(port, baud, quot, 0);
}
/*
* For Tornado devices we force MCR[7] set for the Divide-by-M N/8 baud rate
* generator prescaler (CPR and CPR2). Otherwise no prescaler would be used.
*/
static void pci_oxsemi_tornado_set_mctrl(struct uart_port *port,
unsigned int mctrl)
{
struct uart_8250_port *up = up_to_u8250p(port);
up->mcr |= UART_MCR_CLKSEL;
serial8250_do_set_mctrl(port, mctrl);
}
static int pci_oxsemi_tornado_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_8250_port *up, int idx)
{
struct pci_dev *dev = priv->dev;
if (pci_oxsemi_tornado_p(dev)) {
up->port.get_divisor = pci_oxsemi_tornado_get_divisor;
up->port.set_divisor = pci_oxsemi_tornado_set_divisor;
up->port.set_mctrl = pci_oxsemi_tornado_set_mctrl;
}
return pci_default_setup(priv, board, up, idx);
}
static int pci_asix_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_8250_port *port, int idx)
@ -2244,7 +2436,7 @@ static struct pci_serial_quirk pci_serial_quirks[] = {
.device = PCI_ANY_ID,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.init = pci_endrun_init,
.init = pci_oxsemi_tornado_init,
.setup = pci_default_setup,
},
/*
@ -2256,7 +2448,7 @@ static struct pci_serial_quirk pci_serial_quirks[] = {
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.init = pci_oxsemi_tornado_init,
.setup = pci_default_setup,
.setup = pci_oxsemi_tornado_setup,
},
{
.vendor = PCI_VENDOR_ID_MAINPINE,
@ -2264,7 +2456,7 @@ static struct pci_serial_quirk pci_serial_quirks[] = {
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.init = pci_oxsemi_tornado_init,
.setup = pci_default_setup,
.setup = pci_oxsemi_tornado_setup,
},
{
.vendor = PCI_VENDOR_ID_DIGI,
@ -2272,7 +2464,7 @@ static struct pci_serial_quirk pci_serial_quirks[] = {
.subvendor = PCI_SUBVENDOR_ID_IBM,
.subdevice = PCI_ANY_ID,
.init = pci_oxsemi_tornado_init,
.setup = pci_default_setup,
.setup = pci_oxsemi_tornado_setup,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
@ -2589,7 +2781,7 @@ enum pci_board_num_t {
pbn_b0_2_1843200,
pbn_b0_4_1843200,
pbn_b0_1_3906250,
pbn_b0_1_15625000,
pbn_b0_bt_1_115200,
pbn_b0_bt_2_115200,
@ -2667,12 +2859,11 @@ enum pci_board_num_t {
pbn_panacom2,
pbn_panacom4,
pbn_plx_romulus,
pbn_endrun_2_3906250,
pbn_oxsemi,
pbn_oxsemi_1_3906250,
pbn_oxsemi_2_3906250,
pbn_oxsemi_4_3906250,
pbn_oxsemi_8_3906250,
pbn_oxsemi_1_15625000,
pbn_oxsemi_2_15625000,
pbn_oxsemi_4_15625000,
pbn_oxsemi_8_15625000,
pbn_intel_i960,
pbn_sgi_ioc3,
pbn_computone_4,
@ -2815,10 +3006,10 @@ static struct pciserial_board pci_boards[] = {
.uart_offset = 8,
},
[pbn_b0_1_3906250] = {
[pbn_b0_1_15625000] = {
.flags = FL_BASE0,
.num_ports = 1,
.base_baud = 3906250,
.base_baud = 15625000,
.uart_offset = 8,
},
@ -3189,20 +3380,6 @@ static struct pciserial_board pci_boards[] = {
.first_offset = 0x03,
},
/*
* EndRun Technologies
* Uses the size of PCI Base region 0 to
* signal now many ports are available
* 2 port 952 Uart support
*/
[pbn_endrun_2_3906250] = {
.flags = FL_BASE0,
.num_ports = 2,
.base_baud = 3906250,
.uart_offset = 0x200,
.first_offset = 0x1000,
},
/*
* This board uses the size of PCI Base region 0 to
* signal now many ports are available
@ -3213,31 +3390,31 @@ static struct pciserial_board pci_boards[] = {
.base_baud = 115200,
.uart_offset = 8,
},
[pbn_oxsemi_1_3906250] = {
[pbn_oxsemi_1_15625000] = {
.flags = FL_BASE0,
.num_ports = 1,
.base_baud = 3906250,
.base_baud = 15625000,
.uart_offset = 0x200,
.first_offset = 0x1000,
},
[pbn_oxsemi_2_3906250] = {
[pbn_oxsemi_2_15625000] = {
.flags = FL_BASE0,
.num_ports = 2,
.base_baud = 3906250,
.base_baud = 15625000,
.uart_offset = 0x200,
.first_offset = 0x1000,
},
[pbn_oxsemi_4_3906250] = {
[pbn_oxsemi_4_15625000] = {
.flags = FL_BASE0,
.num_ports = 4,
.base_baud = 3906250,
.base_baud = 15625000,
.uart_offset = 0x200,
.first_offset = 0x1000,
},
[pbn_oxsemi_8_3906250] = {
[pbn_oxsemi_8_15625000] = {
.flags = FL_BASE0,
.num_ports = 8,
.base_baud = 3906250,
.base_baud = 15625000,
.uart_offset = 0x200,
.first_offset = 0x1000,
},
@ -3518,6 +3695,12 @@ static struct pciserial_board pci_boards[] = {
},
};
#define REPORT_CONFIG(option) \
(IS_ENABLED(CONFIG_##option) ? 0 : (kernel_ulong_t)&#option)
#define REPORT_8250_CONFIG(option) \
(IS_ENABLED(CONFIG_SERIAL_8250_##option) ? \
0 : (kernel_ulong_t)&"SERIAL_8250_"#option)
static const struct pci_device_id blacklist[] = {
/* softmodems */
{ PCI_VDEVICE(AL, 0x5457), }, /* ALi Corporation M5457 AC'97 Modem */
@ -3525,40 +3708,43 @@ static const struct pci_device_id blacklist[] = {
{ PCI_DEVICE(0x1543, 0x3052), }, /* Si3052-based modem, default IDs */
/* multi-io cards handled by parport_serial */
{ PCI_DEVICE(0x4348, 0x7053), }, /* WCH CH353 2S1P */
{ PCI_DEVICE(0x4348, 0x5053), }, /* WCH CH353 1S1P */
{ PCI_DEVICE(0x1c00, 0x3250), }, /* WCH CH382 2S1P */
/* WCH CH353 2S1P */
{ PCI_DEVICE(0x4348, 0x7053), 0, 0, REPORT_CONFIG(PARPORT_SERIAL), },
/* WCH CH353 1S1P */
{ PCI_DEVICE(0x4348, 0x5053), 0, 0, REPORT_CONFIG(PARPORT_SERIAL), },
/* WCH CH382 2S1P */
{ PCI_DEVICE(0x1c00, 0x3250), 0, 0, REPORT_CONFIG(PARPORT_SERIAL), },
/* Intel platforms with MID UART */
{ PCI_VDEVICE(INTEL, 0x081b), },
{ PCI_VDEVICE(INTEL, 0x081c), },
{ PCI_VDEVICE(INTEL, 0x081d), },
{ PCI_VDEVICE(INTEL, 0x1191), },
{ PCI_VDEVICE(INTEL, 0x18d8), },
{ PCI_VDEVICE(INTEL, 0x19d8), },
{ PCI_VDEVICE(INTEL, 0x081b), REPORT_8250_CONFIG(MID), },
{ PCI_VDEVICE(INTEL, 0x081c), REPORT_8250_CONFIG(MID), },
{ PCI_VDEVICE(INTEL, 0x081d), REPORT_8250_CONFIG(MID), },
{ PCI_VDEVICE(INTEL, 0x1191), REPORT_8250_CONFIG(MID), },
{ PCI_VDEVICE(INTEL, 0x18d8), REPORT_8250_CONFIG(MID), },
{ PCI_VDEVICE(INTEL, 0x19d8), REPORT_8250_CONFIG(MID), },
/* Intel platforms with DesignWare UART */
{ PCI_VDEVICE(INTEL, 0x0936), },
{ PCI_VDEVICE(INTEL, 0x0f0a), },
{ PCI_VDEVICE(INTEL, 0x0f0c), },
{ PCI_VDEVICE(INTEL, 0x228a), },
{ PCI_VDEVICE(INTEL, 0x228c), },
{ PCI_VDEVICE(INTEL, 0x4b96), },
{ PCI_VDEVICE(INTEL, 0x4b97), },
{ PCI_VDEVICE(INTEL, 0x4b98), },
{ PCI_VDEVICE(INTEL, 0x4b99), },
{ PCI_VDEVICE(INTEL, 0x4b9a), },
{ PCI_VDEVICE(INTEL, 0x4b9b), },
{ PCI_VDEVICE(INTEL, 0x9ce3), },
{ PCI_VDEVICE(INTEL, 0x9ce4), },
{ PCI_VDEVICE(INTEL, 0x0936), REPORT_8250_CONFIG(LPSS), },
{ PCI_VDEVICE(INTEL, 0x0f0a), REPORT_8250_CONFIG(LPSS), },
{ PCI_VDEVICE(INTEL, 0x0f0c), REPORT_8250_CONFIG(LPSS), },
{ PCI_VDEVICE(INTEL, 0x228a), REPORT_8250_CONFIG(LPSS), },
{ PCI_VDEVICE(INTEL, 0x228c), REPORT_8250_CONFIG(LPSS), },
{ PCI_VDEVICE(INTEL, 0x4b96), REPORT_8250_CONFIG(LPSS), },
{ PCI_VDEVICE(INTEL, 0x4b97), REPORT_8250_CONFIG(LPSS), },
{ PCI_VDEVICE(INTEL, 0x4b98), REPORT_8250_CONFIG(LPSS), },
{ PCI_VDEVICE(INTEL, 0x4b99), REPORT_8250_CONFIG(LPSS), },
{ PCI_VDEVICE(INTEL, 0x4b9a), REPORT_8250_CONFIG(LPSS), },
{ PCI_VDEVICE(INTEL, 0x4b9b), REPORT_8250_CONFIG(LPSS), },
{ PCI_VDEVICE(INTEL, 0x9ce3), REPORT_8250_CONFIG(LPSS), },
{ PCI_VDEVICE(INTEL, 0x9ce4), REPORT_8250_CONFIG(LPSS), },
/* Exar devices */
{ PCI_VDEVICE(EXAR, PCI_ANY_ID), },
{ PCI_VDEVICE(COMMTECH, PCI_ANY_ID), },
{ PCI_VDEVICE(EXAR, PCI_ANY_ID), REPORT_8250_CONFIG(EXAR), },
{ PCI_VDEVICE(COMMTECH, PCI_ANY_ID), REPORT_8250_CONFIG(EXAR), },
/* Pericom devices */
{ PCI_VDEVICE(PERICOM, PCI_ANY_ID), },
{ PCI_VDEVICE(ACCESSIO, PCI_ANY_ID), },
{ PCI_VDEVICE(PERICOM, PCI_ANY_ID), REPORT_8250_CONFIG(PERICOM), },
{ PCI_VDEVICE(ACCESSIO, PCI_ANY_ID), REPORT_8250_CONFIG(PERICOM), },
/* End of the black list */
{ }
@ -3840,8 +4026,12 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
board = &pci_boards[ent->driver_data];
exclude = pci_match_id(blacklist, dev);
if (exclude)
if (exclude) {
if (exclude->driver_data)
pci_warn(dev, "ignoring port, enable %s to handle\n",
(const char *)exclude->driver_data);
return -ENODEV;
}
rc = pcim_enable_device(dev);
pci_save_state(dev);
@ -4109,13 +4299,6 @@ static const struct pci_device_id serial_pci_tbl[] = {
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_ROMULUS,
0x10b5, 0x106a, 0, 0,
pbn_plx_romulus },
/*
* EndRun Technologies. PCI express device range.
* EndRun PTP/1588 has 2 Native UARTs.
*/
{ PCI_VENDOR_ID_ENDRUN, PCI_DEVICE_ID_ENDRUN_1588,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_endrun_2_3906250 },
/*
* Quatech cards. These actually have configurable clocks but for
* now we just use the default.
@ -4225,158 +4408,165 @@ static const struct pci_device_id serial_pci_tbl[] = {
*/
{ PCI_VENDOR_ID_OXSEMI, 0xc101, /* OXPCIe952 1 Legacy UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_1_3906250 },
pbn_b0_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc105, /* OXPCIe952 1 Legacy UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_1_3906250 },
pbn_b0_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc11b, /* OXPCIe952 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_1_3906250 },
pbn_oxsemi_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc11f, /* OXPCIe952 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_1_3906250 },
pbn_oxsemi_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc120, /* OXPCIe952 1 Legacy UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_1_3906250 },
pbn_b0_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc124, /* OXPCIe952 1 Legacy UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_1_3906250 },
pbn_b0_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc138, /* OXPCIe952 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_1_3906250 },
pbn_oxsemi_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc13d, /* OXPCIe952 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_1_3906250 },
pbn_oxsemi_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc140, /* OXPCIe952 1 Legacy UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_1_3906250 },
pbn_b0_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc141, /* OXPCIe952 1 Legacy UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_1_3906250 },
pbn_b0_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc144, /* OXPCIe952 1 Legacy UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_1_3906250 },
pbn_b0_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc145, /* OXPCIe952 1 Legacy UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_1_3906250 },
pbn_b0_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc158, /* OXPCIe952 2 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_2_3906250 },
pbn_oxsemi_2_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc15d, /* OXPCIe952 2 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_2_3906250 },
pbn_oxsemi_2_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc208, /* OXPCIe954 4 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_4_3906250 },
pbn_oxsemi_4_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc20d, /* OXPCIe954 4 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_4_3906250 },
pbn_oxsemi_4_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc308, /* OXPCIe958 8 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_8_3906250 },
pbn_oxsemi_8_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc30d, /* OXPCIe958 8 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_8_3906250 },
pbn_oxsemi_8_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc40b, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_1_3906250 },
pbn_oxsemi_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc40f, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_1_3906250 },
pbn_oxsemi_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc41b, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_1_3906250 },
pbn_oxsemi_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc41f, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_1_3906250 },
pbn_oxsemi_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc42b, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_1_3906250 },
pbn_oxsemi_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc42f, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_1_3906250 },
pbn_oxsemi_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc43b, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_1_3906250 },
pbn_oxsemi_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc43f, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_1_3906250 },
pbn_oxsemi_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc44b, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_1_3906250 },
pbn_oxsemi_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc44f, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_1_3906250 },
pbn_oxsemi_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc45b, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_1_3906250 },
pbn_oxsemi_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc45f, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_1_3906250 },
pbn_oxsemi_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc46b, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_1_3906250 },
pbn_oxsemi_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc46f, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_1_3906250 },
pbn_oxsemi_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc47b, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_1_3906250 },
pbn_oxsemi_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc47f, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_1_3906250 },
pbn_oxsemi_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc48b, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_1_3906250 },
pbn_oxsemi_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc48f, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_1_3906250 },
pbn_oxsemi_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc49b, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_1_3906250 },
pbn_oxsemi_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc49f, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_1_3906250 },
pbn_oxsemi_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc4ab, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_1_3906250 },
pbn_oxsemi_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc4af, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_1_3906250 },
pbn_oxsemi_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc4bb, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_1_3906250 },
pbn_oxsemi_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc4bf, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_1_3906250 },
pbn_oxsemi_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc4cb, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_1_3906250 },
pbn_oxsemi_1_15625000 },
{ PCI_VENDOR_ID_OXSEMI, 0xc4cf, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_1_3906250 },
pbn_oxsemi_1_15625000 },
/*
* Mainpine Inc. IQ Express "Rev3" utilizing OxSemi Tornado
*/
{ PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 1 Port V.34 Super-G3 Fax */
PCI_VENDOR_ID_MAINPINE, 0x4001, 0, 0,
pbn_oxsemi_1_3906250 },
pbn_oxsemi_1_15625000 },
{ PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 2 Port V.34 Super-G3 Fax */
PCI_VENDOR_ID_MAINPINE, 0x4002, 0, 0,
pbn_oxsemi_2_3906250 },
pbn_oxsemi_2_15625000 },
{ PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 4 Port V.34 Super-G3 Fax */
PCI_VENDOR_ID_MAINPINE, 0x4004, 0, 0,
pbn_oxsemi_4_3906250 },
pbn_oxsemi_4_15625000 },
{ PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 8 Port V.34 Super-G3 Fax */
PCI_VENDOR_ID_MAINPINE, 0x4008, 0, 0,
pbn_oxsemi_8_3906250 },
pbn_oxsemi_8_15625000 },
/*
* Digi/IBM PCIe 2-port Async EIA-232 Adapter utilizing OxSemi Tornado
*/
{ PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_2_OX_IBM,
PCI_SUBVENDOR_ID_IBM, PCI_ANY_ID, 0, 0,
pbn_oxsemi_2_3906250 },
pbn_oxsemi_2_15625000 },
/*
* EndRun Technologies. PCI express device range.
* EndRun PTP/1588 has 2 Native UARTs utilizing OxSemi 952.
*/
{ PCI_VENDOR_ID_ENDRUN, PCI_DEVICE_ID_ENDRUN_1588,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_2_15625000 },
/*
* SBS Technologies, Inc. P-Octal and PMC-OCTPRO cards,

View File

@ -263,7 +263,7 @@ static const struct serial8250_config uart_config[] = {
.tx_loadsz = 63,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 |
UART_FCR7_64BYTE,
.flags = UART_CAP_FIFO,
.flags = UART_CAP_FIFO | UART_CAP_NOTEMT,
},
[PORT_RT2880] = {
.name = "Palmchip BK-3103",
@ -537,27 +537,6 @@ serial_port_out_sync(struct uart_port *p, int offset, int value)
}
}
/*
* For the 16C950
*/
static void serial_icr_write(struct uart_8250_port *up, int offset, int value)
{
serial_out(up, UART_SCR, offset);
serial_out(up, UART_ICR, value);
}
static unsigned int serial_icr_read(struct uart_8250_port *up, int offset)
{
unsigned int value;
serial_icr_write(up, UART_ACR, up->acr | UART_ACR_ICRRD);
serial_out(up, UART_SCR, offset);
value = serial_in(up, UART_ICR);
serial_icr_write(up, UART_ACR, up->acr);
return value;
}
/*
* FIFO support.
*/
@ -1504,18 +1483,19 @@ static void start_hrtimer_ms(struct hrtimer *hrt, unsigned long msec)
hrtimer_start(hrt, ms_to_ktime(msec), HRTIMER_MODE_REL);
}
static void __stop_tx_rs485(struct uart_8250_port *p)
static void __stop_tx_rs485(struct uart_8250_port *p, u64 stop_delay)
{
struct uart_8250_em485 *em485 = p->em485;
stop_delay += (u64)p->port.rs485.delay_rts_after_send * NSEC_PER_MSEC;
/*
* rs485_stop_tx() is going to set RTS according to config
* AND flush RX FIFO if required.
*/
if (p->port.rs485.delay_rts_after_send > 0) {
if (stop_delay > 0) {
em485->active_timer = &em485->stop_tx_timer;
start_hrtimer_ms(&em485->stop_tx_timer,
p->port.rs485.delay_rts_after_send);
hrtimer_start(&em485->stop_tx_timer, ns_to_ktime(stop_delay), HRTIMER_MODE_REL);
} else {
p->rs485_stop_tx(p);
em485->active_timer = NULL;
@ -1535,16 +1515,32 @@ static inline void __stop_tx(struct uart_8250_port *p)
if (em485) {
unsigned char lsr = serial_in(p, UART_LSR);
u64 stop_delay = 0;
if (!(lsr & UART_LSR_THRE))
return;
/*
* To provide required timeing and allow FIFO transfer,
* __stop_tx_rs485() must be called only when both FIFO and
* shift register are empty. It is for device driver to enable
* interrupt on TEMT.
* shift register are empty. The device driver should either
* enable interrupt on TEMT or set UART_CAP_NOTEMT that will
* enlarge stop_tx_timer by the tx time of one frame to cover
* for emptying of the shift register.
*/
if ((lsr & BOTH_EMPTY) != BOTH_EMPTY)
return;
if (!(lsr & UART_LSR_TEMT)) {
if (!(p->capabilities & UART_CAP_NOTEMT))
return;
/*
* RTS might get deasserted too early with the normal
* frame timing formula. It seems to suggest THRE might
* get asserted already during tx of the stop bit
* rather than after it is fully sent.
* Roughly estimate 1 extra bit here with / 7.
*/
stop_delay = p->port.frame_time + DIV_ROUND_UP(p->port.frame_time, 7);
}
__stop_tx_rs485(p);
__stop_tx_rs485(p, stop_delay);
}
__do_stop_tx(p);
}
@ -1948,9 +1944,12 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
status = serial8250_rx_chars(up, status);
}
serial8250_modem_status(up);
if ((!up->dma || up->dma->tx_err) && (status & UART_LSR_THRE) &&
(up->ier & UART_IER_THRI))
serial8250_tx_chars(up);
if ((status & UART_LSR_THRE) && (up->ier & UART_IER_THRI)) {
if (!up->dma || up->dma->tx_err)
serial8250_tx_chars(up);
else
__stop_tx(up);
}
uart_unlock_and_check_sysrq_irqrestore(port, flags);
@ -2077,10 +2076,7 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state)
serial8250_rpm_put(up);
}
/*
* Wait for transmitter & holding register to empty
*/
static void wait_for_xmitr(struct uart_8250_port *up, int bits)
static void wait_for_lsr(struct uart_8250_port *up, int bits)
{
unsigned int status, tmout = 10000;
@ -2097,6 +2093,16 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits)
udelay(1);
touch_nmi_watchdog();
}
}
/*
* Wait for transmitter & holding register to empty
*/
static void wait_for_xmitr(struct uart_8250_port *up, int bits)
{
unsigned int tmout;
wait_for_lsr(up, bits);
/* Wait up to 1s for flow control if necessary */
if (up->port.flags & UPF_CONS_FLOW) {
@ -2614,10 +2620,8 @@ static unsigned char serial8250_compute_lcr(struct uart_8250_port *up,
}
if (!(c_cflag & PARODD))
cval |= UART_LCR_EPAR;
#ifdef CMSPAR
if (c_cflag & CMSPAR)
cval |= UART_LCR_SPAR;
#endif
return cval;
}
@ -3332,6 +3336,35 @@ static void serial8250_console_restore(struct uart_8250_port *up)
serial8250_out_MCR(up, up->mcr | UART_MCR_DTR | UART_MCR_RTS);
}
/*
* Print a string to the serial port using the device FIFO
*
* It sends fifosize bytes and then waits for the fifo
* to get empty.
*/
static void serial8250_console_fifo_write(struct uart_8250_port *up,
const char *s, unsigned int count)
{
int i;
const char *end = s + count;
unsigned int fifosize = up->tx_loadsz;
bool cr_sent = false;
while (s != end) {
wait_for_lsr(up, UART_LSR_THRE);
for (i = 0; i < fifosize && s != end; ++i) {
if (*s == '\n' && !cr_sent) {
serial_out(up, UART_TX, '\r');
cr_sent = true;
} else {
serial_out(up, UART_TX, *s++);
cr_sent = false;
}
}
}
}
/*
* Print a string to the serial port trying not to disturb
* any possible real use of the port...
@ -3347,7 +3380,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
struct uart_8250_em485 *em485 = up->em485;
struct uart_port *port = &up->port;
unsigned long flags;
unsigned int ier;
unsigned int ier, use_fifo;
int locked = 1;
touch_nmi_watchdog();
@ -3379,7 +3412,30 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
mdelay(port->rs485.delay_rts_before_send);
}
uart_console_write(port, s, count, serial8250_console_putchar);
use_fifo = (up->capabilities & UART_CAP_FIFO) &&
/*
* BCM283x requires to check the fifo
* after each byte.
*/
!(up->capabilities & UART_CAP_MINI) &&
/*
* tx_loadsz contains the transmit fifo size
*/
up->tx_loadsz > 1 &&
(up->fcr & UART_FCR_ENABLE_FIFO) &&
port->state &&
test_bit(TTY_PORT_INITIALIZED, &port->state->port.iflags) &&
/*
* After we put a data in the fifo, the controller will send
* it regardless of the CTS state. Therefore, only use fifo
* if we don't use control flow.
*/
!(up->port.flags & UPF_CONS_FLOW);
if (likely(use_fifo))
serial8250_console_fifo_write(up, s, count);
else
uart_console_write(port, s, count, serial8250_console_putchar);
/*
* Finally, wait for transmitter to become empty

View File

@ -22,7 +22,6 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/pm_runtime.h>
#include "8250.h"

View File

@ -380,7 +380,7 @@ config SERIAL_8250_DW
config SERIAL_8250_EM
tristate "Support for Emma Mobile integrated serial port"
depends on SERIAL_8250 && HAVE_CLK
depends on (ARM && ARCH_RENESAS) || COMPILE_TEST
depends on ARCH_RENESAS || COMPILE_TEST
help
Selecting this option will add support for the integrated serial
port hardware found on the Emma Mobile line of processors.

View File

@ -782,7 +782,7 @@ config SERIAL_PMACZILOG_CONSOLE
config SERIAL_CPM
tristate "CPM SCC/SMC serial port support"
depends on CPM2 || CPM1
depends on CPM2 || CPM1 || (PPC32 && COMPILE_TEST)
select SERIAL_CORE
help
This driver supports the SCC and SMC serial ports on Motorola
@ -806,7 +806,7 @@ config SERIAL_CPM_CONSOLE
config SERIAL_PIC32
tristate "Microchip PIC32 serial support"
depends on MACH_PIC32
depends on MACH_PIC32 || (MIPS && COMPILE_TEST)
select SERIAL_CORE
help
If you have a PIC32, this driver supports the serial ports.
@ -817,7 +817,7 @@ config SERIAL_PIC32
config SERIAL_PIC32_CONSOLE
bool "PIC32 serial console support"
depends on SERIAL_PIC32
depends on SERIAL_PIC32=y
select SERIAL_CORE_CONSOLE
help
If you have a PIC32, this driver supports the putting a console on one
@ -1246,7 +1246,7 @@ config SERIAL_XILINX_PS_UART_CONSOLE
config SERIAL_AR933X
tristate "AR933X serial port support"
depends on HAVE_CLK && ATH79
depends on (HAVE_CLK && ATH79) || (MIPS && COMPILE_TEST)
select SERIAL_CORE
select SERIAL_MCTRL_GPIO if GPIOLIB
help
@ -1442,6 +1442,7 @@ config SERIAL_STM32_CONSOLE
bool "Support for console on STM32"
depends on SERIAL_STM32=y
select SERIAL_CORE_CONSOLE
select SERIAL_EARLYCON
config SERIAL_MVEBU_UART
bool "Marvell EBU serial port support"

View File

@ -168,10 +168,8 @@ static void altera_jtaguart_tx_chars(struct altera_jtaguart *pp)
}
}
if (pending == 0) {
pp->imr &= ~ALTERA_JTAGUART_CONTROL_WE_MSK;
writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
}
if (pending == 0)
altera_jtaguart_stop_tx(port);
}
static irqreturn_t altera_jtaguart_interrupt(int irq, void *data)

View File

@ -42,8 +42,6 @@
#include <linux/io.h>
#include <linux/acpi.h>
#include "amba-pl011.h"
#define UART_NR 14
#define SERIAL_AMBA_MAJOR 204
@ -55,6 +53,36 @@
#define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE)
#define UART_DUMMY_DR_RX (1 << 16)
enum {
REG_DR,
REG_ST_DMAWM,
REG_ST_TIMEOUT,
REG_FR,
REG_LCRH_RX,
REG_LCRH_TX,
REG_IBRD,
REG_FBRD,
REG_CR,
REG_IFLS,
REG_IMSC,
REG_RIS,
REG_MIS,
REG_ICR,
REG_DMACR,
REG_ST_XFCR,
REG_ST_XON1,
REG_ST_XON2,
REG_ST_XOFF1,
REG_ST_XOFF2,
REG_ST_ITCR,
REG_ST_ITIP,
REG_ST_ABCR,
REG_ST_ABIMSC,
/* The size of the array - must be last */
REG_ARRAY_SIZE,
};
static u16 pl011_std_offsets[REG_ARRAY_SIZE] = {
[REG_DR] = UART01x_DR,
[REG_FR] = UART01x_FR,
@ -2175,25 +2203,11 @@ static int pl011_rs485_config(struct uart_port *port,
struct uart_amba_port *uap =
container_of(port, struct uart_amba_port, port);
/* pick sane settings if the user hasn't */
if (!(rs485->flags & SER_RS485_RTS_ON_SEND) ==
!(rs485->flags & SER_RS485_RTS_AFTER_SEND)) {
rs485->flags |= SER_RS485_RTS_ON_SEND;
rs485->flags &= ~SER_RS485_RTS_AFTER_SEND;
}
/* clamp the delays to [0, 100ms] */
rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U);
memset(rs485->padding, 0, sizeof(rs485->padding));
if (port->rs485.flags & SER_RS485_ENABLED)
pl011_rs485_tx_stop(uap);
/* Set new configuration */
port->rs485 = *rs485;
/* Make sure auto RTS is disabled */
if (port->rs485.flags & SER_RS485_ENABLED) {
if (rs485->flags & SER_RS485_ENABLED) {
u32 cr = pl011_read(uap, REG_CR);
cr &= ~UART011_CR_RTSEN;

View File

@ -1,35 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef AMBA_PL011_H
#define AMBA_PL011_H
enum {
REG_DR,
REG_ST_DMAWM,
REG_ST_TIMEOUT,
REG_FR,
REG_LCRH_RX,
REG_LCRH_TX,
REG_IBRD,
REG_FBRD,
REG_CR,
REG_IFLS,
REG_IMSC,
REG_RIS,
REG_MIS,
REG_ICR,
REG_DMACR,
REG_ST_XFCR,
REG_ST_XON1,
REG_ST_XON2,
REG_ST_XOFF1,
REG_ST_XOFF2,
REG_ST_ITCR,
REG_ST_ITIP,
REG_ST_ABCR,
REG_ST_ABIMSC,
/* The size of the array - must be last */
REG_ARRAY_SIZE,
};
#endif

View File

@ -299,11 +299,9 @@ static int atmel_config_rs485(struct uart_port *port,
/* Resetting serial mode to RS232 (0x0) */
mode &= ~ATMEL_US_USMODE;
port->rs485 = *rs485conf;
if (rs485conf->flags & SER_RS485_ENABLED) {
dev_dbg(port->dev, "Setting UART to RS485\n");
if (port->rs485.flags & SER_RS485_RX_DURING_TX)
if (rs485conf->flags & SER_RS485_RX_DURING_TX)
atmel_port->tx_done_mask = ATMEL_US_TXRDY;
else
atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;

View File

@ -19,6 +19,8 @@ struct gpio_desc;
#include "cpm_uart_cpm2.h"
#elif defined(CONFIG_CPM1)
#include "cpm_uart_cpm1.h"
#elif defined(CONFIG_COMPILE_TEST)
#include "cpm_uart_cpm2.h"
#endif
#define SERIAL_CPM_MAJOR 204

View File

@ -1247,7 +1247,7 @@ static int cpm_uart_init_port(struct device_node *np,
}
#ifdef CONFIG_PPC_EARLY_DEBUG_CPM
#ifdef CONFIG_CONSOLE_POLL
#if defined(CONFIG_CONSOLE_POLL) && defined(CONFIG_SERIAL_CPM_CONSOLE)
if (!udbg_port)
#endif
udbg_putc = NULL;

View File

@ -25,7 +25,6 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/fs_pd.h>
#include <asm/prom.h>
#include <linux/serial_core.h>
#include <linux/kernel.h>

View File

@ -309,6 +309,8 @@ static void digicolor_uart_set_termios(struct uart_port *port,
case CS8:
default:
config |= UA_CONFIG_CHAR_LEN;
termios->c_cflag &= ~CSIZE;
termios->c_cflag |= CS8;
break;
}

View File

@ -239,8 +239,6 @@
/* IMX lpuart has four extra unused regs located at the beginning */
#define IMX_REG_OFF 0x10
static DEFINE_IDA(fsl_lpuart_ida);
enum lpuart_type {
VF610_LPUART,
LS1021A_LPUART,
@ -276,7 +274,6 @@ struct lpuart_port {
int rx_dma_rng_buf_len;
unsigned int dma_tx_nents;
wait_queue_head_t dma_wait;
bool id_allocated;
};
struct lpuart_soc_data {
@ -1118,7 +1115,7 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
struct dma_chan *chan = sport->dma_rx_chan;
struct circ_buf *ring = &sport->rx_ring;
unsigned long flags;
int count = 0, copied;
int count, copied;
if (lpuart_is_32(sport)) {
unsigned long sr = lpuart32_read(&sport->port, UARTSTAT);
@ -1377,19 +1374,6 @@ static int lpuart_config_rs485(struct uart_port *port,
/* Enable auto RS-485 RTS mode */
modem |= UARTMODEM_TXRTSE;
/*
* RTS needs to be logic HIGH either during transfer _or_ after
* transfer, other variants are not supported by the hardware.
*/
if (!(rs485->flags & (SER_RS485_RTS_ON_SEND |
SER_RS485_RTS_AFTER_SEND)))
rs485->flags |= SER_RS485_RTS_ON_SEND;
if (rs485->flags & SER_RS485_RTS_ON_SEND &&
rs485->flags & SER_RS485_RTS_AFTER_SEND)
rs485->flags &= ~SER_RS485_RTS_AFTER_SEND;
/*
* The hardware defaults to RTS logic HIGH while transfer.
* Switch polarity in case RTS shall be logic HIGH
@ -1402,9 +1386,6 @@ static int lpuart_config_rs485(struct uart_port *port,
modem |= UARTMODEM_TXRTSPOL;
}
/* Store the new configuration */
sport->port.rs485 = *rs485;
writeb(modem, sport->port.membase + UARTMODEM);
return 0;
}
@ -1428,19 +1409,6 @@ static int lpuart32_config_rs485(struct uart_port *port,
/* Enable auto RS-485 RTS mode */
modem |= UARTMODEM_TXRTSE;
/*
* RTS needs to be logic HIGH either during transfer _or_ after
* transfer, other variants are not supported by the hardware.
*/
if (!(rs485->flags & (SER_RS485_RTS_ON_SEND |
SER_RS485_RTS_AFTER_SEND)))
rs485->flags |= SER_RS485_RTS_ON_SEND;
if (rs485->flags & SER_RS485_RTS_ON_SEND &&
rs485->flags & SER_RS485_RTS_AFTER_SEND)
rs485->flags &= ~SER_RS485_RTS_AFTER_SEND;
/*
* The hardware defaults to RTS logic HIGH while transfer.
* Switch polarity in case RTS shall be logic HIGH
@ -1453,9 +1421,6 @@ static int lpuart32_config_rs485(struct uart_port *port,
modem |= UARTMODEM_TXRTSPOL;
}
/* Store the new configuration */
sport->port.rs485 = *rs485;
lpuart32_write(&sport->port, modem, UARTMODIR);
return 0;
}
@ -2145,12 +2110,10 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
if (sport->port.rs485.flags & SER_RS485_ENABLED)
termios->c_cflag &= ~CRTSCTS;
if (termios->c_cflag & CRTSCTS) {
modem |= (UARTMODIR_RXRTSE | UARTMODIR_TXCTSE);
} else {
termios->c_cflag &= ~CRTSCTS;
if (termios->c_cflag & CRTSCTS)
modem |= UARTMODIR_RXRTSE | UARTMODIR_TXCTSE;
else
modem &= ~(UARTMODIR_RXRTSE | UARTMODIR_TXCTSE);
}
if (termios->c_cflag & CSTOPB)
bd |= UARTBAUD_SBNS;
@ -2717,23 +2680,18 @@ static int lpuart_probe(struct platform_device *pdev)
ret = of_alias_get_id(np, "serial");
if (ret < 0) {
ret = ida_simple_get(&fsl_lpuart_ida, 0, UART_NR, GFP_KERNEL);
if (ret < 0) {
dev_err(&pdev->dev, "port line is full, add device failed\n");
return ret;
}
sport->id_allocated = true;
dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
return ret;
}
if (ret >= ARRAY_SIZE(lpuart_ports)) {
dev_err(&pdev->dev, "serial%d out of range\n", ret);
ret = -EINVAL;
goto failed_out_of_range;
return -EINVAL;
}
sport->port.line = ret;
ret = lpuart_enable_clks(sport);
if (ret)
goto failed_clock_enable;
return ret;
sport->port.uartclk = lpuart_get_baud_clk_rate(sport);
lpuart_ports[sport->port.line] = sport;
@ -2781,10 +2739,6 @@ failed_reset:
uart_remove_one_port(&lpuart_reg, &sport->port);
failed_attach_port:
lpuart_disable_clks(sport);
failed_clock_enable:
failed_out_of_range:
if (sport->id_allocated)
ida_simple_remove(&fsl_lpuart_ida, sport->port.line);
return ret;
}
@ -2794,9 +2748,6 @@ static int lpuart_remove(struct platform_device *pdev)
uart_remove_one_port(&lpuart_reg, &sport->port);
if (sport->id_allocated)
ida_simple_remove(&fsl_lpuart_ida, sport->port.line);
lpuart_disable_clks(sport);
if (sport->dma_tx_chan)
@ -2926,7 +2877,6 @@ static int __init lpuart_serial_init(void)
static void __exit lpuart_serial_exit(void)
{
ida_destroy(&fsl_lpuart_ida);
platform_driver_unregister(&lpuart_driver);
uart_unregister_driver(&lpuart_reg);
}

View File

@ -19,6 +19,7 @@
#include <linux/fs.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/serial_reg.h>
#include <linux/major.h>
#include <linux/string.h>
@ -41,15 +42,273 @@
#include <asm/irq.h>
#include <linux/uaccess.h>
#include "icom.h"
/*#define ICOM_TRACE enable port trace capabilities */
#define ICOM_DRIVER_NAME "icom"
#define ICOM_VERSION_STR "1.3.1"
#define NR_PORTS 128
#define ICOM_PORT ((struct icom_port *)port)
#define to_icom_adapter(d) container_of(d, struct icom_adapter, kref)
static const unsigned int icom_acfg_baud[] = {
300,
600,
900,
1200,
1800,
2400,
3600,
4800,
7200,
9600,
14400,
19200,
28800,
38400,
57600,
76800,
115200,
153600,
230400,
307200,
460800,
};
#define BAUD_TABLE_LIMIT (ARRAY_SIZE(icom_acfg_baud) - 1)
struct icom_regs {
u32 control; /* Adapter Control Register */
u32 interrupt; /* Adapter Interrupt Register */
u32 int_mask; /* Adapter Interrupt Mask Reg */
u32 int_pri; /* Adapter Interrupt Priority r */
u32 int_reg_b; /* Adapter non-masked Interrupt */
u32 resvd01;
u32 resvd02;
u32 resvd03;
u32 control_2; /* Adapter Control Register 2 */
u32 interrupt_2; /* Adapter Interrupt Register 2 */
u32 int_mask_2; /* Adapter Interrupt Mask 2 */
u32 int_pri_2; /* Adapter Interrupt Prior 2 */
u32 int_reg_2b; /* Adapter non-masked 2 */
};
struct func_dram {
u32 reserved[108]; /* 0-1B0 reserved by personality code */
u32 RcvStatusAddr; /* 1B0-1B3 Status Address for Next rcv */
u8 RcvStnAddr; /* 1B4 Receive Station Addr */
u8 IdleState; /* 1B5 Idle State */
u8 IdleMonitor; /* 1B6 Idle Monitor */
u8 FlagFillIdleTimer; /* 1B7 Flag Fill Idle Timer */
u32 XmitStatusAddr; /* 1B8-1BB Transmit Status Address */
u8 StartXmitCmd; /* 1BC Start Xmit Command */
u8 HDLCConfigReg; /* 1BD Reserved */
u8 CauseCode; /* 1BE Cause code for fatal error */
u8 xchar; /* 1BF High priority send */
u32 reserved3; /* 1C0-1C3 Reserved */
u8 PrevCmdReg; /* 1C4 Reserved */
u8 CmdReg; /* 1C5 Command Register */
u8 async_config2; /* 1C6 Async Config Byte 2 */
u8 async_config3; /* 1C7 Async Config Byte 3 */
u8 dce_resvd[20]; /* 1C8-1DB DCE Rsvd */
u8 dce_resvd21; /* 1DC DCE Rsvd (21st byte */
u8 misc_flags; /* 1DD misc flags */
#define V2_HARDWARE 0x40
#define ICOM_HDW_ACTIVE 0x01
u8 call_length; /* 1DE Phone #/CFI buff ln */
u8 call_length2; /* 1DF Upper byte (unused) */
u32 call_addr; /* 1E0-1E3 Phn #/CFI buff addr */
u16 timer_value; /* 1E4-1E5 general timer value */
u8 timer_command; /* 1E6 general timer cmd */
u8 dce_command; /* 1E7 dce command reg */
u8 dce_cmd_status; /* 1E8 dce command stat */
u8 x21_r1_ioff; /* 1E9 dce ready counter */
u8 x21_r0_ioff; /* 1EA dce not ready ctr */
u8 x21_ralt_ioff; /* 1EB dce CNR counter */
u8 x21_r1_ion; /* 1EC dce ready I on ctr */
u8 rsvd_ier; /* 1ED Rsvd for IER (if ne */
u8 ier; /* 1EE Interrupt Enable */
u8 isr; /* 1EF Input Signal Reg */
u8 osr; /* 1F0 Output Signal Reg */
u8 reset; /* 1F1 Reset/Reload Reg */
u8 disable; /* 1F2 Disable Reg */
u8 sync; /* 1F3 Sync Reg */
u8 error_stat; /* 1F4 Error Status */
u8 cable_id; /* 1F5 Cable ID */
u8 cs_length; /* 1F6 CS Load Length */
u8 mac_length; /* 1F7 Mac Load Length */
u32 cs_load_addr; /* 1F8-1FB Call Load PCI Addr */
u32 mac_load_addr; /* 1FC-1FF Mac Load PCI Addr */
};
/*
* adapter defines and structures
*/
#define ICOM_CONTROL_START_A 0x00000008
#define ICOM_CONTROL_STOP_A 0x00000004
#define ICOM_CONTROL_START_B 0x00000002
#define ICOM_CONTROL_STOP_B 0x00000001
#define ICOM_CONTROL_START_C 0x00000008
#define ICOM_CONTROL_STOP_C 0x00000004
#define ICOM_CONTROL_START_D 0x00000002
#define ICOM_CONTROL_STOP_D 0x00000001
#define ICOM_IRAM_OFFSET 0x1000
#define ICOM_IRAM_SIZE 0x0C00
#define ICOM_DCE_IRAM_OFFSET 0x0A00
#define ICOM_CABLE_ID_VALID 0x01
#define ICOM_CABLE_ID_MASK 0xF0
#define ICOM_DISABLE 0x80
#define CMD_XMIT_RCV_ENABLE 0xC0
#define CMD_XMIT_ENABLE 0x40
#define CMD_RCV_DISABLE 0x00
#define CMD_RCV_ENABLE 0x80
#define CMD_RESTART 0x01
#define CMD_HOLD_XMIT 0x02
#define CMD_SND_BREAK 0x04
#define RS232_CABLE 0x06
#define V24_CABLE 0x0E
#define V35_CABLE 0x0C
#define V36_CABLE 0x02
#define NO_CABLE 0x00
#define START_DOWNLOAD 0x80
#define ICOM_INT_MASK_PRC_A 0x00003FFF
#define ICOM_INT_MASK_PRC_B 0x3FFF0000
#define ICOM_INT_MASK_PRC_C 0x00003FFF
#define ICOM_INT_MASK_PRC_D 0x3FFF0000
#define INT_RCV_COMPLETED 0x1000
#define INT_XMIT_COMPLETED 0x2000
#define INT_IDLE_DETECT 0x0800
#define INT_RCV_DISABLED 0x0400
#define INT_XMIT_DISABLED 0x0200
#define INT_RCV_XMIT_SHUTDOWN 0x0100
#define INT_FATAL_ERROR 0x0080
#define INT_CABLE_PULL 0x0020
#define INT_SIGNAL_CHANGE 0x0010
#define HDLC_PPP_PURE_ASYNC 0x02
#define HDLC_FF_FILL 0x00
#define HDLC_HDW_FLOW 0x01
#define START_XMIT 0x80
#define ICOM_ACFG_DRIVE1 0x20
#define ICOM_ACFG_NO_PARITY 0x00
#define ICOM_ACFG_PARITY_ENAB 0x02
#define ICOM_ACFG_PARITY_ODD 0x01
#define ICOM_ACFG_8BPC 0x00
#define ICOM_ACFG_7BPC 0x04
#define ICOM_ACFG_6BPC 0x08
#define ICOM_ACFG_5BPC 0x0C
#define ICOM_ACFG_1STOP_BIT 0x00
#define ICOM_ACFG_2STOP_BIT 0x10
#define ICOM_DTR 0x80
#define ICOM_RTS 0x40
#define ICOM_RI 0x08
#define ICOM_DSR 0x80
#define ICOM_DCD 0x20
#define ICOM_CTS 0x40
#define NUM_XBUFFS 1
#define NUM_RBUFFS 2
#define RCV_BUFF_SZ 0x0200
#define XMIT_BUFF_SZ 0x1000
struct statusArea {
/**********************************************/
/* Transmit Status Area */
/**********************************************/
struct xmit_status_area{
__le32 leNext; /* Next entry in Little Endian on Adapter */
__le32 leNextASD;
__le32 leBuffer; /* Buffer for entry in LE for Adapter */
__le16 leLengthASD;
__le16 leOffsetASD;
__le16 leLength; /* Length of data in segment */
__le16 flags;
#define SA_FLAGS_DONE 0x0080 /* Done with Segment */
#define SA_FLAGS_CONTINUED 0x8000 /* More Segments */
#define SA_FLAGS_IDLE 0x4000 /* Mark IDLE after frm */
#define SA_FLAGS_READY_TO_XMIT 0x0800
#define SA_FLAGS_STAT_MASK 0x007F
} xmit[NUM_XBUFFS];
/**********************************************/
/* Receive Status Area */
/**********************************************/
struct {
__le32 leNext; /* Next entry in Little Endian on Adapter */
__le32 leNextASD;
__le32 leBuffer; /* Buffer for entry in LE for Adapter */
__le16 WorkingLength; /* size of segment */
__le16 reserv01;
__le16 leLength; /* Length of data in segment */
__le16 flags;
#define SA_FL_RCV_DONE 0x0010 /* Data ready */
#define SA_FLAGS_OVERRUN 0x0040
#define SA_FLAGS_PARITY_ERROR 0x0080
#define SA_FLAGS_FRAME_ERROR 0x0001
#define SA_FLAGS_FRAME_TRUNC 0x0002
#define SA_FLAGS_BREAK_DET 0x0004 /* set conditionally by device driver, not hardware */
#define SA_FLAGS_RCV_MASK 0xFFE6
} rcv[NUM_RBUFFS];
};
struct icom_adapter;
#define ICOM_MAJOR 243
#define ICOM_MINOR_START 0
struct icom_port {
struct uart_port uart_port;
unsigned char cable_id;
unsigned char read_status_mask;
unsigned char ignore_status_mask;
void __iomem * int_reg;
struct icom_regs __iomem *global_reg;
struct func_dram __iomem *dram;
int port;
struct statusArea *statStg;
dma_addr_t statStg_pci;
__le32 *xmitRestart;
dma_addr_t xmitRestart_pci;
unsigned char *xmit_buf;
dma_addr_t xmit_buf_pci;
unsigned char *recv_buf;
dma_addr_t recv_buf_pci;
int next_rcv;
int status;
#define ICOM_PORT_ACTIVE 1 /* Port exists. */
#define ICOM_PORT_OFF 0 /* Port does not exist. */
struct icom_adapter *adapter;
};
struct icom_adapter {
void __iomem * base_addr;
unsigned long base_addr_pci;
struct pci_dev *pci_dev;
struct icom_port port_info[4];
int index;
int version;
#define ADAPTER_V1 0x0001
#define ADAPTER_V2 0x0002
u32 subsystem_id;
#define FOUR_PORT_MODEL 0x0252
#define V2_TWO_PORTS_RVX 0x021A
#define V2_ONE_PORT_RVX_ONE_PORT_IMBED_MDM 0x0251
int numb_ports;
struct list_head icom_adapter_entry;
struct kref kref;
};
/* prototype */
extern void iCom_sercons_init(void);
struct lookup_proc_table {
u32 __iomem *global_control_reg;
unsigned long processor_id;
};
struct lookup_int_table {
u32 __iomem *global_int_mask;
unsigned long processor_id;
};
static inline struct icom_port *to_icom_port(struct uart_port *port)
{
return container_of(port, struct icom_port, uart_port);
}
static const struct pci_device_id icom_pci_table[] = {
{
@ -222,7 +481,7 @@ static int get_port_memory(struct icom_port *icom_port)
if (index < (NUM_XBUFFS - 1)) {
memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area));
icom_port->statStg->xmit[index].leLengthASD =
(unsigned short int) cpu_to_le16(XMIT_BUFF_SZ);
cpu_to_le16(XMIT_BUFF_SZ);
trace(icom_port, "FOD_ADDR", stgAddr);
trace(icom_port, "FOD_XBUFF",
(unsigned long) icom_port->xmit_buf);
@ -231,7 +490,7 @@ static int get_port_memory(struct icom_port *icom_port)
} else if (index == (NUM_XBUFFS - 1)) {
memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area));
icom_port->statStg->xmit[index].leLengthASD =
(unsigned short int) cpu_to_le16(XMIT_BUFF_SZ);
cpu_to_le16(XMIT_BUFF_SZ);
trace(icom_port, "FOD_XBUFF",
(unsigned long) icom_port->xmit_buf);
icom_port->statStg->xmit[index].leBuffer =
@ -249,7 +508,7 @@ static int get_port_memory(struct icom_port *icom_port)
stgAddr = stgAddr + sizeof(icom_port->statStg->rcv[0]);
icom_port->statStg->rcv[index].leLength = 0;
icom_port->statStg->rcv[index].WorkingLength =
(unsigned short int) cpu_to_le16(RCV_BUFF_SZ);
cpu_to_le16(RCV_BUFF_SZ);
if (index < (NUM_RBUFFS - 1) ) {
offset = stgAddr - (unsigned long) icom_port->statStg;
icom_port->statStg->rcv[index].leNext =
@ -617,16 +876,17 @@ unlock:
static int icom_write(struct uart_port *port)
{
struct icom_port *icom_port = to_icom_port(port);
unsigned long data_count;
unsigned char cmdReg;
unsigned long offset;
int temp_tail = port->state->xmit.tail;
trace(ICOM_PORT, "WRITE", 0);
trace(icom_port, "WRITE", 0);
if (cpu_to_le16(ICOM_PORT->statStg->xmit[0].flags) &
if (le16_to_cpu(icom_port->statStg->xmit[0].flags) &
SA_FLAGS_READY_TO_XMIT) {
trace(ICOM_PORT, "WRITE_FULL", 0);
trace(icom_port, "WRITE_FULL", 0);
return 0;
}
@ -634,7 +894,7 @@ static int icom_write(struct uart_port *port)
while ((port->state->xmit.head != temp_tail) &&
(data_count <= XMIT_BUFF_SZ)) {
ICOM_PORT->xmit_buf[data_count++] =
icom_port->xmit_buf[data_count++] =
port->state->xmit.buf[temp_tail];
temp_tail++;
@ -642,22 +902,22 @@ static int icom_write(struct uart_port *port)
}
if (data_count) {
ICOM_PORT->statStg->xmit[0].flags =
icom_port->statStg->xmit[0].flags =
cpu_to_le16(SA_FLAGS_READY_TO_XMIT);
ICOM_PORT->statStg->xmit[0].leLength =
icom_port->statStg->xmit[0].leLength =
cpu_to_le16(data_count);
offset =
(unsigned long) &ICOM_PORT->statStg->xmit[0] -
(unsigned long) ICOM_PORT->statStg;
*ICOM_PORT->xmitRestart =
cpu_to_le32(ICOM_PORT->statStg_pci + offset);
cmdReg = readb(&ICOM_PORT->dram->CmdReg);
(unsigned long) &icom_port->statStg->xmit[0] -
(unsigned long) icom_port->statStg;
*icom_port->xmitRestart =
cpu_to_le32(icom_port->statStg_pci + offset);
cmdReg = readb(&icom_port->dram->CmdReg);
writeb(cmdReg | CMD_XMIT_RCV_ENABLE,
&ICOM_PORT->dram->CmdReg);
writeb(START_XMIT, &ICOM_PORT->dram->StartXmitCmd);
trace(ICOM_PORT, "WRITE_START", data_count);
&icom_port->dram->CmdReg);
writeb(START_XMIT, &icom_port->dram->StartXmitCmd);
trace(icom_port, "WRITE_START", data_count);
/* write flush */
readb(&ICOM_PORT->dram->StartXmitCmd);
readb(&icom_port->dram->StartXmitCmd);
}
return data_count;
@ -696,8 +956,7 @@ static inline void check_modem_status(struct icom_port *icom_port)
static void xmit_interrupt(u16 port_int_reg, struct icom_port *icom_port)
{
unsigned short int count;
int i;
u16 count, i;
if (port_int_reg & (INT_XMIT_COMPLETED)) {
trace(icom_port, "XMIT_COMPLETE", 0);
@ -706,8 +965,7 @@ static void xmit_interrupt(u16 port_int_reg, struct icom_port *icom_port)
icom_port->statStg->xmit[0].flags &=
cpu_to_le16(~SA_FLAGS_READY_TO_XMIT);
count = (unsigned short int)
cpu_to_le16(icom_port->statStg->xmit[0].leLength);
count = le16_to_cpu(icom_port->statStg->xmit[0].leLength);
icom_port->uart_port.icount.tx += count;
for (i=0; i<count &&
@ -729,7 +987,7 @@ static void recv_interrupt(u16 port_int_reg, struct icom_port *icom_port)
{
short int count, rcv_buff;
struct tty_port *port = &icom_port->uart_port.state->port;
unsigned short int status;
u16 status;
struct uart_icount *icount;
unsigned long offset;
unsigned char flag;
@ -737,19 +995,18 @@ static void recv_interrupt(u16 port_int_reg, struct icom_port *icom_port)
trace(icom_port, "RCV_COMPLETE", 0);
rcv_buff = icom_port->next_rcv;
status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags);
status = le16_to_cpu(icom_port->statStg->rcv[rcv_buff].flags);
while (status & SA_FL_RCV_DONE) {
int first = -1;
trace(icom_port, "FID_STATUS", status);
count = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].leLength);
count = le16_to_cpu(icom_port->statStg->rcv[rcv_buff].leLength);
trace(icom_port, "RCV_COUNT", count);
trace(icom_port, "REAL_COUNT", count);
offset =
cpu_to_le32(icom_port->statStg->rcv[rcv_buff].leBuffer) -
offset = le32_to_cpu(icom_port->statStg->rcv[rcv_buff].leBuffer) -
icom_port->recv_buf_pci;
/* Block copy all but the last byte as this may have status */
@ -819,13 +1076,13 @@ ignore_char:
icom_port->statStg->rcv[rcv_buff].flags = 0;
icom_port->statStg->rcv[rcv_buff].leLength = 0;
icom_port->statStg->rcv[rcv_buff].WorkingLength =
(unsigned short int) cpu_to_le16(RCV_BUFF_SZ);
cpu_to_le16(RCV_BUFF_SZ);
rcv_buff++;
if (rcv_buff == NUM_RBUFFS)
rcv_buff = 0;
status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags);
status = le16_to_cpu(icom_port->statStg->rcv[rcv_buff].flags);
}
icom_port->next_rcv = rcv_buff;
@ -925,11 +1182,12 @@ static irqreturn_t icom_interrupt(int irq, void *dev_id)
*/
static unsigned int icom_tx_empty(struct uart_port *port)
{
struct icom_port *icom_port = to_icom_port(port);
int ret;
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
if (cpu_to_le16(ICOM_PORT->statStg->xmit[0].flags) &
if (le16_to_cpu(icom_port->statStg->xmit[0].flags) &
SA_FLAGS_READY_TO_XMIT)
ret = TIOCSER_TEMT;
else
@ -941,38 +1199,40 @@ static unsigned int icom_tx_empty(struct uart_port *port)
static void icom_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct icom_port *icom_port = to_icom_port(port);
unsigned char local_osr;
trace(ICOM_PORT, "SET_MODEM", 0);
local_osr = readb(&ICOM_PORT->dram->osr);
trace(icom_port, "SET_MODEM", 0);
local_osr = readb(&icom_port->dram->osr);
if (mctrl & TIOCM_RTS) {
trace(ICOM_PORT, "RAISE_RTS", 0);
trace(icom_port, "RAISE_RTS", 0);
local_osr |= ICOM_RTS;
} else {
trace(ICOM_PORT, "LOWER_RTS", 0);
trace(icom_port, "LOWER_RTS", 0);
local_osr &= ~ICOM_RTS;
}
if (mctrl & TIOCM_DTR) {
trace(ICOM_PORT, "RAISE_DTR", 0);
trace(icom_port, "RAISE_DTR", 0);
local_osr |= ICOM_DTR;
} else {
trace(ICOM_PORT, "LOWER_DTR", 0);
trace(icom_port, "LOWER_DTR", 0);
local_osr &= ~ICOM_DTR;
}
writeb(local_osr, &ICOM_PORT->dram->osr);
writeb(local_osr, &icom_port->dram->osr);
}
static unsigned int icom_get_mctrl(struct uart_port *port)
{
struct icom_port *icom_port = to_icom_port(port);
unsigned char status;
unsigned int result;
trace(ICOM_PORT, "GET_MODEM", 0);
trace(icom_port, "GET_MODEM", 0);
status = readb(&ICOM_PORT->dram->isr);
status = readb(&icom_port->dram->isr);
result = ((status & ICOM_DCD) ? TIOCM_CAR : 0)
| ((status & ICOM_RI) ? TIOCM_RNG : 0)
@ -983,44 +1243,47 @@ static unsigned int icom_get_mctrl(struct uart_port *port)
static void icom_stop_tx(struct uart_port *port)
{
struct icom_port *icom_port = to_icom_port(port);
unsigned char cmdReg;
trace(ICOM_PORT, "STOP", 0);
cmdReg = readb(&ICOM_PORT->dram->CmdReg);
writeb(cmdReg | CMD_HOLD_XMIT, &ICOM_PORT->dram->CmdReg);
trace(icom_port, "STOP", 0);
cmdReg = readb(&icom_port->dram->CmdReg);
writeb(cmdReg | CMD_HOLD_XMIT, &icom_port->dram->CmdReg);
}
static void icom_start_tx(struct uart_port *port)
{
struct icom_port *icom_port = to_icom_port(port);
unsigned char cmdReg;
trace(ICOM_PORT, "START", 0);
cmdReg = readb(&ICOM_PORT->dram->CmdReg);
trace(icom_port, "START", 0);
cmdReg = readb(&icom_port->dram->CmdReg);
if ((cmdReg & CMD_HOLD_XMIT) == CMD_HOLD_XMIT)
writeb(cmdReg & ~CMD_HOLD_XMIT,
&ICOM_PORT->dram->CmdReg);
&icom_port->dram->CmdReg);
icom_write(port);
}
static void icom_send_xchar(struct uart_port *port, char ch)
{
struct icom_port *icom_port = to_icom_port(port);
unsigned char xdata;
int index;
unsigned long flags;
trace(ICOM_PORT, "SEND_XCHAR", ch);
trace(icom_port, "SEND_XCHAR", ch);
/* wait .1 sec to send char */
for (index = 0; index < 10; index++) {
spin_lock_irqsave(&port->lock, flags);
xdata = readb(&ICOM_PORT->dram->xchar);
xdata = readb(&icom_port->dram->xchar);
if (xdata == 0x00) {
trace(ICOM_PORT, "QUICK_WRITE", 0);
writeb(ch, &ICOM_PORT->dram->xchar);
trace(icom_port, "QUICK_WRITE", 0);
writeb(ch, &icom_port->dram->xchar);
/* flush write operation */
xdata = readb(&ICOM_PORT->dram->xchar);
xdata = readb(&icom_port->dram->xchar);
spin_unlock_irqrestore(&port->lock, flags);
break;
}
@ -1031,38 +1294,41 @@ static void icom_send_xchar(struct uart_port *port, char ch)
static void icom_stop_rx(struct uart_port *port)
{
struct icom_port *icom_port = to_icom_port(port);
unsigned char cmdReg;
cmdReg = readb(&ICOM_PORT->dram->CmdReg);
writeb(cmdReg & ~CMD_RCV_ENABLE, &ICOM_PORT->dram->CmdReg);
cmdReg = readb(&icom_port->dram->CmdReg);
writeb(cmdReg & ~CMD_RCV_ENABLE, &icom_port->dram->CmdReg);
}
static void icom_break(struct uart_port *port, int break_state)
{
struct icom_port *icom_port = to_icom_port(port);
unsigned char cmdReg;
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
trace(ICOM_PORT, "BREAK", 0);
cmdReg = readb(&ICOM_PORT->dram->CmdReg);
trace(icom_port, "BREAK", 0);
cmdReg = readb(&icom_port->dram->CmdReg);
if (break_state == -1) {
writeb(cmdReg | CMD_SND_BREAK, &ICOM_PORT->dram->CmdReg);
writeb(cmdReg | CMD_SND_BREAK, &icom_port->dram->CmdReg);
} else {
writeb(cmdReg & ~CMD_SND_BREAK, &ICOM_PORT->dram->CmdReg);
writeb(cmdReg & ~CMD_SND_BREAK, &icom_port->dram->CmdReg);
}
spin_unlock_irqrestore(&port->lock, flags);
}
static int icom_open(struct uart_port *port)
{
struct icom_port *icom_port = to_icom_port(port);
int retval;
kref_get(&ICOM_PORT->adapter->kref);
retval = startup(ICOM_PORT);
kref_get(&icom_port->adapter->kref);
retval = startup(icom_port);
if (retval) {
kref_put(&ICOM_PORT->adapter->kref, icom_kref_release);
trace(ICOM_PORT, "STARTUP_ERROR", 0);
kref_put(&icom_port->adapter->kref, icom_kref_release);
trace(icom_port, "STARTUP_ERROR", 0);
return retval;
}
@ -1071,23 +1337,25 @@ static int icom_open(struct uart_port *port)
static void icom_close(struct uart_port *port)
{
struct icom_port *icom_port = to_icom_port(port);
unsigned char cmdReg;
trace(ICOM_PORT, "CLOSE", 0);
trace(icom_port, "CLOSE", 0);
/* stop receiver */
cmdReg = readb(&ICOM_PORT->dram->CmdReg);
writeb(cmdReg & ~CMD_RCV_ENABLE, &ICOM_PORT->dram->CmdReg);
cmdReg = readb(&icom_port->dram->CmdReg);
writeb(cmdReg & ~CMD_RCV_ENABLE, &icom_port->dram->CmdReg);
shutdown(ICOM_PORT);
shutdown(icom_port);
kref_put(&ICOM_PORT->adapter->kref, icom_kref_release);
kref_put(&icom_port->adapter->kref, icom_kref_release);
}
static void icom_set_termios(struct uart_port *port,
struct ktermios *termios,
struct ktermios *old_termios)
{
struct icom_port *icom_port = to_icom_port(port);
int baud;
unsigned cflag, iflag;
char new_config2;
@ -1099,7 +1367,7 @@ static void icom_set_termios(struct uart_port *port,
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
trace(ICOM_PORT, "CHANGE_SPEED", 0);
trace(icom_port, "CHANGE_SPEED", 0);
cflag = termios->c_cflag;
iflag = termios->c_iflag;
@ -1130,12 +1398,12 @@ static void icom_set_termios(struct uart_port *port,
if (cflag & PARENB) {
/* parity bit enabled */
new_config2 |= ICOM_ACFG_PARITY_ENAB;
trace(ICOM_PORT, "PARENB", 0);
trace(icom_port, "PARENB", 0);
}
if (cflag & PARODD) {
/* odd parity */
new_config2 |= ICOM_ACFG_PARITY_ODD;
trace(ICOM_PORT, "PARODD", 0);
trace(icom_port, "PARODD", 0);
}
/* Determine divisor based on baud rate */
@ -1155,100 +1423,99 @@ static void icom_set_termios(struct uart_port *port,
uart_update_timeout(port, cflag, baud);
/* CTS flow control flag and modem status interrupts */
tmp_byte = readb(&(ICOM_PORT->dram->HDLCConfigReg));
tmp_byte = readb(&(icom_port->dram->HDLCConfigReg));
if (cflag & CRTSCTS)
tmp_byte |= HDLC_HDW_FLOW;
else
tmp_byte &= ~HDLC_HDW_FLOW;
writeb(tmp_byte, &(ICOM_PORT->dram->HDLCConfigReg));
writeb(tmp_byte, &(icom_port->dram->HDLCConfigReg));
/*
* Set up parity check flag
*/
ICOM_PORT->read_status_mask = SA_FLAGS_OVERRUN | SA_FL_RCV_DONE;
icom_port->read_status_mask = SA_FLAGS_OVERRUN | SA_FL_RCV_DONE;
if (iflag & INPCK)
ICOM_PORT->read_status_mask |=
icom_port->read_status_mask |=
SA_FLAGS_FRAME_ERROR | SA_FLAGS_PARITY_ERROR;
if ((iflag & BRKINT) || (iflag & PARMRK))
ICOM_PORT->read_status_mask |= SA_FLAGS_BREAK_DET;
icom_port->read_status_mask |= SA_FLAGS_BREAK_DET;
/*
* Characters to ignore
*/
ICOM_PORT->ignore_status_mask = 0;
icom_port->ignore_status_mask = 0;
if (iflag & IGNPAR)
ICOM_PORT->ignore_status_mask |=
icom_port->ignore_status_mask |=
SA_FLAGS_PARITY_ERROR | SA_FLAGS_FRAME_ERROR;
if (iflag & IGNBRK) {
ICOM_PORT->ignore_status_mask |= SA_FLAGS_BREAK_DET;
icom_port->ignore_status_mask |= SA_FLAGS_BREAK_DET;
/*
* If we're ignore parity and break indicators, ignore
* overruns too. (For real raw support).
*/
if (iflag & IGNPAR)
ICOM_PORT->ignore_status_mask |= SA_FLAGS_OVERRUN;
icom_port->ignore_status_mask |= SA_FLAGS_OVERRUN;
}
/*
* !!! ignore all characters if CREAD is not set
*/
if ((cflag & CREAD) == 0)
ICOM_PORT->ignore_status_mask |= SA_FL_RCV_DONE;
icom_port->ignore_status_mask |= SA_FL_RCV_DONE;
/* Turn off Receiver to prepare for reset */
writeb(CMD_RCV_DISABLE, &ICOM_PORT->dram->CmdReg);
writeb(CMD_RCV_DISABLE, &icom_port->dram->CmdReg);
for (index = 0; index < 10; index++) {
if (readb(&ICOM_PORT->dram->PrevCmdReg) == 0x00) {
if (readb(&icom_port->dram->PrevCmdReg) == 0x00) {
break;
}
}
/* clear all current buffers of data */
for (rcv_buff = 0; rcv_buff < NUM_RBUFFS; rcv_buff++) {
ICOM_PORT->statStg->rcv[rcv_buff].flags = 0;
ICOM_PORT->statStg->rcv[rcv_buff].leLength = 0;
ICOM_PORT->statStg->rcv[rcv_buff].WorkingLength =
(unsigned short int) cpu_to_le16(RCV_BUFF_SZ);
icom_port->statStg->rcv[rcv_buff].flags = 0;
icom_port->statStg->rcv[rcv_buff].leLength = 0;
icom_port->statStg->rcv[rcv_buff].WorkingLength =
cpu_to_le16(RCV_BUFF_SZ);
}
for (xmit_buff = 0; xmit_buff < NUM_XBUFFS; xmit_buff++) {
ICOM_PORT->statStg->xmit[xmit_buff].flags = 0;
icom_port->statStg->xmit[xmit_buff].flags = 0;
}
/* activate changes and start xmit and receiver here */
/* Enable the receiver */
writeb(new_config3, &(ICOM_PORT->dram->async_config3));
writeb(new_config2, &(ICOM_PORT->dram->async_config2));
tmp_byte = readb(&(ICOM_PORT->dram->HDLCConfigReg));
writeb(new_config3, &(icom_port->dram->async_config3));
writeb(new_config2, &(icom_port->dram->async_config2));
tmp_byte = readb(&(icom_port->dram->HDLCConfigReg));
tmp_byte |= HDLC_PPP_PURE_ASYNC | HDLC_FF_FILL;
writeb(tmp_byte, &(ICOM_PORT->dram->HDLCConfigReg));
writeb(0x04, &(ICOM_PORT->dram->FlagFillIdleTimer)); /* 0.5 seconds */
writeb(0xFF, &(ICOM_PORT->dram->ier)); /* enable modem signal interrupts */
writeb(tmp_byte, &(icom_port->dram->HDLCConfigReg));
writeb(0x04, &(icom_port->dram->FlagFillIdleTimer)); /* 0.5 seconds */
writeb(0xFF, &(icom_port->dram->ier)); /* enable modem signal interrupts */
/* reset processor */
writeb(CMD_RESTART, &ICOM_PORT->dram->CmdReg);
writeb(CMD_RESTART, &icom_port->dram->CmdReg);
for (index = 0; index < 10; index++) {
if (readb(&ICOM_PORT->dram->CmdReg) == 0x00) {
if (readb(&icom_port->dram->CmdReg) == 0x00) {
break;
}
}
/* Enable Transmitter and Receiver */
offset =
(unsigned long) &ICOM_PORT->statStg->rcv[0] -
(unsigned long) ICOM_PORT->statStg;
writel(ICOM_PORT->statStg_pci + offset,
&ICOM_PORT->dram->RcvStatusAddr);
ICOM_PORT->next_rcv = 0;
ICOM_PORT->put_length = 0;
*ICOM_PORT->xmitRestart = 0;
writel(ICOM_PORT->xmitRestart_pci,
&ICOM_PORT->dram->XmitStatusAddr);
trace(ICOM_PORT, "XR_ENAB", 0);
writeb(CMD_XMIT_RCV_ENABLE, &ICOM_PORT->dram->CmdReg);
(unsigned long) &icom_port->statStg->rcv[0] -
(unsigned long) icom_port->statStg;
writel(icom_port->statStg_pci + offset,
&icom_port->dram->RcvStatusAddr);
icom_port->next_rcv = 0;
*icom_port->xmitRestart = 0;
writel(icom_port->xmitRestart_pci,
&icom_port->dram->XmitStatusAddr);
trace(icom_port, "XR_ENAB", 0);
writeb(CMD_XMIT_RCV_ENABLE, &icom_port->dram->CmdReg);
spin_unlock_irqrestore(&port->lock, flags);
}
@ -1258,15 +1525,6 @@ static const char *icom_type(struct uart_port *port)
return "icom";
}
static void icom_release_port(struct uart_port *port)
{
}
static int icom_request_port(struct uart_port *port)
{
return 0;
}
static void icom_config_port(struct uart_port *port, int flags)
{
port->type = PORT_ICOM;
@ -1285,8 +1543,6 @@ static const struct uart_ops icom_ops = {
.shutdown = icom_close,
.set_termios = icom_set_termios,
.type = icom_type,
.release_port = icom_release_port,
.request_port = icom_request_port,
.config_port = icom_config_port,
};
@ -1315,7 +1571,6 @@ static int icom_init_ports(struct icom_adapter *icom_adapter)
icom_port = &icom_adapter->port_info[i];
icom_port->port = i;
icom_port->status = ICOM_PORT_ACTIVE;
icom_port->imbed_modem = ICOM_UNKNOWN;
}
} else {
if (subsystem_id == PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL) {
@ -1326,26 +1581,15 @@ static int icom_init_ports(struct icom_adapter *icom_adapter)
icom_port->port = i;
icom_port->status = ICOM_PORT_ACTIVE;
icom_port->imbed_modem = ICOM_IMBED_MODEM;
}
} else {
icom_adapter->numb_ports = 4;
icom_adapter->port_info[0].port = 0;
icom_adapter->port_info[0].status = ICOM_PORT_ACTIVE;
if (subsystem_id ==
PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM) {
icom_adapter->port_info[0].imbed_modem = ICOM_IMBED_MODEM;
} else {
icom_adapter->port_info[0].imbed_modem = ICOM_RVX;
}
icom_adapter->port_info[1].status = ICOM_PORT_OFF;
icom_adapter->port_info[2].port = 2;
icom_adapter->port_info[2].status = ICOM_PORT_ACTIVE;
icom_adapter->port_info[2].imbed_modem = ICOM_RVX;
icom_adapter->port_info[3].status = ICOM_PORT_OFF;
}
}
@ -1401,7 +1645,6 @@ static int icom_alloc_adapter(struct icom_adapter
int adapter_count = 0;
struct icom_adapter *icom_adapter;
struct icom_adapter *cur_adapter_entry;
struct list_head *tmp;
icom_adapter = kzalloc(sizeof(struct icom_adapter), GFP_KERNEL);
@ -1409,10 +1652,8 @@ static int icom_alloc_adapter(struct icom_adapter
return -ENOMEM;
}
list_for_each(tmp, &icom_adapter_head) {
cur_adapter_entry =
list_entry(tmp, struct icom_adapter,
icom_adapter_entry);
list_for_each_entry(cur_adapter_entry, &icom_adapter_head,
icom_adapter_entry) {
if (cur_adapter_entry->index != adapter_count) {
break;
}
@ -1420,7 +1661,8 @@ static int icom_alloc_adapter(struct icom_adapter
}
icom_adapter->index = adapter_count;
list_add_tail(&icom_adapter->icom_adapter_entry, tmp);
list_add_tail(&icom_adapter->icom_adapter_entry,
&cur_adapter_entry->icom_adapter_entry);
*icom_adapter_ref = icom_adapter;
return 0;
@ -1432,8 +1674,10 @@ static void icom_free_adapter(struct icom_adapter *icom_adapter)
kfree(icom_adapter);
}
static void icom_remove_adapter(struct icom_adapter *icom_adapter)
static void icom_kref_release(struct kref *kref)
{
struct icom_adapter *icom_adapter = container_of(kref,
struct icom_adapter, kref);
struct icom_port *icom_port;
int index;
@ -1466,14 +1710,6 @@ static void icom_remove_adapter(struct icom_adapter *icom_adapter)
icom_free_adapter(icom_adapter);
}
static void icom_kref_release(struct kref *kref)
{
struct icom_adapter *icom_adapter;
icom_adapter = to_icom_adapter(kref);
icom_remove_adapter(icom_adapter);
}
static int icom_probe(struct pci_dev *dev,
const struct pci_device_id *ent)
{
@ -1501,7 +1737,7 @@ static int icom_probe(struct pci_dev *dev,
retval = pci_read_config_dword(dev, PCI_COMMAND, &command_reg);
if (retval) {
dev_err(&dev->dev, "PCI Config read FAILED\n");
return retval;
goto probe_exit0;
}
pci_write_config_dword(dev, PCI_COMMAND,
@ -1589,11 +1825,9 @@ probe_exit0:
static void icom_remove(struct pci_dev *dev)
{
struct icom_adapter *icom_adapter;
struct list_head *tmp;
list_for_each(tmp, &icom_adapter_head) {
icom_adapter = list_entry(tmp, struct icom_adapter,
icom_adapter_entry);
list_for_each_entry(icom_adapter, &icom_adapter_head,
icom_adapter_entry) {
if (icom_adapter->pci_dev == dev) {
kref_put(&icom_adapter->kref, icom_kref_release);
return;

View File

@ -1,274 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* icom.h
*
* Copyright (C) 2001 Michael Anderson, IBM Corporation
*
* Serial device driver include file.
*/
#include <linux/serial_core.h>
#define BAUD_TABLE_LIMIT ((sizeof(icom_acfg_baud)/sizeof(int)) - 1)
static int icom_acfg_baud[] = {
300,
600,
900,
1200,
1800,
2400,
3600,
4800,
7200,
9600,
14400,
19200,
28800,
38400,
57600,
76800,
115200,
153600,
230400,
307200,
460800,
};
struct icom_regs {
u32 control; /* Adapter Control Register */
u32 interrupt; /* Adapter Interrupt Register */
u32 int_mask; /* Adapter Interrupt Mask Reg */
u32 int_pri; /* Adapter Interrupt Priority r */
u32 int_reg_b; /* Adapter non-masked Interrupt */
u32 resvd01;
u32 resvd02;
u32 resvd03;
u32 control_2; /* Adapter Control Register 2 */
u32 interrupt_2; /* Adapter Interrupt Register 2 */
u32 int_mask_2; /* Adapter Interrupt Mask 2 */
u32 int_pri_2; /* Adapter Interrupt Prior 2 */
u32 int_reg_2b; /* Adapter non-masked 2 */
};
struct func_dram {
u32 reserved[108]; /* 0-1B0 reserved by personality code */
u32 RcvStatusAddr; /* 1B0-1B3 Status Address for Next rcv */
u8 RcvStnAddr; /* 1B4 Receive Station Addr */
u8 IdleState; /* 1B5 Idle State */
u8 IdleMonitor; /* 1B6 Idle Monitor */
u8 FlagFillIdleTimer; /* 1B7 Flag Fill Idle Timer */
u32 XmitStatusAddr; /* 1B8-1BB Transmit Status Address */
u8 StartXmitCmd; /* 1BC Start Xmit Command */
u8 HDLCConfigReg; /* 1BD Reserved */
u8 CauseCode; /* 1BE Cause code for fatal error */
u8 xchar; /* 1BF High priority send */
u32 reserved3; /* 1C0-1C3 Reserved */
u8 PrevCmdReg; /* 1C4 Reserved */
u8 CmdReg; /* 1C5 Command Register */
u8 async_config2; /* 1C6 Async Config Byte 2 */
u8 async_config3; /* 1C7 Async Config Byte 3 */
u8 dce_resvd[20]; /* 1C8-1DB DCE Rsvd */
u8 dce_resvd21; /* 1DC DCE Rsvd (21st byte */
u8 misc_flags; /* 1DD misc flags */
#define V2_HARDWARE 0x40
#define ICOM_HDW_ACTIVE 0x01
u8 call_length; /* 1DE Phone #/CFI buff ln */
u8 call_length2; /* 1DF Upper byte (unused) */
u32 call_addr; /* 1E0-1E3 Phn #/CFI buff addr */
u16 timer_value; /* 1E4-1E5 general timer value */
u8 timer_command; /* 1E6 general timer cmd */
u8 dce_command; /* 1E7 dce command reg */
u8 dce_cmd_status; /* 1E8 dce command stat */
u8 x21_r1_ioff; /* 1E9 dce ready counter */
u8 x21_r0_ioff; /* 1EA dce not ready ctr */
u8 x21_ralt_ioff; /* 1EB dce CNR counter */
u8 x21_r1_ion; /* 1EC dce ready I on ctr */
u8 rsvd_ier; /* 1ED Rsvd for IER (if ne */
u8 ier; /* 1EE Interrupt Enable */
u8 isr; /* 1EF Input Signal Reg */
u8 osr; /* 1F0 Output Signal Reg */
u8 reset; /* 1F1 Reset/Reload Reg */
u8 disable; /* 1F2 Disable Reg */
u8 sync; /* 1F3 Sync Reg */
u8 error_stat; /* 1F4 Error Status */
u8 cable_id; /* 1F5 Cable ID */
u8 cs_length; /* 1F6 CS Load Length */
u8 mac_length; /* 1F7 Mac Load Length */
u32 cs_load_addr; /* 1F8-1FB Call Load PCI Addr */
u32 mac_load_addr; /* 1FC-1FF Mac Load PCI Addr */
};
/*
* adapter defines and structures
*/
#define ICOM_CONTROL_START_A 0x00000008
#define ICOM_CONTROL_STOP_A 0x00000004
#define ICOM_CONTROL_START_B 0x00000002
#define ICOM_CONTROL_STOP_B 0x00000001
#define ICOM_CONTROL_START_C 0x00000008
#define ICOM_CONTROL_STOP_C 0x00000004
#define ICOM_CONTROL_START_D 0x00000002
#define ICOM_CONTROL_STOP_D 0x00000001
#define ICOM_IRAM_OFFSET 0x1000
#define ICOM_IRAM_SIZE 0x0C00
#define ICOM_DCE_IRAM_OFFSET 0x0A00
#define ICOM_CABLE_ID_VALID 0x01
#define ICOM_CABLE_ID_MASK 0xF0
#define ICOM_DISABLE 0x80
#define CMD_XMIT_RCV_ENABLE 0xC0
#define CMD_XMIT_ENABLE 0x40
#define CMD_RCV_DISABLE 0x00
#define CMD_RCV_ENABLE 0x80
#define CMD_RESTART 0x01
#define CMD_HOLD_XMIT 0x02
#define CMD_SND_BREAK 0x04
#define RS232_CABLE 0x06
#define V24_CABLE 0x0E
#define V35_CABLE 0x0C
#define V36_CABLE 0x02
#define NO_CABLE 0x00
#define START_DOWNLOAD 0x80
#define ICOM_INT_MASK_PRC_A 0x00003FFF
#define ICOM_INT_MASK_PRC_B 0x3FFF0000
#define ICOM_INT_MASK_PRC_C 0x00003FFF
#define ICOM_INT_MASK_PRC_D 0x3FFF0000
#define INT_RCV_COMPLETED 0x1000
#define INT_XMIT_COMPLETED 0x2000
#define INT_IDLE_DETECT 0x0800
#define INT_RCV_DISABLED 0x0400
#define INT_XMIT_DISABLED 0x0200
#define INT_RCV_XMIT_SHUTDOWN 0x0100
#define INT_FATAL_ERROR 0x0080
#define INT_CABLE_PULL 0x0020
#define INT_SIGNAL_CHANGE 0x0010
#define HDLC_PPP_PURE_ASYNC 0x02
#define HDLC_FF_FILL 0x00
#define HDLC_HDW_FLOW 0x01
#define START_XMIT 0x80
#define ICOM_ACFG_DRIVE1 0x20
#define ICOM_ACFG_NO_PARITY 0x00
#define ICOM_ACFG_PARITY_ENAB 0x02
#define ICOM_ACFG_PARITY_ODD 0x01
#define ICOM_ACFG_8BPC 0x00
#define ICOM_ACFG_7BPC 0x04
#define ICOM_ACFG_6BPC 0x08
#define ICOM_ACFG_5BPC 0x0C
#define ICOM_ACFG_1STOP_BIT 0x00
#define ICOM_ACFG_2STOP_BIT 0x10
#define ICOM_DTR 0x80
#define ICOM_RTS 0x40
#define ICOM_RI 0x08
#define ICOM_DSR 0x80
#define ICOM_DCD 0x20
#define ICOM_CTS 0x40
#define NUM_XBUFFS 1
#define NUM_RBUFFS 2
#define RCV_BUFF_SZ 0x0200
#define XMIT_BUFF_SZ 0x1000
struct statusArea {
/**********************************************/
/* Transmit Status Area */
/**********************************************/
struct xmit_status_area{
u32 leNext; /* Next entry in Little Endian on Adapter */
u32 leNextASD;
u32 leBuffer; /* Buffer for entry in LE for Adapter */
u16 leLengthASD;
u16 leOffsetASD;
u16 leLength; /* Length of data in segment */
u16 flags;
#define SA_FLAGS_DONE 0x0080 /* Done with Segment */
#define SA_FLAGS_CONTINUED 0x8000 /* More Segments */
#define SA_FLAGS_IDLE 0x4000 /* Mark IDLE after frm */
#define SA_FLAGS_READY_TO_XMIT 0x0800
#define SA_FLAGS_STAT_MASK 0x007F
} xmit[NUM_XBUFFS];
/**********************************************/
/* Receive Status Area */
/**********************************************/
struct {
u32 leNext; /* Next entry in Little Endian on Adapter */
u32 leNextASD;
u32 leBuffer; /* Buffer for entry in LE for Adapter */
u16 WorkingLength; /* size of segment */
u16 reserv01;
u16 leLength; /* Length of data in segment */
u16 flags;
#define SA_FL_RCV_DONE 0x0010 /* Data ready */
#define SA_FLAGS_OVERRUN 0x0040
#define SA_FLAGS_PARITY_ERROR 0x0080
#define SA_FLAGS_FRAME_ERROR 0x0001
#define SA_FLAGS_FRAME_TRUNC 0x0002
#define SA_FLAGS_BREAK_DET 0x0004 /* set conditionally by device driver, not hardware */
#define SA_FLAGS_RCV_MASK 0xFFE6
} rcv[NUM_RBUFFS];
};
struct icom_adapter;
#define ICOM_MAJOR 243
#define ICOM_MINOR_START 0
struct icom_port {
struct uart_port uart_port;
u8 imbed_modem;
#define ICOM_UNKNOWN 1
#define ICOM_RVX 2
#define ICOM_IMBED_MODEM 3
unsigned char cable_id;
unsigned char read_status_mask;
unsigned char ignore_status_mask;
void __iomem * int_reg;
struct icom_regs __iomem *global_reg;
struct func_dram __iomem *dram;
int port;
struct statusArea *statStg;
dma_addr_t statStg_pci;
u32 *xmitRestart;
dma_addr_t xmitRestart_pci;
unsigned char *xmit_buf;
dma_addr_t xmit_buf_pci;
unsigned char *recv_buf;
dma_addr_t recv_buf_pci;
int next_rcv;
int put_length;
int status;
#define ICOM_PORT_ACTIVE 1 /* Port exists. */
#define ICOM_PORT_OFF 0 /* Port does not exist. */
int load_in_progress;
struct icom_adapter *adapter;
};
struct icom_adapter {
void __iomem * base_addr;
unsigned long base_addr_pci;
struct pci_dev *pci_dev;
struct icom_port port_info[4];
int index;
int version;
#define ADAPTER_V1 0x0001
#define ADAPTER_V2 0x0002
u32 subsystem_id;
#define FOUR_PORT_MODEL 0x0252
#define V2_TWO_PORTS_RVX 0x021A
#define V2_ONE_PORT_RVX_ONE_PORT_IMBED_MDM 0x0251
int numb_ports;
struct list_head icom_adapter_entry;
struct kref kref;
};
/* prototype */
extern void iCom_sercons_init(void);
struct lookup_proc_table {
u32 __iomem *global_control_reg;
unsigned long processor_id;
};
struct lookup_int_table {
u32 __iomem *global_int_mask;
unsigned long processor_id;
};

View File

@ -1937,8 +1937,6 @@ static int imx_uart_rs485_config(struct uart_port *port,
rs485conf->flags & SER_RS485_RX_DURING_TX)
imx_uart_start_rx(port);
port->rs485 = *rs485conf;
return 0;
}

View File

@ -689,7 +689,7 @@ static void cls_param(struct jsm_channel *ch)
/*
* If baud rate is zero, flush queues, and set mval to drop DTR.
*/
if ((ch->ch_c_cflag & (CBAUD)) == 0) {
if ((ch->ch_c_cflag & CBAUD) == B0) {
ch->ch_r_head = 0;
ch->ch_r_tail = 0;
ch->ch_e_head = 0;
@ -723,14 +723,8 @@ static void cls_param(struct jsm_channel *ch)
if (!(ch->ch_c_cflag & PARODD))
lcr |= UART_LCR_EPAR;
/*
* Not all platforms support mark/space parity,
* so this will hide behind an ifdef.
*/
#ifdef CMSPAR
if (ch->ch_c_cflag & CMSPAR)
lcr |= UART_LCR_SPAR;
#endif
if (ch->ch_c_cflag & CSTOPB)
lcr |= UART_LCR_STOP;

View File

@ -938,7 +938,7 @@ static void neo_param(struct jsm_channel *ch)
/*
* If baud rate is zero, flush queues, and set mval to drop DTR.
*/
if ((ch->ch_c_cflag & (CBAUD)) == 0) {
if ((ch->ch_c_cflag & CBAUD) == B0) {
ch->ch_r_head = ch->ch_r_tail = 0;
ch->ch_e_head = ch->ch_e_tail = 0;
@ -997,14 +997,8 @@ static void neo_param(struct jsm_channel *ch)
if (!(ch->ch_c_cflag & PARODD))
lcr |= UART_LCR_EPAR;
/*
* Not all platforms support mark/space parity,
* so this will hide behind an ifdef.
*/
#ifdef CMSPAR
if (ch->ch_c_cflag & CMSPAR)
lcr |= UART_LCR_SPAR;
#endif
if (ch->ch_c_cflag & CSTOPB)
lcr |= UART_LCR_STOP;

View File

@ -1037,7 +1037,6 @@ static int max310x_rs485_config(struct uart_port *port,
rs485->flags &= SER_RS485_RTS_ON_SEND | SER_RS485_RX_DURING_TX |
SER_RS485_ENABLED;
memset(rs485->padding, 0, sizeof(rs485->padding));
port->rs485 = *rs485;
schedule_work(&one->rs_work);

View File

@ -833,7 +833,6 @@ static int men_z135_probe(struct mcb_device *mdev,
uart->port.iotype = UPIO_MEM;
uart->port.ops = &men_z135_ops;
uart->port.irq = mcb_get_irq(mdev);
uart->port.iotype = UPIO_MEM;
uart->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
uart->port.line = line++;
uart->port.dev = dev;

View File

@ -68,6 +68,7 @@
#define AML_UART_BAUD_MASK 0x7fffff
#define AML_UART_BAUD_USE BIT(23)
#define AML_UART_BAUD_XTAL BIT(24)
#define AML_UART_BAUD_XTAL_DIV2 BIT(27)
#define AML_UART_PORT_NUM 12
#define AML_UART_PORT_OFFSET 6
@ -80,6 +81,10 @@ static struct uart_driver meson_uart_driver;
static struct uart_port *meson_ports[AML_UART_PORT_NUM];
struct meson_uart_data {
bool has_xtal_div2;
};
static void meson_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
}
@ -253,6 +258,14 @@ static const char *meson_uart_type(struct uart_port *port)
return (port->type == PORT_MESON) ? "meson_uart" : NULL;
}
/*
* This function is called only from probe() using a temporary io mapping
* in order to perform a reset before setting up the device. Since the
* temporarily mapped region was successfully requested, there can be no
* console on this port at this time. Hence it is not necessary for this
* function to acquire the port->lock. (Since there is no console on this
* port at this time, the port->lock is not initialized yet.)
*/
static void meson_uart_reset(struct uart_port *port)
{
u32 val;
@ -267,9 +280,12 @@ static void meson_uart_reset(struct uart_port *port)
static int meson_uart_startup(struct uart_port *port)
{
unsigned long flags;
u32 val;
int ret = 0;
spin_lock_irqsave(&port->lock, flags);
val = readl(port->membase + AML_UART_CONTROL);
val |= AML_UART_CLEAR_ERR;
writel(val, port->membase + AML_UART_CONTROL);
@ -285,6 +301,8 @@ static int meson_uart_startup(struct uart_port *port)
val = (AML_UART_RECV_IRQ(1) | AML_UART_XMIT_IRQ(port->fifosize / 2));
writel(val, port->membase + AML_UART_MISC);
spin_unlock_irqrestore(&port->lock, flags);
ret = request_irq(port->irq, meson_uart_interrupt, 0,
port->name, port);
@ -293,16 +311,23 @@ static int meson_uart_startup(struct uart_port *port)
static void meson_uart_change_speed(struct uart_port *port, unsigned long baud)
{
u32 val;
const struct meson_uart_data *private_data = port->private_data;
u32 val = 0;
while (!meson_uart_tx_empty(port))
cpu_relax();
if (port->uartclk == 24000000) {
val = ((port->uartclk / 3) / baud) - 1;
unsigned int xtal_div = 3;
if (private_data && private_data->has_xtal_div2) {
xtal_div = 2;
val |= AML_UART_BAUD_XTAL_DIV2;
}
val |= DIV_ROUND_CLOSEST(port->uartclk / xtal_div, baud) - 1;
val |= AML_UART_BAUD_XTAL;
} else {
val = ((port->uartclk * 10 / (baud * 4) + 5) / 10) - 1;
val = DIV_ROUND_CLOSEST(port->uartclk / 4, baud) - 1;
}
val |= AML_UART_BAUD_USE;
writel(val, port->membase + AML_UART_REG5);
@ -749,6 +774,7 @@ static int meson_uart_probe(struct platform_device *pdev)
port->x_char = 0;
port->ops = &meson_uart_ops;
port->fifosize = fifosize;
port->private_data = (void *)device_get_match_data(&pdev->dev);
meson_ports[pdev->id] = port;
platform_set_drvdata(pdev, port);
@ -777,11 +803,19 @@ static int meson_uart_remove(struct platform_device *pdev)
return 0;
}
static struct meson_uart_data s4_uart_data = {
.has_xtal_div2 = true,
};
static const struct of_device_id meson_uart_dt_match[] = {
{ .compatible = "amlogic,meson6-uart" },
{ .compatible = "amlogic,meson8-uart" },
{ .compatible = "amlogic,meson8b-uart" },
{ .compatible = "amlogic,meson-gx-uart" },
{
.compatible = "amlogic,meson-s4-uart",
.data = (void *)&s4_uart_data,
},
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, meson_uart_dt_match);

View File

@ -38,6 +38,8 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/clk.h>
@ -754,9 +756,6 @@ static void mpc512x_psc_get_irq(struct uart_port *port, struct device_node *np)
port->irqflags = IRQF_SHARED;
port->irq = psc_fifoc_irq;
}
#endif
#ifdef CONFIG_PPC_MPC512x
#define PSC_5125(port) ((struct mpc5125_psc __iomem *)((port)->membase))
#define FIFO_5125(port) ((struct mpc512x_psc_fifo __iomem *)(PSC_5125(port)+1))

View File

@ -1599,6 +1599,7 @@ static inline struct uart_port *msm_get_port_from_line(unsigned int line)
static void __msm_console_write(struct uart_port *port, const char *s,
unsigned int count, bool is_uartdm)
{
unsigned long flags;
int i;
int num_newlines = 0;
bool replaced = false;
@ -1616,6 +1617,8 @@ static void __msm_console_write(struct uart_port *port, const char *s,
num_newlines++;
count += num_newlines;
local_irq_save(flags);
if (port->sysrq)
locked = 0;
else if (oops_in_progress)
@ -1661,6 +1664,8 @@ static void __msm_console_write(struct uart_port *port, const char *s,
if (locked)
spin_unlock(&port->lock);
local_irq_restore(flags);
}
static void msm_console_write(struct console *co, const char *s,

View File

@ -1336,18 +1336,11 @@ serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485)
up->ier = 0;
serial_out(up, UART_IER, 0);
/* Clamp the delays to [0, 100ms] */
rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U);
/* store new config */
port->rs485 = *rs485;
if (up->rts_gpiod) {
/* enable / disable rts */
val = (port->rs485.flags & SER_RS485_ENABLED) ?
val = (rs485->flags & SER_RS485_ENABLED) ?
SER_RS485_RTS_AFTER_SEND : SER_RS485_RTS_ON_SEND;
val = (port->rs485.flags & val) ? 1 : 0;
val = (rs485->flags & val) ? 1 : 0;
gpiod_set_value(up->rts_gpiod, val);
}
@ -1358,7 +1351,7 @@ serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485)
/* If RS-485 is disabled, make sure the THR interrupt is fired when
* TX FIFO is below the trigger level.
*/
if (!(port->rs485.flags & SER_RS485_ENABLED) &&
if (!(rs485->flags & SER_RS485_ENABLED) &&
(up->scr & OMAP_UART_SCR_TX_EMPTY)) {
up->scr &= ~OMAP_UART_SCR_TX_EMPTY;
serial_out(up, UART_OMAP_SCR, up->scr);

View File

@ -184,9 +184,6 @@ static void owl_uart_send_chars(struct uart_port *port)
struct circ_buf *xmit = &port->state->xmit;
unsigned int ch;
if (uart_tx_stopped(port))
return;
if (port->x_char) {
while (!(owl_uart_read(port, OWL_UART_STAT) & OWL_UART_STAT_TFFU))
cpu_relax();
@ -195,6 +192,9 @@ static void owl_uart_send_chars(struct uart_port *port)
port->x_char = 0;
}
if (uart_tx_stopped(port))
return;
while (!(owl_uart_read(port, OWL_UART_STAT) & OWL_UART_STAT_TFFU)) {
if (uart_circ_empty(xmit))
break;
@ -731,6 +731,7 @@ static int owl_uart_probe(struct platform_device *pdev)
owl_port->port.uartclk = clk_get_rate(owl_port->clk);
if (owl_port->port.uartclk == 0) {
dev_err(&pdev->dev, "clock rate is zero\n");
clk_disable_unprepare(owl_port->clk);
return -EINVAL;
}
owl_port->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_LOW_LATENCY;

View File

@ -550,18 +550,6 @@ static u8 pch_uart_hal_get_modem(struct eg20t_port *priv)
return (u8)msr;
}
static void pch_uart_hal_write(struct eg20t_port *priv,
const unsigned char *buf, int tx_size)
{
int i;
unsigned int thr;
for (i = 0; i < tx_size;) {
thr = buf[i++];
iowrite8(thr, priv->membase + PCH_UART_THR);
}
}
static int pch_uart_hal_read(struct eg20t_port *priv, unsigned char *buf,
int rx_size)
{
@ -624,22 +612,6 @@ static int push_rx(struct eg20t_port *priv, const unsigned char *buf,
return 0;
}
static int pop_tx_x(struct eg20t_port *priv, unsigned char *buf)
{
int ret = 0;
struct uart_port *port = &priv->port;
if (port->x_char) {
dev_dbg(priv->port.dev, "%s:X character send %02x (%lu)\n",
__func__, port->x_char, jiffies);
buf[0] = port->x_char;
port->x_char = 0;
ret = 1;
}
return ret;
}
static int dma_push_rx(struct eg20t_port *priv, int size)
{
int room;
@ -785,31 +757,6 @@ static void pch_dma_tx_complete(void *arg)
pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_TX_INT);
}
static int pop_tx(struct eg20t_port *priv, int size)
{
int count = 0;
struct uart_port *port = &priv->port;
struct circ_buf *xmit = &port->state->xmit;
if (uart_tx_stopped(port) || uart_circ_empty(xmit) || count >= size)
goto pop_tx_end;
do {
int cnt_to_end =
CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
int sz = min(size - count, cnt_to_end);
pch_uart_hal_write(priv, &xmit->buf[xmit->tail], sz);
xmit->tail = (xmit->tail + sz) & (UART_XMIT_SIZE - 1);
count += sz;
} while (!uart_circ_empty(xmit) && count < size);
pop_tx_end:
dev_dbg(priv->port.dev, "%d characters. Remained %d characters.(%lu)\n",
count, size - count, jiffies);
return count;
}
static int handle_rx_to(struct eg20t_port *priv)
{
struct pch_uart_buffer *buf;
@ -875,8 +822,6 @@ static unsigned int handle_tx(struct eg20t_port *priv)
struct uart_port *port = &priv->port;
struct circ_buf *xmit = &port->state->xmit;
int fifo_size;
int tx_size;
int size;
int tx_empty;
if (!priv->start_tx) {
@ -889,19 +834,19 @@ static unsigned int handle_tx(struct eg20t_port *priv)
fifo_size = max(priv->fifo_size, 1);
tx_empty = 1;
if (pop_tx_x(priv, xmit->buf)) {
pch_uart_hal_write(priv, xmit->buf, 1);
if (port->x_char) {
iowrite8(port->x_char, priv->membase + PCH_UART_THR);
port->icount.tx++;
port->x_char = 0;
tx_empty = 0;
fifo_size--;
}
size = min(xmit->head - xmit->tail, fifo_size);
if (size < 0)
size = fifo_size;
tx_size = pop_tx(priv, size);
if (tx_size > 0) {
port->icount.tx += tx_size;
while (!uart_tx_stopped(port) && !uart_circ_empty(xmit) && fifo_size) {
iowrite8(xmit->buf[xmit->tail], priv->membase + PCH_UART_THR);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
fifo_size--;
tx_empty = 0;
}
@ -946,9 +891,11 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
}
fifo_size = max(priv->fifo_size, 1);
if (pop_tx_x(priv, xmit->buf)) {
pch_uart_hal_write(priv, xmit->buf, 1);
if (port->x_char) {
iowrite8(port->x_char, priv->membase + PCH_UART_THR);
port->icount.tx++;
port->x_char = 0;
fifo_size--;
}

View File

@ -25,13 +25,106 @@
#include <linux/delay.h>
#include <asm/mach-pic32/pic32.h>
#include "pic32_uart.h"
/* UART name and device definitions */
#define PIC32_DEV_NAME "pic32-uart"
#define PIC32_MAX_UARTS 6
#define PIC32_SDEV_NAME "ttyPIC"
#define PIC32_UART_DFLT_BRATE 9600
#define PIC32_UART_TX_FIFO_DEPTH 8
#define PIC32_UART_RX_FIFO_DEPTH 8
#define PIC32_UART_MODE 0x00
#define PIC32_UART_STA 0x10
#define PIC32_UART_TX 0x20
#define PIC32_UART_RX 0x30
#define PIC32_UART_BRG 0x40
/* struct pic32_sport - pic32 serial port descriptor
* @port: uart port descriptor
* @idx: port index
* @irq_fault: virtual fault interrupt number
* @irq_fault_name: irq fault name
* @irq_rx: virtual rx interrupt number
* @irq_rx_name: irq rx name
* @irq_tx: virtual tx interrupt number
* @irq_tx_name: irq tx name
* @cts_gpio: clear to send gpio
* @dev: device descriptor
**/
struct pic32_sport {
struct uart_port port;
int idx;
int irq_fault;
const char *irq_fault_name;
int irq_rx;
const char *irq_rx_name;
int irq_tx;
const char *irq_tx_name;
bool enable_tx_irq;
bool hw_flow_ctrl;
int cts_gpio;
struct clk *clk;
struct device *dev;
};
static inline struct pic32_sport *to_pic32_sport(struct uart_port *port)
{
return container_of(port, struct pic32_sport, port);
}
static inline void pic32_uart_writel(struct pic32_sport *sport,
u32 reg, u32 val)
{
__raw_writel(val, sport->port.membase + reg);
}
static inline u32 pic32_uart_readl(struct pic32_sport *sport, u32 reg)
{
return __raw_readl(sport->port.membase + reg);
}
/* pic32 uart mode register bits */
#define PIC32_UART_MODE_ON BIT(15)
#define PIC32_UART_MODE_FRZ BIT(14)
#define PIC32_UART_MODE_SIDL BIT(13)
#define PIC32_UART_MODE_IREN BIT(12)
#define PIC32_UART_MODE_RTSMD BIT(11)
#define PIC32_UART_MODE_RESV1 BIT(10)
#define PIC32_UART_MODE_UEN1 BIT(9)
#define PIC32_UART_MODE_UEN0 BIT(8)
#define PIC32_UART_MODE_WAKE BIT(7)
#define PIC32_UART_MODE_LPBK BIT(6)
#define PIC32_UART_MODE_ABAUD BIT(5)
#define PIC32_UART_MODE_RXINV BIT(4)
#define PIC32_UART_MODE_BRGH BIT(3)
#define PIC32_UART_MODE_PDSEL1 BIT(2)
#define PIC32_UART_MODE_PDSEL0 BIT(1)
#define PIC32_UART_MODE_STSEL BIT(0)
/* pic32 uart status register bits */
#define PIC32_UART_STA_UTXISEL1 BIT(15)
#define PIC32_UART_STA_UTXISEL0 BIT(14)
#define PIC32_UART_STA_UTXINV BIT(13)
#define PIC32_UART_STA_URXEN BIT(12)
#define PIC32_UART_STA_UTXBRK BIT(11)
#define PIC32_UART_STA_UTXEN BIT(10)
#define PIC32_UART_STA_UTXBF BIT(9)
#define PIC32_UART_STA_TRMT BIT(8)
#define PIC32_UART_STA_URXISEL1 BIT(7)
#define PIC32_UART_STA_URXISEL0 BIT(6)
#define PIC32_UART_STA_ADDEN BIT(5)
#define PIC32_UART_STA_RIDLE BIT(4)
#define PIC32_UART_STA_PERR BIT(3)
#define PIC32_UART_STA_FERR BIT(2)
#define PIC32_UART_STA_OERR BIT(1)
#define PIC32_UART_STA_URXDA BIT(0)
/* pic32_sport pointer for console use */
static struct pic32_sport *pic32_sports[PIC32_MAX_UARTS];
@ -42,23 +135,6 @@ static inline void pic32_wait_deplete_txbuf(struct pic32_sport *sport)
udelay(1);
}
static inline int pic32_enable_clock(struct pic32_sport *sport)
{
int ret = clk_prepare_enable(sport->clk);
if (ret)
return ret;
sport->ref_clk++;
return 0;
}
static inline void pic32_disable_clock(struct pic32_sport *sport)
{
sport->ref_clk--;
clk_disable_unprepare(sport->clk);
}
/* serial core request to check if uart tx buffer is empty */
static unsigned int pic32_uart_tx_empty(struct uart_port *port)
{
@ -117,16 +193,16 @@ static unsigned int pic32_uart_get_mctrl(struct uart_port *port)
*/
static inline void pic32_uart_irqtxen(struct pic32_sport *sport, u8 en)
{
if (en && !tx_irq_enabled(sport)) {
if (en && !sport->enable_tx_irq) {
enable_irq(sport->irq_tx);
tx_irq_enabled(sport) = 1;
} else if (!en && tx_irq_enabled(sport)) {
sport->enable_tx_irq = true;
} else if (!en && sport->enable_tx_irq) {
/* use disable_irq_nosync() and not disable_irq() to avoid self
* imposed deadlock by not waiting for irq handler to end,
* since this callback is called from interrupt context.
*/
disable_irq_nosync(sport->irq_tx);
tx_irq_enabled(sport) = 0;
sport->enable_tx_irq = false;
}
}
@ -395,7 +471,7 @@ static int pic32_uart_startup(struct uart_port *port)
local_irq_save(flags);
ret = pic32_enable_clock(sport);
ret = clk_prepare_enable(sport->clk);
if (ret) {
local_irq_restore(flags);
goto out_done;
@ -419,7 +495,7 @@ static int pic32_uart_startup(struct uart_port *port)
* For each irq request_irq() is called with interrupt disabled.
* And the irq is enabled as soon as we are ready to handle them.
*/
tx_irq_enabled(sport) = 0;
sport->enable_tx_irq = false;
sport->irq_fault_name = kasprintf(GFP_KERNEL, "%s%d-fault",
pic32_uart_type(port),
@ -431,7 +507,7 @@ static int pic32_uart_startup(struct uart_port *port)
}
irq_set_status_flags(sport->irq_fault, IRQ_NOAUTOEN);
ret = request_irq(sport->irq_fault, pic32_uart_fault_interrupt,
sport->irqflags_fault, sport->irq_fault_name, port);
IRQF_NO_THREAD, sport->irq_fault_name, port);
if (ret) {
dev_err(port->dev, "%s: request irq(%d) err! ret:%d name:%s\n",
__func__, sport->irq_fault, ret,
@ -449,7 +525,7 @@ static int pic32_uart_startup(struct uart_port *port)
}
irq_set_status_flags(sport->irq_rx, IRQ_NOAUTOEN);
ret = request_irq(sport->irq_rx, pic32_uart_rx_interrupt,
sport->irqflags_rx, sport->irq_rx_name, port);
IRQF_NO_THREAD, sport->irq_rx_name, port);
if (ret) {
dev_err(port->dev, "%s: request irq(%d) err! ret:%d name:%s\n",
__func__, sport->irq_rx, ret,
@ -467,7 +543,7 @@ static int pic32_uart_startup(struct uart_port *port)
}
irq_set_status_flags(sport->irq_tx, IRQ_NOAUTOEN);
ret = request_irq(sport->irq_tx, pic32_uart_tx_interrupt,
sport->irqflags_tx, sport->irq_tx_name, port);
IRQF_NO_THREAD, sport->irq_tx_name, port);
if (ret) {
dev_err(port->dev, "%s: request irq(%d) err! ret:%d name:%s\n",
__func__, sport->irq_tx, ret,
@ -488,19 +564,21 @@ static int pic32_uart_startup(struct uart_port *port)
/* enable all interrupts and eanable uart */
pic32_uart_en_and_unmask(port);
local_irq_restore(flags);
enable_irq(sport->irq_rx);
return 0;
out_t:
kfree(sport->irq_tx_name);
free_irq(sport->irq_tx, port);
kfree(sport->irq_tx_name);
out_r:
kfree(sport->irq_rx_name);
free_irq(sport->irq_rx, port);
kfree(sport->irq_rx_name);
out_f:
kfree(sport->irq_fault_name);
free_irq(sport->irq_fault, port);
kfree(sport->irq_fault_name);
out_done:
return ret;
}
@ -515,12 +593,15 @@ static void pic32_uart_shutdown(struct uart_port *port)
spin_lock_irqsave(&port->lock, flags);
pic32_uart_dsbl_and_mask(port);
spin_unlock_irqrestore(&port->lock, flags);
pic32_disable_clock(sport);
clk_disable_unprepare(sport->clk);
/* free all 3 interrupts for this UART */
free_irq(sport->irq_fault, port);
kfree(sport->irq_fault_name);
free_irq(sport->irq_tx, port);
kfree(sport->irq_tx_name);
free_irq(sport->irq_rx, port);
kfree(sport->irq_rx_name);
}
/* serial core request to change current uart setting */
@ -712,10 +793,9 @@ static void pic32_console_write(struct console *co, const char *s,
unsigned int count)
{
struct pic32_sport *sport = pic32_sports[co->index];
struct uart_port *port = pic32_get_port(sport);
/* call uart helper to deal with \r\n */
uart_console_write(port, s, count, pic32_console_putchar);
uart_console_write(&sport->port, s, count, pic32_console_putchar);
}
/* console core request to setup given console, find matching uart
@ -724,7 +804,6 @@ static void pic32_console_write(struct console *co, const char *s,
static int pic32_console_setup(struct console *co, char *options)
{
struct pic32_sport *sport;
struct uart_port *port = NULL;
int baud = 115200;
int bits = 8;
int parity = 'n';
@ -737,16 +816,15 @@ static int pic32_console_setup(struct console *co, char *options)
sport = pic32_sports[co->index];
if (!sport)
return -ENODEV;
port = pic32_get_port(sport);
ret = pic32_enable_clock(sport);
ret = clk_prepare_enable(sport->clk);
if (ret)
return ret;
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
return uart_set_options(port, co, baud, parity, bits, flow);
return uart_set_options(&sport->port, co, baud, parity, bits, flow);
}
static struct uart_driver pic32_uart_driver;
@ -816,13 +894,9 @@ static int pic32_uart_probe(struct platform_device *pdev)
sport->idx = uart_idx;
sport->irq_fault = irq_of_parse_and_map(np, 0);
sport->irqflags_fault = IRQF_NO_THREAD;
sport->irq_rx = irq_of_parse_and_map(np, 1);
sport->irqflags_rx = IRQF_NO_THREAD;
sport->irq_tx = irq_of_parse_and_map(np, 2);
sport->irqflags_tx = IRQF_NO_THREAD;
sport->clk = devm_clk_get(&pdev->dev, NULL);
sport->cts_gpio = -EINVAL;
sport->dev = &pdev->dev;
/* Hardware flow control: gpios
@ -850,7 +924,6 @@ static int pic32_uart_probe(struct platform_device *pdev)
pic32_sports[uart_idx] = sport;
port = &sport->port;
memset(port, 0, sizeof(*port));
port->iotype = UPIO_MEM;
port->mapbase = res_mem->start;
port->ops = &pic32_uart_ops;
@ -872,7 +945,7 @@ static int pic32_uart_probe(struct platform_device *pdev)
/* The peripheral clock has been enabled by console_setup,
* so disable it till the port is used.
*/
pic32_disable_clock(sport);
clk_disable_unprepare(sport->clk);
}
#endif
@ -893,7 +966,7 @@ static int pic32_uart_remove(struct platform_device *pdev)
struct pic32_sport *sport = to_pic32_sport(port);
uart_remove_one_port(&pic32_uart_driver, port);
pic32_disable_clock(sport);
clk_disable_unprepare(sport->clk);
platform_set_drvdata(pdev, NULL);
pic32_sports[sport->idx] = NULL;

View File

@ -1,125 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* PIC32 Integrated Serial Driver.
*
* Copyright (C) 2015 Microchip Technology, Inc.
*
* Authors:
* Sorin-Andrei Pistirica <andrei.pistirica@microchip.com>
*/
#ifndef __DT_PIC32_UART_H__
#define __DT_PIC32_UART_H__
#define PIC32_UART_DFLT_BRATE (9600)
#define PIC32_UART_TX_FIFO_DEPTH (8)
#define PIC32_UART_RX_FIFO_DEPTH (8)
#define PIC32_UART_MODE 0x00
#define PIC32_UART_STA 0x10
#define PIC32_UART_TX 0x20
#define PIC32_UART_RX 0x30
#define PIC32_UART_BRG 0x40
struct pic32_console_opt {
int baud;
int parity;
int bits;
int flow;
};
/* struct pic32_sport - pic32 serial port descriptor
* @port: uart port descriptor
* @idx: port index
* @irq_fault: virtual fault interrupt number
* @irqflags_fault: flags related to fault irq
* @irq_fault_name: irq fault name
* @irq_rx: virtual rx interrupt number
* @irqflags_rx: flags related to rx irq
* @irq_rx_name: irq rx name
* @irq_tx: virtual tx interrupt number
* @irqflags_tx: : flags related to tx irq
* @irq_tx_name: irq tx name
* @cts_gpio: clear to send gpio
* @dev: device descriptor
**/
struct pic32_sport {
struct uart_port port;
struct pic32_console_opt opt;
int idx;
int irq_fault;
int irqflags_fault;
const char *irq_fault_name;
int irq_rx;
int irqflags_rx;
const char *irq_rx_name;
int irq_tx;
int irqflags_tx;
const char *irq_tx_name;
u8 enable_tx_irq;
bool hw_flow_ctrl;
int cts_gpio;
int ref_clk;
struct clk *clk;
struct device *dev;
};
#define to_pic32_sport(c) container_of(c, struct pic32_sport, port)
#define pic32_get_port(sport) (&sport->port)
#define pic32_get_opt(sport) (&sport->opt)
#define tx_irq_enabled(sport) (sport->enable_tx_irq)
static inline void pic32_uart_writel(struct pic32_sport *sport,
u32 reg, u32 val)
{
struct uart_port *port = pic32_get_port(sport);
__raw_writel(val, port->membase + reg);
}
static inline u32 pic32_uart_readl(struct pic32_sport *sport, u32 reg)
{
struct uart_port *port = pic32_get_port(sport);
return __raw_readl(port->membase + reg);
}
/* pic32 uart mode register bits */
#define PIC32_UART_MODE_ON BIT(15)
#define PIC32_UART_MODE_FRZ BIT(14)
#define PIC32_UART_MODE_SIDL BIT(13)
#define PIC32_UART_MODE_IREN BIT(12)
#define PIC32_UART_MODE_RTSMD BIT(11)
#define PIC32_UART_MODE_RESV1 BIT(10)
#define PIC32_UART_MODE_UEN1 BIT(9)
#define PIC32_UART_MODE_UEN0 BIT(8)
#define PIC32_UART_MODE_WAKE BIT(7)
#define PIC32_UART_MODE_LPBK BIT(6)
#define PIC32_UART_MODE_ABAUD BIT(5)
#define PIC32_UART_MODE_RXINV BIT(4)
#define PIC32_UART_MODE_BRGH BIT(3)
#define PIC32_UART_MODE_PDSEL1 BIT(2)
#define PIC32_UART_MODE_PDSEL0 BIT(1)
#define PIC32_UART_MODE_STSEL BIT(0)
/* pic32 uart status register bits */
#define PIC32_UART_STA_UTXISEL1 BIT(15)
#define PIC32_UART_STA_UTXISEL0 BIT(14)
#define PIC32_UART_STA_UTXINV BIT(13)
#define PIC32_UART_STA_URXEN BIT(12)
#define PIC32_UART_STA_UTXBRK BIT(11)
#define PIC32_UART_STA_UTXEN BIT(10)
#define PIC32_UART_STA_UTXBF BIT(9)
#define PIC32_UART_STA_TRMT BIT(8)
#define PIC32_UART_STA_URXISEL1 BIT(7)
#define PIC32_UART_STA_URXISEL0 BIT(6)
#define PIC32_UART_STA_ADDEN BIT(5)
#define PIC32_UART_STA_RIDLE BIT(4)
#define PIC32_UART_STA_PERR BIT(3)
#define PIC32_UART_STA_FERR BIT(2)
#define PIC32_UART_STA_OERR BIT(1)
#define PIC32_UART_STA_URXDA BIT(0)
#endif /* __DT_PIC32_UART_H__ */

View File

@ -24,7 +24,6 @@
*/
#undef DEBUG
#undef DEBUG_HARD
#undef USE_CTRL_O_SYSRQ
#include <linux/module.h>
@ -51,7 +50,6 @@
#include <asm/irq.h>
#ifdef CONFIG_PPC_PMAC
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/pmac_feature.h>
#include <asm/dbdma.h>
@ -66,10 +64,6 @@
#include "pmac_zilog.h"
/* Not yet implemented */
#undef HAS_DBDMA
static char version[] __initdata = "pmac_zilog: 0.6 (Benjamin Herrenschmidt <benh@kernel.crashing.org>)";
MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
MODULE_DESCRIPTION("Driver for the Mac and PowerMac serial ports.");
MODULE_LICENSE("GPL");
@ -446,9 +440,6 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id)
spin_lock(&uap_a->port.lock);
r3 = read_zsreg(uap_a, R3);
#ifdef DEBUG_HARD
pmz_debug("irq, r3: %x\n", r3);
#endif
/* Channel A */
push = false;
if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
@ -613,8 +604,6 @@ static void pmz_start_tx(struct uart_port *port)
struct uart_pmac_port *uap = to_pmz(port);
unsigned char status;
pmz_debug("pmz: start_tx()\n");
uap->flags |= PMACZILOG_FLAG_TX_ACTIVE;
uap->flags &= ~PMACZILOG_FLAG_TX_STOPPED;
@ -636,7 +625,7 @@ static void pmz_start_tx(struct uart_port *port)
struct circ_buf *xmit = &port->state->xmit;
if (uart_circ_empty(xmit))
goto out;
return;
write_zsdata(uap, xmit->buf[xmit->tail]);
zssync(uap);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
@ -645,8 +634,6 @@ static void pmz_start_tx(struct uart_port *port)
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&uap->port);
}
out:
pmz_debug("pmz: start_tx() done.\n");
}
/*
@ -659,13 +646,9 @@ static void pmz_stop_rx(struct uart_port *port)
{
struct uart_pmac_port *uap = to_pmz(port);
pmz_debug("pmz: stop_rx()()\n");
/* Disable all RX interrupts. */
uap->curregs[R1] &= ~RxINT_MASK;
pmz_maybe_update_regs(uap);
pmz_debug("pmz: stop_rx() done.\n");
}
/*
@ -910,8 +893,6 @@ static int pmz_startup(struct uart_port *port)
unsigned long flags;
int pwr_delay = 0;
pmz_debug("pmz: startup()\n");
uap->flags |= PMACZILOG_FLAG_IS_OPEN;
/* A console is never powered down. Else, power up and
@ -947,8 +928,6 @@ static int pmz_startup(struct uart_port *port)
pmz_interrupt_control(uap, 1);
spin_unlock_irqrestore(&port->lock, flags);
pmz_debug("pmz: startup() done.\n");
return 0;
}
@ -957,8 +936,6 @@ static void pmz_shutdown(struct uart_port *port)
struct uart_pmac_port *uap = to_pmz(port);
unsigned long flags;
pmz_debug("pmz: shutdown()\n");
spin_lock_irqsave(&port->lock, flags);
/* Disable interrupt requests for the channel */
@ -987,8 +964,6 @@ static void pmz_shutdown(struct uart_port *port)
pmz_set_scc_power(uap, 0); /* Shut the chip down */
spin_unlock_irqrestore(&port->lock, flags);
pmz_debug("pmz: shutdown() done.\n");
}
/* Shared by TTY driver and serial console setup. The port lock is held
@ -1233,10 +1208,6 @@ static void __pmz_set_termios(struct uart_port *port, struct ktermios *termios,
struct uart_pmac_port *uap = to_pmz(port);
unsigned long baud;
pmz_debug("pmz: set_termios()\n");
memcpy(&uap->termios_cache, termios, sizeof(struct ktermios));
/* XXX Check which revs of machines actually allow 1 and 4Mb speeds
* on the IR dongle. Note that the IRTTY driver currently doesn't know
* about the FIR mode and high speed modes. So these are unused. For
@ -1270,8 +1241,6 @@ static void __pmz_set_termios(struct uart_port *port, struct ktermios *termios,
pmz_maybe_update_regs(uap);
}
uart_update_timeout(port, termios->c_cflag, baud);
pmz_debug("pmz: set_termios() done.\n");
}
/* The port lock is not held. */
@ -1400,7 +1369,7 @@ static int __init pmz_init_port(struct uart_pmac_port *uap)
char name[1];
} *slots;
int len;
struct resource r_ports, r_rxdma, r_txdma;
struct resource r_ports;
/*
* Request & map chip registers
@ -1412,35 +1381,6 @@ static int __init pmz_init_port(struct uart_pmac_port *uap)
uap->control_reg = uap->port.membase;
uap->data_reg = uap->control_reg + 0x10;
/*
* Request & map DBDMA registers
*/
#ifdef HAS_DBDMA
if (of_address_to_resource(np, 1, &r_txdma) == 0 &&
of_address_to_resource(np, 2, &r_rxdma) == 0)
uap->flags |= PMACZILOG_FLAG_HAS_DMA;
#else
memset(&r_txdma, 0, sizeof(struct resource));
memset(&r_rxdma, 0, sizeof(struct resource));
#endif
if (ZS_HAS_DMA(uap)) {
uap->tx_dma_regs = ioremap(r_txdma.start, 0x100);
if (uap->tx_dma_regs == NULL) {
uap->flags &= ~PMACZILOG_FLAG_HAS_DMA;
goto no_dma;
}
uap->rx_dma_regs = ioremap(r_rxdma.start, 0x100);
if (uap->rx_dma_regs == NULL) {
iounmap(uap->tx_dma_regs);
uap->tx_dma_regs = NULL;
uap->flags &= ~PMACZILOG_FLAG_HAS_DMA;
goto no_dma;
}
uap->tx_dma_irq = irq_of_parse_and_map(np, 1);
uap->rx_dma_irq = irq_of_parse_and_map(np, 2);
}
no_dma:
/*
* Detect port type
@ -1506,8 +1446,6 @@ no_dma:
of_device_is_compatible(np->parent->parent, "gatwick")) {
/* IRQs on gatwick are offset by 64 */
uap->port.irq = irq_create_mapping(NULL, 64 + 15);
uap->tx_dma_irq = irq_create_mapping(NULL, 64 + 4);
uap->rx_dma_irq = irq_create_mapping(NULL, 64 + 5);
}
/* Setup some valid baud rate information in the register
@ -1527,8 +1465,6 @@ static void pmz_dispose_port(struct uart_pmac_port *uap)
struct device_node *np;
np = uap->node;
iounmap(uap->rx_dma_regs);
iounmap(uap->tx_dma_regs);
iounmap(uap->control_reg);
uap->node = NULL;
of_node_put(np);
@ -1875,7 +1811,6 @@ static struct platform_driver pmz_driver = {
static int __init init_pmz(void)
{
int rc, i;
printk(KERN_INFO "%s\n", version);
/*
* First, we need to do a direct OF-based probe pass. We

View File

@ -43,7 +43,6 @@ struct uart_pmac_port {
#define PMACZILOG_FLAG_TX_ACTIVE 0x00000040
#define PMACZILOG_FLAG_IS_IRDA 0x00000100
#define PMACZILOG_FLAG_IS_INTMODEM 0x00000200
#define PMACZILOG_FLAG_HAS_DMA 0x00000400
#define PMACZILOG_FLAG_RSRC_REQUESTED 0x00000800
#define PMACZILOG_FLAG_IS_OPEN 0x00002000
#define PMACZILOG_FLAG_IS_EXTCLK 0x00008000
@ -55,16 +54,7 @@ struct uart_pmac_port {
volatile u8 __iomem *control_reg;
volatile u8 __iomem *data_reg;
#ifdef CONFIG_PPC_PMAC
unsigned int tx_dma_irq;
unsigned int rx_dma_irq;
volatile struct dbdma_regs __iomem *tx_dma_regs;
volatile struct dbdma_regs __iomem *rx_dma_regs;
#endif
unsigned char irq_name[8];
struct ktermios termios_cache;
};
#define to_pmz(p) ((struct uart_pmac_port *)(p))
@ -377,7 +367,6 @@ static inline void zssync(struct uart_pmac_port *port)
#define ZS_WANTS_MODEM_STATUS(UP) ((UP)->flags & PMACZILOG_FLAG_MODEM_STATUS)
#define ZS_IS_IRDA(UP) ((UP)->flags & PMACZILOG_FLAG_IS_IRDA)
#define ZS_IS_INTMODEM(UP) ((UP)->flags & PMACZILOG_FLAG_IS_INTMODEM)
#define ZS_HAS_DMA(UP) ((UP)->flags & PMACZILOG_FLAG_HAS_DMA)
#define ZS_IS_OPEN(UP) ((UP)->flags & PMACZILOG_FLAG_IS_OPEN)
#define ZS_IS_EXTCLK(UP) ((UP)->flags & PMACZILOG_FLAG_IS_EXTCLK)

View File

@ -149,12 +149,6 @@ static unsigned int qcom_geni_serial_tx_empty(struct uart_port *port);
static void qcom_geni_serial_stop_rx(struct uart_port *uport);
static void qcom_geni_serial_handle_rx(struct uart_port *uport, bool drop);
static const unsigned long root_freq[] = {7372800, 14745600, 19200000, 29491200,
32000000, 48000000, 51200000, 64000000,
80000000, 96000000, 100000000,
102400000, 112000000, 120000000,
128000000};
#define to_dev_port(ptr, member) \
container_of(ptr, struct qcom_geni_serial_port, member)
@ -507,7 +501,7 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s,
*/
qcom_geni_serial_poll_tx_done(uport);
if (uart_circ_chars_pending(&uport->state->xmit)) {
if (!uart_circ_empty(&uport->state->xmit)) {
irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN);
writel(irq_en | M_TX_FIFO_WATERMARK_EN,
uport->membase + SE_GENI_M_IRQ_EN);
@ -946,25 +940,43 @@ static int qcom_geni_serial_startup(struct uart_port *uport)
return 0;
}
static unsigned long get_clk_cfg(unsigned long clk_freq)
{
int i;
for (i = 0; i < ARRAY_SIZE(root_freq); i++) {
if (!(root_freq[i] % clk_freq))
return root_freq[i];
}
return 0;
}
static unsigned long get_clk_div_rate(unsigned int baud,
static unsigned long get_clk_div_rate(struct clk *clk, unsigned int baud,
unsigned int sampling_rate, unsigned int *clk_div)
{
unsigned long ser_clk;
unsigned long desired_clk;
unsigned long freq, prev;
unsigned long div, maxdiv;
int64_t mult;
desired_clk = baud * sampling_rate;
ser_clk = get_clk_cfg(desired_clk);
if (!desired_clk) {
pr_err("%s: Invalid frequency\n", __func__);
return 0;
}
maxdiv = CLK_DIV_MSK >> CLK_DIV_SHFT;
prev = 0;
for (div = 1; div <= maxdiv; div++) {
mult = div * desired_clk;
if (mult > ULONG_MAX)
break;
freq = clk_round_rate(clk, (unsigned long)mult);
if (!(freq % desired_clk)) {
ser_clk = freq;
break;
}
if (!prev)
ser_clk = freq;
else if (prev == freq)
break;
prev = freq;
}
if (!ser_clk) {
pr_err("%s: Can't find matching DFS entry for baud %d\n",
__func__, baud);
@ -972,6 +984,9 @@ static unsigned long get_clk_div_rate(unsigned int baud,
}
*clk_div = ser_clk / desired_clk;
if (!(*clk_div))
*clk_div = 1;
return ser_clk;
}
@ -1003,7 +1018,8 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport,
if (ver >= QUP_SE_VERSION_2_5)
sampling_rate /= 2;
clk_rate = get_clk_div_rate(baud, sampling_rate, &clk_div);
clk_rate = get_clk_div_rate(port->se.clk, baud,
sampling_rate, &clk_div);
if (!clk_rate)
goto out_restart_rx;

View File

@ -262,6 +262,8 @@ static void rda_uart_set_termios(struct uart_port *port,
fallthrough;
case CS7:
ctrl &= ~RDA_UART_DBITS_8;
termios->c_cflag &= ~CSIZE;
termios->c_cflag |= CS7;
break;
default:
ctrl |= RDA_UART_DBITS_8;

View File

@ -446,6 +446,8 @@ sa1100_set_termios(struct uart_port *port, struct ktermios *termios,
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
del_timer_sync(&sport->timer);
spin_lock_irqsave(&sport->port.lock, flags);
sport->port.read_status_mask &= UTSR0_TO_SM(UTSR0_TFS);
@ -476,8 +478,6 @@ sa1100_set_termios(struct uart_port *port, struct ktermios *termios,
UTSR1_TO_SM(UTSR1_ROR);
}
del_timer_sync(&sport->timer);
/*
* Update the per-port timeout.
*/

View File

@ -2480,12 +2480,24 @@ s3c24xx_serial_console_write(struct console *co, const char *s,
unsigned int count)
{
unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON);
unsigned long flags;
bool locked = true;
/* not possible to xmit on unconfigured port */
if (!s3c24xx_port_configured(ucon))
return;
if (cons_uart->sysrq)
locked = false;
else if (oops_in_progress)
locked = spin_trylock_irqsave(&cons_uart->lock, flags);
else
spin_lock_irqsave(&cons_uart->lock, flags);
uart_console_write(cons_uart, s, count, s3c24xx_serial_console_putchar);
if (locked)
spin_unlock_irqrestore(&cons_uart->lock, flags);
}
/* Shouldn't be __init, as it can be instantiated from other module */
@ -2814,6 +2826,7 @@ static const struct s3c24xx_serial_drv_data s5l_serial_drv_data = {
.num_clks = 1,
.clksel_mask = 0,
.clksel_shift = 0,
.ucon_mask = APPLE_S5L_UCON_MASK,
},
.def_cfg = {
.ucon = APPLE_S5L_UCON_DEFAULT,

View File

@ -1134,16 +1134,6 @@ static int sc16is7xx_config_rs485(struct uart_port *port,
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
if (rs485->flags & SER_RS485_ENABLED) {
bool rts_during_rx, rts_during_tx;
rts_during_rx = rs485->flags & SER_RS485_RTS_AFTER_SEND;
rts_during_tx = rs485->flags & SER_RS485_RTS_ON_SEND;
if (rts_during_rx == rts_during_tx)
dev_err(port->dev,
"unsupported RTS signalling on_send:%d after_send:%d - exactly one of RS485 RTS flags should be set\n",
rts_during_tx, rts_during_rx);
/*
* RTS signal is handled by HW, it's timing can't be influenced.
* However, it's sometimes useful to delay TX even without RTS

View File

@ -24,6 +24,7 @@
#include <linux/sysrq.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/math64.h>
#include <linux/security.h>
#include <linux/irq.h>
@ -42,6 +43,11 @@ static struct lock_class_key port_lock_key;
#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
/*
* Max time with active RTS before/after data is sent.
*/
#define RS485_MAX_RTS_DELAY 100 /* msecs */
static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
struct ktermios *old_termios);
static void uart_wait_until_sent(struct tty_struct *tty, int timeout);
@ -333,15 +339,18 @@ void
uart_update_timeout(struct uart_port *port, unsigned int cflag,
unsigned int baud)
{
unsigned int size;
unsigned int size = tty_get_frame_size(cflag);
u64 frame_time;
size = tty_get_frame_size(cflag) * port->fifosize;
frame_time = (u64)size * NSEC_PER_SEC;
size *= port->fifosize;
/*
* Figure the timeout to send the above number of bits.
* Add .02 seconds of slop
*/
port->timeout = (HZ * size) / baud + HZ/50;
port->frame_time = DIV64_U64_ROUND_UP(frame_time, baud);
}
EXPORT_SYMBOL(uart_update_timeout);
@ -1296,8 +1305,36 @@ static int uart_set_rs485_config(struct uart_port *port,
if (copy_from_user(&rs485, rs485_user, sizeof(*rs485_user)))
return -EFAULT;
/* pick sane settings if the user hasn't */
if (!(rs485.flags & SER_RS485_RTS_ON_SEND) ==
!(rs485.flags & SER_RS485_RTS_AFTER_SEND)) {
dev_warn_ratelimited(port->dev,
"%s (%d): invalid RTS setting, using RTS_ON_SEND instead\n",
port->name, port->line);
rs485.flags |= SER_RS485_RTS_ON_SEND;
rs485.flags &= ~SER_RS485_RTS_AFTER_SEND;
}
if (rs485.delay_rts_before_send > RS485_MAX_RTS_DELAY) {
rs485.delay_rts_before_send = RS485_MAX_RTS_DELAY;
dev_warn_ratelimited(port->dev,
"%s (%d): RTS delay before sending clamped to %u ms\n",
port->name, port->line, rs485.delay_rts_before_send);
}
if (rs485.delay_rts_after_send > RS485_MAX_RTS_DELAY) {
rs485.delay_rts_after_send = RS485_MAX_RTS_DELAY;
dev_warn_ratelimited(port->dev,
"%s (%d): RTS delay after sending clamped to %u ms\n",
port->name, port->line, rs485.delay_rts_after_send);
}
/* Return clean padding area to userspace */
memset(rs485.padding, 0, sizeof(rs485.padding));
spin_lock_irqsave(&port->lock, flags);
ret = port->rs485_config(port, &rs485);
if (!ret)
port->rs485 = rs485;
spin_unlock_irqrestore(&port->lock, flags);
if (ret)
return ret;
@ -1610,24 +1647,24 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
* Note: we have to use pretty tight timings here to satisfy
* the NIST-PCTS.
*/
char_time = (port->timeout - HZ/50) / port->fifosize;
char_time = char_time / 5;
if (char_time == 0)
char_time = 1;
char_time = max(nsecs_to_jiffies(port->frame_time / 5), 1UL);
if (timeout && timeout < char_time)
char_time = timeout;
/*
* If the transmitter hasn't cleared in twice the approximate
* amount of time to send the entire FIFO, it probably won't
* ever clear. This assumes the UART isn't doing flow
* control, which is currently the case. Hence, if it ever
* takes longer than port->timeout, this is probably due to a
* UART bug of some kind. So, we clamp the timeout parameter at
* 2*port->timeout.
*/
if (timeout == 0 || timeout > 2 * port->timeout)
timeout = 2 * port->timeout;
if (!uart_cts_enabled(port)) {
/*
* If the transmitter hasn't cleared in twice the approximate
* amount of time to send the entire FIFO, it probably won't
* ever clear. This assumes the UART isn't doing flow
* control, which is currently the case. Hence, if it ever
* takes longer than port->timeout, this is probably due to a
* UART bug of some kind. So, we clamp the timeout parameter at
* 2*port->timeout.
*/
if (timeout == 0 || timeout > 2 * port->timeout)
timeout = 2 * port->timeout;
}
expire = jiffies + timeout;
@ -1643,7 +1680,7 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
msleep_interruptible(jiffies_to_msecs(char_time));
if (signal_pending(current))
break;
if (time_after(jiffies, expire))
if (timeout && time_after(jiffies, expire))
break;
}
uart_port_deref(port);
@ -2174,15 +2211,23 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
}
put_device(tty_dev);
/* Nothing to do if the console is not suspending */
if (!console_suspend_enabled && uart_console(uport))
/*
* Nothing to do if the console is not suspending
* except stop_rx to prevent any asynchronous data
* over RX line. Re-start_rx, when required, is
* done by set_termios in resume sequence
*/
if (!console_suspend_enabled && uart_console(uport)) {
uport->ops->stop_rx(uport);
goto unlock;
}
uport->suspended = 1;
if (tty_port_initialized(port)) {
const struct uart_ops *ops = uport->ops;
int tries;
unsigned int mctrl;
tty_port_set_suspended(port, 1);
tty_port_set_initialized(port, 0);
@ -2190,6 +2235,9 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
spin_lock_irq(&uport->lock);
ops->stop_tx(uport);
ops->set_mctrl(uport, 0);
/* save mctrl so it can be restored on resume */
mctrl = uport->mctrl;
uport->mctrl = 0;
ops->stop_rx(uport);
spin_unlock_irq(&uport->lock);
@ -2203,6 +2251,7 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
uport->name);
ops->shutdown(uport);
uport->mctrl = mctrl;
}
/*

View File

@ -618,6 +618,8 @@ serial_txx9_set_termios(struct uart_port *up, struct ktermios *termios,
case CS6: /* not supported */
case CS8:
cval |= TXX9_SILCR_UMODE_8BIT;
termios->c_cflag &= ~CSIZE;
termios->c_cflag |= CS8;
break;
}

View File

@ -2379,8 +2379,12 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
int best_clk = -1;
unsigned long flags;
if ((termios->c_cflag & CSIZE) == CS7)
if ((termios->c_cflag & CSIZE) == CS7) {
smr_val |= SCSMR_CHR;
} else {
termios->c_cflag &= ~CSIZE;
termios->c_cflag |= CS8;
}
if (termios->c_cflag & PARENB)
smr_val |= SCSMR_PE;
if (termios->c_cflag & PARODD)

View File

@ -148,7 +148,6 @@
* @port: struct uart_port embedded in this struct
* @dev: struct device *
* @ier: shadowed copy of the interrupt enable register
* @clkin_rate: input clock to the UART IP block.
* @baud_rate: UART serial line rate (e.g., 115200 baud)
* @clk: reference to this device's clock
* @clk_notifier: clock rate change notifier for upstream clock changes
@ -159,7 +158,6 @@ struct sifive_serial_port {
struct uart_port port;
struct device *dev;
unsigned char ier;
unsigned long clkin_rate;
unsigned long baud_rate;
struct clk *clk;
struct notifier_block clk_notifier;
@ -463,7 +461,7 @@ static void __ssp_update_div(struct sifive_serial_port *ssp)
{
u16 div;
div = DIV_ROUND_UP(ssp->clkin_rate, ssp->baud_rate) - 1;
div = DIV_ROUND_UP(ssp->port.uartclk, ssp->baud_rate) - 1;
__ssp_writel(div, SIFIVE_SERIAL_DIV_OFFS, ssp);
}
@ -648,8 +646,8 @@ static int sifive_serial_clk_notifier(struct notifier_block *nb,
udelay(DIV_ROUND_UP(12 * 1000 * 1000, ssp->baud_rate));
}
if (event == POST_RATE_CHANGE && ssp->clkin_rate != cnd->new_rate) {
ssp->clkin_rate = cnd->new_rate;
if (event == POST_RATE_CHANGE && ssp->port.uartclk != cnd->new_rate) {
ssp->port.uartclk = cnd->new_rate;
__ssp_update_div(ssp);
}
@ -666,19 +664,24 @@ static void sifive_serial_set_termios(struct uart_port *port,
int rate;
char nstop;
if ((termios->c_cflag & CSIZE) != CS8)
if ((termios->c_cflag & CSIZE) != CS8) {
dev_err_once(ssp->port.dev, "only 8-bit words supported\n");
termios->c_cflag &= ~CSIZE;
termios->c_cflag |= CS8;
}
if (termios->c_iflag & (INPCK | PARMRK))
dev_err_once(ssp->port.dev, "parity checking not supported\n");
if (termios->c_iflag & BRKINT)
dev_err_once(ssp->port.dev, "BREAK detection not supported\n");
termios->c_iflag &= ~(INPCK|PARMRK|BRKINT);
/* Set number of stop bits */
nstop = (termios->c_cflag & CSTOPB) ? 2 : 1;
__ssp_set_stop_bits(ssp, nstop);
/* Set line rate */
rate = uart_get_baud_rate(port, termios, old, 0, ssp->clkin_rate / 16);
rate = uart_get_baud_rate(port, termios, old, 0,
ssp->port.uartclk / 16);
__ssp_update_baud_rate(ssp, rate);
spin_lock_irqsave(&ssp->port.lock, flags);
@ -996,9 +999,8 @@ static int sifive_serial_probe(struct platform_device *pdev)
}
/* Set up clock divider */
ssp->clkin_rate = clk_get_rate(ssp->clk);
ssp->port.uartclk = clk_get_rate(ssp->clk);
ssp->baud_rate = SIFIVE_DEFAULT_BAUD_RATE;
ssp->port.uartclk = ssp->baud_rate * 16;
__ssp_update_div(ssp);
platform_set_drvdata(pdev, ssp);

View File

@ -535,10 +535,14 @@ static void asc_set_termios(struct uart_port *port, struct ktermios *termios,
/* set character length */
if ((cflag & CSIZE) == CS7) {
ctrl_val |= ASC_CTL_MODE_7BIT_PAR;
cflag |= PARENB;
} else {
ctrl_val |= (cflag & PARENB) ? ASC_CTL_MODE_8BIT_PAR :
ASC_CTL_MODE_8BIT;
cflag &= ~CSIZE;
cflag |= CS8;
}
termios->c_cflag = cflag;
/* set stop bit */
ctrl_val |= (cflag & CSTOPB) ? ASC_CTL_STOP_2BIT : ASC_CTL_STOP_1BIT;

View File

@ -37,6 +37,7 @@
static void stm32_usart_stop_tx(struct uart_port *port);
static void stm32_usart_transmit_chars(struct uart_port *port);
static void __maybe_unused stm32_usart_console_putchar(struct uart_port *port, unsigned char ch);
static inline struct stm32_port *to_stm32_port(struct uart_port *port)
{
@ -107,8 +108,6 @@ static int stm32_usart_config_rs485(struct uart_port *port,
stm32_usart_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
port->rs485 = *rs485conf;
rs485conf->flags |= SER_RS485_RX_DURING_TX;
if (rs485conf->flags & SER_RS485_ENABLED) {
@ -128,13 +127,10 @@ static int stm32_usart_config_rs485(struct uart_port *port,
rs485conf->delay_rts_after_send,
baud);
if (rs485conf->flags & SER_RS485_RTS_ON_SEND) {
if (rs485conf->flags & SER_RS485_RTS_ON_SEND)
cr3 &= ~USART_CR3_DEP;
rs485conf->flags &= ~SER_RS485_RTS_AFTER_SEND;
} else {
else
cr3 |= USART_CR3_DEP;
rs485conf->flags |= SER_RS485_RTS_AFTER_SEND;
}
writel_relaxed(cr3, port->membase + ofs->cr3);
writel_relaxed(cr1, port->membase + ofs->cr1);
@ -421,6 +417,14 @@ static void stm32_usart_tx_interrupt_enable(struct uart_port *port)
stm32_usart_set_bits(port, ofs->cr1, USART_CR1_TXEIE);
}
static void stm32_usart_tc_interrupt_enable(struct uart_port *port)
{
struct stm32_port *stm32_port = to_stm32_port(port);
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
stm32_usart_set_bits(port, ofs->cr1, USART_CR1_TCIE);
}
static void stm32_usart_rx_dma_complete(void *arg)
{
struct uart_port *port = arg;
@ -446,6 +450,50 @@ static void stm32_usart_tx_interrupt_disable(struct uart_port *port)
stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_TXEIE);
}
static void stm32_usart_tc_interrupt_disable(struct uart_port *port)
{
struct stm32_port *stm32_port = to_stm32_port(port);
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_TCIE);
}
static void stm32_usart_rs485_rts_enable(struct uart_port *port)
{
struct stm32_port *stm32_port = to_stm32_port(port);
struct serial_rs485 *rs485conf = &port->rs485;
if (stm32_port->hw_flow_control ||
!(rs485conf->flags & SER_RS485_ENABLED))
return;
if (rs485conf->flags & SER_RS485_RTS_ON_SEND) {
mctrl_gpio_set(stm32_port->gpios,
stm32_port->port.mctrl | TIOCM_RTS);
} else {
mctrl_gpio_set(stm32_port->gpios,
stm32_port->port.mctrl & ~TIOCM_RTS);
}
}
static void stm32_usart_rs485_rts_disable(struct uart_port *port)
{
struct stm32_port *stm32_port = to_stm32_port(port);
struct serial_rs485 *rs485conf = &port->rs485;
if (stm32_port->hw_flow_control ||
!(rs485conf->flags & SER_RS485_ENABLED))
return;
if (rs485conf->flags & SER_RS485_RTS_ON_SEND) {
mctrl_gpio_set(stm32_port->gpios,
stm32_port->port.mctrl & ~TIOCM_RTS);
} else {
mctrl_gpio_set(stm32_port->gpios,
stm32_port->port.mctrl | TIOCM_RTS);
}
}
static void stm32_usart_transmit_chars_pio(struct uart_port *port)
{
struct stm32_port *stm32_port = to_stm32_port(port);
@ -553,6 +601,13 @@ static void stm32_usart_transmit_chars(struct uart_port *port)
u32 isr;
int ret;
if (!stm32_port->hw_flow_control &&
port->rs485.flags & SER_RS485_ENABLED) {
stm32_port->txdone = false;
stm32_usart_tc_interrupt_disable(port);
stm32_usart_rs485_rts_enable(port);
}
if (port->x_char) {
if (stm32_usart_tx_dma_started(stm32_port) &&
stm32_usart_tx_dma_enabled(stm32_port))
@ -593,8 +648,14 @@ static void stm32_usart_transmit_chars(struct uart_port *port)
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
if (uart_circ_empty(xmit))
if (uart_circ_empty(xmit)) {
stm32_usart_tx_interrupt_disable(port);
if (!stm32_port->hw_flow_control &&
port->rs485.flags & SER_RS485_ENABLED) {
stm32_port->txdone = true;
stm32_usart_tc_interrupt_enable(port);
}
}
}
static irqreturn_t stm32_usart_interrupt(int irq, void *ptr)
@ -608,6 +669,13 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr)
sr = readl_relaxed(port->membase + ofs->isr);
if (!stm32_port->hw_flow_control &&
port->rs485.flags & SER_RS485_ENABLED &&
(sr & USART_SR_TC)) {
stm32_usart_tc_interrupt_disable(port);
stm32_usart_rs485_rts_disable(port);
}
if ((sr & USART_SR_RTOF) && ofs->icr != UNDEF_REG)
writel_relaxed(USART_ICR_RTOCF,
port->membase + ofs->icr);
@ -717,44 +785,27 @@ static void stm32_usart_disable_ms(struct uart_port *port)
static void stm32_usart_stop_tx(struct uart_port *port)
{
struct stm32_port *stm32_port = to_stm32_port(port);
struct serial_rs485 *rs485conf = &port->rs485;
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
stm32_usart_tx_interrupt_disable(port);
if (stm32_usart_tx_dma_started(stm32_port) && stm32_usart_tx_dma_enabled(stm32_port))
stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
if (rs485conf->flags & SER_RS485_ENABLED) {
if (rs485conf->flags & SER_RS485_RTS_ON_SEND) {
mctrl_gpio_set(stm32_port->gpios,
stm32_port->port.mctrl & ~TIOCM_RTS);
} else {
mctrl_gpio_set(stm32_port->gpios,
stm32_port->port.mctrl | TIOCM_RTS);
}
}
stm32_usart_rs485_rts_disable(port);
}
/* There are probably characters waiting to be transmitted. */
static void stm32_usart_start_tx(struct uart_port *port)
{
struct stm32_port *stm32_port = to_stm32_port(port);
struct serial_rs485 *rs485conf = &port->rs485;
struct circ_buf *xmit = &port->state->xmit;
if (uart_circ_empty(xmit) && !port->x_char)
if (uart_circ_empty(xmit) && !port->x_char) {
stm32_usart_rs485_rts_disable(port);
return;
if (rs485conf->flags & SER_RS485_ENABLED) {
if (rs485conf->flags & SER_RS485_RTS_ON_SEND) {
mctrl_gpio_set(stm32_port->gpios,
stm32_port->port.mctrl | TIOCM_RTS);
} else {
mctrl_gpio_set(stm32_port->gpios,
stm32_port->port.mctrl & ~TIOCM_RTS);
}
}
stm32_usart_rs485_rts_enable(port);
stm32_usart_transmit_chars(port);
}
@ -1037,13 +1088,22 @@ static void stm32_usart_set_termios(struct uart_port *port,
* CS8 or (CS7 + parity), 8 bits word aka [M1:M0] = 0b00
* M0 and M1 already cleared by cr1 initialization.
*/
if (bits == 9)
if (bits == 9) {
cr1 |= USART_CR1_M0;
else if ((bits == 7) && cfg->has_7bits_data)
} else if ((bits == 7) && cfg->has_7bits_data) {
cr1 |= USART_CR1_M1;
else if (bits != 8)
} else if (bits != 8) {
dev_dbg(port->dev, "Unsupported data bits config: %u bits\n"
, bits);
cflag &= ~CSIZE;
cflag |= CS8;
termios->c_cflag = cflag;
bits = 8;
if (cflag & PARENB) {
bits++;
cr1 |= USART_CR1_M0;
}
}
if (ofs->rtor != UNDEF_REG && (stm32_port->rx_ch ||
(stm32_port->fifoen &&
@ -1222,6 +1282,33 @@ static void stm32_usart_pm(struct uart_port *port, unsigned int state,
}
}
#if defined(CONFIG_CONSOLE_POLL)
/* Callbacks for characters polling in debug context (i.e. KGDB). */
static int stm32_usart_poll_init(struct uart_port *port)
{
struct stm32_port *stm32_port = to_stm32_port(port);
return clk_prepare_enable(stm32_port->clk);
}
static int stm32_usart_poll_get_char(struct uart_port *port)
{
struct stm32_port *stm32_port = to_stm32_port(port);
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
if (!(readl_relaxed(port->membase + ofs->isr) & USART_SR_RXNE))
return NO_POLL_CHAR;
return readl_relaxed(port->membase + ofs->rdr) & stm32_port->rdr_mask;
}
static void stm32_usart_poll_put_char(struct uart_port *port, unsigned char ch)
{
stm32_usart_console_putchar(port, ch);
}
#endif /* CONFIG_CONSOLE_POLL */
static const struct uart_ops stm32_uart_ops = {
.tx_empty = stm32_usart_tx_empty,
.set_mctrl = stm32_usart_set_mctrl,
@ -1243,6 +1330,11 @@ static const struct uart_ops stm32_uart_ops = {
.request_port = stm32_usart_request_port,
.config_port = stm32_usart_config_port,
.verify_port = stm32_usart_verify_port,
#if defined(CONFIG_CONSOLE_POLL)
.poll_init = stm32_usart_poll_init,
.poll_get_char = stm32_usart_poll_get_char,
.poll_put_char = stm32_usart_poll_put_char,
#endif /* CONFIG_CONSOLE_POLL */
};
/*
@ -1640,18 +1732,24 @@ static int stm32_usart_serial_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_SERIAL_STM32_CONSOLE
static void stm32_usart_console_putchar(struct uart_port *port, unsigned char ch)
static void __maybe_unused stm32_usart_console_putchar(struct uart_port *port, unsigned char ch)
{
struct stm32_port *stm32_port = to_stm32_port(port);
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
u32 isr;
int ret;
while (!(readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE))
cpu_relax();
ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr, isr,
(isr & USART_SR_TXE), 100,
STM32_USART_TIMEOUT_USEC);
if (ret != 0) {
dev_err(port->dev, "Error while sending data in UART TX : %d\n", ret);
return;
}
writel_relaxed(ch, port->membase + ofs->tdr);
}
#ifdef CONFIG_SERIAL_STM32_CONSOLE
static void stm32_usart_console_write(struct console *co, const char *s,
unsigned int cnt)
{
@ -1727,6 +1825,57 @@ static struct console stm32_console = {
#define STM32_SERIAL_CONSOLE NULL
#endif /* CONFIG_SERIAL_STM32_CONSOLE */
#ifdef CONFIG_SERIAL_EARLYCON
static void early_stm32_usart_console_putchar(struct uart_port *port, unsigned char ch)
{
struct stm32_usart_info *info = port->private_data;
while (!(readl_relaxed(port->membase + info->ofs.isr) & USART_SR_TXE))
cpu_relax();
writel_relaxed(ch, port->membase + info->ofs.tdr);
}
static void early_stm32_serial_write(struct console *console, const char *s, unsigned int count)
{
struct earlycon_device *device = console->data;
struct uart_port *port = &device->port;
uart_console_write(port, s, count, early_stm32_usart_console_putchar);
}
static int __init early_stm32_h7_serial_setup(struct earlycon_device *device, const char *options)
{
if (!(device->port.membase || device->port.iobase))
return -ENODEV;
device->port.private_data = &stm32h7_info;
device->con->write = early_stm32_serial_write;
return 0;
}
static int __init early_stm32_f7_serial_setup(struct earlycon_device *device, const char *options)
{
if (!(device->port.membase || device->port.iobase))
return -ENODEV;
device->port.private_data = &stm32f7_info;
device->con->write = early_stm32_serial_write;
return 0;
}
static int __init early_stm32_f4_serial_setup(struct earlycon_device *device, const char *options)
{
if (!(device->port.membase || device->port.iobase))
return -ENODEV;
device->port.private_data = &stm32f4_info;
device->con->write = early_stm32_serial_write;
return 0;
}
OF_EARLYCON_DECLARE(stm32, "st,stm32h7-uart", early_stm32_h7_serial_setup);
OF_EARLYCON_DECLARE(stm32, "st,stm32f7-uart", early_stm32_f7_serial_setup);
OF_EARLYCON_DECLARE(stm32, "st,stm32-uart", early_stm32_f4_serial_setup);
#endif /* CONFIG_SERIAL_EARLYCON */
static struct uart_driver stm32_usart_driver = {
.driver_name = DRIVER_NAME,
.dev_name = STM32_SERIAL_NAME,

View File

@ -251,6 +251,8 @@ struct stm32_usart_info stm32h7_info = {
#define RX_BUF_P (RX_BUF_L / 2) /* dma rx buffer period */
#define TX_BUF_L RX_BUF_L /* dma tx buffer length */
#define STM32_USART_TIMEOUT_USEC USEC_PER_SEC /* 1s timeout in µs */
struct stm32_port {
struct uart_port port;
struct clk *clk;
@ -269,6 +271,7 @@ struct stm32_port {
bool hw_flow_control;
bool swap; /* swap RX & TX pins */
bool fifoen;
bool txdone;
int rxftcfg; /* RX FIFO threshold CFG */
int txftcfg; /* TX FIFO threshold CFG */
bool wakeup_src;

View File

@ -498,7 +498,7 @@ static const struct uart_ops sunplus_uart_ops = {
};
#ifdef CONFIG_SERIAL_SUNPLUS_CONSOLE
struct sunplus_uart_port *sunplus_console_ports[SUP_UART_NR];
static struct sunplus_uart_port *sunplus_console_ports[SUP_UART_NR];
static void sunplus_uart_console_putchar(struct uart_port *port,
unsigned char ch)

View File

@ -798,10 +798,8 @@ sunsu_change_speed(struct uart_port *port, unsigned int cflag,
cval |= UART_LCR_PARITY;
if (!(cflag & PARODD))
cval |= UART_LCR_EPAR;
#ifdef CMSPAR
if (cflag & CMSPAR)
cval |= UART_LCR_SPAR;
#endif
/*
* Work around a bug in the Oxford Semiconductor 952 rev B

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