2021-11-30 02:27:46

by Sam Protsenko

[permalink] [raw]
Subject: [PATCH v2 3/5] tty: serial: samsung: Remove USI initialization

USI control is now extracted to dedicated USI driver. Remove USI related
code from serial driver to avoid conflicts and code duplication.

Signed-off-by: Sam Protsenko <[email protected]>
---
Changes in v2:
- (none)

drivers/tty/serial/samsung_tty.c | 36 ++++----------------------------
include/linux/serial_s3c.h | 9 --------
2 files changed, 4 insertions(+), 41 deletions(-)

diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c
index ca084c10d0bb..f986a9253dc8 100644
--- a/drivers/tty/serial/samsung_tty.c
+++ b/drivers/tty/serial/samsung_tty.c
@@ -65,7 +65,6 @@ enum s3c24xx_port_type {
struct s3c24xx_uart_info {
char *name;
enum s3c24xx_port_type type;
- bool has_usi;
unsigned int port_type;
unsigned int fifosize;
unsigned long rx_fifomask;
@@ -1357,28 +1356,6 @@ static int apple_s5l_serial_startup(struct uart_port *port)
return ret;
}

-static void exynos_usi_init(struct uart_port *port)
-{
- struct s3c24xx_uart_port *ourport = to_ourport(port);
- struct s3c24xx_uart_info *info = ourport->info;
- unsigned int val;
-
- if (!info->has_usi)
- return;
-
- /* Clear the software reset of USI block (it's set at startup) */
- val = rd_regl(port, USI_CON);
- val &= ~USI_CON_RESET_MASK;
- wr_regl(port, USI_CON, val);
- udelay(1);
-
- /* Continuously provide the clock to USI IP w/o gating (for Rx mode) */
- val = rd_regl(port, USI_OPTION);
- val &= ~USI_OPTION_HWACG_MASK;
- val |= USI_OPTION_HWACG_CLKREQ_ON;
- wr_regl(port, USI_OPTION, val);
-}
-
/* power power management control */

static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
@@ -1405,8 +1382,6 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,

if (!IS_ERR(ourport->baudclk))
clk_prepare_enable(ourport->baudclk);
-
- exynos_usi_init(port);
break;
default:
dev_err(port->dev, "s3c24xx_serial: unknown pm %d\n", level);
@@ -2130,8 +2105,6 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
if (ret)
pr_warn("uart: failed to enable baudclk\n");

- exynos_usi_init(port);
-
/* Keep all interrupts masked and cleared */
switch (ourport->info->type) {
case TYPE_S3C6400:
@@ -2780,11 +2753,10 @@ static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = {
#endif

#if defined(CONFIG_ARCH_EXYNOS)
-#define EXYNOS_COMMON_SERIAL_DRV_DATA(_has_usi) \
+#define EXYNOS_COMMON_SERIAL_DRV_DATA() \
.info = &(struct s3c24xx_uart_info) { \
.name = "Samsung Exynos UART", \
.type = TYPE_S3C6400, \
- .has_usi = _has_usi, \
.port_type = PORT_S3C6400, \
.has_divslot = 1, \
.rx_fifomask = S5PV210_UFSTAT_RXMASK, \
@@ -2805,17 +2777,17 @@ static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = {
} \

static struct s3c24xx_serial_drv_data exynos4210_serial_drv_data = {
- EXYNOS_COMMON_SERIAL_DRV_DATA(false),
+ EXYNOS_COMMON_SERIAL_DRV_DATA(),
.fifosize = { 256, 64, 16, 16 },
};

static struct s3c24xx_serial_drv_data exynos5433_serial_drv_data = {
- EXYNOS_COMMON_SERIAL_DRV_DATA(false),
+ EXYNOS_COMMON_SERIAL_DRV_DATA(),
.fifosize = { 64, 256, 16, 256 },
};

static struct s3c24xx_serial_drv_data exynos850_serial_drv_data = {
- EXYNOS_COMMON_SERIAL_DRV_DATA(true),
+ EXYNOS_COMMON_SERIAL_DRV_DATA(),
.fifosize = { 256, 64, 64, 64 },
};

diff --git a/include/linux/serial_s3c.h b/include/linux/serial_s3c.h
index cf0de4a86640..f6c3323fc4c5 100644
--- a/include/linux/serial_s3c.h
+++ b/include/linux/serial_s3c.h
@@ -27,15 +27,6 @@
#define S3C2410_UERSTAT (0x14)
#define S3C2410_UFSTAT (0x18)
#define S3C2410_UMSTAT (0x1C)
-#define USI_CON (0xC4)
-#define USI_OPTION (0xC8)
-
-#define USI_CON_RESET (1<<0)
-#define USI_CON_RESET_MASK (1<<0)
-
-#define USI_OPTION_HWACG_CLKREQ_ON (1<<1)
-#define USI_OPTION_HWACG_CLKSTOP_ON (1<<2)
-#define USI_OPTION_HWACG_MASK (3<<1)

#define S3C2410_LCON_CFGMASK ((0xF<<3)|(0x3))

--
2.30.2



2021-11-30 02:27:47

by Sam Protsenko

[permalink] [raw]
Subject: [PATCH v2 4/5] tty: serial: samsung: Enable console as module

Enable serial driver to be built as a module. To do so, init the console
support on driver/module load instead of using console_initcall().

This is needed for proper support of USI driver (which can be built as
a module, which in turn makes SERIAL_SAMSUNG be a module too). It also
might be useful for Android GKI modularization efforts.

Inspired by commit 87a0b9f98ac5 ("tty: serial: meson: enable console as
module").

Signed-off-by: Sam Protsenko <[email protected]>
---
Changes in v2:
- Added error path handling in samsung_serial_init()
- Added console unregister in samsung_serial_exit()

drivers/tty/serial/Kconfig | 2 +-
drivers/tty/serial/samsung_tty.c | 36 ++++++++++++++++++++++++++++----
2 files changed, 33 insertions(+), 5 deletions(-)

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index fc543ac97c13..0e5ccb25bdb1 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -263,7 +263,7 @@ config SERIAL_SAMSUNG_UARTS

config SERIAL_SAMSUNG_CONSOLE
bool "Support for console on Samsung SoC serial port"
- depends on SERIAL_SAMSUNG=y
+ depends on SERIAL_SAMSUNG
select SERIAL_CORE_CONSOLE
select SERIAL_EARLYCON
help
diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c
index f986a9253dc8..61ccb359620a 100644
--- a/drivers/tty/serial/samsung_tty.c
+++ b/drivers/tty/serial/samsung_tty.c
@@ -1715,15 +1715,21 @@ s3c24xx_serial_verify_port(struct uart_port *port, struct serial_struct *ser)

static struct console s3c24xx_serial_console;

-static int __init s3c24xx_serial_console_init(void)
+static void __init s3c24xx_serial_register_console(void)
{
register_console(&s3c24xx_serial_console);
- return 0;
}
-console_initcall(s3c24xx_serial_console_init);
+
+static void s3c24xx_serial_unregister_console(void)
+{
+ if (s3c24xx_serial_console.flags & CON_ENABLED)
+ unregister_console(&s3c24xx_serial_console);
+}

#define S3C24XX_SERIAL_CONSOLE &s3c24xx_serial_console
#else
+static inline void s3c24xx_serial_register_console(void) { }
+static inline void s3c24xx_serial_unregister_console(void) { }
#define S3C24XX_SERIAL_CONSOLE NULL
#endif

@@ -2898,7 +2904,29 @@ static struct platform_driver samsung_serial_driver = {
},
};

-module_platform_driver(samsung_serial_driver);
+static int __init samsung_serial_init(void)
+{
+ int ret;
+
+ s3c24xx_serial_register_console();
+
+ ret = platform_driver_register(&samsung_serial_driver);
+ if (ret) {
+ s3c24xx_serial_unregister_console();
+ return ret;
+ }
+
+ return 0;
+}
+
+static void __exit samsung_serial_exit(void)
+{
+ platform_driver_unregister(&samsung_serial_driver);
+ s3c24xx_serial_unregister_console();
+}
+
+module_init(samsung_serial_init);
+module_exit(samsung_serial_exit);

#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
/*
--
2.30.2


2021-11-30 02:27:50

by Sam Protsenko

[permalink] [raw]
Subject: [PATCH v2 5/5] tty: serial: samsung: Fix console registration from module

On modern Exynos SoCs (like Exynos850) the UART can be implemented as a
part of USI IP-core. In such case, USI driver is used to initialize USI
registers, and it also calls of_platform_populate() to instantiate all
sub-nodes (e.g. serial node) of USI node. When serial driver is
built-in, but USI driver is a module, and CONFIG_SERIAL_SAMSUNG_CONSOLE
is enabled, next call chain will happen when loading USI module from
user space:

usi_init
v
usi_probe
v
of_platform_populate
v
s3c24xx_serial_probe
v
uart_add_one_port
v
uart_configure_port
v
register_console
v
try_enable_new_console
v
s3c24xx_serial_console_setup

But because the serial driver is built-in, and
s3c24xx_serial_console_setup() is marked with __init keyword, that
symbol will discarded and long gone by that time already, causing failed
paging request.

That happens during the next config combination:

EXYNOS_USI=m
SERIAL_SAMSUNG=y
SERIAL_SAMSUNG_CONSOLE=y

That config should be completely possible, so rather than limiting
SERIAL_SAMSUNG choice to "m" only when USI=m, remove __init keyword for
all affected functions.

Signed-off-by: Sam Protsenko <[email protected]>
---
Changes in v2:
- This patch is added in v2

drivers/tty/serial/samsung_tty.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c
index 61ccb359620a..d002a4e48ed9 100644
--- a/drivers/tty/serial/samsung_tty.c
+++ b/drivers/tty/serial/samsung_tty.c
@@ -2500,7 +2500,8 @@ s3c24xx_serial_console_write(struct console *co, const char *s,
uart_console_write(cons_uart, s, count, s3c24xx_serial_console_putchar);
}

-static void __init
+/* Shouldn't be __init, as it can be instantiated from other module */
+static void
s3c24xx_serial_get_options(struct uart_port *port, int *baud,
int *parity, int *bits)
{
@@ -2563,7 +2564,8 @@ s3c24xx_serial_get_options(struct uart_port *port, int *baud,
}
}

-static int __init
+/* Shouldn't be __init, as it can be instantiated from other module */
+static int
s3c24xx_serial_console_setup(struct console *co, char *options)
{
struct uart_port *port;
--
2.30.2