tty: serial: samsung: Init USI to keep clocks running

UART block is a part of USI (Universal Serial Interface) IP-core in
Samsung SoCs since Exynos9810 (e.g. in Exynos850). USI allows one to
enable one of three types of serial interface: UART, SPI or I2C. That's
possible because USI shares almost all internal circuits within each
protocol. USI also provides some additional registers so it's possible
to configure it.

One USI register called USI_OPTION has reset value of 0x0. Because of
this the clock gating behavior is controlled by hardware (HWACG =
Hardware Auto Clock Gating), which simply means the serial won't work
after reset as is. In order to make it work, USI_OPTION[2:1] bits must
be set to 0b01, so that HWACG is controlled manually (by software).
Bits meaning:
  - CLKREQ_ON = 1: clock is continuously provided to IP
  - CLKSTOP_ON = 0: drive IP_CLKREQ to High (needs to be set along with
                    CLKREQ_ON = 1)

USI is not present on older chips, like s3c2410, s3c2412, s3c2440,
s3c6400, s5pv210, exynos5433, exynos4210. So the new boolean field
'.has_usi' was added to struct s3c24xx_uart_info. USI registers will be
only actually accessed when '.has_usi' field is set to "1".

This feature is needed for further serial enablement on Exynos850, but
some other new Exynos chips (like Exynos9810) may benefit from this
feature as well.

Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
Signed-off-by: Sam Protsenko <semen.protsenko@linaro.org>
Link: https://lore.kernel.org/r/20210811114827.27322-5-semen.protsenko@linaro.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Sam Protsenko 2021-08-11 14:48:24 +03:00 committed by Greg Kroah-Hartman
parent 541b84ecee
commit 920792aa44
2 changed files with 40 additions and 1 deletions

View File

@ -65,6 +65,7 @@ enum s3c24xx_port_type {
struct s3c24xx_uart_info {
char *name;
enum s3c24xx_port_type type;
unsigned int has_usi;
unsigned int port_type;
unsigned int fifosize;
unsigned long rx_fifomask;
@ -1356,6 +1357,28 @@ 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,
@ -1383,6 +1406,7 @@ 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);
@ -2106,6 +2130,8 @@ 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:
@ -2754,10 +2780,11 @@ static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = {
#endif
#if defined(CONFIG_ARCH_EXYNOS)
#define EXYNOS_COMMON_SERIAL_DRV_DATA \
#define EXYNOS_COMMON_SERIAL_DRV_DATA_USI(_has_usi) \
.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, \
@ -2777,6 +2804,9 @@ static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = {
.has_fracval = 1, \
} \
#define EXYNOS_COMMON_SERIAL_DRV_DATA \
EXYNOS_COMMON_SERIAL_DRV_DATA_USI(0)
static struct s3c24xx_serial_drv_data exynos4210_serial_drv_data = {
EXYNOS_COMMON_SERIAL_DRV_DATA,
.fifosize = { 256, 64, 16, 16 },

View File

@ -27,6 +27,15 @@
#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))