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:
- $ref: serial.yaml#
- $ref: rs485.yaml#
- if:
properties:
compatible:

View File

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

View File

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

View File

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

View File

@ -88,7 +88,7 @@ properties:
TX FIFO threshold configuration (in bytes).
patternProperties:
"^(bluetooth|bluetooth-gnss|gnss|gps|mcu)$":
"^(bluetooth|bluetooth-gnss|gnss|gps|mcu|onewire)$":
if:
type: object
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
power-domains:
maxItems: 1
rx-threshold:
description:
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_ioctl
tty_internals
console
Writing TTY Driver
==================

View File

@ -12,3 +12,4 @@
mxc-w1
omap-hdq
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
* drivers/char/defkeymap.c, as it is autogenerated
*/
#ifdef CONFIG_HW_CONSOLE
#ifdef CONFIG_VT
EXPORT_SYMBOL_GPL(key_maps);
#endif

View File

@ -10,6 +10,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/serial_8250.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/console.h>
@ -67,9 +68,6 @@ static char *hp300_models[] __initdata = {
static char hp300_model_name[13] = "HP9000/";
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)
{
@ -263,7 +261,5 @@ void __init config_hp300(void)
} else {
panic("Unknown HP9000 Model");
}
#ifdef CONFIG_SERIAL_8250_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,
const u8 *data, size_t count)
static size_t btmtkuart_receive_buf(struct serdev_device *serdev,
const u8 *data, size_t count)
{
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 },
};
static ssize_t btnxpuart_receive_buf(struct serdev_device *serdev,
const u8 *data, size_t count)
static size_t btnxpuart_receive_buf(struct serdev_device *serdev,
const u8 *data, size_t count)
{
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
*/
static ssize_t hci_uart_receive_buf(struct serdev_device *serdev,
const u8 *data, size_t count)
static size_t hci_uart_receive_buf(struct serdev_device *serdev,
const u8 *data, size_t count)
{
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,
};
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)
{
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,
};
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)
{
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;
u8 c;
@ -331,8 +331,8 @@ static void hdlc_deinit(struct gb_beagleplay *bg)
flush_work(&bg->tx_work);
}
static ssize_t gb_tty_receive(struct serdev_device *sd, const u8 *data,
size_t count)
static size_t gb_tty_receive(struct serdev_device *sd, const u8 *data,
size_t count)
{
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);
}
static ssize_t pms7003_receive_buf(struct serdev_device *serdev, const u8 *buf,
size_t size)
static size_t pms7003_receive_buf(struct serdev_device *serdev, const u8 *buf,
size_t size)
{
struct iio_dev *indio_dev = serdev_device_get_drvdata(serdev);
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;
}
static ssize_t scd30_serdev_receive_buf(struct serdev_device *serdev,
const u8 *buf, size_t size)
static size_t scd30_serdev_receive_buf(struct serdev_device *serdev,
const u8 *buf, size_t size)
{
struct iio_dev *indio_dev = serdev_device_get_drvdata(serdev);
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;
}
static ssize_t sps30_serial_receive_buf(struct serdev_device *serdev,
const u8 *buf, size_t size)
static size_t sps30_serial_receive_buf(struct serdev_device *serdev,
const u8 *buf, size_t size)
{
struct iio_dev *indio_dev = dev_get_drvdata(&serdev->dev);
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
* 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,
const u8 *buf, size_t size)
static size_t bno055_ser_receive_buf(struct serdev_device *serdev,
const u8 *buf, size_t size)
{
int status;
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_LICENSE("GPL");
#ifdef CONFIG_HW_CONSOLE
#ifdef CONFIG_VT
static unsigned char amikbd_keycode[0x78] __initdata = {
[0] = KEY_GRAVE,
[1] = KEY_1,
@ -148,9 +148,9 @@ static void __init amikbd_init_console_keymaps(void)
memcpy(key_maps[i], temp_map, sizeof(temp_map));
}
}
#else /* !CONFIG_HW_CONSOLE */
#else /* !CONFIG_VT */
static inline void amikbd_init_console_keymaps(void) {}
#endif /* !CONFIG_HW_CONSOLE */
#endif /* !CONFIG_VT */
static const char *amikbd_messages[8] = {
[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);
}
static ssize_t rave_sp_receive_buf(struct serdev_device *serdev,
const u8 *buf, size_t size)
static size_t rave_sp_receive_buf(struct serdev_device *serdev,
const u8 *buf, size_t size)
{
struct device *dev = &serdev->dev;
struct rave_sp *sp = dev_get_drvdata(dev);

View File

@ -45,7 +45,7 @@ struct qcauart {
unsigned char *tx_buffer;
};
static ssize_t
static size_t
qca_tty_receive(struct serdev_device *serdev, const u8 *data, size_t count)
{
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;
}
static ssize_t pn532_receive_buf(struct serdev_device *serdev,
const u8 *data, size_t count)
static size_t pn532_receive_buf(struct serdev_device *serdev,
const u8 *data, size_t count)
{
struct pn532_uart_phy *dev = serdev_device_get_drvdata(serdev);
size_t i;

View File

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

View File

@ -81,8 +81,8 @@ struct cros_ec_uart {
struct response_info response;
};
static ssize_t cros_ec_uart_rx_bytes(struct serdev_device *serdev,
const u8 *data, size_t count)
static size_t cros_ec_uart_rx_bytes(struct serdev_device *serdev,
const u8 *data, size_t count)
{
struct ec_host_response *host_response;
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). ------------------------ */
static ssize_t ssam_receive_buf(struct serdev_device *dev, const u8 *buf,
size_t n)
static size_t ssam_receive_buf(struct serdev_device *dev, const u8 *buf,
size_t n)
{
struct ssam_controller *ctrl;
int ret;

View File

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

View File

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

View File

@ -408,7 +408,7 @@ err_unmap:
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);
@ -424,7 +424,6 @@ static int goldfish_tty_remove(struct platform_device *pdev)
if (goldfish_tty_current_line_count == 0)
goldfish_tty_delete_driver();
mutex_unlock(&goldfish_tty_lock);
return 0;
}
#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 = {
.probe = goldfish_tty_probe,
.remove = goldfish_tty_remove,
.remove_new = goldfish_tty_remove,
.driver = {
.name = "goldfish_tty",
.of_match_table = goldfish_tty_of_match,

View File

@ -1035,6 +1035,10 @@ static const struct attribute_group *hvc_iucv_dev_attr_groups[] = {
NULL,
};
static void hvc_iucv_free(struct device *data)
{
kfree(data);
}
/**
* 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->parent = iucv_root;
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);
if (rc) {
put_device(priv->dev);

View File

@ -431,7 +431,7 @@ static void serdev_drv_remove(struct device *dev)
dev_pm_domain_detach(dev, true);
}
static struct bus_type serdev_bus_type = {
static const struct bus_type serdev_bus_type = {
.name = "serial",
.match = serdev_device_match,
.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 serport *serport = serdev_controller_get_drvdata(ctrl);
int ret;
size_t ret;
if (!test_bit(SERPORT_ACTIVE, &serport->flags))
return 0;
ret = serdev_controller_receive_buf(ctrl, cp, count);
dev_WARN_ONCE(&ctrl->dev, ret < 0 || ret > count,
"receive_buf returns %d (count = %zu)\n",
dev_WARN_ONCE(&ctrl->dev, ret > count,
"receive_buf returns %zu (count = %zu)\n",
ret, count);
if (ret < 0)
return 0;
else if (ret > count)
if (ret > count)
return count;
return ret;

View File

@ -419,8 +419,8 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
struct aspeed_vuart *vuart;
struct device_node *np;
struct resource *res;
u32 clk, prop, sirq[2];
int rc, sirq_polarity;
u32 prop, sirq[2];
struct clk *vclk;
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.dev = &pdev->dev;
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;
rc = sysfs_create_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
if (rc < 0)
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);
if (IS_ERR(vclk)) {
rc = dev_err_probe(dev, PTR_ERR(vclk), "clk or clock-frequency not defined\n");
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 (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.iotype = UPIO_MEM;
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)
port.capabilities = UART_CAP_FIFO;
@ -503,7 +485,7 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
rc = serial8250_register_8250_port(&port);
if (rc < 0)
goto err_clk_disable;
goto err_sysfs_remove;
vuart->line = rc;
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);
if (rc < 0) {
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);
@ -541,14 +523,14 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
rc = aspeed_vuart_set_sirq(vuart, sirq[0]);
if (rc < 0) {
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]);
if (sirq_polarity < 0) {
rc = dev_err_probe(dev, sirq_polarity,
"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);
@ -559,8 +541,6 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
return 0;
err_clk_disable:
irq_dispose_mapping(port.port.irq);
err_sysfs_remove:
sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
return rc;

View File

@ -45,10 +45,6 @@ struct bcm2835aux_data {
u32 cntl;
};
struct bcm2835_aux_serial_driver_data {
resource_size_t offset;
};
static void bcm2835aux_rs485_start_tx(struct uart_8250_port *up)
{
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)
{
const struct bcm2835_aux_serial_driver_data *bcm_data;
const struct software_node *bcm2835_swnode;
struct uart_8250_port up = { };
struct bcm2835aux_data *data;
resource_size_t offset = 0;
struct resource *res;
unsigned int uartclk;
int ret;
@ -101,12 +96,8 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
/* initialize data */
up.capabilities = UART_CAP_FIFO | UART_CAP_MINI;
up.port.dev = &pdev->dev;
up.port.regshift = 2;
up.port.type = PORT_16550;
up.port.iotype = UPIO_MEM;
up.port.fifosize = 8;
up.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE |
UPF_SKIP_TEST | UPF_IOREMAP;
up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SKIP_TEST | UPF_IOREMAP;
up.port.rs485_config = serial8250_em485_config;
up.port.rs485_supported = serial8250_em485_supported;
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))
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 */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
@ -135,52 +120,40 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
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)
* 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.
*/
if (bcm_data)
offset = bcm_data->offset;
bcm2835_swnode = device_get_match_data(&pdev->dev);
if (bcm2835_swnode) {
ret = device_add_software_node(&pdev->dev, bcm2835_swnode);
if (ret)
return ret;
}
up.port.mapbase = res->start + offset;
up.port.mapsize = resource_size(res) - offset;
ret = uart_read_port_properties(&up.port);
if (ret)
goto rm_swnode;
/* Check for a fixed line number */
ret = of_alias_get_id(pdev->dev.of_node, "serial");
if (ret >= 0)
up.port.line = ret;
up.port.regshift = 2;
up.port.fifosize = 8;
/* enable the clock as a last step */
ret = clk_prepare_enable(data->clk);
if (ret) {
dev_err(&pdev->dev, "unable to enable uart clock - %d\n",
ret);
return ret;
dev_err_probe(&pdev->dev, ret, "unable to enable uart clock\n");
goto rm_swnode;
}
uartclk = clk_get_rate(data->clk);
if (!uartclk) {
ret = device_property_read_u32(&pdev->dev, "clock-frequency", &uartclk);
if (ret) {
dev_err_probe(&pdev->dev, ret, "could not get clk rate\n");
goto dis_clk;
}
}
if (uartclk)
up.port.uartclk = uartclk;
/* the HW-clock divider for bcm2835aux is 8,
* but 8250 expects a divider of 16,
* so we have to multiply the actual clock by 2
* to get identical baudrates.
*/
up.port.uartclk = uartclk * 2;
up.port.uartclk *= 2;
/* register the port */
ret = serial8250_register_8250_port(&up);
@ -194,6 +167,8 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
dis_clk:
clk_disable_unprepare(data->clk);
rm_swnode:
device_remove_software_node(&pdev->dev);
return ret;
}
@ -203,10 +178,27 @@ static void bcm2835aux_serial_remove(struct platform_device *pdev)
serial8250_unregister_port(data->line);
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[] = {
@ -216,7 +208,7 @@ static const struct of_device_id bcm2835aux_serial_match[] = {
MODULE_DEVICE_TABLE(of, bcm2835aux_serial_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);

View File

@ -22,6 +22,7 @@
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/debugfs.h>
#include <linux/units.h>
#include "8250.h"
@ -187,21 +188,19 @@
#define TX_BUF_SIZE 4096
#define RX_BUF_SIZE 4096
#define RX_BUFS_COUNT 2
#define KHZ 1000
#define MHZ(x) ((x) * KHZ * KHZ)
static const u32 brcmstb_rate_table[] = {
MHZ(81),
MHZ(108),
MHZ(64), /* Actually 64285715 for some chips */
MHZ(48),
81 * HZ_PER_MHZ,
108 * HZ_PER_MHZ,
64 * HZ_PER_MHZ, /* Actually 64285715 for some chips */
48 * HZ_PER_MHZ,
};
static const u32 brcmstb_rate_table_7278[] = {
MHZ(81),
MHZ(108),
81 * HZ_PER_MHZ,
108 * HZ_PER_MHZ,
0,
MHZ(48),
48 * HZ_PER_MHZ,
};
struct brcmuart_priv {
@ -936,17 +935,14 @@ static void brcmuart_init_debugfs(struct brcmuart_priv *priv,
static int brcmuart_probe(struct platform_device *pdev)
{
struct resource *regs;
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *of_id = NULL;
struct uart_8250_port *new_port;
struct device *dev = &pdev->dev;
struct brcmuart_priv *priv;
struct clk *baud_mux_clk;
struct uart_8250_port up;
int irq;
void __iomem *membase = NULL;
resource_size_t mapbase = 0;
u32 clk_rate = 0;
int ret;
int x;
int dma_irq;
@ -954,15 +950,12 @@ static int brcmuart_probe(struct platform_device *pdev)
"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),
GFP_KERNEL);
if (!priv)
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)
priv->rate_table = brcmstb_rate_table;
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 */
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;
init_real_clk_rates(dev, priv);
clk_rate = priv->default_mux_rate;
up.port.uartclk = priv->default_mux_rate;
} else {
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 */
hrtimer_init(&priv->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
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
* raised, the LCR needs to be rewritten and the uart status register read.
*/
#include <linux/acpi.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
@ -17,7 +16,6 @@
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/notifier.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
@ -56,6 +54,7 @@
#define DW_UART_QUIRK_ARMADA_38X BIT(1)
#define DW_UART_QUIRK_SKIP_SET_RATE BIT(2)
#define DW_UART_QUIRK_IS_DMA_FC BIT(3)
#define DW_UART_QUIRK_APMC0D08 BIT(4)
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)
{
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
if (quirks & DW_UART_QUIRK_OCTEON) {
p->serial_in = dw8250_serial_inq;
p->serial_out = dw8250_serial_outq;
p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
p->type = PORT_OCTEON;
data->skip_autocfg = true;
}
if (quirks & DW_UART_QUIRK_OCTEON) {
p->serial_in = dw8250_serial_inq;
p->serial_out = dw8250_serial_outq;
p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
p->type = PORT_OCTEON;
data->skip_autocfg = true;
}
#endif
if (of_device_is_big_endian(np)) {
p->iotype = UPIO_MEM32BE;
p->serial_in = dw8250_serial_in32be;
p->serial_out = dw8250_serial_out32be;
}
if (quirks & DW_UART_QUIRK_ARMADA_38X)
p->serial_out = dw8250_serial_out38x;
if (quirks & DW_UART_QUIRK_SKIP_SET_RATE)
p->set_termios = dw8250_do_set_termios;
if (quirks & DW_UART_QUIRK_IS_DMA_FC) {
data->data.dma.txconf.device_fc = 1;
data->data.dma.rxconf.device_fc = 1;
data->data.dma.prepare_tx_dma = dw8250_prepare_tx_dma;
data->data.dma.prepare_rx_dma = dw8250_prepare_rx_dma;
}
} else if (acpi_dev_present("APMC0D08", NULL, -1)) {
if (quirks & DW_UART_QUIRK_ARMADA_38X)
p->serial_out = dw8250_serial_out38x;
if (quirks & DW_UART_QUIRK_SKIP_SET_RATE)
p->set_termios = dw8250_do_set_termios;
if (quirks & DW_UART_QUIRK_IS_DMA_FC) {
data->data.dma.txconf.device_fc = 1;
data->data.dma.rxconf.device_fc = 1;
data->data.dma.prepare_tx_dma = dw8250_prepare_tx_dma;
data->data.dma.prepare_rx_dma = dw8250_prepare_rx_dma;
}
if (quirks & DW_UART_QUIRK_APMC0D08) {
p->iotype = UPIO_MEM32;
p->regshift = 2;
p->serial_in = dw8250_serial_in32;
@ -510,39 +494,21 @@ static int dw8250_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct dw8250_data *data;
struct resource *regs;
int irq;
int err;
u32 val;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs)
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);
p->mapbase = regs->start;
p->irq = irq;
p->handle_irq = dw8250_handle_irq;
p->pm = dw8250_do_pm;
p->type = PORT_8250;
p->flags = UPF_SHARE_IRQ | UPF_FIXED_PORT;
p->flags = UPF_FIXED_PORT;
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_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);
if (!data)
return -ENOMEM;
@ -554,15 +520,35 @@ static int dw8250_probe(struct platform_device *pdev)
data->uart_16550_compatible = device_property_read_bool(dev,
"snps,uart-16550-compatible");
err = device_property_read_u32(dev, "reg-shift", &val);
if (!err)
p->regshift = val;
p->mapbase = regs->start;
p->mapsize = resource_size(regs);
err = device_property_read_u32(dev, "reg-io-width", &val);
if (!err && val == 4) {
p->iotype = UPIO_MEM32;
p->membase = devm_ioremap(dev, p->mapbase, p->mapsize);
if (!p->membase)
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_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")) {
@ -589,15 +575,13 @@ static int dw8250_probe(struct platform_device *pdev)
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. */
data->clk = devm_clk_get_optional_enabled(dev, "baudclk");
if (data->clk == NULL)
data->clk = devm_clk_get_optional_enabled(dev, NULL);
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);
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);
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[] = {
{ "80860F0A", (kernel_ulong_t)&dw8250_dw_apb },
{ "8086228A", (kernel_ulong_t)&dw8250_dw_apb },
{ "AMD0020", (kernel_ulong_t)&dw8250_dw_apb },
{ "AMDI0020", (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 },
{ "HISI0031", (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.
*/
#include <linux/acpi.h>
#include <linux/bits.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dmi.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/math.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/pm.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_reg.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/tty.h>
#include <linux/delay.h>
#include <asm/byteorder.h>
#include "8250.h"
#include "8250_pcilib.h"
#define PCI_DEVICE_ID_ACCESSIO_COM_2S 0x1052
#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)
{
const struct exar8250_board *board = priv->board;
unsigned int bar = 0;
unsigned char status;
int err;
port->port.iotype = UPIO_MEM;
port->port.mapbase = pci_resource_start(pcidev, bar) + offset;
port->port.membase = priv->virt + offset;
port->port.regshift = board->reg_shift;
err = serial8250_pci_setup_port(pcidev, port, 0, offset, board->reg_shift);
if (err)
return err;
/*
* 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;
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 ||
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.dev = &pcidev->dev;
/* Clear interrupts */
exar_misc_clear(priv);
rc = devm_request_irq(&pcidev->dev, uart.port.irq, exar_misc_handler,
IRQF_SHARED, "exar_uart", priv);
if (rc)
return rc;
/* Clear interrupts */
exar_misc_clear(priv);
for (i = 0; i < nr_ports && i < maxnr; i++) {
rc = board->setup(priv, pcidev, &uart, i);
if (rc) {
@ -753,28 +758,24 @@ static void exar_pci_remove(struct pci_dev *pcidev)
for (i = 0; i < priv->nr; i++)
serial8250_unregister_port(priv->line[i]);
/* Ensure that every init quirk is properly torn down */
if (priv->board->exit)
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 = pci_get_drvdata(pcidev);
struct exar8250 *priv = dev_get_drvdata(dev);
unsigned int i;
for (i = 0; i < priv->nr; i++)
if (priv->line[i] >= 0)
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;
}
static int __maybe_unused exar_resume(struct device *dev)
static int exar_resume(struct device *dev)
{
struct exar8250 *priv = dev_get_drvdata(dev);
unsigned int i;
@ -788,7 +789,7 @@ static int __maybe_unused exar_resume(struct device *dev)
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 = {
.num_ports = 2,
@ -938,12 +939,13 @@ static struct pci_driver exar_pci_driver = {
.probe = exar_pci_probe,
.remove = exar_pci_remove,
.driver = {
.pm = &exar_pci_pm,
.pm = pm_sleep_ptr(&exar_pci_pm),
},
.id_table = exar_pci_tbl,
};
module_pci_driver(exar_pci_driver);
MODULE_IMPORT_NS(SERIAL_8250_PCI);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Exar Serial Driver");
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;
const struct ingenic_uart_config *cdata;
struct resource *regs;
int irq, err, line;
int err;
cdata = of_device_get_match_data(&pdev->dev);
if (!cdata) {
@ -242,10 +242,6 @@ static int ingenic_uart_probe(struct platform_device *pdev)
return -ENODEV;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs) {
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);
uart.port.type = PORT_16550A;
uart.port.flags = UPF_SKIP_TEST | UPF_IOREMAP | UPF_FIXED_TYPE;
uart.port.iotype = UPIO_MEM;
uart.port.mapbase = regs->start;
uart.port.regshift = 2;
uart.port.serial_out = ingenic_uart_serial_out;
uart.port.serial_in = ingenic_uart_serial_in;
uart.port.irq = irq;
uart.port.dev = &pdev->dev;
uart.port.fifosize = cdata->fifosize;
uart.tx_loadsz = cdata->tx_loadsz;
uart.capabilities = UART_CAP_FIFO | UART_CAP_RTOIE;
/* Check for a fixed line number */
line = of_alias_get_id(pdev->dev.of_node, "serial");
if (line >= 0)
uart.port.line = line;
err = uart_read_port_properties(&uart.port);
if (err)
return err;
uart.port.regshift = 2;
uart.port.fifosize = cdata->fifosize;
uart.port.membase = devm_ioremap(&pdev->dev, regs->start,
resource_size(regs));

View File

@ -92,11 +92,7 @@ static int lpc18xx_serial_probe(struct platform_device *pdev)
struct lpc18xx_uart_data *data;
struct uart_8250_port uart;
struct resource *res;
int irq, ret;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
@ -139,19 +135,12 @@ static int lpc18xx_serial_probe(struct platform_device *pdev)
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.tx_param = data;
spin_lock_init(&uart.port.lock);
uart.port.dev = &pdev->dev;
uart.port.irq = irq;
uart.port.iotype = UPIO_MEM32;
uart.port.mapbase = res->start;
uart.port.regshift = 2;
uart.port.type = PORT_16550A;
uart.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SKIP_TEST;
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.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->rxconf.src_maxburst = 1;
uart.dma->txconf.dst_maxburst = 1;

View File

@ -4,7 +4,10 @@
*
* Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de>, IBM Corp.
*/
#include <linux/bits.h>
#include <linux/console.h>
#include <linux/math.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/serial_core.h>
@ -25,6 +28,36 @@ struct of_serial_info {
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
*/
@ -36,37 +69,22 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
struct device *dev = &ofdev->dev;
struct device_node *np = dev->of_node;
struct uart_port *port = &up->port;
u32 clk, spd, prop;
int ret, irq;
u32 spd;
int ret;
memset(port, 0, sizeof *port);
pm_runtime_enable(&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);
if (ret) {
dev_err_probe(dev, ret, "invalid address\n");
goto err_pmruntime;
}
port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT |
UPF_FIXED_TYPE;
port->dev = &ofdev->dev;
port->flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_FIXED_TYPE;
spin_lock_init(&port->lock);
if (resource_type(&resource) == IORESOURCE_IO) {
@ -75,70 +93,31 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
} else {
port->mapbase = resource.start;
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;
}
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. */
if (of_device_is_compatible(np, "mrvl,mmp-uart"))
port->regshift = 2;
/* Check for registers offset within the devices address range */
if (of_property_read_u32(np, "reg-shift", &prop) == 0)
port->regshift = prop;
/* 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);
if (IS_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;
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_supported = serial8250_em485_supported;
up->rs485_start_tx = serial8250_em485_start_tx;
@ -164,10 +137,17 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
switch (type) {
case PORT_RT2880:
ret = rt288x_setup(port);
if (ret)
goto err_pmruntime;
break;
case PORT_NPCM:
ret = npcm_setup(port);
break;
default:
/* Nothing to do */
ret = 0;
break;
}
if (ret)
goto err_pmruntime;
if (IS_REACHABLE(CONFIG_SERIAL_8250_FSL) &&
(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);
return 0;
err_dispose:
irq_dispose_mapping(port8250.port.irq);
pm_runtime_put_sync(&ofdev->dev);
pm_runtime_disable(&ofdev->dev);
err_free:

View File

@ -1394,11 +1394,7 @@ static int omap8250_probe(struct platform_device *pdev)
struct uart_8250_port up;
struct resource *regs;
void __iomem *membase;
int irq, ret;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
int ret;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs) {
@ -1419,7 +1415,6 @@ static int omap8250_probe(struct platform_device *pdev)
up.port.dev = &pdev->dev;
up.port.mapbase = regs->start;
up.port.membase = membase;
up.port.irq = irq;
/*
* 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
@ -1429,13 +1424,9 @@ static int omap8250_probe(struct platform_device *pdev)
* or pm callback.
*/
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.regshift = OMAP_UART_REGSHIFT;
up.port.fifosize = 64;
up.tx_loadsz = 64;
up.capabilities = UART_CAP_FIFO;
#ifdef CONFIG_PM
@ -1461,14 +1452,14 @@ static int omap8250_probe(struct platform_device *pdev)
up.rs485_stop_tx = serial8250_em485_stop_tx;
up.port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE);
ret = of_alias_get_id(np, "serial");
if (ret < 0) {
dev_err(&pdev->dev, "failed to get alias\n");
ret = uart_read_port_properties(&up.port);
if (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;
clk = devm_clk_get(&pdev->dev, NULL);
@ -1560,8 +1551,8 @@ static int omap8250_probe(struct platform_device *pdev)
}
#endif
irq_set_status_flags(irq, IRQ_NOAUTOEN);
ret = devm_request_irq(&pdev->dev, irq, omap8250_irq, 0,
irq_set_status_flags(up.port.irq, IRQ_NOAUTOEN);
ret = devm_request_irq(&pdev->dev, up.port.irq, omap8250_irq, 0,
dev_name(&pdev->dev), priv);
if (ret < 0)
return ret;

View File

@ -7,23 +7,31 @@
* Copyright (C) 2022 Microchip Technology Inc., All Rights Reserved.
*/
#include <linux/array_size.h>
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/bits.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/iopoll.h>
#include <linux/kernel.h>
#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/overflow.h>
#include <linux/pci.h>
#include <linux/pm.h>
#include <linux/serial_core.h>
#include <linux/serial_reg.h>
#include <linux/serial_8250.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/units.h>
#include <linux/time.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/8250_pci.h>
#include <linux/types.h>
#include <linux/units.h>
#include <asm/byteorder.h>
@ -67,6 +75,7 @@
#define SYSLOCK_RETRY_CNT 1000
#define UART_RX_BYTE_FIFO 0x00
#define UART_TX_BYTE_FIFO 0x00
#define UART_FIFO_CTL 0x02
#define UART_ACTV_REG 0x11
@ -81,10 +90,10 @@
#define ADCL_CFG_PIN_SEL BIT(1)
#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 ADCL_CFG_RTS_DELAY_MASK GENMASK(11, 8)
#define UART_CLOCK_DEFAULT (62500 * HZ_PER_KHZ)
#define UART_WAKE_REG 0x8C
#define UART_WAKE_MASK_REG 0x90
@ -95,13 +104,19 @@
(UART_WAKE_N_PIN | UART_WAKE_NCTS | UART_WAKE_INT)
#define UART_BAUD_CLK_DIVISOR_REG 0x54
#define FRAC_DIV_CFG_REG 0x58
#define UART_RESET_REG 0x94
#define UART_RESET_D3_RESET_DISABLE BIT(16)
#define UART_BURST_STATUS_REG 0x9C
#define UART_TX_BURST_FIFO 0xA0
#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 PORT_OFFSET 0x100
#define RX_BUF_SIZE 512
@ -109,6 +124,7 @@
#define UART_BURST_SIZE 4
#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_LSR_OVERRUN_ERR_CLR 0x43
#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_PARITY_ERR 0x4000000
#define UART_BST_STAT_LSR_FRAME_ERR 0x8000000
#define UART_BST_STAT_LSR_THRE 0x20000000
struct pci1xxxx_8250 {
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,
unsigned int baud, unsigned int *frac)
{
unsigned int uart_sample_cnt;
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.
* Fractional part x denotes x/255 parts of a nanosecond.
*/
quot = NSEC_PER_SEC / (baud * UART_BIT_SAMPLE_CNT);
*frac = (NSEC_PER_SEC - quot * baud * UART_BIT_SAMPLE_CNT) *
255 / UART_BIT_SAMPLE_CNT / baud;
quot = NSEC_PER_SEC / (baud * uart_sample_cnt);
*frac = (NSEC_PER_SEC - quot * baud * uart_sample_cnt) *
255 / uart_sample_cnt / baud;
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,
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,
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 baud_period_in_ns;
u32 mode_cfg = 0;
u32 sample_cnt;
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
@ -249,7 +286,7 @@ static int pci1xxxx_rs485_config(struct uart_port *port,
clock_div = readl(port->membase + UART_BAUD_CLK_DIVISOR_REG);
baud_period_in_ns =
FIELD_GET(BAUD_CLOCK_DIV_INT_MSK, clock_div) *
UART_BIT_SAMPLE_CNT;
sample_cnt;
delay_in_baud_periods =
rs485->delay_rts_after_send * NSEC_PER_MSEC /
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)
{
unsigned long flags;
@ -359,6 +495,9 @@ static int pci1xxxx_handle_irq(struct uart_port *port)
if (status & UART_BST_STAT_LSR_RX_MASK)
pci1xxxx_rx_burst(port, status);
if (status & UART_BST_STAT_LSR_THRE)
pci1xxxx_tx_burst(port, status);
spin_unlock_irqrestore(&port->lock, flags);
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.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.get_divisor = pci1xxxx_get_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));
uart.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT;
uart.port.uartclk = UART_CLOCK_DEFAULT;
uart.port.dev = dev;
if (num_vectors == max_vec_reqd)

View File

@ -38,10 +38,6 @@
#include "8250.h"
/* Nuvoton NPCM timeout register */
#define UART_NPCM_TOR 7
#define UART_NPCM_TOIE BIT(7) /* Timeout Interrupt Enable */
/*
* Debugging.
*/
@ -1329,9 +1325,6 @@ static void autoconfig_irq(struct uart_8250_port *up)
inb_p(ICP);
}
if (uart_console(port))
console_lock();
/* forget possible initially masked and pending IRQ */
probe_irq_off(probe_irq_on());
save_mcr = serial8250_in_MCR(up);
@ -1371,9 +1364,6 @@ static void autoconfig_irq(struct uart_8250_port *up)
if (port->flags & UPF_FOURPORT)
outb_p(save_ICP, ICP);
if (uart_console(port))
console_unlock();
port->irq = (irq > 0) ? irq : 0;
}
@ -2235,15 +2225,6 @@ int serial8250_do_startup(struct uart_port *port)
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
/*
* 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);
}
/* 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,
unsigned int baud,
unsigned int *frac)
@ -2598,8 +2570,6 @@ static unsigned int serial8250_do_get_divisor(struct uart_port *port,
quot = 0x8001;
else if (magic_multiplier && baud >= port->uartclk / 12)
quot = 0x8002;
else if (up->port.type == PORT_NPCM)
quot = npcm_get_divisor(up, baud);
else
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)
{
struct uart_8250_port *up = up_to_u8250p(port);
struct tty_port *tport = &port->state->port;
unsigned int baud, quot, frac = 0;
struct ktermios *termios;
struct tty_struct *tty;
unsigned long flags;
tty = tty_port_tty_get(tport);
if (!tty) {
@ -2740,21 +2706,7 @@ void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk)
if (!tty_port_initialized(tport))
goto out_unlock;
termios = &tty->termios;
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);
serial8250_do_set_termios(port, &tty->termios, NULL);
out_unlock:
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 pxa8250_data *data;
struct resource *mmres;
int irq, ret;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
int ret;
mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mmres)
@ -114,21 +110,21 @@ static int serial_pxa_probe(struct platform_device *pdev)
if (ret)
return ret;
ret = of_alias_get_id(pdev->dev.of_node, "serial");
if (ret >= 0)
uart.port.line = ret;
uart.port.type = PORT_XSCALE;
uart.port.iotype = UPIO_MEM32;
uart.port.mapbase = mmres->start;
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.dev = &pdev->dev;
uart.port.uartclk = clk_get_rate(data->clk);
uart.port.pm = serial_pxa_pm;
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;
ret = serial8250_register_8250_port(&uart);

View File

@ -57,25 +57,11 @@ static int tegra_uart_probe(struct platform_device *pdev)
port = &port8250.port;
spin_lock_init(&port->lock);
port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT |
UPF_FIXED_TYPE;
port->iotype = UPIO_MEM32;
port->regshift = 2;
port->flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_FIXED_TYPE;
port->type = PORT_TEGRA;
port->irqflags |= IRQF_SHARED;
port->dev = &pdev->dev;
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);
if (!res)
return -ENODEV;
@ -88,12 +74,18 @@ static int tegra_uart_probe(struct platform_device *pdev)
port->mapbase = res->start;
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);
if (IS_ERR(uart->rst))
return PTR_ERR(uart->rst);
if (device_property_read_u32(&pdev->dev, "clock-frequency",
&port->uartclk)) {
if (!port->uartclk) {
uart->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(uart->clk)) {
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 resource *regs;
void __iomem *membase;
int irq;
int ret;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@ -175,23 +174,12 @@ static int uniphier_uart_probe(struct platform_device *pdev)
if (!membase)
return -ENOMEM;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
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);
if (IS_ERR(priv->clk)) {
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.mapsize = resource_size(regs);
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.iotype = UPIO_MEM32;

View File

@ -149,6 +149,7 @@ config SERIAL_8250_PCI
config SERIAL_8250_EXAR
tristate "8250/16550 Exar/Commtech PCI/PCIe device support"
depends on SERIAL_8250 && PCI
select SERIAL_8250_PCILIB
default SERIAL_8250
help
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;
}
uart_port_unlock(&uap->port);
sysrq = uart_handle_sysrq_char(&uap->port, ch & 255);
uart_port_lock(&uap->port);
sysrq = uart_prepare_sysrq_char(&uap->port, ch & 255);
if (!sysrq)
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);
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
* 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)
{
struct uart_amba_port *uap = dev_id;
unsigned long flags;
unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
int handled = 0;
uart_port_lock_irqsave(&uap->port, &flags);
uart_port_lock(&uap->port);
status = pl011_read(uap, REG_RIS) & uap->im;
if (status) {
do {
@ -1573,7 +1569,7 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
handled = 1;
}
uart_port_unlock_irqrestore(&uap->port, flags);
uart_unlock_and_check_sysrq(&uap->port);
return IRQ_RETVAL(handled);
}
@ -2322,13 +2318,10 @@ pl011_console_write(struct console *co, const char *s, unsigned int count)
clk_enable(uap->clk);
local_irq_save(flags);
if (uap->port.sysrq)
locked = 0;
else if (oops_in_progress)
locked = uart_port_trylock(&uap->port);
if (oops_in_progress)
locked = uart_port_trylock_irqsave(&uap->port, &flags);
else
uart_port_lock(&uap->port);
uart_port_lock_irqsave(&uap->port, &flags);
/*
* 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);
if (locked)
uart_port_unlock(&uap->port);
local_irq_restore(flags);
uart_port_unlock_irqrestore(&uap->port, flags);
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++;
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;
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);
}
uart_port_unlock(&up->port);
uart_unlock_and_check_sysrq(&up->port);
return IRQ_HANDLED;
}
@ -627,14 +627,10 @@ static void ar933x_uart_console_write(struct console *co, const char *s,
unsigned int int_en;
int locked = 1;
local_irq_save(flags);
if (up->port.sysrq)
locked = 0;
else if (oops_in_progress)
locked = uart_port_trylock(&up->port);
if (oops_in_progress)
locked = uart_port_trylock_irqsave(&up->port, &flags);
else
uart_port_lock(&up->port);
uart_port_lock_irqsave(&up->port, &flags);
/*
* 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);
if (locked)
uart_port_unlock(&up->port);
local_irq_restore(flags);
uart_port_unlock_irqrestore(&up->port, flags);
}
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;
}
if (uart_handle_sysrq_char(port, c))
if (uart_prepare_sysrq_char(port, c))
continue;
if ((cstat & port->ignore_status_mask) == 0)
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);
}
uart_port_unlock(port);
uart_unlock_and_check_sysrq(port);
return IRQ_HANDLED;
}
@ -703,20 +702,14 @@ static void bcm_console_write(struct console *co, const char *s,
{
struct uart_port *port;
unsigned long flags;
int locked;
int locked = 1;
port = &ports[co->index];
local_irq_save(flags);
if (port->sysrq) {
/* bcm_uart_interrupt() already took the lock */
locked = 0;
} else if (oops_in_progress) {
locked = uart_port_trylock(port);
} else {
uart_port_lock(port);
locked = 1;
}
if (oops_in_progress)
locked = uart_port_trylock_irqsave(port, &flags);
else
uart_port_lock_irqsave(port, &flags);
/* call helper to deal with \r\n */
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);
if (locked)
uart_port_unlock(port);
local_irq_restore(flags);
uart_port_unlock_irqrestore(port, flags);
}
/*

View File

@ -837,7 +837,6 @@ static int linflex_probe(struct platform_device *pdev)
return ret;
sport->dev = &pdev->dev;
sport->type = PORT_LINFLEXUART;
sport->iotype = UPIO_MEM;
sport->irq = ret;
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.
*/
if (linestatus & error_mask) {
linestatus = 0;
readb(&ch->ch_cls_uart->txrx);
continue;
}

View File

@ -136,20 +136,16 @@ static void lpc32xx_hsuart_console_write(struct console *co, const char *s,
int locked = 1;
touch_nmi_watchdog();
local_irq_save(flags);
if (up->port.sysrq)
locked = 0;
else if (oops_in_progress)
locked = uart_port_trylock(&up->port);
if (oops_in_progress)
locked = uart_port_trylock_irqsave(&up->port, &flags);
else
uart_port_lock(&up->port);
uart_port_lock_irqsave(&up->port, &flags);
uart_console_write(&up->port, s, count, lpc32xx_hsuart_console_putchar);
wait_for_xmit_empty(&up->port);
if (locked)
uart_port_unlock(&up->port);
local_irq_restore(flags);
uart_port_unlock_irqrestore(&up->port, flags);
}
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++;
}
if (hsu_rate > 0xFF)
hsu_rate = 0xFF;
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, (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));
}
@ -333,7 +328,7 @@ static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id)
__serial_lpc32xx_tx(port);
}
uart_port_unlock(port);
uart_unlock_and_check_sysrq(port);
return IRQ_HANDLED;
}

View File

@ -30,6 +30,7 @@
#define MAX310X_MAJOR 204
#define MAX310X_MINOR 209
#define MAX310X_UART_NRMAX 16
#define MAX310X_MAX_PORTS 4 /* Maximum number of UART ports per IC. */
/* MAX310X register definitions */
#define MAX310X_RHR_REG (0x00) /* RX FIFO */
@ -66,6 +67,7 @@
#define MAX310X_BRGDIVMSB_REG (0x1d) /* Baud rate divisor MSB */
#define MAX310X_CLKSRC_REG (0x1e) /* Clock source */
#define MAX310X_REG_1F (0x1f)
#define MAX310X_EXTREG_START (0x20) /* Only relevant in SPI mode. */
#define MAX310X_REVID_REG MAX310X_REG_1F /* Revision ID */
@ -73,9 +75,9 @@
#define MAX310X_GLOBALCMD_REG MAX310X_REG_1F /* Global Command (WO) */
/* Extended registers */
#define MAX310X_SPI_REVID_EXTREG MAX310X_REG_05 /* Revision ID */
#define MAX310X_I2C_REVID_EXTREG (0x25) /* Revision ID */
#define MAX310X_REVID_EXTREG (0x25) /* Revision ID
* (extended addressing space)
*/
/* IRQ register bits */
#define MAX310X_IRQ_LSR_BIT (1 << 0) /* LSR 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 */
/* Flow control trigger level register masks */
#define MAX310X_FLOWLVL_HALT_MASK (0x000f) /* Flow control halt level */
#define MAX310X_FLOWLVL_RES_MASK (0x00f0) /* Flow control resume level */
#define MAX310X_FLOWLVL_HALT_MASK GENMASK(3, 0) /* Flow control halt level */
#define MAX310X_FLOWLVL_RES_MASK GENMASK(7, 4) /* Flow control resume level */
#define MAX310X_FLOWLVL_HALT(words) ((words / 8) & 0x0f)
#define MAX310X_FLOWLVL_RES(words) (((words / 8) & 0x0f) << 4)
/* FIFO interrupt trigger level register masks */
#define MAX310X_FIFOTRIGLVL_TX_MASK (0x0f) /* TX FIFO trigger level */
#define MAX310X_FIFOTRIGLVL_RX_MASK (0xf0) /* RX FIFO trigger level */
#define MAX310X_FIFOTRIGLVL_TX_MASK GENMASK(3, 0) /* TX 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_RX(words) (((words / 8) & 0x0f) << 4)
@ -177,7 +179,8 @@
#define MAX310X_FLOWCTRL_GPIADDR_BIT (1 << 2) /* Enables that GPIO inputs
* are used in conjunction with
* XOFF2 for definition of
* special character */
* special character
*/
#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_SWFLOW1_BIT (1 << 5) /* SWFLOW bit 1
@ -214,8 +217,8 @@
*/
/* PLL configuration register masks */
#define MAX310X_PLLCFG_PREDIV_MASK (0x3f) /* PLL predivision value */
#define MAX310X_PLLCFG_PLLFACTOR_MASK (0xc0) /* PLL multiplication factor */
#define MAX310X_PLLCFG_PREDIV_MASK GENMASK(5, 0) /* PLL predivision value */
#define MAX310X_PLLCFG_PLLFACTOR_MASK GENMASK(7, 6) /* PLL multiplication factor */
/* Baud rate generator configuration register bits */
#define MAX310X_BRGCFG_2XMODE_BIT (1 << 4) /* Double baud rate */
@ -234,7 +237,7 @@
/* Misc definitions */
#define MAX310X_FIFO_SIZE (128)
#define MAX310x_REV_MASK (0xf8)
#define MAX310x_REV_MASK GENMASK(7, 3)
#define MAX310X_WRITE_BIT 0x80
/* Port startup definitions */
@ -257,20 +260,21 @@
struct max310x_if_cfg {
int (*extended_reg_enable)(struct device *dev, bool enable);
unsigned int rev_id_reg;
u8 rev_id_offset;
};
struct max310x_devtype {
struct {
unsigned short min;
unsigned short max;
} slave_addr;
char name[9];
} slave_addr; /* Relevant only in I2C mode. */
int nr;
char name[9];
u8 mode1;
int (*detect)(struct device *);
void (*power)(struct uart_port *, int);
u8 rev_id_val;
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 {
@ -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);
}
static int max3107_detect(struct device *dev)
static int max310x_detect(struct device *dev)
{
struct max310x_port *s = dev_get_drvdata(dev);
unsigned int val = 0;
int ret;
ret = regmap_read(s->regmap, MAX310X_REVID_REG, &val);
if (ret)
return ret;
/* Check if variant supports REV ID register: */
if (s->devtype->rev_id_val) {
u8 rev_id_reg = s->devtype->rev_id_reg;
if (((val & MAX310x_REV_MASK) != MAX3107_REV_ID)) {
dev_err(dev,
"%s ID 0x%02x does not match\n", s->devtype->name, val);
return -ENODEV;
}
/* Check if REV ID is in extended addressing space: */
if (s->devtype->rev_id_reg >= MAX310X_EXTREG_START) {
ret = s->if_cfg->extended_reg_enable(dev, true);
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)
{
struct max310x_port *s = dev_get_drvdata(dev);
unsigned int val = 0;
int ret;
regmap_read(s->regmap, rev_id_reg, &val);
/* MAX3108 have not REV ID register, we 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;
if (s->devtype->rev_id_reg >= MAX310X_EXTREG_START) {
ret = s->if_cfg->extended_reg_enable(dev, false);
if (ret)
return ret;
}
if (val != (MAX310X_CLKSRC_EXTCLK_BIT | MAX310X_CLKSRC_PLLBYP_BIT)) {
dev_err(dev, "%s not present\n", s->devtype->name);
return -ENODEV;
}
if (((val & MAX310x_REV_MASK) != s->devtype->rev_id_val))
return dev_err_probe(dev, -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;
}
static int max3109_detect(struct device *dev)
{
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;
if (val != (MAX310X_CLKSRC_EXTCLK_BIT | MAX310X_CLKSRC_PLLBYP_BIT))
return dev_err_probe(dev, -ENODEV,
"%s not present\n",
s->devtype->name);
}
return 0;
@ -394,39 +388,10 @@ static int max3109_detect(struct device *dev)
static void max310x_power(struct uart_port *port, int on)
{
max310x_port_update(port, MAX310X_MODE1_REG,
MAX310X_MODE1_FORCESLEEP_BIT,
on ? 0 : MAX310X_MODE1_FORCESLEEP_BIT);
if (on)
msleep(50);
}
struct max310x_port *s = dev_get_drvdata(port->dev);
static int max14830_detect(struct device *dev)
{
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);
max310x_port_update(port, s->devtype->power_reg, s->devtype->power_bit,
on ? 0 : s->devtype->power_bit);
if (on)
msleep(50);
}
@ -435,8 +400,10 @@ static const struct max310x_devtype max3107_devtype = {
.name = "MAX3107",
.nr = 1,
.mode1 = MAX310X_MODE1_AUTOSLEEP_BIT | MAX310X_MODE1_IRQSEL_BIT,
.detect = max3107_detect,
.power = max310x_power,
.rev_id_val = MAX3107_REV_ID,
.rev_id_reg = MAX310X_REVID_REG,
.power_reg = MAX310X_MODE1_REG,
.power_bit = MAX310X_MODE1_FORCESLEEP_BIT,
.slave_addr = {
.min = 0x2c,
.max = 0x2f,
@ -447,8 +414,10 @@ static const struct max310x_devtype max3108_devtype = {
.name = "MAX3108",
.nr = 1,
.mode1 = MAX310X_MODE1_AUTOSLEEP_BIT,
.detect = max3108_detect,
.power = max310x_power,
.rev_id_val = 0, /* Unsupported. */
.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 = {
.min = 0x60,
.max = 0x6f,
@ -459,8 +428,10 @@ static const struct max310x_devtype max3109_devtype = {
.name = "MAX3109",
.nr = 2,
.mode1 = MAX310X_MODE1_AUTOSLEEP_BIT,
.detect = max3109_detect,
.power = max310x_power,
.rev_id_val = MAX3109_REV_ID,
.rev_id_reg = MAX310X_REVID_EXTREG,
.power_reg = MAX310X_MODE1_REG,
.power_bit = MAX310X_MODE1_FORCESLEEP_BIT,
.slave_addr = {
.min = 0x60,
.max = 0x6f,
@ -471,8 +442,10 @@ static const struct max310x_devtype max14830_devtype = {
.name = "MAX14830",
.nr = 4,
.mode1 = MAX310X_MODE1_IRQSEL_BIT,
.detect = max14830_detect,
.power = max14830_power,
.rev_id_val = MAX14830_REV_ID,
.rev_id_reg = MAX310X_REVID_EXTREG,
.power_reg = MAX310X_BRGCFG_REG,
.power_bit = MAX14830_BRGCFG_CLKDIS_BIT,
.slave_addr = {
.min = 0x60,
.max = 0x6f,
@ -490,10 +463,8 @@ static bool max310x_reg_writeable(struct device *dev, unsigned int reg)
case MAX310X_RXFIFOLVL_REG:
return false;
default:
break;
return true;
}
return true;
}
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:
return true;
default:
break;
return false;
}
return false;
}
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:
return true;
default:
break;
return false;
}
return false;
}
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;
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
* 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's also the reason why we cannot do batched reads when
* asked to check the individual statuses.
* */
*/
sts = max310x_port_read(port, MAX310X_LSR_IRQSTS_REG);
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;
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, to_send - until_end);
} else {
@ -848,6 +818,7 @@ static irqreturn_t max310x_port_irq(struct max310x_port *s, int portno)
if (ists & MAX310X_IRQ_TXEMPTY_BIT)
max310x_start_tx(port);
} while (1);
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)
{
/* 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
*/
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_XOFF1_REG, termios->c_cc[VSTOP]);
/* Disable transmitter before enabling AutoCTS or auto transmitter
/*
* Disable transmitter before enabling AutoCTS or auto transmitter
* flow control
*/
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);
/* Enable transmitter after disabling AutoCTS and auto transmitter
/*
* Enable transmitter after disabling AutoCTS and auto transmitter
* flow control
*/
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)
{
struct max310x_port *s = dev_get_drvdata(port->dev);
unsigned int val;
s->devtype->power(port, 1);
max310x_power(port, 1);
/* Configure MODE1 register */
max310x_port_update(port, MAX310X_MODE1_REG,
@ -1103,8 +1076,11 @@ static int max310x_startup(struct uart_port *port)
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_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)
{
struct max310x_port *s = dev_get_drvdata(port->dev);
/* Disable all interrupts */
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)
@ -1187,7 +1161,7 @@ static int __maybe_unused max310x_suspend(struct device *dev)
for (i = 0; i < s->devtype->nr; i++) {
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;
@ -1199,7 +1173,7 @@ static int __maybe_unused max310x_resume(struct device *dev)
int 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);
}
@ -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);
#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;
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)));
}
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 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);
}
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 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,
unsigned offset, int value)
unsigned int offset, int value)
{
struct max310x_port *s = gpiochip_get_data(chip);
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 */
s = devm_kzalloc(dev, struct_size(s, p, devtype->nr), GFP_KERNEL);
if (!s) {
dev_err(dev, "Error allocating port structure\n");
return -ENOMEM;
}
if (!s)
return dev_err_probe(dev, -ENOMEM,
"Error allocating port structure\n");
/* Always ask for fixed clock rate from a property. */
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)
freq = uartclk;
if (freq == 0) {
dev_err(dev, "Cannot get clock rate\n");
ret = -EINVAL;
ret = dev_err_probe(dev, -EINVAL, "Cannot get clock rate\n");
goto out_clk;
}
@ -1345,7 +1317,7 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
dev_set_drvdata(dev, s);
/* Check device to ensure we are talking to what we expect */
ret = devtype->detect(dev);
ret = max310x_detect(dev);
if (ret)
goto out_clk;
@ -1427,14 +1399,13 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
/* Register port */
ret = uart_add_one_port(&max310x_uart, &s->p[i].port);
if (ret) {
s->p[i].port.dev = NULL;
if (ret)
goto out_uart;
}
set_bit(line, max310x_lines);
/* Go to suspend mode */
devtype->power(&s->p[i].port, 0);
max310x_power(&s->p[i].port, 0);
}
#ifdef CONFIG_GPIOLIB
@ -1461,14 +1432,12 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
if (!ret)
return 0;
dev_err(dev, "Unable to reguest IRQ %i\n", irq);
dev_err(dev, "Unable to request IRQ %i\n", irq);
out_uart:
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);
clear_bit(s->p[i].port.line, max310x_lines);
}
}
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].md_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);
s->devtype->power(&s->p[i].port, 0);
if (test_and_clear_bit(s->p[i].port.line, max310x_lines))
uart_remove_one_port(&max310x_uart, &s->p[i].port);
max310x_power(&s->p[i].port, 0);
}
clk_disable_unprepare(s->clk);
@ -1518,6 +1489,19 @@ static struct regmap_config regcfg = {
.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
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 = {
.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)
{
const struct max310x_devtype *devtype;
struct regmap *regmaps[4];
struct regmap *regmaps[MAX310X_MAX_PORTS];
unsigned int i;
int ret;
@ -1547,12 +1531,14 @@ static int max310x_spi_probe(struct spi_device *spi)
if (ret)
return ret;
devtype = device_get_match_data(&spi->dev);
devtype = spi_get_device_match_data(spi);
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++) {
u8 port_mask = i * 0x20;
regcfg.name = max310x_regmap_name(i);
regcfg.read_flag_mask = port_mask;
regcfg.write_flag_mask = port_mask | MAX310X_WRITE_BIT;
regmaps[i] = devm_regmap_init_spi(spi, &regcfg);
@ -1600,7 +1586,7 @@ static struct regmap_config regcfg_i2c = {
.writeable_reg = max310x_reg_writeable,
.volatile_reg = max310x_reg_volatile,
.precious_reg = max310x_reg_precious,
.max_register = MAX310X_I2C_REVID_EXTREG,
.max_register = MAX310X_REVID_EXTREG,
.writeable_noinc_reg = max310x_reg_noinc,
.readable_noinc_reg = max310x_reg_noinc,
.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 = {
.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,
@ -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
* A0 and A1 pins are tied to.
* See Table I2C Address Map of the datasheet.
* Based on that table, the following formulas were determined.
* UART1 - UART0 = 0x10
* UART2 - UART1 = 0x20 + 0x10
* UART3 - UART2 = 0x10
* Based on that table, the following formulas were determined:
* UART1 - UART0 = 0x10
* UART2 - UART1 = 0x20 + 0x10
* UART3 - UART2 = 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)
{
const struct max310x_devtype *devtype =
device_get_match_data(&client->dev);
const struct max310x_devtype *devtype;
struct i2c_client *port_client;
struct regmap *regmaps[4];
struct regmap *regmaps[MAX310X_MAX_PORTS];
unsigned int i;
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 ||
client->addr > devtype->slave_addr.max)
client->addr > devtype->slave_addr.max)
return dev_err_probe(&client->dev, -EINVAL,
"Slave addr 0x%x outside of range [0x%x, 0x%x]\n",
client->addr, devtype->slave_addr.min,
devtype->slave_addr.max);
regcfg_i2c.name = max310x_regmap_name(0);
regmaps[0] = devm_regmap_init_i2c(client, &regcfg_i2c);
for (i = 1; i < devtype->nr; i++) {
@ -1657,6 +1647,7 @@ static int max310x_i2c_probe(struct i2c_client *client)
client->adapter,
port_addr);
regcfg_i2c.name = max310x_regmap_name(i);
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);
}
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 = {
.driver = {
.name = MAX310X_NAME,
@ -1677,6 +1677,7 @@ static struct i2c_driver max310x_i2c_driver = {
},
.probe = max310x_i2c_probe,
.remove = max310x_i2c_remove,
.id_table = max310x_i2c_id_table,
};
#endif

View File

@ -470,33 +470,6 @@ static struct mcf_uart mcf_ports[4];
#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)
{
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;
}
if (uart_handle_sysrq_char(port, ch))
if (uart_prepare_sysrq_char(port, ch))
continue;
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);
}
uart_port_unlock(port);
uart_unlock_and_check_sysrq(port);
return IRQ_HANDLED;
}
@ -556,18 +556,13 @@ static void meson_serial_port_write(struct uart_port *port, const char *s,
u_int count)
{
unsigned long flags;
int locked;
int locked = 1;
u32 val, tmp;
local_irq_save(flags);
if (port->sysrq) {
locked = 0;
} else if (oops_in_progress) {
locked = uart_port_trylock(port);
} else {
uart_port_lock(port);
locked = 1;
}
if (oops_in_progress)
locked = uart_port_trylock_irqsave(port, &flags);
else
uart_port_lock_irqsave(port, &flags);
val = readl(port->membase + AML_UART_CONTROL);
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);
if (locked)
uart_port_unlock(port);
local_irq_restore(flags);
uart_port_unlock_irqrestore(port, flags);
}
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))
flag = TTY_NORMAL;
uart_port_unlock_irqrestore(port, flags);
sysrq = uart_handle_sysrq_char(port, dma->virt[i]);
uart_port_lock_irqsave(port, &flags);
sysrq = uart_prepare_sysrq_char(port, dma->virt[i]);
if (!sysrq)
tty_insert_flip_char(tport, dma->virt[i], flag);
}
msm_start_rx_dma(msm_port);
done:
uart_port_unlock_irqrestore(port, flags);
uart_unlock_and_check_sysrq_irqrestore(port, flags);
if (count)
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))
flag = TTY_NORMAL;
uart_port_unlock(port);
sysrq = uart_handle_sysrq_char(port, buf[i]);
uart_port_lock(port);
sysrq = uart_prepare_sysrq_char(port, buf[i]);
if (!sysrq)
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)
flag = TTY_FRAME;
uart_port_unlock(port);
sysrq = uart_handle_sysrq_char(port, c);
uart_port_lock(port);
sysrq = uart_prepare_sysrq_char(port, c);
if (!sysrq)
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 msm_port *msm_port = to_msm_port(port);
struct msm_dma *dma = &msm_port->rx_dma;
unsigned long flags;
unsigned int misr;
u32 val;
uart_port_lock_irqsave(port, &flags);
uart_port_lock(port);
misr = msm_read(port, MSM_UART_MISR);
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_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;
}
@ -1621,14 +1614,10 @@ static void __msm_console_write(struct uart_port *port, const char *s,
num_newlines++;
count += num_newlines;
local_irq_save(flags);
if (port->sysrq)
locked = 0;
else if (oops_in_progress)
locked = uart_port_trylock(port);
if (oops_in_progress)
locked = uart_port_trylock_irqsave(port, &flags);
else
uart_port_lock(port);
uart_port_lock_irqsave(port, &flags);
if (is_uartdm)
msm_reset_dm_count(port, count);
@ -1667,9 +1656,7 @@ static void __msm_console_write(struct uart_port *port, const char *s,
}
if (locked)
uart_port_unlock(port);
local_irq_restore(flags);
uart_port_unlock_irqrestore(port, flags);
}
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++;
if (uart_handle_sysrq_char(&up->port, ch))
if (uart_prepare_sysrq_char(&up->port, ch))
return;
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--);
uart_port_unlock(&up->port);
uart_unlock_and_check_sysrq(&up->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;
int locked = 1;
local_irq_save(flags);
if (up->port.sysrq)
locked = 0;
else if (oops_in_progress)
locked = uart_port_trylock(&up->port);
if (oops_in_progress)
locked = uart_port_trylock_irqsave(&up->port, &flags);
else
uart_port_lock(&up->port);
uart_port_lock_irqsave(&up->port, &flags);
/*
* 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);
if (locked)
uart_port_unlock(&up->port);
local_irq_restore(flags);
uart_port_unlock_irqrestore(&up->port, flags);
}
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);
while (!(stat & OWL_UART_STAT_RFEM)) {
char flag = TTY_NORMAL;
bool sysrq;
if (stat & OWL_UART_STAT_RXER)
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 &= 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);
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)
{
struct uart_port *port = dev_id;
unsigned long flags;
u32 stat;
uart_port_lock_irqsave(port, &flags);
uart_port_lock(port);
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;
owl_uart_write(port, stat, OWL_UART_STAT);
uart_port_unlock_irqrestore(port, flags);
uart_unlock_and_check_sysrq(port);
return IRQ_HANDLED;
}
@ -508,18 +510,12 @@ static void owl_uart_port_write(struct uart_port *port, const char *s,
{
u32 old_ctl, val;
unsigned long flags;
int locked;
int locked = 1;
local_irq_save(flags);
if (port->sysrq)
locked = 0;
else if (oops_in_progress)
locked = uart_port_trylock(port);
else {
uart_port_lock(port);
locked = 1;
}
if (oops_in_progress)
locked = uart_port_trylock_irqsave(port, &flags);
else
uart_port_lock_irqsave(port, &flags);
old_ctl = owl_uart_read(port, OWL_UART_CTL);
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);
if (locked)
uart_port_unlock(port);
local_irq_restore(flags);
uart_port_unlock_irqrestore(port, flags);
}
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
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))
continue;
}
if (uart_handle_sysrq_char(port, rbr))
if (uart_prepare_sysrq_char(port, rbr))
continue;
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);
}
static int push_rx(struct eg20t_port *priv, const unsigned char *buf,
int size)
static void push_rx(struct eg20t_port *priv, const unsigned char *buf,
int size)
{
struct uart_port *port = &priv->port;
struct tty_port *tport = &port->state->port;
tty_insert_flip_string(tport, buf, size);
tty_flip_buffer_push(tport);
return 0;
}
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;
int rx_size;
int ret;
if (!priv->start_rx) {
pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT |
PCH_UART_HAL_RX_ERR_INT);
@ -770,19 +765,12 @@ static int handle_rx_to(struct eg20t_port *priv)
buf = &priv->rxbuf;
do {
rx_size = pch_uart_hal_read(priv, buf->buf, buf->size);
ret = push_rx(priv, buf->buf, rx_size);
if (ret)
return 0;
push_rx(priv, buf->buf, rx_size);
} while (rx_size == buf->size);
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)
{
struct uart_port *port = &priv->port;
@ -1019,11 +1007,10 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
u8 lsr;
int ret = 0;
unsigned char iid;
unsigned long flags;
int next = 1;
u8 msr;
spin_lock_irqsave(&priv->lock, flags);
uart_port_lock(&priv->port);
handled = 0;
while (next) {
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_ERR_INT);
} else {
ret = handle_rx(priv);
ret = handle_rx_to(priv);
}
break;
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;
}
spin_unlock_irqrestore(&priv->lock, flags);
uart_unlock_and_check_sysrq(&priv->port);
return IRQ_RETVAL(handled);
}
@ -1194,9 +1181,9 @@ static void pch_uart_break_ctl(struct uart_port *port, int ctl)
unsigned long flags;
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);
spin_unlock_irqrestore(&priv->lock, flags);
uart_port_unlock_irqrestore(&priv->port, flags);
}
/* 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);
spin_lock_irqsave(&priv->lock, flags);
uart_port_lock(port);
uart_port_lock_irqsave(port, &flags);
uart_update_timeout(port, termios->c_cflag, baud);
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);
out:
uart_port_unlock(port);
spin_unlock_irqrestore(&priv->lock, flags);
uart_port_unlock_irqrestore(port, flags);
}
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;
unsigned long flags;
int priv_locked = 1;
int port_locked = 1;
int locked = 1;
u8 ier;
priv = pch_uart_ports[co->index];
touch_nmi_watchdog();
local_irq_save(flags);
if (priv->port.sysrq) {
/* call to uart_handle_sysrq_char already took the priv lock */
priv_locked = 0;
/* 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);
}
if (oops_in_progress)
locked = uart_port_trylock_irqsave(&priv->port, &flags);
else
uart_port_lock_irqsave(&priv->port, &flags);
/*
* 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);
iowrite8(ier, priv->membase + UART_IER);
if (port_locked)
uart_port_unlock(&priv->port);
if (priv_locked)
spin_unlock(&priv->lock);
local_irq_restore(flags);
if (locked)
uart_port_unlock_irqrestore(&priv->port, flags);
}
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_set_master(pdev);
spin_lock_init(&priv->lock);
iobase = pci_resource_start(pdev, 0);
mapbase = pci_resource_start(pdev, 1);
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",
priv->port.line);
spin_lock_init(&priv->port.lock);
pci_set_drvdata(pdev, priv);
priv->trigger_level = 1;
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);
}
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);
if (!uap)
return -ENODEV;
uart_remove_one_port(&pmz_uart_reg, &uap->port);
uap->port.dev = NULL;
return 0;
}
#endif /* !CONFIG_PPC_PMAC */
@ -1794,7 +1789,7 @@ static struct macio_driver pmz_driver = {
#else
static struct platform_driver pmz_driver = {
.remove = __exit_p(pmz_detach),
.remove_new = __exit_p(pmz_detach),
.driver = {
.name = "scc",
},

View File

@ -151,7 +151,7 @@ static inline void receive_chars(struct uart_pxa_port *up, int *status)
flag = TTY_FRAME;
}
if (uart_handle_sysrq_char(&up->port, ch))
if (uart_prepare_sysrq_char(&up->port, ch))
goto ignore_char;
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);
if (lsr & UART_LSR_THRE)
transmit_chars(up);
uart_port_unlock(&up->port);
uart_unlock_and_check_sysrq(&up->port);
return IRQ_HANDLED;
}
@ -604,13 +604,10 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
int locked = 1;
clk_enable(up->clk);
local_irq_save(flags);
if (up->port.sysrq)
locked = 0;
else if (oops_in_progress)
locked = uart_port_trylock(&up->port);
if (oops_in_progress)
locked = uart_port_trylock_irqsave(&up->port, &flags);
else
uart_port_lock(&up->port);
uart_port_lock_irqsave(&up->port, &flags);
/*
* 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);
if (locked)
uart_port_unlock(&up->port);
local_irq_restore(flags);
uart_port_unlock_irqrestore(&up->port, flags);
clk_disable(up->clk);
}
#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);
/* Cancel the current write to log the fault */
if (!locked) {
geni_se_cancel_m_cmd(&port->se);
if (!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
M_CMD_CANCEL_EN, true)) {
geni_se_abort_m_cmd(&port->se);
qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
M_CMD_ABORT_EN, true);
writel(M_CMD_ABORT_EN, uport->membase +
SE_GENI_M_IRQ_CLEAR);
}
writel(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
/*
* We can only get here if an oops is in progress then we were
* unable to get the lock. This means we can't safely access
* our state variables like tx_remaining. About the best we
* can do is wait for the FIFO to be empty before we start our
* transfer, so we'll do that.
*/
qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
M_TX_FIFO_NOT_EMPTY_EN, false);
} else if ((geni_status & M_GENI_CMD_ACTIVE) && !port->tx_remaining) {
/*
* 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);
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);
}
}
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;
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);
}
@ -405,10 +406,9 @@ static void rda_uart_receive_chars(struct uart_port *port)
static irqreturn_t rda_interrupt(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
unsigned long flags;
u32 val, irq_mask;
uart_port_lock_irqsave(port, &flags);
uart_port_lock(port);
/* Clear 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);
}
uart_port_unlock_irqrestore(port, flags);
uart_unlock_and_check_sysrq(port);
return IRQ_HANDLED;
}
@ -590,18 +590,12 @@ static void rda_uart_port_write(struct uart_port *port, const char *s,
{
u32 old_irq_mask;
unsigned long flags;
int locked;
int locked = 1;
local_irq_save(flags);
if (port->sysrq) {
locked = 0;
} else if (oops_in_progress) {
locked = uart_port_trylock(port);
} else {
uart_port_lock(port);
locked = 1;
}
if (oops_in_progress)
locked = uart_port_trylock_irqsave(port, &flags);
else
uart_port_lock_irqsave(port, &flags);
old_irq_mask = rda_uart_read(port, 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);
if (locked)
uart_port_unlock(port);
local_irq_restore(flags);
uart_port_unlock_irqrestore(port, flags);
}
static void rda_uart_console_write(struct console *co, const char *s,

View File

@ -21,26 +21,28 @@
* 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/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/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/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>
/* UART name and device definitions */
@ -73,21 +75,21 @@ struct s3c24xx_uart_info {
enum s3c24xx_port_type type;
unsigned int port_type;
unsigned int fifosize;
unsigned long rx_fifomask;
unsigned long rx_fifoshift;
unsigned long rx_fifofull;
unsigned long tx_fifomask;
unsigned long tx_fifoshift;
unsigned long tx_fifofull;
unsigned int def_clk_sel;
unsigned long num_clks;
unsigned long clksel_mask;
unsigned long clksel_shift;
unsigned long ucon_mask;
u32 rx_fifomask;
u32 rx_fifoshift;
u32 rx_fifofull;
u32 tx_fifomask;
u32 tx_fifoshift;
u32 tx_fifofull;
u32 clksel_mask;
u32 clksel_shift;
u32 ucon_mask;
u8 def_clk_sel;
u8 num_clks;
u8 iotype;
/* uart port features */
unsigned int has_divslot:1;
bool has_divslot;
};
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. */
static inline void s3c24xx_set_bit(const struct uart_port *port, int idx,
unsigned int reg)
u32 reg)
{
unsigned long flags;
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,
unsigned int reg)
u32 reg)
{
unsigned long flags;
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;
}
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;
}
@ -242,8 +244,8 @@ static void s3c24xx_serial_rx_enable(struct uart_port *port)
{
struct s3c24xx_uart_port *ourport = to_ourport(port);
unsigned long flags;
unsigned int ucon, ufcon;
int count = 10000;
u32 ucon, ufcon;
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);
unsigned long flags;
unsigned int ucon;
u32 ucon;
uart_port_lock_irqsave(port, &flags);
@ -587,8 +589,8 @@ static inline const struct s3c2410_uartcfg
return ourport->cfg;
}
static int s3c24xx_serial_rx_fifocnt(const struct s3c24xx_uart_port *ourport,
unsigned long ufstat)
static unsigned int
s3c24xx_serial_rx_fifocnt(const struct s3c24xx_uart_port *ourport, u32 ufstat)
{
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)
{
struct uart_port *port = &ourport->port;
unsigned int ucon;
u32 ucon;
/* set Rx mode to DMA mode */
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)
{
struct uart_port *port = &ourport->port;
unsigned int ucon;
u32 ucon;
/* set Rx mode to DMA mode */
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)
{
unsigned int utrstat, received;
struct s3c24xx_uart_port *ourport = dev_id;
struct uart_port *port = &ourport->port;
struct s3c24xx_uart_dma *dma = ourport->dma;
struct tty_struct *tty = tty_port_tty_get(&ourport->port.state->port);
struct tty_port *t = &port->state->port;
struct dma_tx_state state;
unsigned int received;
u32 utrstat;
utrstat = rd_regl(port, S3C2410_UTRSTAT);
rd_regl(port, S3C2410_UFSTAT);
@ -756,9 +759,9 @@ finish:
static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport)
{
struct uart_port *port = &ourport->port;
unsigned int ufcon, ufstat, uerstat;
unsigned int max_count = port->fifosize;
unsigned int fifocnt = 0;
int max_count = port->fifosize;
u32 ufcon, ufstat, uerstat;
u8 ch, flag;
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);
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 (!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 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;
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 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;
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)
{
const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
unsigned long ufstat = rd_regl(port, S3C2410_UFSTAT);
unsigned long ufcon = rd_regl(port, S3C2410_UFCON);
u32 ufstat = rd_regl(port, S3C2410_UFSTAT);
u32 ufcon = rd_regl(port, S3C2410_UFCON);
if (ufcon & S3C2410_UFCON_FIFOMODE) {
if ((ufstat & info->tx_fifomask) != 0 ||
if ((ufstat & info->tx_fifomask) ||
(ufstat & info->tx_fifofull))
return 0;
return 1;
return TIOCSER_TEMT;
}
return s3c24xx_serial_txempty_nofifo(port);
return s3c24xx_serial_txempty_nofifo(port) ? TIOCSER_TEMT : 0;
}
/* no modem control lines */
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)
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)
{
unsigned int umcon = rd_regl(port, S3C2410_UMCON);
unsigned int ucon = rd_regl(port, S3C2410_UCON);
u32 umcon = rd_regl(port, S3C2410_UMCON);
u32 ucon = rd_regl(port, S3C2410_UCON);
if (mctrl & TIOCM_RTS)
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)
{
unsigned long flags;
unsigned int ucon;
u32 ucon;
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);
unsigned int ucon;
u32 ucon;
ucon = rd_regl(port, S3C2410_UCON);
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);
unsigned long flags;
unsigned int ufcon;
u32 ufcon;
int ret;
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);
unsigned long flags;
unsigned int ufcon;
u32 ufcon;
int ret;
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;
}
/* power power management control */
static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
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
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);
unsigned int ucon;
u32 ucon;
if (info->num_clks == 1)
return 0;
@ -1352,11 +1352,10 @@ static inline int s3c24xx_serial_getsource(struct uart_port *port)
return ucon >> info->clksel_shift;
}
static void s3c24xx_serial_setsource(struct uart_port *port,
unsigned int clk_sel)
static void s3c24xx_serial_setsource(struct uart_port *port, u8 clk_sel)
{
const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
unsigned int ucon;
u32 ucon;
if (info->num_clks == 1)
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,
unsigned int req_baud, struct clk **best_clk,
unsigned int *clk_num)
u8 *clk_num)
{
const struct s3c24xx_uart_info *info = ourport->info;
struct clk *clk;
unsigned long rate;
unsigned int cnt, baud, quot, best_quot = 0;
unsigned int baud, quot, best_quot = 0;
char clkname[MAX_CLK_NAME_LENGTH];
int calc_deviation, deviation = (1 << 30) - 1;
u8 cnt;
for (cnt = 0; cnt < info->num_clks; cnt++) {
/* 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 clk *clk = ERR_PTR(-EINVAL);
unsigned long flags;
unsigned int baud, quot, clk_sel = 0;
unsigned int ulcon;
unsigned int umcon;
unsigned int baud, quot;
unsigned int udivslot = 0;
u32 ulcon, umcon;
u8 clk_sel = 0;
/*
* 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 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;
spin_lock_init(&port->lock);
port->iotype = UPIO_MEM;
port->uartclk = 0;
port->fifosize = 16;
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 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);
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;
const struct s3c24xx_uart_info *info = ourport->info;
char clk_name[MAX_CLK_NAME_LENGTH];
unsigned int clk_sel;
struct clk *clk;
int clk_num;
int ret;
u8 clk_sel, clk_num;
clk_sel = ourport->cfg->clk_sel ? : info->def_clk_sel;
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);
break;
case TYPE_APPLE_S5L: {
unsigned int ucon;
u32 ucon;
ucon = rd_regl(port, S3C2410_UCON);
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 s3c24xx_uart_port *ourport;
int index = probe_index;
int ret, prop = 0;
int ret, prop = 0, fifosize_prop = 1;
if (np) {
ret = of_alias_get_id(np, "serial");
@ -1989,9 +1988,11 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
break;
}
ourport->port.iotype = ourport->info->iotype;
if (np) {
of_property_read_u32(np,
"samsung,uart-fifosize", &ourport->port.fifosize);
fifosize_prop = of_property_read_u32(np, "samsung,uart-fifosize",
&ourport->port.fifosize);
if (of_property_read_u32(np, "reg-io-width", &prop) == 0) {
switch (prop) {
@ -2009,10 +2010,13 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
}
}
if (ourport->drv_data->fifosize[index])
ourport->port.fifosize = ourport->drv_data->fifosize[index];
else if (ourport->info->fifosize)
ourport->port.fifosize = ourport->info->fifosize;
if (fifosize_prop) {
if (ourport->drv_data->fifosize[index])
ourport->port.fifosize = ourport->drv_data->fifosize[index];
else if (ourport->info->fifosize)
ourport->port.fifosize = ourport->info->fifosize;
}
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);
if (port) {
if (port)
uart_remove_one_port(&s3c24xx_uart_drv, port);
}
uart_unregister_driver(&s3c24xx_uart_drv);
}
@ -2106,7 +2109,7 @@ static int s3c24xx_serial_resume_noirq(struct device *dev)
/* restore IRQ mask */
switch (ourport->info->type) {
case TYPE_S3C6400: {
unsigned int uintm = 0xf;
u32 uintm = 0xf;
if (ourport->tx_enabled)
uintm &= ~S3C64XX_UINTM_TXD_MSK;
@ -2122,7 +2125,7 @@ static int s3c24xx_serial_resume_noirq(struct device *dev)
break;
}
case TYPE_APPLE_S5L: {
unsigned int ucon;
u32 ucon;
int ret;
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 int
s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon)
static bool
s3c24xx_serial_console_txrdy(struct uart_port *port, u32 ufcon)
{
const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
unsigned long ufstat, utrstat;
u32 ufstat, utrstat;
if (ufcon & S3C2410_UFCON_FIFOMODE) {
/* fifo mode - check amount of data in fifo registers... */
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 */
utrstat = rd_regl(port, S3C2410_UTRSTAT);
return (utrstat & S3C2410_UTRSTAT_TXE) ? 1 : 0;
return utrstat & S3C2410_UTRSTAT_TXE;
}
static bool
s3c24xx_port_configured(unsigned int ucon)
s3c24xx_port_configured(u32 ucon)
{
/* consider the serial port configured if the tx/rx mode set */
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)
{
const struct s3c24xx_uart_port *ourport = to_ourport(port);
unsigned int ufstat;
u32 ufstat;
ufstat = rd_regl(port, S3C2410_UFSTAT);
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,
unsigned char c)
{
unsigned int ufcon = rd_regl(port, S3C2410_UFCON);
unsigned int ucon = rd_regl(port, S3C2410_UCON);
u32 ufcon = rd_regl(port, S3C2410_UFCON);
u32 ucon = rd_regl(port, S3C2410_UCON);
/* not possible to xmit on unconfigured port */
if (!s3c24xx_port_configured(ucon))
@ -2247,7 +2250,7 @@ static void s3c24xx_serial_put_poll_char(struct uart_port *port,
static void
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))
cpu_relax();
@ -2258,7 +2261,7 @@ static void
s3c24xx_serial_console_write(struct console *co, const char *s,
unsigned int count)
{
unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON);
u32 ucon = rd_regl(cons_uart, S3C2410_UCON);
unsigned long flags;
bool locked = true;
@ -2285,12 +2288,10 @@ s3c24xx_serial_get_options(struct uart_port *port, int *baud,
int *parity, int *bits)
{
struct clk *clk;
unsigned int ulcon;
unsigned int ucon;
unsigned int ubrdiv;
unsigned long rate;
unsigned int clk_sel;
u32 ulcon, ucon, ubrdiv;
char clk_name[MAX_CLK_NAME_LENGTH];
u8 clk_sel;
ulcon = rd_regl(port, S3C2410_ULCON);
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",
.type = TYPE_S3C6400,
.port_type = PORT_S3C6400,
.iotype = UPIO_MEM,
.fifosize = 64,
.has_divslot = 1,
.has_divslot = true,
.rx_fifomask = S3C2440_UFSTAT_RXMASK,
.rx_fifoshift = S3C2440_UFSTAT_RXSHIFT,
.rx_fifofull = S3C2440_UFSTAT_RXFULL,
@ -2428,7 +2430,8 @@ static const struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = {
.name = "Samsung S5PV210 UART",
.type = TYPE_S3C6400,
.port_type = PORT_S3C6400,
.has_divslot = 1,
.iotype = UPIO_MEM,
.has_divslot = true,
.rx_fifomask = S5PV210_UFSTAT_RXMASK,
.rx_fifoshift = S5PV210_UFSTAT_RXSHIFT,
.rx_fifofull = S5PV210_UFSTAT_RXFULL,
@ -2452,12 +2455,13 @@ static const struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = {
#endif
#if defined(CONFIG_ARCH_EXYNOS)
#define EXYNOS_COMMON_SERIAL_DRV_DATA() \
#define EXYNOS_COMMON_SERIAL_DRV_DATA \
.info = { \
.name = "Samsung Exynos UART", \
.type = TYPE_S3C6400, \
.port_type = PORT_S3C6400, \
.has_divslot = 1, \
.iotype = UPIO_MEM, \
.has_divslot = true, \
.rx_fifomask = S5PV210_UFSTAT_RXMASK, \
.rx_fifoshift = S5PV210_UFSTAT_RXSHIFT, \
.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 = {
EXYNOS_COMMON_SERIAL_DRV_DATA(),
EXYNOS_COMMON_SERIAL_DRV_DATA,
.fifosize = { 256, 64, 16, 16 },
};
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 },
};
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 },
};
/*
* Common drv_data struct for platforms that specify samsung,uart-fifosize in
* device tree.
*/
static const struct s3c24xx_serial_drv_data exynos_fifoszdt_serial_drv_data = {
EXYNOS_COMMON_SERIAL_DRV_DATA(),
static const struct s3c24xx_serial_drv_data gs101_serial_drv_data = {
.info = {
.name = "Google GS101 UART",
.type = TYPE_S3C6400,
.port_type = PORT_S3C6400,
.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 },
};
#define EXYNOS4210_SERIAL_DRV_DATA (&exynos4210_serial_drv_data)
#define EXYNOS5433_SERIAL_DRV_DATA (&exynos5433_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
#define EXYNOS4210_SERIAL_DRV_DATA NULL
#define EXYNOS5433_SERIAL_DRV_DATA NULL
#define EXYNOS850_SERIAL_DRV_DATA NULL
#define EXYNOS_FIFOSZDT_DRV_DATA NULL
#define GS101_SERIAL_DRV_DATA NULL
#endif
#ifdef CONFIG_ARCH_APPLE
@ -2517,6 +2539,7 @@ static const struct s3c24xx_serial_drv_data s5l_serial_drv_data = {
.name = "Apple S5L UART",
.type = TYPE_APPLE_S5L,
.port_type = PORT_8250,
.iotype = UPIO_MEM,
.fifosize = 16,
.rx_fifomask = S3C2410_UFSTAT_RXMASK,
.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",
.type = TYPE_S3C6400,
.port_type = PORT_S3C6400,
.iotype = UPIO_MEM,
.fifosize = 64,
.has_divslot = 1,
.has_divslot = true,
.rx_fifomask = S5PV210_UFSTAT_RXMASK,
.rx_fifoshift = S5PV210_UFSTAT_RXSHIFT,
.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,
}, {
.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",
.data = ARTPEC8_SERIAL_DRV_DATA },
{ .compatible = "google,gs101-uart",
.data = EXYNOS_FIFOSZDT_DRV_DATA },
.data = GS101_SERIAL_DRV_DATA },
{},
};
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;
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) {
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",
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 */
static int __init apple_s5l_early_console_setup(struct earlycon_device *device,
const char *opt)

View File

@ -41,7 +41,7 @@ static int serial_base_match(struct device *dev, struct device_driver *drv)
return 0;
}
static struct bus_type serial_base_bus_type = {
static const struct bus_type serial_base_bus_type = {
.name = "serial-base",
.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;
flags |= UART_CONFIG_TYPE;
}
/* Synchronize with possible boot console. */
if (uart_console(port))
console_lock();
port->ops->config_port(port, flags);
if (uart_console(port))
console_unlock();
}
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);
/* Synchronize with possible boot console. */
if (uart_console(port))
console_lock();
/* Power up port for set_mctrl() */
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);
if (uart_console(port))
console_unlock();
/*
* If this driver supports console, and it hasn't been
* successfully registered yet, try to re-register it.

View File

@ -8,7 +8,10 @@
#include <linux/device.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
#include <linux/serial_core.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);
/**
* __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 = {
.name = "port",
.suppress_bind_attrs = true,

View File

@ -23,9 +23,10 @@
#include <linux/serial.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/io.h>
#include <asm/txx9/generic.h>
#define PASS_LIMIT 256
#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
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)
new = scr | SCSCR_TDRQE;
else
new = scr & ~SCSCR_TDRQE;
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) &&
@ -599,7 +599,7 @@ static void sci_start_tx(struct uart_port *port)
if (!s->chan_tx || s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE ||
port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
/* 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
@ -609,7 +609,7 @@ static void sci_start_tx(struct uart_port *port)
if (port->type == PORT_SCI)
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;
/* 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)
ctrl &= ~SCSCR_TDRQE;
ctrl &= ~SCSCR_TIE;
serial_port_out(port, SCSCR, ctrl);
sci_serial_out(port, SCSCR, ctrl);
#ifdef CONFIG_SERIAL_SH_SCI_DMA
if (to_sci_port(port)->chan_tx &&
@ -640,41 +640,40 @@ static void sci_start_rx(struct uart_port *port)
{
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)
ctrl &= ~SCSCR_RDRQE;
serial_port_out(port, SCSCR, ctrl);
sci_serial_out(port, SCSCR, ctrl);
}
static void sci_stop_rx(struct uart_port *port)
{
unsigned short ctrl;
ctrl = serial_port_in(port, SCSCR);
ctrl = sci_serial_in(port, SCSCR);
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
ctrl &= ~SCSCR_RDRQE;
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)
{
if (port->type == PORT_SCI) {
/* 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) {
/* SCIFA/SCIFB and SCIF on SH7705/SH7720/SH7721 */
/* Only clear the status bits we want to clear */
serial_port_out(port, SCxSR,
serial_port_in(port, SCxSR) & mask);
sci_serial_out(port, SCxSR, sci_serial_in(port, SCxSR) & mask);
} else {
/* 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;
do {
status = serial_port_in(port, SCxSR);
status = sci_serial_in(port, SCxSR);
if (status & SCxSR_ERRORS(port)) {
sci_clear_SCxSR(port, SCxSR_ERROR_CLEAR(port));
continue;
@ -699,10 +698,10 @@ static int sci_poll_get_char(struct uart_port *port)
if (!(status & SCxSR_RDxF(port)))
return NO_POLL_CHAR;
c = serial_port_in(port, SCxRDR);
c = sci_serial_in(port, SCxRDR);
/* Dummy read */
serial_port_in(port, SCxSR);
sci_serial_in(port, SCxSR);
sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
return c;
@ -714,10 +713,10 @@ static void sci_poll_put_char(struct uart_port *port, unsigned char c)
unsigned short status;
do {
status = serial_port_in(port, SCxSR);
status = sci_serial_in(port, SCxSR);
} 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));
}
#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) {
u16 data = serial_port_in(port, SCPDR);
u16 ctrl = serial_port_in(port, SCPCR);
u16 data = sci_serial_in(port, SCPDR);
u16 ctrl = sci_serial_in(port, SCPCR);
/* Enable RXD and TXD pin functions */
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 */
ctrl &= ~SCPCR_CTSC;
}
serial_port_out(port, SCPDR, data);
serial_port_out(port, SCPCR, ctrl);
sci_serial_out(port, SCPDR, data);
sci_serial_out(port, SCPCR, ctrl);
} 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 */
status |= SCSPTR_RTSIO;
@ -769,7 +768,7 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag)
status &= ~SCSPTR_RTSDT;
/* CTS# and SCK are inputs */
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);
if (reg->size)
return serial_port_in(port, SCTFDR) & fifo_mask;
return sci_serial_in(port, SCTFDR) & fifo_mask;
reg = sci_getreg(port, SCFDR);
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)
@ -803,13 +802,13 @@ static int sci_rxfill(struct uart_port *port)
reg = sci_getreg(port, SCRFDR);
if (reg->size)
return serial_port_in(port, SCRFDR) & fifo_mask;
return sci_serial_in(port, SCRFDR) & fifo_mask;
reg = sci_getreg(port, SCFDR);
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;
int count;
status = serial_port_in(port, SCxSR);
status = sci_serial_in(port, SCxSR);
if (!(status & SCxSR_TDxE(port))) {
ctrl = serial_port_in(port, SCSCR);
ctrl = sci_serial_in(port, SCSCR);
if (uart_circ_empty(xmit))
ctrl &= ~SCSCR_TIE;
else
ctrl |= SCSCR_TIE;
serial_port_out(port, SCSCR, ctrl);
sci_serial_out(port, SCSCR, ctrl);
return;
}
@ -847,15 +846,15 @@ static void sci_transmit_chars(struct uart_port *port)
c = xmit->buf[xmit->tail];
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
} 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;
serial_port_out(port, SCSCR, ctrl);
sci_serial_out(port, SCSCR, ctrl);
return;
} else {
break;
}
serial_port_out(port, SCxTDR, c);
sci_serial_out(port, SCxTDR, c);
port->icount.tx++;
} while (--count > 0);
@ -866,10 +865,10 @@ static void sci_transmit_chars(struct uart_port *port)
uart_write_wakeup(port);
if (uart_circ_empty(xmit)) {
if (port->type == PORT_SCI) {
ctrl = serial_port_in(port, SCSCR);
ctrl = sci_serial_in(port, SCSCR);
ctrl &= ~SCSCR_TIE;
ctrl |= SCSCR_TEIE;
serial_port_out(port, SCSCR, ctrl);
sci_serial_out(port, SCSCR, ctrl);
}
sci_stop_tx(port);
@ -883,7 +882,7 @@ static void sci_receive_chars(struct uart_port *port)
unsigned short status;
unsigned char flag;
status = serial_port_in(port, SCxSR);
status = sci_serial_in(port, SCxSR);
if (!(status & SCxSR_RDxF(port)))
return;
@ -896,7 +895,7 @@ static void sci_receive_chars(struct uart_port *port)
break;
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))
count = 0;
else
@ -907,11 +906,11 @@ static void sci_receive_chars(struct uart_port *port)
if (port->type == PORT_SCIF ||
port->type == PORT_HSCIF) {
status = serial_port_in(port, SCxSR);
c = serial_port_in(port, SCxRDR);
status = sci_serial_in(port, SCxSR);
c = sci_serial_in(port, SCxRDR);
} else {
c = serial_port_in(port, SCxRDR);
status = serial_port_in(port, SCxSR);
c = sci_serial_in(port, SCxRDR);
status = sci_serial_in(port, SCxSR);
}
if (uart_handle_sysrq_char(port, c)) {
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));
copied += count;
@ -944,8 +943,8 @@ static void sci_receive_chars(struct uart_port *port)
tty_flip_buffer_push(tport);
} else {
/* TTY buffers full; read from RX reg to prevent lockup */
serial_port_in(port, SCxRDR);
serial_port_in(port, SCxSR); /* dummy read */
sci_serial_in(port, SCxRDR);
sci_serial_in(port, SCxSR); /* dummy read */
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)
{
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 sci_port *s = to_sci_port(port);
@ -1000,10 +999,10 @@ static int sci_handle_fifo_overrun(struct uart_port *port)
if (!reg->size)
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) {
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++;
@ -1018,7 +1017,7 @@ static int sci_handle_fifo_overrun(struct uart_port *port)
static int sci_handle_breaks(struct uart_port *port)
{
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;
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. */
if (sci_getreg(port, HSRTRGR)->size) {
serial_port_out(port, HSRTRGR, rx_trig);
sci_serial_out(port, HSRTRGR, rx_trig);
return rx_trig;
}
@ -1092,9 +1091,9 @@ static int scif_set_rtrg(struct uart_port *port, int rx_trig)
return 1;
}
serial_port_out(port, SCFCR,
(serial_port_in(port, SCFCR) &
~(SCFCR_RTRG1 | SCFCR_RTRG0)) | bits);
sci_serial_out(port, SCFCR,
(sci_serial_in(port, SCFCR) &
~(SCFCR_RTRG1 | SCFCR_RTRG0)) | bits);
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)
{
if (sci_getreg(port, HSRTRGR)->size)
return serial_port_in(port, HSRTRGR) != 0;
return sci_serial_in(port, HSRTRGR) != 0;
else
return (serial_port_in(port, SCFCR) &
return (sci_serial_in(port, SCFCR) &
(SCFCR_RTRG0 | SCFCR_RTRG1)) != 0;
}
@ -1219,8 +1218,8 @@ static void sci_dma_tx_complete(void *arg)
s->cookie_tx = -EINVAL;
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB ||
s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) {
u16 ctrl = serial_port_in(port, SCSCR);
serial_port_out(port, SCSCR, ctrl & ~SCSCR_TIE);
u16 ctrl = sci_serial_in(port, SCSCR);
sci_serial_out(port, SCSCR, ctrl & ~SCSCR_TIE);
if (s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) {
/* Switch irq from DMA to SCIF */
dmaengine_pause(s->chan_tx_saved);
@ -1296,7 +1295,7 @@ static void sci_dma_rx_reenable_irq(struct sci_port *s)
u16 scr;
/* 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 ||
s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) {
enable_irq(s->irqs[SCIx_RXI_IRQ]);
@ -1305,7 +1304,7 @@ static void sci_dma_rx_reenable_irq(struct sci_port *s)
else
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)
@ -1714,8 +1713,8 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
#ifdef CONFIG_SERIAL_SH_SCI_DMA
if (s->chan_rx) {
u16 scr = serial_port_in(port, SCSCR);
u16 ssr = serial_port_in(port, SCxSR);
u16 scr = sci_serial_in(port, SCSCR);
u16 ssr = sci_serial_in(port, SCxSR);
/* Disable future Rx interrupts */
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;
}
serial_port_out(port, SCSCR, scr);
sci_serial_out(port, SCSCR, scr);
/* Clear current interrupt */
serial_port_out(port, SCxSR,
ssr & ~(SCIF_DR | SCxSR_RDxF(port)));
sci_serial_out(port, SCxSR,
ssr & ~(SCIF_DR | SCxSR_RDxF(port)));
dev_dbg(port->dev, "Rx IRQ %lu: setup t-out in %u us\n",
jiffies, 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);
uart_port_lock_irqsave(port, &flags);
ctrl = serial_port_in(port, SCSCR);
ctrl = sci_serial_in(port, SCSCR);
ctrl &= ~(SCSCR_TE | SCSCR_TEIE);
serial_port_out(port, SCSCR, ctrl);
sci_serial_out(port, SCSCR, ctrl);
uart_port_unlock_irqrestore(port, flags);
return IRQ_HANDLED;
@ -1802,7 +1801,7 @@ static irqreturn_t sci_br_interrupt(int irq, void *ptr)
sci_handle_breaks(port);
/* 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));
@ -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]) {
/* 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 */
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 (sci_handle_errors(port)) {
/* discard character in rx buffer */
serial_port_in(port, SCxSR);
sci_serial_in(port, SCxSR);
sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
}
} else {
@ -1856,12 +1855,12 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
struct sci_port *s = to_sci_port(port);
irqreturn_t ret = IRQ_NONE;
ssr_status = serial_port_in(port, SCxSR);
scr_status = serial_port_in(port, SCSCR);
ssr_status = sci_serial_in(port, SCxSR);
scr_status = sci_serial_in(port, SCSCR);
if (s->params->overrun_reg == SCxSR)
orer_status = ssr_status;
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);
@ -2038,7 +2037,7 @@ static void sci_free_irq(struct sci_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);
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)
{
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 */
if (state)
data &= ~SCPDR_RTSD;
else
data |= SCPDR_RTSD;
serial_port_out(port, SCPDR, data);
sci_serial_out(port, SCPDR, data);
/* RTS# is output */
serial_port_out(port, SCPCR,
serial_port_in(port, SCPCR) | SCPCR_RTSC);
sci_serial_out(port, SCPCR,
sci_serial_in(port, SCPCR) | SCPCR_RTSC);
} else if (sci_getreg(port, SCSPTR)->size) {
u16 ctrl = serial_port_in(port, SCSPTR);
u16 ctrl = sci_serial_in(port, SCSPTR);
/* Active low */
if (state)
ctrl &= ~SCSPTR_RTSDT;
else
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) {
/* 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) {
/* Active low */
return !(serial_port_in(port, SCSPTR) & SCSPTR_CTSDT);
return !(sci_serial_in(port, SCSPTR) & SCSPTR_CTSDT);
}
return true;
@ -2108,9 +2107,8 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
*/
reg = sci_getreg(port, SCFCR);
if (reg->size)
serial_port_out(port, SCFCR,
serial_port_in(port, SCFCR) |
SCFCR_LOOP);
sci_serial_out(port, SCFCR,
sci_serial_in(port, SCFCR) | SCFCR_LOOP);
}
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)) {
/* Disable Auto RTS */
serial_port_out(port, SCFCR,
serial_port_in(port, SCFCR) & ~SCFCR_MCE);
sci_serial_out(port, SCFCR,
sci_serial_in(port, SCFCR) & ~SCFCR_MCE);
/* Clear RTS */
sci_set_rts(port, 0);
} else if (s->autorts) {
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
/* Enable RTS# pin function */
serial_port_out(port, SCPCR,
serial_port_in(port, SCPCR) & ~SCPCR_RTSC);
sci_serial_out(port, SCPCR,
sci_serial_in(port, SCPCR) & ~SCPCR_RTSC);
}
/* Enable Auto RTS */
serial_port_out(port, SCFCR,
serial_port_in(port, SCFCR) | SCFCR_MCE);
sci_serial_out(port, SCFCR,
sci_serial_in(port, SCFCR) | SCFCR_MCE);
} else {
/* Set RTS */
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);
scsptr = serial_port_in(port, SCSPTR);
scscr = serial_port_in(port, SCSCR);
scsptr = sci_serial_in(port, SCSPTR);
scscr = sci_serial_in(port, SCSCR);
if (break_state == -1) {
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;
}
serial_port_out(port, SCSPTR, scsptr);
serial_port_out(port, SCSCR, scscr);
sci_serial_out(port, SCSPTR, scsptr);
sci_serial_out(port, SCSCR, scscr);
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
* and HSCIF TOT bits
*/
scr = serial_port_in(port, SCSCR);
serial_port_out(port, SCSCR, scr &
(SCSCR_CKE1 | SCSCR_CKE0 | s->hscif_tot));
scr = sci_serial_in(port, SCSCR);
sci_serial_out(port, SCSCR,
scr & (SCSCR_CKE1 | SCSCR_CKE0 | s->hscif_tot));
uart_port_unlock_irqrestore(port, flags);
#ifdef CONFIG_SERIAL_SH_SCI_DMA
@ -2390,19 +2388,19 @@ static void sci_reset(struct uart_port *port)
unsigned int status;
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);
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,
SCxSR_RDxF_CLEAR(port) & SCxSR_ERROR_CLEAR(port) &
SCxSR_BREAK_CLEAR(port));
if (sci_getreg(port, SCLSR)->size) {
status = serial_port_in(port, SCLSR);
status = sci_serial_in(port, SCLSR);
status &= ~(SCLSR_TO | SCLSR_ORER);
serial_port_out(port, SCLSR, status);
sci_serial_out(port, SCLSR, status);
}
if (s->rx_trigger > 1) {
@ -2540,8 +2538,8 @@ done:
* It controls the mux to select (H)SCK or frequency divided clock.
*/
if (best_clk >= 0 && sci_getreg(port, SCCKS)->size) {
serial_port_out(port, SCDL, dl);
serial_port_out(port, SCCKS, sccks);
sci_serial_out(port, SCDL, dl);
sci_serial_out(port, SCCKS, sccks);
}
uart_port_lock_irqsave(port, &flags);
@ -2554,7 +2552,7 @@ done:
bits = tty_get_frame_size(termios->c_cflag);
if (sci_getreg(port, SEMR)->size)
serial_port_out(port, SEMR, 0);
sci_serial_out(port, SEMR, 0);
if (best_clk >= 0) {
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
@ -2569,9 +2567,9 @@ done:
case 27: smr_val |= SCSMR_SRC_27; break;
}
smr_val |= cks;
serial_port_out(port, SCSCR, scr_val | s->hscif_tot);
serial_port_out(port, SCSMR, smr_val);
serial_port_out(port, SCBRR, brr);
sci_serial_out(port, SCSCR, scr_val | s->hscif_tot);
sci_serial_out(port, SCSMR, smr_val);
sci_serial_out(port, SCBRR, brr);
if (sci_getreg(port, HSSRR)->size) {
unsigned int hssrr = srr | HSCIF_SRE;
/* Calculate deviation from intended rate at the
@ -2593,7 +2591,7 @@ done:
HSCIF_SRHP_MASK;
hssrr |= HSCIF_SRDE;
}
serial_port_out(port, HSSRR, hssrr);
sci_serial_out(port, HSSRR, hssrr);
}
/* Wait one bit interval */
@ -2601,10 +2599,10 @@ done:
} else {
/* Don't touch the bit rate configuration */
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);
serial_port_out(port, SCSCR, scr_val | s->hscif_tot);
serial_port_out(port, SCSMR, smr_val);
sci_serial_out(port, SCSCR, scr_val | s->hscif_tot);
sci_serial_out(port, SCSMR, smr_val);
}
sci_init_pins(port, termios->c_cflag);
@ -2613,7 +2611,7 @@ done:
s->autorts = false;
reg = sci_getreg(port, SCFCR);
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) &&
(termios->c_cflag & CRTSCTS)) {
@ -2630,7 +2628,7 @@ done:
*/
ctrl &= ~(SCFCR_RFRST | SCFCR_TFRST);
serial_port_out(port, SCFCR, ctrl);
sci_serial_out(port, SCFCR, ctrl);
}
if (port->flags & UPF_HARD_FLOW) {
/* Refresh (Auto) RTS */
@ -2645,7 +2643,7 @@ done:
if (port->type != PORT_SCI)
scr_val |= SCSCR_TE;
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) &&
(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->irqflags = 0;
port->serial_in = sci_serial_in;
port->serial_out = sci_serial_out;
return 0;
}
@ -3056,21 +3051,21 @@ static void serial_console_write(struct console *co, const char *s,
uart_port_lock_irqsave(port, &flags);
/* 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 |
(sci_port->cfg->scscr & ~(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);
/* wait until fifo is empty and last bit has been transmitted */
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();
/* restore the SCSCR */
serial_port_out(port, SCSCR, ctrl);
sci_serial_out(port, SCSCR, ctrl);
if (locked)
uart_port_unlock_irqrestore(port, flags);
@ -3503,8 +3498,6 @@ static int __init early_console_setup(struct earlycon_device *device,
if (!device->port.membase)
return -ENODEV;
device->port.serial_in = sci_serial_in;
device->port.serial_out = sci_serial_out;
device->port.type = type;
memcpy(&sci_ports[0].port, &device->port, sizeof(struct uart_port));
port_cfg.type = type;

View File

@ -412,7 +412,8 @@ static void __ssp_receive_chars(struct sifive_serial_port *ssp)
break;
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);
@ -534,7 +535,7 @@ static irqreturn_t sifive_serial_irq(int irq, void *dev_id)
if (ip & SIFIVE_SERIAL_IP_TXWM_MASK)
__ssp_transmit_chars(ssp);
uart_port_unlock(&ssp->port);
uart_unlock_and_check_sysrq(&ssp->port);
return IRQ_HANDLED;
}
@ -791,13 +792,10 @@ static void sifive_serial_console_write(struct console *co, const char *s,
if (!ssp)
return;
local_irq_save(flags);
if (ssp->port.sysrq)
locked = 0;
else if (oops_in_progress)
locked = uart_port_trylock(&ssp->port);
if (oops_in_progress)
locked = uart_port_trylock_irqsave(&ssp->port, &flags);
else
uart_port_lock(&ssp->port);
uart_port_lock_irqsave(&ssp->port, &flags);
ier = __ssp_readl(ssp, SIFIVE_SERIAL_IE_OFFS);
__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);
if (locked)
uart_port_unlock(&ssp->port);
local_irq_restore(flags);
uart_port_unlock_irqrestore(&ssp->port, flags);
}
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)
{
struct asc_port *ascport = to_asc_port(port);
bool manual_rts, toggle_rts = false;
struct gpio_desc *gpiod;
unsigned int baud;
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 (ascport->rts) {
devm_gpiod_put(port->dev, ascport->rts);
ascport->rts = NULL;
pinctrl_select_state(ascport->pinctrl,
ascport->states[DEFAULT]);
toggle_rts = true;
manual_rts = false;
}
} else {
/* If flow-control disabled, it's safe to handle RTS manually */
if (!ascport->rts && ascport->states[NO_HW_FLOWCTRL]) {
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;
}
}
if (!ascport->rts && ascport->states[NO_HW_FLOWCTRL])
manual_rts = toggle_rts = true;
}
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));
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)

View File

@ -9,6 +9,7 @@
* Inspired by st-asc.c from STMicroelectronics (c)
*/
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/console.h>
#include <linux/delay.h>
@ -39,60 +40,64 @@
/* Register offsets */
static struct stm32_usart_info __maybe_unused stm32f4_info = {
.ofs = {
.isr = 0x00,
.rdr = 0x04,
.tdr = 0x04,
.brr = 0x08,
.cr1 = 0x0c,
.cr2 = 0x10,
.cr3 = 0x14,
.gtpr = 0x18,
.rtor = UNDEF_REG,
.rqr = UNDEF_REG,
.icr = UNDEF_REG,
.isr = 0x00,
.rdr = 0x04,
.tdr = 0x04,
.brr = 0x08,
.cr1 = 0x0c,
.cr2 = 0x10,
.cr3 = 0x14,
.gtpr = 0x18,
.rtor = UNDEF_REG,
.rqr = UNDEF_REG,
.icr = UNDEF_REG,
.presc = UNDEF_REG,
.hwcfgr1 = UNDEF_REG,
},
.cfg = {
.uart_enable_bit = 13,
.has_7bits_data = false,
.fifosize = 1,
}
};
static struct stm32_usart_info __maybe_unused stm32f7_info = {
.ofs = {
.cr1 = 0x00,
.cr2 = 0x04,
.cr3 = 0x08,
.brr = 0x0c,
.gtpr = 0x10,
.rtor = 0x14,
.rqr = 0x18,
.isr = 0x1c,
.icr = 0x20,
.rdr = 0x24,
.tdr = 0x28,
.cr1 = 0x00,
.cr2 = 0x04,
.cr3 = 0x08,
.brr = 0x0c,
.gtpr = 0x10,
.rtor = 0x14,
.rqr = 0x18,
.isr = 0x1c,
.icr = 0x20,
.rdr = 0x24,
.tdr = 0x28,
.presc = UNDEF_REG,
.hwcfgr1 = UNDEF_REG,
},
.cfg = {
.uart_enable_bit = 0,
.has_7bits_data = true,
.has_swap = true,
.fifosize = 1,
}
};
static struct stm32_usart_info __maybe_unused stm32h7_info = {
.ofs = {
.cr1 = 0x00,
.cr2 = 0x04,
.cr3 = 0x08,
.brr = 0x0c,
.gtpr = 0x10,
.rtor = 0x14,
.rqr = 0x18,
.isr = 0x1c,
.icr = 0x20,
.rdr = 0x24,
.tdr = 0x28,
.cr1 = 0x00,
.cr2 = 0x04,
.cr3 = 0x08,
.brr = 0x0c,
.gtpr = 0x10,
.rtor = 0x14,
.rqr = 0x18,
.isr = 0x1c,
.icr = 0x20,
.rdr = 0x24,
.tdr = 0x28,
.presc = 0x2c,
.hwcfgr1 = 0x3f0,
},
.cfg = {
.uart_enable_bit = 0,
@ -100,7 +105,6 @@ static struct stm32_usart_info __maybe_unused stm32h7_info = {
.has_swap = true,
.has_wakeup = true,
.has_fifo = true,
.fifosize = 16,
}
};
@ -1147,6 +1151,8 @@ static void stm32_usart_shutdown(struct uart_port *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,
struct ktermios *termios,
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_config *cfg = &stm32_port->info->cfg;
struct serial_rs485 *rs485conf = &port->rs485;
unsigned int baud, bits;
unsigned int baud, bits, uart_clk, uart_clk_pres;
u32 usartdiv, mantissa, fraction, oversampling;
tcflag_t cflag = termios->c_cflag;
u32 cr1, cr2, cr3, isr;
u32 cr1, cr2, cr3, isr, brr, presc;
unsigned long flags;
int ret;
if (!stm32_port->hw_flow_control)
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);
@ -1267,27 +1275,48 @@ static void stm32_usart_set_termios(struct uart_port *port,
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.
* By default we prefer 16 times oversampling, so that the receiver
* has a better tolerance to clock deviations.
* 8 times oversampling is only used to achieve higher speeds.
*/
if (usartdiv < 16) {
oversampling = 8;
cr1 |= USART_CR1_OVER8;
stm32_usart_set_bits(port, ofs->cr1, USART_CR1_OVER8);
} else {
oversampling = 16;
cr1 &= ~USART_CR1_OVER8;
stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_OVER8);
/*
* The USART supports 16 or 8 times oversampling.
* By default we prefer 16 times oversampling, so that the receiver
* has a better tolerance to clock deviations.
* 8 times oversampling is only used to achieve higher speeds.
*/
if (usartdiv < 16) {
oversampling = 8;
cr1 |= USART_CR1_OVER8;
stm32_usart_set_bits(port, ofs->cr1, USART_CR1_OVER8);
} else {
oversampling = 16;
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;
fraction = usartdiv % oversampling;
writel_relaxed(mantissa | fraction, port->membase + ofs->brr);
writel_relaxed(brr, port->membase + ofs->brr);
uart_update_timeout(port, cflag, baud);
@ -1471,37 +1500,57 @@ static const struct uart_ops stm32_uart_ops = {
#endif /* CONFIG_CONSOLE_POLL */
};
/*
* STM32H7 RX & TX FIFO threshold configuration (CR3 RXFTCFG / TXFTCFG)
* Note: 1 isn't a valid value in RXFTCFG / TXFTCFG. In this case,
* 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 };
struct stm32_usart_thresh_ratio {
int mul;
int div;
};
static void stm32_usart_get_ftcfg(struct platform_device *pdev, const char *p,
int *ftcfg)
static const struct stm32_usart_thresh_ratio stm32h7_usart_fifo_thresh_cfg[] = {
{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))
bytes = 8;
bytes = fifo_size / 2;
for (i = 0; i < ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg); i++)
if (stm32h7_usart_fifo_thresh_cfg[i] >= bytes)
if (bytes < stm32_usart_get_thresh_value(fifo_size, 0)) {
*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;
}
if (i >= ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg))
i = ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg) - 1;
dev_dbg(&pdev->dev, "%s set to %d bytes\n", p,
stm32h7_usart_fifo_thresh_cfg[i]);
dev_dbg(&pdev->dev, "%s set to %d/%d bytes\n", p,
stm32_usart_get_thresh_value(fifo_size, i), fifo_size);
/* Provide FIFO threshold ftcfg (1 is invalid: threshold irq unused) */
if (i)
*ftcfg = i - 1;
else
*ftcfg = -EINVAL;
*ftcfg = i;
return fifo_size;
}
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->ops = &stm32_uart_ops;
port->dev = &pdev->dev;
port->fifosize = stm32port->info->cfg.fifosize;
port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_STM32_CONSOLE);
port->irq = irq;
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 &&
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);
if (IS_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;
}
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);
if (IS_ERR(stm32port->gpios)) {
ret = PTR_ERR(stm32port->gpios);

View File

@ -9,17 +9,19 @@
#define DRIVER_NAME "stm32-usart"
struct stm32_usart_offsets {
u8 cr1;
u8 cr2;
u8 cr3;
u8 brr;
u8 gtpr;
u8 rtor;
u8 rqr;
u8 isr;
u8 icr;
u8 rdr;
u8 tdr;
u16 cr1;
u16 cr2;
u16 cr3;
u16 brr;
u16 gtpr;
u16 rtor;
u16 rqr;
u16 isr;
u16 icr;
u16 rdr;
u16 tdr;
u16 presc;
u16 hwcfgr1;
};
struct stm32_usart_config {
@ -28,7 +30,6 @@ struct stm32_usart_config {
bool has_swap;
bool has_wakeup;
bool has_fifo;
int fifosize;
};
struct stm32_usart_info {
@ -36,7 +37,7 @@ struct stm32_usart_info {
struct stm32_usart_config cfg;
};
#define UNDEF_REG 0xff
#define UNDEF_REG 0xffff
/* USART_SR (F4) / USART_ISR (F7) */
#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_SHIFT 4
#define USART_BRR_04_R_SHIFT 1
#define USART_BRR_MASK (USART_BRR_DIV_M_MASK | USART_BRR_DIV_F_MASK)
/* USART_CR1 */
#define USART_CR1_SBK BIT(0)
@ -176,8 +178,16 @@ struct stm32_usart_info {
#define USART_ICR_CMCF BIT(17) /* F7 */
#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_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_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)
goto ignore_char;
if (uart_handle_sysrq_char(port, ch))
if (uart_prepare_sysrq_char(port, ch))
goto ignore_char;
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)
transmit_chars(port);
uart_port_unlock(port);
uart_unlock_and_check_sysrq(port);
return IRQ_HANDLED;
}
@ -512,22 +512,16 @@ static void sunplus_console_write(struct console *co,
unsigned long flags;
int locked = 1;
local_irq_save(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);
if (oops_in_progress)
locked = uart_port_trylock_irqsave(&sunplus_console_ports[co->index]->port, &flags);
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,
sunplus_uart_console_putchar);
if (locked)
uart_port_unlock(&sunplus_console_ports[co->index]->port);
local_irq_restore(flags);
uart_port_unlock_irqrestore(&sunplus_console_ports[co->index]->port, flags);
}
static int __init sunplus_console_setup(struct console *co, char *options)

View File

@ -22,7 +22,9 @@
#include <linux/of.h>
#include <linux/module.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_NAME "xuartps"
@ -193,6 +195,9 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
* @clk_rate_change_nb: Notifier block for clock changes
* @quirks: Flags for RXBS support.
* @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 uart_port *port;
@ -203,10 +208,21 @@ struct cdns_uart {
struct notifier_block clk_rate_change_nb;
u32 quirks;
bool cts_override;
struct gpio_desc *gpiod_rts;
bool rs485_tx_started;
struct hrtimer tx_timer;
};
struct cdns_platform_data {
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, \
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
* Return: None
*/
static void cdns_uart_handle_tx(void *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;
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);
return;
}
@ -332,6 +445,16 @@ static void cdns_uart_handle_tx(void *dev_id)
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
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
/**
* 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
* @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)
{
unsigned int status;
struct cdns_uart *cdns_uart = port->private_data;
if (uart_tx_stopped(port))
return;
@ -587,12 +726,19 @@ static void cdns_uart_start_tx(struct uart_port *port)
if (uart_circ_empty(&port->state->xmit))
return;
/* Clear the TX Empty interrupt */
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);
/* 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)
{
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 |= 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);
}
/**
* 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
* transmitting char breaks
@ -829,6 +964,9 @@ static int cdns_uart_startup(struct uart_port *port)
(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
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
* the receiver.
@ -888,6 +1026,10 @@ static void cdns_uart_shutdown(struct uart_port *port)
{
int status;
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);
@ -1033,6 +1175,8 @@ static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
if (mctrl & TIOCM_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)
val |= CDNS_UART_MODEMCR_DTR;
if (mctrl & TIOCM_LOOP)
@ -1455,6 +1599,39 @@ MODULE_DEVICE_TABLE(of, cdns_uart_of_match);
/* Temporary variable for storing number of 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
* @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->read_status_mask = CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_RXTRIG |
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;
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_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT);
pm_runtime_set_active(&pdev->dev);
@ -1618,6 +1809,8 @@ static int cdns_uart_probe(struct platform_device *pdev)
console_port = port;
}
#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);
if (rc) {
@ -1646,6 +1839,7 @@ err_out_pm_disable:
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
err_out_clk_notifier:
#ifdef CONFIG_COMMON_CLK
clk_notifier_unregister(cdns_uart_data->uartclk,
&cdns_uart_data->clk_rate_change_nb);

View File

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

View File

@ -5,9 +5,9 @@
FONTMAPFILE = cp437.uni
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_HW_CONSOLE) += vt.o defkeymap.o
# Files generated that shall be removed upon make clean
clean-files := consolemap_deftbl.c defkeymap.c

View File

@ -7,7 +7,7 @@
* 'int set_selection_kernel(struct tiocl_selection *, struct tty_struct *)'
* 'void clear_selection(void)'
* '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.
*/
@ -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
* holding the selection. The caller must hold the console lock.
* Remove the current selection highlight, if any from the console holding the
* selection.
*
* Locking: The caller must hold the console lock.
*/
void clear_selection(void)
{
@ -88,7 +90,7 @@ void clear_selection(void)
}
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;
}
@ -110,18 +112,25 @@ static inline int inword(const u32 c)
}
/**
* sel_loadlut() - load the LUT table
* @p: user table
* sel_loadlut() - load the LUT table
* @lut: user table
*
* Load the LUT table from user space. The caller must hold the console
* lock. Make a temporary copy so a partial update doesn't make a mess.
* Load the LUT table from user space. Make a temporary copy so a partial
* 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)];
if (copy_from_user(tmplut, (u32 __user *)(p+4), sizeof(inwordLut)))
if (copy_from_user(tmplut, lut, sizeof(inwordLut)))
return -EFAULT;
console_lock();
memcpy(inwordLut, tmplut, sizeof(inwordLut));
console_unlock();
return 0;
}
@ -166,14 +175,14 @@ static int store_utf8(u32 c, char *p)
}
/**
* set_selection_user - set the current selection.
* @sel: user selection info
* @tty: the console tty
* set_selection_user - set the current selection.
* @sel: user selection info
* @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
* a lot under the lock but its hardly a performance path
* Locking: The entire selection process is managed under the console_lock.
* It's a lot under the lock but its hardly a performance path.
*/
int set_selection_user(const struct tiocl_selection __user *sel,
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;
if (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);
ret = __vc_resize(vcp, v.v_cols, v.v_rows, true);
if (ret) {
vcp->vc_scan_lines = save_scan_lines;
vcp->vc_cell_height = save_cell_height;
@ -923,9 +922,8 @@ int vt_ioctl(struct tty_struct *tty,
vc = vc_cons[i].d;
if (vc) {
vc->vc_resize_user = 1;
/* FIXME: review v tty lock */
vc_resize(vc_cons[i].d, cc, ll);
__vc_resize(vc_cons[i].d, cc, ll, true);
}
}
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);
}
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();
@ -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);
}
static void dummycon_putcs(struct vc_data *vc, const unsigned short *s,
int count, int ypos, int xpos)
static void dummycon_putcs(struct vc_data *vc, const u16 *s, unsigned int count,
unsigned int ypos, unsigned int xpos)
{
int i;
unsigned int i;
if (!dummycon_putc_called) {
/* 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);
}
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 */
return 1;
return true;
}
#else
static void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos) { }
static void dummycon_putcs(struct vc_data *vc, const unsigned short *s,
int count, int ypos, int xpos) { }
static int dummycon_blank(struct vc_data *vc, int blank, int mode_switch)
static void dummycon_putc(struct vc_data *vc, u16 c, unsigned int y,
unsigned int x) { }
static void dummycon_putcs(struct vc_data *vc, const u16 *s, unsigned int count,
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
@ -98,7 +102,7 @@ static const char *dummycon_startup(void)
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;
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_clear(struct vc_data *vc, int sy, int sx, int height,
int width) { }
static void dummycon_cursor(struct vc_data *vc, int mode) { }
static void dummycon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
unsigned int width) { }
static void dummycon_cursor(struct vc_data *vc, bool enable) { }
static bool dummycon_scroll(struct vc_data *vc, unsigned int top,
unsigned int bottom, enum con_scroll dir,
@ -120,9 +124,9 @@ static bool dummycon_scroll(struct vc_data *vc, unsigned int top,
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";
}
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_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;
}
static void mdacon_putc(struct vc_data *c, int ch, int y, 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)
static void mdacon_putcs(struct vc_data *c, const u16 *s, unsigned int count,
unsigned int y, unsigned int x)
{
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,
int height, int width)
static void mdacon_clear(struct vc_data *c, unsigned int y, unsigned int x,
unsigned int width)
{
u16 *dest = mda_addr(x, y);
u16 eattr = mda_convert_attr(c->vc_video_erase_char);
if (width <= 0 || height <= 0)
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);
}
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 (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),
c->vc_screenbuf_size);
/* Tell console.c that it has to restore the screen itself */
return 1;
return true;
} else {
if (blank)
outb_p(0x00, mda_mode_port); /* disable video */
else
outb_p(MDA_MODE_VIDEO_EN | MDA_MODE_BLINK_EN,
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);
return;
}
@ -544,7 +532,6 @@ static const struct consw mda_con = {
.con_init = mdacon_init,
.con_deinit = mdacon_deinit,
.con_clear = mdacon_clear,
.con_putc = mdacon_putc,
.con_putcs = mdacon_putcs,
.con_cursor = mdacon_cursor,
.con_scroll = mdacon_scroll,

View File

@ -324,7 +324,7 @@ out_unmap:
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;
@ -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,
int width)
static void newport_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
unsigned int width)
{
int xend = ((sx + width) << 3) - 1;
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)
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,
int xpos)
static void newport_putc(struct vc_data *vc, u16 charattr, unsigned int ypos,
unsigned int xpos)
{
unsigned char *p;
@ -396,12 +396,13 @@ static void newport_putc(struct vc_data *vc, int charattr, int ypos,
RENDER(npregs, p);
}
static void newport_putcs(struct vc_data *vc, const unsigned short *s,
int count, int ypos, int xpos)
static void newport_putcs(struct vc_data *vc, const u16 *s,
unsigned int count, unsigned int ypos,
unsigned int xpos)
{
int i;
int charattr;
unsigned char *p;
unsigned int i;
u16 charattr;
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;
int xcurs, ycurs;
switch (mode) {
case CM_ERASE:
treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
if (!enable) {
newport_vc2_set(npregs, VC2_IREG_CONTROL,
(treg & ~(VC2_CTRL_ECDISP)));
break;
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);
return;
}
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;
@ -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;
if (blank == 0) {
if (blank == VESA_NO_BLANKING) {
/* unblank console */
treg = newport_vc2_get(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,
(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 h = op->height;
@ -564,12 +564,13 @@ static int newport_set_def_font(int unit, struct console_font *op)
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);
}
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)
{
return newport_set_font(vc->vc_num, font, vpitch);

View File

@ -71,19 +71,8 @@ static const char *sticon_startup(void)
return "STI console";
}
static void sticon_putc(struct vc_data *conp, int c, int ypos, 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)
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;
@ -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;
@ -106,23 +95,20 @@ static void sticon_cursor(struct vc_data *conp, int mode)
return;
car1 = conp->vc_screenbuf[conp->state.x + conp->state.y * conp->vc_cols];
switch (mode) {
case CM_ERASE:
if (!enable) {
sti_putc(sticon_sti, car1, conp->state.y, conp->state.x,
font_data[conp->vc_num]);
break;
case CM_MOVE:
case CM_DRAW:
switch (CUR_SIZE(conp->vc_cursor_type)) {
case CUR_UNDERLINE:
case CUR_LOWER_THIRD:
case CUR_LOWER_HALF:
case CUR_TWO_THIRDS:
case CUR_BLOCK:
sti_putc(sticon_sti, (car1 & 255) + (0 << 8) + (7 << 11),
conp->state.y, conp->state.x, font_data[conp->vc_num]);
break;
}
return;
}
switch (CUR_SIZE(conp->vc_cursor_type)) {
case CUR_UNDERLINE:
case CUR_LOWER_THIRD:
case CUR_LOWER_HALF:
case CUR_TWO_THIRDS:
case CUR_BLOCK:
sti_putc(sticon_sti, (car1 & 255) + (0 << 8) + (7 << 11),
conp->state.y, conp->state.x, font_data[conp->vc_num]);
break;
}
}
@ -135,7 +121,7 @@ static bool sticon_scroll(struct vc_data *conp, unsigned int t,
if (vga_is_gfx)
return false;
sticon_cursor(conp, CM_ERASE);
sticon_cursor(conp, false);
switch (dir) {
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)
{
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;
}
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);
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)
{
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;
int vc_cols, vc_rows;
@ -300,33 +287,32 @@ static void sticon_deinit(struct vc_data *c)
sticon_set_def_font(i);
}
static void sticon_clear(struct vc_data *conp, int sy, int sx, int height,
int width)
static void sticon_clear(struct vc_data *conp, unsigned int sy, unsigned int sx,
unsigned int width)
{
if (!height || !width)
return;
sti_clear(sticon_sti, sy, sx, height, width,
sti_clear(sticon_sti, sy, sx, 1, width,
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)
vga_is_gfx = 0;
return 1;
return true;
}
sti_clear(sticon_sti, 0, 0, c->vc_rows, c->vc_cols, BLANK,
font_data[c->vc_num]);
if (mode_switch)
vga_is_gfx = 1;
return 1;
return true;
}
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_deinit = sticon_deinit,
.con_clear = sticon_clear,
.con_putc = sticon_putc,
.con_putcs = sticon_putcs,
.con_cursor = sticon_cursor,
.con_scroll = sticon_scroll,

View File

@ -65,7 +65,7 @@ static struct vgastate vgastate;
* 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 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 unsigned int vga_default_font_height __read_mostly; /* Height of default screen font */
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_is_gfx;
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)
{
vc_scrolldelta_helper(c, lines, vga_rolled_over, (void *)vga_vram_base,
vga_vram_size);
unsigned long scr_end = c->vc_scr_end - vga_vram_base;
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);
}
@ -335,7 +367,7 @@ static const char *vgacon_startup(void)
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;
@ -352,7 +384,7 @@ static void vgacon_init(struct vc_data *c, int init)
c->vc_scan_lines = vga_scan_lines;
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) {
c->vc_cols = vga_video_num_columns;
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);
}
static void vgacon_cursor(struct vc_data *c, int mode)
static void vgacon_cursor(struct vc_data *c, bool enable)
{
unsigned int c_height;
@ -482,47 +514,41 @@ static void vgacon_cursor(struct vc_data *c, int mode)
c_height = c->vc_cell_height;
switch (mode) {
case CM_ERASE:
write_vga(14, (c->vc_pos - vga_vram_base) / 2);
write_vga(14, (c->vc_pos - vga_vram_base) / 2);
if (!enable) {
if (vga_video_type >= VIDEO_TYPE_VGAC)
vgacon_set_cursor_size(31, 30);
else
vgacon_set_cursor_size(31, 31);
break;
return;
}
case CM_MOVE:
case CM_DRAW:
write_vga(14, (c->vc_pos - vga_vram_base) / 2);
switch (CUR_SIZE(c->vc_cursor_type)) {
case CUR_UNDERLINE:
vgacon_set_cursor_size(c_height -
(c_height < 10 ? 2 : 3),
c_height -
(c_height < 10 ? 1 : 2));
break;
case CUR_TWO_THIRDS:
vgacon_set_cursor_size(c_height / 3, c_height -
(c_height < 10 ? 1 : 2));
break;
case CUR_LOWER_THIRD:
vgacon_set_cursor_size(c_height * 2 / 3, c_height -
(c_height < 10 ? 1 : 2));
break;
case CUR_LOWER_HALF:
vgacon_set_cursor_size(c_height / 2, c_height -
(c_height < 10 ? 1 : 2));
break;
case CUR_NONE:
if (vga_video_type >= VIDEO_TYPE_VGAC)
vgacon_set_cursor_size(31, 30);
else
vgacon_set_cursor_size(31, 31);
break;
default:
vgacon_set_cursor_size(1, c_height);
break;
}
switch (CUR_SIZE(c->vc_cursor_type)) {
case CUR_UNDERLINE:
vgacon_set_cursor_size(c_height - (c_height < 10 ? 2 : 3),
c_height - (c_height < 10 ? 1 : 2));
break;
case CUR_TWO_THIRDS:
vgacon_set_cursor_size(c_height / 3,
c_height - (c_height < 10 ? 1 : 2));
break;
case CUR_LOWER_THIRD:
vgacon_set_cursor_size(c_height * 2 / 3,
c_height - (c_height < 10 ? 1 : 2));
break;
case CUR_LOWER_HALF:
vgacon_set_cursor_size(c_height / 2,
c_height - (c_height < 10 ? 1 : 2));
break;
case CUR_NONE:
if (vga_video_type >= VIDEO_TYPE_VGAC)
vgacon_set_cursor_size(31, 30);
else
vgacon_set_cursor_size(31, 31);
break;
default:
vgacon_set_cursor_size(1, c_height);
break;
}
}
@ -588,7 +614,7 @@ static void vgacon_doresize(struct vc_data *c,
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 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);
}
return 0; /* Redrawing not needed */
return false; /* Redrawing not needed */
}
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 */
} 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 */
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) {
case 0: /* Unblank */
case VESA_NO_BLANKING: /* Unblank */
if (vga_vesa_blanked) {
vga_vesa_unblank(&vgastate);
vga_vesa_blanked = 0;
vga_vesa_blanked = VESA_NO_BLANKING;
}
if (vga_palette_blanked) {
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;
/* Tell console.c that it has to restore the screen itself */
return 1;
case 1: /* Normal blanking */
case -1: /* Obsolete */
case VESA_VSYNC_SUSPEND: /* Normal blanking */
if (!mode_switch && vga_video_type == VIDEO_TYPE_VGAC) {
vga_pal_blank(&vgastate);
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 */
cursor_size_lastfrom = 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;
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;
}
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 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,
unsigned int height, unsigned int user)
unsigned int height, bool from_user)
{
if ((width << 1) * height > vga_vram_size)
return -EINVAL;
if (user) {
if (from_user) {
/*
* Ho ho! Someone (svgatextmode, eh?) may have reprogrammed
* 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;
}
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 */
(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;
vga_set_mem_top(c);
vga_rolled_over = 0;
return 1;
return true;
}
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
*/
static void vgacon_clear(struct vc_data *vc, int sy, int sx, int height,
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 unsigned short *s,
int count, int ypos, int xpos) { }
static void vgacon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
unsigned int width) { }
static void vgacon_putcs(struct vc_data *vc, const u16 *s, unsigned int count,
unsigned int ypos, unsigned int xpos) { }
const struct consw vga_con = {
.owner = THIS_MODULE,
@ -1171,7 +1196,6 @@ const struct consw vga_con = {
.con_init = vgacon_init,
.con_deinit = vgacon_deinit,
.con_clear = vgacon_clear,
.con_putc = vgacon_putc,
.con_putcs = vgacon_putcs,
.con_cursor = vgacon_cursor,
.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)
{
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;
}
switch (mode) {
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;
}
ops->cursor_state.enable = enable && !use_sw;
cursor.image.data = src;
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 vc_data *vc = NULL;
int c;
int mode;
bool enable;
int ret;
/* 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);
mode = (!ops->cursor_flash || ops->cursor_state.enable) ?
CM_ERASE : CM_DRAW;
ops->cursor(vc, info, mode, get_color(vc, info, c, 1),
enable = ops->cursor_flash && !ops->cursor_state.enable;
ops->cursor(vc, info, enable, get_color(vc, info, c, 1),
get_color(vc, info, c, 0));
console_unlock();
@ -920,7 +919,7 @@ static void display_to_var(struct fb_var_screeninfo *var,
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 vc_data *vc = vc_cons[fg_console].d;
const struct font_desc *font = NULL;
@ -987,7 +986,7 @@ static const char *fbcon_startup(void)
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 fbcon_ops *ops;
@ -1234,8 +1233,8 @@ finished:
* restriction is simplicity & efficiency at the moment.
*/
static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height,
int width)
static void __fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
unsigned int height, unsigned int width)
{
struct fb_info *info = fbcon_info_from_console(vc->vc_num);
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);
}
static void fbcon_putcs(struct vc_data *vc, const unsigned short *s,
int count, int ypos, int xpos)
static void fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
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 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));
}
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)
{
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);
}
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 fbcon_ops *ops = info->fbcon_par;
@ -1318,12 +1315,12 @@ static void fbcon_cursor(struct vc_data *vc, int mode)
else
fbcon_add_cursor_work(info);
ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1;
ops->cursor_flash = enable;
if (!ops->cursor)
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));
}
@ -1743,7 +1740,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
if (fbcon_is_inactive(vc, info))
return true;
fbcon_cursor(vc, CM_ERASE);
fbcon_cursor(vc, false);
/*
* ++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:
fbcon_redraw_blit(vc, info, p, t, b - t - 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 +
vc->vc_size_row *
(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);
else
goto redraw_up;
fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
__fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
break;
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);
} else
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;
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);
else
goto redraw_up;
fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
__fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
break;
case SCROLL_REDRAW:
redraw_up:
fbcon_redraw(vc, t, b - t - count,
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 +
vc->vc_size_row *
(b - count)),
@ -1847,7 +1844,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
case SCROLL_MOVE:
fbcon_redraw_blit(vc, info, p, b - 1, b - t - 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 +
vc->vc_size_row *
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);
else
goto redraw_down;
fbcon_clear(vc, t, 0, count, vc->vc_cols);
__fbcon_clear(vc, t, 0, count, vc->vc_cols);
break;
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);
else
goto redraw_down;
fbcon_clear(vc, t, 0, count, vc->vc_cols);
__fbcon_clear(vc, t, 0, count, vc->vc_cols);
break;
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);
} else
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;
case SCROLL_REDRAW:
redraw_down:
fbcon_redraw(vc, b - 1, b - t - count,
-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 +
vc->vc_size_row *
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 */
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 fbcon_ops *ops = info->fbcon_par;
@ -2058,7 +2055,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
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 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_size_row * (vc->vc_bottom -
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,
@ -2195,12 +2192,13 @@ static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info,
oldc = vc->vc_video_erase_char;
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;
}
}
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 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 (ops->blank_state != blank) {
ops->blank_state = blank;
fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW);
fbcon_cursor(vc, !blank);
ops->cursor_flash = (!blank);
if (fb_blank(info, blank))
@ -2239,10 +2237,10 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
else
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 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)
info->fbops->fb_debug_enter(info);
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 fbcon_ops *ops = info->fbcon_par;
@ -2263,7 +2260,6 @@ static int fbcon_debug_leave(struct vc_data *vc)
ops->graphics = ops->save_graphics;
if (info->fbops->fb_debug_leave)
info->fbops->fb_debug_leave(info);
return 0;
}
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.
*/
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)
{
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);
}
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);
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);
}
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,
that's why we have to use a separate routine. */
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;
/* Clear cursor, restore saved data */
fbcon_cursor(vc, CM_ERASE);
fbcon_cursor(vc, false);
}
void fbcon_resumed(struct fb_info *info)
@ -3152,7 +3120,6 @@ static const struct consw fb_con = {
.con_init = fbcon_init,
.con_deinit = fbcon_deinit,
.con_clear = fbcon_clear,
.con_putc = fbcon_putc,
.con_putcs = fbcon_putcs,
.con_cursor = fbcon_cursor,
.con_scroll = fbcon_scroll,
@ -3163,8 +3130,6 @@ static const struct consw fb_con = {
.con_font_default = fbcon_set_def_font,
.con_set_palette = fbcon_set_palette,
.con_invert_region = fbcon_invert_region,
.con_screen_pos = fbcon_screen_pos,
.con_getxy = fbcon_getxy,
.con_resize = fbcon_resize,
.con_debug_enter = fbcon_debug_enter,
.con_debug_leave = fbcon_debug_leave,

View File

@ -61,8 +61,8 @@ struct fbcon_ops {
int fg, int bg);
void (*clear_margins)(struct vc_data *vc, struct fb_info *info,
int color, int bottom_only);
void (*cursor)(struct vc_data *vc, struct fb_info *info, int mode,
int fg, int bg);
void (*cursor)(struct vc_data *vc, struct fb_info *info,
bool enable, int fg, int bg);
int (*update_start)(struct fb_info *info);
int (*rotate_font)(struct fb_info *info, struct vc_data *vc);
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)
{
struct fb_cursor cursor;
@ -349,16 +349,7 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
kfree(tmp);
}
switch (mode) {
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;
}
ops->cursor_state.enable = enable && !use_sw;
cursor.image.data = src;
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)
{
struct fb_cursor cursor;
@ -332,16 +332,7 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
kfree(tmp);
}
switch (mode) {
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;
}
ops->cursor_state.enable = enable && !use_sw;
cursor.image.data = src;
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)
{
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;
}
switch (mode) {
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;
}
ops->cursor_state.enable = enable && !use_sw;
cursor.image.data = src;
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;
}
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)
{
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.sy = vc->state.y;
cursor.mode = (mode == CM_ERASE || use_sw) ? 0 : 1;
cursor.mode = enable && !use_sw;
cursor.fg = fg;
cursor.bg = bg;

View File

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

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