linux/drivers/tty/serial/samsung_tty.c

// SPDX-License-Identifier: GPL-2.0
/*
 * Driver core for Samsung SoC onboard UARTs.
 *
 * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
 *	http://armlinux.simtec.co.uk/
 */

/* Note on 2410 error handling
 *
 * The s3c2410 manual has a love/hate affair with the contents of the
 * UERSTAT register in the UART blocks, and keeps marking some of the
 * error bits as reserved. Having checked with the s3c2410x01,
 * it copes with BREAKs properly, so I am happy to ignore the RESERVED
 * feature from the latter versions of the manual.
 *
 * If it becomes aparrent that latter versions of the 2410 remove these
 * bits, then action will have to be taken to differentiate the versions
 * and change the policy on BREAK
 *
 * BJD, 04-Nov-2004
 */

#include <linux/console.h>
#include <linux/clk.h>
#include <linux/cpufreq.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/math.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/serial_s3c.h>
#include <linux/slab.h>
#include <linux/sysrq.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/types.h>

#include <asm/irq.h>

/* UART name and device definitions */

#define S3C24XX_SERIAL_NAME
#define S3C24XX_SERIAL_MAJOR
#define S3C24XX_SERIAL_MINOR

#ifdef CONFIG_ARM64
#define UART_NR
#else
#define UART_NR
#endif

#define S3C24XX_TX_PIO
#define S3C24XX_TX_DMA
#define S3C24XX_RX_PIO
#define S3C24XX_RX_DMA

/* flag to ignore all characters coming in */
#define RXSTAT_DUMMY_READ

enum s3c24xx_port_type {};

struct s3c24xx_uart_info {};

struct s3c24xx_serial_drv_data {};

struct s3c24xx_uart_dma {};

struct s3c24xx_uart_port {};

static void s3c24xx_serial_tx_chars(struct s3c24xx_uart_port *ourport);

/* conversion functions */

#define s3c24xx_dev_to_port(__dev)

/* register access controls */

#define portaddr(port, reg)
#define portaddrl(port, reg)

static u32 rd_reg(const struct uart_port *port, u32 reg)
{}

#define rd_regl(port, reg)

static void wr_reg(const struct uart_port *port, u32 reg, u32 val)
{}

#define wr_regl(port, reg, val)

/* Byte-order aware bit setting/clearing functions. */

static inline void s3c24xx_set_bit(const struct uart_port *port, int idx,
				   u32 reg)
{}

static inline void s3c24xx_clear_bit(const struct uart_port *port, int idx,
				     u32 reg)
{}

static inline struct s3c24xx_uart_port *to_ourport(struct uart_port *port)
{}

/* translate a port to the device name */

static inline const char *s3c24xx_serial_portname(const struct uart_port *port)
{}

static bool s3c24xx_serial_txempty_nofifo(const struct uart_port *port)
{}

static void s3c24xx_serial_rx_enable(struct uart_port *port)
{}

static void s3c24xx_serial_rx_disable(struct uart_port *port)
{}

static void s3c24xx_serial_stop_tx(struct uart_port *port)
{}

static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport);

static void s3c24xx_serial_tx_dma_complete(void *args)
{}

static void enable_tx_dma(struct s3c24xx_uart_port *ourport)
{}

static void enable_tx_pio(struct s3c24xx_uart_port *ourport)
{}

static void s3c24xx_serial_start_tx_pio(struct s3c24xx_uart_port *ourport)
{}

static int s3c24xx_serial_start_tx_dma(struct s3c24xx_uart_port *ourport,
				      unsigned int count, unsigned int tail)
{}

static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport)
{}

static void s3c24xx_serial_start_tx(struct uart_port *port)
{}

static void s3c24xx_uart_copy_rx_to_tty(struct s3c24xx_uart_port *ourport,
		struct tty_port *tty, int count)
{}

static void s3c24xx_serial_stop_rx(struct uart_port *port)
{}

static inline const struct s3c24xx_uart_info
	*s3c24xx_port_to_info(struct uart_port *port)
{}

static inline const struct s3c2410_uartcfg
	*s3c24xx_port_to_cfg(const struct uart_port *port)
{}

static unsigned int
s3c24xx_serial_rx_fifocnt(const struct s3c24xx_uart_port *ourport, u32 ufstat)
{}

