Commit aba9753c authored by Linus Torvalds's avatar Linus Torvalds

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

Pull tty / serial updates from Greg KH:
 "Here is a small set of tty and serial driver updates for 6.11-rc1. Not
  much happened this cycle, unlike the previous kernel release which had
  lots of "excitement" in this part of the kernel. Included in here are
  the following changes:

   - dt binding updates for new platforms

   - 8250 driver updates

   - various small serial driver fixes and updates

   - printk/console naming and matching attempt #2 (was reverted for
     6.10-final, should be good to go this time around, acked by the
     relevant maintainers).

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

* tag 'tty-6.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (22 commits)
  Documentation: kernel-parameters: Add DEVNAME:0.0 format for serial ports
  serial: core: Add serial_base_match_and_update_preferred_console()
  printk: Add match_devname_and_update_preferred_console()
  serial: sc16is7xx: hardware reset chip if reset-gpios is defined in DT
  dt-bindings: serial: sc16is7xx: add reset-gpios
  dt-bindings: serial: vt8500-uart: convert to json-schema
  serial: 8250_platform: Explicitly show we initialise ISA ports only once
  tty: add missing MODULE_DESCRIPTION() macros
  dt-bindings: serial: mediatek,uart: add MT7988
  serial: sh-sci: Add support for RZ/V2H(P) SoC
  dt-bindings: serial: Add documentation for Renesas RZ/V2H(P) (R9A09G057) SCIF support
  dt-bindings: serial: renesas,scif: Make 'interrupt-names' property as required
  dt-bindings: serial: renesas,scif: Validate 'interrupts' and 'interrupt-names'
  dt-bindings: serial: renesas,scif: Move ref for serial.yaml at the end
  riscv: dts: starfive: jh7110: Add the core reset and jh7110 compatible for uarts
  serial: 8250_dw: Use reset array API to get resets
  dt-bindings: serial: snps-dw-apb-uart: Add one more reset signal for StarFive JH7110 SoC
  serial: 8250: Extract platform driver
  serial: 8250: Extract RSA bits
  serial: imx: stop casting struct uart_port to struct imx_port
  ...
