TTY/Serial driver update for 6.9-rc1

Here is the big set of TTY/Serial driver updates and cleanups for
 6.9-rc1.  Included in here are:
   - more tty cleanups from Jiri
   - loads of 8250 driver cleanups from Andy
   - max310x driver updates
   - samsung serial driver updates
   - uart_prepare_sysrq_char() updates for many drivers
   - platform driver remove callback void cleanups
   - stm32 driver updates
   - other small tty/serial driver updates
 
 All of these have been in linux-next for a long time with no reported
 issues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCZfwqow8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ynNegCffxTbsnbMGjWhVrQ326IJx/DFvNMAoI9csigv
 m+G3RzefzZLRx8nAma0c
 =GMfc
 -----END PGP SIGNATURE-----

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

Pull tty / serial driver updates from Greg KH:
 "Here is the big set of TTY/Serial driver updates and cleanups for
  6.9-rc1. Included in here are:

   - more tty cleanups from Jiri

   - loads of 8250 driver cleanups from Andy

   - max310x driver updates

   - samsung serial driver updates

   - uart_prepare_sysrq_char() updates for many drivers

   - platform driver remove callback void cleanups

   - stm32 driver updates

   - other small tty/serial driver updates

  All of these have been in linux-next for a long time with no reported
  issues"

* tag 'tty-6.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (199 commits)
  dt-bindings: serial: stm32: add power-domains property
  serial: 8250_dw: Replace ACPI device check by a quirk
  serial: Lock console when calling into driver before registration
  serial: 8250_uniphier: Switch to use uart_read_port_properties()
  serial: 8250_tegra: Switch to use uart_read_port_properties()
  serial: 8250_pxa: Switch to use uart_read_port_properties()
  serial: 8250_omap: Switch to use uart_read_port_properties()
  serial: 8250_of: Switch to use uart_read_port_properties()
  serial: 8250_lpc18xx: Switch to use uart_read_port_properties()
  serial: 8250_ingenic: Switch to use uart_read_port_properties()
  serial: 8250_dw: Switch to use uart_read_port_properties()
  serial: 8250_bcm7271: Switch to use uart_read_port_properties()
  serial: 8250_bcm2835aux: Switch to use uart_read_port_properties()
  serial: 8250_aspeed_vuart: Switch to use uart_read_port_properties()
  serial: port: Introduce a common helper to read properties
  serial: core: Add UPIO_UNKNOWN constant for unknown port type
  serial: core: Move struct uart_port::quirks closer to possible values
  serial: sh-sci: Call sci_serial_{in,out}() directly
  serial: core: only stop transmit when HW fifo is empty
  serial: pch: Use uart_prepare_sysrq_char().
  ...
This commit is contained in:
Linus Torvalds 2024-03-21 12:44:10 -07:00
commit 3bcb0bf65c
122 changed files with 3546 additions and 2525 deletions

View File

@ -55,6 +55,7 @@ required:
allOf: allOf:
- $ref: serial.yaml# - $ref: serial.yaml#
- $ref: rs485.yaml#
- if: - if:
properties: properties:
compatible: compatible:

View File

@ -30,6 +30,7 @@ properties:
- items: - items:
- enum: - enum:
- fsl,imx93-lpuart - fsl,imx93-lpuart
- fsl,imx95-lpuart
- const: fsl,imx8ulp-lpuart - const: fsl,imx8ulp-lpuart
- const: fsl,imx7ulp-lpuart - const: fsl,imx7ulp-lpuart
- items: - items:

View File

@ -59,6 +59,7 @@ properties:
- renesas,hscif-r8a779a0 # R-Car V3U - renesas,hscif-r8a779a0 # R-Car V3U
- renesas,hscif-r8a779f0 # R-Car S4-8 - renesas,hscif-r8a779f0 # R-Car S4-8
- renesas,hscif-r8a779g0 # R-Car V4H - renesas,hscif-r8a779g0 # R-Car V4H
- renesas,hscif-r8a779h0 # R-Car V4M
- const: renesas,rcar-gen4-hscif # R-Car Gen4 - const: renesas,rcar-gen4-hscif # R-Car Gen4
- const: renesas,hscif # generic HSCIF compatible UART - const: renesas,hscif # generic HSCIF compatible UART

View File

@ -143,6 +143,8 @@ allOf:
then: then:
required: required:
- samsung,uart-fifosize - samsung,uart-fifosize
properties:
reg-io-width: false
unevaluatedProperties: false unevaluatedProperties: false

View File

@ -88,7 +88,7 @@ properties:
TX FIFO threshold configuration (in bytes). TX FIFO threshold configuration (in bytes).
patternProperties: patternProperties:
"^(bluetooth|bluetooth-gnss|gnss|gps|mcu)$": "^(bluetooth|bluetooth-gnss|gnss|gps|mcu|onewire)$":
if: if:
type: object type: object
then: then:

View File

@ -0,0 +1,55 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/serial/st,asc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: STMicroelectronics STi SoCs Serial Port
maintainers:
- Patrice Chotard <patrice.chotard@foss.st.com>
allOf:
- $ref: serial.yaml#
properties:
compatible:
const: st,asc
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
maxItems: 1
st,hw-flow-ctrl:
description: When set, enable hardware flow control.
type: boolean
st,force-m1:
description: When set, force asc to be in Mode-1. This is recommended for
high bit rates above 19.2K.
type: boolean
required:
- compatible
- reg
- interrupts
- clocks
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/stih407-clks.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
serial@9830000 {
compatible = "st,asc";
reg = <0x9830000 0x2c>;
interrupts = <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk_s_c0_flexgen CLK_EXT2F_A9>;
};
...

View File

@ -58,6 +58,9 @@ properties:
wakeup-source: true wakeup-source: true
power-domains:
maxItems: 1
rx-threshold: rx-threshold:
description: description:
If value is set to 1, RX FIFO threshold is disabled. If value is set to 1, RX FIFO threshold is disabled.

View File

@ -1,18 +0,0 @@
*st-asc(Serial Port)
Required properties:
- compatible : Should be "st,asc".
- reg, reg-names, interrupts, interrupt-names : Standard way to define device
resources with names. look in
Documentation/devicetree/bindings/resource-names.txt
Optional properties:
- st,hw-flow-ctrl bool flag to enable hardware flow control.
- st,force-m1 bool flat to force asc to be in Mode-1 recommended
for high bit rates (above 19.2K)
Example:
serial@fe440000{
compatible = "st,asc";
reg = <0xfe440000 0x2c>;
interrupts = <0 209 0>;
};

View File

@ -0,0 +1,59 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/w1/w1-uart.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: UART 1-Wire Bus
maintainers:
- Christoph Winklhofer <cj.winklhofer@gmail.com>
description: |
UART 1-wire bus. Utilizes the UART interface via the Serial Device Bus
to create the 1-Wire timing patterns.
The UART peripheral must support full-duplex and operate in open-drain
mode. The timing patterns are generated by a specific combination of
baud-rate and transmitted byte, which corresponds to a 1-Wire read bit,
write bit or reset pulse.
The default baud-rate for reset and presence detection is 9600 and for
a 1-Wire read or write operation 115200. In case the actual baud-rate
is different from the requested one, the transmitted byte is adapted
to generate the 1-Wire timing patterns.
https://www.analog.com/en/technical-articles/using-a-uart-to-implement-a-1wire-bus-master.html
properties:
compatible:
const: w1-uart
reset-bps:
default: 9600
description:
The baud rate for the 1-Wire reset and presence detect.
write-0-bps:
default: 115200
description:
The baud rate for the 1-Wire write-0 cycle.
write-1-bps:
default: 115200
description:
The baud rate for the 1-Wire write-1 and read cycle.
required:
- compatible
additionalProperties:
type: object
examples:
- |
serial {
onewire {
compatible = "w1-uart";
};
};

View File

@ -0,0 +1,45 @@
.. SPDX-License-Identifier: GPL-2.0
=======
Console
=======
.. contents:: :local:
Struct Console
==============
.. kernel-doc:: include/linux/console.h
:identifiers: console cons_flags
Internals
---------
.. kernel-doc:: include/linux/console.h
:identifiers: nbcon_state nbcon_prio nbcon_context nbcon_write_context
Struct Consw
============
.. kernel-doc:: include/linux/console.h
:identifiers: consw
Console functions
=================
.. kernel-doc:: include/linux/console.h
:identifiers: console_srcu_read_flags console_srcu_write_flags
console_is_registered for_each_console_srcu for_each_console
.. kernel-doc:: drivers/tty/vt/selection.c
:export:
.. kernel-doc:: drivers/tty/vt/vt.c
:export:
Internals
---------
.. kernel-doc:: drivers/tty/vt/selection.c
:internal:
.. kernel-doc:: drivers/tty/vt/vt.c
:internal:

View File

@ -38,6 +38,7 @@ In-detail description of the named TTY structures is in separate documents:
tty_buffer tty_buffer
tty_ioctl tty_ioctl
tty_internals tty_internals
console
Writing TTY Driver Writing TTY Driver
================== ==================

View File

@ -12,3 +12,4 @@
mxc-w1 mxc-w1
omap-hdq omap-hdq
w1-gpio w1-gpio
w1-uart

View File

@ -0,0 +1,54 @@
.. SPDX-License-Identifier: GPL-2.0-or-later
=====================
Kernel driver w1-uart
=====================
Author: Christoph Winklhofer <cj.winklhofer@gmail.com>
Description
-----------
UART 1-Wire bus driver. The driver utilizes the UART interface via the
Serial Device Bus to create the 1-Wire timing patterns as described in
the document `"Using a UART to Implement a 1-Wire Bus Master"`_.
.. _"Using a UART to Implement a 1-Wire Bus Master": https://www.analog.com/en/technical-articles/using-a-uart-to-implement-a-1wire-bus-master.html
In short, the UART peripheral must support full-duplex and operate in
open-drain mode. The timing patterns are generated by a specific
combination of baud-rate and transmitted byte, which corresponds to a
1-Wire read bit, write bit or reset pulse.
For instance the timing pattern for a 1-Wire reset and presence detect uses
the baud-rate 9600, i.e. 104.2 us per bit. The transmitted byte 0xf0 over
UART (least significant bit first, start-bit low) sets the reset low time
for 1-Wire to 521 us. A present 1-Wire device changes the received byte by
pulling the line low, which is used by the driver to evaluate the result of
the 1-Wire operation.
Similar for a 1-Wire read bit or write bit, which uses the baud-rate
115200, i.e. 8.7 us per bit. The transmitted byte 0x80 is used for a
Write-0 operation (low time 69.6us) and the byte 0xff for Read-0, Read-1
and Write-1 (low time 8.7us).
The default baud-rate for reset and presence detection is 9600 and for
a 1-Wire read or write operation 115200. In case the actual baud-rate
is different from the requested one, the transmitted byte is adapted
to generate the 1-Wire timing patterns.
Usage
-----
Specify the UART 1-wire bus in the device tree by adding the single child
onewire to the serial node (e.g. uart0). For example:
::
@uart0 {
...
onewire {
compatible = "w1-uart";
};
};

View File

@ -846,6 +846,6 @@ static void amiga_get_hardware_list(struct seq_file *m)
* The Amiga keyboard driver needs key_maps, but we cannot export it in * The Amiga keyboard driver needs key_maps, but we cannot export it in
* drivers/char/defkeymap.c, as it is autogenerated * drivers/char/defkeymap.c, as it is autogenerated
*/ */
#ifdef CONFIG_HW_CONSOLE #ifdef CONFIG_VT
EXPORT_SYMBOL_GPL(key_maps); EXPORT_SYMBOL_GPL(key_maps);
#endif #endif

View File

@ -10,6 +10,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/serial_8250.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/console.h> #include <linux/console.h>
@ -67,9 +68,6 @@ static char *hp300_models[] __initdata = {
static char hp300_model_name[13] = "HP9000/"; static char hp300_model_name[13] = "HP9000/";
extern void hp300_reset(void); extern void hp300_reset(void);
#ifdef CONFIG_SERIAL_8250_CONSOLE
extern int hp300_setup_serial_console(void) __init;
#endif
int __init hp300_parse_bootinfo(const struct bi_record *record) int __init hp300_parse_bootinfo(const struct bi_record *record)
{ {
@ -263,7 +261,5 @@ void __init config_hp300(void)
} else { } else {
panic("Unknown HP9000 Model"); panic("Unknown HP9000 Model");
} }
#ifdef CONFIG_SERIAL_8250_CONSOLE
hp300_setup_serial_console(); hp300_setup_serial_console();
#endif
} }

View File

@ -383,8 +383,8 @@ static void btmtkuart_recv(struct hci_dev *hdev, const u8 *data, size_t count)
} }
} }
static ssize_t btmtkuart_receive_buf(struct serdev_device *serdev, static size_t btmtkuart_receive_buf(struct serdev_device *serdev,
const u8 *data, size_t count) const u8 *data, size_t count)
{ {
struct btmtkuart_dev *bdev = serdev_device_get_drvdata(serdev); struct btmtkuart_dev *bdev = serdev_device_get_drvdata(serdev);

View File

@ -1285,8 +1285,8 @@ static const struct h4_recv_pkt nxp_recv_pkts[] = {
{ NXP_RECV_FW_REQ_V3, .recv = nxp_recv_fw_req_v3 }, { NXP_RECV_FW_REQ_V3, .recv = nxp_recv_fw_req_v3 },
}; };
static ssize_t btnxpuart_receive_buf(struct serdev_device *serdev, static size_t btnxpuart_receive_buf(struct serdev_device *serdev,
const u8 *data, size_t count) const u8 *data, size_t count)
{ {
struct btnxpuart_dev *nxpdev = serdev_device_get_drvdata(serdev); struct btnxpuart_dev *nxpdev = serdev_device_get_drvdata(serdev);

View File

@ -271,8 +271,8 @@ static void hci_uart_write_wakeup(struct serdev_device *serdev)
* *
* Return: number of processed bytes * Return: number of processed bytes
*/ */
static ssize_t hci_uart_receive_buf(struct serdev_device *serdev, static size_t hci_uart_receive_buf(struct serdev_device *serdev,
const u8 *data, size_t count) const u8 *data, size_t count)
{ {
struct hci_uart *hu = serdev_device_get_drvdata(serdev); struct hci_uart *hu = serdev_device_get_drvdata(serdev);

View File

@ -80,7 +80,7 @@ static const struct gnss_operations gnss_serial_gnss_ops = {
.write_raw = gnss_serial_write_raw, .write_raw = gnss_serial_write_raw,
}; };
static ssize_t gnss_serial_receive_buf(struct serdev_device *serdev, static size_t gnss_serial_receive_buf(struct serdev_device *serdev,
const u8 *buf, size_t count) const u8 *buf, size_t count)
{ {
struct gnss_serial *gserial = serdev_device_get_drvdata(serdev); struct gnss_serial *gserial = serdev_device_get_drvdata(serdev);

View File

@ -160,7 +160,7 @@ static const struct gnss_operations sirf_gnss_ops = {
.write_raw = sirf_write_raw, .write_raw = sirf_write_raw,
}; };
static ssize_t sirf_receive_buf(struct serdev_device *serdev, static size_t sirf_receive_buf(struct serdev_device *serdev,
const u8 *buf, size_t count) const u8 *buf, size_t count)
{ {
struct sirf_data *data = serdev_device_get_drvdata(serdev); struct sirf_data *data = serdev_device_get_drvdata(serdev);

View File

@ -271,7 +271,7 @@ static void hdlc_rx_frame(struct gb_beagleplay *bg)
} }
} }
static ssize_t hdlc_rx(struct gb_beagleplay *bg, const u8 *data, size_t count) static size_t hdlc_rx(struct gb_beagleplay *bg, const u8 *data, size_t count)
{ {
size_t i; size_t i;
u8 c; u8 c;
@ -331,8 +331,8 @@ static void hdlc_deinit(struct gb_beagleplay *bg)
flush_work(&bg->tx_work); flush_work(&bg->tx_work);
} }
static ssize_t gb_tty_receive(struct serdev_device *sd, const u8 *data, static size_t gb_tty_receive(struct serdev_device *sd, const u8 *data,
size_t count) size_t count)
{ {
struct gb_beagleplay *bg = serdev_device_get_drvdata(sd); struct gb_beagleplay *bg = serdev_device_get_drvdata(sd);

View File

@ -211,8 +211,8 @@ static bool pms7003_frame_is_okay(struct pms7003_frame *frame)
return checksum == pms7003_calc_checksum(frame); return checksum == pms7003_calc_checksum(frame);
} }
static ssize_t pms7003_receive_buf(struct serdev_device *serdev, const u8 *buf, static size_t pms7003_receive_buf(struct serdev_device *serdev, const u8 *buf,
size_t size) size_t size)
{ {
struct iio_dev *indio_dev = serdev_device_get_drvdata(serdev); struct iio_dev *indio_dev = serdev_device_get_drvdata(serdev);
struct pms7003_state *state = iio_priv(indio_dev); struct pms7003_state *state = iio_priv(indio_dev);

View File

@ -174,8 +174,8 @@ static int scd30_serdev_command(struct scd30_state *state, enum scd30_cmd cmd, u
return 0; return 0;
} }
static ssize_t scd30_serdev_receive_buf(struct serdev_device *serdev, static size_t scd30_serdev_receive_buf(struct serdev_device *serdev,
const u8 *buf, size_t size) const u8 *buf, size_t size)
{ {
struct iio_dev *indio_dev = serdev_device_get_drvdata(serdev); struct iio_dev *indio_dev = serdev_device_get_drvdata(serdev);
struct scd30_serdev_priv *priv; struct scd30_serdev_priv *priv;

View File

@ -210,8 +210,8 @@ static int sps30_serial_command(struct sps30_state *state, unsigned char cmd,
return rsp_size; return rsp_size;
} }
static ssize_t sps30_serial_receive_buf(struct serdev_device *serdev, static size_t sps30_serial_receive_buf(struct serdev_device *serdev,
const u8 *buf, size_t size) const u8 *buf, size_t size)
{ {
struct iio_dev *indio_dev = dev_get_drvdata(&serdev->dev); struct iio_dev *indio_dev = dev_get_drvdata(&serdev->dev);
struct sps30_serial_priv *priv; struct sps30_serial_priv *priv;

View File

@ -378,8 +378,8 @@ static void bno055_ser_handle_rx(struct bno055_ser_priv *priv, int status)
* Also, we assume to RX one pkt per time (i.e. the HW doesn't send anything * Also, we assume to RX one pkt per time (i.e. the HW doesn't send anything
* unless we require to AND we don't queue more than one request per time). * unless we require to AND we don't queue more than one request per time).
*/ */
static ssize_t bno055_ser_receive_buf(struct serdev_device *serdev, static size_t bno055_ser_receive_buf(struct serdev_device *serdev,
const u8 *buf, size_t size) const u8 *buf, size_t size)
{ {
int status; int status;
struct bno055_ser_priv *priv = serdev_device_get_drvdata(serdev); struct bno055_ser_priv *priv = serdev_device_get_drvdata(serdev);

View File

@ -26,7 +26,7 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Amiga keyboard driver"); MODULE_DESCRIPTION("Amiga keyboard driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
#ifdef CONFIG_HW_CONSOLE #ifdef CONFIG_VT
static unsigned char amikbd_keycode[0x78] __initdata = { static unsigned char amikbd_keycode[0x78] __initdata = {
[0] = KEY_GRAVE, [0] = KEY_GRAVE,
[1] = KEY_1, [1] = KEY_1,
@ -148,9 +148,9 @@ static void __init amikbd_init_console_keymaps(void)
memcpy(key_maps[i], temp_map, sizeof(temp_map)); memcpy(key_maps[i], temp_map, sizeof(temp_map));
} }
} }
#else /* !CONFIG_HW_CONSOLE */ #else /* !CONFIG_VT */
static inline void amikbd_init_console_keymaps(void) {} static inline void amikbd_init_console_keymaps(void) {}
#endif /* !CONFIG_HW_CONSOLE */ #endif /* !CONFIG_VT */
static const char *amikbd_messages[8] = { static const char *amikbd_messages[8] = {
[0] = KERN_ALERT "amikbd: Ctrl-Amiga-Amiga reset warning!!\n", [0] = KERN_ALERT "amikbd: Ctrl-Amiga-Amiga reset warning!!\n",

View File

@ -471,8 +471,8 @@ static void rave_sp_receive_frame(struct rave_sp *sp,
rave_sp_receive_reply(sp, data, length); rave_sp_receive_reply(sp, data, length);
} }
static ssize_t rave_sp_receive_buf(struct serdev_device *serdev, static size_t rave_sp_receive_buf(struct serdev_device *serdev,
const u8 *buf, size_t size) const u8 *buf, size_t size)
{ {
struct device *dev = &serdev->dev; struct device *dev = &serdev->dev;
struct rave_sp *sp = dev_get_drvdata(dev); struct rave_sp *sp = dev_get_drvdata(dev);

View File

@ -45,7 +45,7 @@ struct qcauart {
unsigned char *tx_buffer; unsigned char *tx_buffer;
}; };
static ssize_t static size_t
qca_tty_receive(struct serdev_device *serdev, const u8 *data, size_t count) qca_tty_receive(struct serdev_device *serdev, const u8 *data, size_t count)
{ {
struct qcauart *qca = serdev_device_get_drvdata(serdev); struct qcauart *qca = serdev_device_get_drvdata(serdev);

View File

@ -203,8 +203,8 @@ static int pn532_uart_rx_is_frame(struct sk_buff *skb)
return 0; return 0;
} }
static ssize_t pn532_receive_buf(struct serdev_device *serdev, static size_t pn532_receive_buf(struct serdev_device *serdev,
const u8 *data, size_t count) const u8 *data, size_t count)
{ {
struct pn532_uart_phy *dev = serdev_device_get_drvdata(serdev); struct pn532_uart_phy *dev = serdev_device_get_drvdata(serdev);
size_t i; size_t i;

View File

@ -51,8 +51,8 @@ static const struct s3fwrn5_phy_ops uart_phy_ops = {
.write = s3fwrn82_uart_write, .write = s3fwrn82_uart_write,
}; };
static ssize_t s3fwrn82_uart_read(struct serdev_device *serdev, static size_t s3fwrn82_uart_read(struct serdev_device *serdev,
const u8 *data, size_t count) const u8 *data, size_t count)
{ {
struct s3fwrn82_uart_phy *phy = serdev_device_get_drvdata(serdev); struct s3fwrn82_uart_phy *phy = serdev_device_get_drvdata(serdev);
size_t i; size_t i;

View File

@ -81,8 +81,8 @@ struct cros_ec_uart {
struct response_info response; struct response_info response;
}; };
static ssize_t cros_ec_uart_rx_bytes(struct serdev_device *serdev, static size_t cros_ec_uart_rx_bytes(struct serdev_device *serdev,
const u8 *data, size_t count) const u8 *data, size_t count)
{ {
struct ec_host_response *host_response; struct ec_host_response *host_response;
struct cros_ec_device *ec_dev = serdev_device_get_drvdata(serdev); struct cros_ec_device *ec_dev = serdev_device_get_drvdata(serdev);

View File

@ -227,8 +227,8 @@ EXPORT_SYMBOL_GPL(ssam_client_bind);
/* -- Glue layer (serdev_device -> ssam_controller). ------------------------ */ /* -- Glue layer (serdev_device -> ssam_controller). ------------------------ */
static ssize_t ssam_receive_buf(struct serdev_device *dev, const u8 *buf, static size_t ssam_receive_buf(struct serdev_device *dev, const u8 *buf,
size_t n) size_t n)
{ {
struct ssam_controller *ctrl; struct ssam_controller *ctrl;
int ret; int ret;

View File

@ -75,14 +75,9 @@ config VT_CONSOLE_SLEEP
def_bool y def_bool y
depends on VT_CONSOLE && PM_SLEEP depends on VT_CONSOLE && PM_SLEEP
config HW_CONSOLE
bool
depends on VT
default y
config VT_HW_CONSOLE_BINDING config VT_HW_CONSOLE_BINDING
bool "Support for binding and unbinding console drivers" bool "Support for binding and unbinding console drivers"
depends on HW_CONSOLE depends on VT
help help
The virtual terminal is the device that interacts with the physical The virtual terminal is the device that interacts with the physical
terminal through console drivers. On these systems, at least one terminal through console drivers. On these systems, at least one

View File

@ -1566,7 +1566,7 @@ fail_tty_driver_kref_put:
return error; return error;
} }
static int __exit amiga_serial_remove(struct platform_device *pdev) static void __exit amiga_serial_remove(struct platform_device *pdev)
{ {
struct serial_state *state = platform_get_drvdata(pdev); struct serial_state *state = platform_get_drvdata(pdev);
@ -1576,12 +1576,10 @@ static int __exit amiga_serial_remove(struct platform_device *pdev)
free_irq(IRQ_AMIGA_TBE, state); free_irq(IRQ_AMIGA_TBE, state);
free_irq(IRQ_AMIGA_RBF, state); free_irq(IRQ_AMIGA_RBF, state);
return 0;
} }
static struct platform_driver amiga_serial_driver = { static struct platform_driver amiga_serial_driver = {
.remove = __exit_p(amiga_serial_remove), .remove_new = __exit_p(amiga_serial_remove),
.driver = { .driver = {
.name = "amiga-serial", .name = "amiga-serial",
}, },

View File

@ -408,7 +408,7 @@ err_unmap:
return ret; return ret;
} }
static int goldfish_tty_remove(struct platform_device *pdev) static void goldfish_tty_remove(struct platform_device *pdev)
{ {
struct goldfish_tty *qtty = platform_get_drvdata(pdev); struct goldfish_tty *qtty = platform_get_drvdata(pdev);
@ -424,7 +424,6 @@ static int goldfish_tty_remove(struct platform_device *pdev)
if (goldfish_tty_current_line_count == 0) if (goldfish_tty_current_line_count == 0)
goldfish_tty_delete_driver(); goldfish_tty_delete_driver();
mutex_unlock(&goldfish_tty_lock); mutex_unlock(&goldfish_tty_lock);
return 0;
} }
#ifdef CONFIG_GOLDFISH_TTY_EARLY_CONSOLE #ifdef CONFIG_GOLDFISH_TTY_EARLY_CONSOLE
@ -462,7 +461,7 @@ MODULE_DEVICE_TABLE(of, goldfish_tty_of_match);
static struct platform_driver goldfish_tty_platform_driver = { static struct platform_driver goldfish_tty_platform_driver = {
.probe = goldfish_tty_probe, .probe = goldfish_tty_probe,
.remove = goldfish_tty_remove, .remove_new = goldfish_tty_remove,
.driver = { .driver = {
.name = "goldfish_tty", .name = "goldfish_tty",
.of_match_table = goldfish_tty_of_match, .of_match_table = goldfish_tty_of_match,

View File

@ -1035,6 +1035,10 @@ static const struct attribute_group *hvc_iucv_dev_attr_groups[] = {
NULL, NULL,
}; };
static void hvc_iucv_free(struct device *data)
{
kfree(data);
}
/** /**
* hvc_iucv_alloc() - Allocates a new struct hvc_iucv_private instance * hvc_iucv_alloc() - Allocates a new struct hvc_iucv_private instance
@ -1097,7 +1101,7 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console)
priv->dev->bus = &iucv_bus; priv->dev->bus = &iucv_bus;
priv->dev->parent = iucv_root; priv->dev->parent = iucv_root;
priv->dev->groups = hvc_iucv_dev_attr_groups; priv->dev->groups = hvc_iucv_dev_attr_groups;
priv->dev->release = (void (*)(struct device *)) kfree; priv->dev->release = hvc_iucv_free;
rc = device_register(priv->dev); rc = device_register(priv->dev);
if (rc) { if (rc) {
put_device(priv->dev); put_device(priv->dev);

View File

@ -431,7 +431,7 @@ static void serdev_drv_remove(struct device *dev)
dev_pm_domain_detach(dev, true); dev_pm_domain_detach(dev, true);
} }
static struct bus_type serdev_bus_type = { static const struct bus_type serdev_bus_type = {
.name = "serial", .name = "serial",
.match = serdev_device_match, .match = serdev_device_match,
.probe = serdev_drv_probe, .probe = serdev_drv_probe,

View File

@ -27,19 +27,17 @@ static size_t ttyport_receive_buf(struct tty_port *port, const u8 *cp,
{ {
struct serdev_controller *ctrl = port->client_data; struct serdev_controller *ctrl = port->client_data;
struct serport *serport = serdev_controller_get_drvdata(ctrl); struct serport *serport = serdev_controller_get_drvdata(ctrl);
int ret; size_t ret;
if (!test_bit(SERPORT_ACTIVE, &serport->flags)) if (!test_bit(SERPORT_ACTIVE, &serport->flags))
return 0; return 0;
ret = serdev_controller_receive_buf(ctrl, cp, count); ret = serdev_controller_receive_buf(ctrl, cp, count);
dev_WARN_ONCE(&ctrl->dev, ret < 0 || ret > count, dev_WARN_ONCE(&ctrl->dev, ret > count,
"receive_buf returns %d (count = %zu)\n", "receive_buf returns %zu (count = %zu)\n",
ret, count); ret, count);
if (ret < 0) if (ret > count)
return 0;
else if (ret > count)
return count; return count;
return ret; return ret;

View File

@ -419,8 +419,8 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
struct aspeed_vuart *vuart; struct aspeed_vuart *vuart;
struct device_node *np; struct device_node *np;
struct resource *res; struct resource *res;
u32 clk, prop, sirq[2];
int rc, sirq_polarity; int rc, sirq_polarity;
u32 prop, sirq[2];
struct clk *vclk; struct clk *vclk;
np = pdev->dev.of_node; np = pdev->dev.of_node;
@ -447,53 +447,35 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
port.port.status = UPSTAT_SYNC_FIFO; port.port.status = UPSTAT_SYNC_FIFO;
port.port.dev = &pdev->dev; port.port.dev = &pdev->dev;
port.port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE); port.port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE);
port.port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_FIXED_PORT | UPF_FIXED_TYPE |
UPF_NO_THRE_TEST;
port.bugs |= UART_BUG_TXRACE; port.bugs |= UART_BUG_TXRACE;
rc = sysfs_create_group(&vuart->dev->kobj, &aspeed_vuart_attr_group); rc = sysfs_create_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
if (rc < 0) if (rc < 0)
return rc; return rc;
if (of_property_read_u32(np, "clock-frequency", &clk)) { rc = uart_read_port_properties(&port.port);
if (rc)
goto err_sysfs_remove;
/* Get clk rate through clk driver if present */
if (!port.port.uartclk) {
vclk = devm_clk_get_enabled(dev, NULL); vclk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(vclk)) { if (IS_ERR(vclk)) {
rc = dev_err_probe(dev, PTR_ERR(vclk), "clk or clock-frequency not defined\n"); rc = dev_err_probe(dev, PTR_ERR(vclk), "clk or clock-frequency not defined\n");
goto err_sysfs_remove; goto err_sysfs_remove;
} }
clk = clk_get_rate(vclk); port.port.uartclk = clk_get_rate(vclk);
} }
/* If current-speed was set, then try not to change it. */ /* If current-speed was set, then try not to change it. */
if (of_property_read_u32(np, "current-speed", &prop) == 0) if (of_property_read_u32(np, "current-speed", &prop) == 0)
port.port.custom_divisor = clk / (16 * prop); port.port.custom_divisor = port.port.uartclk / (16 * prop);
/* Check for shifted address mapping */
if (of_property_read_u32(np, "reg-offset", &prop) == 0)
port.port.mapbase += prop;
/* Check for registers offset within the devices address range */
if (of_property_read_u32(np, "reg-shift", &prop) == 0)
port.port.regshift = prop;
/* Check for fifo size */
if (of_property_read_u32(np, "fifo-size", &prop) == 0)
port.port.fifosize = prop;
/* Check for a fixed line number */
rc = of_alias_get_id(np, "serial");
if (rc >= 0)
port.port.line = rc;
port.port.irq = irq_of_parse_and_map(np, 0);
port.port.handle_irq = aspeed_vuart_handle_irq; port.port.handle_irq = aspeed_vuart_handle_irq;
port.port.iotype = UPIO_MEM;
port.port.type = PORT_ASPEED_VUART; port.port.type = PORT_ASPEED_VUART;
port.port.uartclk = clk;
port.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP
| UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_NO_THRE_TEST;
if (of_property_read_bool(np, "no-loopback-test"))
port.port.flags |= UPF_SKIP_TEST;
if (port.port.fifosize) if (port.port.fifosize)
port.capabilities = UART_CAP_FIFO; port.capabilities = UART_CAP_FIFO;
@ -503,7 +485,7 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
rc = serial8250_register_8250_port(&port); rc = serial8250_register_8250_port(&port);
if (rc < 0) if (rc < 0)
goto err_clk_disable; goto err_sysfs_remove;
vuart->line = rc; vuart->line = rc;
vuart->port = serial8250_get_port(vuart->line); vuart->port = serial8250_get_port(vuart->line);
@ -529,7 +511,7 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
rc = aspeed_vuart_set_lpc_address(vuart, prop); rc = aspeed_vuart_set_lpc_address(vuart, prop);
if (rc < 0) { if (rc < 0) {
dev_err_probe(dev, rc, "invalid value in aspeed,lpc-io-reg property\n"); dev_err_probe(dev, rc, "invalid value in aspeed,lpc-io-reg property\n");
goto err_clk_disable; goto err_sysfs_remove;
} }
rc = of_property_read_u32_array(np, "aspeed,lpc-interrupts", sirq, 2); rc = of_property_read_u32_array(np, "aspeed,lpc-interrupts", sirq, 2);
@ -541,14 +523,14 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
rc = aspeed_vuart_set_sirq(vuart, sirq[0]); rc = aspeed_vuart_set_sirq(vuart, sirq[0]);
if (rc < 0) { if (rc < 0) {
dev_err_probe(dev, rc, "invalid sirq number in aspeed,lpc-interrupts property\n"); dev_err_probe(dev, rc, "invalid sirq number in aspeed,lpc-interrupts property\n");
goto err_clk_disable; goto err_sysfs_remove;
} }
sirq_polarity = aspeed_vuart_map_irq_polarity(sirq[1]); sirq_polarity = aspeed_vuart_map_irq_polarity(sirq[1]);
if (sirq_polarity < 0) { if (sirq_polarity < 0) {
rc = dev_err_probe(dev, sirq_polarity, rc = dev_err_probe(dev, sirq_polarity,
"invalid sirq polarity in aspeed,lpc-interrupts property\n"); "invalid sirq polarity in aspeed,lpc-interrupts property\n");
goto err_clk_disable; goto err_sysfs_remove;
} }
aspeed_vuart_set_sirq_polarity(vuart, sirq_polarity); aspeed_vuart_set_sirq_polarity(vuart, sirq_polarity);
@ -559,8 +541,6 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
return 0; return 0;
err_clk_disable:
irq_dispose_mapping(port.port.irq);
err_sysfs_remove: err_sysfs_remove:
sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group); sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
return rc; return rc;

View File

@ -45,10 +45,6 @@ struct bcm2835aux_data {
u32 cntl; u32 cntl;
}; };
struct bcm2835_aux_serial_driver_data {
resource_size_t offset;
};
static void bcm2835aux_rs485_start_tx(struct uart_8250_port *up) static void bcm2835aux_rs485_start_tx(struct uart_8250_port *up)
{ {
if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) { if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) {
@ -85,10 +81,9 @@ static void bcm2835aux_rs485_stop_tx(struct uart_8250_port *up)
static int bcm2835aux_serial_probe(struct platform_device *pdev) static int bcm2835aux_serial_probe(struct platform_device *pdev)
{ {
const struct bcm2835_aux_serial_driver_data *bcm_data; const struct software_node *bcm2835_swnode;
struct uart_8250_port up = { }; struct uart_8250_port up = { };
struct bcm2835aux_data *data; struct bcm2835aux_data *data;
resource_size_t offset = 0;
struct resource *res; struct resource *res;
unsigned int uartclk; unsigned int uartclk;
int ret; int ret;
@ -101,12 +96,8 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
/* initialize data */ /* initialize data */
up.capabilities = UART_CAP_FIFO | UART_CAP_MINI; up.capabilities = UART_CAP_FIFO | UART_CAP_MINI;
up.port.dev = &pdev->dev; up.port.dev = &pdev->dev;
up.port.regshift = 2;
up.port.type = PORT_16550; up.port.type = PORT_16550;
up.port.iotype = UPIO_MEM; up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SKIP_TEST | UPF_IOREMAP;
up.port.fifosize = 8;
up.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE |
UPF_SKIP_TEST | UPF_IOREMAP;
up.port.rs485_config = serial8250_em485_config; up.port.rs485_config = serial8250_em485_config;
up.port.rs485_supported = serial8250_em485_supported; up.port.rs485_supported = serial8250_em485_supported;
up.rs485_start_tx = bcm2835aux_rs485_start_tx; up.rs485_start_tx = bcm2835aux_rs485_start_tx;
@ -122,12 +113,6 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
if (IS_ERR(data->clk)) if (IS_ERR(data->clk))
return dev_err_probe(&pdev->dev, PTR_ERR(data->clk), "could not get clk\n"); return dev_err_probe(&pdev->dev, PTR_ERR(data->clk), "could not get clk\n");
/* get the interrupt */
ret = platform_get_irq(pdev, 0);
if (ret < 0)
return ret;
up.port.irq = ret;
/* map the main registers */ /* map the main registers */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) { if (!res) {
@ -135,52 +120,40 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
return -EINVAL; return -EINVAL;
} }
bcm_data = device_get_match_data(&pdev->dev); up.port.mapbase = res->start;
up.port.mapsize = resource_size(res);
/* Some UEFI implementations (e.g. tianocore/edk2 for the Raspberry Pi) bcm2835_swnode = device_get_match_data(&pdev->dev);
* describe the miniuart with a base address that encompasses the auxiliary if (bcm2835_swnode) {
* registers shared between the miniuart and spi. ret = device_add_software_node(&pdev->dev, bcm2835_swnode);
* if (ret)
* This is due to historical reasons, see discussion here : return ret;
* https://edk2.groups.io/g/devel/topic/87501357#84349 }
*
* We need to add the offset between the miniuart and auxiliary
* registers to get the real miniuart base address.
*/
if (bcm_data)
offset = bcm_data->offset;
up.port.mapbase = res->start + offset; ret = uart_read_port_properties(&up.port);
up.port.mapsize = resource_size(res) - offset; if (ret)
goto rm_swnode;
/* Check for a fixed line number */ up.port.regshift = 2;
ret = of_alias_get_id(pdev->dev.of_node, "serial"); up.port.fifosize = 8;
if (ret >= 0)
up.port.line = ret;
/* enable the clock as a last step */ /* enable the clock as a last step */
ret = clk_prepare_enable(data->clk); ret = clk_prepare_enable(data->clk);
if (ret) { if (ret) {
dev_err(&pdev->dev, "unable to enable uart clock - %d\n", dev_err_probe(&pdev->dev, ret, "unable to enable uart clock\n");
ret); goto rm_swnode;
return ret;
} }
uartclk = clk_get_rate(data->clk); uartclk = clk_get_rate(data->clk);
if (!uartclk) { if (uartclk)
ret = device_property_read_u32(&pdev->dev, "clock-frequency", &uartclk); up.port.uartclk = uartclk;
if (ret) {
dev_err_probe(&pdev->dev, ret, "could not get clk rate\n");
goto dis_clk;
}
}
/* the HW-clock divider for bcm2835aux is 8, /* the HW-clock divider for bcm2835aux is 8,
* but 8250 expects a divider of 16, * but 8250 expects a divider of 16,
* so we have to multiply the actual clock by 2 * so we have to multiply the actual clock by 2
* to get identical baudrates. * to get identical baudrates.
*/ */
up.port.uartclk = uartclk * 2; up.port.uartclk *= 2;
/* register the port */ /* register the port */
ret = serial8250_register_8250_port(&up); ret = serial8250_register_8250_port(&up);
@ -194,6 +167,8 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
dis_clk: dis_clk:
clk_disable_unprepare(data->clk); clk_disable_unprepare(data->clk);
rm_swnode:
device_remove_software_node(&pdev->dev);
return ret; return ret;
} }
@ -203,10 +178,27 @@ static void bcm2835aux_serial_remove(struct platform_device *pdev)
serial8250_unregister_port(data->line); serial8250_unregister_port(data->line);
clk_disable_unprepare(data->clk); clk_disable_unprepare(data->clk);
device_remove_software_node(&pdev->dev);
} }
static const struct bcm2835_aux_serial_driver_data bcm2835_acpi_data = { /*
.offset = 0x40, * Some UEFI implementations (e.g. tianocore/edk2 for the Raspberry Pi)
* describe the miniuart with a base address that encompasses the auxiliary
* registers shared between the miniuart and spi.
*
* This is due to historical reasons, see discussion here:
* https://edk2.groups.io/g/devel/topic/87501357#84349
*
* We need to add the offset between the miniuart and auxiliary registers
* to get the real miniuart base address.
*/
static const struct property_entry bcm2835_acpi_properties[] = {
PROPERTY_ENTRY_U32("reg-offset", 0x40),
{ }
};
static const struct software_node bcm2835_acpi_node = {
.properties = bcm2835_acpi_properties,
}; };
static const struct of_device_id bcm2835aux_serial_match[] = { static const struct of_device_id bcm2835aux_serial_match[] = {
@ -216,7 +208,7 @@ static const struct of_device_id bcm2835aux_serial_match[] = {
MODULE_DEVICE_TABLE(of, bcm2835aux_serial_match); MODULE_DEVICE_TABLE(of, bcm2835aux_serial_match);
static const struct acpi_device_id bcm2835aux_serial_acpi_match[] = { static const struct acpi_device_id bcm2835aux_serial_acpi_match[] = {
{ "BCM2836", (kernel_ulong_t)&bcm2835_acpi_data }, { "BCM2836", (kernel_ulong_t)&bcm2835_acpi_node },
{ } { }
}; };
MODULE_DEVICE_TABLE(acpi, bcm2835aux_serial_acpi_match); MODULE_DEVICE_TABLE(acpi, bcm2835aux_serial_acpi_match);

View File

@ -22,6 +22,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/units.h>
#include "8250.h" #include "8250.h"
@ -187,21 +188,19 @@
#define TX_BUF_SIZE 4096 #define TX_BUF_SIZE 4096
#define RX_BUF_SIZE 4096 #define RX_BUF_SIZE 4096
#define RX_BUFS_COUNT 2 #define RX_BUFS_COUNT 2
#define KHZ 1000
#define MHZ(x) ((x) * KHZ * KHZ)
static const u32 brcmstb_rate_table[] = { static const u32 brcmstb_rate_table[] = {
MHZ(81), 81 * HZ_PER_MHZ,
MHZ(108), 108 * HZ_PER_MHZ,
MHZ(64), /* Actually 64285715 for some chips */ 64 * HZ_PER_MHZ, /* Actually 64285715 for some chips */
MHZ(48), 48 * HZ_PER_MHZ,
}; };
static const u32 brcmstb_rate_table_7278[] = { static const u32 brcmstb_rate_table_7278[] = {
MHZ(81), 81 * HZ_PER_MHZ,
MHZ(108), 108 * HZ_PER_MHZ,
0, 0,
MHZ(48), 48 * HZ_PER_MHZ,
}; };
struct brcmuart_priv { struct brcmuart_priv {
@ -936,17 +935,14 @@ static void brcmuart_init_debugfs(struct brcmuart_priv *priv,
static int brcmuart_probe(struct platform_device *pdev) static int brcmuart_probe(struct platform_device *pdev)
{ {
struct resource *regs; struct resource *regs;
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *of_id = NULL; const struct of_device_id *of_id = NULL;
struct uart_8250_port *new_port; struct uart_8250_port *new_port;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct brcmuart_priv *priv; struct brcmuart_priv *priv;
struct clk *baud_mux_clk; struct clk *baud_mux_clk;
struct uart_8250_port up; struct uart_8250_port up;
int irq;
void __iomem *membase = NULL; void __iomem *membase = NULL;
resource_size_t mapbase = 0; resource_size_t mapbase = 0;
u32 clk_rate = 0;
int ret; int ret;
int x; int x;
int dma_irq; int dma_irq;
@ -954,15 +950,12 @@ static int brcmuart_probe(struct platform_device *pdev)
"uart", "dma_rx", "dma_tx", "dma_intr2", "dma_arb" "uart", "dma_rx", "dma_tx", "dma_intr2", "dma_arb"
}; };
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
priv = devm_kzalloc(dev, sizeof(struct brcmuart_priv), priv = devm_kzalloc(dev, sizeof(struct brcmuart_priv),
GFP_KERNEL); GFP_KERNEL);
if (!priv) if (!priv)
return -ENOMEM; return -ENOMEM;
of_id = of_match_node(brcmuart_dt_ids, np); of_id = of_match_node(brcmuart_dt_ids, dev->of_node);
if (!of_id || !of_id->data) if (!of_id || !of_id->data)
priv->rate_table = brcmstb_rate_table; priv->rate_table = brcmstb_rate_table;
else else
@ -1012,7 +1005,23 @@ static int brcmuart_probe(struct platform_device *pdev)
} }
} }
of_property_read_u32(np, "clock-frequency", &clk_rate); dev_dbg(dev, "DMA is %senabled\n", priv->dma_enabled ? "" : "not ");
memset(&up, 0, sizeof(up));
up.port.type = PORT_BCM7271;
up.port.dev = dev;
up.port.mapbase = mapbase;
up.port.membase = membase;
up.port.handle_irq = brcmuart_handle_irq;
up.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_FIXED_TYPE;
up.port.private_data = priv;
ret = uart_read_port_properties(&up.port);
if (ret)
goto release_dma;
up.port.regshift = 2;
up.port.iotype = device_is_big_endian(dev) ? UPIO_MEM32BE : UPIO_MEM32;
/* See if a Baud clock has been specified */ /* See if a Baud clock has been specified */
baud_mux_clk = devm_clk_get_optional_enabled(dev, "sw_baud"); baud_mux_clk = devm_clk_get_optional_enabled(dev, "sw_baud");
@ -1024,39 +1033,11 @@ static int brcmuart_probe(struct platform_device *pdev)
priv->baud_mux_clk = baud_mux_clk; priv->baud_mux_clk = baud_mux_clk;
init_real_clk_rates(dev, priv); init_real_clk_rates(dev, priv);
clk_rate = priv->default_mux_rate; up.port.uartclk = priv->default_mux_rate;
} else { } else {
dev_dbg(dev, "BAUD MUX clock not specified\n"); dev_dbg(dev, "BAUD MUX clock not specified\n");
} }
if (clk_rate == 0) {
ret = dev_err_probe(dev, -EINVAL, "clock-frequency or clk not defined\n");
goto release_dma;
}
dev_dbg(dev, "DMA is %senabled\n", priv->dma_enabled ? "" : "not ");
memset(&up, 0, sizeof(up));
up.port.type = PORT_BCM7271;
up.port.uartclk = clk_rate;
up.port.dev = dev;
up.port.mapbase = mapbase;
up.port.membase = membase;
up.port.irq = irq;
up.port.handle_irq = brcmuart_handle_irq;
up.port.regshift = 2;
up.port.iotype = of_device_is_big_endian(np) ?
UPIO_MEM32BE : UPIO_MEM32;
up.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF
| UPF_FIXED_PORT | UPF_FIXED_TYPE;
up.port.dev = dev;
up.port.private_data = priv;
/* Check for a fixed line number */
ret = of_alias_get_id(np, "serial");
if (ret >= 0)
up.port.line = ret;
/* setup HR timer */ /* setup HR timer */
hrtimer_init(&priv->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); hrtimer_init(&priv->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
priv->hrt.function = brcmuart_hrtimer_func; priv->hrt.function = brcmuart_hrtimer_func;

View File

@ -9,7 +9,6 @@
* LCR is written whilst busy. If it is, then a busy detect interrupt is * LCR is written whilst busy. If it is, then a busy detect interrupt is
* raised, the LCR needs to be rewritten and the uart status register read. * raised, the LCR needs to be rewritten and the uart status register read.
*/ */
#include <linux/acpi.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/device.h> #include <linux/device.h>
@ -17,7 +16,6 @@
#include <linux/mod_devicetable.h> #include <linux/mod_devicetable.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/of.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/property.h> #include <linux/property.h>
@ -56,6 +54,7 @@
#define DW_UART_QUIRK_ARMADA_38X BIT(1) #define DW_UART_QUIRK_ARMADA_38X BIT(1)
#define DW_UART_QUIRK_SKIP_SET_RATE BIT(2) #define DW_UART_QUIRK_SKIP_SET_RATE BIT(2)
#define DW_UART_QUIRK_IS_DMA_FC BIT(3) #define DW_UART_QUIRK_IS_DMA_FC BIT(3)
#define DW_UART_QUIRK_APMC0D08 BIT(4)
static inline struct dw8250_data *clk_to_dw8250_data(struct notifier_block *nb) static inline struct dw8250_data *clk_to_dw8250_data(struct notifier_block *nb)
{ {
@ -445,44 +444,29 @@ static void dw8250_prepare_rx_dma(struct uart_8250_port *p)
static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data) static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
{ {
struct device_node *np = p->dev->of_node; unsigned int quirks = data->pdata ? data->pdata->quirks : 0;
if (np) {
unsigned int quirks = data->pdata->quirks;
int id;
/* get index of serial line, if found in DT aliases */
id = of_alias_get_id(np, "serial");
if (id >= 0)
p->line = id;
#ifdef CONFIG_64BIT #ifdef CONFIG_64BIT
if (quirks & DW_UART_QUIRK_OCTEON) { if (quirks & DW_UART_QUIRK_OCTEON) {
p->serial_in = dw8250_serial_inq; p->serial_in = dw8250_serial_inq;
p->serial_out = dw8250_serial_outq; p->serial_out = dw8250_serial_outq;
p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE; p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
p->type = PORT_OCTEON; p->type = PORT_OCTEON;
data->skip_autocfg = true; data->skip_autocfg = true;
} }
#endif #endif
if (of_device_is_big_endian(np)) { if (quirks & DW_UART_QUIRK_ARMADA_38X)
p->iotype = UPIO_MEM32BE; p->serial_out = dw8250_serial_out38x;
p->serial_in = dw8250_serial_in32be; if (quirks & DW_UART_QUIRK_SKIP_SET_RATE)
p->serial_out = dw8250_serial_out32be; p->set_termios = dw8250_do_set_termios;
} if (quirks & DW_UART_QUIRK_IS_DMA_FC) {
data->data.dma.txconf.device_fc = 1;
if (quirks & DW_UART_QUIRK_ARMADA_38X) data->data.dma.rxconf.device_fc = 1;
p->serial_out = dw8250_serial_out38x; data->data.dma.prepare_tx_dma = dw8250_prepare_tx_dma;
if (quirks & DW_UART_QUIRK_SKIP_SET_RATE) data->data.dma.prepare_rx_dma = dw8250_prepare_rx_dma;
p->set_termios = dw8250_do_set_termios; }
if (quirks & DW_UART_QUIRK_IS_DMA_FC) { if (quirks & DW_UART_QUIRK_APMC0D08) {
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; p->iotype = UPIO_MEM32;
p->regshift = 2; p->regshift = 2;
p->serial_in = dw8250_serial_in32; p->serial_in = dw8250_serial_in32;
@ -510,39 +494,21 @@ static int dw8250_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct dw8250_data *data; struct dw8250_data *data;
struct resource *regs; struct resource *regs;
int irq;
int err; int err;
u32 val;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs) if (!regs)
return dev_err_probe(dev, -EINVAL, "no registers defined\n"); return dev_err_probe(dev, -EINVAL, "no registers defined\n");
irq = platform_get_irq_optional(pdev, 0);
/* no interrupt -> fall back to polling */
if (irq == -ENXIO)
irq = 0;
if (irq < 0)
return irq;
spin_lock_init(&p->lock); spin_lock_init(&p->lock);
p->mapbase = regs->start;
p->irq = irq;
p->handle_irq = dw8250_handle_irq; p->handle_irq = dw8250_handle_irq;
p->pm = dw8250_do_pm; p->pm = dw8250_do_pm;
p->type = PORT_8250; p->type = PORT_8250;
p->flags = UPF_SHARE_IRQ | UPF_FIXED_PORT; p->flags = UPF_FIXED_PORT;
p->dev = dev; p->dev = dev;
p->iotype = UPIO_MEM;
p->serial_in = dw8250_serial_in;
p->serial_out = dw8250_serial_out;
p->set_ldisc = dw8250_set_ldisc; p->set_ldisc = dw8250_set_ldisc;
p->set_termios = dw8250_set_termios; p->set_termios = dw8250_set_termios;
p->membase = devm_ioremap(dev, regs->start, resource_size(regs));
if (!p->membase)
return -ENOMEM;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data) if (!data)
return -ENOMEM; return -ENOMEM;
@ -554,15 +520,35 @@ static int dw8250_probe(struct platform_device *pdev)
data->uart_16550_compatible = device_property_read_bool(dev, data->uart_16550_compatible = device_property_read_bool(dev,
"snps,uart-16550-compatible"); "snps,uart-16550-compatible");
err = device_property_read_u32(dev, "reg-shift", &val); p->mapbase = regs->start;
if (!err) p->mapsize = resource_size(regs);
p->regshift = val;
err = device_property_read_u32(dev, "reg-io-width", &val); p->membase = devm_ioremap(dev, p->mapbase, p->mapsize);
if (!err && val == 4) { if (!p->membase)
p->iotype = UPIO_MEM32; return -ENOMEM;
err = uart_read_port_properties(p);
/* no interrupt -> fall back to polling */
if (err == -ENXIO)
err = 0;
if (err)
return err;
switch (p->iotype) {
case UPIO_MEM:
p->serial_in = dw8250_serial_in;
p->serial_out = dw8250_serial_out;
break;
case UPIO_MEM32:
p->serial_in = dw8250_serial_in32; p->serial_in = dw8250_serial_in32;
p->serial_out = dw8250_serial_out32; p->serial_out = dw8250_serial_out32;
break;
case UPIO_MEM32BE:
p->serial_in = dw8250_serial_in32be;
p->serial_out = dw8250_serial_out32be;
break;
default:
return -ENODEV;
} }
if (device_property_read_bool(dev, "dcd-override")) { if (device_property_read_bool(dev, "dcd-override")) {
@ -589,15 +575,13 @@ static int dw8250_probe(struct platform_device *pdev)
data->msr_mask_off |= UART_MSR_TERI; data->msr_mask_off |= UART_MSR_TERI;
} }
/* Always ask for fixed clock rate from a property. */
device_property_read_u32(dev, "clock-frequency", &p->uartclk);
/* If there is separate baudclk, get the rate from it. */ /* If there is separate baudclk, get the rate from it. */
data->clk = devm_clk_get_optional_enabled(dev, "baudclk"); data->clk = devm_clk_get_optional_enabled(dev, "baudclk");
if (data->clk == NULL) if (data->clk == NULL)
data->clk = devm_clk_get_optional_enabled(dev, NULL); data->clk = devm_clk_get_optional_enabled(dev, NULL);
if (IS_ERR(data->clk)) if (IS_ERR(data->clk))
return PTR_ERR(data->clk); return dev_err_probe(dev, PTR_ERR(data->clk),
"failed to get baudclk\n");
INIT_WORK(&data->clk_work, dw8250_clk_work_cb); INIT_WORK(&data->clk_work, dw8250_clk_work_cb);
data->clk_notifier.notifier_call = dw8250_clk_notifier_cb; data->clk_notifier.notifier_call = dw8250_clk_notifier_cb;
@ -762,13 +746,18 @@ static const struct of_device_id dw8250_of_match[] = {
}; };
MODULE_DEVICE_TABLE(of, dw8250_of_match); MODULE_DEVICE_TABLE(of, dw8250_of_match);
static const struct dw8250_platform_data dw8250_apmc0d08 = {
.usr_reg = DW_UART_USR,
.quirks = DW_UART_QUIRK_APMC0D08,
};
static const struct acpi_device_id dw8250_acpi_match[] = { static const struct acpi_device_id dw8250_acpi_match[] = {
{ "80860F0A", (kernel_ulong_t)&dw8250_dw_apb }, { "80860F0A", (kernel_ulong_t)&dw8250_dw_apb },
{ "8086228A", (kernel_ulong_t)&dw8250_dw_apb }, { "8086228A", (kernel_ulong_t)&dw8250_dw_apb },
{ "AMD0020", (kernel_ulong_t)&dw8250_dw_apb }, { "AMD0020", (kernel_ulong_t)&dw8250_dw_apb },
{ "AMDI0020", (kernel_ulong_t)&dw8250_dw_apb }, { "AMDI0020", (kernel_ulong_t)&dw8250_dw_apb },
{ "AMDI0022", (kernel_ulong_t)&dw8250_dw_apb }, { "AMDI0022", (kernel_ulong_t)&dw8250_dw_apb },
{ "APMC0D08", (kernel_ulong_t)&dw8250_dw_apb}, { "APMC0D08", (kernel_ulong_t)&dw8250_apmc0d08 },
{ "BRCM2032", (kernel_ulong_t)&dw8250_dw_apb }, { "BRCM2032", (kernel_ulong_t)&dw8250_dw_apb },
{ "HISI0031", (kernel_ulong_t)&dw8250_dw_apb }, { "HISI0031", (kernel_ulong_t)&dw8250_dw_apb },
{ "INT33C4", (kernel_ulong_t)&dw8250_dw_apb }, { "INT33C4", (kernel_ulong_t)&dw8250_dw_apb },

View File

@ -6,23 +6,29 @@
* *
* Copyright (C) 2017 Sudip Mukherjee, All Rights Reserved. * Copyright (C) 2017 Sudip Mukherjee, All Rights Reserved.
*/ */
#include <linux/acpi.h> #include <linux/bits.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dmi.h> #include <linux/dmi.h>
#include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/kernel.h> #include <linux/math.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/property.h> #include <linux/property.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/serial_8250.h>
#include <linux/serial_core.h> #include <linux/serial_core.h>
#include <linux/serial_reg.h> #include <linux/serial_reg.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/tty.h>
#include <linux/delay.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include "8250.h" #include "8250.h"
#include "8250_pcilib.h"
#define PCI_DEVICE_ID_ACCESSIO_COM_2S 0x1052 #define PCI_DEVICE_ID_ACCESSIO_COM_2S 0x1052
#define PCI_DEVICE_ID_ACCESSIO_COM_4S 0x105d #define PCI_DEVICE_ID_ACCESSIO_COM_4S 0x105d
@ -229,13 +235,12 @@ static int default_setup(struct exar8250 *priv, struct pci_dev *pcidev,
struct uart_8250_port *port) struct uart_8250_port *port)
{ {
const struct exar8250_board *board = priv->board; const struct exar8250_board *board = priv->board;
unsigned int bar = 0;
unsigned char status; unsigned char status;
int err;
port->port.iotype = UPIO_MEM; err = serial8250_pci_setup_port(pcidev, port, 0, offset, board->reg_shift);
port->port.mapbase = pci_resource_start(pcidev, bar) + offset; if (err)
port->port.membase = priv->virt + offset; return err;
port->port.regshift = board->reg_shift;
/* /*
* XR17V35x UARTs have an extra divisor register, DLD that gets enabled * XR17V35x UARTs have an extra divisor register, DLD that gets enabled
@ -375,7 +380,7 @@ static struct platform_device *__xr17v35x_register_gpio(struct pci_dev *pcidev,
return NULL; return NULL;
pdev->dev.parent = &pcidev->dev; pdev->dev.parent = &pcidev->dev;
ACPI_COMPANION_SET(&pdev->dev, ACPI_COMPANION(&pcidev->dev)); device_set_node(&pdev->dev, dev_fwnode(&pcidev->dev));
if (device_add_software_node(&pdev->dev, node) < 0 || if (device_add_software_node(&pdev->dev, node) < 0 ||
platform_device_add(pdev) < 0) { platform_device_add(pdev) < 0) {
@ -713,14 +718,14 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
uart.port.irq = pci_irq_vector(pcidev, 0); uart.port.irq = pci_irq_vector(pcidev, 0);
uart.port.dev = &pcidev->dev; uart.port.dev = &pcidev->dev;
/* Clear interrupts */
exar_misc_clear(priv);
rc = devm_request_irq(&pcidev->dev, uart.port.irq, exar_misc_handler, rc = devm_request_irq(&pcidev->dev, uart.port.irq, exar_misc_handler,
IRQF_SHARED, "exar_uart", priv); IRQF_SHARED, "exar_uart", priv);
if (rc) if (rc)
return rc; return rc;
/* Clear interrupts */
exar_misc_clear(priv);
for (i = 0; i < nr_ports && i < maxnr; i++) { for (i = 0; i < nr_ports && i < maxnr; i++) {
rc = board->setup(priv, pcidev, &uart, i); rc = board->setup(priv, pcidev, &uart, i);
if (rc) { if (rc) {
@ -753,28 +758,24 @@ static void exar_pci_remove(struct pci_dev *pcidev)
for (i = 0; i < priv->nr; i++) for (i = 0; i < priv->nr; i++)
serial8250_unregister_port(priv->line[i]); serial8250_unregister_port(priv->line[i]);
/* Ensure that every init quirk is properly torn down */
if (priv->board->exit) if (priv->board->exit)
priv->board->exit(pcidev); priv->board->exit(pcidev);
} }
static int __maybe_unused exar_suspend(struct device *dev) static int exar_suspend(struct device *dev)
{ {
struct pci_dev *pcidev = to_pci_dev(dev); struct exar8250 *priv = dev_get_drvdata(dev);
struct exar8250 *priv = pci_get_drvdata(pcidev);
unsigned int i; unsigned int i;
for (i = 0; i < priv->nr; i++) for (i = 0; i < priv->nr; i++)
if (priv->line[i] >= 0) if (priv->line[i] >= 0)
serial8250_suspend_port(priv->line[i]); serial8250_suspend_port(priv->line[i]);
/* Ensure that every init quirk is properly torn down */
if (priv->board->exit)
priv->board->exit(pcidev);
return 0; return 0;
} }
static int __maybe_unused exar_resume(struct device *dev) static int exar_resume(struct device *dev)
{ {
struct exar8250 *priv = dev_get_drvdata(dev); struct exar8250 *priv = dev_get_drvdata(dev);
unsigned int i; unsigned int i;
@ -788,7 +789,7 @@ static int __maybe_unused exar_resume(struct device *dev)
return 0; return 0;
} }
static SIMPLE_DEV_PM_OPS(exar_pci_pm, exar_suspend, exar_resume); static DEFINE_SIMPLE_DEV_PM_OPS(exar_pci_pm, exar_suspend, exar_resume);
static const struct exar8250_board pbn_fastcom335_2 = { static const struct exar8250_board pbn_fastcom335_2 = {
.num_ports = 2, .num_ports = 2,
@ -938,12 +939,13 @@ static struct pci_driver exar_pci_driver = {
.probe = exar_pci_probe, .probe = exar_pci_probe,
.remove = exar_pci_remove, .remove = exar_pci_remove,
.driver = { .driver = {
.pm = &exar_pci_pm, .pm = pm_sleep_ptr(&exar_pci_pm),
}, },
.id_table = exar_pci_tbl, .id_table = exar_pci_tbl,
}; };
module_pci_driver(exar_pci_driver); module_pci_driver(exar_pci_driver);
MODULE_IMPORT_NS(SERIAL_8250_PCI);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Exar Serial Driver"); MODULE_DESCRIPTION("Exar Serial Driver");
MODULE_AUTHOR("Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>"); MODULE_AUTHOR("Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>");

View File

@ -234,7 +234,7 @@ static int ingenic_uart_probe(struct platform_device *pdev)
struct ingenic_uart_data *data; struct ingenic_uart_data *data;
const struct ingenic_uart_config *cdata; const struct ingenic_uart_config *cdata;
struct resource *regs; struct resource *regs;
int irq, err, line; int err;
cdata = of_device_get_match_data(&pdev->dev); cdata = of_device_get_match_data(&pdev->dev);
if (!cdata) { if (!cdata) {
@ -242,10 +242,6 @@ static int ingenic_uart_probe(struct platform_device *pdev)
return -ENODEV; return -ENODEV;
} }
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs) { if (!regs) {
dev_err(&pdev->dev, "no registers defined\n"); dev_err(&pdev->dev, "no registers defined\n");
@ -259,21 +255,19 @@ static int ingenic_uart_probe(struct platform_device *pdev)
spin_lock_init(&uart.port.lock); spin_lock_init(&uart.port.lock);
uart.port.type = PORT_16550A; uart.port.type = PORT_16550A;
uart.port.flags = UPF_SKIP_TEST | UPF_IOREMAP | UPF_FIXED_TYPE; uart.port.flags = UPF_SKIP_TEST | UPF_IOREMAP | UPF_FIXED_TYPE;
uart.port.iotype = UPIO_MEM;
uart.port.mapbase = regs->start; uart.port.mapbase = regs->start;
uart.port.regshift = 2;
uart.port.serial_out = ingenic_uart_serial_out; uart.port.serial_out = ingenic_uart_serial_out;
uart.port.serial_in = ingenic_uart_serial_in; uart.port.serial_in = ingenic_uart_serial_in;
uart.port.irq = irq;
uart.port.dev = &pdev->dev; uart.port.dev = &pdev->dev;
uart.port.fifosize = cdata->fifosize;
uart.tx_loadsz = cdata->tx_loadsz; uart.tx_loadsz = cdata->tx_loadsz;
uart.capabilities = UART_CAP_FIFO | UART_CAP_RTOIE; uart.capabilities = UART_CAP_FIFO | UART_CAP_RTOIE;
/* Check for a fixed line number */ err = uart_read_port_properties(&uart.port);
line = of_alias_get_id(pdev->dev.of_node, "serial"); if (err)
if (line >= 0) return err;
uart.port.line = line;
uart.port.regshift = 2;
uart.port.fifosize = cdata->fifosize;
uart.port.membase = devm_ioremap(&pdev->dev, regs->start, uart.port.membase = devm_ioremap(&pdev->dev, regs->start,
resource_size(regs)); resource_size(regs));

View File

@ -92,11 +92,7 @@ static int lpc18xx_serial_probe(struct platform_device *pdev)
struct lpc18xx_uart_data *data; struct lpc18xx_uart_data *data;
struct uart_8250_port uart; struct uart_8250_port uart;
struct resource *res; struct resource *res;
int irq, ret; int ret;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) { if (!res) {
@ -139,19 +135,12 @@ static int lpc18xx_serial_probe(struct platform_device *pdev)
goto dis_clk_reg; goto dis_clk_reg;
} }
ret = of_alias_get_id(pdev->dev.of_node, "serial");
if (ret >= 0)
uart.port.line = ret;
data->dma.rx_param = data; data->dma.rx_param = data;
data->dma.tx_param = data; data->dma.tx_param = data;
spin_lock_init(&uart.port.lock); spin_lock_init(&uart.port.lock);
uart.port.dev = &pdev->dev; uart.port.dev = &pdev->dev;
uart.port.irq = irq;
uart.port.iotype = UPIO_MEM32;
uart.port.mapbase = res->start; uart.port.mapbase = res->start;
uart.port.regshift = 2;
uart.port.type = PORT_16550A; uart.port.type = PORT_16550A;
uart.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SKIP_TEST; uart.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SKIP_TEST;
uart.port.uartclk = clk_get_rate(data->clk_uart); uart.port.uartclk = clk_get_rate(data->clk_uart);
@ -160,6 +149,13 @@ static int lpc18xx_serial_probe(struct platform_device *pdev)
uart.port.rs485_supported = lpc18xx_rs485_supported; uart.port.rs485_supported = lpc18xx_rs485_supported;
uart.port.serial_out = lpc18xx_uart_serial_out; uart.port.serial_out = lpc18xx_uart_serial_out;
ret = uart_read_port_properties(&uart.port);
if (ret)
return ret;
uart.port.iotype = UPIO_MEM32;
uart.port.regshift = 2;
uart.dma = &data->dma; uart.dma = &data->dma;
uart.dma->rxconf.src_maxburst = 1; uart.dma->rxconf.src_maxburst = 1;
uart.dma->txconf.dst_maxburst = 1; uart.dma->txconf.dst_maxburst = 1;

View File

@ -4,7 +4,10 @@
* *
* Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de>, IBM Corp. * Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de>, IBM Corp.
*/ */
#include <linux/bits.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/math.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/serial_core.h> #include <linux/serial_core.h>
@ -25,6 +28,36 @@ struct of_serial_info {
int line; int line;
}; };
/* Nuvoton NPCM timeout register */
#define UART_NPCM_TOR 7
#define UART_NPCM_TOIE BIT(7) /* Timeout Interrupt Enable */
static int npcm_startup(struct uart_port *port)
{
/*
* Nuvoton calls the scratch register 'UART_TOR' (timeout
* register). Enable it, and set TIOC (timeout interrupt
* comparator) to be 0x20 for correct operation.
*/
serial_port_out(port, UART_NPCM_TOR, UART_NPCM_TOIE | 0x20);
return serial8250_do_startup(port);
}
/* Nuvoton NPCM UARTs have a custom divisor calculation */
static unsigned int npcm_get_divisor(struct uart_port *port, unsigned int baud,
unsigned int *frac)
{
return DIV_ROUND_CLOSEST(port->uartclk, 16 * baud + 2) - 2;
}
static int npcm_setup(struct uart_port *port)
{
port->get_divisor = npcm_get_divisor;
port->startup = npcm_startup;
return 0;
}
/* /*
* Fill a struct uart_port for a given device node * Fill a struct uart_port for a given device node
*/ */
@ -36,37 +69,22 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
struct device *dev = &ofdev->dev; struct device *dev = &ofdev->dev;
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
struct uart_port *port = &up->port; struct uart_port *port = &up->port;
u32 clk, spd, prop; u32 spd;
int ret, irq; int ret;
memset(port, 0, sizeof *port); memset(port, 0, sizeof *port);
pm_runtime_enable(&ofdev->dev); pm_runtime_enable(&ofdev->dev);
pm_runtime_get_sync(&ofdev->dev); pm_runtime_get_sync(&ofdev->dev);
if (of_property_read_u32(np, "clock-frequency", &clk)) {
/* Get clk rate through clk driver if present */
info->clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(info->clk)) {
ret = dev_err_probe(dev, PTR_ERR(info->clk), "failed to get clock\n");
goto err_pmruntime;
}
clk = clk_get_rate(info->clk);
}
/* If current-speed was set, then try not to change it. */
if (of_property_read_u32(np, "current-speed", &spd) == 0)
port->custom_divisor = clk / (16 * spd);
ret = of_address_to_resource(np, 0, &resource); ret = of_address_to_resource(np, 0, &resource);
if (ret) { if (ret) {
dev_err_probe(dev, ret, "invalid address\n"); dev_err_probe(dev, ret, "invalid address\n");
goto err_pmruntime; goto err_pmruntime;
} }
port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | port->dev = &ofdev->dev;
UPF_FIXED_TYPE; port->flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_FIXED_TYPE;
spin_lock_init(&port->lock); spin_lock_init(&port->lock);
if (resource_type(&resource) == IORESOURCE_IO) { if (resource_type(&resource) == IORESOURCE_IO) {
@ -75,70 +93,31 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
} else { } else {
port->mapbase = resource.start; port->mapbase = resource.start;
port->mapsize = resource_size(&resource); port->mapsize = resource_size(&resource);
/* Check for shifted address mapping */
if (of_property_read_u32(np, "reg-offset", &prop) == 0) {
if (prop >= port->mapsize) {
ret = dev_err_probe(dev, -EINVAL, "reg-offset %u exceeds region size %pa\n",
prop, &port->mapsize);
goto err_pmruntime;
}
port->mapbase += prop;
port->mapsize -= prop;
}
port->iotype = UPIO_MEM;
if (of_property_read_u32(np, "reg-io-width", &prop) == 0) {
switch (prop) {
case 1:
port->iotype = UPIO_MEM;
break;
case 2:
port->iotype = UPIO_MEM16;
break;
case 4:
port->iotype = of_device_is_big_endian(np) ?
UPIO_MEM32BE : UPIO_MEM32;
break;
default:
ret = dev_err_probe(dev, -EINVAL, "unsupported reg-io-width (%u)\n",
prop);
goto err_pmruntime;
}
}
port->flags |= UPF_IOREMAP; port->flags |= UPF_IOREMAP;
} }
ret = uart_read_and_validate_port_properties(port);
if (ret)
goto err_pmruntime;
/* Get clk rate through clk driver if present */
if (!port->uartclk) {
info->clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(info->clk)) {
ret = dev_err_probe(dev, PTR_ERR(info->clk), "failed to get clock\n");
goto err_pmruntime;
}
port->uartclk = clk_get_rate(info->clk);
}
/* If current-speed was set, then try not to change it. */
if (of_property_read_u32(np, "current-speed", &spd) == 0)
port->custom_divisor = port->uartclk / (16 * spd);
/* Compatibility with the deprecated pxa driver and 8250_pxa drivers. */ /* Compatibility with the deprecated pxa driver and 8250_pxa drivers. */
if (of_device_is_compatible(np, "mrvl,mmp-uart")) if (of_device_is_compatible(np, "mrvl,mmp-uart"))
port->regshift = 2; port->regshift = 2;
/* Check for registers offset within the devices address range */
if (of_property_read_u32(np, "reg-shift", &prop) == 0)
port->regshift = prop;
/* Check for fifo size */
if (of_property_read_u32(np, "fifo-size", &prop) == 0)
port->fifosize = prop;
/* Check for a fixed line number */
ret = of_alias_get_id(np, "serial");
if (ret >= 0)
port->line = ret;
irq = of_irq_get(np, 0);
if (irq < 0) {
if (irq == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
goto err_pmruntime;
}
/* IRQ support not mandatory */
irq = 0;
}
port->irq = irq;
info->rst = devm_reset_control_get_optional_shared(&ofdev->dev, NULL); info->rst = devm_reset_control_get_optional_shared(&ofdev->dev, NULL);
if (IS_ERR(info->rst)) { if (IS_ERR(info->rst)) {
ret = PTR_ERR(info->rst); ret = PTR_ERR(info->rst);
@ -150,12 +129,6 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
goto err_pmruntime; goto err_pmruntime;
port->type = type; port->type = type;
port->uartclk = clk;
if (of_property_read_bool(np, "no-loopback-test"))
port->flags |= UPF_SKIP_TEST;
port->dev = &ofdev->dev;
port->rs485_config = serial8250_em485_config; port->rs485_config = serial8250_em485_config;
port->rs485_supported = serial8250_em485_supported; port->rs485_supported = serial8250_em485_supported;
up->rs485_start_tx = serial8250_em485_start_tx; up->rs485_start_tx = serial8250_em485_start_tx;
@ -164,10 +137,17 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
switch (type) { switch (type) {
case PORT_RT2880: case PORT_RT2880:
ret = rt288x_setup(port); ret = rt288x_setup(port);
if (ret) break;
goto err_pmruntime; case PORT_NPCM:
ret = npcm_setup(port);
break;
default:
/* Nothing to do */
ret = 0;
break; break;
} }
if (ret)
goto err_pmruntime;
if (IS_REACHABLE(CONFIG_SERIAL_8250_FSL) && if (IS_REACHABLE(CONFIG_SERIAL_8250_FSL) &&
(of_device_is_compatible(np, "fsl,ns16550") || (of_device_is_compatible(np, "fsl,ns16550") ||
@ -240,7 +220,6 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
platform_set_drvdata(ofdev, info); platform_set_drvdata(ofdev, info);
return 0; return 0;
err_dispose: err_dispose:
irq_dispose_mapping(port8250.port.irq);
pm_runtime_put_sync(&ofdev->dev); pm_runtime_put_sync(&ofdev->dev);
pm_runtime_disable(&ofdev->dev); pm_runtime_disable(&ofdev->dev);
err_free: err_free:

View File

@ -1394,11 +1394,7 @@ static int omap8250_probe(struct platform_device *pdev)
struct uart_8250_port up; struct uart_8250_port up;
struct resource *regs; struct resource *regs;
void __iomem *membase; void __iomem *membase;
int irq, ret; int ret;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs) { if (!regs) {
@ -1419,7 +1415,6 @@ static int omap8250_probe(struct platform_device *pdev)
up.port.dev = &pdev->dev; up.port.dev = &pdev->dev;
up.port.mapbase = regs->start; up.port.mapbase = regs->start;
up.port.membase = membase; up.port.membase = membase;
up.port.irq = irq;
/* /*
* It claims to be 16C750 compatible however it is a little different. * It claims to be 16C750 compatible however it is a little different.
* It has EFR and has no FCR7_64byte bit. The AFE (which it claims to * It has EFR and has no FCR7_64byte bit. The AFE (which it claims to
@ -1429,13 +1424,9 @@ static int omap8250_probe(struct platform_device *pdev)
* or pm callback. * or pm callback.
*/ */
up.port.type = PORT_8250; up.port.type = PORT_8250;
up.port.iotype = UPIO_MEM; up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SOFT_FLOW | UPF_HARD_FLOW;
up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SOFT_FLOW |
UPF_HARD_FLOW;
up.port.private_data = priv; up.port.private_data = priv;
up.port.regshift = OMAP_UART_REGSHIFT;
up.port.fifosize = 64;
up.tx_loadsz = 64; up.tx_loadsz = 64;
up.capabilities = UART_CAP_FIFO; up.capabilities = UART_CAP_FIFO;
#ifdef CONFIG_PM #ifdef CONFIG_PM
@ -1461,14 +1452,14 @@ static int omap8250_probe(struct platform_device *pdev)
up.rs485_stop_tx = serial8250_em485_stop_tx; up.rs485_stop_tx = serial8250_em485_stop_tx;
up.port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE); up.port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE);
ret = of_alias_get_id(np, "serial"); ret = uart_read_port_properties(&up.port);
if (ret < 0) { if (ret)
dev_err(&pdev->dev, "failed to get alias\n");
return ret; return ret;
}
up.port.line = ret;
if (of_property_read_u32(np, "clock-frequency", &up.port.uartclk)) { up.port.regshift = OMAP_UART_REGSHIFT;
up.port.fifosize = 64;
if (!up.port.uartclk) {
struct clk *clk; struct clk *clk;
clk = devm_clk_get(&pdev->dev, NULL); clk = devm_clk_get(&pdev->dev, NULL);
@ -1560,8 +1551,8 @@ static int omap8250_probe(struct platform_device *pdev)
} }
#endif #endif
irq_set_status_flags(irq, IRQ_NOAUTOEN); irq_set_status_flags(up.port.irq, IRQ_NOAUTOEN);
ret = devm_request_irq(&pdev->dev, irq, omap8250_irq, 0, ret = devm_request_irq(&pdev->dev, up.port.irq, omap8250_irq, 0,
dev_name(&pdev->dev), priv); dev_name(&pdev->dev), priv);
if (ret < 0) if (ret < 0)
return ret; return ret;

View File

@ -7,23 +7,31 @@
* Copyright (C) 2022 Microchip Technology Inc., All Rights Reserved. * Copyright (C) 2022 Microchip Technology Inc., All Rights Reserved.
*/ */
#include <linux/array_size.h>
#include <linux/bitfield.h> #include <linux/bitfield.h>
#include <linux/bitops.h> #include <linux/bits.h>
#include <linux/delay.h> #include <linux/circ_buf.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/gfp_types.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/iopoll.h> #include <linux/iopoll.h>
#include <linux/kernel.h> #include <linux/minmax.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h>
#include <linux/overflow.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/pm.h>
#include <linux/serial_core.h> #include <linux/serial_core.h>
#include <linux/serial_reg.h> #include <linux/serial_reg.h>
#include <linux/serial_8250.h> #include <linux/serial_8250.h>
#include <linux/slab.h> #include <linux/spinlock.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/units.h> #include <linux/time.h>
#include <linux/tty.h> #include <linux/tty.h>
#include <linux/tty_flip.h> #include <linux/tty_flip.h>
#include <linux/8250_pci.h> #include <linux/types.h>
#include <linux/units.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
@ -67,6 +75,7 @@
#define SYSLOCK_RETRY_CNT 1000 #define SYSLOCK_RETRY_CNT 1000
#define UART_RX_BYTE_FIFO 0x00 #define UART_RX_BYTE_FIFO 0x00
#define UART_TX_BYTE_FIFO 0x00
#define UART_FIFO_CTL 0x02 #define UART_FIFO_CTL 0x02
#define UART_ACTV_REG 0x11 #define UART_ACTV_REG 0x11
@ -81,10 +90,10 @@
#define ADCL_CFG_PIN_SEL BIT(1) #define ADCL_CFG_PIN_SEL BIT(1)
#define ADCL_CFG_EN BIT(0) #define ADCL_CFG_EN BIT(0)
#define UART_BIT_SAMPLE_CNT 16 #define UART_BIT_SAMPLE_CNT_8 8
#define UART_BIT_SAMPLE_CNT_16 16
#define BAUD_CLOCK_DIV_INT_MSK GENMASK(31, 8) #define BAUD_CLOCK_DIV_INT_MSK GENMASK(31, 8)
#define ADCL_CFG_RTS_DELAY_MASK GENMASK(11, 8) #define ADCL_CFG_RTS_DELAY_MASK GENMASK(11, 8)
#define UART_CLOCK_DEFAULT (62500 * HZ_PER_KHZ)
#define UART_WAKE_REG 0x8C #define UART_WAKE_REG 0x8C
#define UART_WAKE_MASK_REG 0x90 #define UART_WAKE_MASK_REG 0x90
@ -95,13 +104,19 @@
(UART_WAKE_N_PIN | UART_WAKE_NCTS | UART_WAKE_INT) (UART_WAKE_N_PIN | UART_WAKE_NCTS | UART_WAKE_INT)
#define UART_BAUD_CLK_DIVISOR_REG 0x54 #define UART_BAUD_CLK_DIVISOR_REG 0x54
#define FRAC_DIV_CFG_REG 0x58
#define UART_RESET_REG 0x94 #define UART_RESET_REG 0x94
#define UART_RESET_D3_RESET_DISABLE BIT(16) #define UART_RESET_D3_RESET_DISABLE BIT(16)
#define UART_BURST_STATUS_REG 0x9C #define UART_BURST_STATUS_REG 0x9C
#define UART_TX_BURST_FIFO 0xA0
#define UART_RX_BURST_FIFO 0xA4 #define UART_RX_BURST_FIFO 0xA4
#define UART_BIT_DIVISOR_8 0x26731000
#define UART_BIT_DIVISOR_16 0x6ef71000
#define UART_BAUD_4MBPS 4000000
#define MAX_PORTS 4 #define MAX_PORTS 4
#define PORT_OFFSET 0x100 #define PORT_OFFSET 0x100
#define RX_BUF_SIZE 512 #define RX_BUF_SIZE 512
@ -109,6 +124,7 @@
#define UART_BURST_SIZE 4 #define UART_BURST_SIZE 4
#define UART_BST_STAT_RX_COUNT_MASK 0x00FF #define UART_BST_STAT_RX_COUNT_MASK 0x00FF
#define UART_BST_STAT_TX_COUNT_MASK 0xFF00
#define UART_BST_STAT_IIR_INT_PEND 0x100000 #define UART_BST_STAT_IIR_INT_PEND 0x100000
#define UART_LSR_OVERRUN_ERR_CLR 0x43 #define UART_LSR_OVERRUN_ERR_CLR 0x43
#define UART_BST_STAT_LSR_RX_MASK 0x9F000000 #define UART_BST_STAT_LSR_RX_MASK 0x9F000000
@ -116,6 +132,7 @@
#define UART_BST_STAT_LSR_OVERRUN_ERR 0x2000000 #define UART_BST_STAT_LSR_OVERRUN_ERR 0x2000000
#define UART_BST_STAT_LSR_PARITY_ERR 0x4000000 #define UART_BST_STAT_LSR_PARITY_ERR 0x4000000
#define UART_BST_STAT_LSR_FRAME_ERR 0x8000000 #define UART_BST_STAT_LSR_FRAME_ERR 0x8000000
#define UART_BST_STAT_LSR_THRE 0x20000000
struct pci1xxxx_8250 { struct pci1xxxx_8250 {
unsigned int nr; unsigned int nr;
@ -206,15 +223,21 @@ static int pci1xxxx_get_num_ports(struct pci_dev *dev)
static unsigned int pci1xxxx_get_divisor(struct uart_port *port, static unsigned int pci1xxxx_get_divisor(struct uart_port *port,
unsigned int baud, unsigned int *frac) unsigned int baud, unsigned int *frac)
{ {
unsigned int uart_sample_cnt;
unsigned int quot; unsigned int quot;
if (baud >= UART_BAUD_4MBPS)
uart_sample_cnt = UART_BIT_SAMPLE_CNT_8;
else
uart_sample_cnt = UART_BIT_SAMPLE_CNT_16;
/* /*
* Calculate baud rate sampling period in nanoseconds. * Calculate baud rate sampling period in nanoseconds.
* Fractional part x denotes x/255 parts of a nanosecond. * Fractional part x denotes x/255 parts of a nanosecond.
*/ */
quot = NSEC_PER_SEC / (baud * UART_BIT_SAMPLE_CNT); quot = NSEC_PER_SEC / (baud * uart_sample_cnt);
*frac = (NSEC_PER_SEC - quot * baud * UART_BIT_SAMPLE_CNT) * *frac = (NSEC_PER_SEC - quot * baud * uart_sample_cnt) *
255 / UART_BIT_SAMPLE_CNT / baud; 255 / uart_sample_cnt / baud;
return quot; return quot;
} }
@ -222,6 +245,11 @@ static unsigned int pci1xxxx_get_divisor(struct uart_port *port,
static void pci1xxxx_set_divisor(struct uart_port *port, unsigned int baud, static void pci1xxxx_set_divisor(struct uart_port *port, unsigned int baud,
unsigned int quot, unsigned int frac) unsigned int quot, unsigned int frac)
{ {
if (baud >= UART_BAUD_4MBPS)
writel(UART_BIT_DIVISOR_8, port->membase + FRAC_DIV_CFG_REG);
else
writel(UART_BIT_DIVISOR_16, port->membase + FRAC_DIV_CFG_REG);
writel(FIELD_PREP(BAUD_CLOCK_DIV_INT_MSK, quot) | frac, writel(FIELD_PREP(BAUD_CLOCK_DIV_INT_MSK, quot) | frac,
port->membase + UART_BAUD_CLK_DIVISOR_REG); port->membase + UART_BAUD_CLK_DIVISOR_REG);
} }
@ -233,7 +261,16 @@ static int pci1xxxx_rs485_config(struct uart_port *port,
u32 delay_in_baud_periods; u32 delay_in_baud_periods;
u32 baud_period_in_ns; u32 baud_period_in_ns;
u32 mode_cfg = 0; u32 mode_cfg = 0;
u32 sample_cnt;
u32 clock_div; u32 clock_div;
u32 frac_div;
frac_div = readl(port->membase + FRAC_DIV_CFG_REG);
if (frac_div == UART_BIT_DIVISOR_16)
sample_cnt = UART_BIT_SAMPLE_CNT_16;
else
sample_cnt = UART_BIT_SAMPLE_CNT_8;
/* /*
* pci1xxxx's uart hardware supports only RTS delay after * pci1xxxx's uart hardware supports only RTS delay after
@ -249,7 +286,7 @@ static int pci1xxxx_rs485_config(struct uart_port *port,
clock_div = readl(port->membase + UART_BAUD_CLK_DIVISOR_REG); clock_div = readl(port->membase + UART_BAUD_CLK_DIVISOR_REG);
baud_period_in_ns = baud_period_in_ns =
FIELD_GET(BAUD_CLOCK_DIV_INT_MSK, clock_div) * FIELD_GET(BAUD_CLOCK_DIV_INT_MSK, clock_div) *
UART_BIT_SAMPLE_CNT; sample_cnt;
delay_in_baud_periods = delay_in_baud_periods =
rs485->delay_rts_after_send * NSEC_PER_MSEC / rs485->delay_rts_after_send * NSEC_PER_MSEC /
baud_period_in_ns; baud_period_in_ns;
@ -344,6 +381,105 @@ static void pci1xxxx_rx_burst(struct uart_port *port, u32 uart_status)
} }
} }
static void pci1xxxx_process_write_data(struct uart_port *port,
struct circ_buf *xmit,
int *data_empty_count,
u32 *valid_byte_count)
{
u32 valid_burst_count = *valid_byte_count / UART_BURST_SIZE;
/*
* Each transaction transfers data in DWORDs. If there are less than
* four remaining valid_byte_count to transfer or if the circular
* buffer has insufficient space for a DWORD, the data is transferred
* one byte at a time.
*/
while (valid_burst_count) {
if (*data_empty_count - UART_BURST_SIZE < 0)
break;
if (xmit->tail > (UART_XMIT_SIZE - UART_BURST_SIZE))
break;
writel(*(unsigned int *)&xmit->buf[xmit->tail],
port->membase + UART_TX_BURST_FIFO);
*valid_byte_count -= UART_BURST_SIZE;
*data_empty_count -= UART_BURST_SIZE;
valid_burst_count -= UART_BYTE_SIZE;
xmit->tail = (xmit->tail + UART_BURST_SIZE) &
(UART_XMIT_SIZE - 1);
}
while (*valid_byte_count) {
if (*data_empty_count - UART_BYTE_SIZE < 0)
break;
writeb(xmit->buf[xmit->tail], port->membase +
UART_TX_BYTE_FIFO);
*data_empty_count -= UART_BYTE_SIZE;
*valid_byte_count -= UART_BYTE_SIZE;
/*
* When the tail of the circular buffer is reached, the next
* byte is transferred to the beginning of the buffer.
*/
xmit->tail = (xmit->tail + UART_BYTE_SIZE) &
(UART_XMIT_SIZE - 1);
/*
* If there are any pending burst count, data is handled by
* transmitting DWORDs at a time.
*/
if (valid_burst_count && (xmit->tail <
(UART_XMIT_SIZE - UART_BURST_SIZE)))
break;
}
}
static void pci1xxxx_tx_burst(struct uart_port *port, u32 uart_status)
{
struct uart_8250_port *up = up_to_u8250p(port);
u32 valid_byte_count;
int data_empty_count;
struct circ_buf *xmit;
xmit = &port->state->xmit;
if (port->x_char) {
writeb(port->x_char, port->membase + UART_TX);
port->icount.tx++;
port->x_char = 0;
return;
}
if ((uart_tx_stopped(port)) || (uart_circ_empty(xmit))) {
port->ops->stop_tx(port);
} else {
data_empty_count = (pci1xxxx_read_burst_status(port) &
UART_BST_STAT_TX_COUNT_MASK) >> 8;
do {
valid_byte_count = uart_circ_chars_pending(xmit);
pci1xxxx_process_write_data(port, xmit,
&data_empty_count,
&valid_byte_count);
port->icount.tx++;
if (uart_circ_empty(xmit))
break;
} while (data_empty_count && valid_byte_count);
}
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
/*
* With RPM enabled, we have to wait until the FIFO is empty before
* the HW can go idle. So we get here once again with empty FIFO and
* disable the interrupt and RPM in __stop_tx()
*/
if (uart_circ_empty(xmit) && !(up->capabilities & UART_CAP_RPM))
port->ops->stop_tx(port);
}
static int pci1xxxx_handle_irq(struct uart_port *port) static int pci1xxxx_handle_irq(struct uart_port *port)
{ {
unsigned long flags; unsigned long flags;
@ -359,6 +495,9 @@ static int pci1xxxx_handle_irq(struct uart_port *port)
if (status & UART_BST_STAT_LSR_RX_MASK) if (status & UART_BST_STAT_LSR_RX_MASK)
pci1xxxx_rx_burst(port, status); pci1xxxx_rx_burst(port, status);
if (status & UART_BST_STAT_LSR_THRE)
pci1xxxx_tx_burst(port, status);
spin_unlock_irqrestore(&port->lock, flags); spin_unlock_irqrestore(&port->lock, flags);
return 1; return 1;
@ -481,6 +620,17 @@ static int pci1xxxx_setup(struct pci_dev *pdev,
port->port.flags |= UPF_FIXED_TYPE | UPF_SKIP_TEST; port->port.flags |= UPF_FIXED_TYPE | UPF_SKIP_TEST;
port->port.type = PORT_MCHP16550A; port->port.type = PORT_MCHP16550A;
/*
* 8250 core considers prescaller value to be always 16.
* The MCHP ports support downscaled mode and hence the
* functional UART clock can be lower, i.e. 62.5MHz, than
* software expects in order to support higher baud rates.
* Assign here 64MHz to support 4Mbps.
*
* The value itself is not really used anywhere except baud
* rate calculations, so we can mangle it as we wish.
*/
port->port.uartclk = 64 * HZ_PER_MHZ;
port->port.set_termios = serial8250_do_set_termios; port->port.set_termios = serial8250_do_set_termios;
port->port.get_divisor = pci1xxxx_get_divisor; port->port.get_divisor = pci1xxxx_get_divisor;
port->port.set_divisor = pci1xxxx_set_divisor; port->port.set_divisor = pci1xxxx_set_divisor;
@ -594,7 +744,6 @@ static int pci1xxxx_serial_probe(struct pci_dev *pdev,
memset(&uart, 0, sizeof(uart)); memset(&uart, 0, sizeof(uart));
uart.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT; uart.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT;
uart.port.uartclk = UART_CLOCK_DEFAULT;
uart.port.dev = dev; uart.port.dev = dev;
if (num_vectors == max_vec_reqd) if (num_vectors == max_vec_reqd)

View File

@ -38,10 +38,6 @@
#include "8250.h" #include "8250.h"
/* Nuvoton NPCM timeout register */
#define UART_NPCM_TOR 7
#define UART_NPCM_TOIE BIT(7) /* Timeout Interrupt Enable */
/* /*
* Debugging. * Debugging.
*/ */
@ -1329,9 +1325,6 @@ static void autoconfig_irq(struct uart_8250_port *up)
inb_p(ICP); inb_p(ICP);
} }
if (uart_console(port))
console_lock();
/* forget possible initially masked and pending IRQ */ /* forget possible initially masked and pending IRQ */
probe_irq_off(probe_irq_on()); probe_irq_off(probe_irq_on());
save_mcr = serial8250_in_MCR(up); save_mcr = serial8250_in_MCR(up);
@ -1371,9 +1364,6 @@ static void autoconfig_irq(struct uart_8250_port *up)
if (port->flags & UPF_FOURPORT) if (port->flags & UPF_FOURPORT)
outb_p(save_ICP, ICP); outb_p(save_ICP, ICP);
if (uart_console(port))
console_unlock();
port->irq = (irq > 0) ? irq : 0; port->irq = (irq > 0) ? irq : 0;
} }
@ -2235,15 +2225,6 @@ int serial8250_do_startup(struct uart_port *port)
UART_DA830_PWREMU_MGMT_FREE); UART_DA830_PWREMU_MGMT_FREE);
} }
if (port->type == PORT_NPCM) {
/*
* Nuvoton calls the scratch register 'UART_TOR' (timeout
* register). Enable it, and set TIOC (timeout interrupt
* comparator) to be 0x20 for correct operation.
*/
serial_port_out(port, UART_NPCM_TOR, UART_NPCM_TOIE | 0x20);
}
#ifdef CONFIG_SERIAL_8250_RSA #ifdef CONFIG_SERIAL_8250_RSA
/* /*
* If this is an RSA port, see if we can kick it up to the * If this is an RSA port, see if we can kick it up to the
@ -2545,15 +2526,6 @@ static void serial8250_shutdown(struct uart_port *port)
serial8250_do_shutdown(port); serial8250_do_shutdown(port);
} }
/* Nuvoton NPCM UARTs have a custom divisor calculation */
static unsigned int npcm_get_divisor(struct uart_8250_port *up,
unsigned int baud)
{
struct uart_port *port = &up->port;
return DIV_ROUND_CLOSEST(port->uartclk, 16 * baud + 2) - 2;
}
static unsigned int serial8250_do_get_divisor(struct uart_port *port, static unsigned int serial8250_do_get_divisor(struct uart_port *port,
unsigned int baud, unsigned int baud,
unsigned int *frac) unsigned int *frac)
@ -2598,8 +2570,6 @@ static unsigned int serial8250_do_get_divisor(struct uart_port *port,
quot = 0x8001; quot = 0x8001;
else if (magic_multiplier && baud >= port->uartclk / 12) else if (magic_multiplier && baud >= port->uartclk / 12)
quot = 0x8002; quot = 0x8002;
else if (up->port.type == PORT_NPCM)
quot = npcm_get_divisor(up, baud);
else else
quot = uart_get_divisor(port, baud); quot = uart_get_divisor(port, baud);
@ -2714,12 +2684,8 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port,
*/ */
void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk) void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk)
{ {
struct uart_8250_port *up = up_to_u8250p(port);
struct tty_port *tport = &port->state->port; struct tty_port *tport = &port->state->port;
unsigned int baud, quot, frac = 0;
struct ktermios *termios;
struct tty_struct *tty; struct tty_struct *tty;
unsigned long flags;
tty = tty_port_tty_get(tport); tty = tty_port_tty_get(tport);
if (!tty) { if (!tty) {
@ -2740,21 +2706,7 @@ void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk)
if (!tty_port_initialized(tport)) if (!tty_port_initialized(tport))
goto out_unlock; goto out_unlock;
termios = &tty->termios; serial8250_do_set_termios(port, &tty->termios, NULL);
baud = serial8250_get_baud_rate(port, termios, NULL);
quot = serial8250_get_divisor(port, baud, &frac);
serial8250_rpm_get(up);
uart_port_lock_irqsave(port, &flags);
uart_update_timeout(port, termios->c_cflag, baud);
serial8250_set_divisor(port, baud, quot, frac);
serial_port_out(port, UART_LCR, up->lcr);
uart_port_unlock_irqrestore(port, flags);
serial8250_rpm_put(up);
out_unlock: out_unlock:
mutex_unlock(&tport->mutex); mutex_unlock(&tport->mutex);

View File

@ -92,11 +92,7 @@ static int serial_pxa_probe(struct platform_device *pdev)
struct uart_8250_port uart = {}; struct uart_8250_port uart = {};
struct pxa8250_data *data; struct pxa8250_data *data;
struct resource *mmres; struct resource *mmres;
int irq, ret; int ret;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mmres) if (!mmres)
@ -114,21 +110,21 @@ static int serial_pxa_probe(struct platform_device *pdev)
if (ret) if (ret)
return ret; return ret;
ret = of_alias_get_id(pdev->dev.of_node, "serial");
if (ret >= 0)
uart.port.line = ret;
uart.port.type = PORT_XSCALE; uart.port.type = PORT_XSCALE;
uart.port.iotype = UPIO_MEM32;
uart.port.mapbase = mmres->start; uart.port.mapbase = mmres->start;
uart.port.regshift = 2;
uart.port.irq = irq;
uart.port.fifosize = 64;
uart.port.flags = UPF_IOREMAP | UPF_SKIP_TEST | UPF_FIXED_TYPE; uart.port.flags = UPF_IOREMAP | UPF_SKIP_TEST | UPF_FIXED_TYPE;
uart.port.dev = &pdev->dev; uart.port.dev = &pdev->dev;
uart.port.uartclk = clk_get_rate(data->clk); uart.port.uartclk = clk_get_rate(data->clk);
uart.port.pm = serial_pxa_pm; uart.port.pm = serial_pxa_pm;
uart.port.private_data = data; uart.port.private_data = data;
ret = uart_read_port_properties(&uart.port);
if (ret)
return ret;
uart.port.iotype = UPIO_MEM32;
uart.port.regshift = 2;
uart.port.fifosize = 64;
uart.dl_write = serial_pxa_dl_write; uart.dl_write = serial_pxa_dl_write;
ret = serial8250_register_8250_port(&uart); ret = serial8250_register_8250_port(&uart);

View File

@ -57,25 +57,11 @@ static int tegra_uart_probe(struct platform_device *pdev)
port = &port8250.port; port = &port8250.port;
spin_lock_init(&port->lock); spin_lock_init(&port->lock);
port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | port->flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_FIXED_TYPE;
UPF_FIXED_TYPE;
port->iotype = UPIO_MEM32;
port->regshift = 2;
port->type = PORT_TEGRA; port->type = PORT_TEGRA;
port->irqflags |= IRQF_SHARED;
port->dev = &pdev->dev; port->dev = &pdev->dev;
port->handle_break = tegra_uart_handle_break; port->handle_break = tegra_uart_handle_break;
ret = of_alias_get_id(pdev->dev.of_node, "serial");
if (ret >= 0)
port->line = ret;
ret = platform_get_irq(pdev, 0);
if (ret < 0)
return ret;
port->irq = ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) if (!res)
return -ENODEV; return -ENODEV;
@ -88,12 +74,18 @@ static int tegra_uart_probe(struct platform_device *pdev)
port->mapbase = res->start; port->mapbase = res->start;
port->mapsize = resource_size(res); port->mapsize = resource_size(res);
ret = uart_read_port_properties(port);
if (ret)
return ret;
port->iotype = UPIO_MEM32;
port->regshift = 2;
uart->rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL); uart->rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL);
if (IS_ERR(uart->rst)) if (IS_ERR(uart->rst))
return PTR_ERR(uart->rst); return PTR_ERR(uart->rst);
if (device_property_read_u32(&pdev->dev, "clock-frequency", if (!port->uartclk) {
&port->uartclk)) {
uart->clk = devm_clk_get(&pdev->dev, NULL); uart->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(uart->clk)) { if (IS_ERR(uart->clk)) {
dev_err(&pdev->dev, "failed to get clock!\n"); dev_err(&pdev->dev, "failed to get clock!\n");

View File

@ -162,7 +162,6 @@ static int uniphier_uart_probe(struct platform_device *pdev)
struct uniphier8250_priv *priv; struct uniphier8250_priv *priv;
struct resource *regs; struct resource *regs;
void __iomem *membase; void __iomem *membase;
int irq;
int ret; int ret;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@ -175,23 +174,12 @@ static int uniphier_uart_probe(struct platform_device *pdev)
if (!membase) if (!membase)
return -ENOMEM; return -ENOMEM;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv) if (!priv)
return -ENOMEM; return -ENOMEM;
memset(&up, 0, sizeof(up)); memset(&up, 0, sizeof(up));
ret = of_alias_get_id(dev->of_node, "serial");
if (ret < 0) {
dev_err(dev, "failed to get alias id\n");
return ret;
}
up.port.line = ret;
priv->clk = devm_clk_get(dev, NULL); priv->clk = devm_clk_get(dev, NULL);
if (IS_ERR(priv->clk)) { if (IS_ERR(priv->clk)) {
dev_err(dev, "failed to get clock\n"); dev_err(dev, "failed to get clock\n");
@ -211,7 +199,10 @@ static int uniphier_uart_probe(struct platform_device *pdev)
up.port.mapbase = regs->start; up.port.mapbase = regs->start;
up.port.mapsize = resource_size(regs); up.port.mapsize = resource_size(regs);
up.port.membase = membase; up.port.membase = membase;
up.port.irq = irq;
ret = uart_read_port_properties(&up.port);
if (ret)
return ret;
up.port.type = PORT_16550A; up.port.type = PORT_16550A;
up.port.iotype = UPIO_MEM32; up.port.iotype = UPIO_MEM32;

View File

@ -149,6 +149,7 @@ config SERIAL_8250_PCI
config SERIAL_8250_EXAR config SERIAL_8250_EXAR
tristate "8250/16550 Exar/Commtech PCI/PCIe device support" tristate "8250/16550 Exar/Commtech PCI/PCIe device support"
depends on SERIAL_8250 && PCI depends on SERIAL_8250 && PCI
select SERIAL_8250_PCILIB
default SERIAL_8250 default SERIAL_8250
help help
This builds support for XR17C1xx, XR17V3xx and some Commtech This builds support for XR17C1xx, XR17V3xx and some Commtech

View File

@ -348,10 +348,7 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap)
flag = TTY_FRAME; flag = TTY_FRAME;
} }
uart_port_unlock(&uap->port); sysrq = uart_prepare_sysrq_char(&uap->port, ch & 255);
sysrq = uart_handle_sysrq_char(&uap->port, ch & 255);
uart_port_lock(&uap->port);
if (!sysrq) if (!sysrq)
uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag); uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag);
} }
@ -1017,7 +1014,7 @@ static void pl011_dma_rx_callback(void *data)
ret = pl011_dma_rx_trigger_dma(uap); ret = pl011_dma_rx_trigger_dma(uap);
pl011_dma_rx_chars(uap, pending, lastbuf, false); pl011_dma_rx_chars(uap, pending, lastbuf, false);
uart_port_unlock_irq(&uap->port); uart_unlock_and_check_sysrq(&uap->port);
/* /*
* Do this check after we picked the DMA chars so we don't * Do this check after we picked the DMA chars so we don't
* get some IRQ immediately from RX. * get some IRQ immediately from RX.
@ -1540,11 +1537,10 @@ static void check_apply_cts_event_workaround(struct uart_amba_port *uap)
static irqreturn_t pl011_int(int irq, void *dev_id) static irqreturn_t pl011_int(int irq, void *dev_id)
{ {
struct uart_amba_port *uap = dev_id; struct uart_amba_port *uap = dev_id;
unsigned long flags;
unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT; unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
int handled = 0; int handled = 0;
uart_port_lock_irqsave(&uap->port, &flags); uart_port_lock(&uap->port);
status = pl011_read(uap, REG_RIS) & uap->im; status = pl011_read(uap, REG_RIS) & uap->im;
if (status) { if (status) {
do { do {
@ -1573,7 +1569,7 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
handled = 1; handled = 1;
} }
uart_port_unlock_irqrestore(&uap->port, flags); uart_unlock_and_check_sysrq(&uap->port);
return IRQ_RETVAL(handled); return IRQ_RETVAL(handled);
} }
@ -2322,13 +2318,10 @@ pl011_console_write(struct console *co, const char *s, unsigned int count)
clk_enable(uap->clk); clk_enable(uap->clk);
local_irq_save(flags); if (oops_in_progress)
if (uap->port.sysrq) locked = uart_port_trylock_irqsave(&uap->port, &flags);
locked = 0;
else if (oops_in_progress)
locked = uart_port_trylock(&uap->port);
else else
uart_port_lock(&uap->port); uart_port_lock_irqsave(&uap->port, &flags);
/* /*
* First save the CR then disable the interrupts * First save the CR then disable the interrupts
@ -2354,8 +2347,7 @@ pl011_console_write(struct console *co, const char *s, unsigned int count)
pl011_write(old_cr, uap, REG_CR); pl011_write(old_cr, uap, REG_CR);
if (locked) if (locked)
uart_port_unlock(&uap->port); uart_port_unlock_irqrestore(&uap->port, flags);
local_irq_restore(flags);
clk_disable(uap->clk); clk_disable(uap->clk);
} }

View File

@ -378,7 +378,7 @@ static void ar933x_uart_rx_chars(struct ar933x_uart_port *up)
up->port.icount.rx++; up->port.icount.rx++;
ch = rdata & AR933X_UART_DATA_TX_RX_MASK; ch = rdata & AR933X_UART_DATA_TX_RX_MASK;
if (uart_handle_sysrq_char(&up->port, ch)) if (uart_prepare_sysrq_char(&up->port, ch))
continue; continue;
if ((up->port.ignore_status_mask & AR933X_DUMMY_STATUS_RD) == 0) if ((up->port.ignore_status_mask & AR933X_DUMMY_STATUS_RD) == 0)
@ -468,7 +468,7 @@ static irqreturn_t ar933x_uart_interrupt(int irq, void *dev_id)
ar933x_uart_tx_chars(up); ar933x_uart_tx_chars(up);
} }
uart_port_unlock(&up->port); uart_unlock_and_check_sysrq(&up->port);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -627,14 +627,10 @@ static void ar933x_uart_console_write(struct console *co, const char *s,
unsigned int int_en; unsigned int int_en;
int locked = 1; int locked = 1;
local_irq_save(flags); if (oops_in_progress)
locked = uart_port_trylock_irqsave(&up->port, &flags);
if (up->port.sysrq)
locked = 0;
else if (oops_in_progress)
locked = uart_port_trylock(&up->port);
else else
uart_port_lock(&up->port); uart_port_lock_irqsave(&up->port, &flags);
/* /*
* First save the IER then disable the interrupts * First save the IER then disable the interrupts
@ -654,9 +650,7 @@ static void ar933x_uart_console_write(struct console *co, const char *s,
ar933x_uart_write(up, AR933X_UART_INT_REG, AR933X_UART_INT_ALLINTS); ar933x_uart_write(up, AR933X_UART_INT_REG, AR933X_UART_INT_ALLINTS);
if (locked) if (locked)
uart_port_unlock(&up->port); uart_port_unlock_irqrestore(&up->port, flags);
local_irq_restore(flags);
} }
static int ar933x_uart_console_setup(struct console *co, char *options) static int ar933x_uart_console_setup(struct console *co, char *options)

View File

@ -285,10 +285,9 @@ static void bcm_uart_do_rx(struct uart_port *port)
flag = TTY_PARITY; flag = TTY_PARITY;
} }
if (uart_handle_sysrq_char(port, c)) if (uart_prepare_sysrq_char(port, c))
continue; continue;
if ((cstat & port->ignore_status_mask) == 0) if ((cstat & port->ignore_status_mask) == 0)
tty_insert_flip_char(tty_port, c, flag); tty_insert_flip_char(tty_port, c, flag);
@ -353,7 +352,7 @@ static irqreturn_t bcm_uart_interrupt(int irq, void *dev_id)
estat & UART_EXTINP_DCD_MASK); estat & UART_EXTINP_DCD_MASK);
} }
uart_port_unlock(port); uart_unlock_and_check_sysrq(port);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -703,20 +702,14 @@ static void bcm_console_write(struct console *co, const char *s,
{ {
struct uart_port *port; struct uart_port *port;
unsigned long flags; unsigned long flags;
int locked; int locked = 1;
port = &ports[co->index]; port = &ports[co->index];
local_irq_save(flags); if (oops_in_progress)
if (port->sysrq) { locked = uart_port_trylock_irqsave(port, &flags);
/* bcm_uart_interrupt() already took the lock */ else
locked = 0; uart_port_lock_irqsave(port, &flags);
} else if (oops_in_progress) {
locked = uart_port_trylock(port);
} else {
uart_port_lock(port);
locked = 1;
}
/* call helper to deal with \r\n */ /* call helper to deal with \r\n */
uart_console_write(port, s, count, bcm_console_putchar); uart_console_write(port, s, count, bcm_console_putchar);
@ -725,8 +718,7 @@ static void bcm_console_write(struct console *co, const char *s,
wait_for_xmitr(port); wait_for_xmitr(port);
if (locked) if (locked)
uart_port_unlock(port); uart_port_unlock_irqrestore(port, flags);
local_irq_restore(flags);
} }
/* /*

View File

@ -837,7 +837,6 @@ static int linflex_probe(struct platform_device *pdev)
return ret; return ret;
sport->dev = &pdev->dev; sport->dev = &pdev->dev;
sport->type = PORT_LINFLEXUART;
sport->iotype = UPIO_MEM; sport->iotype = UPIO_MEM;
sport->irq = ret; sport->irq = ret;
sport->ops = &linflex_pops; sport->ops = &linflex_pops;

View File

@ -395,7 +395,6 @@ static void cls_copy_data_from_uart_to_queue(struct jsm_channel *ch)
* which in this case is the break signal. * which in this case is the break signal.
*/ */
if (linestatus & error_mask) { if (linestatus & error_mask) {
linestatus = 0;
readb(&ch->ch_cls_uart->txrx); readb(&ch->ch_cls_uart->txrx);
continue; continue;
} }

View File

@ -136,20 +136,16 @@ static void lpc32xx_hsuart_console_write(struct console *co, const char *s,
int locked = 1; int locked = 1;
touch_nmi_watchdog(); touch_nmi_watchdog();
local_irq_save(flags); if (oops_in_progress)
if (up->port.sysrq) locked = uart_port_trylock_irqsave(&up->port, &flags);
locked = 0;
else if (oops_in_progress)
locked = uart_port_trylock(&up->port);
else else
uart_port_lock(&up->port); uart_port_lock_irqsave(&up->port, &flags);
uart_console_write(&up->port, s, count, lpc32xx_hsuart_console_putchar); uart_console_write(&up->port, s, count, lpc32xx_hsuart_console_putchar);
wait_for_xmit_empty(&up->port); wait_for_xmit_empty(&up->port);
if (locked) if (locked)
uart_port_unlock(&up->port); uart_port_unlock_irqrestore(&up->port, flags);
local_irq_restore(flags);
} }
static int __init lpc32xx_hsuart_console_setup(struct console *co, static int __init lpc32xx_hsuart_console_setup(struct console *co,
@ -233,8 +229,6 @@ static unsigned int __serial_get_clock_div(unsigned long uartclk,
hsu_rate++; hsu_rate++;
} }
if (hsu_rate > 0xFF)
hsu_rate = 0xFF;
return goodrate; return goodrate;
} }
@ -268,7 +262,8 @@ static void __serial_lpc32xx_rx(struct uart_port *port)
tty_insert_flip_char(tport, 0, TTY_FRAME); tty_insert_flip_char(tport, 0, TTY_FRAME);
} }
tty_insert_flip_char(tport, (tmp & 0xFF), flag); if (!uart_prepare_sysrq_char(port, tmp & 0xff))
tty_insert_flip_char(tport, (tmp & 0xFF), flag);
tmp = readl(LPC32XX_HSUART_FIFO(port->membase)); tmp = readl(LPC32XX_HSUART_FIFO(port->membase));
} }
@ -333,7 +328,7 @@ static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id)
__serial_lpc32xx_tx(port); __serial_lpc32xx_tx(port);
} }
uart_port_unlock(port); uart_unlock_and_check_sysrq(port);
return IRQ_HANDLED; return IRQ_HANDLED;
} }

View File

@ -30,6 +30,7 @@
#define MAX310X_MAJOR 204 #define MAX310X_MAJOR 204
#define MAX310X_MINOR 209 #define MAX310X_MINOR 209
#define MAX310X_UART_NRMAX 16 #define MAX310X_UART_NRMAX 16
#define MAX310X_MAX_PORTS 4 /* Maximum number of UART ports per IC. */
/* MAX310X register definitions */ /* MAX310X register definitions */
#define MAX310X_RHR_REG (0x00) /* RX FIFO */ #define MAX310X_RHR_REG (0x00) /* RX FIFO */
@ -66,6 +67,7 @@
#define MAX310X_BRGDIVMSB_REG (0x1d) /* Baud rate divisor MSB */ #define MAX310X_BRGDIVMSB_REG (0x1d) /* Baud rate divisor MSB */
#define MAX310X_CLKSRC_REG (0x1e) /* Clock source */ #define MAX310X_CLKSRC_REG (0x1e) /* Clock source */
#define MAX310X_REG_1F (0x1f) #define MAX310X_REG_1F (0x1f)
#define MAX310X_EXTREG_START (0x20) /* Only relevant in SPI mode. */
#define MAX310X_REVID_REG MAX310X_REG_1F /* Revision ID */ #define MAX310X_REVID_REG MAX310X_REG_1F /* Revision ID */
@ -73,9 +75,9 @@
#define MAX310X_GLOBALCMD_REG MAX310X_REG_1F /* Global Command (WO) */ #define MAX310X_GLOBALCMD_REG MAX310X_REG_1F /* Global Command (WO) */
/* Extended registers */ /* Extended registers */
#define MAX310X_SPI_REVID_EXTREG MAX310X_REG_05 /* Revision ID */ #define MAX310X_REVID_EXTREG (0x25) /* Revision ID
#define MAX310X_I2C_REVID_EXTREG (0x25) /* Revision ID */ * (extended addressing space)
*/
/* IRQ register bits */ /* IRQ register bits */
#define MAX310X_IRQ_LSR_BIT (1 << 0) /* LSR interrupt */ #define MAX310X_IRQ_LSR_BIT (1 << 0) /* LSR interrupt */
#define MAX310X_IRQ_SPCHR_BIT (1 << 1) /* Special char interrupt */ #define MAX310X_IRQ_SPCHR_BIT (1 << 1) /* Special char interrupt */
@ -160,14 +162,14 @@
#define MAX310X_IRDA_SIR_BIT (1 << 1) /* SIR mode enable */ #define MAX310X_IRDA_SIR_BIT (1 << 1) /* SIR mode enable */
/* Flow control trigger level register masks */ /* Flow control trigger level register masks */
#define MAX310X_FLOWLVL_HALT_MASK (0x000f) /* Flow control halt level */ #define MAX310X_FLOWLVL_HALT_MASK GENMASK(3, 0) /* Flow control halt level */
#define MAX310X_FLOWLVL_RES_MASK (0x00f0) /* Flow control resume level */ #define MAX310X_FLOWLVL_RES_MASK GENMASK(7, 4) /* Flow control resume level */
#define MAX310X_FLOWLVL_HALT(words) ((words / 8) & 0x0f) #define MAX310X_FLOWLVL_HALT(words) ((words / 8) & 0x0f)
#define MAX310X_FLOWLVL_RES(words) (((words / 8) & 0x0f) << 4) #define MAX310X_FLOWLVL_RES(words) (((words / 8) & 0x0f) << 4)
/* FIFO interrupt trigger level register masks */ /* FIFO interrupt trigger level register masks */
#define MAX310X_FIFOTRIGLVL_TX_MASK (0x0f) /* TX FIFO trigger level */ #define MAX310X_FIFOTRIGLVL_TX_MASK GENMASK(3, 0) /* TX FIFO trigger level */
#define MAX310X_FIFOTRIGLVL_RX_MASK (0xf0) /* RX FIFO trigger level */ #define MAX310X_FIFOTRIGLVL_RX_MASK GENMASK(7, 4) /* RX FIFO trigger level */
#define MAX310X_FIFOTRIGLVL_TX(words) ((words / 8) & 0x0f) #define MAX310X_FIFOTRIGLVL_TX(words) ((words / 8) & 0x0f)
#define MAX310X_FIFOTRIGLVL_RX(words) (((words / 8) & 0x0f) << 4) #define MAX310X_FIFOTRIGLVL_RX(words) (((words / 8) & 0x0f) << 4)
@ -177,7 +179,8 @@
#define MAX310X_FLOWCTRL_GPIADDR_BIT (1 << 2) /* Enables that GPIO inputs #define MAX310X_FLOWCTRL_GPIADDR_BIT (1 << 2) /* Enables that GPIO inputs
* are used in conjunction with * are used in conjunction with
* XOFF2 for definition of * XOFF2 for definition of
* special character */ * special character
*/
#define MAX310X_FLOWCTRL_SWFLOWEN_BIT (1 << 3) /* Auto SW flow ctrl enable */ #define MAX310X_FLOWCTRL_SWFLOWEN_BIT (1 << 3) /* Auto SW flow ctrl enable */
#define MAX310X_FLOWCTRL_SWFLOW0_BIT (1 << 4) /* SWFLOW bit 0 */ #define MAX310X_FLOWCTRL_SWFLOW0_BIT (1 << 4) /* SWFLOW bit 0 */
#define MAX310X_FLOWCTRL_SWFLOW1_BIT (1 << 5) /* SWFLOW bit 1 #define MAX310X_FLOWCTRL_SWFLOW1_BIT (1 << 5) /* SWFLOW bit 1
@ -214,8 +217,8 @@
*/ */
/* PLL configuration register masks */ /* PLL configuration register masks */
#define MAX310X_PLLCFG_PREDIV_MASK (0x3f) /* PLL predivision value */ #define MAX310X_PLLCFG_PREDIV_MASK GENMASK(5, 0) /* PLL predivision value */
#define MAX310X_PLLCFG_PLLFACTOR_MASK (0xc0) /* PLL multiplication factor */ #define MAX310X_PLLCFG_PLLFACTOR_MASK GENMASK(7, 6) /* PLL multiplication factor */
/* Baud rate generator configuration register bits */ /* Baud rate generator configuration register bits */
#define MAX310X_BRGCFG_2XMODE_BIT (1 << 4) /* Double baud rate */ #define MAX310X_BRGCFG_2XMODE_BIT (1 << 4) /* Double baud rate */
@ -234,7 +237,7 @@
/* Misc definitions */ /* Misc definitions */
#define MAX310X_FIFO_SIZE (128) #define MAX310X_FIFO_SIZE (128)
#define MAX310x_REV_MASK (0xf8) #define MAX310x_REV_MASK GENMASK(7, 3)
#define MAX310X_WRITE_BIT 0x80 #define MAX310X_WRITE_BIT 0x80
/* Port startup definitions */ /* Port startup definitions */
@ -257,20 +260,21 @@
struct max310x_if_cfg { struct max310x_if_cfg {
int (*extended_reg_enable)(struct device *dev, bool enable); int (*extended_reg_enable)(struct device *dev, bool enable);
u8 rev_id_offset;
unsigned int rev_id_reg;
}; };
struct max310x_devtype { struct max310x_devtype {
struct { struct {
unsigned short min; unsigned short min;
unsigned short max; unsigned short max;
} slave_addr; } slave_addr; /* Relevant only in I2C mode. */
char name[9];
int nr; int nr;
char name[9];
u8 mode1; u8 mode1;
int (*detect)(struct device *); u8 rev_id_val;
void (*power)(struct uart_port *, int); u8 rev_id_reg; /* Relevant only if rev_id_val is defined. */
u8 power_reg; /* Register address for power/sleep control. */
u8 power_bit; /* Bit for sleep or power-off mode (active high). */
}; };
struct max310x_one { struct max310x_one {
@ -331,62 +335,52 @@ static void max310x_port_update(struct uart_port *port, u8 reg, u8 mask, u8 val)
regmap_update_bits(one->regmap, reg, mask, val); regmap_update_bits(one->regmap, reg, mask, val);
} }
static int max3107_detect(struct device *dev) static int max310x_detect(struct device *dev)
{ {
struct max310x_port *s = dev_get_drvdata(dev); struct max310x_port *s = dev_get_drvdata(dev);
unsigned int val = 0; unsigned int val = 0;
int ret; int ret;
ret = regmap_read(s->regmap, MAX310X_REVID_REG, &val); /* Check if variant supports REV ID register: */
if (ret) if (s->devtype->rev_id_val) {
return ret; u8 rev_id_reg = s->devtype->rev_id_reg;
if (((val & MAX310x_REV_MASK) != MAX3107_REV_ID)) { /* Check if REV ID is in extended addressing space: */
dev_err(dev, if (s->devtype->rev_id_reg >= MAX310X_EXTREG_START) {
"%s ID 0x%02x does not match\n", s->devtype->name, val); ret = s->if_cfg->extended_reg_enable(dev, true);
return -ENODEV; if (ret)
} return ret;
return 0; /* Adjust REV ID extended addressing space address: */
} if (s->if_cfg->rev_id_offset)
rev_id_reg -= s->if_cfg->rev_id_offset;
}
static int max3108_detect(struct device *dev) regmap_read(s->regmap, rev_id_reg, &val);
{
struct max310x_port *s = dev_get_drvdata(dev);
unsigned int val = 0;
int ret;
/* MAX3108 have not REV ID register, we just check default value if (s->devtype->rev_id_reg >= MAX310X_EXTREG_START) {
* from clocksource register to make sure everything works. ret = s->if_cfg->extended_reg_enable(dev, false);
*/ if (ret)
ret = regmap_read(s->regmap, MAX310X_CLKSRC_REG, &val); return ret;
if (ret) }
return ret;
if (val != (MAX310X_CLKSRC_EXTCLK_BIT | MAX310X_CLKSRC_PLLBYP_BIT)) { if (((val & MAX310x_REV_MASK) != s->devtype->rev_id_val))
dev_err(dev, "%s not present\n", s->devtype->name); return dev_err_probe(dev, -ENODEV,
return -ENODEV; "%s ID 0x%02x does not match\n",
} s->devtype->name, val);
} else {
/*
* For variant without REV ID register, just check default value
* from clocksource register to make sure everything works.
*/
ret = regmap_read(s->regmap, MAX310X_CLKSRC_REG, &val);
if (ret)
return ret;
return 0; if (val != (MAX310X_CLKSRC_EXTCLK_BIT | MAX310X_CLKSRC_PLLBYP_BIT))
} return dev_err_probe(dev, -ENODEV,
"%s not present\n",
static int max3109_detect(struct device *dev) s->devtype->name);
{
struct max310x_port *s = dev_get_drvdata(dev);
unsigned int val = 0;
int ret;
ret = s->if_cfg->extended_reg_enable(dev, true);
if (ret)
return ret;
regmap_read(s->regmap, s->if_cfg->rev_id_reg, &val);
s->if_cfg->extended_reg_enable(dev, false);
if (((val & MAX310x_REV_MASK) != MAX3109_REV_ID)) {
dev_err(dev,
"%s ID 0x%02x does not match\n", s->devtype->name, val);
return -ENODEV;
} }
return 0; return 0;
@ -394,39 +388,10 @@ static int max3109_detect(struct device *dev)
static void max310x_power(struct uart_port *port, int on) static void max310x_power(struct uart_port *port, int on)
{ {
max310x_port_update(port, MAX310X_MODE1_REG, struct max310x_port *s = dev_get_drvdata(port->dev);
MAX310X_MODE1_FORCESLEEP_BIT,
on ? 0 : MAX310X_MODE1_FORCESLEEP_BIT);
if (on)
msleep(50);
}
static int max14830_detect(struct device *dev) max310x_port_update(port, s->devtype->power_reg, s->devtype->power_bit,
{ on ? 0 : s->devtype->power_bit);
struct max310x_port *s = dev_get_drvdata(dev);
unsigned int val = 0;
int ret;
ret = s->if_cfg->extended_reg_enable(dev, true);
if (ret)
return ret;
regmap_read(s->regmap, s->if_cfg->rev_id_reg, &val);
s->if_cfg->extended_reg_enable(dev, false);
if (((val & MAX310x_REV_MASK) != MAX14830_REV_ID)) {
dev_err(dev,
"%s ID 0x%02x does not match\n", s->devtype->name, val);
return -ENODEV;
}
return 0;
}
static void max14830_power(struct uart_port *port, int on)
{
max310x_port_update(port, MAX310X_BRGCFG_REG,
MAX14830_BRGCFG_CLKDIS_BIT,
on ? 0 : MAX14830_BRGCFG_CLKDIS_BIT);
if (on) if (on)
msleep(50); msleep(50);
} }
@ -435,8 +400,10 @@ static const struct max310x_devtype max3107_devtype = {
.name = "MAX3107", .name = "MAX3107",
.nr = 1, .nr = 1,
.mode1 = MAX310X_MODE1_AUTOSLEEP_BIT | MAX310X_MODE1_IRQSEL_BIT, .mode1 = MAX310X_MODE1_AUTOSLEEP_BIT | MAX310X_MODE1_IRQSEL_BIT,
.detect = max3107_detect, .rev_id_val = MAX3107_REV_ID,
.power = max310x_power, .rev_id_reg = MAX310X_REVID_REG,
.power_reg = MAX310X_MODE1_REG,
.power_bit = MAX310X_MODE1_FORCESLEEP_BIT,
.slave_addr = { .slave_addr = {
.min = 0x2c, .min = 0x2c,
.max = 0x2f, .max = 0x2f,
@ -447,8 +414,10 @@ static const struct max310x_devtype max3108_devtype = {
.name = "MAX3108", .name = "MAX3108",
.nr = 1, .nr = 1,
.mode1 = MAX310X_MODE1_AUTOSLEEP_BIT, .mode1 = MAX310X_MODE1_AUTOSLEEP_BIT,
.detect = max3108_detect, .rev_id_val = 0, /* Unsupported. */
.power = max310x_power, .rev_id_reg = 0, /* Irrelevant when rev_id_val is not defined. */
.power_reg = MAX310X_MODE1_REG,
.power_bit = MAX310X_MODE1_FORCESLEEP_BIT,
.slave_addr = { .slave_addr = {
.min = 0x60, .min = 0x60,
.max = 0x6f, .max = 0x6f,
@ -459,8 +428,10 @@ static const struct max310x_devtype max3109_devtype = {
.name = "MAX3109", .name = "MAX3109",
.nr = 2, .nr = 2,
.mode1 = MAX310X_MODE1_AUTOSLEEP_BIT, .mode1 = MAX310X_MODE1_AUTOSLEEP_BIT,
.detect = max3109_detect, .rev_id_val = MAX3109_REV_ID,
.power = max310x_power, .rev_id_reg = MAX310X_REVID_EXTREG,
.power_reg = MAX310X_MODE1_REG,
.power_bit = MAX310X_MODE1_FORCESLEEP_BIT,
.slave_addr = { .slave_addr = {
.min = 0x60, .min = 0x60,
.max = 0x6f, .max = 0x6f,
@ -471,8 +442,10 @@ static const struct max310x_devtype max14830_devtype = {
.name = "MAX14830", .name = "MAX14830",
.nr = 4, .nr = 4,
.mode1 = MAX310X_MODE1_IRQSEL_BIT, .mode1 = MAX310X_MODE1_IRQSEL_BIT,
.detect = max14830_detect, .rev_id_val = MAX14830_REV_ID,
.power = max14830_power, .rev_id_reg = MAX310X_REVID_EXTREG,
.power_reg = MAX310X_BRGCFG_REG,
.power_bit = MAX14830_BRGCFG_CLKDIS_BIT,
.slave_addr = { .slave_addr = {
.min = 0x60, .min = 0x60,
.max = 0x6f, .max = 0x6f,
@ -490,10 +463,8 @@ static bool max310x_reg_writeable(struct device *dev, unsigned int reg)
case MAX310X_RXFIFOLVL_REG: case MAX310X_RXFIFOLVL_REG:
return false; return false;
default: default:
break; return true;
} }
return true;
} }
static bool max310x_reg_volatile(struct device *dev, unsigned int reg) static bool max310x_reg_volatile(struct device *dev, unsigned int reg)
@ -512,10 +483,8 @@ static bool max310x_reg_volatile(struct device *dev, unsigned int reg)
case MAX310X_REG_1F: case MAX310X_REG_1F:
return true; return true;
default: default:
break; return false;
} }
return false;
} }
static bool max310x_reg_precious(struct device *dev, unsigned int reg) static bool max310x_reg_precious(struct device *dev, unsigned int reg)
@ -527,10 +496,8 @@ static bool max310x_reg_precious(struct device *dev, unsigned int reg)
case MAX310X_STS_IRQSTS_REG: case MAX310X_STS_IRQSTS_REG:
return true; return true;
default: default:
break; return false;
} }
return false;
} }
static bool max310x_reg_noinc(struct device *dev, unsigned int reg) static bool max310x_reg_noinc(struct device *dev, unsigned int reg)
@ -689,7 +656,8 @@ static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen)
u8 ch, flag; u8 ch, flag;
if (port->read_status_mask == MAX310X_LSR_RXOVR_BIT) { if (port->read_status_mask == MAX310X_LSR_RXOVR_BIT) {
/* We are just reading, happily ignoring any error conditions. /*
* We are just reading, happily ignoring any error conditions.
* Break condition, parity checking, framing errors -- they * Break condition, parity checking, framing errors -- they
* are all ignored. That means that we can do a batch-read. * are all ignored. That means that we can do a batch-read.
* *
@ -698,7 +666,7 @@ static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen)
* that the LSR register applies to the "current" character. * that the LSR register applies to the "current" character.
* That's also the reason why we cannot do batched reads when * That's also the reason why we cannot do batched reads when
* asked to check the individual statuses. * asked to check the individual statuses.
* */ */
sts = max310x_port_read(port, MAX310X_LSR_IRQSTS_REG); sts = max310x_port_read(port, MAX310X_LSR_IRQSTS_REG);
max310x_batch_read(port, one->rx_buf, rxlen); max310x_batch_read(port, one->rx_buf, rxlen);
@ -802,8 +770,10 @@ static void max310x_handle_tx(struct uart_port *port)
to_send = (to_send > txlen) ? txlen : to_send; to_send = (to_send > txlen) ? txlen : to_send;
if (until_end < to_send) { if (until_end < to_send) {
/* It's a circ buffer -- wrap around. /*
* We could do that in one SPI transaction, but meh. */ * It's a circ buffer -- wrap around.
* We could do that in one SPI transaction, but meh.
*/
max310x_batch_write(port, xmit->buf + xmit->tail, until_end); max310x_batch_write(port, xmit->buf + xmit->tail, until_end);
max310x_batch_write(port, xmit->buf, to_send - until_end); max310x_batch_write(port, xmit->buf, to_send - until_end);
} else { } else {
@ -848,6 +818,7 @@ static irqreturn_t max310x_port_irq(struct max310x_port *s, int portno)
if (ists & MAX310X_IRQ_TXEMPTY_BIT) if (ists & MAX310X_IRQ_TXEMPTY_BIT)
max310x_start_tx(port); max310x_start_tx(port);
} while (1); } while (1);
return res; return res;
} }
@ -892,7 +863,8 @@ static unsigned int max310x_tx_empty(struct uart_port *port)
static unsigned int max310x_get_mctrl(struct uart_port *port) static unsigned int max310x_get_mctrl(struct uart_port *port)
{ {
/* DCD and DSR are not wired and CTS/RTS is handled automatically /*
* DCD and DSR are not wired and CTS/RTS is handled automatically
* so just indicate DSR and CAR asserted * so just indicate DSR and CAR asserted
*/ */
return TIOCM_DSR | TIOCM_CAR; return TIOCM_DSR | TIOCM_CAR;
@ -984,7 +956,8 @@ static void max310x_set_termios(struct uart_port *port,
max310x_port_write(port, MAX310X_XON1_REG, termios->c_cc[VSTART]); max310x_port_write(port, MAX310X_XON1_REG, termios->c_cc[VSTART]);
max310x_port_write(port, MAX310X_XOFF1_REG, termios->c_cc[VSTOP]); max310x_port_write(port, MAX310X_XOFF1_REG, termios->c_cc[VSTOP]);
/* Disable transmitter before enabling AutoCTS or auto transmitter /*
* Disable transmitter before enabling AutoCTS or auto transmitter
* flow control * flow control
*/ */
if (termios->c_cflag & CRTSCTS || termios->c_iflag & IXOFF) { if (termios->c_cflag & CRTSCTS || termios->c_iflag & IXOFF) {
@ -1011,7 +984,8 @@ static void max310x_set_termios(struct uart_port *port,
} }
max310x_port_write(port, MAX310X_FLOWCTRL_REG, flow); max310x_port_write(port, MAX310X_FLOWCTRL_REG, flow);
/* Enable transmitter after disabling AutoCTS and auto transmitter /*
* Enable transmitter after disabling AutoCTS and auto transmitter
* flow control * flow control
*/ */
if (!(termios->c_cflag & CRTSCTS) && !(termios->c_iflag & IXOFF)) { if (!(termios->c_cflag & CRTSCTS) && !(termios->c_iflag & IXOFF)) {
@ -1072,10 +1046,9 @@ static int max310x_rs485_config(struct uart_port *port, struct ktermios *termios
static int max310x_startup(struct uart_port *port) static int max310x_startup(struct uart_port *port)
{ {
struct max310x_port *s = dev_get_drvdata(port->dev);
unsigned int val; unsigned int val;
s->devtype->power(port, 1); max310x_power(port, 1);
/* Configure MODE1 register */ /* Configure MODE1 register */
max310x_port_update(port, MAX310X_MODE1_REG, max310x_port_update(port, MAX310X_MODE1_REG,
@ -1103,8 +1076,11 @@ static int max310x_startup(struct uart_port *port)
MAX310X_MODE2_ECHOSUPR_BIT); MAX310X_MODE2_ECHOSUPR_BIT);
} }
/* Configure flow control levels */ /*
/* Flow control halt level 96, resume level 48 */ * Configure flow control levels:
* resume: 48
* halt: 96
*/
max310x_port_write(port, MAX310X_FLOWLVL_REG, max310x_port_write(port, MAX310X_FLOWLVL_REG,
MAX310X_FLOWLVL_RES(48) | MAX310X_FLOWLVL_HALT(96)); MAX310X_FLOWLVL_RES(48) | MAX310X_FLOWLVL_HALT(96));
@ -1120,12 +1096,10 @@ static int max310x_startup(struct uart_port *port)
static void max310x_shutdown(struct uart_port *port) static void max310x_shutdown(struct uart_port *port)
{ {
struct max310x_port *s = dev_get_drvdata(port->dev);
/* Disable all interrupts */ /* Disable all interrupts */
max310x_port_write(port, MAX310X_IRQEN_REG, 0); max310x_port_write(port, MAX310X_IRQEN_REG, 0);
s->devtype->power(port, 0); max310x_power(port, 0);
} }
static const char *max310x_type(struct uart_port *port) static const char *max310x_type(struct uart_port *port)
@ -1187,7 +1161,7 @@ static int __maybe_unused max310x_suspend(struct device *dev)
for (i = 0; i < s->devtype->nr; i++) { for (i = 0; i < s->devtype->nr; i++) {
uart_suspend_port(&max310x_uart, &s->p[i].port); uart_suspend_port(&max310x_uart, &s->p[i].port);
s->devtype->power(&s->p[i].port, 0); max310x_power(&s->p[i].port, 0);
} }
return 0; return 0;
@ -1199,7 +1173,7 @@ static int __maybe_unused max310x_resume(struct device *dev)
int i; int i;
for (i = 0; i < s->devtype->nr; i++) { for (i = 0; i < s->devtype->nr; i++) {
s->devtype->power(&s->p[i].port, 1); max310x_power(&s->p[i].port, 1);
uart_resume_port(&max310x_uart, &s->p[i].port); uart_resume_port(&max310x_uart, &s->p[i].port);
} }
@ -1209,7 +1183,7 @@ static int __maybe_unused max310x_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(max310x_pm_ops, max310x_suspend, max310x_resume); static SIMPLE_DEV_PM_OPS(max310x_pm_ops, max310x_suspend, max310x_resume);
#ifdef CONFIG_GPIOLIB #ifdef CONFIG_GPIOLIB
static int max310x_gpio_get(struct gpio_chip *chip, unsigned offset) static int max310x_gpio_get(struct gpio_chip *chip, unsigned int offset)
{ {
unsigned int val; unsigned int val;
struct max310x_port *s = gpiochip_get_data(chip); struct max310x_port *s = gpiochip_get_data(chip);
@ -1220,7 +1194,7 @@ static int max310x_gpio_get(struct gpio_chip *chip, unsigned offset)
return !!((val >> 4) & (1 << (offset % 4))); return !!((val >> 4) & (1 << (offset % 4)));
} }
static void max310x_gpio_set(struct gpio_chip *chip, unsigned offset, int value) static void max310x_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
{ {
struct max310x_port *s = gpiochip_get_data(chip); struct max310x_port *s = gpiochip_get_data(chip);
struct uart_port *port = &s->p[offset / 4].port; struct uart_port *port = &s->p[offset / 4].port;
@ -1229,7 +1203,7 @@ static void max310x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
value ? 1 << (offset % 4) : 0); value ? 1 << (offset % 4) : 0);
} }
static int max310x_gpio_direction_input(struct gpio_chip *chip, unsigned offset) static int max310x_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
{ {
struct max310x_port *s = gpiochip_get_data(chip); struct max310x_port *s = gpiochip_get_data(chip);
struct uart_port *port = &s->p[offset / 4].port; struct uart_port *port = &s->p[offset / 4].port;
@ -1240,7 +1214,7 @@ static int max310x_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
} }
static int max310x_gpio_direction_output(struct gpio_chip *chip, static int max310x_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int value) unsigned int offset, int value)
{ {
struct max310x_port *s = gpiochip_get_data(chip); struct max310x_port *s = gpiochip_get_data(chip);
struct uart_port *port = &s->p[offset / 4].port; struct uart_port *port = &s->p[offset / 4].port;
@ -1296,10 +1270,9 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
/* Alloc port structure */ /* Alloc port structure */
s = devm_kzalloc(dev, struct_size(s, p, devtype->nr), GFP_KERNEL); s = devm_kzalloc(dev, struct_size(s, p, devtype->nr), GFP_KERNEL);
if (!s) { if (!s)
dev_err(dev, "Error allocating port structure\n"); return dev_err_probe(dev, -ENOMEM,
return -ENOMEM; "Error allocating port structure\n");
}
/* Always ask for fixed clock rate from a property. */ /* Always ask for fixed clock rate from a property. */
device_property_read_u32(dev, "clock-frequency", &uartclk); device_property_read_u32(dev, "clock-frequency", &uartclk);
@ -1320,8 +1293,7 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
if (freq == 0) if (freq == 0)
freq = uartclk; freq = uartclk;
if (freq == 0) { if (freq == 0) {
dev_err(dev, "Cannot get clock rate\n"); ret = dev_err_probe(dev, -EINVAL, "Cannot get clock rate\n");
ret = -EINVAL;
goto out_clk; goto out_clk;
} }
@ -1345,7 +1317,7 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
dev_set_drvdata(dev, s); dev_set_drvdata(dev, s);
/* Check device to ensure we are talking to what we expect */ /* Check device to ensure we are talking to what we expect */
ret = devtype->detect(dev); ret = max310x_detect(dev);
if (ret) if (ret)
goto out_clk; goto out_clk;
@ -1427,14 +1399,13 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
/* Register port */ /* Register port */
ret = uart_add_one_port(&max310x_uart, &s->p[i].port); ret = uart_add_one_port(&max310x_uart, &s->p[i].port);
if (ret) { if (ret)
s->p[i].port.dev = NULL;
goto out_uart; goto out_uart;
}
set_bit(line, max310x_lines); set_bit(line, max310x_lines);
/* Go to suspend mode */ /* Go to suspend mode */
devtype->power(&s->p[i].port, 0); max310x_power(&s->p[i].port, 0);
} }
#ifdef CONFIG_GPIOLIB #ifdef CONFIG_GPIOLIB
@ -1461,14 +1432,12 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
if (!ret) if (!ret)
return 0; return 0;
dev_err(dev, "Unable to reguest IRQ %i\n", irq); dev_err(dev, "Unable to request IRQ %i\n", irq);
out_uart: out_uart:
for (i = 0; i < devtype->nr; i++) { for (i = 0; i < devtype->nr; i++) {
if (s->p[i].port.dev) { if (test_and_clear_bit(s->p[i].port.line, max310x_lines))
uart_remove_one_port(&max310x_uart, &s->p[i].port); uart_remove_one_port(&max310x_uart, &s->p[i].port);
clear_bit(s->p[i].port.line, max310x_lines);
}
} }
out_clk: out_clk:
@ -1486,9 +1455,11 @@ static void max310x_remove(struct device *dev)
cancel_work_sync(&s->p[i].tx_work); cancel_work_sync(&s->p[i].tx_work);
cancel_work_sync(&s->p[i].md_work); cancel_work_sync(&s->p[i].md_work);
cancel_work_sync(&s->p[i].rs_work); cancel_work_sync(&s->p[i].rs_work);
uart_remove_one_port(&max310x_uart, &s->p[i].port);
clear_bit(s->p[i].port.line, max310x_lines); if (test_and_clear_bit(s->p[i].port.line, max310x_lines))
s->devtype->power(&s->p[i].port, 0); uart_remove_one_port(&max310x_uart, &s->p[i].port);
max310x_power(&s->p[i].port, 0);
} }
clk_disable_unprepare(s->clk); clk_disable_unprepare(s->clk);
@ -1518,6 +1489,19 @@ static struct regmap_config regcfg = {
.max_raw_write = MAX310X_FIFO_SIZE, .max_raw_write = MAX310X_FIFO_SIZE,
}; };
static const char *max310x_regmap_name(u8 port_id)
{
switch (port_id) {
case 0: return "port0";
case 1: return "port1";
case 2: return "port2";
case 3: return "port3";
default:
WARN_ON(true);
return NULL;
}
}
#ifdef CONFIG_SPI_MASTER #ifdef CONFIG_SPI_MASTER
static int max310x_spi_extended_reg_enable(struct device *dev, bool enable) static int max310x_spi_extended_reg_enable(struct device *dev, bool enable)
{ {
@ -1529,13 +1513,13 @@ static int max310x_spi_extended_reg_enable(struct device *dev, bool enable)
static const struct max310x_if_cfg __maybe_unused max310x_spi_if_cfg = { static const struct max310x_if_cfg __maybe_unused max310x_spi_if_cfg = {
.extended_reg_enable = max310x_spi_extended_reg_enable, .extended_reg_enable = max310x_spi_extended_reg_enable,
.rev_id_reg = MAX310X_SPI_REVID_EXTREG, .rev_id_offset = MAX310X_EXTREG_START,
}; };
static int max310x_spi_probe(struct spi_device *spi) static int max310x_spi_probe(struct spi_device *spi)
{ {
const struct max310x_devtype *devtype; const struct max310x_devtype *devtype;
struct regmap *regmaps[4]; struct regmap *regmaps[MAX310X_MAX_PORTS];
unsigned int i; unsigned int i;
int ret; int ret;
@ -1547,12 +1531,14 @@ static int max310x_spi_probe(struct spi_device *spi)
if (ret) if (ret)
return ret; return ret;
devtype = device_get_match_data(&spi->dev); devtype = spi_get_device_match_data(spi);
if (!devtype) if (!devtype)
devtype = (struct max310x_devtype *)spi_get_device_id(spi)->driver_data; return dev_err_probe(&spi->dev, -ENODEV, "Failed to match device\n");
for (i = 0; i < devtype->nr; i++) { for (i = 0; i < devtype->nr; i++) {
u8 port_mask = i * 0x20; u8 port_mask = i * 0x20;
regcfg.name = max310x_regmap_name(i);
regcfg.read_flag_mask = port_mask; regcfg.read_flag_mask = port_mask;
regcfg.write_flag_mask = port_mask | MAX310X_WRITE_BIT; regcfg.write_flag_mask = port_mask | MAX310X_WRITE_BIT;
regmaps[i] = devm_regmap_init_spi(spi, &regcfg); regmaps[i] = devm_regmap_init_spi(spi, &regcfg);
@ -1600,7 +1586,7 @@ static struct regmap_config regcfg_i2c = {
.writeable_reg = max310x_reg_writeable, .writeable_reg = max310x_reg_writeable,
.volatile_reg = max310x_reg_volatile, .volatile_reg = max310x_reg_volatile,
.precious_reg = max310x_reg_precious, .precious_reg = max310x_reg_precious,
.max_register = MAX310X_I2C_REVID_EXTREG, .max_register = MAX310X_REVID_EXTREG,
.writeable_noinc_reg = max310x_reg_noinc, .writeable_noinc_reg = max310x_reg_noinc,
.readable_noinc_reg = max310x_reg_noinc, .readable_noinc_reg = max310x_reg_noinc,
.max_raw_read = MAX310X_FIFO_SIZE, .max_raw_read = MAX310X_FIFO_SIZE,
@ -1609,7 +1595,7 @@ static struct regmap_config regcfg_i2c = {
static const struct max310x_if_cfg max310x_i2c_if_cfg = { static const struct max310x_if_cfg max310x_i2c_if_cfg = {
.extended_reg_enable = max310x_i2c_extended_reg_enable, .extended_reg_enable = max310x_i2c_extended_reg_enable,
.rev_id_reg = MAX310X_I2C_REVID_EXTREG, .rev_id_offset = 0, /* No offset in I2C mode. */
}; };
static unsigned short max310x_i2c_slave_addr(unsigned short addr, static unsigned short max310x_i2c_slave_addr(unsigned short addr,
@ -1619,10 +1605,10 @@ static unsigned short max310x_i2c_slave_addr(unsigned short addr,
* For MAX14830 and MAX3109, the slave address depends on what the * For MAX14830 and MAX3109, the slave address depends on what the
* A0 and A1 pins are tied to. * A0 and A1 pins are tied to.
* See Table I2C Address Map of the datasheet. * See Table I2C Address Map of the datasheet.
* Based on that table, the following formulas were determined. * Based on that table, the following formulas were determined:
* UART1 - UART0 = 0x10 * UART1 - UART0 = 0x10
* UART2 - UART1 = 0x20 + 0x10 * UART2 - UART1 = 0x20 + 0x10
* UART3 - UART2 = 0x10 * UART3 - UART2 = 0x10
*/ */
addr -= nr * 0x10; addr -= nr * 0x10;
@ -1635,20 +1621,24 @@ static unsigned short max310x_i2c_slave_addr(unsigned short addr,
static int max310x_i2c_probe(struct i2c_client *client) static int max310x_i2c_probe(struct i2c_client *client)
{ {
const struct max310x_devtype *devtype = const struct max310x_devtype *devtype;
device_get_match_data(&client->dev);
struct i2c_client *port_client; struct i2c_client *port_client;
struct regmap *regmaps[4]; struct regmap *regmaps[MAX310X_MAX_PORTS];
unsigned int i; unsigned int i;
u8 port_addr; u8 port_addr;
devtype = i2c_get_match_data(client);
if (!devtype)
return dev_err_probe(&client->dev, -ENODEV, "Failed to match device\n");
if (client->addr < devtype->slave_addr.min || if (client->addr < devtype->slave_addr.min ||
client->addr > devtype->slave_addr.max) client->addr > devtype->slave_addr.max)
return dev_err_probe(&client->dev, -EINVAL, return dev_err_probe(&client->dev, -EINVAL,
"Slave addr 0x%x outside of range [0x%x, 0x%x]\n", "Slave addr 0x%x outside of range [0x%x, 0x%x]\n",
client->addr, devtype->slave_addr.min, client->addr, devtype->slave_addr.min,
devtype->slave_addr.max); devtype->slave_addr.max);
regcfg_i2c.name = max310x_regmap_name(0);
regmaps[0] = devm_regmap_init_i2c(client, &regcfg_i2c); regmaps[0] = devm_regmap_init_i2c(client, &regcfg_i2c);
for (i = 1; i < devtype->nr; i++) { for (i = 1; i < devtype->nr; i++) {
@ -1657,6 +1647,7 @@ static int max310x_i2c_probe(struct i2c_client *client)
client->adapter, client->adapter,
port_addr); port_addr);
regcfg_i2c.name = max310x_regmap_name(i);
regmaps[i] = devm_regmap_init_i2c(port_client, &regcfg_i2c); regmaps[i] = devm_regmap_init_i2c(port_client, &regcfg_i2c);
} }
@ -1669,6 +1660,15 @@ static void max310x_i2c_remove(struct i2c_client *client)
max310x_remove(&client->dev); max310x_remove(&client->dev);
} }
static const struct i2c_device_id max310x_i2c_id_table[] = {
{ "max3107", (kernel_ulong_t)&max3107_devtype, },
{ "max3108", (kernel_ulong_t)&max3108_devtype, },
{ "max3109", (kernel_ulong_t)&max3109_devtype, },
{ "max14830", (kernel_ulong_t)&max14830_devtype, },
{ }
};
MODULE_DEVICE_TABLE(i2c, max310x_i2c_id_table);
static struct i2c_driver max310x_i2c_driver = { static struct i2c_driver max310x_i2c_driver = {
.driver = { .driver = {
.name = MAX310X_NAME, .name = MAX310X_NAME,
@ -1677,6 +1677,7 @@ static struct i2c_driver max310x_i2c_driver = {
}, },
.probe = max310x_i2c_probe, .probe = max310x_i2c_probe,
.remove = max310x_i2c_remove, .remove = max310x_i2c_remove,
.id_table = max310x_i2c_id_table,
}; };
#endif #endif

View File

@ -470,33 +470,6 @@ static struct mcf_uart mcf_ports[4];
#if defined(CONFIG_SERIAL_MCF_CONSOLE) #if defined(CONFIG_SERIAL_MCF_CONSOLE)
/****************************************************************************/ /****************************************************************************/
int __init early_mcf_setup(struct mcf_platform_uart *platp)
{
struct uart_port *port;
int i;
for (i = 0; ((i < MCF_MAXPORTS) && (platp[i].mapbase)); i++) {
port = &mcf_ports[i].port;
port->line = i;
port->type = PORT_MCF;
port->mapbase = platp[i].mapbase;
port->membase = (platp[i].membase) ? platp[i].membase :
(unsigned char __iomem *) port->mapbase;
port->iotype = SERIAL_IO_MEM;
port->irq = platp[i].irq;
port->uartclk = MCF_BUSCLK;
port->flags = UPF_BOOT_AUTOCONF;
port->rs485_config = mcf_config_rs485;
port->rs485_supported = mcf_rs485_supported;
port->ops = &mcf_uart_ops;
}
return 0;
}
/****************************************************************************/
static void mcf_console_putc(struct console *co, const char c) static void mcf_console_putc(struct console *co, const char c)
{ {
struct uart_port *port = &(mcf_ports + co->index)->port; struct uart_port *port = &(mcf_ports + co->index)->port;

View File

@ -220,7 +220,7 @@ static void meson_receive_chars(struct uart_port *port)
continue; continue;
} }
if (uart_handle_sysrq_char(port, ch)) if (uart_prepare_sysrq_char(port, ch))
continue; continue;
if ((status & port->ignore_status_mask) == 0) if ((status & port->ignore_status_mask) == 0)
@ -248,7 +248,7 @@ static irqreturn_t meson_uart_interrupt(int irq, void *dev_id)
meson_uart_start_tx(port); meson_uart_start_tx(port);
} }
uart_port_unlock(port); uart_unlock_and_check_sysrq(port);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -556,18 +556,13 @@ static void meson_serial_port_write(struct uart_port *port, const char *s,
u_int count) u_int count)
{ {
unsigned long flags; unsigned long flags;
int locked; int locked = 1;
u32 val, tmp; u32 val, tmp;
local_irq_save(flags); if (oops_in_progress)
if (port->sysrq) { locked = uart_port_trylock_irqsave(port, &flags);
locked = 0; else
} else if (oops_in_progress) { uart_port_lock_irqsave(port, &flags);
locked = uart_port_trylock(port);
} else {
uart_port_lock(port);
locked = 1;
}
val = readl(port->membase + AML_UART_CONTROL); val = readl(port->membase + AML_UART_CONTROL);
tmp = val & ~(AML_UART_TX_INT_EN | AML_UART_RX_INT_EN); tmp = val & ~(AML_UART_TX_INT_EN | AML_UART_RX_INT_EN);
@ -577,8 +572,7 @@ static void meson_serial_port_write(struct uart_port *port, const char *s,
writel(val, port->membase + AML_UART_CONTROL); writel(val, port->membase + AML_UART_CONTROL);
if (locked) if (locked)
uart_port_unlock(port); uart_port_unlock_irqrestore(port, flags);
local_irq_restore(flags);
} }
static void meson_serial_console_write(struct console *co, const char *s, static void meson_serial_console_write(struct console *co, const char *s,

View File

@ -588,16 +588,14 @@ static void msm_complete_rx_dma(void *args)
if (!(port->read_status_mask & MSM_UART_SR_RX_BREAK)) if (!(port->read_status_mask & MSM_UART_SR_RX_BREAK))
flag = TTY_NORMAL; flag = TTY_NORMAL;
uart_port_unlock_irqrestore(port, flags); sysrq = uart_prepare_sysrq_char(port, dma->virt[i]);
sysrq = uart_handle_sysrq_char(port, dma->virt[i]);
uart_port_lock_irqsave(port, &flags);
if (!sysrq) if (!sysrq)
tty_insert_flip_char(tport, dma->virt[i], flag); tty_insert_flip_char(tport, dma->virt[i], flag);
} }
msm_start_rx_dma(msm_port); msm_start_rx_dma(msm_port);
done: done:
uart_port_unlock_irqrestore(port, flags); uart_unlock_and_check_sysrq_irqrestore(port, flags);
if (count) if (count)
tty_flip_buffer_push(tport); tty_flip_buffer_push(tport);
@ -763,9 +761,7 @@ static void msm_handle_rx_dm(struct uart_port *port, unsigned int misr)
if (!(port->read_status_mask & MSM_UART_SR_RX_BREAK)) if (!(port->read_status_mask & MSM_UART_SR_RX_BREAK))
flag = TTY_NORMAL; flag = TTY_NORMAL;
uart_port_unlock(port); sysrq = uart_prepare_sysrq_char(port, buf[i]);
sysrq = uart_handle_sysrq_char(port, buf[i]);
uart_port_lock(port);
if (!sysrq) if (!sysrq)
tty_insert_flip_char(tport, buf[i], flag); tty_insert_flip_char(tport, buf[i], flag);
} }
@ -825,9 +821,7 @@ static void msm_handle_rx(struct uart_port *port)
else if (sr & MSM_UART_SR_PAR_FRAME_ERR) else if (sr & MSM_UART_SR_PAR_FRAME_ERR)
flag = TTY_FRAME; flag = TTY_FRAME;
uart_port_unlock(port); sysrq = uart_prepare_sysrq_char(port, c);
sysrq = uart_handle_sysrq_char(port, c);
uart_port_lock(port);
if (!sysrq) if (!sysrq)
tty_insert_flip_char(tport, c, flag); tty_insert_flip_char(tport, c, flag);
} }
@ -948,11 +942,10 @@ static irqreturn_t msm_uart_irq(int irq, void *dev_id)
struct uart_port *port = dev_id; struct uart_port *port = dev_id;
struct msm_port *msm_port = to_msm_port(port); struct msm_port *msm_port = to_msm_port(port);
struct msm_dma *dma = &msm_port->rx_dma; struct msm_dma *dma = &msm_port->rx_dma;
unsigned long flags;
unsigned int misr; unsigned int misr;
u32 val; u32 val;
uart_port_lock_irqsave(port, &flags); uart_port_lock(port);
misr = msm_read(port, MSM_UART_MISR); misr = msm_read(port, MSM_UART_MISR);
msm_write(port, 0, MSM_UART_IMR); /* disable interrupt */ msm_write(port, 0, MSM_UART_IMR); /* disable interrupt */
@ -984,7 +977,7 @@ static irqreturn_t msm_uart_irq(int irq, void *dev_id)
msm_handle_delta_cts(port); msm_handle_delta_cts(port);
msm_write(port, msm_port->imr, MSM_UART_IMR); /* restore interrupt */ msm_write(port, msm_port->imr, MSM_UART_IMR); /* restore interrupt */
uart_port_unlock_irqrestore(port, flags); uart_unlock_and_check_sysrq(port);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -1621,14 +1614,10 @@ static void __msm_console_write(struct uart_port *port, const char *s,
num_newlines++; num_newlines++;
count += num_newlines; count += num_newlines;
local_irq_save(flags); if (oops_in_progress)
locked = uart_port_trylock_irqsave(port, &flags);
if (port->sysrq)
locked = 0;
else if (oops_in_progress)
locked = uart_port_trylock(port);
else else
uart_port_lock(port); uart_port_lock_irqsave(port, &flags);
if (is_uartdm) if (is_uartdm)
msm_reset_dm_count(port, count); msm_reset_dm_count(port, count);
@ -1667,9 +1656,7 @@ static void __msm_console_write(struct uart_port *port, const char *s,
} }
if (locked) if (locked)
uart_port_unlock(port); uart_port_unlock_irqrestore(port, flags);
local_irq_restore(flags);
} }
static void msm_console_write(struct console *co, const char *s, static void msm_console_write(struct console *co, const char *s,

View File

@ -508,7 +508,7 @@ static void serial_omap_rdi(struct uart_omap_port *up, unsigned int lsr)
up->port.icount.rx++; up->port.icount.rx++;
if (uart_handle_sysrq_char(&up->port, ch)) if (uart_prepare_sysrq_char(&up->port, ch))
return; return;
uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, TTY_NORMAL); uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, TTY_NORMAL);
@ -563,7 +563,7 @@ static irqreturn_t serial_omap_irq(int irq, void *dev_id)
} }
} while (max_count--); } while (max_count--);
uart_port_unlock(&up->port); uart_unlock_and_check_sysrq(&up->port);
tty_flip_buffer_push(&up->port.state->port); tty_flip_buffer_push(&up->port.state->port);
@ -1212,13 +1212,10 @@ serial_omap_console_write(struct console *co, const char *s,
unsigned int ier; unsigned int ier;
int locked = 1; int locked = 1;
local_irq_save(flags); if (oops_in_progress)
if (up->port.sysrq) locked = uart_port_trylock_irqsave(&up->port, &flags);
locked = 0;
else if (oops_in_progress)
locked = uart_port_trylock(&up->port);
else else
uart_port_lock(&up->port); uart_port_lock_irqsave(&up->port, &flags);
/* /*
* First save the IER then disable the interrupts * First save the IER then disable the interrupts
@ -1245,8 +1242,7 @@ serial_omap_console_write(struct console *co, const char *s,
check_modem_status(up); check_modem_status(up);
if (locked) if (locked)
uart_port_unlock(&up->port); uart_port_unlock_irqrestore(&up->port, flags);
local_irq_restore(flags);
} }
static int __init static int __init

View File

@ -199,6 +199,7 @@ static void owl_uart_receive_chars(struct uart_port *port)
stat = owl_uart_read(port, OWL_UART_STAT); stat = owl_uart_read(port, OWL_UART_STAT);
while (!(stat & OWL_UART_STAT_RFEM)) { while (!(stat & OWL_UART_STAT_RFEM)) {
char flag = TTY_NORMAL; char flag = TTY_NORMAL;
bool sysrq;
if (stat & OWL_UART_STAT_RXER) if (stat & OWL_UART_STAT_RXER)
port->icount.overrun++; port->icount.overrun++;
@ -217,7 +218,9 @@ static void owl_uart_receive_chars(struct uart_port *port)
val = owl_uart_read(port, OWL_UART_RXDAT); val = owl_uart_read(port, OWL_UART_RXDAT);
val &= 0xff; val &= 0xff;
if ((stat & port->ignore_status_mask) == 0) sysrq = uart_prepare_sysrq_char(port, val);
if (!sysrq && (stat & port->ignore_status_mask) == 0)
tty_insert_flip_char(&port->state->port, val, flag); tty_insert_flip_char(&port->state->port, val, flag);
stat = owl_uart_read(port, OWL_UART_STAT); stat = owl_uart_read(port, OWL_UART_STAT);
@ -229,10 +232,9 @@ static void owl_uart_receive_chars(struct uart_port *port)
static irqreturn_t owl_uart_irq(int irq, void *dev_id) static irqreturn_t owl_uart_irq(int irq, void *dev_id)
{ {
struct uart_port *port = dev_id; struct uart_port *port = dev_id;
unsigned long flags;
u32 stat; u32 stat;
uart_port_lock_irqsave(port, &flags); uart_port_lock(port);
stat = owl_uart_read(port, OWL_UART_STAT); stat = owl_uart_read(port, OWL_UART_STAT);
@ -246,7 +248,7 @@ static irqreturn_t owl_uart_irq(int irq, void *dev_id)
stat |= OWL_UART_STAT_RIP | OWL_UART_STAT_TIP; stat |= OWL_UART_STAT_RIP | OWL_UART_STAT_TIP;
owl_uart_write(port, stat, OWL_UART_STAT); owl_uart_write(port, stat, OWL_UART_STAT);
uart_port_unlock_irqrestore(port, flags); uart_unlock_and_check_sysrq(port);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -508,18 +510,12 @@ static void owl_uart_port_write(struct uart_port *port, const char *s,
{ {
u32 old_ctl, val; u32 old_ctl, val;
unsigned long flags; unsigned long flags;
int locked; int locked = 1;
local_irq_save(flags); if (oops_in_progress)
locked = uart_port_trylock_irqsave(port, &flags);
if (port->sysrq) else
locked = 0; uart_port_lock_irqsave(port, &flags);
else if (oops_in_progress)
locked = uart_port_trylock(port);
else {
uart_port_lock(port);
locked = 1;
}
old_ctl = owl_uart_read(port, OWL_UART_CTL); old_ctl = owl_uart_read(port, OWL_UART_CTL);
val = old_ctl | OWL_UART_CTL_TRFS_TX; val = old_ctl | OWL_UART_CTL_TRFS_TX;
@ -541,9 +537,7 @@ static void owl_uart_port_write(struct uart_port *port, const char *s,
owl_uart_write(port, old_ctl, OWL_UART_CTL); owl_uart_write(port, old_ctl, OWL_UART_CTL);
if (locked) if (locked)
uart_port_unlock(port); uart_port_unlock_irqrestore(port, flags);
local_irq_restore(flags);
} }
static void owl_uart_console_write(struct console *co, const char *s, static void owl_uart_console_write(struct console *co, const char *s,

View File

@ -237,9 +237,6 @@ struct eg20t_port {
#define IRQ_NAME_SIZE 17 #define IRQ_NAME_SIZE 17
char irq_name[IRQ_NAME_SIZE]; char irq_name[IRQ_NAME_SIZE];
/* protect the eg20t_port private structure and io access to membase */
spinlock_t lock;
}; };
/** /**
@ -567,7 +564,7 @@ static int pch_uart_hal_read(struct eg20t_port *priv, unsigned char *buf,
if (uart_handle_break(port)) if (uart_handle_break(port))
continue; continue;
} }
if (uart_handle_sysrq_char(port, rbr)) if (uart_prepare_sysrq_char(port, rbr))
continue; continue;
buf[i++] = rbr; buf[i++] = rbr;
@ -599,16 +596,14 @@ static void pch_uart_hal_set_break(struct eg20t_port *priv, int on)
iowrite8(lcr, priv->membase + UART_LCR); iowrite8(lcr, priv->membase + UART_LCR);
} }
static int push_rx(struct eg20t_port *priv, const unsigned char *buf, static void push_rx(struct eg20t_port *priv, const unsigned char *buf,
int size) int size)
{ {
struct uart_port *port = &priv->port; struct uart_port *port = &priv->port;
struct tty_port *tport = &port->state->port; struct tty_port *tport = &port->state->port;
tty_insert_flip_string(tport, buf, size); tty_insert_flip_string(tport, buf, size);
tty_flip_buffer_push(tport); tty_flip_buffer_push(tport);
return 0;
} }
static int dma_push_rx(struct eg20t_port *priv, int size) static int dma_push_rx(struct eg20t_port *priv, int size)
@ -761,7 +756,7 @@ static int handle_rx_to(struct eg20t_port *priv)
{ {
struct pch_uart_buffer *buf; struct pch_uart_buffer *buf;
int rx_size; int rx_size;
int ret;
if (!priv->start_rx) { if (!priv->start_rx) {
pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT | pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT |
PCH_UART_HAL_RX_ERR_INT); PCH_UART_HAL_RX_ERR_INT);
@ -770,19 +765,12 @@ static int handle_rx_to(struct eg20t_port *priv)
buf = &priv->rxbuf; buf = &priv->rxbuf;
do { do {
rx_size = pch_uart_hal_read(priv, buf->buf, buf->size); rx_size = pch_uart_hal_read(priv, buf->buf, buf->size);
ret = push_rx(priv, buf->buf, rx_size); push_rx(priv, buf->buf, rx_size);
if (ret)
return 0;
} while (rx_size == buf->size); } while (rx_size == buf->size);
return PCH_UART_HANDLED_RX_INT; return PCH_UART_HANDLED_RX_INT;
} }
static int handle_rx(struct eg20t_port *priv)
{
return handle_rx_to(priv);
}
static int dma_handle_rx(struct eg20t_port *priv) static int dma_handle_rx(struct eg20t_port *priv)
{ {
struct uart_port *port = &priv->port; struct uart_port *port = &priv->port;
@ -1019,11 +1007,10 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
u8 lsr; u8 lsr;
int ret = 0; int ret = 0;
unsigned char iid; unsigned char iid;
unsigned long flags;
int next = 1; int next = 1;
u8 msr; u8 msr;
spin_lock_irqsave(&priv->lock, flags); uart_port_lock(&priv->port);
handled = 0; handled = 0;
while (next) { while (next) {
iid = pch_uart_hal_get_iid(priv); iid = pch_uart_hal_get_iid(priv);
@ -1051,7 +1038,7 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
PCH_UART_HAL_RX_INT | PCH_UART_HAL_RX_INT |
PCH_UART_HAL_RX_ERR_INT); PCH_UART_HAL_RX_ERR_INT);
} else { } else {
ret = handle_rx(priv); ret = handle_rx_to(priv);
} }
break; break;
case PCH_UART_IID_RDR_TO: /* Received Data Ready case PCH_UART_IID_RDR_TO: /* Received Data Ready
@ -1083,7 +1070,7 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
handled |= (unsigned int)ret; handled |= (unsigned int)ret;
} }
spin_unlock_irqrestore(&priv->lock, flags); uart_unlock_and_check_sysrq(&priv->port);
return IRQ_RETVAL(handled); return IRQ_RETVAL(handled);
} }
@ -1194,9 +1181,9 @@ static void pch_uart_break_ctl(struct uart_port *port, int ctl)
unsigned long flags; unsigned long flags;
priv = container_of(port, struct eg20t_port, port); priv = container_of(port, struct eg20t_port, port);
spin_lock_irqsave(&priv->lock, flags); uart_port_lock_irqsave(&priv->port, &flags);
pch_uart_hal_set_break(priv, ctl); pch_uart_hal_set_break(priv, ctl);
spin_unlock_irqrestore(&priv->lock, flags); uart_port_unlock_irqrestore(&priv->port, flags);
} }
/* Grab any interrupt resources and initialise any low level driver state. */ /* Grab any interrupt resources and initialise any low level driver state. */
@ -1346,8 +1333,7 @@ static void pch_uart_set_termios(struct uart_port *port,
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
spin_lock_irqsave(&priv->lock, flags); uart_port_lock_irqsave(port, &flags);
uart_port_lock(port);
uart_update_timeout(port, termios->c_cflag, baud); uart_update_timeout(port, termios->c_cflag, baud);
rtn = pch_uart_hal_set_line(priv, baud, parity, bits, stb); rtn = pch_uart_hal_set_line(priv, baud, parity, bits, stb);
@ -1360,8 +1346,7 @@ static void pch_uart_set_termios(struct uart_port *port,
tty_termios_encode_baud_rate(termios, baud, baud); tty_termios_encode_baud_rate(termios, baud, baud);
out: out:
uart_port_unlock(port); uart_port_unlock_irqrestore(port, flags);
spin_unlock_irqrestore(&priv->lock, flags);
} }
static const char *pch_uart_type(struct uart_port *port) static const char *pch_uart_type(struct uart_port *port)
@ -1565,27 +1550,17 @@ pch_console_write(struct console *co, const char *s, unsigned int count)
{ {
struct eg20t_port *priv; struct eg20t_port *priv;
unsigned long flags; unsigned long flags;
int priv_locked = 1; int locked = 1;
int port_locked = 1;
u8 ier; u8 ier;
priv = pch_uart_ports[co->index]; priv = pch_uart_ports[co->index];
touch_nmi_watchdog(); touch_nmi_watchdog();
local_irq_save(flags); if (oops_in_progress)
if (priv->port.sysrq) { locked = uart_port_trylock_irqsave(&priv->port, &flags);
/* call to uart_handle_sysrq_char already took the priv lock */ else
priv_locked = 0; uart_port_lock_irqsave(&priv->port, &flags);
/* serial8250_handle_port() already took the port lock */
port_locked = 0;
} else if (oops_in_progress) {
priv_locked = spin_trylock(&priv->lock);
port_locked = uart_port_trylock(&priv->port);
} else {
spin_lock(&priv->lock);
uart_port_lock(&priv->port);
}
/* /*
* First save the IER then disable the interrupts * First save the IER then disable the interrupts
@ -1603,11 +1578,8 @@ pch_console_write(struct console *co, const char *s, unsigned int count)
wait_for_xmitr(priv, UART_LSR_BOTH_EMPTY); wait_for_xmitr(priv, UART_LSR_BOTH_EMPTY);
iowrite8(ier, priv->membase + UART_IER); iowrite8(ier, priv->membase + UART_IER);
if (port_locked) if (locked)
uart_port_unlock(&priv->port); uart_port_unlock_irqrestore(&priv->port, flags);
if (priv_locked)
spin_unlock(&priv->lock);
local_irq_restore(flags);
} }
static int __init pch_console_setup(struct console *co, char *options) static int __init pch_console_setup(struct console *co, char *options)
@ -1704,8 +1676,6 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
pci_enable_msi(pdev); pci_enable_msi(pdev);
pci_set_master(pdev); pci_set_master(pdev);
spin_lock_init(&priv->lock);
iobase = pci_resource_start(pdev, 0); iobase = pci_resource_start(pdev, 0);
mapbase = pci_resource_start(pdev, 1); mapbase = pci_resource_start(pdev, 1);
priv->mapbase = mapbase; priv->mapbase = mapbase;
@ -1735,8 +1705,6 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
KBUILD_MODNAME ":" PCH_UART_DRIVER_DEVICE "%d", KBUILD_MODNAME ":" PCH_UART_DRIVER_DEVICE "%d",
priv->port.line); priv->port.line);
spin_lock_init(&priv->port.lock);
pci_set_drvdata(pdev, priv); pci_set_drvdata(pdev, priv);
priv->trigger_level = 1; priv->trigger_level = 1;
priv->fcr = 0; priv->fcr = 0;

View File

@ -1714,18 +1714,13 @@ static int __init pmz_attach(struct platform_device *pdev)
return uart_add_one_port(&pmz_uart_reg, &uap->port); return uart_add_one_port(&pmz_uart_reg, &uap->port);
} }
static int __exit pmz_detach(struct platform_device *pdev) static void __exit pmz_detach(struct platform_device *pdev)
{ {
struct uart_pmac_port *uap = platform_get_drvdata(pdev); struct uart_pmac_port *uap = platform_get_drvdata(pdev);
if (!uap)
return -ENODEV;
uart_remove_one_port(&pmz_uart_reg, &uap->port); uart_remove_one_port(&pmz_uart_reg, &uap->port);
uap->port.dev = NULL; uap->port.dev = NULL;
return 0;
} }
#endif /* !CONFIG_PPC_PMAC */ #endif /* !CONFIG_PPC_PMAC */
@ -1794,7 +1789,7 @@ static struct macio_driver pmz_driver = {
#else #else
static struct platform_driver pmz_driver = { static struct platform_driver pmz_driver = {
.remove = __exit_p(pmz_detach), .remove_new = __exit_p(pmz_detach),
.driver = { .driver = {
.name = "scc", .name = "scc",
}, },

View File

@ -151,7 +151,7 @@ static inline void receive_chars(struct uart_pxa_port *up, int *status)
flag = TTY_FRAME; flag = TTY_FRAME;
} }
if (uart_handle_sysrq_char(&up->port, ch)) if (uart_prepare_sysrq_char(&up->port, ch))
goto ignore_char; goto ignore_char;
uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag); uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag);
@ -232,7 +232,7 @@ static inline irqreturn_t serial_pxa_irq(int irq, void *dev_id)
check_modem_status(up); check_modem_status(up);
if (lsr & UART_LSR_THRE) if (lsr & UART_LSR_THRE)
transmit_chars(up); transmit_chars(up);
uart_port_unlock(&up->port); uart_unlock_and_check_sysrq(&up->port);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -604,13 +604,10 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
int locked = 1; int locked = 1;
clk_enable(up->clk); clk_enable(up->clk);
local_irq_save(flags); if (oops_in_progress)
if (up->port.sysrq) locked = uart_port_trylock_irqsave(&up->port, &flags);
locked = 0;
else if (oops_in_progress)
locked = uart_port_trylock(&up->port);
else else
uart_port_lock(&up->port); uart_port_lock_irqsave(&up->port, &flags);
/* /*
* First save the IER then disable the interrupts * First save the IER then disable the interrupts
@ -628,10 +625,8 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
serial_out(up, UART_IER, ier); serial_out(up, UART_IER, ier);
if (locked) if (locked)
uart_port_unlock(&up->port); uart_port_unlock_irqrestore(&up->port, flags);
local_irq_restore(flags);
clk_disable(up->clk); clk_disable(up->clk);
} }
#ifdef CONFIG_CONSOLE_POLL #ifdef CONFIG_CONSOLE_POLL

View File

@ -488,18 +488,16 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s,
geni_status = readl(uport->membase + SE_GENI_STATUS); geni_status = readl(uport->membase + SE_GENI_STATUS);
/* Cancel the current write to log the fault */
if (!locked) { if (!locked) {
geni_se_cancel_m_cmd(&port->se); /*
if (!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, * We can only get here if an oops is in progress then we were
M_CMD_CANCEL_EN, true)) { * unable to get the lock. This means we can't safely access
geni_se_abort_m_cmd(&port->se); * our state variables like tx_remaining. About the best we
qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, * can do is wait for the FIFO to be empty before we start our
M_CMD_ABORT_EN, true); * transfer, so we'll do that.
writel(M_CMD_ABORT_EN, uport->membase + */
SE_GENI_M_IRQ_CLEAR); qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
} M_TX_FIFO_NOT_EMPTY_EN, false);
writel(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
} else if ((geni_status & M_GENI_CMD_ACTIVE) && !port->tx_remaining) { } else if ((geni_status & M_GENI_CMD_ACTIVE) && !port->tx_remaining) {
/* /*
* It seems we can't interrupt existing transfers if all data * It seems we can't interrupt existing transfers if all data
@ -516,11 +514,12 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s,
__qcom_geni_serial_console_write(uport, s, count); __qcom_geni_serial_console_write(uport, s, count);
if (port->tx_remaining)
qcom_geni_serial_setup_tx(uport, port->tx_remaining);
if (locked) if (locked) {
if (port->tx_remaining)
qcom_geni_serial_setup_tx(uport, port->tx_remaining);
uart_port_unlock_irqrestore(uport, flags); uart_port_unlock_irqrestore(uport, flags);
}
} }
static void handle_rx_console(struct uart_port *uport, u32 bytes, bool drop) static void handle_rx_console(struct uart_port *uport, u32 bytes, bool drop)

View File

@ -394,7 +394,8 @@ static void rda_uart_receive_chars(struct uart_port *port)
val &= 0xff; val &= 0xff;
port->icount.rx++; port->icount.rx++;
tty_insert_flip_char(&port->state->port, val, flag); if (!uart_prepare_sysrq_char(port, val))
tty_insert_flip_char(&port->state->port, val, flag);
status = rda_uart_read(port, RDA_UART_STATUS); status = rda_uart_read(port, RDA_UART_STATUS);
} }
@ -405,10 +406,9 @@ static void rda_uart_receive_chars(struct uart_port *port)
static irqreturn_t rda_interrupt(int irq, void *dev_id) static irqreturn_t rda_interrupt(int irq, void *dev_id)
{ {
struct uart_port *port = dev_id; struct uart_port *port = dev_id;
unsigned long flags;
u32 val, irq_mask; u32 val, irq_mask;
uart_port_lock_irqsave(port, &flags); uart_port_lock(port);
/* Clear IRQ cause */ /* Clear IRQ cause */
val = rda_uart_read(port, RDA_UART_IRQ_CAUSE); val = rda_uart_read(port, RDA_UART_IRQ_CAUSE);
@ -425,7 +425,7 @@ static irqreturn_t rda_interrupt(int irq, void *dev_id)
rda_uart_send_chars(port); rda_uart_send_chars(port);
} }
uart_port_unlock_irqrestore(port, flags); uart_unlock_and_check_sysrq(port);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -590,18 +590,12 @@ static void rda_uart_port_write(struct uart_port *port, const char *s,
{ {
u32 old_irq_mask; u32 old_irq_mask;
unsigned long flags; unsigned long flags;
int locked; int locked = 1;
local_irq_save(flags); if (oops_in_progress)
locked = uart_port_trylock_irqsave(port, &flags);
if (port->sysrq) { else
locked = 0; uart_port_lock_irqsave(port, &flags);
} else if (oops_in_progress) {
locked = uart_port_trylock(port);
} else {
uart_port_lock(port);
locked = 1;
}
old_irq_mask = rda_uart_read(port, RDA_UART_IRQ_MASK); old_irq_mask = rda_uart_read(port, RDA_UART_IRQ_MASK);
rda_uart_write(port, 0, RDA_UART_IRQ_MASK); rda_uart_write(port, 0, RDA_UART_IRQ_MASK);
@ -615,9 +609,7 @@ static void rda_uart_port_write(struct uart_port *port, const char *s,
rda_uart_write(port, old_irq_mask, RDA_UART_IRQ_MASK); rda_uart_write(port, old_irq_mask, RDA_UART_IRQ_MASK);
if (locked) if (locked)
uart_port_unlock(port); uart_port_unlock_irqrestore(port, flags);
local_irq_restore(flags);
} }
static void rda_uart_console_write(struct console *co, const char *s, static void rda_uart_console_write(struct console *co, const char *s,

View File

@ -21,26 +21,28 @@
* BJD, 04-Nov-2004 * BJD, 04-Nov-2004
*/ */
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/math.h>
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/sysrq.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <linux/serial_s3c.h>
#include <linux/delay.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/math.h>
#include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/serial_s3c.h>
#include <linux/slab.h>
#include <linux/sysrq.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/types.h>
#include <asm/irq.h> #include <asm/irq.h>
/* UART name and device definitions */ /* UART name and device definitions */
@ -73,21 +75,21 @@ struct s3c24xx_uart_info {
enum s3c24xx_port_type type; enum s3c24xx_port_type type;
unsigned int port_type; unsigned int port_type;
unsigned int fifosize; unsigned int fifosize;
unsigned long rx_fifomask; u32 rx_fifomask;
unsigned long rx_fifoshift; u32 rx_fifoshift;
unsigned long rx_fifofull; u32 rx_fifofull;
unsigned long tx_fifomask; u32 tx_fifomask;
unsigned long tx_fifoshift; u32 tx_fifoshift;
unsigned long tx_fifofull; u32 tx_fifofull;
unsigned int def_clk_sel; u32 clksel_mask;
unsigned long num_clks; u32 clksel_shift;
unsigned long clksel_mask; u32 ucon_mask;
unsigned long clksel_shift; u8 def_clk_sel;
unsigned long ucon_mask; u8 num_clks;
u8 iotype;
/* uart port features */ /* uart port features */
bool has_divslot;
unsigned int has_divslot:1;
}; };
struct s3c24xx_serial_drv_data { struct s3c24xx_serial_drv_data {
@ -196,7 +198,7 @@ static void wr_reg(const struct uart_port *port, u32 reg, u32 val)
/* Byte-order aware bit setting/clearing functions. */ /* Byte-order aware bit setting/clearing functions. */
static inline void s3c24xx_set_bit(const struct uart_port *port, int idx, static inline void s3c24xx_set_bit(const struct uart_port *port, int idx,
unsigned int reg) u32 reg)
{ {
unsigned long flags; unsigned long flags;
u32 val; u32 val;
@ -209,7 +211,7 @@ static inline void s3c24xx_set_bit(const struct uart_port *port, int idx,
} }
static inline void s3c24xx_clear_bit(const struct uart_port *port, int idx, static inline void s3c24xx_clear_bit(const struct uart_port *port, int idx,
unsigned int reg) u32 reg)
{ {
unsigned long flags; unsigned long flags;
u32 val; u32 val;
@ -233,7 +235,7 @@ static inline const char *s3c24xx_serial_portname(const struct uart_port *port)
return to_platform_device(port->dev)->name; return to_platform_device(port->dev)->name;
} }
static int s3c24xx_serial_txempty_nofifo(const struct uart_port *port) static bool s3c24xx_serial_txempty_nofifo(const struct uart_port *port)
{ {
return rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE; return rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE;
} }
@ -242,8 +244,8 @@ static void s3c24xx_serial_rx_enable(struct uart_port *port)
{ {
struct s3c24xx_uart_port *ourport = to_ourport(port); struct s3c24xx_uart_port *ourport = to_ourport(port);
unsigned long flags; unsigned long flags;
unsigned int ucon, ufcon;
int count = 10000; int count = 10000;
u32 ucon, ufcon;
uart_port_lock_irqsave(port, &flags); uart_port_lock_irqsave(port, &flags);
@ -266,7 +268,7 @@ static void s3c24xx_serial_rx_disable(struct uart_port *port)
{ {
struct s3c24xx_uart_port *ourport = to_ourport(port); struct s3c24xx_uart_port *ourport = to_ourport(port);
unsigned long flags; unsigned long flags;
unsigned int ucon; u32 ucon;
uart_port_lock_irqsave(port, &flags); uart_port_lock_irqsave(port, &flags);
@ -587,8 +589,8 @@ static inline const struct s3c2410_uartcfg
return ourport->cfg; return ourport->cfg;
} }
static int s3c24xx_serial_rx_fifocnt(const struct s3c24xx_uart_port *ourport, static unsigned int
unsigned long ufstat) s3c24xx_serial_rx_fifocnt(const struct s3c24xx_uart_port *ourport, u32 ufstat)
{ {
const struct s3c24xx_uart_info *info = ourport->info; const struct s3c24xx_uart_info *info = ourport->info;
@ -660,7 +662,7 @@ static void s3c64xx_start_rx_dma(struct s3c24xx_uart_port *ourport)
static void enable_rx_dma(struct s3c24xx_uart_port *ourport) static void enable_rx_dma(struct s3c24xx_uart_port *ourport)
{ {
struct uart_port *port = &ourport->port; struct uart_port *port = &ourport->port;
unsigned int ucon; u32 ucon;
/* set Rx mode to DMA mode */ /* set Rx mode to DMA mode */
ucon = rd_regl(port, S3C2410_UCON); ucon = rd_regl(port, S3C2410_UCON);
@ -683,7 +685,7 @@ static void enable_rx_dma(struct s3c24xx_uart_port *ourport)
static void enable_rx_pio(struct s3c24xx_uart_port *ourport) static void enable_rx_pio(struct s3c24xx_uart_port *ourport)
{ {
struct uart_port *port = &ourport->port; struct uart_port *port = &ourport->port;
unsigned int ucon; u32 ucon;
/* set Rx mode to DMA mode */ /* set Rx mode to DMA mode */
ucon = rd_regl(port, S3C2410_UCON); ucon = rd_regl(port, S3C2410_UCON);
@ -708,13 +710,14 @@ static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport);
static irqreturn_t s3c24xx_serial_rx_chars_dma(void *dev_id) static irqreturn_t s3c24xx_serial_rx_chars_dma(void *dev_id)
{ {
unsigned int utrstat, received;
struct s3c24xx_uart_port *ourport = dev_id; struct s3c24xx_uart_port *ourport = dev_id;
struct uart_port *port = &ourport->port; struct uart_port *port = &ourport->port;
struct s3c24xx_uart_dma *dma = ourport->dma; struct s3c24xx_uart_dma *dma = ourport->dma;
struct tty_struct *tty = tty_port_tty_get(&ourport->port.state->port); struct tty_struct *tty = tty_port_tty_get(&ourport->port.state->port);
struct tty_port *t = &port->state->port; struct tty_port *t = &port->state->port;
struct dma_tx_state state; struct dma_tx_state state;
unsigned int received;
u32 utrstat;
utrstat = rd_regl(port, S3C2410_UTRSTAT); utrstat = rd_regl(port, S3C2410_UTRSTAT);
rd_regl(port, S3C2410_UFSTAT); rd_regl(port, S3C2410_UFSTAT);
@ -756,9 +759,9 @@ finish:
static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport) static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport)
{ {
struct uart_port *port = &ourport->port; struct uart_port *port = &ourport->port;
unsigned int ufcon, ufstat, uerstat; unsigned int max_count = port->fifosize;
unsigned int fifocnt = 0; unsigned int fifocnt = 0;
int max_count = port->fifosize; u32 ufcon, ufstat, uerstat;
u8 ch, flag; u8 ch, flag;
while (max_count-- > 0) { while (max_count-- > 0) {
@ -778,7 +781,7 @@ static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport)
ch = rd_reg(port, S3C2410_URXH); ch = rd_reg(port, S3C2410_URXH);
if (port->flags & UPF_CONS_FLOW) { if (port->flags & UPF_CONS_FLOW) {
int txe = s3c24xx_serial_txempty_nofifo(port); bool txe = s3c24xx_serial_txempty_nofifo(port);
if (ourport->rx_enabled) { if (ourport->rx_enabled) {
if (!txe) { if (!txe) {
@ -942,7 +945,7 @@ static irqreturn_t s3c64xx_serial_handle_irq(int irq, void *id)
{ {
const struct s3c24xx_uart_port *ourport = id; const struct s3c24xx_uart_port *ourport = id;
const struct uart_port *port = &ourport->port; const struct uart_port *port = &ourport->port;
unsigned int pend = rd_regl(port, S3C64XX_UINTP); u32 pend = rd_regl(port, S3C64XX_UINTP);
irqreturn_t ret = IRQ_HANDLED; irqreturn_t ret = IRQ_HANDLED;
if (pend & S3C64XX_UINTM_RXD_MSK) { if (pend & S3C64XX_UINTM_RXD_MSK) {
@ -961,7 +964,7 @@ static irqreturn_t apple_serial_handle_irq(int irq, void *id)
{ {
const struct s3c24xx_uart_port *ourport = id; const struct s3c24xx_uart_port *ourport = id;
const struct uart_port *port = &ourport->port; const struct uart_port *port = &ourport->port;
unsigned int pend = rd_regl(port, S3C2410_UTRSTAT); u32 pend = rd_regl(port, S3C2410_UTRSTAT);
irqreturn_t ret = IRQ_NONE; irqreturn_t ret = IRQ_NONE;
if (pend & (APPLE_S5L_UTRSTAT_RXTHRESH | APPLE_S5L_UTRSTAT_RXTO)) { if (pend & (APPLE_S5L_UTRSTAT_RXTHRESH | APPLE_S5L_UTRSTAT_RXTO)) {
@ -980,24 +983,23 @@ static irqreturn_t apple_serial_handle_irq(int irq, void *id)
static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port) static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port)
{ {
const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
unsigned long ufstat = rd_regl(port, S3C2410_UFSTAT); u32 ufstat = rd_regl(port, S3C2410_UFSTAT);
unsigned long ufcon = rd_regl(port, S3C2410_UFCON); u32 ufcon = rd_regl(port, S3C2410_UFCON);
if (ufcon & S3C2410_UFCON_FIFOMODE) { if (ufcon & S3C2410_UFCON_FIFOMODE) {
if ((ufstat & info->tx_fifomask) != 0 || if ((ufstat & info->tx_fifomask) ||
(ufstat & info->tx_fifofull)) (ufstat & info->tx_fifofull))
return 0; return 0;
return TIOCSER_TEMT;
return 1;
} }
return s3c24xx_serial_txempty_nofifo(port); return s3c24xx_serial_txempty_nofifo(port) ? TIOCSER_TEMT : 0;
} }
/* no modem control lines */ /* no modem control lines */
static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port) static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port)
{ {
unsigned int umstat = rd_reg(port, S3C2410_UMSTAT); u32 umstat = rd_reg(port, S3C2410_UMSTAT);
if (umstat & S3C2410_UMSTAT_CTS) if (umstat & S3C2410_UMSTAT_CTS)
return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
@ -1007,8 +1009,8 @@ static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port)
static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl) static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
{ {
unsigned int umcon = rd_regl(port, S3C2410_UMCON); u32 umcon = rd_regl(port, S3C2410_UMCON);
unsigned int ucon = rd_regl(port, S3C2410_UCON); u32 ucon = rd_regl(port, S3C2410_UCON);
if (mctrl & TIOCM_RTS) if (mctrl & TIOCM_RTS)
umcon |= S3C2410_UMCOM_RTS_LOW; umcon |= S3C2410_UMCOM_RTS_LOW;
@ -1028,7 +1030,7 @@ static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state) static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state)
{ {
unsigned long flags; unsigned long flags;
unsigned int ucon; u32 ucon;
uart_port_lock_irqsave(port, &flags); uart_port_lock_irqsave(port, &flags);
@ -1186,7 +1188,7 @@ static void apple_s5l_serial_shutdown(struct uart_port *port)
{ {
struct s3c24xx_uart_port *ourport = to_ourport(port); struct s3c24xx_uart_port *ourport = to_ourport(port);
unsigned int ucon; u32 ucon;
ucon = rd_regl(port, S3C2410_UCON); ucon = rd_regl(port, S3C2410_UCON);
ucon &= ~(APPLE_S5L_UCON_TXTHRESH_ENA_MSK | ucon &= ~(APPLE_S5L_UCON_TXTHRESH_ENA_MSK |
@ -1212,7 +1214,7 @@ static int s3c64xx_serial_startup(struct uart_port *port)
{ {
struct s3c24xx_uart_port *ourport = to_ourport(port); struct s3c24xx_uart_port *ourport = to_ourport(port);
unsigned long flags; unsigned long flags;
unsigned int ufcon; u32 ufcon;
int ret; int ret;
wr_regl(port, S3C64XX_UINTM, 0xf); wr_regl(port, S3C64XX_UINTM, 0xf);
@ -1257,7 +1259,7 @@ static int apple_s5l_serial_startup(struct uart_port *port)
{ {
struct s3c24xx_uart_port *ourport = to_ourport(port); struct s3c24xx_uart_port *ourport = to_ourport(port);
unsigned long flags; unsigned long flags;
unsigned int ufcon; u32 ufcon;
int ret; int ret;
wr_regl(port, S3C2410_UTRSTAT, APPLE_S5L_UTRSTAT_ALL_FLAGS); wr_regl(port, S3C2410_UTRSTAT, APPLE_S5L_UTRSTAT_ALL_FLAGS);
@ -1292,8 +1294,6 @@ static int apple_s5l_serial_startup(struct uart_port *port)
return ret; return ret;
} }
/* power power management control */
static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
unsigned int old) unsigned int old)
{ {
@ -1339,10 +1339,10 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
#define MAX_CLK_NAME_LENGTH 15 #define MAX_CLK_NAME_LENGTH 15
static inline int s3c24xx_serial_getsource(struct uart_port *port) static inline u8 s3c24xx_serial_getsource(struct uart_port *port)
{ {
const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
unsigned int ucon; u32 ucon;
if (info->num_clks == 1) if (info->num_clks == 1)
return 0; return 0;
@ -1352,11 +1352,10 @@ static inline int s3c24xx_serial_getsource(struct uart_port *port)
return ucon >> info->clksel_shift; return ucon >> info->clksel_shift;
} }
static void s3c24xx_serial_setsource(struct uart_port *port, static void s3c24xx_serial_setsource(struct uart_port *port, u8 clk_sel)
unsigned int clk_sel)
{ {
const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
unsigned int ucon; u32 ucon;
if (info->num_clks == 1) if (info->num_clks == 1)
return; return;
@ -1372,14 +1371,15 @@ static void s3c24xx_serial_setsource(struct uart_port *port,
static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport, static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport,
unsigned int req_baud, struct clk **best_clk, unsigned int req_baud, struct clk **best_clk,
unsigned int *clk_num) u8 *clk_num)
{ {
const struct s3c24xx_uart_info *info = ourport->info; const struct s3c24xx_uart_info *info = ourport->info;
struct clk *clk; struct clk *clk;
unsigned long rate; unsigned long rate;
unsigned int cnt, baud, quot, best_quot = 0; unsigned int baud, quot, best_quot = 0;
char clkname[MAX_CLK_NAME_LENGTH]; char clkname[MAX_CLK_NAME_LENGTH];
int calc_deviation, deviation = (1 << 30) - 1; int calc_deviation, deviation = (1 << 30) - 1;
u8 cnt;
for (cnt = 0; cnt < info->num_clks; cnt++) { for (cnt = 0; cnt < info->num_clks; cnt++) {
/* Keep selected clock if provided */ /* Keep selected clock if provided */
@ -1472,10 +1472,10 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
struct s3c24xx_uart_port *ourport = to_ourport(port); struct s3c24xx_uart_port *ourport = to_ourport(port);
struct clk *clk = ERR_PTR(-EINVAL); struct clk *clk = ERR_PTR(-EINVAL);
unsigned long flags; unsigned long flags;
unsigned int baud, quot, clk_sel = 0; unsigned int baud, quot;
unsigned int ulcon;
unsigned int umcon;
unsigned int udivslot = 0; unsigned int udivslot = 0;
u32 ulcon, umcon;
u8 clk_sel = 0;
/* /*
* We don't support modem control lines. * We don't support modem control lines.
@ -1737,12 +1737,12 @@ static struct uart_driver s3c24xx_uart_drv = {
static struct s3c24xx_uart_port s3c24xx_serial_ports[UART_NR]; static struct s3c24xx_uart_port s3c24xx_serial_ports[UART_NR];
static void s3c24xx_serial_init_port_default(int index) { static void s3c24xx_serial_init_port_default(int index)
{
struct uart_port *port = &s3c24xx_serial_ports[index].port; struct uart_port *port = &s3c24xx_serial_ports[index].port;
spin_lock_init(&port->lock); spin_lock_init(&port->lock);
port->iotype = UPIO_MEM;
port->uartclk = 0; port->uartclk = 0;
port->fifosize = 16; port->fifosize = 16;
port->flags = UPF_BOOT_AUTOCONF; port->flags = UPF_BOOT_AUTOCONF;
@ -1758,7 +1758,7 @@ static void s3c24xx_serial_resetport(struct uart_port *port,
const struct s3c2410_uartcfg *cfg) const struct s3c2410_uartcfg *cfg)
{ {
const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
unsigned long ucon = rd_regl(port, S3C2410_UCON); u32 ucon = rd_regl(port, S3C2410_UCON);
ucon &= (info->clksel_mask | info->ucon_mask); ucon &= (info->clksel_mask | info->ucon_mask);
wr_regl(port, S3C2410_UCON, ucon | cfg->ucon); wr_regl(port, S3C2410_UCON, ucon | cfg->ucon);
@ -1776,10 +1776,9 @@ static int s3c24xx_serial_enable_baudclk(struct s3c24xx_uart_port *ourport)
struct device *dev = ourport->port.dev; struct device *dev = ourport->port.dev;
const struct s3c24xx_uart_info *info = ourport->info; const struct s3c24xx_uart_info *info = ourport->info;
char clk_name[MAX_CLK_NAME_LENGTH]; char clk_name[MAX_CLK_NAME_LENGTH];
unsigned int clk_sel;
struct clk *clk; struct clk *clk;
int clk_num;
int ret; int ret;
u8 clk_sel, clk_num;
clk_sel = ourport->cfg->clk_sel ? : info->def_clk_sel; clk_sel = ourport->cfg->clk_sel ? : info->def_clk_sel;
for (clk_num = 0; clk_num < info->num_clks; clk_num++) { for (clk_num = 0; clk_num < info->num_clks; clk_num++) {
@ -1904,7 +1903,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
wr_regl(port, S3C64XX_UINTSP, 0xf); wr_regl(port, S3C64XX_UINTSP, 0xf);
break; break;
case TYPE_APPLE_S5L: { case TYPE_APPLE_S5L: {
unsigned int ucon; u32 ucon;
ucon = rd_regl(port, S3C2410_UCON); ucon = rd_regl(port, S3C2410_UCON);
ucon &= ~(APPLE_S5L_UCON_TXTHRESH_ENA_MSK | ucon &= ~(APPLE_S5L_UCON_TXTHRESH_ENA_MSK |
@ -1952,7 +1951,7 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
struct s3c24xx_uart_port *ourport; struct s3c24xx_uart_port *ourport;
int index = probe_index; int index = probe_index;
int ret, prop = 0; int ret, prop = 0, fifosize_prop = 1;
if (np) { if (np) {
ret = of_alias_get_id(np, "serial"); ret = of_alias_get_id(np, "serial");
@ -1989,9 +1988,11 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
break; break;
} }
ourport->port.iotype = ourport->info->iotype;
if (np) { if (np) {
of_property_read_u32(np, fifosize_prop = of_property_read_u32(np, "samsung,uart-fifosize",
"samsung,uart-fifosize", &ourport->port.fifosize); &ourport->port.fifosize);
if (of_property_read_u32(np, "reg-io-width", &prop) == 0) { if (of_property_read_u32(np, "reg-io-width", &prop) == 0) {
switch (prop) { switch (prop) {
@ -2009,10 +2010,13 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
} }
} }
if (ourport->drv_data->fifosize[index]) if (fifosize_prop) {
ourport->port.fifosize = ourport->drv_data->fifosize[index]; if (ourport->drv_data->fifosize[index])
else if (ourport->info->fifosize) ourport->port.fifosize = ourport->drv_data->fifosize[index];
ourport->port.fifosize = ourport->info->fifosize; else if (ourport->info->fifosize)
ourport->port.fifosize = ourport->info->fifosize;
}
ourport->port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_SAMSUNG_CONSOLE); ourport->port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_SAMSUNG_CONSOLE);
/* /*
@ -2058,9 +2062,8 @@ static void s3c24xx_serial_remove(struct platform_device *dev)
{ {
struct uart_port *port = s3c24xx_dev_to_port(&dev->dev); struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
if (port) { if (port)
uart_remove_one_port(&s3c24xx_uart_drv, port); uart_remove_one_port(&s3c24xx_uart_drv, port);
}
uart_unregister_driver(&s3c24xx_uart_drv); uart_unregister_driver(&s3c24xx_uart_drv);
} }
@ -2106,7 +2109,7 @@ static int s3c24xx_serial_resume_noirq(struct device *dev)
/* restore IRQ mask */ /* restore IRQ mask */
switch (ourport->info->type) { switch (ourport->info->type) {
case TYPE_S3C6400: { case TYPE_S3C6400: {
unsigned int uintm = 0xf; u32 uintm = 0xf;
if (ourport->tx_enabled) if (ourport->tx_enabled)
uintm &= ~S3C64XX_UINTM_TXD_MSK; uintm &= ~S3C64XX_UINTM_TXD_MSK;
@ -2122,7 +2125,7 @@ static int s3c24xx_serial_resume_noirq(struct device *dev)
break; break;
} }
case TYPE_APPLE_S5L: { case TYPE_APPLE_S5L: {
unsigned int ucon; u32 ucon;
int ret; int ret;
ret = clk_prepare_enable(ourport->clk); ret = clk_prepare_enable(ourport->clk);
@ -2183,27 +2186,27 @@ static const struct dev_pm_ops s3c24xx_serial_pm_ops = {
static struct uart_port *cons_uart; static struct uart_port *cons_uart;
static int static bool
s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon) s3c24xx_serial_console_txrdy(struct uart_port *port, u32 ufcon)
{ {
const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
unsigned long ufstat, utrstat; u32 ufstat, utrstat;
if (ufcon & S3C2410_UFCON_FIFOMODE) { if (ufcon & S3C2410_UFCON_FIFOMODE) {
/* fifo mode - check amount of data in fifo registers... */ /* fifo mode - check amount of data in fifo registers... */
ufstat = rd_regl(port, S3C2410_UFSTAT); ufstat = rd_regl(port, S3C2410_UFSTAT);
return (ufstat & info->tx_fifofull) ? 0 : 1; return !(ufstat & info->tx_fifofull);
} }
/* in non-fifo mode, we go and use the tx buffer empty */ /* in non-fifo mode, we go and use the tx buffer empty */
utrstat = rd_regl(port, S3C2410_UTRSTAT); utrstat = rd_regl(port, S3C2410_UTRSTAT);
return (utrstat & S3C2410_UTRSTAT_TXE) ? 1 : 0; return utrstat & S3C2410_UTRSTAT_TXE;
} }
static bool static bool
s3c24xx_port_configured(unsigned int ucon) s3c24xx_port_configured(u32 ucon)
{ {
/* consider the serial port configured if the tx/rx mode set */ /* consider the serial port configured if the tx/rx mode set */
return (ucon & 0xf) != 0; return (ucon & 0xf) != 0;
@ -2218,7 +2221,7 @@ s3c24xx_port_configured(unsigned int ucon)
static int s3c24xx_serial_get_poll_char(struct uart_port *port) static int s3c24xx_serial_get_poll_char(struct uart_port *port)
{ {
const struct s3c24xx_uart_port *ourport = to_ourport(port); const struct s3c24xx_uart_port *ourport = to_ourport(port);
unsigned int ufstat; u32 ufstat;
ufstat = rd_regl(port, S3C2410_UFSTAT); ufstat = rd_regl(port, S3C2410_UFSTAT);
if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0) if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0)
@ -2230,8 +2233,8 @@ static int s3c24xx_serial_get_poll_char(struct uart_port *port)
static void s3c24xx_serial_put_poll_char(struct uart_port *port, static void s3c24xx_serial_put_poll_char(struct uart_port *port,
unsigned char c) unsigned char c)
{ {
unsigned int ufcon = rd_regl(port, S3C2410_UFCON); u32 ufcon = rd_regl(port, S3C2410_UFCON);
unsigned int ucon = rd_regl(port, S3C2410_UCON); u32 ucon = rd_regl(port, S3C2410_UCON);
/* not possible to xmit on unconfigured port */ /* not possible to xmit on unconfigured port */
if (!s3c24xx_port_configured(ucon)) if (!s3c24xx_port_configured(ucon))
@ -2247,7 +2250,7 @@ static void s3c24xx_serial_put_poll_char(struct uart_port *port,
static void static void
s3c24xx_serial_console_putchar(struct uart_port *port, unsigned char ch) s3c24xx_serial_console_putchar(struct uart_port *port, unsigned char ch)
{ {
unsigned int ufcon = rd_regl(port, S3C2410_UFCON); u32 ufcon = rd_regl(port, S3C2410_UFCON);
while (!s3c24xx_serial_console_txrdy(port, ufcon)) while (!s3c24xx_serial_console_txrdy(port, ufcon))
cpu_relax(); cpu_relax();
@ -2258,7 +2261,7 @@ static void
s3c24xx_serial_console_write(struct console *co, const char *s, s3c24xx_serial_console_write(struct console *co, const char *s,
unsigned int count) unsigned int count)
{ {
unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON); u32 ucon = rd_regl(cons_uart, S3C2410_UCON);
unsigned long flags; unsigned long flags;
bool locked = true; bool locked = true;
@ -2285,12 +2288,10 @@ s3c24xx_serial_get_options(struct uart_port *port, int *baud,
int *parity, int *bits) int *parity, int *bits)
{ {
struct clk *clk; struct clk *clk;
unsigned int ulcon;
unsigned int ucon;
unsigned int ubrdiv;
unsigned long rate; unsigned long rate;
unsigned int clk_sel; u32 ulcon, ucon, ubrdiv;
char clk_name[MAX_CLK_NAME_LENGTH]; char clk_name[MAX_CLK_NAME_LENGTH];
u8 clk_sel;
ulcon = rd_regl(port, S3C2410_ULCON); ulcon = rd_regl(port, S3C2410_ULCON);
ucon = rd_regl(port, S3C2410_UCON); ucon = rd_regl(port, S3C2410_UCON);
@ -2399,8 +2400,9 @@ static const struct s3c24xx_serial_drv_data s3c6400_serial_drv_data = {
.name = "Samsung S3C6400 UART", .name = "Samsung S3C6400 UART",
.type = TYPE_S3C6400, .type = TYPE_S3C6400,
.port_type = PORT_S3C6400, .port_type = PORT_S3C6400,
.iotype = UPIO_MEM,
.fifosize = 64, .fifosize = 64,
.has_divslot = 1, .has_divslot = true,
.rx_fifomask = S3C2440_UFSTAT_RXMASK, .rx_fifomask = S3C2440_UFSTAT_RXMASK,
.rx_fifoshift = S3C2440_UFSTAT_RXSHIFT, .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT,
.rx_fifofull = S3C2440_UFSTAT_RXFULL, .rx_fifofull = S3C2440_UFSTAT_RXFULL,
@ -2428,7 +2430,8 @@ static const struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = {
.name = "Samsung S5PV210 UART", .name = "Samsung S5PV210 UART",
.type = TYPE_S3C6400, .type = TYPE_S3C6400,
.port_type = PORT_S3C6400, .port_type = PORT_S3C6400,
.has_divslot = 1, .iotype = UPIO_MEM,
.has_divslot = true,
.rx_fifomask = S5PV210_UFSTAT_RXMASK, .rx_fifomask = S5PV210_UFSTAT_RXMASK,
.rx_fifoshift = S5PV210_UFSTAT_RXSHIFT, .rx_fifoshift = S5PV210_UFSTAT_RXSHIFT,
.rx_fifofull = S5PV210_UFSTAT_RXFULL, .rx_fifofull = S5PV210_UFSTAT_RXFULL,
@ -2452,12 +2455,13 @@ static const struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = {
#endif #endif
#if defined(CONFIG_ARCH_EXYNOS) #if defined(CONFIG_ARCH_EXYNOS)
#define EXYNOS_COMMON_SERIAL_DRV_DATA() \ #define EXYNOS_COMMON_SERIAL_DRV_DATA \
.info = { \ .info = { \
.name = "Samsung Exynos UART", \ .name = "Samsung Exynos UART", \
.type = TYPE_S3C6400, \ .type = TYPE_S3C6400, \
.port_type = PORT_S3C6400, \ .port_type = PORT_S3C6400, \
.has_divslot = 1, \ .iotype = UPIO_MEM, \
.has_divslot = true, \
.rx_fifomask = S5PV210_UFSTAT_RXMASK, \ .rx_fifomask = S5PV210_UFSTAT_RXMASK, \
.rx_fifoshift = S5PV210_UFSTAT_RXSHIFT, \ .rx_fifoshift = S5PV210_UFSTAT_RXSHIFT, \
.rx_fifofull = S5PV210_UFSTAT_RXFULL, \ .rx_fifofull = S5PV210_UFSTAT_RXFULL, \
@ -2476,39 +2480,57 @@ static const struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = {
} \ } \
static const struct s3c24xx_serial_drv_data exynos4210_serial_drv_data = { static const struct s3c24xx_serial_drv_data exynos4210_serial_drv_data = {
EXYNOS_COMMON_SERIAL_DRV_DATA(), EXYNOS_COMMON_SERIAL_DRV_DATA,
.fifosize = { 256, 64, 16, 16 }, .fifosize = { 256, 64, 16, 16 },
}; };
static const struct s3c24xx_serial_drv_data exynos5433_serial_drv_data = { static const struct s3c24xx_serial_drv_data exynos5433_serial_drv_data = {
EXYNOS_COMMON_SERIAL_DRV_DATA(), EXYNOS_COMMON_SERIAL_DRV_DATA,
.fifosize = { 64, 256, 16, 256 }, .fifosize = { 64, 256, 16, 256 },
}; };
static const struct s3c24xx_serial_drv_data exynos850_serial_drv_data = { static const struct s3c24xx_serial_drv_data exynos850_serial_drv_data = {
EXYNOS_COMMON_SERIAL_DRV_DATA(), EXYNOS_COMMON_SERIAL_DRV_DATA,
.fifosize = { 256, 64, 64, 64 }, .fifosize = { 256, 64, 64, 64 },
}; };
/* static const struct s3c24xx_serial_drv_data gs101_serial_drv_data = {
* Common drv_data struct for platforms that specify samsung,uart-fifosize in .info = {
* device tree. .name = "Google GS101 UART",
*/ .type = TYPE_S3C6400,
static const struct s3c24xx_serial_drv_data exynos_fifoszdt_serial_drv_data = { .port_type = PORT_S3C6400,
EXYNOS_COMMON_SERIAL_DRV_DATA(), .iotype = UPIO_MEM32,
.has_divslot = true,
.rx_fifomask = S5PV210_UFSTAT_RXMASK,
.rx_fifoshift = S5PV210_UFSTAT_RXSHIFT,
.rx_fifofull = S5PV210_UFSTAT_RXFULL,
.tx_fifofull = S5PV210_UFSTAT_TXFULL,
.tx_fifomask = S5PV210_UFSTAT_TXMASK,
.tx_fifoshift = S5PV210_UFSTAT_TXSHIFT,
.def_clk_sel = S3C2410_UCON_CLKSEL0,
.num_clks = 1,
.clksel_mask = 0,
.clksel_shift = 0,
},
.def_cfg = {
.ucon = S5PV210_UCON_DEFAULT,
.ufcon = S5PV210_UFCON_DEFAULT,
.has_fracval = 1,
},
/* samsung,uart-fifosize must be specified in the device tree. */
.fifosize = { 0 }, .fifosize = { 0 },
}; };
#define EXYNOS4210_SERIAL_DRV_DATA (&exynos4210_serial_drv_data) #define EXYNOS4210_SERIAL_DRV_DATA (&exynos4210_serial_drv_data)
#define EXYNOS5433_SERIAL_DRV_DATA (&exynos5433_serial_drv_data) #define EXYNOS5433_SERIAL_DRV_DATA (&exynos5433_serial_drv_data)
#define EXYNOS850_SERIAL_DRV_DATA (&exynos850_serial_drv_data) #define EXYNOS850_SERIAL_DRV_DATA (&exynos850_serial_drv_data)
#define EXYNOS_FIFOSZDT_DRV_DATA (&exynos_fifoszdt_serial_drv_data) #define GS101_SERIAL_DRV_DATA (&gs101_serial_drv_data)
#else #else
#define EXYNOS4210_SERIAL_DRV_DATA NULL #define EXYNOS4210_SERIAL_DRV_DATA NULL
#define EXYNOS5433_SERIAL_DRV_DATA NULL #define EXYNOS5433_SERIAL_DRV_DATA NULL
#define EXYNOS850_SERIAL_DRV_DATA NULL #define EXYNOS850_SERIAL_DRV_DATA NULL
#define EXYNOS_FIFOSZDT_DRV_DATA NULL #define GS101_SERIAL_DRV_DATA NULL
#endif #endif
#ifdef CONFIG_ARCH_APPLE #ifdef CONFIG_ARCH_APPLE
@ -2517,6 +2539,7 @@ static const struct s3c24xx_serial_drv_data s5l_serial_drv_data = {
.name = "Apple S5L UART", .name = "Apple S5L UART",
.type = TYPE_APPLE_S5L, .type = TYPE_APPLE_S5L,
.port_type = PORT_8250, .port_type = PORT_8250,
.iotype = UPIO_MEM,
.fifosize = 16, .fifosize = 16,
.rx_fifomask = S3C2410_UFSTAT_RXMASK, .rx_fifomask = S3C2410_UFSTAT_RXMASK,
.rx_fifoshift = S3C2410_UFSTAT_RXSHIFT, .rx_fifoshift = S3C2410_UFSTAT_RXSHIFT,
@ -2546,8 +2569,9 @@ static const struct s3c24xx_serial_drv_data artpec8_serial_drv_data = {
.name = "Axis ARTPEC-8 UART", .name = "Axis ARTPEC-8 UART",
.type = TYPE_S3C6400, .type = TYPE_S3C6400,
.port_type = PORT_S3C6400, .port_type = PORT_S3C6400,
.iotype = UPIO_MEM,
.fifosize = 64, .fifosize = 64,
.has_divslot = 1, .has_divslot = true,
.rx_fifomask = S5PV210_UFSTAT_RXMASK, .rx_fifomask = S5PV210_UFSTAT_RXMASK,
.rx_fifoshift = S5PV210_UFSTAT_RXSHIFT, .rx_fifoshift = S5PV210_UFSTAT_RXSHIFT,
.rx_fifofull = S5PV210_UFSTAT_RXFULL, .rx_fifofull = S5PV210_UFSTAT_RXFULL,
@ -2594,7 +2618,7 @@ static const struct platform_device_id s3c24xx_serial_driver_ids[] = {
.driver_data = (kernel_ulong_t)ARTPEC8_SERIAL_DRV_DATA, .driver_data = (kernel_ulong_t)ARTPEC8_SERIAL_DRV_DATA,
}, { }, {
.name = "gs101-uart", .name = "gs101-uart",
.driver_data = (kernel_ulong_t)EXYNOS_FIFOSZDT_DRV_DATA, .driver_data = (kernel_ulong_t)GS101_SERIAL_DRV_DATA,
}, },
{ }, { },
}; };
@ -2617,7 +2641,7 @@ static const struct of_device_id s3c24xx_uart_dt_match[] = {
{ .compatible = "axis,artpec8-uart", { .compatible = "axis,artpec8-uart",
.data = ARTPEC8_SERIAL_DRV_DATA }, .data = ARTPEC8_SERIAL_DRV_DATA },
{ .compatible = "google,gs101-uart", { .compatible = "google,gs101-uart",
.data = EXYNOS_FIFOSZDT_DRV_DATA }, .data = GS101_SERIAL_DRV_DATA },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, s3c24xx_uart_dt_match); MODULE_DEVICE_TABLE(of, s3c24xx_uart_dt_match);
@ -2716,7 +2740,8 @@ static int samsung_early_read(struct console *con, char *s, unsigned int n)
{ {
struct earlycon_device *dev = con->data; struct earlycon_device *dev = con->data;
const struct samsung_early_console_data *data = dev->port.private_data; const struct samsung_early_console_data *data = dev->port.private_data;
int ch, ufstat, num_read = 0; int num_read = 0;
u32 ch, ufstat;
while (num_read < n) { while (num_read < n) {
ufstat = rd_regl(&dev->port, S3C2410_UFSTAT); ufstat = rd_regl(&dev->port, S3C2410_UFSTAT);
@ -2785,6 +2810,17 @@ OF_EARLYCON_DECLARE(exynos4210, "samsung,exynos4210-uart",
OF_EARLYCON_DECLARE(artpec8, "axis,artpec8-uart", OF_EARLYCON_DECLARE(artpec8, "axis,artpec8-uart",
s5pv210_early_console_setup); s5pv210_early_console_setup);
static int __init gs101_early_console_setup(struct earlycon_device *device,
const char *opt)
{
/* gs101 always expects MMIO32 register accesses. */
device->port.iotype = UPIO_MEM32;
return s5pv210_early_console_setup(device, opt);
}
OF_EARLYCON_DECLARE(gs101, "google,gs101-uart", gs101_early_console_setup);
/* Apple S5L */ /* Apple S5L */
static int __init apple_s5l_early_console_setup(struct earlycon_device *device, static int __init apple_s5l_early_console_setup(struct earlycon_device *device,
const char *opt) const char *opt)

View File

@ -41,7 +41,7 @@ static int serial_base_match(struct device *dev, struct device_driver *drv)
return 0; return 0;
} }
static struct bus_type serial_base_bus_type = { static const struct bus_type serial_base_bus_type = {
.name = "serial-base", .name = "serial-base",
.match = serial_base_match, .match = serial_base_match,
}; };

View File

@ -2608,7 +2608,12 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
port->type = PORT_UNKNOWN; port->type = PORT_UNKNOWN;
flags |= UART_CONFIG_TYPE; flags |= UART_CONFIG_TYPE;
} }
/* Synchronize with possible boot console. */
if (uart_console(port))
console_lock();
port->ops->config_port(port, flags); port->ops->config_port(port, flags);
if (uart_console(port))
console_unlock();
} }
if (port->type != PORT_UNKNOWN) { if (port->type != PORT_UNKNOWN) {
@ -2616,6 +2621,10 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
uart_report_port(drv, port); uart_report_port(drv, port);
/* Synchronize with possible boot console. */
if (uart_console(port))
console_lock();
/* Power up port for set_mctrl() */ /* Power up port for set_mctrl() */
uart_change_pm(state, UART_PM_STATE_ON); uart_change_pm(state, UART_PM_STATE_ON);
@ -2632,6 +2641,9 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
uart_rs485_config(port); uart_rs485_config(port);
if (uart_console(port))
console_unlock();
/* /*
* If this driver supports console, and it hasn't been * If this driver supports console, and it hasn't been
* successfully registered yet, try to re-register it. * successfully registered yet, try to re-register it.

View File

@ -8,7 +8,10 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/property.h>
#include <linux/serial_core.h> #include <linux/serial_core.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
@ -105,6 +108,148 @@ void uart_remove_one_port(struct uart_driver *drv, struct uart_port *port)
} }
EXPORT_SYMBOL(uart_remove_one_port); EXPORT_SYMBOL(uart_remove_one_port);
/**
* __uart_read_properties - read firmware properties of the given UART port
* @port: corresponding port
* @use_defaults: apply defaults (when %true) or validate the values (when %false)
*
* The following device properties are supported:
* - clock-frequency (optional)
* - fifo-size (optional)
* - no-loopback-test (optional)
* - reg-shift (defaults may apply)
* - reg-offset (value may be validated)
* - reg-io-width (defaults may apply or value may be validated)
* - interrupts (OF only)
* - serial [alias ID] (OF only)
*
* If the port->dev is of struct platform_device type the interrupt line
* will be retrieved via platform_get_irq() call against that device.
* Otherwise it will be assigned by fwnode_irq_get() call. In both cases
* the index 0 of the resource is used.
*
* The caller is responsible to initialize the following fields of the @port
* ->dev (must be valid)
* ->flags
* ->mapbase
* ->mapsize
* ->regshift (if @use_defaults is false)
* before calling this function. Alternatively the above mentioned fields
* may be zeroed, in such case the only ones, that have associated properties
* found, will be set to the respective values.
*
* If no error happened, the ->irq, ->mapbase, ->mapsize will be altered.
* The ->iotype is always altered.
*
* When @use_defaults is true and the respective property is not found
* the following values will be applied:
* ->regshift = 0
* In this case IRQ must be provided, otherwise an error will be returned.
*
* When @use_defaults is false and the respective property is found
* the following values will be validated:
* - reg-io-width (->iotype)
* - reg-offset (->mapsize against ->mapbase)
*
* Returns: 0 on success or negative errno on failure
*/
static int __uart_read_properties(struct uart_port *port, bool use_defaults)
{
struct device *dev = port->dev;
u32 value;
int ret;
/* Read optional UART functional clock frequency */
device_property_read_u32(dev, "clock-frequency", &port->uartclk);
/* Read the registers alignment (default: 8-bit) */
ret = device_property_read_u32(dev, "reg-shift", &value);
if (ret)
port->regshift = use_defaults ? 0 : port->regshift;
else
port->regshift = value;
/* Read the registers I/O access type (default: MMIO 8-bit) */
ret = device_property_read_u32(dev, "reg-io-width", &value);
if (ret) {
port->iotype = UPIO_MEM;
} else {
switch (value) {
case 1:
port->iotype = UPIO_MEM;
break;
case 2:
port->iotype = UPIO_MEM16;
break;
case 4:
port->iotype = device_is_big_endian(dev) ? UPIO_MEM32BE : UPIO_MEM32;
break;
default:
if (!use_defaults) {
dev_err(dev, "Unsupported reg-io-width (%u)\n", value);
return -EINVAL;
}
port->iotype = UPIO_UNKNOWN;
break;
}
}
/* Read the address mapping base offset (default: no offset) */
ret = device_property_read_u32(dev, "reg-offset", &value);
if (ret)
value = 0;
/* Check for shifted address mapping overflow */
if (!use_defaults && port->mapsize < value) {
dev_err(dev, "reg-offset %u exceeds region size %pa\n", value, &port->mapsize);
return -EINVAL;
}
port->mapbase += value;
port->mapsize -= value;
/* Read optional FIFO size */
device_property_read_u32(dev, "fifo-size", &port->fifosize);
if (device_property_read_bool(dev, "no-loopback-test"))
port->flags |= UPF_SKIP_TEST;
/* Get index of serial line, if found in DT aliases */
ret = of_alias_get_id(dev_of_node(dev), "serial");
if (ret >= 0)
port->line = ret;
if (dev_is_platform(dev))
ret = platform_get_irq(to_platform_device(dev), 0);
else
ret = fwnode_irq_get(dev_fwnode(dev), 0);
if (ret == -EPROBE_DEFER)
return ret;
if (ret > 0)
port->irq = ret;
else if (use_defaults)
/* By default IRQ support is mandatory */
return ret;
else
port->irq = 0;
port->flags |= UPF_SHARE_IRQ;
return 0;
}
int uart_read_port_properties(struct uart_port *port)
{
return __uart_read_properties(port, true);
}
EXPORT_SYMBOL_GPL(uart_read_port_properties);
int uart_read_and_validate_port_properties(struct uart_port *port)
{
return __uart_read_properties(port, false);
}
EXPORT_SYMBOL_GPL(uart_read_and_validate_port_properties);
static struct device_driver serial_port_driver = { static struct device_driver serial_port_driver = {
.name = "port", .name = "port",
.suppress_bind_attrs = true, .suppress_bind_attrs = true,

View File

@ -23,9 +23,10 @@
#include <linux/serial.h> #include <linux/serial.h>
#include <linux/tty.h> #include <linux/tty.h>
#include <linux/tty_flip.h> #include <linux/tty_flip.h>
#include <linux/io.h> #include <linux/io.h>
#include <asm/txx9/generic.h>
#define PASS_LIMIT 256 #define PASS_LIMIT 256
#if !defined(CONFIG_SERIAL_TXX9_STDSERIAL) #if !defined(CONFIG_SERIAL_TXX9_STDSERIAL)

View File

@ -576,13 +576,13 @@ static void sci_start_tx(struct uart_port *port)
#ifdef CONFIG_SERIAL_SH_SCI_DMA #ifdef CONFIG_SERIAL_SH_SCI_DMA
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
u16 new, scr = serial_port_in(port, SCSCR); u16 new, scr = sci_serial_in(port, SCSCR);
if (s->chan_tx) if (s->chan_tx)
new = scr | SCSCR_TDRQE; new = scr | SCSCR_TDRQE;
else else
new = scr & ~SCSCR_TDRQE; new = scr & ~SCSCR_TDRQE;
if (new != scr) if (new != scr)
serial_port_out(port, SCSCR, new); sci_serial_out(port, SCSCR, new);
} }
if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) && if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) &&
@ -599,7 +599,7 @@ static void sci_start_tx(struct uart_port *port)
if (!s->chan_tx || s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE || if (!s->chan_tx || s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE ||
port->type == PORT_SCIFA || port->type == PORT_SCIFB) { port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
/* Set TIE (Transmit Interrupt Enable) bit in SCSCR */ /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */
ctrl = serial_port_in(port, SCSCR); ctrl = sci_serial_in(port, SCSCR);
/* /*
* For SCI, TE (transmit enable) must be set after setting TIE * For SCI, TE (transmit enable) must be set after setting TIE
@ -609,7 +609,7 @@ static void sci_start_tx(struct uart_port *port)
if (port->type == PORT_SCI) if (port->type == PORT_SCI)
ctrl |= SCSCR_TE; ctrl |= SCSCR_TE;
serial_port_out(port, SCSCR, ctrl | SCSCR_TIE); sci_serial_out(port, SCSCR, ctrl | SCSCR_TIE);
} }
} }
@ -618,14 +618,14 @@ static void sci_stop_tx(struct uart_port *port)
unsigned short ctrl; unsigned short ctrl;
/* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */ /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */
ctrl = serial_port_in(port, SCSCR); ctrl = sci_serial_in(port, SCSCR);
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
ctrl &= ~SCSCR_TDRQE; ctrl &= ~SCSCR_TDRQE;
ctrl &= ~SCSCR_TIE; ctrl &= ~SCSCR_TIE;
serial_port_out(port, SCSCR, ctrl); sci_serial_out(port, SCSCR, ctrl);
#ifdef CONFIG_SERIAL_SH_SCI_DMA #ifdef CONFIG_SERIAL_SH_SCI_DMA
if (to_sci_port(port)->chan_tx && if (to_sci_port(port)->chan_tx &&
@ -640,41 +640,40 @@ static void sci_start_rx(struct uart_port *port)
{ {
unsigned short ctrl; unsigned short ctrl;
ctrl = serial_port_in(port, SCSCR) | port_rx_irq_mask(port); ctrl = sci_serial_in(port, SCSCR) | port_rx_irq_mask(port);
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
ctrl &= ~SCSCR_RDRQE; ctrl &= ~SCSCR_RDRQE;
serial_port_out(port, SCSCR, ctrl); sci_serial_out(port, SCSCR, ctrl);
} }
static void sci_stop_rx(struct uart_port *port) static void sci_stop_rx(struct uart_port *port)
{ {
unsigned short ctrl; unsigned short ctrl;
ctrl = serial_port_in(port, SCSCR); ctrl = sci_serial_in(port, SCSCR);
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
ctrl &= ~SCSCR_RDRQE; ctrl &= ~SCSCR_RDRQE;
ctrl &= ~port_rx_irq_mask(port); ctrl &= ~port_rx_irq_mask(port);
serial_port_out(port, SCSCR, ctrl); sci_serial_out(port, SCSCR, ctrl);
} }
static void sci_clear_SCxSR(struct uart_port *port, unsigned int mask) static void sci_clear_SCxSR(struct uart_port *port, unsigned int mask)
{ {
if (port->type == PORT_SCI) { if (port->type == PORT_SCI) {
/* Just store the mask */ /* Just store the mask */
serial_port_out(port, SCxSR, mask); sci_serial_out(port, SCxSR, mask);
} else if (to_sci_port(port)->params->overrun_mask == SCIFA_ORER) { } else if (to_sci_port(port)->params->overrun_mask == SCIFA_ORER) {
/* SCIFA/SCIFB and SCIF on SH7705/SH7720/SH7721 */ /* SCIFA/SCIFB and SCIF on SH7705/SH7720/SH7721 */
/* Only clear the status bits we want to clear */ /* Only clear the status bits we want to clear */
serial_port_out(port, SCxSR, sci_serial_out(port, SCxSR, sci_serial_in(port, SCxSR) & mask);
serial_port_in(port, SCxSR) & mask);
} else { } else {
/* Store the mask, clear parity/framing errors */ /* Store the mask, clear parity/framing errors */
serial_port_out(port, SCxSR, mask & ~(SCIF_FERC | SCIF_PERC)); sci_serial_out(port, SCxSR, mask & ~(SCIF_FERC | SCIF_PERC));
} }
} }
@ -688,7 +687,7 @@ static int sci_poll_get_char(struct uart_port *port)
int c; int c;
do { do {
status = serial_port_in(port, SCxSR); status = sci_serial_in(port, SCxSR);
if (status & SCxSR_ERRORS(port)) { if (status & SCxSR_ERRORS(port)) {
sci_clear_SCxSR(port, SCxSR_ERROR_CLEAR(port)); sci_clear_SCxSR(port, SCxSR_ERROR_CLEAR(port));
continue; continue;
@ -699,10 +698,10 @@ static int sci_poll_get_char(struct uart_port *port)
if (!(status & SCxSR_RDxF(port))) if (!(status & SCxSR_RDxF(port)))
return NO_POLL_CHAR; return NO_POLL_CHAR;
c = serial_port_in(port, SCxRDR); c = sci_serial_in(port, SCxRDR);
/* Dummy read */ /* Dummy read */
serial_port_in(port, SCxSR); sci_serial_in(port, SCxSR);
sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
return c; return c;
@ -714,10 +713,10 @@ static void sci_poll_put_char(struct uart_port *port, unsigned char c)
unsigned short status; unsigned short status;
do { do {
status = serial_port_in(port, SCxSR); status = sci_serial_in(port, SCxSR);
} while (!(status & SCxSR_TDxE(port))); } while (!(status & SCxSR_TDxE(port)));
serial_port_out(port, SCxTDR, c); sci_serial_out(port, SCxTDR, c);
sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port)); sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port));
} }
#endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE || #endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE ||
@ -736,8 +735,8 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag)
} }
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
u16 data = serial_port_in(port, SCPDR); u16 data = sci_serial_in(port, SCPDR);
u16 ctrl = serial_port_in(port, SCPCR); u16 ctrl = sci_serial_in(port, SCPCR);
/* Enable RXD and TXD pin functions */ /* Enable RXD and TXD pin functions */
ctrl &= ~(SCPCR_RXDC | SCPCR_TXDC); ctrl &= ~(SCPCR_RXDC | SCPCR_TXDC);
@ -756,10 +755,10 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag)
/* Enable CTS# pin function */ /* Enable CTS# pin function */
ctrl &= ~SCPCR_CTSC; ctrl &= ~SCPCR_CTSC;
} }
serial_port_out(port, SCPDR, data); sci_serial_out(port, SCPDR, data);
serial_port_out(port, SCPCR, ctrl); sci_serial_out(port, SCPCR, ctrl);
} else if (sci_getreg(port, SCSPTR)->size) { } else if (sci_getreg(port, SCSPTR)->size) {
u16 status = serial_port_in(port, SCSPTR); u16 status = sci_serial_in(port, SCSPTR);
/* RTS# is always output; and active low, unless autorts */ /* RTS# is always output; and active low, unless autorts */
status |= SCSPTR_RTSIO; status |= SCSPTR_RTSIO;
@ -769,7 +768,7 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag)
status &= ~SCSPTR_RTSDT; status &= ~SCSPTR_RTSDT;
/* CTS# and SCK are inputs */ /* CTS# and SCK are inputs */
status &= ~(SCSPTR_CTSIO | SCSPTR_SCKIO); status &= ~(SCSPTR_CTSIO | SCSPTR_SCKIO);
serial_port_out(port, SCSPTR, status); sci_serial_out(port, SCSPTR, status);
} }
} }
@ -781,13 +780,13 @@ static int sci_txfill(struct uart_port *port)
reg = sci_getreg(port, SCTFDR); reg = sci_getreg(port, SCTFDR);
if (reg->size) if (reg->size)
return serial_port_in(port, SCTFDR) & fifo_mask; return sci_serial_in(port, SCTFDR) & fifo_mask;
reg = sci_getreg(port, SCFDR); reg = sci_getreg(port, SCFDR);
if (reg->size) if (reg->size)
return serial_port_in(port, SCFDR) >> 8; return sci_serial_in(port, SCFDR) >> 8;
return !(serial_port_in(port, SCxSR) & SCI_TDRE); return !(sci_serial_in(port, SCxSR) & SCI_TDRE);
} }
static int sci_txroom(struct uart_port *port) static int sci_txroom(struct uart_port *port)
@ -803,13 +802,13 @@ static int sci_rxfill(struct uart_port *port)
reg = sci_getreg(port, SCRFDR); reg = sci_getreg(port, SCRFDR);
if (reg->size) if (reg->size)
return serial_port_in(port, SCRFDR) & fifo_mask; return sci_serial_in(port, SCRFDR) & fifo_mask;
reg = sci_getreg(port, SCFDR); reg = sci_getreg(port, SCFDR);
if (reg->size) if (reg->size)
return serial_port_in(port, SCFDR) & fifo_mask; return sci_serial_in(port, SCFDR) & fifo_mask;
return (serial_port_in(port, SCxSR) & SCxSR_RDxF(port)) != 0; return (sci_serial_in(port, SCxSR) & SCxSR_RDxF(port)) != 0;
} }
/* ********************************************************************** * /* ********************************************************************** *
@ -824,14 +823,14 @@ static void sci_transmit_chars(struct uart_port *port)
unsigned short ctrl; unsigned short ctrl;
int count; int count;
status = serial_port_in(port, SCxSR); status = sci_serial_in(port, SCxSR);
if (!(status & SCxSR_TDxE(port))) { if (!(status & SCxSR_TDxE(port))) {
ctrl = serial_port_in(port, SCSCR); ctrl = sci_serial_in(port, SCSCR);
if (uart_circ_empty(xmit)) if (uart_circ_empty(xmit))
ctrl &= ~SCSCR_TIE; ctrl &= ~SCSCR_TIE;
else else
ctrl |= SCSCR_TIE; ctrl |= SCSCR_TIE;
serial_port_out(port, SCSCR, ctrl); sci_serial_out(port, SCSCR, ctrl);
return; return;
} }
@ -847,15 +846,15 @@ static void sci_transmit_chars(struct uart_port *port)
c = xmit->buf[xmit->tail]; c = xmit->buf[xmit->tail];
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
} else if (port->type == PORT_SCI && uart_circ_empty(xmit)) { } else if (port->type == PORT_SCI && uart_circ_empty(xmit)) {
ctrl = serial_port_in(port, SCSCR); ctrl = sci_serial_in(port, SCSCR);
ctrl &= ~SCSCR_TE; ctrl &= ~SCSCR_TE;
serial_port_out(port, SCSCR, ctrl); sci_serial_out(port, SCSCR, ctrl);
return; return;
} else { } else {
break; break;
} }
serial_port_out(port, SCxTDR, c); sci_serial_out(port, SCxTDR, c);
port->icount.tx++; port->icount.tx++;
} while (--count > 0); } while (--count > 0);
@ -866,10 +865,10 @@ static void sci_transmit_chars(struct uart_port *port)
uart_write_wakeup(port); uart_write_wakeup(port);
if (uart_circ_empty(xmit)) { if (uart_circ_empty(xmit)) {
if (port->type == PORT_SCI) { if (port->type == PORT_SCI) {
ctrl = serial_port_in(port, SCSCR); ctrl = sci_serial_in(port, SCSCR);
ctrl &= ~SCSCR_TIE; ctrl &= ~SCSCR_TIE;
ctrl |= SCSCR_TEIE; ctrl |= SCSCR_TEIE;
serial_port_out(port, SCSCR, ctrl); sci_serial_out(port, SCSCR, ctrl);
} }
sci_stop_tx(port); sci_stop_tx(port);
@ -883,7 +882,7 @@ static void sci_receive_chars(struct uart_port *port)
unsigned short status; unsigned short status;
unsigned char flag; unsigned char flag;
status = serial_port_in(port, SCxSR); status = sci_serial_in(port, SCxSR);
if (!(status & SCxSR_RDxF(port))) if (!(status & SCxSR_RDxF(port)))
return; return;
@ -896,7 +895,7 @@ static void sci_receive_chars(struct uart_port *port)
break; break;
if (port->type == PORT_SCI) { if (port->type == PORT_SCI) {
char c = serial_port_in(port, SCxRDR); char c = sci_serial_in(port, SCxRDR);
if (uart_handle_sysrq_char(port, c)) if (uart_handle_sysrq_char(port, c))
count = 0; count = 0;
else else
@ -907,11 +906,11 @@ static void sci_receive_chars(struct uart_port *port)
if (port->type == PORT_SCIF || if (port->type == PORT_SCIF ||
port->type == PORT_HSCIF) { port->type == PORT_HSCIF) {
status = serial_port_in(port, SCxSR); status = sci_serial_in(port, SCxSR);
c = serial_port_in(port, SCxRDR); c = sci_serial_in(port, SCxRDR);
} else { } else {
c = serial_port_in(port, SCxRDR); c = sci_serial_in(port, SCxRDR);
status = serial_port_in(port, SCxSR); status = sci_serial_in(port, SCxSR);
} }
if (uart_handle_sysrq_char(port, c)) { if (uart_handle_sysrq_char(port, c)) {
count--; i--; count--; i--;
@ -932,7 +931,7 @@ static void sci_receive_chars(struct uart_port *port)
} }
} }
serial_port_in(port, SCxSR); /* dummy read */ sci_serial_in(port, SCxSR); /* dummy read */
sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
copied += count; copied += count;
@ -944,8 +943,8 @@ static void sci_receive_chars(struct uart_port *port)
tty_flip_buffer_push(tport); tty_flip_buffer_push(tport);
} else { } else {
/* TTY buffers full; read from RX reg to prevent lockup */ /* TTY buffers full; read from RX reg to prevent lockup */
serial_port_in(port, SCxRDR); sci_serial_in(port, SCxRDR);
serial_port_in(port, SCxSR); /* dummy read */ sci_serial_in(port, SCxSR); /* dummy read */
sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
} }
} }
@ -953,7 +952,7 @@ static void sci_receive_chars(struct uart_port *port)
static int sci_handle_errors(struct uart_port *port) static int sci_handle_errors(struct uart_port *port)
{ {
int copied = 0; int copied = 0;
unsigned short status = serial_port_in(port, SCxSR); unsigned short status = sci_serial_in(port, SCxSR);
struct tty_port *tport = &port->state->port; struct tty_port *tport = &port->state->port;
struct sci_port *s = to_sci_port(port); struct sci_port *s = to_sci_port(port);
@ -1000,10 +999,10 @@ static int sci_handle_fifo_overrun(struct uart_port *port)
if (!reg->size) if (!reg->size)
return 0; return 0;
status = serial_port_in(port, s->params->overrun_reg); status = sci_serial_in(port, s->params->overrun_reg);
if (status & s->params->overrun_mask) { if (status & s->params->overrun_mask) {
status &= ~s->params->overrun_mask; status &= ~s->params->overrun_mask;
serial_port_out(port, s->params->overrun_reg, status); sci_serial_out(port, s->params->overrun_reg, status);
port->icount.overrun++; port->icount.overrun++;
@ -1018,7 +1017,7 @@ static int sci_handle_fifo_overrun(struct uart_port *port)
static int sci_handle_breaks(struct uart_port *port) static int sci_handle_breaks(struct uart_port *port)
{ {
int copied = 0; int copied = 0;
unsigned short status = serial_port_in(port, SCxSR); unsigned short status = sci_serial_in(port, SCxSR);
struct tty_port *tport = &port->state->port; struct tty_port *tport = &port->state->port;
if (uart_handle_break(port)) if (uart_handle_break(port))
@ -1051,7 +1050,7 @@ static int scif_set_rtrg(struct uart_port *port, int rx_trig)
/* HSCIF can be set to an arbitrary level. */ /* HSCIF can be set to an arbitrary level. */
if (sci_getreg(port, HSRTRGR)->size) { if (sci_getreg(port, HSRTRGR)->size) {
serial_port_out(port, HSRTRGR, rx_trig); sci_serial_out(port, HSRTRGR, rx_trig);
return rx_trig; return rx_trig;
} }
@ -1092,9 +1091,9 @@ static int scif_set_rtrg(struct uart_port *port, int rx_trig)
return 1; return 1;
} }
serial_port_out(port, SCFCR, sci_serial_out(port, SCFCR,
(serial_port_in(port, SCFCR) & (sci_serial_in(port, SCFCR) &
~(SCFCR_RTRG1 | SCFCR_RTRG0)) | bits); ~(SCFCR_RTRG1 | SCFCR_RTRG0)) | bits);
return rx_trig; return rx_trig;
} }
@ -1102,9 +1101,9 @@ static int scif_set_rtrg(struct uart_port *port, int rx_trig)
static int scif_rtrg_enabled(struct uart_port *port) static int scif_rtrg_enabled(struct uart_port *port)
{ {
if (sci_getreg(port, HSRTRGR)->size) if (sci_getreg(port, HSRTRGR)->size)
return serial_port_in(port, HSRTRGR) != 0; return sci_serial_in(port, HSRTRGR) != 0;
else else
return (serial_port_in(port, SCFCR) & return (sci_serial_in(port, SCFCR) &
(SCFCR_RTRG0 | SCFCR_RTRG1)) != 0; (SCFCR_RTRG0 | SCFCR_RTRG1)) != 0;
} }
@ -1219,8 +1218,8 @@ static void sci_dma_tx_complete(void *arg)
s->cookie_tx = -EINVAL; s->cookie_tx = -EINVAL;
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB || if (port->type == PORT_SCIFA || port->type == PORT_SCIFB ||
s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) { s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) {
u16 ctrl = serial_port_in(port, SCSCR); u16 ctrl = sci_serial_in(port, SCSCR);
serial_port_out(port, SCSCR, ctrl & ~SCSCR_TIE); sci_serial_out(port, SCSCR, ctrl & ~SCSCR_TIE);
if (s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) { if (s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) {
/* Switch irq from DMA to SCIF */ /* Switch irq from DMA to SCIF */
dmaengine_pause(s->chan_tx_saved); dmaengine_pause(s->chan_tx_saved);
@ -1296,7 +1295,7 @@ static void sci_dma_rx_reenable_irq(struct sci_port *s)
u16 scr; u16 scr;
/* Direct new serial port interrupts back to CPU */ /* Direct new serial port interrupts back to CPU */
scr = serial_port_in(port, SCSCR); scr = sci_serial_in(port, SCSCR);
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB || if (port->type == PORT_SCIFA || port->type == PORT_SCIFB ||
s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) { s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) {
enable_irq(s->irqs[SCIx_RXI_IRQ]); enable_irq(s->irqs[SCIx_RXI_IRQ]);
@ -1305,7 +1304,7 @@ static void sci_dma_rx_reenable_irq(struct sci_port *s)
else else
scr &= ~SCSCR_RDRQE; scr &= ~SCSCR_RDRQE;
} }
serial_port_out(port, SCSCR, scr | SCSCR_RIE); sci_serial_out(port, SCSCR, scr | SCSCR_RIE);
} }
static void sci_dma_rx_complete(void *arg) static void sci_dma_rx_complete(void *arg)
@ -1714,8 +1713,8 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
#ifdef CONFIG_SERIAL_SH_SCI_DMA #ifdef CONFIG_SERIAL_SH_SCI_DMA
if (s->chan_rx) { if (s->chan_rx) {
u16 scr = serial_port_in(port, SCSCR); u16 scr = sci_serial_in(port, SCSCR);
u16 ssr = serial_port_in(port, SCxSR); u16 ssr = sci_serial_in(port, SCxSR);
/* Disable future Rx interrupts */ /* Disable future Rx interrupts */
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB || if (port->type == PORT_SCIFA || port->type == PORT_SCIFB ||
@ -1733,10 +1732,10 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
scr &= ~SCSCR_RIE; scr &= ~SCSCR_RIE;
} }
serial_port_out(port, SCSCR, scr); sci_serial_out(port, SCSCR, scr);
/* Clear current interrupt */ /* Clear current interrupt */
serial_port_out(port, SCxSR, sci_serial_out(port, SCxSR,
ssr & ~(SCIF_DR | SCxSR_RDxF(port))); ssr & ~(SCIF_DR | SCxSR_RDxF(port)));
dev_dbg(port->dev, "Rx IRQ %lu: setup t-out in %u us\n", dev_dbg(port->dev, "Rx IRQ %lu: setup t-out in %u us\n",
jiffies, s->rx_timeout); jiffies, s->rx_timeout);
start_hrtimer_us(&s->rx_timer, s->rx_timeout); start_hrtimer_us(&s->rx_timer, s->rx_timeout);
@ -1786,9 +1785,9 @@ static irqreturn_t sci_tx_end_interrupt(int irq, void *ptr)
return sci_tx_interrupt(irq, ptr); return sci_tx_interrupt(irq, ptr);
uart_port_lock_irqsave(port, &flags); uart_port_lock_irqsave(port, &flags);
ctrl = serial_port_in(port, SCSCR); ctrl = sci_serial_in(port, SCSCR);
ctrl &= ~(SCSCR_TE | SCSCR_TEIE); ctrl &= ~(SCSCR_TE | SCSCR_TEIE);
serial_port_out(port, SCSCR, ctrl); sci_serial_out(port, SCSCR, ctrl);
uart_port_unlock_irqrestore(port, flags); uart_port_unlock_irqrestore(port, flags);
return IRQ_HANDLED; return IRQ_HANDLED;
@ -1802,7 +1801,7 @@ static irqreturn_t sci_br_interrupt(int irq, void *ptr)
sci_handle_breaks(port); sci_handle_breaks(port);
/* drop invalid character received before break was detected */ /* drop invalid character received before break was detected */
serial_port_in(port, SCxRDR); sci_serial_in(port, SCxRDR);
sci_clear_SCxSR(port, SCxSR_BREAK_CLEAR(port)); sci_clear_SCxSR(port, SCxSR_BREAK_CLEAR(port));
@ -1816,7 +1815,7 @@ static irqreturn_t sci_er_interrupt(int irq, void *ptr)
if (s->irqs[SCIx_ERI_IRQ] == s->irqs[SCIx_BRI_IRQ]) { if (s->irqs[SCIx_ERI_IRQ] == s->irqs[SCIx_BRI_IRQ]) {
/* Break and Error interrupts are muxed */ /* Break and Error interrupts are muxed */
unsigned short ssr_status = serial_port_in(port, SCxSR); unsigned short ssr_status = sci_serial_in(port, SCxSR);
/* Break Interrupt */ /* Break Interrupt */
if (ssr_status & SCxSR_BRK(port)) if (ssr_status & SCxSR_BRK(port))
@ -1831,7 +1830,7 @@ static irqreturn_t sci_er_interrupt(int irq, void *ptr)
if (port->type == PORT_SCI) { if (port->type == PORT_SCI) {
if (sci_handle_errors(port)) { if (sci_handle_errors(port)) {
/* discard character in rx buffer */ /* discard character in rx buffer */
serial_port_in(port, SCxSR); sci_serial_in(port, SCxSR);
sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
} }
} else { } else {
@ -1856,12 +1855,12 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
struct sci_port *s = to_sci_port(port); struct sci_port *s = to_sci_port(port);
irqreturn_t ret = IRQ_NONE; irqreturn_t ret = IRQ_NONE;
ssr_status = serial_port_in(port, SCxSR); ssr_status = sci_serial_in(port, SCxSR);
scr_status = serial_port_in(port, SCSCR); scr_status = sci_serial_in(port, SCSCR);
if (s->params->overrun_reg == SCxSR) if (s->params->overrun_reg == SCxSR)
orer_status = ssr_status; orer_status = ssr_status;
else if (sci_getreg(port, s->params->overrun_reg)->size) else if (sci_getreg(port, s->params->overrun_reg)->size)
orer_status = serial_port_in(port, s->params->overrun_reg); orer_status = sci_serial_in(port, s->params->overrun_reg);
err_enabled = scr_status & port_rx_irq_mask(port); err_enabled = scr_status & port_rx_irq_mask(port);
@ -2038,7 +2037,7 @@ static void sci_free_irq(struct sci_port *port)
static unsigned int sci_tx_empty(struct uart_port *port) static unsigned int sci_tx_empty(struct uart_port *port)
{ {
unsigned short status = serial_port_in(port, SCxSR); unsigned short status = sci_serial_in(port, SCxSR);
unsigned short in_tx_fifo = sci_txfill(port); unsigned short in_tx_fifo = sci_txfill(port);
return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0; return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0;
@ -2047,27 +2046,27 @@ static unsigned int sci_tx_empty(struct uart_port *port)
static void sci_set_rts(struct uart_port *port, bool state) static void sci_set_rts(struct uart_port *port, bool state)
{ {
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
u16 data = serial_port_in(port, SCPDR); u16 data = sci_serial_in(port, SCPDR);
/* Active low */ /* Active low */
if (state) if (state)
data &= ~SCPDR_RTSD; data &= ~SCPDR_RTSD;
else else
data |= SCPDR_RTSD; data |= SCPDR_RTSD;
serial_port_out(port, SCPDR, data); sci_serial_out(port, SCPDR, data);
/* RTS# is output */ /* RTS# is output */
serial_port_out(port, SCPCR, sci_serial_out(port, SCPCR,
serial_port_in(port, SCPCR) | SCPCR_RTSC); sci_serial_in(port, SCPCR) | SCPCR_RTSC);
} else if (sci_getreg(port, SCSPTR)->size) { } else if (sci_getreg(port, SCSPTR)->size) {
u16 ctrl = serial_port_in(port, SCSPTR); u16 ctrl = sci_serial_in(port, SCSPTR);
/* Active low */ /* Active low */
if (state) if (state)
ctrl &= ~SCSPTR_RTSDT; ctrl &= ~SCSPTR_RTSDT;
else else
ctrl |= SCSPTR_RTSDT; ctrl |= SCSPTR_RTSDT;
serial_port_out(port, SCSPTR, ctrl); sci_serial_out(port, SCSPTR, ctrl);
} }
} }
@ -2075,10 +2074,10 @@ static bool sci_get_cts(struct uart_port *port)
{ {
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
/* Active low */ /* Active low */
return !(serial_port_in(port, SCPDR) & SCPDR_CTSD); return !(sci_serial_in(port, SCPDR) & SCPDR_CTSD);
} else if (sci_getreg(port, SCSPTR)->size) { } else if (sci_getreg(port, SCSPTR)->size) {
/* Active low */ /* Active low */
return !(serial_port_in(port, SCSPTR) & SCSPTR_CTSDT); return !(sci_serial_in(port, SCSPTR) & SCSPTR_CTSDT);
} }
return true; return true;
@ -2108,9 +2107,8 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
*/ */
reg = sci_getreg(port, SCFCR); reg = sci_getreg(port, SCFCR);
if (reg->size) if (reg->size)
serial_port_out(port, SCFCR, sci_serial_out(port, SCFCR,
serial_port_in(port, SCFCR) | sci_serial_in(port, SCFCR) | SCFCR_LOOP);
SCFCR_LOOP);
} }
mctrl_gpio_set(s->gpios, mctrl); mctrl_gpio_set(s->gpios, mctrl);
@ -2120,21 +2118,21 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
if (!(mctrl & TIOCM_RTS)) { if (!(mctrl & TIOCM_RTS)) {
/* Disable Auto RTS */ /* Disable Auto RTS */
serial_port_out(port, SCFCR, sci_serial_out(port, SCFCR,
serial_port_in(port, SCFCR) & ~SCFCR_MCE); sci_serial_in(port, SCFCR) & ~SCFCR_MCE);
/* Clear RTS */ /* Clear RTS */
sci_set_rts(port, 0); sci_set_rts(port, 0);
} else if (s->autorts) { } else if (s->autorts) {
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
/* Enable RTS# pin function */ /* Enable RTS# pin function */
serial_port_out(port, SCPCR, sci_serial_out(port, SCPCR,
serial_port_in(port, SCPCR) & ~SCPCR_RTSC); sci_serial_in(port, SCPCR) & ~SCPCR_RTSC);
} }
/* Enable Auto RTS */ /* Enable Auto RTS */
serial_port_out(port, SCFCR, sci_serial_out(port, SCFCR,
serial_port_in(port, SCFCR) | SCFCR_MCE); sci_serial_in(port, SCFCR) | SCFCR_MCE);
} else { } else {
/* Set RTS */ /* Set RTS */
sci_set_rts(port, 1); sci_set_rts(port, 1);
@ -2187,8 +2185,8 @@ static void sci_break_ctl(struct uart_port *port, int break_state)
} }
uart_port_lock_irqsave(port, &flags); uart_port_lock_irqsave(port, &flags);
scsptr = serial_port_in(port, SCSPTR); scsptr = sci_serial_in(port, SCSPTR);
scscr = serial_port_in(port, SCSCR); scscr = sci_serial_in(port, SCSCR);
if (break_state == -1) { if (break_state == -1) {
scsptr = (scsptr | SCSPTR_SPB2IO) & ~SCSPTR_SPB2DT; scsptr = (scsptr | SCSPTR_SPB2IO) & ~SCSPTR_SPB2DT;
@ -2198,8 +2196,8 @@ static void sci_break_ctl(struct uart_port *port, int break_state)
scscr |= SCSCR_TE; scscr |= SCSCR_TE;
} }
serial_port_out(port, SCSPTR, scsptr); sci_serial_out(port, SCSPTR, scsptr);
serial_port_out(port, SCSCR, scscr); sci_serial_out(port, SCSCR, scscr);
uart_port_unlock_irqrestore(port, flags); uart_port_unlock_irqrestore(port, flags);
} }
@ -2239,9 +2237,9 @@ static void sci_shutdown(struct uart_port *port)
* Stop RX and TX, disable related interrupts, keep clock source * Stop RX and TX, disable related interrupts, keep clock source
* and HSCIF TOT bits * and HSCIF TOT bits
*/ */
scr = serial_port_in(port, SCSCR); scr = sci_serial_in(port, SCSCR);
serial_port_out(port, SCSCR, scr & sci_serial_out(port, SCSCR,
(SCSCR_CKE1 | SCSCR_CKE0 | s->hscif_tot)); scr & (SCSCR_CKE1 | SCSCR_CKE0 | s->hscif_tot));
uart_port_unlock_irqrestore(port, flags); uart_port_unlock_irqrestore(port, flags);
#ifdef CONFIG_SERIAL_SH_SCI_DMA #ifdef CONFIG_SERIAL_SH_SCI_DMA
@ -2390,19 +2388,19 @@ static void sci_reset(struct uart_port *port)
unsigned int status; unsigned int status;
struct sci_port *s = to_sci_port(port); struct sci_port *s = to_sci_port(port);
serial_port_out(port, SCSCR, s->hscif_tot); /* TE=0, RE=0, CKE1=0 */ sci_serial_out(port, SCSCR, s->hscif_tot); /* TE=0, RE=0, CKE1=0 */
reg = sci_getreg(port, SCFCR); reg = sci_getreg(port, SCFCR);
if (reg->size) if (reg->size)
serial_port_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST); sci_serial_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST);
sci_clear_SCxSR(port, sci_clear_SCxSR(port,
SCxSR_RDxF_CLEAR(port) & SCxSR_ERROR_CLEAR(port) & SCxSR_RDxF_CLEAR(port) & SCxSR_ERROR_CLEAR(port) &
SCxSR_BREAK_CLEAR(port)); SCxSR_BREAK_CLEAR(port));
if (sci_getreg(port, SCLSR)->size) { if (sci_getreg(port, SCLSR)->size) {
status = serial_port_in(port, SCLSR); status = sci_serial_in(port, SCLSR);
status &= ~(SCLSR_TO | SCLSR_ORER); status &= ~(SCLSR_TO | SCLSR_ORER);
serial_port_out(port, SCLSR, status); sci_serial_out(port, SCLSR, status);
} }
if (s->rx_trigger > 1) { if (s->rx_trigger > 1) {
@ -2540,8 +2538,8 @@ done:
* It controls the mux to select (H)SCK or frequency divided clock. * It controls the mux to select (H)SCK or frequency divided clock.
*/ */
if (best_clk >= 0 && sci_getreg(port, SCCKS)->size) { if (best_clk >= 0 && sci_getreg(port, SCCKS)->size) {
serial_port_out(port, SCDL, dl); sci_serial_out(port, SCDL, dl);
serial_port_out(port, SCCKS, sccks); sci_serial_out(port, SCCKS, sccks);
} }
uart_port_lock_irqsave(port, &flags); uart_port_lock_irqsave(port, &flags);
@ -2554,7 +2552,7 @@ done:
bits = tty_get_frame_size(termios->c_cflag); bits = tty_get_frame_size(termios->c_cflag);
if (sci_getreg(port, SEMR)->size) if (sci_getreg(port, SEMR)->size)
serial_port_out(port, SEMR, 0); sci_serial_out(port, SEMR, 0);
if (best_clk >= 0) { if (best_clk >= 0) {
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
@ -2569,9 +2567,9 @@ done:
case 27: smr_val |= SCSMR_SRC_27; break; case 27: smr_val |= SCSMR_SRC_27; break;
} }
smr_val |= cks; smr_val |= cks;
serial_port_out(port, SCSCR, scr_val | s->hscif_tot); sci_serial_out(port, SCSCR, scr_val | s->hscif_tot);
serial_port_out(port, SCSMR, smr_val); sci_serial_out(port, SCSMR, smr_val);
serial_port_out(port, SCBRR, brr); sci_serial_out(port, SCBRR, brr);
if (sci_getreg(port, HSSRR)->size) { if (sci_getreg(port, HSSRR)->size) {
unsigned int hssrr = srr | HSCIF_SRE; unsigned int hssrr = srr | HSCIF_SRE;
/* Calculate deviation from intended rate at the /* Calculate deviation from intended rate at the
@ -2593,7 +2591,7 @@ done:
HSCIF_SRHP_MASK; HSCIF_SRHP_MASK;
hssrr |= HSCIF_SRDE; hssrr |= HSCIF_SRDE;
} }
serial_port_out(port, HSSRR, hssrr); sci_serial_out(port, HSSRR, hssrr);
} }
/* Wait one bit interval */ /* Wait one bit interval */
@ -2601,10 +2599,10 @@ done:
} else { } else {
/* Don't touch the bit rate configuration */ /* Don't touch the bit rate configuration */
scr_val = s->cfg->scscr & (SCSCR_CKE1 | SCSCR_CKE0); scr_val = s->cfg->scscr & (SCSCR_CKE1 | SCSCR_CKE0);
smr_val |= serial_port_in(port, SCSMR) & smr_val |= sci_serial_in(port, SCSMR) &
(SCSMR_CKEDG | SCSMR_SRC_MASK | SCSMR_CKS); (SCSMR_CKEDG | SCSMR_SRC_MASK | SCSMR_CKS);
serial_port_out(port, SCSCR, scr_val | s->hscif_tot); sci_serial_out(port, SCSCR, scr_val | s->hscif_tot);
serial_port_out(port, SCSMR, smr_val); sci_serial_out(port, SCSMR, smr_val);
} }
sci_init_pins(port, termios->c_cflag); sci_init_pins(port, termios->c_cflag);
@ -2613,7 +2611,7 @@ done:
s->autorts = false; s->autorts = false;
reg = sci_getreg(port, SCFCR); reg = sci_getreg(port, SCFCR);
if (reg->size) { if (reg->size) {
unsigned short ctrl = serial_port_in(port, SCFCR); unsigned short ctrl = sci_serial_in(port, SCFCR);
if ((port->flags & UPF_HARD_FLOW) && if ((port->flags & UPF_HARD_FLOW) &&
(termios->c_cflag & CRTSCTS)) { (termios->c_cflag & CRTSCTS)) {
@ -2630,7 +2628,7 @@ done:
*/ */
ctrl &= ~(SCFCR_RFRST | SCFCR_TFRST); ctrl &= ~(SCFCR_RFRST | SCFCR_TFRST);
serial_port_out(port, SCFCR, ctrl); sci_serial_out(port, SCFCR, ctrl);
} }
if (port->flags & UPF_HARD_FLOW) { if (port->flags & UPF_HARD_FLOW) {
/* Refresh (Auto) RTS */ /* Refresh (Auto) RTS */
@ -2645,7 +2643,7 @@ done:
if (port->type != PORT_SCI) if (port->type != PORT_SCI)
scr_val |= SCSCR_TE; scr_val |= SCSCR_TE;
scr_val |= SCSCR_RE | (s->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0)); scr_val |= SCSCR_RE | (s->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0));
serial_port_out(port, SCSCR, scr_val | s->hscif_tot); sci_serial_out(port, SCSCR, scr_val | s->hscif_tot);
if ((srr + 1 == 5) && if ((srr + 1 == 5) &&
(port->type == PORT_SCIFA || port->type == PORT_SCIFB)) { (port->type == PORT_SCIFA || port->type == PORT_SCIFB)) {
/* /*
@ -3017,9 +3015,6 @@ static int sci_init_single(struct platform_device *dev,
port->irq = sci_port->irqs[SCIx_RXI_IRQ]; port->irq = sci_port->irqs[SCIx_RXI_IRQ];
port->irqflags = 0; port->irqflags = 0;
port->serial_in = sci_serial_in;
port->serial_out = sci_serial_out;
return 0; return 0;
} }
@ -3056,21 +3051,21 @@ static void serial_console_write(struct console *co, const char *s,
uart_port_lock_irqsave(port, &flags); uart_port_lock_irqsave(port, &flags);
/* first save SCSCR then disable interrupts, keep clock source */ /* first save SCSCR then disable interrupts, keep clock source */
ctrl = serial_port_in(port, SCSCR); ctrl = sci_serial_in(port, SCSCR);
ctrl_temp = SCSCR_RE | SCSCR_TE | ctrl_temp = SCSCR_RE | SCSCR_TE |
(sci_port->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0)) | (sci_port->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0)) |
(ctrl & (SCSCR_CKE1 | SCSCR_CKE0)); (ctrl & (SCSCR_CKE1 | SCSCR_CKE0));
serial_port_out(port, SCSCR, ctrl_temp | sci_port->hscif_tot); sci_serial_out(port, SCSCR, ctrl_temp | sci_port->hscif_tot);
uart_console_write(port, s, count, serial_console_putchar); uart_console_write(port, s, count, serial_console_putchar);
/* wait until fifo is empty and last bit has been transmitted */ /* wait until fifo is empty and last bit has been transmitted */
bits = SCxSR_TDxE(port) | SCxSR_TEND(port); bits = SCxSR_TDxE(port) | SCxSR_TEND(port);
while ((serial_port_in(port, SCxSR) & bits) != bits) while ((sci_serial_in(port, SCxSR) & bits) != bits)
cpu_relax(); cpu_relax();
/* restore the SCSCR */ /* restore the SCSCR */
serial_port_out(port, SCSCR, ctrl); sci_serial_out(port, SCSCR, ctrl);
if (locked) if (locked)
uart_port_unlock_irqrestore(port, flags); uart_port_unlock_irqrestore(port, flags);
@ -3503,8 +3498,6 @@ static int __init early_console_setup(struct earlycon_device *device,
if (!device->port.membase) if (!device->port.membase)
return -ENODEV; return -ENODEV;
device->port.serial_in = sci_serial_in;
device->port.serial_out = sci_serial_out;
device->port.type = type; device->port.type = type;
memcpy(&sci_ports[0].port, &device->port, sizeof(struct uart_port)); memcpy(&sci_ports[0].port, &device->port, sizeof(struct uart_port));
port_cfg.type = type; port_cfg.type = type;

View File

@ -412,7 +412,8 @@ static void __ssp_receive_chars(struct sifive_serial_port *ssp)
break; break;
ssp->port.icount.rx++; ssp->port.icount.rx++;
uart_insert_char(&ssp->port, 0, 0, ch, TTY_NORMAL); if (!uart_prepare_sysrq_char(&ssp->port, ch))
uart_insert_char(&ssp->port, 0, 0, ch, TTY_NORMAL);
} }
tty_flip_buffer_push(&ssp->port.state->port); tty_flip_buffer_push(&ssp->port.state->port);
@ -534,7 +535,7 @@ static irqreturn_t sifive_serial_irq(int irq, void *dev_id)
if (ip & SIFIVE_SERIAL_IP_TXWM_MASK) if (ip & SIFIVE_SERIAL_IP_TXWM_MASK)
__ssp_transmit_chars(ssp); __ssp_transmit_chars(ssp);
uart_port_unlock(&ssp->port); uart_unlock_and_check_sysrq(&ssp->port);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -791,13 +792,10 @@ static void sifive_serial_console_write(struct console *co, const char *s,
if (!ssp) if (!ssp)
return; return;
local_irq_save(flags); if (oops_in_progress)
if (ssp->port.sysrq) locked = uart_port_trylock_irqsave(&ssp->port, &flags);
locked = 0;
else if (oops_in_progress)
locked = uart_port_trylock(&ssp->port);
else else
uart_port_lock(&ssp->port); uart_port_lock_irqsave(&ssp->port, &flags);
ier = __ssp_readl(ssp, SIFIVE_SERIAL_IE_OFFS); ier = __ssp_readl(ssp, SIFIVE_SERIAL_IE_OFFS);
__ssp_writel(0, SIFIVE_SERIAL_IE_OFFS, ssp); __ssp_writel(0, SIFIVE_SERIAL_IE_OFFS, ssp);
@ -807,8 +805,7 @@ static void sifive_serial_console_write(struct console *co, const char *s,
__ssp_writel(ier, SIFIVE_SERIAL_IE_OFFS, ssp); __ssp_writel(ier, SIFIVE_SERIAL_IE_OFFS, ssp);
if (locked) if (locked)
uart_port_unlock(&ssp->port); uart_port_unlock_irqrestore(&ssp->port, flags);
local_irq_restore(flags);
} }
static int sifive_serial_console_setup(struct console *co, char *options) static int sifive_serial_console_setup(struct console *co, char *options)

View File

@ -465,6 +465,7 @@ static void asc_set_termios(struct uart_port *port, struct ktermios *termios,
const struct ktermios *old) const struct ktermios *old)
{ {
struct asc_port *ascport = to_asc_port(port); struct asc_port *ascport = to_asc_port(port);
bool manual_rts, toggle_rts = false;
struct gpio_desc *gpiod; struct gpio_desc *gpiod;
unsigned int baud; unsigned int baud;
u32 ctrl_val; u32 ctrl_val;
@ -518,25 +519,13 @@ static void asc_set_termios(struct uart_port *port, struct ktermios *termios,
/* If flow-control selected, stop handling RTS manually */ /* If flow-control selected, stop handling RTS manually */
if (ascport->rts) { if (ascport->rts) {
devm_gpiod_put(port->dev, ascport->rts); toggle_rts = true;
ascport->rts = NULL; manual_rts = false;
pinctrl_select_state(ascport->pinctrl,
ascport->states[DEFAULT]);
} }
} else { } else {
/* If flow-control disabled, it's safe to handle RTS manually */ /* If flow-control disabled, it's safe to handle RTS manually */
if (!ascport->rts && ascport->states[NO_HW_FLOWCTRL]) { if (!ascport->rts && ascport->states[NO_HW_FLOWCTRL])
pinctrl_select_state(ascport->pinctrl, manual_rts = toggle_rts = true;
ascport->states[NO_HW_FLOWCTRL]);
gpiod = devm_gpiod_get(port->dev, "rts", GPIOD_OUT_LOW);
if (!IS_ERR(gpiod)) {
gpiod_set_consumer_name(gpiod,
port->dev->of_node->name);
ascport->rts = gpiod;
}
}
} }
if ((baud < 19200) && !ascport->force_m1) { if ((baud < 19200) && !ascport->force_m1) {
@ -595,6 +584,25 @@ static void asc_set_termios(struct uart_port *port, struct ktermios *termios,
asc_out(port, ASC_CTL, (ctrl_val | ASC_CTL_RUN)); asc_out(port, ASC_CTL, (ctrl_val | ASC_CTL_RUN));
uart_port_unlock_irqrestore(port, flags); uart_port_unlock_irqrestore(port, flags);
if (toggle_rts) {
if (manual_rts) {
pinctrl_select_state(ascport->pinctrl,
ascport->states[NO_HW_FLOWCTRL]);
gpiod = devm_gpiod_get(port->dev, "rts", GPIOD_OUT_LOW);
if (!IS_ERR(gpiod)) {
gpiod_set_consumer_name(gpiod,
port->dev->of_node->name);
ascport->rts = gpiod;
}
} else {
devm_gpiod_put(port->dev, ascport->rts);
ascport->rts = NULL;
pinctrl_select_state(ascport->pinctrl,
ascport->states[DEFAULT]);
}
}
} }
static const char *asc_type(struct uart_port *port) static const char *asc_type(struct uart_port *port)

View File

@ -9,6 +9,7 @@
* Inspired by st-asc.c from STMicroelectronics (c) * Inspired by st-asc.c from STMicroelectronics (c)
*/ */
#include <linux/bitfield.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/delay.h> #include <linux/delay.h>
@ -39,60 +40,64 @@
/* Register offsets */ /* Register offsets */
static struct stm32_usart_info __maybe_unused stm32f4_info = { static struct stm32_usart_info __maybe_unused stm32f4_info = {
.ofs = { .ofs = {
.isr = 0x00, .isr = 0x00,
.rdr = 0x04, .rdr = 0x04,
.tdr = 0x04, .tdr = 0x04,
.brr = 0x08, .brr = 0x08,
.cr1 = 0x0c, .cr1 = 0x0c,
.cr2 = 0x10, .cr2 = 0x10,
.cr3 = 0x14, .cr3 = 0x14,
.gtpr = 0x18, .gtpr = 0x18,
.rtor = UNDEF_REG, .rtor = UNDEF_REG,
.rqr = UNDEF_REG, .rqr = UNDEF_REG,
.icr = UNDEF_REG, .icr = UNDEF_REG,
.presc = UNDEF_REG,
.hwcfgr1 = UNDEF_REG,
}, },
.cfg = { .cfg = {
.uart_enable_bit = 13, .uart_enable_bit = 13,
.has_7bits_data = false, .has_7bits_data = false,
.fifosize = 1,
} }
}; };
static struct stm32_usart_info __maybe_unused stm32f7_info = { static struct stm32_usart_info __maybe_unused stm32f7_info = {
.ofs = { .ofs = {
.cr1 = 0x00, .cr1 = 0x00,
.cr2 = 0x04, .cr2 = 0x04,
.cr3 = 0x08, .cr3 = 0x08,
.brr = 0x0c, .brr = 0x0c,
.gtpr = 0x10, .gtpr = 0x10,
.rtor = 0x14, .rtor = 0x14,
.rqr = 0x18, .rqr = 0x18,
.isr = 0x1c, .isr = 0x1c,
.icr = 0x20, .icr = 0x20,
.rdr = 0x24, .rdr = 0x24,
.tdr = 0x28, .tdr = 0x28,
.presc = UNDEF_REG,
.hwcfgr1 = UNDEF_REG,
}, },
.cfg = { .cfg = {
.uart_enable_bit = 0, .uart_enable_bit = 0,
.has_7bits_data = true, .has_7bits_data = true,
.has_swap = true, .has_swap = true,
.fifosize = 1,
} }
}; };
static struct stm32_usart_info __maybe_unused stm32h7_info = { static struct stm32_usart_info __maybe_unused stm32h7_info = {
.ofs = { .ofs = {
.cr1 = 0x00, .cr1 = 0x00,
.cr2 = 0x04, .cr2 = 0x04,
.cr3 = 0x08, .cr3 = 0x08,
.brr = 0x0c, .brr = 0x0c,
.gtpr = 0x10, .gtpr = 0x10,
.rtor = 0x14, .rtor = 0x14,
.rqr = 0x18, .rqr = 0x18,
.isr = 0x1c, .isr = 0x1c,
.icr = 0x20, .icr = 0x20,
.rdr = 0x24, .rdr = 0x24,
.tdr = 0x28, .tdr = 0x28,
.presc = 0x2c,
.hwcfgr1 = 0x3f0,
}, },
.cfg = { .cfg = {
.uart_enable_bit = 0, .uart_enable_bit = 0,
@ -100,7 +105,6 @@ static struct stm32_usart_info __maybe_unused stm32h7_info = {
.has_swap = true, .has_swap = true,
.has_wakeup = true, .has_wakeup = true,
.has_fifo = true, .has_fifo = true,
.fifosize = 16,
} }
}; };
@ -1147,6 +1151,8 @@ static void stm32_usart_shutdown(struct uart_port *port)
free_irq(port->irq, port); free_irq(port->irq, port);
} }
static const unsigned int stm32_usart_presc_val[] = {1, 2, 4, 6, 8, 10, 12, 16, 32, 64, 128, 256};
static void stm32_usart_set_termios(struct uart_port *port, static void stm32_usart_set_termios(struct uart_port *port,
struct ktermios *termios, struct ktermios *termios,
const struct ktermios *old) const struct ktermios *old)
@ -1155,17 +1161,19 @@ static void stm32_usart_set_termios(struct uart_port *port,
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
const struct stm32_usart_config *cfg = &stm32_port->info->cfg; const struct stm32_usart_config *cfg = &stm32_port->info->cfg;
struct serial_rs485 *rs485conf = &port->rs485; struct serial_rs485 *rs485conf = &port->rs485;
unsigned int baud, bits; unsigned int baud, bits, uart_clk, uart_clk_pres;
u32 usartdiv, mantissa, fraction, oversampling; u32 usartdiv, mantissa, fraction, oversampling;
tcflag_t cflag = termios->c_cflag; tcflag_t cflag = termios->c_cflag;
u32 cr1, cr2, cr3, isr; u32 cr1, cr2, cr3, isr, brr, presc;
unsigned long flags; unsigned long flags;
int ret; int ret;
if (!stm32_port->hw_flow_control) if (!stm32_port->hw_flow_control)
cflag &= ~CRTSCTS; cflag &= ~CRTSCTS;
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 8); uart_clk = clk_get_rate(stm32_port->clk);
baud = uart_get_baud_rate(port, termios, old, 0, uart_clk / 8);
uart_port_lock_irqsave(port, &flags); uart_port_lock_irqsave(port, &flags);
@ -1267,27 +1275,48 @@ static void stm32_usart_set_termios(struct uart_port *port,
cr3 |= USART_CR3_CTSE | USART_CR3_RTSE; cr3 |= USART_CR3_CTSE | USART_CR3_RTSE;
} }
usartdiv = DIV_ROUND_CLOSEST(port->uartclk, baud); for (presc = 0; presc <= USART_PRESC_MAX; presc++) {
uart_clk_pres = DIV_ROUND_CLOSEST(uart_clk, stm32_usart_presc_val[presc]);
usartdiv = DIV_ROUND_CLOSEST(uart_clk_pres, baud);
/* /*
* The USART supports 16 or 8 times oversampling. * The USART supports 16 or 8 times oversampling.
* By default we prefer 16 times oversampling, so that the receiver * By default we prefer 16 times oversampling, so that the receiver
* has a better tolerance to clock deviations. * has a better tolerance to clock deviations.
* 8 times oversampling is only used to achieve higher speeds. * 8 times oversampling is only used to achieve higher speeds.
*/ */
if (usartdiv < 16) { if (usartdiv < 16) {
oversampling = 8; oversampling = 8;
cr1 |= USART_CR1_OVER8; cr1 |= USART_CR1_OVER8;
stm32_usart_set_bits(port, ofs->cr1, USART_CR1_OVER8); stm32_usart_set_bits(port, ofs->cr1, USART_CR1_OVER8);
} else { } else {
oversampling = 16; oversampling = 16;
cr1 &= ~USART_CR1_OVER8; cr1 &= ~USART_CR1_OVER8;
stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_OVER8); stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_OVER8);
}
mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT;
fraction = usartdiv % oversampling;
brr = mantissa | fraction;
if (FIELD_FIT(USART_BRR_MASK, brr)) {
if (ofs->presc != UNDEF_REG) {
port->uartclk = uart_clk_pres;
writel_relaxed(presc, port->membase + ofs->presc);
} else if (presc) {
/* We need a prescaler but we don't have it (STM32F4, STM32F7) */
dev_err(port->dev,
"unable to set baudrate, input clock is too high");
}
break;
} else if (presc == USART_PRESC_MAX) {
/* Even with prescaler and brr at max value we can't set baudrate */
dev_err(port->dev, "unable to set baudrate, input clock is too high");
break;
}
} }
mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT; writel_relaxed(brr, port->membase + ofs->brr);
fraction = usartdiv % oversampling;
writel_relaxed(mantissa | fraction, port->membase + ofs->brr);
uart_update_timeout(port, cflag, baud); uart_update_timeout(port, cflag, baud);
@ -1471,37 +1500,57 @@ static const struct uart_ops stm32_uart_ops = {
#endif /* CONFIG_CONSOLE_POLL */ #endif /* CONFIG_CONSOLE_POLL */
}; };
/* struct stm32_usart_thresh_ratio {
* STM32H7 RX & TX FIFO threshold configuration (CR3 RXFTCFG / TXFTCFG) int mul;
* Note: 1 isn't a valid value in RXFTCFG / TXFTCFG. In this case, int div;
* RXNEIE / TXEIE can be used instead of threshold irqs: RXFTIE / TXFTIE. };
* So, RXFTCFG / TXFTCFG bitfields values are encoded as array index + 1.
*/
static const u32 stm32h7_usart_fifo_thresh_cfg[] = { 1, 2, 4, 8, 12, 14, 16 };
static void stm32_usart_get_ftcfg(struct platform_device *pdev, const char *p, static const struct stm32_usart_thresh_ratio stm32h7_usart_fifo_thresh_cfg[] = {
int *ftcfg) {1, 8}, {1, 4}, {1, 2}, {3, 4}, {7, 8}, {1, 1} };
static int stm32_usart_get_thresh_value(u32 fifo_size, int index)
{ {
u32 bytes, i; return fifo_size * stm32h7_usart_fifo_thresh_cfg[index].mul /
stm32h7_usart_fifo_thresh_cfg[index].div;
}
/* DT option to get RX & TX FIFO threshold (default to 8 bytes) */ static int stm32_usart_get_ftcfg(struct platform_device *pdev, struct stm32_port *stm32port,
const char *p, int *ftcfg)
{
const struct stm32_usart_offsets *ofs = &stm32port->info->ofs;
u32 bytes, i, cfg8;
int fifo_size;
if (WARN_ON(ofs->hwcfgr1 == UNDEF_REG))
return 1;
cfg8 = FIELD_GET(USART_HWCFGR1_CFG8,
readl_relaxed(stm32port->port.membase + ofs->hwcfgr1));
/* On STM32H7, hwcfgr is not present, so returned value will be 0 */
fifo_size = cfg8 ? 1 << cfg8 : STM32H7_USART_FIFO_SIZE;
/* DT option to get RX & TX FIFO threshold (default to half fifo size) */
if (of_property_read_u32(pdev->dev.of_node, p, &bytes)) if (of_property_read_u32(pdev->dev.of_node, p, &bytes))
bytes = 8; bytes = fifo_size / 2;
for (i = 0; i < ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg); i++) if (bytes < stm32_usart_get_thresh_value(fifo_size, 0)) {
if (stm32h7_usart_fifo_thresh_cfg[i] >= bytes) *ftcfg = -EINVAL;
return fifo_size;
}
for (i = 0; i < ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg); i++) {
if (stm32_usart_get_thresh_value(fifo_size, i) >= bytes)
break; break;
}
if (i >= ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg)) if (i >= ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg))
i = ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg) - 1; i = ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg) - 1;
dev_dbg(&pdev->dev, "%s set to %d bytes\n", p, dev_dbg(&pdev->dev, "%s set to %d/%d bytes\n", p,
stm32h7_usart_fifo_thresh_cfg[i]); stm32_usart_get_thresh_value(fifo_size, i), fifo_size);
/* Provide FIFO threshold ftcfg (1 is invalid: threshold irq unused) */ *ftcfg = i;
if (i) return fifo_size;
*ftcfg = i - 1;
else
*ftcfg = -EINVAL;
} }
static void stm32_usart_deinit_port(struct stm32_port *stm32port) static void stm32_usart_deinit_port(struct stm32_port *stm32port)
@ -1531,7 +1580,6 @@ static int stm32_usart_init_port(struct stm32_port *stm32port,
port->flags = UPF_BOOT_AUTOCONF; port->flags = UPF_BOOT_AUTOCONF;
port->ops = &stm32_uart_ops; port->ops = &stm32_uart_ops;
port->dev = &pdev->dev; port->dev = &pdev->dev;
port->fifosize = stm32port->info->cfg.fifosize;
port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_STM32_CONSOLE); port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_STM32_CONSOLE);
port->irq = irq; port->irq = irq;
port->rs485_config = stm32_usart_config_rs485; port->rs485_config = stm32_usart_config_rs485;
@ -1547,14 +1595,6 @@ static int stm32_usart_init_port(struct stm32_port *stm32port,
stm32port->swap = stm32port->info->cfg.has_swap && stm32port->swap = stm32port->info->cfg.has_swap &&
of_property_read_bool(pdev->dev.of_node, "rx-tx-swap"); of_property_read_bool(pdev->dev.of_node, "rx-tx-swap");
stm32port->fifoen = stm32port->info->cfg.has_fifo;
if (stm32port->fifoen) {
stm32_usart_get_ftcfg(pdev, "rx-threshold",
&stm32port->rxftcfg);
stm32_usart_get_ftcfg(pdev, "tx-threshold",
&stm32port->txftcfg);
}
port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res); port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(port->membase)) if (IS_ERR(port->membase))
return PTR_ERR(port->membase); return PTR_ERR(port->membase);
@ -1577,6 +1617,15 @@ static int stm32_usart_init_port(struct stm32_port *stm32port,
goto err_clk; goto err_clk;
} }
stm32port->fifoen = stm32port->info->cfg.has_fifo;
if (stm32port->fifoen) {
stm32_usart_get_ftcfg(pdev, stm32port, "rx-threshold", &stm32port->rxftcfg);
port->fifosize = stm32_usart_get_ftcfg(pdev, stm32port, "tx-threshold",
&stm32port->txftcfg);
} else {
port->fifosize = 1;
}
stm32port->gpios = mctrl_gpio_init(&stm32port->port, 0); stm32port->gpios = mctrl_gpio_init(&stm32port->port, 0);
if (IS_ERR(stm32port->gpios)) { if (IS_ERR(stm32port->gpios)) {
ret = PTR_ERR(stm32port->gpios); ret = PTR_ERR(stm32port->gpios);

View File

@ -9,17 +9,19 @@
#define DRIVER_NAME "stm32-usart" #define DRIVER_NAME "stm32-usart"
struct stm32_usart_offsets { struct stm32_usart_offsets {
u8 cr1; u16 cr1;
u8 cr2; u16 cr2;
u8 cr3; u16 cr3;
u8 brr; u16 brr;
u8 gtpr; u16 gtpr;
u8 rtor; u16 rtor;
u8 rqr; u16 rqr;
u8 isr; u16 isr;
u8 icr; u16 icr;
u8 rdr; u16 rdr;
u8 tdr; u16 tdr;
u16 presc;
u16 hwcfgr1;
}; };
struct stm32_usart_config { struct stm32_usart_config {
@ -28,7 +30,6 @@ struct stm32_usart_config {
bool has_swap; bool has_swap;
bool has_wakeup; bool has_wakeup;
bool has_fifo; bool has_fifo;
int fifosize;
}; };
struct stm32_usart_info { struct stm32_usart_info {
@ -36,7 +37,7 @@ struct stm32_usart_info {
struct stm32_usart_config cfg; struct stm32_usart_config cfg;
}; };
#define UNDEF_REG 0xff #define UNDEF_REG 0xffff
/* USART_SR (F4) / USART_ISR (F7) */ /* USART_SR (F4) / USART_ISR (F7) */
#define USART_SR_PE BIT(0) #define USART_SR_PE BIT(0)
@ -71,6 +72,7 @@ struct stm32_usart_info {
#define USART_BRR_DIV_M_MASK GENMASK(15, 4) #define USART_BRR_DIV_M_MASK GENMASK(15, 4)
#define USART_BRR_DIV_M_SHIFT 4 #define USART_BRR_DIV_M_SHIFT 4
#define USART_BRR_04_R_SHIFT 1 #define USART_BRR_04_R_SHIFT 1
#define USART_BRR_MASK (USART_BRR_DIV_M_MASK | USART_BRR_DIV_F_MASK)
/* USART_CR1 */ /* USART_CR1 */
#define USART_CR1_SBK BIT(0) #define USART_CR1_SBK BIT(0)
@ -176,8 +178,16 @@ struct stm32_usart_info {
#define USART_ICR_CMCF BIT(17) /* F7 */ #define USART_ICR_CMCF BIT(17) /* F7 */
#define USART_ICR_WUCF BIT(20) /* H7 */ #define USART_ICR_WUCF BIT(20) /* H7 */
/* USART_PRESC */
#define USART_PRESC GENMASK(3, 0) /* H7 */
#define USART_PRESC_MAX 0b1011
/* USART_HWCFCR1 */
#define USART_HWCFGR1_CFG8 GENMASK(31, 28) /* MP1 */
#define STM32_SERIAL_NAME "ttySTM" #define STM32_SERIAL_NAME "ttySTM"
#define STM32_MAX_PORTS 8 #define STM32_MAX_PORTS 9
#define STM32H7_USART_FIFO_SIZE 16
#define RX_BUF_L 4096 /* dma rx buffer length */ #define RX_BUF_L 4096 /* dma rx buffer length */
#define RX_BUF_P (RX_BUF_L / 2) /* dma rx buffer period */ #define RX_BUF_P (RX_BUF_L / 2) /* dma rx buffer period */

View File

@ -260,7 +260,7 @@ static void receive_chars(struct uart_port *port)
if (port->ignore_status_mask & SUP_DUMMY_READ) if (port->ignore_status_mask & SUP_DUMMY_READ)
goto ignore_char; goto ignore_char;
if (uart_handle_sysrq_char(port, ch)) if (uart_prepare_sysrq_char(port, ch))
goto ignore_char; goto ignore_char;
uart_insert_char(port, lsr, SUP_UART_LSR_OE, ch, flag); uart_insert_char(port, lsr, SUP_UART_LSR_OE, ch, flag);
@ -287,7 +287,7 @@ static irqreturn_t sunplus_uart_irq(int irq, void *args)
if (isc & SUP_UART_ISC_TX) if (isc & SUP_UART_ISC_TX)
transmit_chars(port); transmit_chars(port);
uart_port_unlock(port); uart_unlock_and_check_sysrq(port);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -512,22 +512,16 @@ static void sunplus_console_write(struct console *co,
unsigned long flags; unsigned long flags;
int locked = 1; int locked = 1;
local_irq_save(flags); if (oops_in_progress)
locked = uart_port_trylock_irqsave(&sunplus_console_ports[co->index]->port, &flags);
if (sunplus_console_ports[co->index]->port.sysrq)
locked = 0;
else if (oops_in_progress)
locked = uart_port_trylock(&sunplus_console_ports[co->index]->port);
else else
uart_port_lock(&sunplus_console_ports[co->index]->port); uart_port_lock_irqsave(&sunplus_console_ports[co->index]->port, &flags);
uart_console_write(&sunplus_console_ports[co->index]->port, s, count, uart_console_write(&sunplus_console_ports[co->index]->port, s, count,
sunplus_uart_console_putchar); sunplus_uart_console_putchar);
if (locked) if (locked)
uart_port_unlock(&sunplus_console_ports[co->index]->port); uart_port_unlock_irqrestore(&sunplus_console_ports[co->index]->port, flags);
local_irq_restore(flags);
} }
static int __init sunplus_console_setup(struct console *co, char *options) static int __init sunplus_console_setup(struct console *co, char *options)

View File

@ -22,7 +22,9 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/iopoll.h> #include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#define CDNS_UART_TTY_NAME "ttyPS" #define CDNS_UART_TTY_NAME "ttyPS"
#define CDNS_UART_NAME "xuartps" #define CDNS_UART_NAME "xuartps"
@ -193,6 +195,9 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
* @clk_rate_change_nb: Notifier block for clock changes * @clk_rate_change_nb: Notifier block for clock changes
* @quirks: Flags for RXBS support. * @quirks: Flags for RXBS support.
* @cts_override: Modem control state override * @cts_override: Modem control state override
* @gpiod_rts: Pointer to the gpio descriptor
* @rs485_tx_started: RS485 tx state
* @tx_timer: Timer for tx
*/ */
struct cdns_uart { struct cdns_uart {
struct uart_port *port; struct uart_port *port;
@ -203,10 +208,21 @@ struct cdns_uart {
struct notifier_block clk_rate_change_nb; struct notifier_block clk_rate_change_nb;
u32 quirks; u32 quirks;
bool cts_override; bool cts_override;
struct gpio_desc *gpiod_rts;
bool rs485_tx_started;
struct hrtimer tx_timer;
}; };
struct cdns_platform_data { struct cdns_platform_data {
u32 quirks; u32 quirks;
}; };
struct serial_rs485 cdns_rs485_supported = {
.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
SER_RS485_RTS_AFTER_SEND,
.delay_rts_before_send = 1,
.delay_rts_after_send = 1,
};
#define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \ #define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \
clk_rate_change_nb) clk_rate_change_nb)
@ -306,17 +322,114 @@ static void cdns_uart_handle_rx(void *dev_id, unsigned int isrstatus)
} }
/** /**
* cdns_uart_handle_tx - Handle the bytes to be Txed. * cdns_rts_gpio_enable - Configure RTS/GPIO to high/low
* @cdns_uart: Handle to the cdns_uart
* @enable: Value to be set to RTS/GPIO
*/
static void cdns_rts_gpio_enable(struct cdns_uart *cdns_uart, bool enable)
{
u32 val;
if (cdns_uart->gpiod_rts) {
gpiod_set_value(cdns_uart->gpiod_rts, enable);
} else {
val = readl(cdns_uart->port->membase + CDNS_UART_MODEMCR);
if (enable)
val |= CDNS_UART_MODEMCR_RTS;
else
val &= ~CDNS_UART_MODEMCR_RTS;
writel(val, cdns_uart->port->membase + CDNS_UART_MODEMCR);
}
}
/**
* cdns_rs485_tx_setup - Tx setup specific to rs485
* @cdns_uart: Handle to the cdns_uart
*/
static void cdns_rs485_tx_setup(struct cdns_uart *cdns_uart)
{
bool enable;
enable = cdns_uart->port->rs485.flags & SER_RS485_RTS_ON_SEND;
cdns_rts_gpio_enable(cdns_uart, enable);
cdns_uart->rs485_tx_started = true;
}
/**
* cdns_rs485_rx_setup - Rx setup specific to rs485
* @cdns_uart: Handle to the cdns_uart
*/
static void cdns_rs485_rx_setup(struct cdns_uart *cdns_uart)
{
bool enable;
enable = cdns_uart->port->rs485.flags & SER_RS485_RTS_AFTER_SEND;
cdns_rts_gpio_enable(cdns_uart, enable);
cdns_uart->rs485_tx_started = false;
}
/**
* cdns_uart_tx_empty - Check whether TX is empty
* @port: Handle to the uart port structure
*
* Return: TIOCSER_TEMT on success, 0 otherwise
*/
static unsigned int cdns_uart_tx_empty(struct uart_port *port)
{
unsigned int status;
status = readl(port->membase + CDNS_UART_SR);
status &= (CDNS_UART_SR_TXEMPTY | CDNS_UART_SR_TACTIVE);
return (status == CDNS_UART_SR_TXEMPTY) ? TIOCSER_TEMT : 0;
}
/**
* cdns_rs485_rx_callback - Timer rx callback handler for rs485.
* @t: Handle to the hrtimer structure
*/
static enum hrtimer_restart cdns_rs485_rx_callback(struct hrtimer *t)
{
struct cdns_uart *cdns_uart = container_of(t, struct cdns_uart, tx_timer);
/*
* Default Rx should be setup, because Rx signaling path
* need to enable to receive data.
*/
cdns_rs485_rx_setup(cdns_uart);
return HRTIMER_NORESTART;
}
/**
* cdns_calc_after_tx_delay - calculate delay required for after tx.
* @cdns_uart: Handle to the cdns_uart
*/
static u64 cdns_calc_after_tx_delay(struct cdns_uart *cdns_uart)
{
/*
* Frame time + stop bit time + rs485.delay_rts_after_send
*/
return cdns_uart->port->frame_time
+ DIV_ROUND_UP(cdns_uart->port->frame_time, 7)
+ (u64)cdns_uart->port->rs485.delay_rts_after_send * NSEC_PER_MSEC;
}
/**
* cdns_uart_handle_tx - Handle the bytes to be transmitted.
* @dev_id: Id of the UART port * @dev_id: Id of the UART port
* Return: None * Return: None
*/ */
static void cdns_uart_handle_tx(void *dev_id) static void cdns_uart_handle_tx(void *dev_id)
{ {
struct uart_port *port = (struct uart_port *)dev_id; struct uart_port *port = (struct uart_port *)dev_id;
struct cdns_uart *cdns_uart = port->private_data;
struct circ_buf *xmit = &port->state->xmit; struct circ_buf *xmit = &port->state->xmit;
unsigned int numbytes; unsigned int numbytes;
if (uart_circ_empty(xmit)) { if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
/* Disable the TX Empty interrupt */
writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IDR); writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IDR);
return; return;
} }
@ -332,6 +445,16 @@ static void cdns_uart_handle_tx(void *dev_id)
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port); uart_write_wakeup(port);
/* Enable the TX Empty interrupt */
writel(CDNS_UART_IXR_TXEMPTY, cdns_uart->port->membase + CDNS_UART_IER);
if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED &&
(uart_circ_empty(xmit) || uart_tx_stopped(port))) {
cdns_uart->tx_timer.function = &cdns_rs485_rx_callback;
hrtimer_start(&cdns_uart->tx_timer,
ns_to_ktime(cdns_calc_after_tx_delay(cdns_uart)), HRTIMER_MODE_REL);
}
} }
/** /**
@ -564,6 +687,21 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb,
} }
#endif #endif
/**
* cdns_rs485_tx_callback - Timer tx callback handler for rs485.
* @t: Handle to the hrtimer structure
*/
static enum hrtimer_restart cdns_rs485_tx_callback(struct hrtimer *t)
{
struct cdns_uart *cdns_uart = container_of(t, struct cdns_uart, tx_timer);
uart_port_lock(cdns_uart->port);
cdns_uart_handle_tx(cdns_uart->port);
uart_port_unlock(cdns_uart->port);
return HRTIMER_NORESTART;
}
/** /**
* cdns_uart_start_tx - Start transmitting bytes * cdns_uart_start_tx - Start transmitting bytes
* @port: Handle to the uart port structure * @port: Handle to the uart port structure
@ -571,6 +709,7 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb,
static void cdns_uart_start_tx(struct uart_port *port) static void cdns_uart_start_tx(struct uart_port *port)
{ {
unsigned int status; unsigned int status;
struct cdns_uart *cdns_uart = port->private_data;
if (uart_tx_stopped(port)) if (uart_tx_stopped(port))
return; return;
@ -587,12 +726,19 @@ static void cdns_uart_start_tx(struct uart_port *port)
if (uart_circ_empty(&port->state->xmit)) if (uart_circ_empty(&port->state->xmit))
return; return;
/* Clear the TX Empty interrupt */
writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_ISR); writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_ISR);
if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) {
if (!cdns_uart->rs485_tx_started) {
cdns_uart->tx_timer.function = &cdns_rs485_tx_callback;
cdns_rs485_tx_setup(cdns_uart);
return hrtimer_start(&cdns_uart->tx_timer,
ms_to_ktime(port->rs485.delay_rts_before_send),
HRTIMER_MODE_REL);
}
}
cdns_uart_handle_tx(port); cdns_uart_handle_tx(port);
/* Enable the TX Empty interrupt */
writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IER);
} }
/** /**
@ -602,6 +748,10 @@ static void cdns_uart_start_tx(struct uart_port *port)
static void cdns_uart_stop_tx(struct uart_port *port) static void cdns_uart_stop_tx(struct uart_port *port)
{ {
unsigned int regval; unsigned int regval;
struct cdns_uart *cdns_uart = port->private_data;
if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED)
cdns_rs485_rx_setup(cdns_uart);
regval = readl(port->membase + CDNS_UART_CR); regval = readl(port->membase + CDNS_UART_CR);
regval |= CDNS_UART_CR_TX_DIS; regval |= CDNS_UART_CR_TX_DIS;
@ -626,21 +776,6 @@ static void cdns_uart_stop_rx(struct uart_port *port)
writel(regval, port->membase + CDNS_UART_CR); writel(regval, port->membase + CDNS_UART_CR);
} }
/**
* cdns_uart_tx_empty - Check whether TX is empty
* @port: Handle to the uart port structure
*
* Return: TIOCSER_TEMT on success, 0 otherwise
*/
static unsigned int cdns_uart_tx_empty(struct uart_port *port)
{
unsigned int status;
status = readl(port->membase + CDNS_UART_SR) &
(CDNS_UART_SR_TXEMPTY | CDNS_UART_SR_TACTIVE);
return (status == CDNS_UART_SR_TXEMPTY) ? TIOCSER_TEMT : 0;
}
/** /**
* cdns_uart_break_ctl - Based on the input ctl we have to start or stop * cdns_uart_break_ctl - Based on the input ctl we have to start or stop
* transmitting char breaks * transmitting char breaks
@ -829,6 +964,9 @@ static int cdns_uart_startup(struct uart_port *port)
(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST)) (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
cpu_relax(); cpu_relax();
if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED)
cdns_rs485_rx_setup(cdns_uart);
/* /*
* Clear the RX disable bit and then set the RX enable bit to enable * Clear the RX disable bit and then set the RX enable bit to enable
* the receiver. * the receiver.
@ -888,6 +1026,10 @@ static void cdns_uart_shutdown(struct uart_port *port)
{ {
int status; int status;
unsigned long flags; unsigned long flags;
struct cdns_uart *cdns_uart = port->private_data;
if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED)
hrtimer_cancel(&cdns_uart->tx_timer);
uart_port_lock_irqsave(port, &flags); uart_port_lock_irqsave(port, &flags);
@ -1033,6 +1175,8 @@ static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
if (mctrl & TIOCM_RTS) if (mctrl & TIOCM_RTS)
val |= CDNS_UART_MODEMCR_RTS; val |= CDNS_UART_MODEMCR_RTS;
if (cdns_uart_data->gpiod_rts)
gpiod_set_value(cdns_uart_data->gpiod_rts, !(mctrl & TIOCM_RTS));
if (mctrl & TIOCM_DTR) if (mctrl & TIOCM_DTR)
val |= CDNS_UART_MODEMCR_DTR; val |= CDNS_UART_MODEMCR_DTR;
if (mctrl & TIOCM_LOOP) if (mctrl & TIOCM_LOOP)
@ -1455,6 +1599,39 @@ MODULE_DEVICE_TABLE(of, cdns_uart_of_match);
/* Temporary variable for storing number of instances */ /* Temporary variable for storing number of instances */
static int instances; static int instances;
/**
* cdns_rs485_config - Called when an application calls TIOCSRS485 ioctl.
* @port: Pointer to the uart_port structure
* @termios: Pointer to the ktermios structure
* @rs485: Pointer to the serial_rs485 structure
*
* Return: 0
*/
static int cdns_rs485_config(struct uart_port *port, struct ktermios *termios,
struct serial_rs485 *rs485)
{
u32 val;
struct cdns_uart *cdns_uart = port->private_data;
if (rs485->flags & SER_RS485_ENABLED) {
dev_dbg(port->dev, "Setting UART to RS485\n");
/* Make sure auto RTS is disabled */
val = readl(port->membase + CDNS_UART_MODEMCR);
val &= ~CDNS_UART_MODEMCR_FCM;
writel(val, port->membase + CDNS_UART_MODEMCR);
/* Timer setup */
hrtimer_init(&cdns_uart->tx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
cdns_uart->tx_timer.function = &cdns_rs485_tx_callback;
/* Disable transmitter and make Rx setup*/
cdns_uart_stop_tx(port);
} else {
hrtimer_cancel(&cdns_uart->tx_timer);
}
return 0;
}
/** /**
* cdns_uart_probe - Platform driver probe * cdns_uart_probe - Platform driver probe
* @pdev: Pointer to the platform device structure * @pdev: Pointer to the platform device structure
@ -1597,9 +1774,23 @@ static int cdns_uart_probe(struct platform_device *pdev)
port->private_data = cdns_uart_data; port->private_data = cdns_uart_data;
port->read_status_mask = CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_RXTRIG | port->read_status_mask = CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_RXTRIG |
CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_TOUT; CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_TOUT;
port->rs485_config = cdns_rs485_config;
port->rs485_supported = cdns_rs485_supported;
cdns_uart_data->port = port; cdns_uart_data->port = port;
platform_set_drvdata(pdev, port); platform_set_drvdata(pdev, port);
rc = uart_get_rs485_mode(port);
if (rc)
goto err_out_clk_notifier;
cdns_uart_data->gpiod_rts = devm_gpiod_get_optional(&pdev->dev, "rts",
GPIOD_OUT_LOW);
if (IS_ERR(cdns_uart_data->gpiod_rts)) {
rc = PTR_ERR(cdns_uart_data->gpiod_rts);
dev_err(port->dev, "xuartps: devm_gpiod_get_optional failed\n");
goto err_out_clk_notifier;
}
pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT); pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT);
pm_runtime_set_active(&pdev->dev); pm_runtime_set_active(&pdev->dev);
@ -1618,6 +1809,8 @@ static int cdns_uart_probe(struct platform_device *pdev)
console_port = port; console_port = port;
} }
#endif #endif
if (cdns_uart_data->port->rs485.flags & SER_RS485_ENABLED)
cdns_rs485_rx_setup(cdns_uart_data);
rc = uart_add_one_port(&cdns_uart_uart_driver, port); rc = uart_add_one_port(&cdns_uart_uart_driver, port);
if (rc) { if (rc) {
@ -1646,6 +1839,7 @@ err_out_pm_disable:
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev); pm_runtime_set_suspended(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_dont_use_autosuspend(&pdev->dev);
err_out_clk_notifier:
#ifdef CONFIG_COMMON_CLK #ifdef CONFIG_COMMON_CLK
clk_notifier_unregister(cdns_uart_data->uartclk, clk_notifier_unregister(cdns_uart_data->uartclk,
&cdns_uart_data->clk_rate_change_nb); &cdns_uart_data->clk_rate_change_nb);

View File

@ -7,6 +7,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/minmax.h> #include <linux/minmax.h>
#include <linux/tty.h> #include <linux/tty.h>
#include <linux/tty_buffer.h>
#include <linux/tty_driver.h> #include <linux/tty_driver.h>
#include <linux/tty_flip.h> #include <linux/tty_flip.h>
#include <linux/timer.h> #include <linux/timer.h>

View File

@ -5,9 +5,9 @@
FONTMAPFILE = cp437.uni FONTMAPFILE = cp437.uni
obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o \ obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o \
selection.o keyboard.o selection.o keyboard.o \
vt.o defkeymap.o
obj-$(CONFIG_CONSOLE_TRANSLATIONS) += consolemap.o consolemap_deftbl.o obj-$(CONFIG_CONSOLE_TRANSLATIONS) += consolemap.o consolemap_deftbl.o
obj-$(CONFIG_HW_CONSOLE) += vt.o defkeymap.o
# Files generated that shall be removed upon make clean # Files generated that shall be removed upon make clean
clean-files := consolemap_deftbl.c defkeymap.c clean-files := consolemap_deftbl.c defkeymap.c

View File

@ -7,7 +7,7 @@
* 'int set_selection_kernel(struct tiocl_selection *, struct tty_struct *)' * 'int set_selection_kernel(struct tiocl_selection *, struct tty_struct *)'
* 'void clear_selection(void)' * 'void clear_selection(void)'
* 'int paste_selection(struct tty_struct *)' * 'int paste_selection(struct tty_struct *)'
* 'int sel_loadlut(char __user *)' * 'int sel_loadlut(u32 __user *)'
* *
* Now that /dev/vcs exists, most of this can disappear again. * Now that /dev/vcs exists, most of this can disappear again.
*/ */
@ -73,10 +73,12 @@ sel_pos(int n, bool unicode)
} }
/** /**
* clear_selection - remove current selection * clear_selection - remove current selection
* *
* Remove the current selection highlight, if any from the console * Remove the current selection highlight, if any from the console holding the
* holding the selection. The caller must hold the console lock. * selection.
*
* Locking: The caller must hold the console lock.
*/ */
void clear_selection(void) void clear_selection(void)
{ {
@ -88,7 +90,7 @@ void clear_selection(void)
} }
EXPORT_SYMBOL_GPL(clear_selection); EXPORT_SYMBOL_GPL(clear_selection);
bool vc_is_sel(struct vc_data *vc) bool vc_is_sel(const struct vc_data *vc)
{ {
return vc == vc_sel.cons; return vc == vc_sel.cons;
} }
@ -110,18 +112,25 @@ static inline int inword(const u32 c)
} }
/** /**
* sel_loadlut() - load the LUT table * sel_loadlut() - load the LUT table
* @p: user table * @lut: user table
* *
* Load the LUT table from user space. The caller must hold the console * Load the LUT table from user space. Make a temporary copy so a partial
* lock. Make a temporary copy so a partial update doesn't make a mess. * update doesn't make a mess.
*
* Locking: The console lock is acquired.
*/ */
int sel_loadlut(char __user *p) int sel_loadlut(u32 __user *lut)
{ {
u32 tmplut[ARRAY_SIZE(inwordLut)]; u32 tmplut[ARRAY_SIZE(inwordLut)];
if (copy_from_user(tmplut, (u32 __user *)(p+4), sizeof(inwordLut)))
if (copy_from_user(tmplut, lut, sizeof(inwordLut)))
return -EFAULT; return -EFAULT;
console_lock();
memcpy(inwordLut, tmplut, sizeof(inwordLut)); memcpy(inwordLut, tmplut, sizeof(inwordLut));
console_unlock();
return 0; return 0;
} }
@ -166,14 +175,14 @@ static int store_utf8(u32 c, char *p)
} }
/** /**
* set_selection_user - set the current selection. * set_selection_user - set the current selection.
* @sel: user selection info * @sel: user selection info
* @tty: the console tty * @tty: the console tty
* *
* Invoked by the ioctl handle for the vt layer. * Invoked by the ioctl handle for the vt layer.
* *
* The entire selection process is managed under the console_lock. It's * Locking: The entire selection process is managed under the console_lock.
* a lot under the lock but its hardly a performance path * It's a lot under the lock but its hardly a performance path.
*/ */
int set_selection_user(const struct tiocl_selection __user *sel, int set_selection_user(const struct tiocl_selection __user *sel,
struct tty_struct *tty) struct tty_struct *tty)

File diff suppressed because it is too large Load Diff

View File

@ -714,8 +714,7 @@ static int vt_resizex(struct vc_data *vc, struct vt_consize __user *cs)
vcp->vc_scan_lines = v.v_vlin; vcp->vc_scan_lines = v.v_vlin;
if (v.v_clin) if (v.v_clin)
vcp->vc_cell_height = v.v_clin; vcp->vc_cell_height = v.v_clin;
vcp->vc_resize_user = 1; ret = __vc_resize(vcp, v.v_cols, v.v_rows, true);
ret = vc_resize(vcp, v.v_cols, v.v_rows);
if (ret) { if (ret) {
vcp->vc_scan_lines = save_scan_lines; vcp->vc_scan_lines = save_scan_lines;
vcp->vc_cell_height = save_cell_height; vcp->vc_cell_height = save_cell_height;
@ -923,9 +922,8 @@ int vt_ioctl(struct tty_struct *tty,
vc = vc_cons[i].d; vc = vc_cons[i].d;
if (vc) { if (vc) {
vc->vc_resize_user = 1;
/* FIXME: review v tty lock */ /* FIXME: review v tty lock */
vc_resize(vc_cons[i].d, cc, ll); __vc_resize(vc_cons[i].d, cc, ll, true);
} }
} }
console_unlock(); console_unlock();

View File

@ -50,7 +50,8 @@ void dummycon_unregister_output_notifier(struct notifier_block *nb)
raw_notifier_chain_unregister(&dummycon_output_nh, nb); raw_notifier_chain_unregister(&dummycon_output_nh, nb);
} }
static void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos) static void dummycon_putc(struct vc_data *vc, u16 c, unsigned int y,
unsigned int x)
{ {
WARN_CONSOLE_UNLOCKED(); WARN_CONSOLE_UNLOCKED();
@ -58,10 +59,10 @@ static void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos)
raw_notifier_call_chain(&dummycon_output_nh, 0, NULL); raw_notifier_call_chain(&dummycon_output_nh, 0, NULL);
} }
static void dummycon_putcs(struct vc_data *vc, const unsigned short *s, static void dummycon_putcs(struct vc_data *vc, const u16 *s, unsigned int count,
int count, int ypos, int xpos) unsigned int ypos, unsigned int xpos)
{ {
int i; unsigned int i;
if (!dummycon_putc_called) { if (!dummycon_putc_called) {
/* Ignore erases */ /* Ignore erases */
@ -78,18 +79,21 @@ static void dummycon_putcs(struct vc_data *vc, const unsigned short *s,
raw_notifier_call_chain(&dummycon_output_nh, 0, NULL); raw_notifier_call_chain(&dummycon_output_nh, 0, NULL);
} }
static int dummycon_blank(struct vc_data *vc, int blank, int mode_switch) static bool dummycon_blank(struct vc_data *vc, enum vesa_blank_mode blank,
bool mode_switch)
{ {
/* Redraw, so that we get putc(s) for output done while blanked */ /* Redraw, so that we get putc(s) for output done while blanked */
return 1; return true;
} }
#else #else
static void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos) { } static void dummycon_putc(struct vc_data *vc, u16 c, unsigned int y,
static void dummycon_putcs(struct vc_data *vc, const unsigned short *s, unsigned int x) { }
int count, int ypos, int xpos) { } static void dummycon_putcs(struct vc_data *vc, const u16 *s, unsigned int count,
static int dummycon_blank(struct vc_data *vc, int blank, int mode_switch) unsigned int ypos, unsigned int xpos) { }
static bool dummycon_blank(struct vc_data *vc, enum vesa_blank_mode blank,
bool mode_switch)
{ {
return 0; return false;
} }
#endif #endif
@ -98,7 +102,7 @@ static const char *dummycon_startup(void)
return "dummy device"; return "dummy device";
} }
static void dummycon_init(struct vc_data *vc, int init) static void dummycon_init(struct vc_data *vc, bool init)
{ {
vc->vc_can_do_color = 1; vc->vc_can_do_color = 1;
if (init) { if (init) {
@ -109,9 +113,9 @@ static void dummycon_init(struct vc_data *vc, int init)
} }
static void dummycon_deinit(struct vc_data *vc) { } static void dummycon_deinit(struct vc_data *vc) { }
static void dummycon_clear(struct vc_data *vc, int sy, int sx, int height, static void dummycon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
int width) { } unsigned int width) { }
static void dummycon_cursor(struct vc_data *vc, int mode) { } static void dummycon_cursor(struct vc_data *vc, bool enable) { }
static bool dummycon_scroll(struct vc_data *vc, unsigned int top, static bool dummycon_scroll(struct vc_data *vc, unsigned int top,
unsigned int bottom, enum con_scroll dir, unsigned int bottom, enum con_scroll dir,
@ -120,9 +124,9 @@ static bool dummycon_scroll(struct vc_data *vc, unsigned int top,
return false; return false;
} }
static int dummycon_switch(struct vc_data *vc) static bool dummycon_switch(struct vc_data *vc)
{ {
return 0; return false;
} }
/* /*

View File

@ -352,7 +352,7 @@ static const char *mdacon_startup(void)
return "MDA-2"; return "MDA-2";
} }
static void mdacon_init(struct vc_data *c, int init) static void mdacon_init(struct vc_data *c, bool init)
{ {
c->vc_complement_mask = 0x0800; /* reverse video */ c->vc_complement_mask = 0x0800; /* reverse video */
c->vc_display_fg = &mda_display_fg; c->vc_display_fg = &mda_display_fg;
@ -427,13 +427,8 @@ static inline u16 *mda_addr(unsigned int x, unsigned int y)
return mda_vram_base + y * mda_num_columns + x; return mda_vram_base + y * mda_num_columns + x;
} }
static void mdacon_putc(struct vc_data *c, int ch, int y, int x) static void mdacon_putcs(struct vc_data *c, const u16 *s, unsigned int count,
{ unsigned int y, unsigned int x)
scr_writew(mda_convert_attr(ch), mda_addr(x, y));
}
static void mdacon_putcs(struct vc_data *c, const unsigned short *s,
int count, int y, int x)
{ {
u16 *dest = mda_addr(x, y); u16 *dest = mda_addr(x, y);
@ -442,29 +437,22 @@ static void mdacon_putcs(struct vc_data *c, const unsigned short *s,
} }
} }
static void mdacon_clear(struct vc_data *c, int y, int x, static void mdacon_clear(struct vc_data *c, unsigned int y, unsigned int x,
int height, int width) unsigned int width)
{ {
u16 *dest = mda_addr(x, y); u16 *dest = mda_addr(x, y);
u16 eattr = mda_convert_attr(c->vc_video_erase_char); u16 eattr = mda_convert_attr(c->vc_video_erase_char);
if (width <= 0 || height <= 0) scr_memsetw(dest, eattr, width * 2);
return;
if (x==0 && width==mda_num_columns) {
scr_memsetw(dest, eattr, height*width*2);
} else {
for (; height > 0; height--, dest+=mda_num_columns)
scr_memsetw(dest, eattr, width*2);
}
} }
static int mdacon_switch(struct vc_data *c) static bool mdacon_switch(struct vc_data *c)
{ {
return 1; /* redrawing needed */ return true; /* redrawing needed */
} }
static int mdacon_blank(struct vc_data *c, int blank, int mode_switch) static bool mdacon_blank(struct vc_data *c, enum vesa_blank_mode blank,
bool mode_switch)
{ {
if (mda_type == TYPE_MDA) { if (mda_type == TYPE_MDA) {
if (blank) if (blank)
@ -472,20 +460,20 @@ static int mdacon_blank(struct vc_data *c, int blank, int mode_switch)
mda_convert_attr(c->vc_video_erase_char), mda_convert_attr(c->vc_video_erase_char),
c->vc_screenbuf_size); c->vc_screenbuf_size);
/* Tell console.c that it has to restore the screen itself */ /* Tell console.c that it has to restore the screen itself */
return 1; return true;
} else { } else {
if (blank) if (blank)
outb_p(0x00, mda_mode_port); /* disable video */ outb_p(0x00, mda_mode_port); /* disable video */
else else
outb_p(MDA_MODE_VIDEO_EN | MDA_MODE_BLINK_EN, outb_p(MDA_MODE_VIDEO_EN | MDA_MODE_BLINK_EN,
mda_mode_port); mda_mode_port);
return 0; return false;
} }
} }
static void mdacon_cursor(struct vc_data *c, int mode) static void mdacon_cursor(struct vc_data *c, bool enable)
{ {
if (mode == CM_ERASE) { if (!enable) {
mda_set_cursor(mda_vram_len - 1); mda_set_cursor(mda_vram_len - 1);
return; return;
} }
@ -544,7 +532,6 @@ static const struct consw mda_con = {
.con_init = mdacon_init, .con_init = mdacon_init,
.con_deinit = mdacon_deinit, .con_deinit = mdacon_deinit,
.con_clear = mdacon_clear, .con_clear = mdacon_clear,
.con_putc = mdacon_putc,
.con_putcs = mdacon_putcs, .con_putcs = mdacon_putcs,
.con_cursor = mdacon_cursor, .con_cursor = mdacon_cursor,
.con_scroll = mdacon_scroll, .con_scroll = mdacon_scroll,

View File

@ -324,7 +324,7 @@ out_unmap:
return NULL; return NULL;
} }
static void newport_init(struct vc_data *vc, int init) static void newport_init(struct vc_data *vc, bool init)
{ {
int cols, rows; int cols, rows;
@ -346,12 +346,12 @@ static void newport_deinit(struct vc_data *c)
} }
} }
static void newport_clear(struct vc_data *vc, int sy, int sx, int height, static void newport_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
int width) unsigned int width)
{ {
int xend = ((sx + width) << 3) - 1; int xend = ((sx + width) << 3) - 1;
int ystart = ((sy << 4) + topscan) & 0x3ff; int ystart = ((sy << 4) + topscan) & 0x3ff;
int yend = (((sy + height) << 4) + topscan - 1) & 0x3ff; int yend = (((sy + 1) << 4) + topscan - 1) & 0x3ff;
if (logo_active) if (logo_active)
return; return;
@ -367,8 +367,8 @@ static void newport_clear(struct vc_data *vc, int sy, int sx, int height,
} }
} }
static void newport_putc(struct vc_data *vc, int charattr, int ypos, static void newport_putc(struct vc_data *vc, u16 charattr, unsigned int ypos,
int xpos) unsigned int xpos)
{ {
unsigned char *p; unsigned char *p;
@ -396,12 +396,13 @@ static void newport_putc(struct vc_data *vc, int charattr, int ypos,
RENDER(npregs, p); RENDER(npregs, p);
} }
static void newport_putcs(struct vc_data *vc, const unsigned short *s, static void newport_putcs(struct vc_data *vc, const u16 *s,
int count, int ypos, int xpos) unsigned int count, unsigned int ypos,
unsigned int xpos)
{ {
int i;
int charattr;
unsigned char *p; unsigned char *p;
unsigned int i;
u16 charattr;
charattr = (scr_readw(s) >> 8) & 0xff; charattr = (scr_readw(s) >> 8) & 0xff;
@ -437,32 +438,28 @@ static void newport_putcs(struct vc_data *vc, const unsigned short *s,
} }
} }
static void newport_cursor(struct vc_data *vc, int mode) static void newport_cursor(struct vc_data *vc, bool enable)
{ {
unsigned short treg; unsigned short treg;
int xcurs, ycurs; int xcurs, ycurs;
switch (mode) { treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
case CM_ERASE:
treg = newport_vc2_get(npregs, VC2_IREG_CONTROL); if (!enable) {
newport_vc2_set(npregs, VC2_IREG_CONTROL, newport_vc2_set(npregs, VC2_IREG_CONTROL,
(treg & ~(VC2_CTRL_ECDISP))); (treg & ~(VC2_CTRL_ECDISP)));
break; return;
case CM_MOVE:
case CM_DRAW:
treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
newport_vc2_set(npregs, VC2_IREG_CONTROL,
(treg | VC2_CTRL_ECDISP));
xcurs = (vc->vc_pos - vc->vc_visible_origin) / 2;
ycurs = ((xcurs / vc->vc_cols) << 4) + 31;
xcurs = ((xcurs % vc->vc_cols) << 3) + xcurs_correction;
newport_vc2_set(npregs, VC2_IREG_CURSX, xcurs);
newport_vc2_set(npregs, VC2_IREG_CURSY, ycurs);
} }
newport_vc2_set(npregs, VC2_IREG_CONTROL, (treg | VC2_CTRL_ECDISP));
xcurs = (vc->vc_pos - vc->vc_visible_origin) / 2;
ycurs = ((xcurs / vc->vc_cols) << 4) + 31;
xcurs = ((xcurs % vc->vc_cols) << 3) + xcurs_correction;
newport_vc2_set(npregs, VC2_IREG_CURSX, xcurs);
newport_vc2_set(npregs, VC2_IREG_CURSY, ycurs);
} }
static int newport_switch(struct vc_data *vc) static bool newport_switch(struct vc_data *vc)
{ {
static int logo_drawn = 0; static int logo_drawn = 0;
@ -476,14 +473,15 @@ static int newport_switch(struct vc_data *vc)
} }
} }
return 1; return true;
} }
static int newport_blank(struct vc_data *c, int blank, int mode_switch) static bool newport_blank(struct vc_data *c, enum vesa_blank_mode blank,
bool mode_switch)
{ {
unsigned short treg; unsigned short treg;
if (blank == 0) { if (blank == VESA_NO_BLANKING) {
/* unblank console */ /* unblank console */
treg = newport_vc2_get(npregs, VC2_IREG_CONTROL); treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
newport_vc2_set(npregs, VC2_IREG_CONTROL, newport_vc2_set(npregs, VC2_IREG_CONTROL,
@ -494,10 +492,12 @@ static int newport_blank(struct vc_data *c, int blank, int mode_switch)
newport_vc2_set(npregs, VC2_IREG_CONTROL, newport_vc2_set(npregs, VC2_IREG_CONTROL,
(treg & ~(VC2_CTRL_EDISP))); (treg & ~(VC2_CTRL_EDISP)));
} }
return 1;
return true;
} }
static int newport_set_font(int unit, struct console_font *op, unsigned int vpitch) static int newport_set_font(int unit, const struct console_font *op,
unsigned int vpitch)
{ {
int w = op->width; int w = op->width;
int h = op->height; int h = op->height;
@ -564,12 +564,13 @@ static int newport_set_def_font(int unit, struct console_font *op)
return 0; return 0;
} }
static int newport_font_default(struct vc_data *vc, struct console_font *op, char *name) static int newport_font_default(struct vc_data *vc, struct console_font *op,
const char *name)
{ {
return newport_set_def_font(vc->vc_num, op); return newport_set_def_font(vc->vc_num, op);
} }
static int newport_font_set(struct vc_data *vc, struct console_font *font, static int newport_font_set(struct vc_data *vc, const struct console_font *font,
unsigned int vpitch, unsigned int flags) unsigned int vpitch, unsigned int flags)
{ {
return newport_set_font(vc->vc_num, font, vpitch); return newport_set_font(vc->vc_num, font, vpitch);

View File

@ -71,19 +71,8 @@ static const char *sticon_startup(void)
return "STI console"; return "STI console";
} }
static void sticon_putc(struct vc_data *conp, int c, int ypos, int xpos) static void sticon_putcs(struct vc_data *conp, const u16 *s, unsigned int count,
{ unsigned int ypos, unsigned int xpos)
if (vga_is_gfx || console_blanked)
return;
if (conp->vc_mode != KD_TEXT)
return;
sti_putc(sticon_sti, c, ypos, xpos, font_data[conp->vc_num]);
}
static void sticon_putcs(struct vc_data *conp, const unsigned short *s,
int count, int ypos, int xpos)
{ {
if (vga_is_gfx || console_blanked) if (vga_is_gfx || console_blanked)
return; return;
@ -97,7 +86,7 @@ static void sticon_putcs(struct vc_data *conp, const unsigned short *s,
} }
} }
static void sticon_cursor(struct vc_data *conp, int mode) static void sticon_cursor(struct vc_data *conp, bool enable)
{ {
unsigned short car1; unsigned short car1;
@ -106,23 +95,20 @@ static void sticon_cursor(struct vc_data *conp, int mode)
return; return;
car1 = conp->vc_screenbuf[conp->state.x + conp->state.y * conp->vc_cols]; car1 = conp->vc_screenbuf[conp->state.x + conp->state.y * conp->vc_cols];
switch (mode) { if (!enable) {
case CM_ERASE:
sti_putc(sticon_sti, car1, conp->state.y, conp->state.x, sti_putc(sticon_sti, car1, conp->state.y, conp->state.x,
font_data[conp->vc_num]); font_data[conp->vc_num]);
break; return;
case CM_MOVE: }
case CM_DRAW:
switch (CUR_SIZE(conp->vc_cursor_type)) { switch (CUR_SIZE(conp->vc_cursor_type)) {
case CUR_UNDERLINE: case CUR_UNDERLINE:
case CUR_LOWER_THIRD: case CUR_LOWER_THIRD:
case CUR_LOWER_HALF: case CUR_LOWER_HALF:
case CUR_TWO_THIRDS: case CUR_TWO_THIRDS:
case CUR_BLOCK: case CUR_BLOCK:
sti_putc(sticon_sti, (car1 & 255) + (0 << 8) + (7 << 11), sti_putc(sticon_sti, (car1 & 255) + (0 << 8) + (7 << 11),
conp->state.y, conp->state.x, font_data[conp->vc_num]); conp->state.y, conp->state.x, font_data[conp->vc_num]);
break;
}
break; break;
} }
} }
@ -135,7 +121,7 @@ static bool sticon_scroll(struct vc_data *conp, unsigned int t,
if (vga_is_gfx) if (vga_is_gfx)
return false; return false;
sticon_cursor(conp, CM_ERASE); sticon_cursor(conp, false);
switch (dir) { switch (dir) {
case SM_UP: case SM_UP:
@ -167,7 +153,7 @@ static void sticon_set_def_font(int unit)
} }
} }
static int sticon_set_font(struct vc_data *vc, struct console_font *op, static int sticon_set_font(struct vc_data *vc, const struct console_font *op,
unsigned int vpitch) unsigned int vpitch)
{ {
struct sti_struct *sti = sticon_sti; struct sti_struct *sti = sticon_sti;
@ -260,20 +246,21 @@ static int sticon_set_font(struct vc_data *vc, struct console_font *op,
return 0; return 0;
} }
static int sticon_font_default(struct vc_data *vc, struct console_font *op, char *name) static int sticon_font_default(struct vc_data *vc, struct console_font *op,
const char *name)
{ {
sticon_set_def_font(vc->vc_num); sticon_set_def_font(vc->vc_num);
return 0; return 0;
} }
static int sticon_font_set(struct vc_data *vc, struct console_font *font, static int sticon_font_set(struct vc_data *vc, const struct console_font *font,
unsigned int vpitch, unsigned int flags) unsigned int vpitch, unsigned int flags)
{ {
return sticon_set_font(vc, font, vpitch); return sticon_set_font(vc, font, vpitch);
} }
static void sticon_init(struct vc_data *c, int init) static void sticon_init(struct vc_data *c, bool init)
{ {
struct sti_struct *sti = sticon_sti; struct sti_struct *sti = sticon_sti;
int vc_cols, vc_rows; int vc_cols, vc_rows;
@ -300,33 +287,32 @@ static void sticon_deinit(struct vc_data *c)
sticon_set_def_font(i); sticon_set_def_font(i);
} }
static void sticon_clear(struct vc_data *conp, int sy, int sx, int height, static void sticon_clear(struct vc_data *conp, unsigned int sy, unsigned int sx,
int width) unsigned int width)
{ {
if (!height || !width) sti_clear(sticon_sti, sy, sx, 1, width,
return;
sti_clear(sticon_sti, sy, sx, height, width,
conp->vc_video_erase_char, font_data[conp->vc_num]); conp->vc_video_erase_char, font_data[conp->vc_num]);
} }
static int sticon_switch(struct vc_data *conp) static bool sticon_switch(struct vc_data *conp)
{ {
return 1; /* needs refreshing */ return true; /* needs refreshing */
} }
static int sticon_blank(struct vc_data *c, int blank, int mode_switch) static bool sticon_blank(struct vc_data *c, enum vesa_blank_mode blank,
bool mode_switch)
{ {
if (blank == 0) { if (blank == VESA_NO_BLANKING) {
if (mode_switch) if (mode_switch)
vga_is_gfx = 0; vga_is_gfx = 0;
return 1; return true;
} }
sti_clear(sticon_sti, 0, 0, c->vc_rows, c->vc_cols, BLANK, sti_clear(sticon_sti, 0, 0, c->vc_rows, c->vc_cols, BLANK,
font_data[c->vc_num]); font_data[c->vc_num]);
if (mode_switch) if (mode_switch)
vga_is_gfx = 1; vga_is_gfx = 1;
return 1;
return true;
} }
static u8 sticon_build_attr(struct vc_data *conp, u8 color, static u8 sticon_build_attr(struct vc_data *conp, u8 color,
@ -365,7 +351,6 @@ static const struct consw sti_con = {
.con_init = sticon_init, .con_init = sticon_init,
.con_deinit = sticon_deinit, .con_deinit = sticon_deinit,
.con_clear = sticon_clear, .con_clear = sticon_clear,
.con_putc = sticon_putc,
.con_putcs = sticon_putcs, .con_putcs = sticon_putcs,
.con_cursor = sticon_cursor, .con_cursor = sticon_cursor,
.con_scroll = sticon_scroll, .con_scroll = sticon_scroll,

View File

@ -65,7 +65,7 @@ static struct vgastate vgastate;
* Interface used by the world * Interface used by the world
*/ */
static int vgacon_set_origin(struct vc_data *c); static bool vgacon_set_origin(struct vc_data *c);
static struct uni_pagedict *vgacon_uni_pagedir; static struct uni_pagedict *vgacon_uni_pagedir;
static int vgacon_refcount; static int vgacon_refcount;
@ -81,7 +81,7 @@ static unsigned int vga_video_num_lines; /* Number of text lines */
static bool vga_can_do_color; /* Do we support colors? */ static bool vga_can_do_color; /* Do we support colors? */
static unsigned int vga_default_font_height __read_mostly; /* Height of default screen font */ static unsigned int vga_default_font_height __read_mostly; /* Height of default screen font */
static unsigned char vga_video_type __read_mostly; /* Card type */ static unsigned char vga_video_type __read_mostly; /* Card type */
static int vga_vesa_blanked; static enum vesa_blank_mode vga_vesa_blanked;
static bool vga_palette_blanked; static bool vga_palette_blanked;
static bool vga_is_gfx; static bool vga_is_gfx;
static bool vga_512_chars; static bool vga_512_chars;
@ -138,8 +138,40 @@ static inline void vga_set_mem_top(struct vc_data *c)
static void vgacon_scrolldelta(struct vc_data *c, int lines) static void vgacon_scrolldelta(struct vc_data *c, int lines)
{ {
vc_scrolldelta_helper(c, lines, vga_rolled_over, (void *)vga_vram_base, unsigned long scr_end = c->vc_scr_end - vga_vram_base;
vga_vram_size); unsigned long vorigin = c->vc_visible_origin - vga_vram_base;
unsigned long origin = c->vc_origin - vga_vram_base;
int margin = c->vc_size_row * 4;
int from, wrap, from_off, avail;
/* Turn scrollback off */
if (!lines) {
c->vc_visible_origin = c->vc_origin;
return;
}
/* Do we have already enough to allow jumping from 0 to the end? */
if (vga_rolled_over > scr_end + margin) {
from = scr_end;
wrap = vga_rolled_over + c->vc_size_row;
} else {
from = 0;
wrap = vga_vram_size;
}
from_off = (vorigin - from + wrap) % wrap + lines * c->vc_size_row;
avail = (origin - from + wrap) % wrap;
/* Only a little piece would be left? Show all incl. the piece! */
if (avail < 2 * margin)
margin = 0;
if (from_off < margin)
from_off = 0;
if (from_off > avail - margin)
from_off = avail;
c->vc_visible_origin = vga_vram_base + (from + from_off) % wrap;
vga_set_mem_top(c); vga_set_mem_top(c);
} }
@ -335,7 +367,7 @@ static const char *vgacon_startup(void)
return display_desc; return display_desc;
} }
static void vgacon_init(struct vc_data *c, int init) static void vgacon_init(struct vc_data *c, bool init)
{ {
struct uni_pagedict *p; struct uni_pagedict *p;
@ -352,7 +384,7 @@ static void vgacon_init(struct vc_data *c, int init)
c->vc_scan_lines = vga_scan_lines; c->vc_scan_lines = vga_scan_lines;
c->vc_font.height = c->vc_cell_height = vga_video_font_height; c->vc_font.height = c->vc_cell_height = vga_video_font_height;
/* set dimensions manually if init != 0 since vc_resize() will fail */ /* set dimensions manually if init is true since vc_resize() will fail */
if (init) { if (init) {
c->vc_cols = vga_video_num_columns; c->vc_cols = vga_video_num_columns;
c->vc_rows = vga_video_num_lines; c->vc_rows = vga_video_num_lines;
@ -471,7 +503,7 @@ static void vgacon_set_cursor_size(int from, int to)
raw_spin_unlock_irqrestore(&vga_lock, flags); raw_spin_unlock_irqrestore(&vga_lock, flags);
} }
static void vgacon_cursor(struct vc_data *c, int mode) static void vgacon_cursor(struct vc_data *c, bool enable)
{ {
unsigned int c_height; unsigned int c_height;
@ -482,47 +514,41 @@ static void vgacon_cursor(struct vc_data *c, int mode)
c_height = c->vc_cell_height; c_height = c->vc_cell_height;
switch (mode) { write_vga(14, (c->vc_pos - vga_vram_base) / 2);
case CM_ERASE:
write_vga(14, (c->vc_pos - vga_vram_base) / 2); if (!enable) {
if (vga_video_type >= VIDEO_TYPE_VGAC) if (vga_video_type >= VIDEO_TYPE_VGAC)
vgacon_set_cursor_size(31, 30); vgacon_set_cursor_size(31, 30);
else else
vgacon_set_cursor_size(31, 31); vgacon_set_cursor_size(31, 31);
break; return;
}
case CM_MOVE: switch (CUR_SIZE(c->vc_cursor_type)) {
case CM_DRAW: case CUR_UNDERLINE:
write_vga(14, (c->vc_pos - vga_vram_base) / 2); vgacon_set_cursor_size(c_height - (c_height < 10 ? 2 : 3),
switch (CUR_SIZE(c->vc_cursor_type)) { c_height - (c_height < 10 ? 1 : 2));
case CUR_UNDERLINE: break;
vgacon_set_cursor_size(c_height - case CUR_TWO_THIRDS:
(c_height < 10 ? 2 : 3), vgacon_set_cursor_size(c_height / 3,
c_height - c_height - (c_height < 10 ? 1 : 2));
(c_height < 10 ? 1 : 2)); break;
break; case CUR_LOWER_THIRD:
case CUR_TWO_THIRDS: vgacon_set_cursor_size(c_height * 2 / 3,
vgacon_set_cursor_size(c_height / 3, c_height - c_height - (c_height < 10 ? 1 : 2));
(c_height < 10 ? 1 : 2)); break;
break; case CUR_LOWER_HALF:
case CUR_LOWER_THIRD: vgacon_set_cursor_size(c_height / 2,
vgacon_set_cursor_size(c_height * 2 / 3, c_height - c_height - (c_height < 10 ? 1 : 2));
(c_height < 10 ? 1 : 2)); break;
break; case CUR_NONE:
case CUR_LOWER_HALF: if (vga_video_type >= VIDEO_TYPE_VGAC)
vgacon_set_cursor_size(c_height / 2, c_height - vgacon_set_cursor_size(31, 30);
(c_height < 10 ? 1 : 2)); else
break; vgacon_set_cursor_size(31, 31);
case CUR_NONE: break;
if (vga_video_type >= VIDEO_TYPE_VGAC) default:
vgacon_set_cursor_size(31, 30); vgacon_set_cursor_size(1, c_height);
else
vgacon_set_cursor_size(31, 31);
break;
default:
vgacon_set_cursor_size(1, c_height);
break;
}
break; break;
} }
} }
@ -588,7 +614,7 @@ static void vgacon_doresize(struct vc_data *c,
raw_spin_unlock_irqrestore(&vga_lock, flags); raw_spin_unlock_irqrestore(&vga_lock, flags);
} }
static int vgacon_switch(struct vc_data *c) static bool vgacon_switch(struct vc_data *c)
{ {
int x = c->vc_cols * VGA_FONTWIDTH; int x = c->vc_cols * VGA_FONTWIDTH;
int y = c->vc_rows * c->vc_cell_height; int y = c->vc_rows * c->vc_cell_height;
@ -617,7 +643,7 @@ static int vgacon_switch(struct vc_data *c)
vgacon_doresize(c, c->vc_cols, c->vc_rows); vgacon_doresize(c, c->vc_cols, c->vc_rows);
} }
return 0; /* Redrawing not needed */ return false; /* Redrawing not needed */
} }
static void vga_set_palette(struct vc_data *vc, const unsigned char *table) static void vga_set_palette(struct vc_data *vc, const unsigned char *table)
@ -657,7 +683,7 @@ static struct {
unsigned char ClockingMode; /* Seq-Controller:01h */ unsigned char ClockingMode; /* Seq-Controller:01h */
} vga_state; } vga_state;
static void vga_vesa_blank(struct vgastate *state, int mode) static void vga_vesa_blank(struct vgastate *state, enum vesa_blank_mode mode)
{ {
/* save original values of VGA controller registers */ /* save original values of VGA controller registers */
if (!vga_vesa_blanked) { if (!vga_vesa_blanked) {
@ -771,13 +797,14 @@ static void vga_pal_blank(struct vgastate *state)
} }
} }
static int vgacon_blank(struct vc_data *c, int blank, int mode_switch) static bool vgacon_blank(struct vc_data *c, enum vesa_blank_mode blank,
bool mode_switch)
{ {
switch (blank) { switch (blank) {
case 0: /* Unblank */ case VESA_NO_BLANKING: /* Unblank */
if (vga_vesa_blanked) { if (vga_vesa_blanked) {
vga_vesa_unblank(&vgastate); vga_vesa_unblank(&vgastate);
vga_vesa_blanked = 0; vga_vesa_blanked = VESA_NO_BLANKING;
} }
if (vga_palette_blanked) { if (vga_palette_blanked) {
vga_set_palette(c, color_table); vga_set_palette(c, color_table);
@ -787,8 +814,7 @@ static int vgacon_blank(struct vc_data *c, int blank, int mode_switch)
vga_is_gfx = false; vga_is_gfx = false;
/* Tell console.c that it has to restore the screen itself */ /* Tell console.c that it has to restore the screen itself */
return 1; return 1;
case 1: /* Normal blanking */ case VESA_VSYNC_SUSPEND: /* Normal blanking */
case -1: /* Obsolete */
if (!mode_switch && vga_video_type == VIDEO_TYPE_VGAC) { if (!mode_switch && vga_video_type == VIDEO_TYPE_VGAC) {
vga_pal_blank(&vgastate); vga_pal_blank(&vgastate);
vga_palette_blanked = true; vga_palette_blanked = true;
@ -1004,7 +1030,7 @@ static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight)
/* void size to cause regs to be rewritten */ /* void size to cause regs to be rewritten */
cursor_size_lastfrom = 0; cursor_size_lastfrom = 0;
cursor_size_lastto = 0; cursor_size_lastto = 0;
c->vc_sw->con_cursor(c, CM_DRAW); c->vc_sw->con_cursor(c, true);
} }
c->vc_font.height = c->vc_cell_height = fontheight; c->vc_font.height = c->vc_cell_height = fontheight;
vc_resize(c, 0, rows); /* Adjust console size */ vc_resize(c, 0, rows); /* Adjust console size */
@ -1013,7 +1039,7 @@ static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight)
return 0; return 0;
} }
static int vgacon_font_set(struct vc_data *c, struct console_font *font, static int vgacon_font_set(struct vc_data *c, const struct console_font *font,
unsigned int vpitch, unsigned int flags) unsigned int vpitch, unsigned int flags)
{ {
unsigned charcount = font->charcount; unsigned charcount = font->charcount;
@ -1049,12 +1075,12 @@ static int vgacon_font_get(struct vc_data *c, struct console_font *font, unsigne
} }
static int vgacon_resize(struct vc_data *c, unsigned int width, static int vgacon_resize(struct vc_data *c, unsigned int width,
unsigned int height, unsigned int user) unsigned int height, bool from_user)
{ {
if ((width << 1) * height > vga_vram_size) if ((width << 1) * height > vga_vram_size)
return -EINVAL; return -EINVAL;
if (user) { if (from_user) {
/* /*
* Ho ho! Someone (svgatextmode, eh?) may have reprogrammed * Ho ho! Someone (svgatextmode, eh?) may have reprogrammed
* the video mode! Set the new defaults then and go away. * the video mode! Set the new defaults then and go away.
@ -1074,15 +1100,15 @@ static int vgacon_resize(struct vc_data *c, unsigned int width,
return 0; return 0;
} }
static int vgacon_set_origin(struct vc_data *c) static bool vgacon_set_origin(struct vc_data *c)
{ {
if (vga_is_gfx || /* We don't play origin tricks in graphic modes */ if (vga_is_gfx || /* We don't play origin tricks in graphic modes */
(console_blanked && !vga_palette_blanked)) /* Nor we write to blanked screens */ (console_blanked && !vga_palette_blanked)) /* Nor we write to blanked screens */
return 0; return false;
c->vc_origin = c->vc_visible_origin = vga_vram_base; c->vc_origin = c->vc_visible_origin = vga_vram_base;
vga_set_mem_top(c); vga_set_mem_top(c);
vga_rolled_over = 0; vga_rolled_over = 0;
return 1; return true;
} }
static void vgacon_save_screen(struct vc_data *c) static void vgacon_save_screen(struct vc_data *c)
@ -1159,11 +1185,10 @@ static bool vgacon_scroll(struct vc_data *c, unsigned int t, unsigned int b,
* The console `switch' structure for the VGA based console * The console `switch' structure for the VGA based console
*/ */
static void vgacon_clear(struct vc_data *vc, int sy, int sx, int height, static void vgacon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
int width) { } unsigned int width) { }
static void vgacon_putc(struct vc_data *vc, int c, int ypos, int xpos) { } static void vgacon_putcs(struct vc_data *vc, const u16 *s, unsigned int count,
static void vgacon_putcs(struct vc_data *vc, const unsigned short *s, unsigned int ypos, unsigned int xpos) { }
int count, int ypos, int xpos) { }
const struct consw vga_con = { const struct consw vga_con = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
@ -1171,7 +1196,6 @@ const struct consw vga_con = {
.con_init = vgacon_init, .con_init = vgacon_init,
.con_deinit = vgacon_deinit, .con_deinit = vgacon_deinit,
.con_clear = vgacon_clear, .con_clear = vgacon_clear,
.con_putc = vgacon_putc,
.con_putcs = vgacon_putcs, .con_putcs = vgacon_putcs,
.con_cursor = vgacon_cursor, .con_cursor = vgacon_cursor,
.con_scroll = vgacon_scroll, .con_scroll = vgacon_scroll,

View File

@ -233,7 +233,7 @@ static void bit_clear_margins(struct vc_data *vc, struct fb_info *info,
} }
} }
static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode, static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
int fg, int bg) int fg, int bg)
{ {
struct fb_cursor cursor; struct fb_cursor cursor;
@ -348,16 +348,7 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode,
mask[i++] = msk; mask[i++] = msk;
} }
switch (mode) { ops->cursor_state.enable = enable && !use_sw;
case CM_ERASE:
ops->cursor_state.enable = 0;
break;
case CM_DRAW:
case CM_MOVE:
default:
ops->cursor_state.enable = (use_sw) ? 0 : 1;
break;
}
cursor.image.data = src; cursor.image.data = src;
cursor.image.fg_color = ops->cursor_state.image.fg_color; cursor.image.fg_color = ops->cursor_state.image.fg_color;

View File

@ -351,7 +351,7 @@ static void fb_flashcursor(struct work_struct *work)
struct fb_info *info; struct fb_info *info;
struct vc_data *vc = NULL; struct vc_data *vc = NULL;
int c; int c;
int mode; bool enable;
int ret; int ret;
/* FIXME: we should sort out the unbind locking instead */ /* FIXME: we should sort out the unbind locking instead */
@ -375,9 +375,8 @@ static void fb_flashcursor(struct work_struct *work)
} }
c = scr_readw((u16 *) vc->vc_pos); c = scr_readw((u16 *) vc->vc_pos);
mode = (!ops->cursor_flash || ops->cursor_state.enable) ? enable = ops->cursor_flash && !ops->cursor_state.enable;
CM_ERASE : CM_DRAW; ops->cursor(vc, info, enable, get_color(vc, info, c, 1),
ops->cursor(vc, info, mode, get_color(vc, info, c, 1),
get_color(vc, info, c, 0)); get_color(vc, info, c, 0));
console_unlock(); console_unlock();
@ -920,7 +919,7 @@ static void display_to_var(struct fb_var_screeninfo *var,
static const char *fbcon_startup(void) static const char *fbcon_startup(void)
{ {
const char *display_desc = "frame buffer device"; static const char display_desc[] = "frame buffer device";
struct fbcon_display *p = &fb_display[fg_console]; struct fbcon_display *p = &fb_display[fg_console];
struct vc_data *vc = vc_cons[fg_console].d; struct vc_data *vc = vc_cons[fg_console].d;
const struct font_desc *font = NULL; const struct font_desc *font = NULL;
@ -987,7 +986,7 @@ static const char *fbcon_startup(void)
return display_desc; return display_desc;
} }
static void fbcon_init(struct vc_data *vc, int init) static void fbcon_init(struct vc_data *vc, bool init)
{ {
struct fb_info *info; struct fb_info *info;
struct fbcon_ops *ops; struct fbcon_ops *ops;
@ -1234,8 +1233,8 @@ finished:
* restriction is simplicity & efficiency at the moment. * restriction is simplicity & efficiency at the moment.
*/ */
static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height, static void __fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
int width) unsigned int height, unsigned int width)
{ {
struct fb_info *info = fbcon_info_from_console(vc->vc_num); struct fb_info *info = fbcon_info_from_console(vc->vc_num);
struct fbcon_ops *ops = info->fbcon_par; struct fbcon_ops *ops = info->fbcon_par;
@ -1272,8 +1271,14 @@ static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height,
ops->clear(vc, info, real_y(p, sy), sx, height, width); ops->clear(vc, info, real_y(p, sy), sx, height, width);
} }
static void fbcon_putcs(struct vc_data *vc, const unsigned short *s, static void fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
int count, int ypos, int xpos) unsigned int width)
{
__fbcon_clear(vc, sy, sx, 1, width);
}
static void fbcon_putcs(struct vc_data *vc, const u16 *s, unsigned int count,
unsigned int ypos, unsigned int xpos)
{ {
struct fb_info *info = fbcon_info_from_console(vc->vc_num); struct fb_info *info = fbcon_info_from_console(vc->vc_num);
struct fbcon_display *p = &fb_display[vc->vc_num]; struct fbcon_display *p = &fb_display[vc->vc_num];
@ -1285,14 +1290,6 @@ static void fbcon_putcs(struct vc_data *vc, const unsigned short *s,
get_color(vc, info, scr_readw(s), 0)); get_color(vc, info, scr_readw(s), 0));
} }
static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos)
{
unsigned short chr;
scr_writew(c, &chr);
fbcon_putcs(vc, &chr, 1, ypos, xpos);
}
static void fbcon_clear_margins(struct vc_data *vc, int bottom_only) static void fbcon_clear_margins(struct vc_data *vc, int bottom_only)
{ {
struct fb_info *info = fbcon_info_from_console(vc->vc_num); struct fb_info *info = fbcon_info_from_console(vc->vc_num);
@ -1302,7 +1299,7 @@ static void fbcon_clear_margins(struct vc_data *vc, int bottom_only)
ops->clear_margins(vc, info, margin_color, bottom_only); ops->clear_margins(vc, info, margin_color, bottom_only);
} }
static void fbcon_cursor(struct vc_data *vc, int mode) static void fbcon_cursor(struct vc_data *vc, bool enable)
{ {
struct fb_info *info = fbcon_info_from_console(vc->vc_num); struct fb_info *info = fbcon_info_from_console(vc->vc_num);
struct fbcon_ops *ops = info->fbcon_par; struct fbcon_ops *ops = info->fbcon_par;
@ -1318,12 +1315,12 @@ static void fbcon_cursor(struct vc_data *vc, int mode)
else else
fbcon_add_cursor_work(info); fbcon_add_cursor_work(info);
ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1; ops->cursor_flash = enable;
if (!ops->cursor) if (!ops->cursor)
return; return;
ops->cursor(vc, info, mode, get_color(vc, info, c, 1), ops->cursor(vc, info, enable, get_color(vc, info, c, 1),
get_color(vc, info, c, 0)); get_color(vc, info, c, 0));
} }
@ -1743,7 +1740,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
if (fbcon_is_inactive(vc, info)) if (fbcon_is_inactive(vc, info))
return true; return true;
fbcon_cursor(vc, CM_ERASE); fbcon_cursor(vc, false);
/* /*
* ++Geert: Only use ywrap/ypan if the console is in text mode * ++Geert: Only use ywrap/ypan if the console is in text mode
@ -1759,7 +1756,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
case SCROLL_MOVE: case SCROLL_MOVE:
fbcon_redraw_blit(vc, info, p, t, b - t - count, fbcon_redraw_blit(vc, info, p, t, b - t - count,
count); count);
fbcon_clear(vc, b - count, 0, count, vc->vc_cols); __fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
scr_memsetw((unsigned short *) (vc->vc_origin + scr_memsetw((unsigned short *) (vc->vc_origin +
vc->vc_size_row * vc->vc_size_row *
(b - count)), (b - count)),
@ -1782,7 +1779,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
b - t - count, vc->vc_cols); b - t - count, vc->vc_cols);
else else
goto redraw_up; goto redraw_up;
fbcon_clear(vc, b - count, 0, count, vc->vc_cols); __fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
break; break;
case SCROLL_PAN_REDRAW: case SCROLL_PAN_REDRAW:
@ -1800,7 +1797,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
vc->vc_rows - b, b); vc->vc_rows - b, b);
} else } else
fbcon_redraw_move(vc, p, t + count, b - t - count, t); fbcon_redraw_move(vc, p, t + count, b - t - count, t);
fbcon_clear(vc, b - count, 0, count, vc->vc_cols); __fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
break; break;
case SCROLL_PAN_MOVE: case SCROLL_PAN_MOVE:
@ -1823,14 +1820,14 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
b - t - count, vc->vc_cols); b - t - count, vc->vc_cols);
else else
goto redraw_up; goto redraw_up;
fbcon_clear(vc, b - count, 0, count, vc->vc_cols); __fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
break; break;
case SCROLL_REDRAW: case SCROLL_REDRAW:
redraw_up: redraw_up:
fbcon_redraw(vc, t, b - t - count, fbcon_redraw(vc, t, b - t - count,
count * vc->vc_cols); count * vc->vc_cols);
fbcon_clear(vc, b - count, 0, count, vc->vc_cols); __fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
scr_memsetw((unsigned short *) (vc->vc_origin + scr_memsetw((unsigned short *) (vc->vc_origin +
vc->vc_size_row * vc->vc_size_row *
(b - count)), (b - count)),
@ -1847,7 +1844,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
case SCROLL_MOVE: case SCROLL_MOVE:
fbcon_redraw_blit(vc, info, p, b - 1, b - t - count, fbcon_redraw_blit(vc, info, p, b - 1, b - t - count,
-count); -count);
fbcon_clear(vc, t, 0, count, vc->vc_cols); __fbcon_clear(vc, t, 0, count, vc->vc_cols);
scr_memsetw((unsigned short *) (vc->vc_origin + scr_memsetw((unsigned short *) (vc->vc_origin +
vc->vc_size_row * vc->vc_size_row *
t), t),
@ -1870,7 +1867,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
b - t - count, vc->vc_cols); b - t - count, vc->vc_cols);
else else
goto redraw_down; goto redraw_down;
fbcon_clear(vc, t, 0, count, vc->vc_cols); __fbcon_clear(vc, t, 0, count, vc->vc_cols);
break; break;
case SCROLL_PAN_MOVE: case SCROLL_PAN_MOVE:
@ -1892,7 +1889,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
b - t - count, vc->vc_cols); b - t - count, vc->vc_cols);
else else
goto redraw_down; goto redraw_down;
fbcon_clear(vc, t, 0, count, vc->vc_cols); __fbcon_clear(vc, t, 0, count, vc->vc_cols);
break; break;
case SCROLL_PAN_REDRAW: case SCROLL_PAN_REDRAW:
@ -1909,14 +1906,14 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
fbcon_redraw_move(vc, p, count, t, 0); fbcon_redraw_move(vc, p, count, t, 0);
} else } else
fbcon_redraw_move(vc, p, t, b - t - count, t + count); fbcon_redraw_move(vc, p, t, b - t - count, t + count);
fbcon_clear(vc, t, 0, count, vc->vc_cols); __fbcon_clear(vc, t, 0, count, vc->vc_cols);
break; break;
case SCROLL_REDRAW: case SCROLL_REDRAW:
redraw_down: redraw_down:
fbcon_redraw(vc, b - 1, b - t - count, fbcon_redraw(vc, b - 1, b - t - count,
-count * vc->vc_cols); -count * vc->vc_cols);
fbcon_clear(vc, t, 0, count, vc->vc_cols); __fbcon_clear(vc, t, 0, count, vc->vc_cols);
scr_memsetw((unsigned short *) (vc->vc_origin + scr_memsetw((unsigned short *) (vc->vc_origin +
vc->vc_size_row * vc->vc_size_row *
t), t),
@ -1995,7 +1992,7 @@ static void updatescrollmode(struct fbcon_display *p,
#define CALC_FONTSZ(h, p, c) ((h) * (p) * (c)) /* size = height * pitch * charcount */ #define CALC_FONTSZ(h, p, c) ((h) * (p) * (c)) /* size = height * pitch * charcount */
static int fbcon_resize(struct vc_data *vc, unsigned int width, static int fbcon_resize(struct vc_data *vc, unsigned int width,
unsigned int height, unsigned int user) unsigned int height, bool from_user)
{ {
struct fb_info *info = fbcon_info_from_console(vc->vc_num); struct fb_info *info = fbcon_info_from_console(vc->vc_num);
struct fbcon_ops *ops = info->fbcon_par; struct fbcon_ops *ops = info->fbcon_par;
@ -2058,7 +2055,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
return 0; return 0;
} }
static int fbcon_switch(struct vc_data *vc) static bool fbcon_switch(struct vc_data *vc)
{ {
struct fb_info *info, *old_info = NULL; struct fb_info *info, *old_info = NULL;
struct fbcon_ops *ops; struct fbcon_ops *ops;
@ -2180,9 +2177,9 @@ static int fbcon_switch(struct vc_data *vc)
vc->vc_origin + vc->vc_size_row * vc->vc_top, vc->vc_origin + vc->vc_size_row * vc->vc_top,
vc->vc_size_row * (vc->vc_bottom - vc->vc_size_row * (vc->vc_bottom -
vc->vc_top) / 2); vc->vc_top) / 2);
return 0; return false;
} }
return 1; return true;
} }
static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info, static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info,
@ -2195,12 +2192,13 @@ static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info,
oldc = vc->vc_video_erase_char; oldc = vc->vc_video_erase_char;
vc->vc_video_erase_char &= charmask; vc->vc_video_erase_char &= charmask;
fbcon_clear(vc, 0, 0, vc->vc_rows, vc->vc_cols); __fbcon_clear(vc, 0, 0, vc->vc_rows, vc->vc_cols);
vc->vc_video_erase_char = oldc; vc->vc_video_erase_char = oldc;
} }
} }
static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch) static bool fbcon_blank(struct vc_data *vc, enum vesa_blank_mode blank,
bool mode_switch)
{ {
struct fb_info *info = fbcon_info_from_console(vc->vc_num); struct fb_info *info = fbcon_info_from_console(vc->vc_num);
struct fbcon_ops *ops = info->fbcon_par; struct fbcon_ops *ops = info->fbcon_par;
@ -2222,7 +2220,7 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
if (!fbcon_is_inactive(vc, info)) { if (!fbcon_is_inactive(vc, info)) {
if (ops->blank_state != blank) { if (ops->blank_state != blank) {
ops->blank_state = blank; ops->blank_state = blank;
fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW); fbcon_cursor(vc, !blank);
ops->cursor_flash = (!blank); ops->cursor_flash = (!blank);
if (fb_blank(info, blank)) if (fb_blank(info, blank))
@ -2239,10 +2237,10 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
else else
fbcon_add_cursor_work(info); fbcon_add_cursor_work(info);
return 0; return false;
} }
static int fbcon_debug_enter(struct vc_data *vc) static void fbcon_debug_enter(struct vc_data *vc)
{ {
struct fb_info *info = fbcon_info_from_console(vc->vc_num); struct fb_info *info = fbcon_info_from_console(vc->vc_num);
struct fbcon_ops *ops = info->fbcon_par; struct fbcon_ops *ops = info->fbcon_par;
@ -2252,10 +2250,9 @@ static int fbcon_debug_enter(struct vc_data *vc)
if (info->fbops->fb_debug_enter) if (info->fbops->fb_debug_enter)
info->fbops->fb_debug_enter(info); info->fbops->fb_debug_enter(info);
fbcon_set_palette(vc, color_table); fbcon_set_palette(vc, color_table);
return 0;
} }
static int fbcon_debug_leave(struct vc_data *vc) static void fbcon_debug_leave(struct vc_data *vc)
{ {
struct fb_info *info = fbcon_info_from_console(vc->vc_num); struct fb_info *info = fbcon_info_from_console(vc->vc_num);
struct fbcon_ops *ops = info->fbcon_par; struct fbcon_ops *ops = info->fbcon_par;
@ -2263,7 +2260,6 @@ static int fbcon_debug_leave(struct vc_data *vc)
ops->graphics = ops->save_graphics; ops->graphics = ops->save_graphics;
if (info->fbops->fb_debug_leave) if (info->fbops->fb_debug_leave)
info->fbops->fb_debug_leave(info); info->fbops->fb_debug_leave(info);
return 0;
} }
static int fbcon_get_font(struct vc_data *vc, struct console_font *font, unsigned int vpitch) static int fbcon_get_font(struct vc_data *vc, struct console_font *font, unsigned int vpitch)
@ -2461,7 +2457,7 @@ err_out:
* but lets not assume that, since charcount of 512 is small for unicode support. * but lets not assume that, since charcount of 512 is small for unicode support.
*/ */
static int fbcon_set_font(struct vc_data *vc, struct console_font *font, static int fbcon_set_font(struct vc_data *vc, const struct console_font *font,
unsigned int vpitch, unsigned int flags) unsigned int vpitch, unsigned int flags)
{ {
struct fb_info *info = fbcon_info_from_console(vc->vc_num); struct fb_info *info = fbcon_info_from_console(vc->vc_num);
@ -2534,7 +2530,8 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font,
return fbcon_do_set_font(vc, font->width, font->height, charcount, new_data, 1); return fbcon_do_set_font(vc, font->width, font->height, charcount, new_data, 1);
} }
static int fbcon_set_def_font(struct vc_data *vc, struct console_font *font, char *name) static int fbcon_set_def_font(struct vc_data *vc, struct console_font *font,
const char *name)
{ {
struct fb_info *info = fbcon_info_from_console(vc->vc_num); struct fb_info *info = fbcon_info_from_console(vc->vc_num);
const struct font_desc *f; const struct font_desc *f;
@ -2593,35 +2590,6 @@ static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table)
fb_set_cmap(&palette_cmap, info); fb_set_cmap(&palette_cmap, info);
} }
static u16 *fbcon_screen_pos(const struct vc_data *vc, int offset)
{
return (u16 *) (vc->vc_origin + offset);
}
static unsigned long fbcon_getxy(struct vc_data *vc, unsigned long pos,
int *px, int *py)
{
unsigned long ret;
int x, y;
if (pos >= vc->vc_origin && pos < vc->vc_scr_end) {
unsigned long offset = (pos - vc->vc_origin) / 2;
x = offset % vc->vc_cols;
y = offset / vc->vc_cols;
ret = pos + (vc->vc_cols - x) * 2;
} else {
/* Should not happen */
x = y = 0;
ret = vc->vc_origin;
}
if (px)
*px = x;
if (py)
*py = y;
return ret;
}
/* As we might be inside of softback, we may work with non-contiguous buffer, /* As we might be inside of softback, we may work with non-contiguous buffer,
that's why we have to use a separate routine. */ that's why we have to use a separate routine. */
static void fbcon_invert_region(struct vc_data *vc, u16 * p, int cnt) static void fbcon_invert_region(struct vc_data *vc, u16 * p, int cnt)
@ -2650,7 +2618,7 @@ void fbcon_suspended(struct fb_info *info)
vc = vc_cons[ops->currcon].d; vc = vc_cons[ops->currcon].d;
/* Clear cursor, restore saved data */ /* Clear cursor, restore saved data */
fbcon_cursor(vc, CM_ERASE); fbcon_cursor(vc, false);
} }
void fbcon_resumed(struct fb_info *info) void fbcon_resumed(struct fb_info *info)
@ -3152,7 +3120,6 @@ static const struct consw fb_con = {
.con_init = fbcon_init, .con_init = fbcon_init,
.con_deinit = fbcon_deinit, .con_deinit = fbcon_deinit,
.con_clear = fbcon_clear, .con_clear = fbcon_clear,
.con_putc = fbcon_putc,
.con_putcs = fbcon_putcs, .con_putcs = fbcon_putcs,
.con_cursor = fbcon_cursor, .con_cursor = fbcon_cursor,
.con_scroll = fbcon_scroll, .con_scroll = fbcon_scroll,
@ -3163,8 +3130,6 @@ static const struct consw fb_con = {
.con_font_default = fbcon_set_def_font, .con_font_default = fbcon_set_def_font,
.con_set_palette = fbcon_set_palette, .con_set_palette = fbcon_set_palette,
.con_invert_region = fbcon_invert_region, .con_invert_region = fbcon_invert_region,
.con_screen_pos = fbcon_screen_pos,
.con_getxy = fbcon_getxy,
.con_resize = fbcon_resize, .con_resize = fbcon_resize,
.con_debug_enter = fbcon_debug_enter, .con_debug_enter = fbcon_debug_enter,
.con_debug_leave = fbcon_debug_leave, .con_debug_leave = fbcon_debug_leave,

View File

@ -61,8 +61,8 @@ struct fbcon_ops {
int fg, int bg); int fg, int bg);
void (*clear_margins)(struct vc_data *vc, struct fb_info *info, void (*clear_margins)(struct vc_data *vc, struct fb_info *info,
int color, int bottom_only); int color, int bottom_only);
void (*cursor)(struct vc_data *vc, struct fb_info *info, int mode, void (*cursor)(struct vc_data *vc, struct fb_info *info,
int fg, int bg); bool enable, int fg, int bg);
int (*update_start)(struct fb_info *info); int (*update_start)(struct fb_info *info);
int (*rotate_font)(struct fb_info *info, struct vc_data *vc); int (*rotate_font)(struct fb_info *info, struct vc_data *vc);
struct fb_var_screeninfo var; /* copy of the current fb_var_screeninfo */ struct fb_var_screeninfo var; /* copy of the current fb_var_screeninfo */

View File

@ -218,7 +218,7 @@ static void ccw_clear_margins(struct vc_data *vc, struct fb_info *info,
} }
} }
static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode, static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
int fg, int bg) int fg, int bg)
{ {
struct fb_cursor cursor; struct fb_cursor cursor;
@ -349,16 +349,7 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
kfree(tmp); kfree(tmp);
} }
switch (mode) { ops->cursor_state.enable = enable && !use_sw;
case CM_ERASE:
ops->cursor_state.enable = 0;
break;
case CM_DRAW:
case CM_MOVE:
default:
ops->cursor_state.enable = (use_sw) ? 0 : 1;
break;
}
cursor.image.data = src; cursor.image.data = src;
cursor.image.fg_color = ops->cursor_state.image.fg_color; cursor.image.fg_color = ops->cursor_state.image.fg_color;

View File

@ -201,7 +201,7 @@ static void cw_clear_margins(struct vc_data *vc, struct fb_info *info,
} }
} }
static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode, static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
int fg, int bg) int fg, int bg)
{ {
struct fb_cursor cursor; struct fb_cursor cursor;
@ -332,16 +332,7 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
kfree(tmp); kfree(tmp);
} }
switch (mode) { ops->cursor_state.enable = enable && !use_sw;
case CM_ERASE:
ops->cursor_state.enable = 0;
break;
case CM_DRAW:
case CM_MOVE:
default:
ops->cursor_state.enable = (use_sw) ? 0 : 1;
break;
}
cursor.image.data = src; cursor.image.data = src;
cursor.image.fg_color = ops->cursor_state.image.fg_color; cursor.image.fg_color = ops->cursor_state.image.fg_color;

View File

@ -248,7 +248,7 @@ static void ud_clear_margins(struct vc_data *vc, struct fb_info *info,
} }
} }
static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode, static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
int fg, int bg) int fg, int bg)
{ {
struct fb_cursor cursor; struct fb_cursor cursor;
@ -372,16 +372,7 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode,
mask[i++] = ~msk; mask[i++] = ~msk;
} }
switch (mode) { ops->cursor_state.enable = enable && !use_sw;
case CM_ERASE:
ops->cursor_state.enable = 0;
break;
case CM_DRAW:
case CM_MOVE:
default:
ops->cursor_state.enable = (use_sw) ? 0 : 1;
break;
}
cursor.image.data = src; cursor.image.data = src;
cursor.image.fg_color = ops->cursor_state.image.fg_color; cursor.image.fg_color = ops->cursor_state.image.fg_color;

View File

@ -79,7 +79,7 @@ static void tile_clear_margins(struct vc_data *vc, struct fb_info *info,
return; return;
} }
static void tile_cursor(struct vc_data *vc, struct fb_info *info, int mode, static void tile_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
int fg, int bg) int fg, int bg)
{ {
struct fb_tilecursor cursor; struct fb_tilecursor cursor;
@ -87,7 +87,7 @@ static void tile_cursor(struct vc_data *vc, struct fb_info *info, int mode,
cursor.sx = vc->state.x; cursor.sx = vc->state.x;
cursor.sy = vc->state.y; cursor.sy = vc->state.y;
cursor.mode = (mode == CM_ERASE || use_sw) ? 0 : 1; cursor.mode = enable && !use_sw;
cursor.fg = fg; cursor.fg = fg;
cursor.bg = bg; cursor.bg = bg;

View File

@ -380,7 +380,7 @@ tgafb_set_par(struct fb_info *info)
BT463_LOAD_ADDR(par, 0x0000); BT463_LOAD_ADDR(par, 0x0000);
TGA_WRITE_REG(par, BT463_PALETTE << 2, TGA_RAMDAC_SETUP_REG); TGA_WRITE_REG(par, BT463_PALETTE << 2, TGA_RAMDAC_SETUP_REG);
#ifdef CONFIG_HW_CONSOLE #ifdef CONFIG_VT
for (i = 0; i < 16; i++) { for (i = 0; i < 16; i++) {
int j = color_table[i]; int j = color_table[i];

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