static void s3c64xx_start_rx_dma(struct s3c24xx_uart_port *ourport);
static void s3c24xx_serial_rx_dma_complete(void *args)
{}

static void s3c64xx_start_rx_dma(struct s3c24xx_uart_port *ourport)
{}

/* ? - where has parity gone?? */
#define S3C2410_UERSTAT_PARITY

static void enable_rx_dma(struct s3c24xx_uart_port *ourport)
{}

static void enable_rx_pio(struct s3c24xx_uart_port *ourport)
{}

static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport);

static irqreturn_t s3c24xx_serial_rx_chars_dma(struct s3c24xx_uart_port *ourport)
{}

static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport)
{}

static irqreturn_t s3c24xx_serial_rx_chars_pio(struct s3c24xx_uart_port *ourport)
{}

static irqreturn_t s3c24xx_serial_rx_irq(struct s3c24xx_uart_port *ourport)
{}

static void s3c24xx_serial_tx_chars(struct s3c24xx_uart_port *ourport)
{}

static irqreturn_t s3c24xx_serial_tx_irq(struct s3c24xx_uart_port *ourport)
{}

/* interrupt handler for s3c64xx and later SoC's.*/
static irqreturn_t s3c64xx_serial_handle_irq(int irq, void *id)
{}

/* interrupt handler for Apple SoC's.*/
static irqreturn_t apple_serial_handle_irq(int irq, void *id)
{}

static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port)
{}

/* no modem control lines */
static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port)
{}

static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
{}

static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state)
{}

static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
{}

static void s3c24xx_serial_release_dma(struct s3c24xx_uart_port *p)
{}

static void s3c64xx_serial_shutdown(struct uart_port *port)
{}

static void apple_s5l_serial_shutdown(struct uart_port *port)
{}

static int s3c64xx_serial_startup(struct uart_port *port)
{}

static int apple_s5l_serial_startup(struct uart_port *port)
{}

static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
			      unsigned int old)
{}

/* baud rate calculation
 *
 * The UARTs on the S3C2410/S3C2440 can take their clocks from a number
 * of different sources, including the peripheral clock ("pclk") and an
 * external clock ("uclk"). The S3C2440 also adds the core clock ("fclk")
 * with a programmable extra divisor.
 *
 * The following code goes through the clock sources, and calculates the
 * baud clocks (and the resultant actual baud rates) and then tries to
 * pick the closest one and select that.
 *
 */

#define MAX_CLK_NAME_LENGTH

static inline u8 s3c24xx_serial_getsource(struct uart_port *port)
{}

static void s3c24xx_serial_setsource(struct uart_port *port, u8 clk_sel)
{}

static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport,
			unsigned int req_baud, struct clk **best_clk,
			u8 *clk_num)
{}

/* udivslot_table[]
 *
 * This table takes the fractional value of the baud divisor and gives
 * the recommended setting for the UDIVSLOT register.
 */
static const u16 udivslot_table[16] =;

static void s3c24xx_serial_set_termios(struct uart_port *port,
				       struct ktermios *termios,
				       const struct ktermios *old)
{}

static const char *s3c24xx_serial_type(struct uart_port *port)
{}

static void s3c24xx_serial_config_port(struct uart_port *port, int flags)
{}

/*
 * verify the new serial_struct (for TIOCSSERIAL).
 */
static int
s3c24xx_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
{}

#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE

static struct console s3c24xx_serial_console;

static void __init s3c24xx_serial_register_console(void)
{}

static void s3c24xx_serial_unregister_console(void)
{}

#define S3C24XX_SERIAL_CONSOLE
#else
static inline void s3c24xx_serial_register_console(void) { }
static inline void s3c24xx_serial_unregister_console(void) { }
#define S3C24XX_SERIAL_CONSOLE
#endif

#if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_CONSOLE_POLL)
static int s3c24xx_serial_get_poll_char(struct uart_port *port);
static void s3c24xx_serial_put_poll_char(struct uart_port *port,
			 unsigned char c);
#endif

static const struct uart_ops s3c64xx_serial_ops =;

static const struct uart_ops apple_s5l_serial_ops =;

static struct uart_driver s3c24xx_uart_drv =;

static struct s3c24xx_uart_port s3c24xx_serial_ports[UART_NR];

static void s3c24xx_serial_init_port_default(int index)
{}

/* s3c24xx_serial_resetport
 *
 * reset the fifos and other the settings.
 */

static void s3c24xx_serial_resetport(struct uart_port *port,
				     const struct s3c2410_uartcfg *cfg)
{}

static int s3c24xx_serial_enable_baudclk(struct s3c24xx_uart_port *ourport)
{}

/* s3c24xx_serial_init_port
 *
 * initialise a single serial port from the platform device given
 */

static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
				    struct platform_device *platdev)
{}

/* Device driver serial port probe */

static int probe_index;

static inline const struct s3c24xx_serial_drv_data *
s3c24xx_get_driver_data(struct platform_device *pdev)
{}

static int s3c24xx_serial_probe(struct platform_device *pdev)
{}

static void s3c24xx_serial_remove(struct platform_device *dev)
{}

/* UART power management code */
#ifdef CONFIG_PM_SLEEP
static int s3c24xx_serial_suspend(struct device *dev)
{}

static int s3c24xx_serial_resume(struct device *dev)
{}

static int s3c24xx_serial_resume_noirq(struct device *dev)
{}

static const struct dev_pm_ops s3c24xx_serial_pm_ops =;
#define SERIAL_SAMSUNG_PM_OPS

#else /* !CONFIG_PM_SLEEP */

#define SERIAL_SAMSUNG_PM_OPS
#endif /* CONFIG_PM_SLEEP */

/* Console code */

#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE

static struct uart_port *cons_uart;

static bool
s3c24xx_serial_console_txrdy(struct uart_port *port, u32 ufcon)
{}

static bool
s3c24xx_port_configured(u32 ucon)
{}

#ifdef CONFIG_CONSOLE_POLL
/*
 * Console polling routines for writing and reading from the uart while
 * in an interrupt or debug context.
 */

static int s3c24xx_serial_get_poll_char(struct uart_port *port)
{}

static void s3c24xx_serial_put_poll_char(struct uart_port *port,
		unsigned char c)
{}

#endif /* CONFIG_CONSOLE_POLL */

static void
s3c24xx_serial_console_putchar(struct uart_port *port, unsigned char ch)
{}

static void
s3c24xx_serial_console_write(struct console *co, const char *s,
			     unsigned int count)
{}

/* 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)
{}

/* Shouldn't be __init, as it can be instantiated from other module */
static int
s3c24xx_serial_console_setup(struct console *co, char *options)
{}

static struct console s3c24xx_serial_console =;
#endif /* CONFIG_SERIAL_SAMSUNG_CONSOLE */

#if defined(CONFIG_CPU_S3C6400) || defined(CONFIG_CPU_S3C6410)
static const struct s3c24xx_serial_drv_data s3c6400_serial_drv_data = {
	.info = {
		.name		= "Samsung S3C6400 UART",
		.type		= TYPE_S3C6400,
		.port_type	= PORT_S3C6400,
		.iotype		= UPIO_MEM,
		.fifosize	= 64,
		.has_divslot	= true,
		.rx_fifomask	= S3C2440_UFSTAT_RXMASK,
		.rx_fifoshift	= S3C2440_UFSTAT_RXSHIFT,
		.rx_fifofull	= S3C2440_UFSTAT_RXFULL,
		.tx_fifofull	= S3C2440_UFSTAT_TXFULL,
		.tx_fifomask	= S3C2440_UFSTAT_TXMASK,
		.tx_fifoshift	= S3C2440_UFSTAT_TXSHIFT,
		.def_clk_sel	= S3C2410_UCON_CLKSEL2,
		.num_clks	= 4,
		.clksel_mask	= S3C6400_UCON_CLKMASK,
		.clksel_shift	= S3C6400_UCON_CLKSHIFT,
	},
	.def_cfg = {
		.ucon		= S3C2410_UCON_DEFAULT,
		.ufcon		= S3C2410_UFCON_DEFAULT,
	},
};
#define S3C6400_SERIAL_DRV_DATA
#else
#define S3C6400_SERIAL_DRV_DATA
#endif

#ifdef CONFIG_CPU_S5PV210
static const struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = {
	.info = {
		.name		= "Samsung S5PV210 UART",
		.type		= TYPE_S3C6400,
		.port_type	= PORT_S3C6400,
		.iotype		= UPIO_MEM,
		.has_divslot	= true,
		.rx_fifomask	= S5PV210_UFSTAT_RXMASK,
		.rx_fifoshift	= S5PV210_UFSTAT_RXSHIFT,
		.rx_fifofull	= S5PV210_UFSTAT_RXFULL,
		.tx_fifofull	= S5PV210_UFSTAT_TXFULL,
		.tx_fifomask	= S5PV210_UFSTAT_TXMASK,
		.tx_fifoshift	= S5PV210_UFSTAT_TXSHIFT,
		.def_clk_sel	= S3C2410_UCON_CLKSEL0,
		.num_clks	= 2,
		.clksel_mask	= S5PV210_UCON_CLKMASK,
		.clksel_shift	= S5PV210_UCON_CLKSHIFT,
	},
	.def_cfg = {
		.ucon		= S5PV210_UCON_DEFAULT,
		.ufcon		= S5PV210_UFCON_DEFAULT,
	},
	.fifosize = { 256, 64, 16, 16 },
};
#define S5PV210_SERIAL_DRV_DATA
#else
#define S5PV210_SERIAL_DRV_DATA
#endif

#if defined(CONFIG_ARCH_EXYNOS)
#define EXYNOS_COMMON_SERIAL_DRV_DATA							\

static const struct s3c24xx_serial_drv_data exynos4210_serial_drv_data = {
	EXYNOS_COMMON_SERIAL_DRV_DATA,
	.fifosize = { 256, 64, 16, 16 },
};

static const struct s3c24xx_serial_drv_data exynos5433_serial_drv_data = {
	EXYNOS_COMMON_SERIAL_DRV_DATA,
	.fifosize = { 64, 256, 16, 256 },
};

static const struct s3c24xx_serial_drv_data exynos850_serial_drv_data = {
	EXYNOS_COMMON_SERIAL_DRV_DATA,
	.fifosize = { 256, 64, 64, 64 },
};

static const struct s3c24xx_serial_drv_data gs101_serial_drv_data = {
	.info = {
		.name		= "Google GS101 UART",
		.type		= TYPE_S3C6400,
		.port_type	= PORT_S3C6400,
		.iotype		= UPIO_MEM32,
		.has_divslot	= true,
		.rx_fifomask	= S5PV210_UFSTAT_RXMASK,
		.rx_fifoshift	= S5PV210_UFSTAT_RXSHIFT,
		.rx_fifofull	= S5PV210_UFSTAT_RXFULL,
		.tx_fifofull	= S5PV210_UFSTAT_TXFULL,
		.tx_fifomask	= S5PV210_UFSTAT_TXMASK,
		.tx_fifoshift	= S5PV210_UFSTAT_TXSHIFT,
		.def_clk_sel	= S3C2410_UCON_CLKSEL0,
		.num_clks	= 1,
		.clksel_mask	= 0,
		.clksel_shift	= 0,
	},
	.def_cfg = {
		.ucon		= S5PV210_UCON_DEFAULT,
		.ufcon		= S5PV210_UFCON_DEFAULT,
		.has_fracval	= 1,
	},
	/* samsung,uart-fifosize must be specified in the device tree. */
	.fifosize = { 0 },
};

#define EXYNOS4210_SERIAL_DRV_DATA
#define EXYNOS5433_SERIAL_DRV_DATA
#define EXYNOS850_SERIAL_DRV_DATA
#define GS101_SERIAL_DRV_DATA

#else
#define EXYNOS4210_SERIAL_DRV_DATA
#define EXYNOS5433_SERIAL_DRV_DATA
#define EXYNOS850_SERIAL_DRV_DATA
#define GS101_SERIAL_DRV_DATA
#endif

#ifdef CONFIG_ARCH_APPLE
static const struct s3c24xx_serial_drv_data s5l_serial_drv_data = {
	.info = {
		.name		= "Apple S5L UART",
		.type		= TYPE_APPLE_S5L,
		.port_type	= PORT_8250,
		.iotype		= UPIO_MEM32,
		.fifosize	= 16,
		.rx_fifomask	= S3C2410_UFSTAT_RXMASK,
		.rx_fifoshift	= S3C2410_UFSTAT_RXSHIFT,
		.rx_fifofull	= S3C2410_UFSTAT_RXFULL,
		.tx_fifofull	= S3C2410_UFSTAT_TXFULL,
		.tx_fifomask	= S3C2410_UFSTAT_TXMASK,
		.tx_fifoshift	= S3C2410_UFSTAT_TXSHIFT,
		.def_clk_sel	= S3C2410_UCON_CLKSEL0,
		.num_clks	= 1,
		.clksel_mask	= 0,
		.clksel_shift	= 0,
		.ucon_mask	= APPLE_S5L_UCON_MASK,
	},
	.def_cfg = {
		.ucon		= APPLE_S5L_UCON_DEFAULT,
		.ufcon		= S3C2410_UFCON_DEFAULT,
	},
};
#define S5L_SERIAL_DRV_DATA
#else
#define S5L_SERIAL_DRV_DATA
#endif

#if defined(CONFIG_ARCH_ARTPEC)
static const struct s3c24xx_serial_drv_data artpec8_serial_drv_data = {
	.info = {
		.name		= "Axis ARTPEC-8 UART",
		.type		= TYPE_S3C6400,
		.port_type	= PORT_S3C6400,
		.iotype		= UPIO_MEM,
		.fifosize	= 64,
		.has_divslot	= true,
		.rx_fifomask	= S5PV210_UFSTAT_RXMASK,
		.rx_fifoshift	= S5PV210_UFSTAT_RXSHIFT,
		.rx_fifofull	= S5PV210_UFSTAT_RXFULL,
		.tx_fifofull	= S5PV210_UFSTAT_TXFULL,
		.tx_fifomask	= S5PV210_UFSTAT_TXMASK,
		.tx_fifoshift	= S5PV210_UFSTAT_TXSHIFT,
		.def_clk_sel	= S3C2410_UCON_CLKSEL0,
		.num_clks	= 1,
		.clksel_mask	= 0,
		.clksel_shift	= 0,
	},
	.def_cfg = {
		.ucon		= S5PV210_UCON_DEFAULT,
		.ufcon		= S5PV210_UFCON_DEFAULT,
		.has_fracval	= 1,
	}
};
#define ARTPEC8_SERIAL_DRV_DATA
#else
#define ARTPEC8_SERIAL_DRV_DATA
#endif

static const struct platform_device_id s3c24xx_serial_driver_ids[] =;
MODULE_DEVICE_TABLE(platform, s3c24xx_serial_driver_ids);

#ifdef CONFIG_OF
static const struct of_device_id s3c24xx_uart_dt_match[] =;
MODULE_DEVICE_TABLE(of, s3c24xx_uart_dt_match);
#endif

static struct platform_driver samsung_serial_driver =;

static int __init samsung_serial_init(void)
{}

static void __exit samsung_serial_exit(void)
{}

module_init();
module_exit(samsung_serial_exit);

#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
/*
 * Early console.
 */

static void wr_reg_barrier(const struct uart_port *port, u32 reg, u32 val)
{}

struct samsung_early_console_data {};

static void samsung_early_busyuart(const struct uart_port *port)
{}

static void samsung_early_busyuart_fifo(const struct uart_port *port)
{}

static void samsung_early_putc(struct uart_port *port, unsigned char c)
{}

static void samsung_early_write(struct console *con, const char *s,
				unsigned int n)
{}

static int samsung_early_read(struct console *con, char *s, unsigned int n)
{}

static int __init samsung_early_console_setup(struct earlycon_device *device,
					      const char *opt)
{}

/* S3C2410 */
static struct samsung_early_console_data s3c2410_early_console_data =;

/* S3C64xx */
static struct samsung_early_console_data s3c2440_early_console_data =;

static int __init s3c2440_early_console_setup(struct earlycon_device *device,
					      const char *opt)
{}

OF_EARLYCON_DECLARE();

/* S5PV210, Exynos */
static struct samsung_early_console_data s5pv210_early_console_data =;

static int __init s5pv210_early_console_setup(struct earlycon_device *device,
					      const char *opt)
{}

OF_EARLYCON_DECLARE();
OF_EARLYCON_DECLARE();
OF_EARLYCON_DECLARE();

static int __init gs101_early_console_setup(struct earlycon_device *device,
					    const char *opt)
{}

OF_EARLYCON_DECLARE();

/* Apple S5L */
static int __init apple_s5l_early_console_setup(struct earlycon_device *device,
						const char *opt)
{}

OF_EARLYCON_DECLARE();
#endif

MODULE_ALIAS();
MODULE_DESCRIPTION();
MODULE_AUTHOR();
MODULE_LICENSE();