parents d7e78951 17199dfc
...@@ -792,6 +792,25 @@ ...@@ -792,6 +792,25 @@
Documentation/networking/netconsole.rst for an Documentation/networking/netconsole.rst for an
alternative. alternative.
<DEVNAME>:<n>.<n>[,options]
Use the specified serial port on the serial core bus.
The addressing uses DEVNAME of the physical serial port
device, followed by the serial core controller instance,
and the serial port instance. The options are the same
as documented for the ttyS addressing above.
The mapping of the serial ports to the tty instances
can be viewed with:
$ ls -d /sys/bus/serial-base/devices/*:*.*/tty/*
/sys/bus/serial-base/devices/00:04:0.0/tty/ttyS0
In the above example, the console can be addressed with
console=00:04:0.0. Note that a console addressed this
way will only get added when the related device driver
is ready. The use of an earlycon parameter in addition to
the console may be desired for console output early on.
uart[8250],io,<addr>[,options] uart[8250],io,<addr>[,options]
uart[8250],mmio,<addr>[,options] uart[8250],mmio,<addr>[,options]
uart[8250],mmio16,<addr>[,options] uart[8250],mmio16,<addr>[,options]
......
...@@ -37,6 +37,7 @@ properties: ...@@ -37,6 +37,7 @@ properties:
- mediatek,mt7623-uart - mediatek,mt7623-uart
- mediatek,mt7629-uart - mediatek,mt7629-uart
- mediatek,mt7986-uart - mediatek,mt7986-uart
- mediatek,mt7988-uart
- mediatek,mt8127-uart - mediatek,mt8127-uart
- mediatek,mt8135-uart - mediatek,mt8135-uart
- mediatek,mt8173-uart - mediatek,mt8173-uart
......
...@@ -28,6 +28,9 @@ properties: ...@@ -28,6 +28,9 @@ properties:
clocks: clocks:
maxItems: 1 maxItems: 1
reset-gpios:
maxItems: 1
clock-frequency: clock-frequency:
description: description:
When there is no clock provider visible to the platform, this When there is no clock provider visible to the platform, this
...@@ -91,6 +94,7 @@ unevaluatedProperties: false ...@@ -91,6 +94,7 @@ unevaluatedProperties: false
examples: examples:
- | - |
#include <dt-bindings/interrupt-controller/irq.h> #include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/gpio/gpio.h>
i2c { i2c {
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
...@@ -120,6 +124,7 @@ examples: ...@@ -120,6 +124,7 @@ examples:
compatible = "nxp,sc16is752"; compatible = "nxp,sc16is752";
reg = <0x54>; reg = <0x54>;
clocks = <&clk20m>; clocks = <&clk20m>;
reset-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>;
interrupt-parent = <&gpio3>; interrupt-parent = <&gpio3>;
interrupts = <7 IRQ_TYPE_EDGE_FALLING>; interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
nxp,modem-control-line-ports = <0 1>; /* Ports 0 and 1 as modem control lines */ nxp,modem-control-line-ports = <0 1>; /* Ports 0 and 1 as modem control lines */
......
...@@ -9,9 +9,6 @@ title: Renesas Serial Communication Interface with FIFO (SCIF) ...@@ -9,9 +9,6 @@ title: Renesas Serial Communication Interface with FIFO (SCIF)
maintainers: maintainers:
- Geert Uytterhoeven <geert+renesas@glider.be> - Geert Uytterhoeven <geert+renesas@glider.be>
allOf:
- $ref: serial.yaml#
properties: properties:
compatible: compatible:
oneOf: oneOf:
...@@ -83,6 +80,8 @@ properties: ...@@ -83,6 +80,8 @@ properties:
- renesas,scif-r9a08g045 # RZ/G3S - renesas,scif-r9a08g045 # RZ/G3S
- const: renesas,scif-r9a07g044 # RZ/G2{L,LC} fallback - const: renesas,scif-r9a07g044 # RZ/G2{L,LC} fallback
- const: renesas,scif-r9a09g057 # RZ/V2H(P)
reg: reg:
maxItems: 1 maxItems: 1
...@@ -90,11 +89,6 @@ properties: ...@@ -90,11 +89,6 @@ properties:
oneOf: oneOf:
- items: - items:
- description: A combined interrupt - description: A combined interrupt
- items:
- description: Error interrupt
- description: Receive buffer full interrupt
- description: Transmit buffer empty interrupt
- description: Break interrupt
- items: - items:
- description: Error interrupt - description: Error interrupt
- description: Receive buffer full interrupt - description: Receive buffer full interrupt
...@@ -102,21 +96,23 @@ properties: ...@@ -102,21 +96,23 @@ properties:
- description: Break interrupt - description: Break interrupt
- description: Data Ready interrupt - description: Data Ready interrupt
- description: Transmit End interrupt - description: Transmit End interrupt
- description: Transmit End/Data Ready interrupt
- description: Receive buffer full interrupt (EDGE trigger)
- description: Transmit buffer empty interrupt (EDGE trigger)
minItems: 4
interrupt-names: interrupt-names:
oneOf: minItems: 4
- items: items:
- const: eri - const: eri
- const: rxi - const: rxi
- const: txi - const: txi
- const: bri - const: bri
- items: - const: dri
- const: eri - const: tei
- const: rxi - const: tei-dri
- const: txi - const: rxi-edge
- const: bri - const: txi-edge
- const: dri
- const: tei
clocks: clocks:
minItems: 1 minItems: 1
...@@ -161,18 +157,92 @@ required: ...@@ -161,18 +157,92 @@ required:
- clock-names - clock-names
- power-domains - power-domains
if: allOf:
properties: - $ref: serial.yaml#
compatible:
contains: - if:
enum: properties:
- renesas,rcar-gen2-scif compatible:
- renesas,rcar-gen3-scif contains:
- renesas,rcar-gen4-scif enum:
- renesas,scif-r9a07g044 - renesas,rcar-gen2-scif
then: - renesas,rcar-gen3-scif
required: - renesas,rcar-gen4-scif
- resets - renesas,scif-r9a07g044
- renesas,scif-r9a09g057
then:
required:
- resets
- if:
properties:
compatible:
contains:
enum:
- renesas,rcar-gen1-scif
- renesas,rcar-gen2-scif
- renesas,rcar-gen3-scif
- renesas,rcar-gen4-scif
then:
properties:
interrupts:
maxItems: 1
interrupt-names: false
else:
required:
- interrupt-names
- if:
properties:
compatible:
contains:
enum:
- renesas,scif-r7s72100
then:
properties:
interrupts:
minItems: 4
maxItems: 4
interrupt-names:
maxItems: 4
- if:
properties:
compatible:
contains:
enum:
- renesas,scif-r7s9210
- renesas,scif-r9a07g044
then:
properties:
interrupts:
minItems: 6
maxItems: 6
interrupt-names:
minItems: 6
maxItems: 6
- if:
properties:
compatible:
contains:
const: renesas,scif-r9a09g057
then:
properties:
clocks:
maxItems: 1
clock-names:
maxItems: 1
interrupts:
minItems: 9
interrupt-names:
minItems: 9
unevaluatedProperties: false unevaluatedProperties: false
......
...@@ -13,6 +13,20 @@ allOf: ...@@ -13,6 +13,20 @@ allOf:
- $ref: serial.yaml# - $ref: serial.yaml#
- $ref: rs485.yaml# - $ref: rs485.yaml#
- if:
properties:
compatible:
contains:
const: starfive,jh7110-uart
then:
properties:
resets:
minItems: 2
else:
properties:
resets:
maxItems: 1
properties: properties:
compatible: compatible:
oneOf: oneOf:
...@@ -48,6 +62,7 @@ properties: ...@@ -48,6 +62,7 @@ properties:
- enum: - enum:
- starfive,jh7100-hsuart - starfive,jh7100-hsuart
- starfive,jh7100-uart - starfive,jh7100-uart
- starfive,jh7110-uart
- const: snps,dw-apb-uart - const: snps,dw-apb-uart
- const: snps,dw-apb-uart - const: snps,dw-apb-uart
...@@ -82,7 +97,8 @@ properties: ...@@ -82,7 +97,8 @@ properties:
type: boolean type: boolean
resets: resets:
maxItems: 1 minItems: 1
maxItems: 2
reg-shift: true reg-shift: true
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/serial/via,vt8500-uart.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: VIA VT8500 and WonderMedia WM8xxx UART Controller
maintainers:
- Alexey Charkov <alchark@gmail.com>
allOf:
- $ref: serial.yaml
properties:
compatible:
enum:
- via,vt8500-uart # up to WM8850/WM8950
- wm,wm8880-uart # for WM8880 and later
clocks:
maxItems: 1
interrupts:
maxItems: 1
reg:
maxItems: 1
required:
- compatible
- clocks
- interrupts
- reg
unevaluatedProperties: false
examples:
- |
serial@d8200000 {
compatible = "via,vt8500-uart";
reg = <0xd8200000 0x1040>;
interrupts = <32>;
clocks = <&clkuart0>;
};
* VIA VT8500 and WonderMedia WM8xxx UART Controller
Required properties:
- compatible: should be "via,vt8500-uart" (for VIA/WonderMedia chips up to and
including WM8850/WM8950), or "wm,wm8880-uart" (for WM8880 and later)
- reg: base physical address of the controller and length of memory mapped
region.
- interrupts: hardware interrupt number
- clocks: shall be the input parent clock phandle for the clock. This should
be the 24Mhz reference clock.
Aliases may be defined to ensure the correct ordering of the uarts.
Example:
aliases {
serial0 = &uart0;
};
uart0: serial@d8200000 {
compatible = "via,vt8500-uart";
reg = <0xd8200000 0x1040>;
interrupts = <32>;
clocks = <&clkuart0>;
};
...@@ -387,12 +387,13 @@ plic: interrupt-controller@c000000 { ...@@ -387,12 +387,13 @@ plic: interrupt-controller@c000000 {
}; };
uart0: serial@10000000 { uart0: serial@10000000 {
compatible = "snps,dw-apb-uart"; compatible = "starfive,jh7110-uart", "snps,dw-apb-uart";
reg = <0x0 0x10000000 0x0 0x10000>; reg = <0x0 0x10000000 0x0 0x10000>;
clocks = <&syscrg JH7110_SYSCLK_UART0_CORE>, clocks = <&syscrg JH7110_SYSCLK_UART0_CORE>,
<&syscrg JH7110_SYSCLK_UART0_APB>; <&syscrg JH7110_SYSCLK_UART0_APB>;
clock-names = "baudclk", "apb_pclk"; clock-names = "baudclk", "apb_pclk";
resets = <&syscrg JH7110_SYSRST_UART0_APB>; resets = <&syscrg JH7110_SYSRST_UART0_APB>,
<&syscrg JH7110_SYSRST_UART0_CORE>;
interrupts = <32>; interrupts = <32>;
reg-io-width = <4>; reg-io-width = <4>;
reg-shift = <2>; reg-shift = <2>;
...@@ -400,12 +401,13 @@ uart0: serial@10000000 { ...@@ -400,12 +401,13 @@ uart0: serial@10000000 {
}; };
uart1: serial@10010000 { uart1: serial@10010000 {
compatible = "snps,dw-apb-uart"; compatible = "starfive,jh7110-uart", "snps,dw-apb-uart";
reg = <0x0 0x10010000 0x0 0x10000>; reg = <0x0 0x10010000 0x0 0x10000>;
clocks = <&syscrg JH7110_SYSCLK_UART1_CORE>, clocks = <&syscrg JH7110_SYSCLK_UART1_CORE>,
<&syscrg JH7110_SYSCLK_UART1_APB>; <&syscrg JH7110_SYSCLK_UART1_APB>;
clock-names = "baudclk", "apb_pclk"; clock-names = "baudclk", "apb_pclk";
resets = <&syscrg JH7110_SYSRST_UART1_APB>; resets = <&syscrg JH7110_SYSRST_UART1_APB>,
<&syscrg JH7110_SYSRST_UART1_CORE>;
interrupts = <33>; interrupts = <33>;
reg-io-width = <4>; reg-io-width = <4>;
reg-shift = <2>; reg-shift = <2>;
...@@ -413,12 +415,13 @@ uart1: serial@10010000 { ...@@ -413,12 +415,13 @@ uart1: serial@10010000 {
}; };
uart2: serial@10020000 { uart2: serial@10020000 {
compatible = "snps,dw-apb-uart"; compatible = "starfive,jh7110-uart", "snps,dw-apb-uart";
reg = <0x0 0x10020000 0x0 0x10000>; reg = <0x0 0x10020000 0x0 0x10000>;
clocks = <&syscrg JH7110_SYSCLK_UART2_CORE>, clocks = <&syscrg JH7110_SYSCLK_UART2_CORE>,
<&syscrg JH7110_SYSCLK_UART2_APB>; <&syscrg JH7110_SYSCLK_UART2_APB>;
clock-names = "baudclk", "apb_pclk"; clock-names = "baudclk", "apb_pclk";
resets = <&syscrg JH7110_SYSRST_UART2_APB>; resets = <&syscrg JH7110_SYSRST_UART2_APB>,
<&syscrg JH7110_SYSRST_UART2_CORE>;
interrupts = <34>; interrupts = <34>;
reg-io-width = <4>; reg-io-width = <4>;
reg-shift = <2>; reg-shift = <2>;
...@@ -642,12 +645,13 @@ stg_syscon: syscon@10240000 { ...@@ -642,12 +645,13 @@ stg_syscon: syscon@10240000 {
}; };
uart3: serial@12000000 { uart3: serial@12000000 {
compatible = "snps,dw-apb-uart"; compatible = "starfive,jh7110-uart", "snps,dw-apb-uart";
reg = <0x0 0x12000000 0x0 0x10000>; reg = <0x0 0x12000000 0x0 0x10000>;
clocks = <&syscrg JH7110_SYSCLK_UART3_CORE>, clocks = <&syscrg JH7110_SYSCLK_UART3_CORE>,
<&syscrg JH7110_SYSCLK_UART3_APB>; <&syscrg JH7110_SYSCLK_UART3_APB>;
clock-names = "baudclk", "apb_pclk"; clock-names = "baudclk", "apb_pclk";
resets = <&syscrg JH7110_SYSRST_UART3_APB>; resets = <&syscrg JH7110_SYSRST_UART3_APB>,
<&syscrg JH7110_SYSRST_UART3_CORE>;
interrupts = <45>; interrupts = <45>;
reg-io-width = <4>; reg-io-width = <4>;
reg-shift = <2>; reg-shift = <2>;
...@@ -655,12 +659,13 @@ uart3: serial@12000000 { ...@@ -655,12 +659,13 @@ uart3: serial@12000000 {
}; };
uart4: serial@12010000 { uart4: serial@12010000 {
compatible = "snps,dw-apb-uart"; compatible = "starfive,jh7110-uart", "snps,dw-apb-uart";
reg = <0x0 0x12010000 0x0 0x10000>; reg = <0x0 0x12010000 0x0 0x10000>;
clocks = <&syscrg JH7110_SYSCLK_UART4_CORE>, clocks = <&syscrg JH7110_SYSCLK_UART4_CORE>,
<&syscrg JH7110_SYSCLK_UART4_APB>; <&syscrg JH7110_SYSCLK_UART4_APB>;
clock-names = "baudclk", "apb_pclk"; clock-names = "baudclk", "apb_pclk";
resets = <&syscrg JH7110_SYSRST_UART4_APB>; resets = <&syscrg JH7110_SYSRST_UART4_APB>,
<&syscrg JH7110_SYSRST_UART4_CORE>;
interrupts = <46>; interrupts = <46>;
reg-io-width = <4>; reg-io-width = <4>;
reg-shift = <2>; reg-shift = <2>;
...@@ -668,12 +673,13 @@ uart4: serial@12010000 { ...@@ -668,12 +673,13 @@ uart4: serial@12010000 {
}; };
uart5: serial@12020000 { uart5: serial@12020000 {
compatible = "snps,dw-apb-uart"; compatible = "starfive,jh7110-uart", "snps,dw-apb-uart";
reg = <0x0 0x12020000 0x0 0x10000>; reg = <0x0 0x12020000 0x0 0x10000>;
clocks = <&syscrg JH7110_SYSCLK_UART5_CORE>, clocks = <&syscrg JH7110_SYSCLK_UART5_CORE>,
<&syscrg JH7110_SYSCLK_UART5_APB>; <&syscrg JH7110_SYSCLK_UART5_APB>;
clock-names = "baudclk", "apb_pclk"; clock-names = "baudclk", "apb_pclk";
resets = <&syscrg JH7110_SYSRST_UART5_APB>; resets = <&syscrg JH7110_SYSRST_UART5_APB>,
<&syscrg JH7110_SYSRST_UART5_CORE>;
interrupts = <47>; interrupts = <47>;
reg-io-width = <4>; reg-io-width = <4>;
reg-shift = <2>; reg-shift = <2>;
......
...@@ -1660,5 +1660,6 @@ console_initcall(amiserial_console_init); ...@@ -1660,5 +1660,6 @@ console_initcall(amiserial_console_init);
#endif /* CONFIG_SERIAL_CONSOLE && !MODULE */ #endif /* CONFIG_SERIAL_CONSOLE && !MODULE */
MODULE_DESCRIPTION("Serial driver for the amiga builtin port");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:amiga-serial"); MODULE_ALIAS("platform:amiga-serial");
...@@ -470,4 +470,5 @@ static struct platform_driver goldfish_tty_platform_driver = { ...@@ -470,4 +470,5 @@ static struct platform_driver goldfish_tty_platform_driver = {
module_platform_driver(goldfish_tty_platform_driver); module_platform_driver(goldfish_tty_platform_driver);
MODULE_DESCRIPTION("Goldfish TTY Driver");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
...@@ -4634,5 +4634,6 @@ module_init(gsm_init); ...@@ -4634,5 +4634,6 @@ module_init(gsm_init);
module_exit(gsm_exit); module_exit(gsm_exit);
MODULE_DESCRIPTION("GSM 0710 tty multiplexor");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_ALIAS_LDISC(N_GSM0710); MODULE_ALIAS_LDISC(N_GSM0710);
...@@ -822,6 +822,7 @@ static void __exit n_hdlc_exit(void) ...@@ -822,6 +822,7 @@ static void __exit n_hdlc_exit(void)
module_init(n_hdlc_init); module_init(n_hdlc_init);
module_exit(n_hdlc_exit); module_exit(n_hdlc_exit);
MODULE_DESCRIPTION("HDLC line discipline support");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Paul Fulghum paulkf@microgate.com"); MODULE_AUTHOR("Paul Fulghum paulkf@microgate.com");
module_param(maxframe, int, 0); module_param(maxframe, int, 0);
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#include <linux/bits.h> #include <linux/bits.h>
#include <linux/serial_8250.h> #include <linux/serial_8250.h>
#include <linux/serial_reg.h> #include <linux/serial_core.h>
#include <linux/dmaengine.h> #include <linux/dmaengine.h>
#include "../serial_mctrl_gpio.h" #include "../serial_mctrl_gpio.h"
...@@ -93,6 +93,10 @@ struct serial8250_config { ...@@ -93,6 +93,10 @@ struct serial8250_config {
#define UART_BUG_THRE BIT(3) /* UART has buggy THRE reassertion */ #define UART_BUG_THRE BIT(3) /* UART has buggy THRE reassertion */
#define UART_BUG_TXRACE BIT(5) /* UART Tx fails to set remote DR */ #define UART_BUG_TXRACE BIT(5) /* UART Tx fails to set remote DR */
/* Module parameters */
#define UART_NR CONFIG_SERIAL_8250_NR_UARTS
extern unsigned int nr_uarts;
#ifdef CONFIG_SERIAL_8250_SHARE_IRQ #ifdef CONFIG_SERIAL_8250_SHARE_IRQ
#define SERIAL8250_SHARE_IRQS 1 #define SERIAL8250_SHARE_IRQS 1
...@@ -100,6 +104,9 @@ struct serial8250_config { ...@@ -100,6 +104,9 @@ struct serial8250_config {
#define SERIAL8250_SHARE_IRQS 0 #define SERIAL8250_SHARE_IRQS 0
#endif #endif
extern unsigned int share_irqs;
extern unsigned int skip_txen_test;
#define SERIAL8250_PORT_FLAGS(_base, _irq, _flags) \ #define SERIAL8250_PORT_FLAGS(_base, _irq, _flags) \
{ \ { \
.iobase = _base, \ .iobase = _base, \
...@@ -111,6 +118,19 @@ struct serial8250_config { ...@@ -111,6 +118,19 @@ struct serial8250_config {
#define SERIAL8250_PORT(_base, _irq) SERIAL8250_PORT_FLAGS(_base, _irq, 0) #define SERIAL8250_PORT(_base, _irq) SERIAL8250_PORT_FLAGS(_base, _irq, 0)
extern struct uart_driver serial8250_reg;
void serial8250_register_ports(struct uart_driver *drv, struct device *dev);
/* Legacy ISA bus related APIs */
typedef void (*serial8250_isa_config_fn)(int, struct uart_port *, u32 *);
extern serial8250_isa_config_fn serial8250_isa_config;
void serial8250_isa_init_ports(void);
extern struct platform_device *serial8250_isa_devs;
extern const struct uart_ops *univ8250_port_base_ops;
extern struct uart_ops univ8250_port_ops;
static inline int serial_in(struct uart_8250_port *up, int offset) static inline int serial_in(struct uart_8250_port *up, int offset)
{ {
...@@ -200,6 +220,7 @@ static inline bool serial8250_clear_THRI(struct uart_8250_port *up) ...@@ -200,6 +220,7 @@ static inline bool serial8250_clear_THRI(struct uart_8250_port *up)
return true; return true;
} }
struct uart_8250_port *serial8250_setup_port(int index);
struct uart_8250_port *serial8250_get_port(int line); struct uart_8250_port *serial8250_get_port(int line);
void serial8250_rpm_get(struct uart_8250_port *p); void serial8250_rpm_get(struct uart_8250_port *p);
...@@ -301,6 +322,12 @@ static inline int serial8250_pnp_init(void) { return 0; } ...@@ -301,6 +322,12 @@ static inline int serial8250_pnp_init(void) { return 0; }
static inline void serial8250_pnp_exit(void) { } static inline void serial8250_pnp_exit(void) { }
#endif #endif
#ifdef CONFIG_SERIAL_8250_RSA
void univ8250_rsa_support(struct uart_ops *ops);
#else
static inline void univ8250_rsa_support(struct uart_ops *ops) { }
#endif
#ifdef CONFIG_SERIAL_8250_FINTEK #ifdef CONFIG_SERIAL_8250_FINTEK
int fintek_8250_probe(struct uart_8250_port *uart); int fintek_8250_probe(struct uart_8250_port *uart);
#else #else
......
...@@ -6,11 +6,9 @@ ...@@ -6,11 +6,9 @@
* *
* Copyright (C) 2001 Russell King. * Copyright (C) 2001 Russell King.
* *
* Supports: ISA-compatible 8250/16550 ports * Supports:
* PNP 8250/16550 ports
* early_serial_setup() ports * early_serial_setup() ports
* userspace-configurable "phantom" ports * userspace-configurable "phantom" ports
* "serial8250" platform devices
* serial8250_register_8250_port() ports * serial8250_register_8250_port() ports
*/ */
...@@ -35,52 +33,13 @@ ...@@ -35,52 +33,13 @@
#include <linux/string_helpers.h> #include <linux/string_helpers.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/io.h> #include <linux/io.h>
#ifdef CONFIG_SPARC
#include <linux/sunserialcore.h>
#endif
#include <asm/irq.h> #include <asm/irq.h>
#include "8250.h" #include "8250.h"
/*
* Configuration:
* share_irqs - whether we pass IRQF_SHARED to request_irq(). This option
* is unsafe when used on edge-triggered interrupts.
*/
static unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS;
static struct uart_driver serial8250_reg;
static unsigned int skip_txen_test; /* force skip of txen test at init time */
#define PASS_LIMIT 512 #define PASS_LIMIT 512
#include <asm/serial.h>
/*
* SERIAL_PORT_DFNS tells us about built-in ports that have no
* standard enumeration mechanism. Platforms that can find all
* serial ports via mechanisms like ACPI or PCI need not supply it.
*/
#ifndef SERIAL_PORT_DFNS
#define SERIAL_PORT_DFNS
#endif
static const struct old_serial_port old_serial_port[] = {
SERIAL_PORT_DFNS /* defined in asm/serial.h */
};
#define UART_NR CONFIG_SERIAL_8250_NR_UARTS
#ifdef CONFIG_SERIAL_8250_RSA
#define PORT_RSA_MAX 4
static unsigned long probe_rsa[PORT_RSA_MAX];
static unsigned int probe_rsa_count;
#endif /* CONFIG_SERIAL_8250_RSA */
struct irq_info { struct irq_info {
struct hlist_node node; struct hlist_node node;
int irq; int irq;
...@@ -345,45 +304,8 @@ static void univ8250_release_irq(struct uart_8250_port *up) ...@@ -345,45 +304,8 @@ static void univ8250_release_irq(struct uart_8250_port *up)
serial_unlink_irq_chain(up); serial_unlink_irq_chain(up);
} }
#ifdef CONFIG_SERIAL_8250_RSA const struct uart_ops *univ8250_port_base_ops = NULL;
static int serial8250_request_rsa_resource(struct uart_8250_port *up) struct uart_ops univ8250_port_ops;
{
unsigned long start = UART_RSA_BASE << up->port.regshift;
unsigned int size = 8 << up->port.regshift;
struct uart_port *port = &up->port;
int ret = -EINVAL;
switch (port->iotype) {
case UPIO_HUB6:
case UPIO_PORT:
start += port->iobase;
if (request_region(start, size, "serial-rsa"))
ret = 0;
else
ret = -EBUSY;
break;
}
return ret;
}
static void serial8250_release_rsa_resource(struct uart_8250_port *up)
{
unsigned long offset = UART_RSA_BASE << up->port.regshift;
unsigned int size = 8 << up->port.regshift;
struct uart_port *port = &up->port;
switch (port->iotype) {
case UPIO_HUB6:
case UPIO_PORT:
release_region(port->iobase + offset, size);
break;
}
}
#endif
static const struct uart_ops *base_ops;
static struct uart_ops univ8250_port_ops;
static const struct uart_8250_ops univ8250_driver_ops = { static const struct uart_8250_ops univ8250_driver_ops = {
.setup_irq = univ8250_setup_irq, .setup_irq = univ8250_setup_irq,
...@@ -411,85 +333,12 @@ struct uart_8250_port *serial8250_get_port(int line) ...@@ -411,85 +333,12 @@ struct uart_8250_port *serial8250_get_port(int line)
} }
EXPORT_SYMBOL_GPL(serial8250_get_port); EXPORT_SYMBOL_GPL(serial8250_get_port);
static void (*serial8250_isa_config)(int port, struct uart_port *up,
u32 *capabilities);
void serial8250_set_isa_configurator(
void (*v)(int port, struct uart_port *up, u32 *capabilities))
{
serial8250_isa_config = v;
}
EXPORT_SYMBOL(serial8250_set_isa_configurator);
#ifdef CONFIG_SERIAL_8250_RSA
static void univ8250_config_port(struct uart_port *port, int flags)
{
struct uart_8250_port *up = up_to_u8250p(port);
up->probe &= ~UART_PROBE_RSA;
if (port->type == PORT_RSA) {
if (serial8250_request_rsa_resource(up) == 0)
up->probe |= UART_PROBE_RSA;
} else if (flags & UART_CONFIG_TYPE) {
int i;
for (i = 0; i < probe_rsa_count; i++) {
if (probe_rsa[i] == up->port.iobase) {
if (serial8250_request_rsa_resource(up) == 0)
up->probe |= UART_PROBE_RSA;
break;
}
}
}
base_ops->config_port(port, flags);
if (port->type != PORT_RSA && up->probe & UART_PROBE_RSA)
serial8250_release_rsa_resource(up);
}
static int univ8250_request_port(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
int ret;
ret = base_ops->request_port(port);
if (ret == 0 && port->type == PORT_RSA) {
ret = serial8250_request_rsa_resource(up);
if (ret < 0)
base_ops->release_port(port);
}
return ret;
}
static void univ8250_release_port(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
if (port->type == PORT_RSA)
serial8250_release_rsa_resource(up);
base_ops->release_port(port);
}
static void univ8250_rsa_support(struct uart_ops *ops)
{
ops->config_port = univ8250_config_port;
ops->request_port = univ8250_request_port;
ops->release_port = univ8250_release_port;
}
#else
#define univ8250_rsa_support(x) do { } while (0)
#endif /* CONFIG_SERIAL_8250_RSA */
static inline void serial8250_apply_quirks(struct uart_8250_port *up) static inline void serial8250_apply_quirks(struct uart_8250_port *up)
{ {
up->port.quirks |= skip_txen_test ? UPQ_NO_TXEN_TEST : 0; up->port.quirks |= skip_txen_test ? UPQ_NO_TXEN_TEST : 0;
} }
static struct uart_8250_port *serial8250_setup_port(int index) struct uart_8250_port *serial8250_setup_port(int index)
{ {
struct uart_8250_port *up; struct uart_8250_port *up;
...@@ -501,8 +350,8 @@ static struct uart_8250_port *serial8250_setup_port(int index) ...@@ -501,8 +350,8 @@ static struct uart_8250_port *serial8250_setup_port(int index)
up->port.port_id = index; up->port.port_id = index;
serial8250_init_port(up); serial8250_init_port(up);
if (!base_ops) if (!univ8250_port_base_ops)
base_ops = up->port.ops; univ8250_port_base_ops = up->port.ops;
up->port.ops = &univ8250_port_ops; up->port.ops = &univ8250_port_ops;
timer_setup(&up->timer, serial8250_timeout, 0); timer_setup(&up->timer, serial8250_timeout, 0);
...@@ -514,57 +363,7 @@ static struct uart_8250_port *serial8250_setup_port(int index) ...@@ -514,57 +363,7 @@ static struct uart_8250_port *serial8250_setup_port(int index)
return up; return up;
} }
static void __init serial8250_isa_init_ports(void) void __init serial8250_register_ports(struct uart_driver *drv, struct device *dev)
{
struct uart_8250_port *up;
static int first = 1;
int i, irqflag = 0;
if (!first)
return;
first = 0;
if (nr_uarts > UART_NR)
nr_uarts = UART_NR;
/*
* Set up initial isa ports based on nr_uart module param, or else
* default to CONFIG_SERIAL_8250_RUNTIME_UARTS. Note that we do not
* need to increase nr_uarts when setting up the initial isa ports.
*/
for (i = 0; i < nr_uarts; i++)
serial8250_setup_port(i);
/* chain base port ops to support Remote Supervisor Adapter */
univ8250_port_ops = *base_ops;
univ8250_rsa_support(&univ8250_port_ops);
if (share_irqs)
irqflag = IRQF_SHARED;
for (i = 0, up = serial8250_ports;
i < ARRAY_SIZE(old_serial_port) && i < nr_uarts;
i++, up++) {
struct uart_port *port = &up->port;
port->iobase = old_serial_port[i].port;
port->irq = irq_canonicalize(old_serial_port[i].irq);
port->irqflags = 0;
port->uartclk = old_serial_port[i].baud_base * 16;
port->flags = old_serial_port[i].flags;
port->hub6 = 0;
port->membase = old_serial_port[i].iomem_base;
port->iotype = old_serial_port[i].io_type;
port->regshift = old_serial_port[i].iomem_reg_shift;
port->irqflags |= irqflag;
if (serial8250_isa_config != NULL)
serial8250_isa_config(i, &up->port, &up->capabilities);
}
}
static void __init
serial8250_register_ports(struct uart_driver *drv, struct device *dev)
{ {
int i; int i;
...@@ -721,7 +520,7 @@ console_initcall(univ8250_console_init); ...@@ -721,7 +520,7 @@ console_initcall(univ8250_console_init);
#define SERIAL8250_CONSOLE NULL #define SERIAL8250_CONSOLE NULL
#endif #endif
static struct uart_driver serial8250_reg = { struct uart_driver serial8250_reg = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.driver_name = "serial", .driver_name = "serial",
.dev_name = "ttyS", .dev_name = "ttyS",
...@@ -822,120 +621,6 @@ void serial8250_resume_port(int line) ...@@ -822,120 +621,6 @@ void serial8250_resume_port(int line)
} }
EXPORT_SYMBOL(serial8250_resume_port); EXPORT_SYMBOL(serial8250_resume_port);
/*
* Register a set of serial devices attached to a platform device. The
* list is terminated with a zero flags entry, which means we expect
* all entries to have at least UPF_BOOT_AUTOCONF set.
*/
static int serial8250_probe(struct platform_device *dev)
{
struct plat_serial8250_port *p = dev_get_platdata(&dev->dev);
struct uart_8250_port uart;
int ret, i, irqflag = 0;
memset(&uart, 0, sizeof(uart));
if (share_irqs)
irqflag = IRQF_SHARED;
for (i = 0; p && p->flags != 0; p++, i++) {
uart.port.iobase = p->iobase;
uart.port.membase = p->membase;
uart.port.irq = p->irq;
uart.port.irqflags = p->irqflags;
uart.port.uartclk = p->uartclk;
uart.port.regshift = p->regshift;
uart.port.iotype = p->iotype;
uart.port.flags = p->flags;
uart.port.mapbase = p->mapbase;
uart.port.mapsize = p->mapsize;
uart.port.hub6 = p->hub6;
uart.port.has_sysrq = p->has_sysrq;
uart.port.private_data = p->private_data;
uart.port.type = p->type;
uart.bugs = p->bugs;
uart.port.serial_in = p->serial_in;
uart.port.serial_out = p->serial_out;
uart.dl_read = p->dl_read;
uart.dl_write = p->dl_write;
uart.port.handle_irq = p->handle_irq;
uart.port.handle_break = p->handle_break;
uart.port.set_termios = p->set_termios;
uart.port.set_ldisc = p->set_ldisc;
uart.port.get_mctrl = p->get_mctrl;
uart.port.pm = p->pm;
uart.port.dev = &dev->dev;
uart.port.irqflags |= irqflag;
ret = serial8250_register_8250_port(&uart);
if (ret < 0) {
dev_err(&dev->dev, "unable to register port at index %d "
"(IO%lx MEM%llx IRQ%d): %d\n", i,
p->iobase, (unsigned long long)p->mapbase,
p->irq, ret);
}
}
return 0;
}
/*
* Remove serial ports registered against a platform device.
*/
static void serial8250_remove(struct platform_device *dev)
{
int i;
for (i = 0; i < nr_uarts; i++) {
struct uart_8250_port *up = &serial8250_ports[i];
if (up->port.dev == &dev->dev)
serial8250_unregister_port(i);
}
}
static int serial8250_suspend(struct platform_device *dev, pm_message_t state)
{
int i;
for (i = 0; i < UART_NR; i++) {
struct uart_8250_port *up = &serial8250_ports[i];
if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
uart_suspend_port(&serial8250_reg, &up->port);
}
return 0;
}
static int serial8250_resume(struct platform_device *dev)
{
int i;
for (i = 0; i < UART_NR; i++) {
struct uart_8250_port *up = &serial8250_ports[i];
if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
serial8250_resume_port(i);
}
return 0;
}
static struct platform_driver serial8250_isa_driver = {
.probe = serial8250_probe,
.remove_new = serial8250_remove,
.suspend = serial8250_suspend,
.resume = serial8250_resume,
.driver = {
.name = "serial8250",
},
};
/*
* This "device" covers _all_ ISA 8250-compatible serial devices listed
* in the table in include/asm/serial.h
*/
static struct platform_device *serial8250_isa_devs;
/* /*
* serial8250_register_8250_port and serial8250_unregister_port allows for * serial8250_register_8250_port and serial8250_unregister_port allows for
* 16x50 serial ports to be configured at run-time, to support PCMCIA * 16x50 serial ports to be configured at run-time, to support PCMCIA
...@@ -1212,134 +897,5 @@ void serial8250_unregister_port(int line) ...@@ -1212,134 +897,5 @@ void serial8250_unregister_port(int line)
} }
EXPORT_SYMBOL(serial8250_unregister_port); EXPORT_SYMBOL(serial8250_unregister_port);
static int __init serial8250_init(void)
{
int ret;
if (nr_uarts == 0)
return -ENODEV;
serial8250_isa_init_ports();
pr_info("Serial: 8250/16550 driver, %d ports, IRQ sharing %s\n",
nr_uarts, str_enabled_disabled(share_irqs));
#ifdef CONFIG_SPARC
ret = sunserial_register_minors(&serial8250_reg, UART_NR);
#else
serial8250_reg.nr = UART_NR;
ret = uart_register_driver(&serial8250_reg);
#endif
if (ret)
goto out;
ret = serial8250_pnp_init();
if (ret)
goto unreg_uart_drv;
serial8250_isa_devs = platform_device_alloc("serial8250",
PLAT8250_DEV_LEGACY);
if (!serial8250_isa_devs) {
ret = -ENOMEM;
goto unreg_pnp;
}
ret = platform_device_add(serial8250_isa_devs);
if (ret)
goto put_dev;
serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev);
ret = platform_driver_register(&serial8250_isa_driver);
if (ret == 0)
goto out;
platform_device_del(serial8250_isa_devs);
put_dev:
platform_device_put(serial8250_isa_devs);
unreg_pnp:
serial8250_pnp_exit();
unreg_uart_drv:
#ifdef CONFIG_SPARC
sunserial_unregister_minors(&serial8250_reg, UART_NR);
#else
uart_unregister_driver(&serial8250_reg);
#endif
out:
return ret;
}
static void __exit serial8250_exit(void)
{
struct platform_device *isa_dev = serial8250_isa_devs;
/*
* This tells serial8250_unregister_port() not to re-register
* the ports (thereby making serial8250_isa_driver permanently
* in use.)
*/
serial8250_isa_devs = NULL;
platform_driver_unregister(&serial8250_isa_driver);
platform_device_unregister(isa_dev);
serial8250_pnp_exit();
#ifdef CONFIG_SPARC
sunserial_unregister_minors(&serial8250_reg, UART_NR);
#else
uart_unregister_driver(&serial8250_reg);
#endif
}
module_init(serial8250_init);
module_exit(serial8250_exit);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Generic 8250/16x50 serial driver"); MODULE_DESCRIPTION("Generic 8250/16x50 serial driver");
module_param_hw(share_irqs, uint, other, 0644);
MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices (unsafe)");
module_param(nr_uarts, uint, 0644);
MODULE_PARM_DESC(nr_uarts, "Maximum number of UARTs supported. (1-" __MODULE_STRING(CONFIG_SERIAL_8250_NR_UARTS) ")");
module_param(skip_txen_test, uint, 0644);
MODULE_PARM_DESC(skip_txen_test, "Skip checking for the TXEN bug at init time");
#ifdef CONFIG_SERIAL_8250_RSA
module_param_hw_array(probe_rsa, ulong, ioport, &probe_rsa_count, 0444);
MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA");
#endif
MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR);
#ifdef CONFIG_SERIAL_8250_DEPRECATED_OPTIONS
#ifndef MODULE
/* This module was renamed to 8250_core in 3.7. Keep the old "8250" name
* working as well for the module options so we don't break people. We
* need to keep the names identical and the convenient macros will happily
* refuse to let us do that by failing the build with redefinition errors
* of global variables. So we stick them inside a dummy function to avoid
* those conflicts. The options still get parsed, and the redefined
* MODULE_PARAM_PREFIX lets us keep the "8250." syntax alive.
*
* This is hacky. I'm sorry.
*/
static void __used s8250_options(void)
{
#undef MODULE_PARAM_PREFIX
#define MODULE_PARAM_PREFIX "8250_core."
module_param_cb(share_irqs, &param_ops_uint, &share_irqs, 0644);
module_param_cb(nr_uarts, &param_ops_uint, &nr_uarts, 0644);
module_param_cb(skip_txen_test, &param_ops_uint, &skip_txen_test, 0644);
#ifdef CONFIG_SERIAL_8250_RSA
__module_param_call(MODULE_PARAM_PREFIX, probe_rsa,
&param_array_ops, .arr = &__param_arr_probe_rsa,
0444, -1, 0);
#endif
}
#else
MODULE_ALIAS("8250_core");
#endif
#endif
...@@ -616,7 +616,7 @@ static int dw8250_probe(struct platform_device *pdev) ...@@ -616,7 +616,7 @@ static int dw8250_probe(struct platform_device *pdev)
if (IS_ERR(data->pclk)) if (IS_ERR(data->pclk))
return PTR_ERR(data->pclk); return PTR_ERR(data->pclk);
data->rst = devm_reset_control_get_optional_exclusive(dev, NULL); data->rst = devm_reset_control_array_get_optional_exclusive(dev);
if (IS_ERR(data->rst)) if (IS_ERR(data->rst))
return PTR_ERR(data->rst); return PTR_ERR(data->rst);
......
...@@ -127,4 +127,5 @@ static int __init probe_serial_gsc(void) ...@@ -127,4 +127,5 @@ static int __init probe_serial_gsc(void)
module_init(probe_serial_gsc); module_init(probe_serial_gsc);
MODULE_DESCRIPTION("Serial Device Initialisation for Lasi/Asp/Wax/Dino");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -37,4 +37,5 @@ int serial8250_pci_setup_port(struct pci_dev *dev, struct uart_8250_port *port, ...@@ -37,4 +37,5 @@ int serial8250_pci_setup_port(struct pci_dev *dev, struct uart_8250_port *port,
return 0; return 0;
} }
EXPORT_SYMBOL_NS_GPL(serial8250_pci_setup_port, SERIAL_8250_PCI); EXPORT_SYMBOL_NS_GPL(serial8250_pci_setup_port, SERIAL_8250_PCI);
MODULE_DESCRIPTION("8250 PCI library");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
// SPDX-License-Identifier: GPL-2.0+
/*
* Universal/legacy platform driver for 8250/16550-type serial ports
*
* Supports: ISA-compatible 8250/16550 ports
* PNP 8250/16550 ports
* "serial8250" platform devices
*/
#include <linux/array_size.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/once.h>
#include <linux/platform_device.h>
#include <linux/serial_8250.h>
#ifdef CONFIG_SPARC
#include <linux/sunserialcore.h>
#endif
#include "8250.h"
/*
* Configuration:
* share_irqs Whether we pass IRQF_SHARED to request_irq().
* This option is unsafe when used on edge-triggered interrupts.
* skip_txen_test Force skip of txen test at init time.
*/
unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
unsigned int skip_txen_test;
unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS;
#include <asm/serial.h>
/*
* SERIAL_PORT_DFNS tells us about built-in ports that have no
* standard enumeration mechanism. Platforms that can find all
* serial ports via mechanisms like ACPI or PCI need not supply it.
*/
#ifndef SERIAL_PORT_DFNS
#define SERIAL_PORT_DFNS
#endif
static const struct old_serial_port old_serial_port[] = {
SERIAL_PORT_DFNS /* defined in asm/serial.h */
};
serial8250_isa_config_fn serial8250_isa_config;
void serial8250_set_isa_configurator(serial8250_isa_config_fn v)
{
serial8250_isa_config = v;
}
EXPORT_SYMBOL(serial8250_set_isa_configurator);
static void __init __serial8250_isa_init_ports(void)
{
int i, irqflag = 0;
if (nr_uarts > UART_NR)
nr_uarts = UART_NR;
/*
* Set up initial isa ports based on nr_uart module param, or else
* default to CONFIG_SERIAL_8250_RUNTIME_UARTS. Note that we do not
* need to increase nr_uarts when setting up the initial isa ports.
*/
for (i = 0; i < nr_uarts; i++)
serial8250_setup_port(i);
/* chain base port ops to support Remote Supervisor Adapter */
univ8250_port_ops = *univ8250_port_base_ops;
univ8250_rsa_support(&univ8250_port_ops);
if (share_irqs)
irqflag = IRQF_SHARED;
for (i = 0; i < ARRAY_SIZE(old_serial_port) && i < nr_uarts; i++) {
struct uart_8250_port *up = serial8250_get_port(i);
struct uart_port *port = &up->port;
port->iobase = old_serial_port[i].port;
port->irq = irq_canonicalize(old_serial_port[i].irq);
port->irqflags = 0;
port->uartclk = old_serial_port[i].baud_base * 16;
port->flags = old_serial_port[i].flags;
port->hub6 = 0;
port->membase = old_serial_port[i].iomem_base;
port->iotype = old_serial_port[i].io_type;
port->regshift = old_serial_port[i].iomem_reg_shift;
port->irqflags |= irqflag;
if (serial8250_isa_config != NULL)
serial8250_isa_config(i, &up->port, &up->capabilities);
}
}
void __init serial8250_isa_init_ports(void)
{
DO_ONCE(__serial8250_isa_init_ports);
}
/*
* Register a set of serial devices attached to a platform device. The
* list is terminated with a zero flags entry, which means we expect
* all entries to have at least UPF_BOOT_AUTOCONF set.
*/
static int serial8250_probe(struct platform_device *dev)
{
struct plat_serial8250_port *p = dev_get_platdata(&dev->dev);
struct uart_8250_port uart;
int ret, i, irqflag = 0;
memset(&uart, 0, sizeof(uart));
if (share_irqs)
irqflag = IRQF_SHARED;
for (i = 0; p && p->flags != 0; p++, i++) {
uart.port.iobase = p->iobase;
uart.port.membase = p->membase;
uart.port.irq = p->irq;
uart.port.irqflags = p->irqflags;
uart.port.uartclk = p->uartclk;
uart.port.regshift = p->regshift;
uart.port.iotype = p->iotype;
uart.port.flags = p->flags;
uart.port.mapbase = p->mapbase;
uart.port.mapsize = p->mapsize;
uart.port.hub6 = p->hub6;
uart.port.has_sysrq = p->has_sysrq;
uart.port.private_data = p->private_data;
uart.port.type = p->type;
uart.bugs = p->bugs;
uart.port.serial_in = p->serial_in;
uart.port.serial_out = p->serial_out;
uart.dl_read = p->dl_read;
uart.dl_write = p->dl_write;
uart.port.handle_irq = p->handle_irq;
uart.port.handle_break = p->handle_break;
uart.port.set_termios = p->set_termios;
uart.port.set_ldisc = p->set_ldisc;
uart.port.get_mctrl = p->get_mctrl;
uart.port.pm = p->pm;
uart.port.dev = &dev->dev;
uart.port.irqflags |= irqflag;
ret = serial8250_register_8250_port(&uart);
if (ret < 0) {
dev_err(&dev->dev, "unable to register port at index %d "
"(IO%lx MEM%llx IRQ%d): %d\n", i,
p->iobase, (unsigned long long)p->mapbase,
p->irq, ret);
}
}
return 0;
}
/*
* Remove serial ports registered against a platform device.
*/
static void serial8250_remove(struct platform_device *dev)
{
int i;
for (i = 0; i < nr_uarts; i++) {
struct uart_8250_port *up = serial8250_get_port(i);
if (up->port.dev == &dev->dev)
serial8250_unregister_port(i);
}
}
static int serial8250_suspend(struct platform_device *dev, pm_message_t state)
{
int i;
for (i = 0; i < UART_NR; i++) {
struct uart_8250_port *up = serial8250_get_port(i);
if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
uart_suspend_port(&serial8250_reg, &up->port);
}
return 0;
}
static int serial8250_resume(struct platform_device *dev)
{
int i;
for (i = 0; i < UART_NR; i++) {
struct uart_8250_port *up = serial8250_get_port(i);
if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
serial8250_resume_port(i);
}
return 0;
}
static struct platform_driver serial8250_isa_driver = {
.probe = serial8250_probe,
.remove_new = serial8250_remove,
.suspend = serial8250_suspend,
.resume = serial8250_resume,
.driver = {
.name = "serial8250",
},
};
/*
* This "device" covers _all_ ISA 8250-compatible serial devices listed
* in the table in include/asm/serial.h
*/
struct platform_device *serial8250_isa_devs;
static int __init serial8250_init(void)
{
int ret;
if (nr_uarts == 0)
return -ENODEV;
serial8250_isa_init_ports();
pr_info("Serial: 8250/16550 driver, %d ports, IRQ sharing %s\n",
nr_uarts, str_enabled_disabled(share_irqs));
#ifdef CONFIG_SPARC
ret = sunserial_register_minors(&serial8250_reg, UART_NR);
#else
serial8250_reg.nr = UART_NR;
ret = uart_register_driver(&serial8250_reg);
#endif
if (ret)
goto out;
ret = serial8250_pnp_init();
if (ret)
goto unreg_uart_drv;
serial8250_isa_devs = platform_device_alloc("serial8250",
PLAT8250_DEV_LEGACY);
if (!serial8250_isa_devs) {
ret = -ENOMEM;
goto unreg_pnp;
}
ret = platform_device_add(serial8250_isa_devs);
if (ret)
goto put_dev;
serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev);
ret = platform_driver_register(&serial8250_isa_driver);
if (ret == 0)
goto out;
platform_device_del(serial8250_isa_devs);
put_dev:
platform_device_put(serial8250_isa_devs);
unreg_pnp:
serial8250_pnp_exit();
unreg_uart_drv:
#ifdef CONFIG_SPARC
sunserial_unregister_minors(&serial8250_reg, UART_NR);
#else
uart_unregister_driver(&serial8250_reg);
#endif
out:
return ret;
}
module_init(serial8250_init);
static void __exit serial8250_exit(void)
{
struct platform_device *isa_dev = serial8250_isa_devs;
/*
* This tells serial8250_unregister_port() not to re-register
* the ports (thereby making serial8250_isa_driver permanently
* in use.)
*/
serial8250_isa_devs = NULL;
platform_driver_unregister(&serial8250_isa_driver);
platform_device_unregister(isa_dev);
serial8250_pnp_exit();
#ifdef CONFIG_SPARC
sunserial_unregister_minors(&serial8250_reg, UART_NR);
#else
uart_unregister_driver(&serial8250_reg);
#endif
}
module_exit(serial8250_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Generic 8250/16x50 serial platform driver");
module_param_hw(share_irqs, uint, other, 0644);
MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices (unsafe)");
module_param(nr_uarts, uint, 0644);
MODULE_PARM_DESC(nr_uarts, "Maximum number of UARTs supported. (1-" __MODULE_STRING(CONFIG_SERIAL_8250_NR_UARTS) ")");
module_param(skip_txen_test, uint, 0644);
MODULE_PARM_DESC(skip_txen_test, "Skip checking for the TXEN bug at init time");
MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR);
#ifdef CONFIG_SERIAL_8250_DEPRECATED_OPTIONS
#ifndef MODULE
/* This module was renamed to 8250_core in 3.7. Keep the old "8250" name
* working as well for the module options so we don't break people. We
* need to keep the names identical and the convenient macros will happily
* refuse to let us do that by failing the build with redefinition errors
* of global variables. So we stick them inside a dummy function to avoid
* those conflicts. The options still get parsed, and the redefined
* MODULE_PARAM_PREFIX lets us keep the "8250." syntax alive.
*
* This is hacky. I'm sorry.
*/
static void __used s8250_options(void)
{
#undef MODULE_PARAM_PREFIX
#define MODULE_PARAM_PREFIX "8250_core."
module_param_cb(share_irqs, &param_ops_uint, &share_irqs, 0644);
module_param_cb(nr_uarts, &param_ops_uint, &nr_uarts, 0644);
module_param_cb(skip_txen_test, &param_ops_uint, &skip_txen_test, 0644);
}
#else
MODULE_ALIAS("8250_core");
#endif
#endif
...@@ -3473,4 +3473,5 @@ int serial8250_console_exit(struct uart_port *port) ...@@ -3473,4 +3473,5 @@ int serial8250_console_exit(struct uart_port *port)
#endif /* CONFIG_SERIAL_8250_CONSOLE */ #endif /* CONFIG_SERIAL_8250_CONSOLE */
MODULE_DESCRIPTION("Base port operations for 8250/16550-type serial ports");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -182,5 +182,6 @@ OF_EARLYCON_DECLARE(mmp, "mrvl,mmp-uart", early_serial_pxa_setup); ...@@ -182,5 +182,6 @@ OF_EARLYCON_DECLARE(mmp, "mrvl,mmp-uart", early_serial_pxa_setup);
#endif #endif
MODULE_AUTHOR("Sergei Ianovich"); MODULE_AUTHOR("Sergei Ianovich");
MODULE_DESCRIPTION("driver for PXA on-board UARTS");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:pxa2xx-uart"); MODULE_ALIAS("platform:pxa2xx-uart");
// SPDX-License-Identifier: GPL-2.0+
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/serial.h>
#include <linux/serial_8250.h>
#include "8250.h"
#define PORT_RSA_MAX 4
static unsigned long probe_rsa[PORT_RSA_MAX];
static unsigned int probe_rsa_count;
static int rsa8250_request_resource(struct uart_8250_port *up)
{
unsigned long start = UART_RSA_BASE << up->port.regshift;
unsigned int size = 8 << up->port.regshift;
struct uart_port *port = &up->port;
int ret = -EINVAL;
switch (port->iotype) {
case UPIO_HUB6:
case UPIO_PORT:
start += port->iobase;
if (request_region(start, size, "serial-rsa"))
ret = 0;
else
ret = -EBUSY;
break;
}
return ret;
}
static void rsa8250_release_resource(struct uart_8250_port *up)
{
unsigned long offset = UART_RSA_BASE << up->port.regshift;
unsigned int size = 8 << up->port.regshift;
struct uart_port *port = &up->port;
switch (port->iotype) {
case UPIO_HUB6:
case UPIO_PORT:
release_region(port->iobase + offset, size);
break;
}
}
static void univ8250_config_port(struct uart_port *port, int flags)
{
struct uart_8250_port *up = up_to_u8250p(port);
unsigned int i;
up->probe &= ~UART_PROBE_RSA;
if (port->type == PORT_RSA) {
if (rsa8250_request_resource(up) == 0)
up->probe |= UART_PROBE_RSA;
} else if (flags & UART_CONFIG_TYPE) {
for (i = 0; i < probe_rsa_count; i++) {
if (probe_rsa[i] == up->port.iobase) {
if (rsa8250_request_resource(up) == 0)
up->probe |= UART_PROBE_RSA;
break;
}
}
}
univ8250_port_base_ops->config_port(port, flags);
if (port->type != PORT_RSA && up->probe & UART_PROBE_RSA)
rsa8250_release_resource(up);
}
static int univ8250_request_port(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
int ret;
ret = univ8250_port_base_ops->request_port(port);
if (ret == 0 && port->type == PORT_RSA) {
ret = rsa8250_request_resource(up);
if (ret < 0)
univ8250_port_base_ops->release_port(port);
}
return ret;
}
static void univ8250_release_port(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
if (port->type == PORT_RSA)
rsa8250_release_resource(up);
univ8250_port_base_ops->release_port(port);
}
void univ8250_rsa_support(struct uart_ops *ops)
{
ops->config_port = univ8250_config_port;
ops->request_port = univ8250_request_port;
ops->release_port = univ8250_release_port;
}
module_param_hw_array(probe_rsa, ulong, ioport, &probe_rsa_count, 0444);
MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA");
#ifdef CONFIG_SERIAL_8250_DEPRECATED_OPTIONS
#ifndef MODULE
/*
* Keep the old "8250" name working as well for the module options so we don't
* break people. We need to keep the names identical and the convenient macros
* will happily refuse to let us do that by failing the build with redefinition
* errors of global variables. So we stick them inside a dummy function to
* avoid those conflicts. The options still get parsed, and the redefined
* MODULE_PARAM_PREFIX lets us keep the "8250." syntax alive.
*
* This is hacky. I'm sorry.
*/
static void __used rsa8250_options(void)
{
#undef MODULE_PARAM_PREFIX
#define MODULE_PARAM_PREFIX "8250_core."
__module_param_call(MODULE_PARAM_PREFIX, probe_rsa,
&param_array_ops, .arr = &__param_arr_probe_rsa,
0444, -1, 0);
}
#endif
#endif
...@@ -3,9 +3,13 @@ ...@@ -3,9 +3,13 @@
# Makefile for the 8250 serial device drivers. # Makefile for the 8250 serial device drivers.
# #
obj-$(CONFIG_SERIAL_8250) += 8250.o 8250_base.o obj-$(CONFIG_SERIAL_8250) += 8250.o
8250-y := 8250_core.o 8250-y := 8250_core.o
8250-y += 8250_platform.o
8250-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o 8250-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
8250-$(CONFIG_SERIAL_8250_RSA) += 8250_rsa.o
obj-$(CONFIG_SERIAL_8250) += 8250_base.o
8250_base-y := 8250_port.o 8250_base-y := 8250_port.o
8250_base-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o 8250_base-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o
8250_base-$(CONFIG_SERIAL_8250_DWLIB) += 8250_dwlib.o 8250_base-$(CONFIG_SERIAL_8250_DWLIB) += 8250_dwlib.o
......
...@@ -864,4 +864,5 @@ static struct pcmcia_driver serial_cs_driver = { ...@@ -864,4 +864,5 @@ static struct pcmcia_driver serial_cs_driver = {
}; };
module_pcmcia_driver(serial_cs_driver); module_pcmcia_driver(serial_cs_driver);
MODULE_DESCRIPTION("driver for PCMCIA serial devices");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -455,4 +455,5 @@ module_init(esp32s3_acm_init); ...@@ -455,4 +455,5 @@ module_init(esp32s3_acm_init);
module_exit(esp32s3_acm_exit); module_exit(esp32s3_acm_exit);
MODULE_AUTHOR("Max Filippov <jcmvbkbc@gmail.com>"); MODULE_AUTHOR("Max Filippov <jcmvbkbc@gmail.com>");
MODULE_DESCRIPTION("Espressif ESP32 USB ACM gadget support");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -775,4 +775,5 @@ module_init(esp32_uart_init); ...@@ -775,4 +775,5 @@ module_init(esp32_uart_init);
module_exit(esp32_uart_exit); module_exit(esp32_uart_exit);
MODULE_AUTHOR("Max Filippov <jcmvbkbc@gmail.com>"); MODULE_AUTHOR("Max Filippov <jcmvbkbc@gmail.com>");
MODULE_DESCRIPTION("Espressif ESP32 UART support");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -265,6 +265,11 @@ static const struct of_device_id imx_uart_dt_ids[] = { ...@@ -265,6 +265,11 @@ static const struct of_device_id imx_uart_dt_ids[] = {
}; };
MODULE_DEVICE_TABLE(of, imx_uart_dt_ids); MODULE_DEVICE_TABLE(of, imx_uart_dt_ids);
static inline struct imx_port *to_imx_port(struct uart_port *port)
{
return container_of(port, struct imx_port, port);
}
static inline void imx_uart_writel(struct imx_port *sport, u32 val, u32 offset) static inline void imx_uart_writel(struct imx_port *sport, u32 val, u32 offset)
{ {
writel(val, sport->port.membase + offset); writel(val, sport->port.membase + offset);
...@@ -378,7 +383,7 @@ static void imx_uart_disable_loopback_rs485(struct imx_port *sport) ...@@ -378,7 +383,7 @@ static void imx_uart_disable_loopback_rs485(struct imx_port *sport)
/* called with port.lock taken and irqs off */ /* called with port.lock taken and irqs off */
static void imx_uart_start_rx(struct uart_port *port) static void imx_uart_start_rx(struct uart_port *port)
{ {
struct imx_port *sport = (struct imx_port *)port; struct imx_port *sport = to_imx_port(port);
unsigned int ucr1, ucr2; unsigned int ucr1, ucr2;
ucr1 = imx_uart_readl(sport, UCR1); ucr1 = imx_uart_readl(sport, UCR1);
...@@ -402,7 +407,7 @@ static void imx_uart_start_rx(struct uart_port *port) ...@@ -402,7 +407,7 @@ static void imx_uart_start_rx(struct uart_port *port)
/* called with port.lock taken and irqs off */ /* called with port.lock taken and irqs off */
static void imx_uart_stop_tx(struct uart_port *port) static void imx_uart_stop_tx(struct uart_port *port)
{ {
struct imx_port *sport = (struct imx_port *)port; struct imx_port *sport = to_imx_port(port);
u32 ucr1, ucr4, usr2; u32 ucr1, ucr4, usr2;
if (sport->tx_state == OFF) if (sport->tx_state == OFF)
...@@ -467,7 +472,7 @@ static void imx_uart_stop_tx(struct uart_port *port) ...@@ -467,7 +472,7 @@ static void imx_uart_stop_tx(struct uart_port *port)
static void imx_uart_stop_rx_with_loopback_ctrl(struct uart_port *port, bool loopback) static void imx_uart_stop_rx_with_loopback_ctrl(struct uart_port *port, bool loopback)
{ {
struct imx_port *sport = (struct imx_port *)port; struct imx_port *sport = to_imx_port(port);
u32 ucr1, ucr2, ucr4, uts; u32 ucr1, ucr2, ucr4, uts;
ucr1 = imx_uart_readl(sport, UCR1); ucr1 = imx_uart_readl(sport, UCR1);
...@@ -512,7 +517,7 @@ static void imx_uart_stop_rx(struct uart_port *port) ...@@ -512,7 +517,7 @@ static void imx_uart_stop_rx(struct uart_port *port)
/* called with port.lock taken and irqs off */ /* called with port.lock taken and irqs off */
static void imx_uart_enable_ms(struct uart_port *port) static void imx_uart_enable_ms(struct uart_port *port)
{ {
struct imx_port *sport = (struct imx_port *)port; struct imx_port *sport = to_imx_port(port);
mod_timer(&sport->timer, jiffies); mod_timer(&sport->timer, jiffies);
...@@ -663,7 +668,7 @@ static void imx_uart_dma_tx(struct imx_port *sport) ...@@ -663,7 +668,7 @@ static void imx_uart_dma_tx(struct imx_port *sport)
/* called with port.lock taken and irqs off */ /* called with port.lock taken and irqs off */
static void imx_uart_start_tx(struct uart_port *port) static void imx_uart_start_tx(struct uart_port *port)
{ {
struct imx_port *sport = (struct imx_port *)port; struct imx_port *sport = to_imx_port(port);
struct tty_port *tport = &sport->port.state->port; struct tty_port *tport = &sport->port.state->port;
u32 ucr1; u32 ucr1;
...@@ -1044,7 +1049,7 @@ static irqreturn_t imx_uart_int(int irq, void *dev_id) ...@@ -1044,7 +1049,7 @@ static irqreturn_t imx_uart_int(int irq, void *dev_id)
*/ */
static unsigned int imx_uart_tx_empty(struct uart_port *port) static unsigned int imx_uart_tx_empty(struct uart_port *port)
{ {
struct imx_port *sport = (struct imx_port *)port; struct imx_port *sport = to_imx_port(port);
unsigned int ret; unsigned int ret;
ret = (imx_uart_readl(sport, USR2) & USR2_TXDC) ? TIOCSER_TEMT : 0; ret = (imx_uart_readl(sport, USR2) & USR2_TXDC) ? TIOCSER_TEMT : 0;
...@@ -1059,7 +1064,7 @@ static unsigned int imx_uart_tx_empty(struct uart_port *port) ...@@ -1059,7 +1064,7 @@ static unsigned int imx_uart_tx_empty(struct uart_port *port)
/* called with port.lock taken and irqs off */ /* called with port.lock taken and irqs off */
static unsigned int imx_uart_get_mctrl(struct uart_port *port) static unsigned int imx_uart_get_mctrl(struct uart_port *port)
{ {
struct imx_port *sport = (struct imx_port *)port; struct imx_port *sport = to_imx_port(port);
unsigned int ret = imx_uart_get_hwmctrl(sport); unsigned int ret = imx_uart_get_hwmctrl(sport);
mctrl_gpio_get(sport->gpios, &ret); mctrl_gpio_get(sport->gpios, &ret);
...@@ -1070,7 +1075,7 @@ static unsigned int imx_uart_get_mctrl(struct uart_port *port) ...@@ -1070,7 +1075,7 @@ static unsigned int imx_uart_get_mctrl(struct uart_port *port)
/* called with port.lock taken and irqs off */ /* called with port.lock taken and irqs off */
static void imx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) static void imx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{ {
struct imx_port *sport = (struct imx_port *)port; struct imx_port *sport = to_imx_port(port);
u32 ucr3, uts; u32 ucr3, uts;
if (!(port->rs485.flags & SER_RS485_ENABLED)) { if (!(port->rs485.flags & SER_RS485_ENABLED)) {
...@@ -1113,7 +1118,7 @@ static void imx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) ...@@ -1113,7 +1118,7 @@ static void imx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
*/ */
static void imx_uart_break_ctl(struct uart_port *port, int break_state) static void imx_uart_break_ctl(struct uart_port *port, int break_state)
{ {
struct imx_port *sport = (struct imx_port *)port; struct imx_port *sport = to_imx_port(port);
unsigned long flags; unsigned long flags;
u32 ucr1; u32 ucr1;
...@@ -1435,7 +1440,7 @@ static void imx_uart_disable_dma(struct imx_port *sport) ...@@ -1435,7 +1440,7 @@ static void imx_uart_disable_dma(struct imx_port *sport)
static int imx_uart_startup(struct uart_port *port) static int imx_uart_startup(struct uart_port *port)
{ {
struct imx_port *sport = (struct imx_port *)port; struct imx_port *sport = to_imx_port(port);
int retval; int retval;
unsigned long flags; unsigned long flags;
int dma_is_inited = 0; int dma_is_inited = 0;
...@@ -1549,7 +1554,7 @@ static int imx_uart_startup(struct uart_port *port) ...@@ -1549,7 +1554,7 @@ static int imx_uart_startup(struct uart_port *port)
static void imx_uart_shutdown(struct uart_port *port) static void imx_uart_shutdown(struct uart_port *port)
{ {
struct imx_port *sport = (struct imx_port *)port; struct imx_port *sport = to_imx_port(port);
unsigned long flags; unsigned long flags;
u32 ucr1, ucr2, ucr4, uts; u32 ucr1, ucr2, ucr4, uts;
int loops; int loops;
...@@ -1674,7 +1679,7 @@ static void imx_uart_shutdown(struct uart_port *port) ...@@ -1674,7 +1679,7 @@ static void imx_uart_shutdown(struct uart_port *port)
/* called with port.lock taken and irqs off */ /* called with port.lock taken and irqs off */
static void imx_uart_flush_buffer(struct uart_port *port) static void imx_uart_flush_buffer(struct uart_port *port)
{ {
struct imx_port *sport = (struct imx_port *)port; struct imx_port *sport = to_imx_port(port);
struct scatterlist *sgl = &sport->tx_sgl[0]; struct scatterlist *sgl = &sport->tx_sgl[0];
if (!sport->dma_chan_tx) if (!sport->dma_chan_tx)
...@@ -1701,7 +1706,7 @@ static void ...@@ -1701,7 +1706,7 @@ static void
imx_uart_set_termios(struct uart_port *port, struct ktermios *termios, imx_uart_set_termios(struct uart_port *port, struct ktermios *termios,
const struct ktermios *old) const struct ktermios *old)
{ {
struct imx_port *sport = (struct imx_port *)port; struct imx_port *sport = to_imx_port(port);
unsigned long flags; unsigned long flags;
u32 ucr2, old_ucr2, ufcr; u32 ucr2, old_ucr2, ufcr;
unsigned int baud, quot; unsigned int baud, quot;
...@@ -1904,7 +1909,7 @@ imx_uart_verify_port(struct uart_port *port, struct serial_struct *ser) ...@@ -1904,7 +1909,7 @@ imx_uart_verify_port(struct uart_port *port, struct serial_struct *ser)
static int imx_uart_poll_init(struct uart_port *port) static int imx_uart_poll_init(struct uart_port *port)
{ {
struct imx_port *sport = (struct imx_port *)port; struct imx_port *sport = to_imx_port(port);
unsigned long flags; unsigned long flags;
u32 ucr1, ucr2; u32 ucr1, ucr2;
int retval; int retval;
...@@ -1953,7 +1958,7 @@ static int imx_uart_poll_init(struct uart_port *port) ...@@ -1953,7 +1958,7 @@ static int imx_uart_poll_init(struct uart_port *port)
static int imx_uart_poll_get_char(struct uart_port *port) static int imx_uart_poll_get_char(struct uart_port *port)
{ {
struct imx_port *sport = (struct imx_port *)port; struct imx_port *sport = to_imx_port(port);
if (!(imx_uart_readl(sport, USR2) & USR2_RDR)) if (!(imx_uart_readl(sport, USR2) & USR2_RDR))
return NO_POLL_CHAR; return NO_POLL_CHAR;
...@@ -1962,7 +1967,7 @@ static int imx_uart_poll_get_char(struct uart_port *port) ...@@ -1962,7 +1967,7 @@ static int imx_uart_poll_get_char(struct uart_port *port)
static void imx_uart_poll_put_char(struct uart_port *port, unsigned char c) static void imx_uart_poll_put_char(struct uart_port *port, unsigned char c)
{ {
struct imx_port *sport = (struct imx_port *)port; struct imx_port *sport = to_imx_port(port);
unsigned int status; unsigned int status;
/* drain */ /* drain */
...@@ -1984,7 +1989,7 @@ static void imx_uart_poll_put_char(struct uart_port *port, unsigned char c) ...@@ -1984,7 +1989,7 @@ static void imx_uart_poll_put_char(struct uart_port *port, unsigned char c)
static int imx_uart_rs485_config(struct uart_port *port, struct ktermios *termios, static int imx_uart_rs485_config(struct uart_port *port, struct ktermios *termios,
struct serial_rs485 *rs485conf) struct serial_rs485 *rs485conf)
{ {
struct imx_port *sport = (struct imx_port *)port; struct imx_port *sport = to_imx_port(port);
u32 ucr2, ufcr; u32 ucr2, ufcr;
if (rs485conf->flags & SER_RS485_ENABLED) { if (rs485conf->flags & SER_RS485_ENABLED) {
...@@ -2043,7 +2048,7 @@ static struct imx_port *imx_uart_ports[UART_NR]; ...@@ -2043,7 +2048,7 @@ static struct imx_port *imx_uart_ports[UART_NR];
#if IS_ENABLED(CONFIG_SERIAL_IMX_CONSOLE) #if IS_ENABLED(CONFIG_SERIAL_IMX_CONSOLE)
static void imx_uart_console_putchar(struct uart_port *port, unsigned char ch) static void imx_uart_console_putchar(struct uart_port *port, unsigned char ch)
{ {
struct imx_port *sport = (struct imx_port *)port; struct imx_port *sport = to_imx_port(port);
while (imx_uart_readl(sport, imx_uart_uts_reg(sport)) & UTS_TXFULL) while (imx_uart_readl(sport, imx_uart_uts_reg(sport)) & UTS_TXFULL)
barrier(); barrier();
......
...@@ -761,4 +761,5 @@ static void __exit owl_uart_exit(void) ...@@ -761,4 +761,5 @@ static void __exit owl_uart_exit(void)
module_init(owl_uart_init); module_init(owl_uart_init);
module_exit(owl_uart_exit); module_exit(owl_uart_exit);
MODULE_DESCRIPTION("Actions Semi Owl family serial console");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
#include <linux/idr.h> #include <linux/idr.h>
#include <linux/kthread.h> #include <linux/kthread.h>
...@@ -1467,6 +1468,29 @@ static const struct serial_rs485 sc16is7xx_rs485_supported = { ...@@ -1467,6 +1468,29 @@ static const struct serial_rs485 sc16is7xx_rs485_supported = {
.delay_rts_after_send = 1, /* Not supported but keep returning -EINVAL */ .delay_rts_after_send = 1, /* Not supported but keep returning -EINVAL */
}; };
/* Reset device, purging any pending irq / data */
static int sc16is7xx_reset(struct device *dev, struct regmap *regmap)
{
struct gpio_desc *reset_gpio;
/* Assert reset GPIO if defined and valid. */
reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(reset_gpio))
return dev_err_probe(dev, PTR_ERR(reset_gpio), "Failed to get reset GPIO\n");
if (reset_gpio) {
/* The minimum reset pulse width is 3 us. */
fsleep(5);
gpiod_set_value_cansleep(reset_gpio, 0); /* Deassert GPIO */
} else {
/* Software reset */
regmap_write(regmap, SC16IS7XX_IOCONTROL_REG,
SC16IS7XX_IOCONTROL_SRESET_BIT);
}
return 0;
}
int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype, int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype,
struct regmap *regmaps[], int irq) struct regmap *regmaps[], int irq)
{ {
...@@ -1536,9 +1560,9 @@ int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype, ...@@ -1536,9 +1560,9 @@ int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype,
} }
sched_set_fifo(s->kworker_task); sched_set_fifo(s->kworker_task);
/* reset device, purging any pending irq / data */ ret = sc16is7xx_reset(dev, regmaps[0]);
regmap_write(regmaps[0], SC16IS7XX_IOCONTROL_REG, if (ret)
SC16IS7XX_IOCONTROL_SRESET_BIT); goto out_kthread;
/* Mark each port line and status as uninitialised. */ /* Mark each port line and status as uninitialised. */
for (i = 0; i < devtype->nr_uart; ++i) { for (i = 0; i < devtype->nr_uart; ++i) {
...@@ -1663,6 +1687,7 @@ int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype, ...@@ -1663,6 +1687,7 @@ int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype,
uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port); uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port);
} }
out_kthread:
kthread_stop(s->kworker_task); kthread_stop(s->kworker_task);
out_clk: out_clk:
......
...@@ -49,3 +49,19 @@ void serial_ctrl_unregister_port(struct uart_driver *drv, struct uart_port *port ...@@ -49,3 +49,19 @@ void serial_ctrl_unregister_port(struct uart_driver *drv, struct uart_port *port
int serial_core_register_port(struct uart_driver *drv, struct uart_port *port); int serial_core_register_port(struct uart_driver *drv, struct uart_port *port);
void serial_core_unregister_port(struct uart_driver *drv, struct uart_port *port); void serial_core_unregister_port(struct uart_driver *drv, struct uart_port *port);
#ifdef CONFIG_SERIAL_CORE_CONSOLE
int serial_base_match_and_update_preferred_console(struct uart_driver *drv,
struct uart_port *port);
#else
static inline
int serial_base_match_and_update_preferred_console(struct uart_driver *drv,
struct uart_port *port)
{
return 0;
}
#endif
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
* The serial core bus manages the serial core controller instances. * The serial core bus manages the serial core controller instances.
*/ */
#include <linux/cleanup.h>
#include <linux/container_of.h> #include <linux/container_of.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/idr.h> #include <linux/idr.h>
...@@ -204,6 +205,42 @@ void serial_base_port_device_remove(struct serial_port_device *port_dev) ...@@ -204,6 +205,42 @@ void serial_base_port_device_remove(struct serial_port_device *port_dev)
put_device(&port_dev->dev); put_device(&port_dev->dev);
} }
#ifdef CONFIG_SERIAL_CORE_CONSOLE
/**
* serial_base_match_and_update_preferred_console - Match and update a preferred console
* @drv: Serial port device driver
* @port: Serial port instance
*
* Tries to match and update the preferred console for a serial port for
* the kernel command line option console=DEVNAME:0.0.
*
* Cannot be called early for ISA ports, depends on struct device.
*
* Return: 0 on success, negative error code on failure.
*/
int serial_base_match_and_update_preferred_console(struct uart_driver *drv,
struct uart_port *port)
{
const char *port_match __free(kfree) = NULL;
int ret;
port_match = kasprintf(GFP_KERNEL, "%s:%d.%d", dev_name(port->dev),
port->ctrl_id, port->port_id);
if (!port_match)
return -ENOMEM;
ret = match_devname_and_update_preferred_console(port_match,
drv->dev_name,
port->line);
if (ret == -ENOENT)
return 0;
return ret;
}
#endif
static int serial_base_init(void) static int serial_base_init(void)
{ {
int ret; int ret;
......
...@@ -3422,6 +3422,10 @@ int serial_core_register_port(struct uart_driver *drv, struct uart_port *port) ...@@ -3422,6 +3422,10 @@ int serial_core_register_port(struct uart_driver *drv, struct uart_port *port)
if (ret) if (ret)
goto err_unregister_ctrl_dev; goto err_unregister_ctrl_dev;
ret = serial_base_match_and_update_preferred_console(drv, port);
if (ret)
goto err_unregister_port_dev;
ret = serial_core_add_one_port(drv, port); ret = serial_core_add_one_port(drv, port);
if (ret) if (ret)
goto err_unregister_port_dev; goto err_unregister_port_dev;
......
...@@ -385,4 +385,5 @@ void mctrl_gpio_disable_irq_wake(struct mctrl_gpios *gpios) ...@@ -385,4 +385,5 @@ void mctrl_gpio_disable_irq_wake(struct mctrl_gpios *gpios)
} }
EXPORT_SYMBOL_GPL(mctrl_gpio_disable_irq_wake); EXPORT_SYMBOL_GPL(mctrl_gpio_disable_irq_wake);
MODULE_DESCRIPTION("Helpers for controlling modem lines via GPIO");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -317,6 +317,37 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { ...@@ -317,6 +317,37 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.error_clear = SCIF_ERROR_CLEAR, .error_clear = SCIF_ERROR_CLEAR,
}, },
/*
* The "SCIF" that is in RZ/V2H(P) SoC is similar to one found on RZ/G2L SoC
* with below differences,
* - Break out of interrupts are different: ERI, BRI, RXI, TXI, TEI, DRI,
* TEI-DRI, RXI-EDGE and TXI-EDGE.
* - SCSMR register does not have CM bit (BIT(7)) ie it does not support synchronous mode.
* - SCFCR register does not have SCFCR_MCE bit.
* - SCSPTR register has only bits SCSPTR_SPB2DT and SCSPTR_SPB2IO.
*/
[SCIx_RZV2H_SCIF_REGTYPE] = {
.regs = {
[SCSMR] = { 0x00, 16 },
[SCBRR] = { 0x02, 8 },
[SCSCR] = { 0x04, 16 },
[SCxTDR] = { 0x06, 8 },
[SCxSR] = { 0x08, 16 },
[SCxRDR] = { 0x0a, 8 },
[SCFCR] = { 0x0c, 16 },
[SCFDR] = { 0x0e, 16 },
[SCSPTR] = { 0x10, 16 },
[SCLSR] = { 0x12, 16 },
[SEMR] = { 0x14, 8 },
},
.fifosize = 16,
.overrun_reg = SCLSR,
.overrun_mask = SCLSR_ORER,
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
},
/* /*
* Common SH-3 SCIF definitions. * Common SH-3 SCIF definitions.
*/ */
...@@ -757,7 +788,7 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag) ...@@ -757,7 +788,7 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag)
} }
sci_serial_out(port, SCPDR, data); sci_serial_out(port, SCPDR, data);
sci_serial_out(port, SCPCR, ctrl); sci_serial_out(port, SCPCR, ctrl);
} else if (sci_getreg(port, SCSPTR)->size) { } else if (sci_getreg(port, SCSPTR)->size && s->cfg->regtype != SCIx_RZV2H_SCIF_REGTYPE) {
u16 status = sci_serial_in(port, SCSPTR); u16 status = sci_serial_in(port, SCSPTR);
/* RTS# is always output; and active low, unless autorts */ /* RTS# is always output; and active low, unless autorts */
...@@ -2124,8 +2155,9 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl) ...@@ -2124,8 +2155,9 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
if (!(mctrl & TIOCM_RTS)) { if (!(mctrl & TIOCM_RTS)) {
/* Disable Auto RTS */ /* Disable Auto RTS */
sci_serial_out(port, SCFCR, if (s->cfg->regtype != SCIx_RZV2H_SCIF_REGTYPE)
sci_serial_in(port, SCFCR) & ~SCFCR_MCE); sci_serial_out(port, SCFCR,
sci_serial_in(port, SCFCR) & ~SCFCR_MCE);
/* Clear RTS */ /* Clear RTS */
sci_set_rts(port, 0); sci_set_rts(port, 0);
...@@ -2137,8 +2169,9 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl) ...@@ -2137,8 +2169,9 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
} }
/* Enable Auto RTS */ /* Enable Auto RTS */
sci_serial_out(port, SCFCR, if (s->cfg->regtype != SCIx_RZV2H_SCIF_REGTYPE)
sci_serial_in(port, SCFCR) | SCFCR_MCE); sci_serial_out(port, SCFCR,
sci_serial_in(port, SCFCR) | SCFCR_MCE);
} else { } else {
/* Set RTS */ /* Set RTS */
sci_set_rts(port, 1); sci_set_rts(port, 1);
...@@ -3225,6 +3258,10 @@ static const struct of_device_id of_sci_match[] __maybe_unused = { ...@@ -3225,6 +3258,10 @@ static const struct of_device_id of_sci_match[] __maybe_unused = {
.compatible = "renesas,scif-r9a07g044", .compatible = "renesas,scif-r9a07g044",
.data = SCI_OF_DATA(PORT_SCIF, SCIx_RZ_SCIFA_REGTYPE), .data = SCI_OF_DATA(PORT_SCIF, SCIx_RZ_SCIFA_REGTYPE),
}, },
{
.compatible = "renesas,scif-r9a09g057",
.data = SCI_OF_DATA(PORT_SCIF, SCIx_RZV2H_SCIF_REGTYPE),
},
/* Family-specific types */ /* Family-specific types */
{ {
.compatible = "renesas,rcar-gen1-scif", .compatible = "renesas,rcar-gen1-scif",
...@@ -3533,6 +3570,13 @@ static int __init rzscifa_early_console_setup(struct earlycon_device *device, ...@@ -3533,6 +3570,13 @@ static int __init rzscifa_early_console_setup(struct earlycon_device *device,
return early_console_setup(device, PORT_SCIF); return early_console_setup(device, PORT_SCIF);
} }
static int __init rzv2hscif_early_console_setup(struct earlycon_device *device,
const char *opt)
{
port_cfg.regtype = SCIx_RZV2H_SCIF_REGTYPE;
return early_console_setup(device, PORT_SCIF);
}
static int __init scifa_early_console_setup(struct earlycon_device *device, static int __init scifa_early_console_setup(struct earlycon_device *device,
const char *opt) const char *opt)
{ {
...@@ -3553,6 +3597,7 @@ OF_EARLYCON_DECLARE(sci, "renesas,sci", sci_early_console_setup); ...@@ -3553,6 +3597,7 @@ OF_EARLYCON_DECLARE(sci, "renesas,sci", sci_early_console_setup);
OF_EARLYCON_DECLARE(scif, "renesas,scif", scif_early_console_setup); OF_EARLYCON_DECLARE(scif, "renesas,scif", scif_early_console_setup);
OF_EARLYCON_DECLARE(scif, "renesas,scif-r7s9210", rzscifa_early_console_setup); OF_EARLYCON_DECLARE(scif, "renesas,scif-r7s9210", rzscifa_early_console_setup);
OF_EARLYCON_DECLARE(scif, "renesas,scif-r9a07g044", rzscifa_early_console_setup); OF_EARLYCON_DECLARE(scif, "renesas,scif-r9a07g044", rzscifa_early_console_setup);
OF_EARLYCON_DECLARE(scif, "renesas,scif-r9a09g057", rzv2hscif_early_console_setup);
OF_EARLYCON_DECLARE(scifa, "renesas,scifa", scifa_early_console_setup); OF_EARLYCON_DECLARE(scifa, "renesas,scifa", scifa_early_console_setup);
OF_EARLYCON_DECLARE(scifb, "renesas,scifb", scifb_early_console_setup); OF_EARLYCON_DECLARE(scifb, "renesas,scifb", scifb_early_console_setup);
OF_EARLYCON_DECLARE(hscif, "renesas,hscif", hscif_early_console_setup); OF_EARLYCON_DECLARE(hscif, "renesas,hscif", hscif_early_console_setup);
......
...@@ -1382,44 +1382,29 @@ static inline struct console *SUNSU_CONSOLE(void) ...@@ -1382,44 +1382,29 @@ static inline struct console *SUNSU_CONSOLE(void)
static enum su_type su_get_type(struct device_node *dp) static enum su_type su_get_type(struct device_node *dp)
{ {
struct device_node *ap = of_find_node_by_path("/aliases"); struct device_node *ap __free(device_node) =
enum su_type rc = SU_PORT_PORT; of_find_node_by_path("/aliases");
if (ap) { if (ap) {
const char *keyb = of_get_property(ap, "keyboard", NULL); const char *keyb = of_get_property(ap, "keyboard", NULL);
const char *ms = of_get_property(ap, "mouse", NULL); const char *ms = of_get_property(ap, "mouse", NULL);
struct device_node *match;
if (keyb) { if (keyb) {
match = of_find_node_by_path(keyb); struct device_node *match __free(device_node) =
of_find_node_by_path(keyb);
/* if (dp == match)
* The pointer is used as an identifier not return SU_PORT_KBD;
* as a pointer, we can drop the refcount on
* the of__node immediately after getting it.
*/
of_node_put(match);
if (dp == match) {
rc = SU_PORT_KBD;
goto out;
}
} }
if (ms) { if (ms) {
match = of_find_node_by_path(ms); struct device_node *match __free(device_node) =
of_find_node_by_path(ms);
of_node_put(match); if (dp == match)
return SU_PORT_MS;
if (dp == match) {
rc = SU_PORT_MS;
goto out;
}
} }
} }
return SU_PORT_PORT;
out:
of_node_put(ap);
return rc;
} }
static int su_probe(struct platform_device *op) static int su_probe(struct platform_device *op)
......
...@@ -89,6 +89,7 @@ ...@@ -89,6 +89,7 @@
*/ */
static const char driver_name[] = "SyncLink GT"; static const char driver_name[] = "SyncLink GT";
static const char tty_dev_prefix[] = "ttySLG"; static const char tty_dev_prefix[] = "ttySLG";
MODULE_DESCRIPTION("Device driver for Microgate SyncLink GT serial adapters");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
#define MAX_DEVICES 32 #define MAX_DEVICES 32
......
...@@ -106,4 +106,5 @@ static void __exit ttynull_exit(void) ...@@ -106,4 +106,5 @@ static void __exit ttynull_exit(void)
module_init(ttynull_init); module_init(ttynull_init);
module_exit(ttynull_exit); module_exit(ttynull_exit);
MODULE_DESCRIPTION("NULL TTY driver");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
...@@ -1033,9 +1033,7 @@ static int kbd_led_trigger_activate(struct led_classdev *cdev) ...@@ -1033,9 +1033,7 @@ static int kbd_led_trigger_activate(struct led_classdev *cdev)
tasklet_disable(&keyboard_tasklet); tasklet_disable(&keyboard_tasklet);
if (ledstate != -1U) if (ledstate != -1U)
led_trigger_event(&trigger->trigger, led_set_brightness(cdev, ledstate & trigger->mask ? LED_FULL : LED_OFF);
ledstate & trigger->mask ?
LED_FULL : LED_OFF);
tasklet_enable(&keyboard_tasklet); tasklet_enable(&keyboard_tasklet);
return 0; return 0;
......
...@@ -60,6 +60,10 @@ static inline const char *printk_skip_headers(const char *buffer) ...@@ -60,6 +60,10 @@ static inline const char *printk_skip_headers(const char *buffer)
#define CONSOLE_LOGLEVEL_DEFAULT CONFIG_CONSOLE_LOGLEVEL_DEFAULT #define CONSOLE_LOGLEVEL_DEFAULT CONFIG_CONSOLE_LOGLEVEL_DEFAULT
#define CONSOLE_LOGLEVEL_QUIET CONFIG_CONSOLE_LOGLEVEL_QUIET #define CONSOLE_LOGLEVEL_QUIET CONFIG_CONSOLE_LOGLEVEL_QUIET
int match_devname_and_update_preferred_console(const char *match,
const char *name,
const short idx);
extern int console_printk[]; extern int console_printk[];
#define console_loglevel (console_printk[0]) #define console_loglevel (console_printk[0])
......
...@@ -37,6 +37,7 @@ enum { ...@@ -37,6 +37,7 @@ enum {
SCIx_SH7705_SCIF_REGTYPE, SCIx_SH7705_SCIF_REGTYPE,
SCIx_HSCIF_REGTYPE, SCIx_HSCIF_REGTYPE,
SCIx_RZ_SCIFA_REGTYPE, SCIx_RZ_SCIFA_REGTYPE,
SCIx_RZV2H_SCIF_REGTYPE,
SCIx_NR_REGTYPES, SCIx_NR_REGTYPES,
}; };
......
...@@ -6,6 +6,7 @@ struct console_cmdline ...@@ -6,6 +6,7 @@ struct console_cmdline
{ {
char name[16]; /* Name of the driver */ char name[16]; /* Name of the driver */
int index; /* Minor dev. to use */ int index; /* Minor dev. to use */
char devname[32]; /* DEVNAME:0.0 style device name */
bool user_specified; /* Specified by command line vs. platform */ bool user_specified; /* Specified by command line vs. platform */
char *options; /* Options for the driver */ char *options; /* Options for the driver */
#ifdef CONFIG_A11Y_BRAILLE_CONSOLE #ifdef CONFIG_A11Y_BRAILLE_CONSOLE
......
...@@ -2429,18 +2429,23 @@ static void set_user_specified(struct console_cmdline *c, bool user_specified) ...@@ -2429,18 +2429,23 @@ static void set_user_specified(struct console_cmdline *c, bool user_specified)
console_set_on_cmdline = 1; console_set_on_cmdline = 1;
} }
static int __add_preferred_console(const char *name, const short idx, char *options, static int __add_preferred_console(const char *name, const short idx,
const char *devname, char *options,
char *brl_options, bool user_specified) char *brl_options, bool user_specified)
{ {
struct console_cmdline *c; struct console_cmdline *c;
int i; int i;
if (!name && !devname)
return -EINVAL;
/* /*
* We use a signed short index for struct console for device drivers to * We use a signed short index for struct console for device drivers to
* indicate a not yet assigned index or port. However, a negative index * indicate a not yet assigned index or port. However, a negative index
* value is not valid for preferred console. * value is not valid when the console name and index are defined on
* the command line.
*/ */
if (idx < 0) if (name && idx < 0)
return -EINVAL; return -EINVAL;
/* /*
...@@ -2448,9 +2453,10 @@ static int __add_preferred_console(const char *name, const short idx, char *opti ...@@ -2448,9 +2453,10 @@ static int __add_preferred_console(const char *name, const short idx, char *opti
* if we have a slot free. * if we have a slot free.
*/ */
for (i = 0, c = console_cmdline; for (i = 0, c = console_cmdline;
i < MAX_CMDLINECONSOLES && c->name[0]; i < MAX_CMDLINECONSOLES && (c->name[0] || c->devname[0]);
i++, c++) { i++, c++) {
if (strcmp(c->name, name) == 0 && c->index == idx) { if ((name && strcmp(c->name, name) == 0 && c->index == idx) ||
(devname && strcmp(c->devname, devname) == 0)) {
if (!brl_options) if (!brl_options)
preferred_console = i; preferred_console = i;
set_user_specified(c, user_specified); set_user_specified(c, user_specified);
...@@ -2461,7 +2467,10 @@ static int __add_preferred_console(const char *name, const short idx, char *opti ...@@ -2461,7 +2467,10 @@ static int __add_preferred_console(const char *name, const short idx, char *opti
return -E2BIG; return -E2BIG;
if (!brl_options) if (!brl_options)
preferred_console = i; preferred_console = i;
strscpy(c->name, name, sizeof(c->name)); if (name)
strscpy(c->name, name);
if (devname)
strscpy(c->devname, devname);
c->options = options; c->options = options;
set_user_specified(c, user_specified); set_user_specified(c, user_specified);
braille_set_options(c, brl_options); braille_set_options(c, brl_options);
...@@ -2486,8 +2495,13 @@ __setup("console_msg_format=", console_msg_format_setup); ...@@ -2486,8 +2495,13 @@ __setup("console_msg_format=", console_msg_format_setup);
*/ */
static int __init console_setup(char *str) static int __init console_setup(char *str)
{ {
char buf[sizeof(console_cmdline[0].name) + 4]; /* 4 for "ttyS" */ static_assert(sizeof(console_cmdline[0].devname) >= sizeof(console_cmdline[0].name) + 4);
char *s, *options, *brl_options = NULL; char buf[sizeof(console_cmdline[0].devname)];
char *brl_options = NULL;
char *ttyname = NULL;
char *devname = NULL;
char *options;
char *s;
int idx; int idx;
/* /*
...@@ -2496,17 +2510,23 @@ static int __init console_setup(char *str) ...@@ -2496,17 +2510,23 @@ static int __init console_setup(char *str)
* for exactly this purpose. * for exactly this purpose.
*/ */
if (str[0] == 0 || strcmp(str, "null") == 0) { if (str[0] == 0 || strcmp(str, "null") == 0) {
__add_preferred_console("ttynull", 0, NULL, NULL, true); __add_preferred_console("ttynull", 0, NULL, NULL, NULL, true);
return 1; return 1;
} }
if (_braille_console_setup(&str, &brl_options)) if (_braille_console_setup(&str, &brl_options))
return 1; return 1;
/* For a DEVNAME:0.0 style console the character device is unknown early */
if (strchr(str, ':'))
devname = buf;
else
ttyname = buf;
/* /*
* Decode str into name, index, options. * Decode str into name, index, options.
*/ */
if (isdigit(str[0])) if (ttyname && isdigit(str[0]))
scnprintf(buf, sizeof(buf), "ttyS%s", str); scnprintf(buf, sizeof(buf), "ttyS%s", str);
else else
strscpy(buf, str); strscpy(buf, str);
...@@ -2523,12 +2543,18 @@ static int __init console_setup(char *str) ...@@ -2523,12 +2543,18 @@ static int __init console_setup(char *str)
#endif #endif
for (s = buf; *s; s++) for (s = buf; *s; s++)
if (isdigit(*s) || *s == ',') if ((ttyname && isdigit(*s)) || *s == ',')
break; break;
idx = simple_strtoul(s, NULL, 10);
/* @idx will get defined when devname matches. */
if (devname)
idx = -1;
else
idx = simple_strtoul(s, NULL, 10);
*s = 0; *s = 0;
__add_preferred_console(buf, idx, options, brl_options, true); __add_preferred_console(ttyname, idx, devname, options, brl_options, true);
return 1; return 1;
} }
__setup("console=", console_setup); __setup("console=", console_setup);
...@@ -2548,7 +2574,51 @@ __setup("console=", console_setup); ...@@ -2548,7 +2574,51 @@ __setup("console=", console_setup);
*/ */
int add_preferred_console(const char *name, const short idx, char *options) int add_preferred_console(const char *name, const short idx, char *options)
{ {
return __add_preferred_console(name, idx, options, NULL, false); return __add_preferred_console(name, idx, NULL, options, NULL, false);
}
/**
* match_devname_and_update_preferred_console - Update a preferred console
* when matching devname is found.
* @devname: DEVNAME:0.0 style device name
* @name: Name of the corresponding console driver, e.g. "ttyS"
* @idx: Console index, e.g. port number.
*
* The function checks whether a device with the given @devname is
* preferred via the console=DEVNAME:0.0 command line option.
* It fills the missing console driver name and console index
* so that a later register_console() call could find (match)
* and enable this device.
*
* It might be used when a driver subsystem initializes particular
* devices with already known DEVNAME:0.0 style names. And it
* could predict which console driver name and index this device
* would later get associated with.
*
* Return: 0 on success, negative error code on failure.
*/
int match_devname_and_update_preferred_console(const char *devname,
const char *name,
const short idx)
{
struct console_cmdline *c = console_cmdline;
int i;
if (!devname || !strlen(devname) || !name || !strlen(name) || idx < 0)
return -EINVAL;
for (i = 0; i < MAX_CMDLINECONSOLES && (c->name[0] || c->devname[0]);
i++, c++) {
if (!strcmp(devname, c->devname)) {
pr_info("associate the preferred console \"%s\" with \"%s%d\"\n",
devname, name, idx);
strscpy(c->name, name);
c->index = idx;
return 0;
}
}
return -ENOENT;
} }
bool console_suspend_enabled = true; bool console_suspend_enabled = true;
...@@ -3318,8 +3388,11 @@ static int try_enable_preferred_console(struct console *newcon, ...@@ -3318,8 +3388,11 @@ static int try_enable_preferred_console(struct console *newcon,
int i, err; int i, err;
for (i = 0, c = console_cmdline; for (i = 0, c = console_cmdline;
i < MAX_CMDLINECONSOLES && c->name[0]; i < MAX_CMDLINECONSOLES && (c->name[0] || c->devname[0]);
i++, c++) { i++, c++) {
/* Console not yet initialized? */
if (!c->name[0])
continue;
if (c->user_specified != user_specified) if (c->user_specified != user_specified)
continue; continue;
if (!newcon->match || if (!newcon->match ||
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment