[PATCH linux dev-4.13 v1 2/2] serial: npcm: add NPCM UART driver

Tomer Maimon tmaimon77 at gmail.com
Thu Dec 21 20:04:52 AEDT 2017


Add Nuvoton BMC NPCM UART driver.

The NPCM7xx BMC contains four UART blocks and accessory logic.

Signed-off-by: Tomer Maimon <tmaimon77 at gmail.com>
---
 drivers/tty/serial/Kconfig     |   15 +
 drivers/tty/serial/Makefile    |    1 +
 drivers/tty/serial/npcm_uart.c | 1592 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1608 insertions(+)
 create mode 100644 drivers/tty/serial/npcm_uart.c

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 1f096e2bb398..353c8623c07a 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1707,6 +1707,21 @@ config SERIAL_OWL_CONSOLE
 	  Say 'Y' here if you wish to use Actions Semiconductor S500/S900 UART
 	  as the system console. Only earlycon is implemented currently.
 
+config SERIAL_NPCM
+	tristate "Nuvoton NPCM Serial port support"
+	depends on ARCH_NPCM
+	select SERIAL_CORE
+	help
+	  Support for the on-chip UARTs on the Nuvoton NPCM CPU,
+	  providing /dev/ttyS0, 1 and 2 (note, some machines may not
+	  provide all of these ports, depending on how the serial port
+	  pins are configured.
+
+config SERIAL_NPCM_CONSOLE
+	bool "Support for console on NPCM serial port"
+	depends on SERIAL_NPCM=y
+	select SERIAL_CORE_CONSOLE
+
 endmenu
 
 config SERIAL_MCTRL_GPIO
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index fe88a75d9a59..863c2bb42873 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -92,6 +92,7 @@ obj-$(CONFIG_SERIAL_STM32)	+= stm32-usart.o
 obj-$(CONFIG_SERIAL_MVEBU_UART)	+= mvebu-uart.o
 obj-$(CONFIG_SERIAL_PIC32)	+= pic32_uart.o
 obj-$(CONFIG_SERIAL_MPS2_UART)	+= mps2-uart.o
+obj-$(CONFIG_SERIAL_NPCM)	+= npcm_uart.o
 obj-$(CONFIG_SERIAL_OWL)	+= owl-uart.o
 
 # GPIOLIB helpers for modem control lines
diff --git a/drivers/tty/serial/npcm_uart.c b/drivers/tty/serial/npcm_uart.c
new file mode 100644
index 000000000000..abdb57075c6e
--- /dev/null
+++ b/drivers/tty/serial/npcm_uart.c
@@ -0,0 +1,1592 @@
+/*
+ * Support for Nuvoton UART HW.
+ *
+ * Copyright (c) 2014-2017 Nuvoton Technology corporation.
+ *
+ * Released under the GPLv2 only.
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock_types.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+
+static struct regmap *gcr_regmap;
+
+#define  MFSEL1_OFFSET 0x00C
+#define  MFSEL4_OFFSET 0x0B0
+#define  SPSWC_OFFSET  0x038
+
+#define MSN(parm8)	((u8)((u8)(parm8) >> 4))
+#define LSN(parm8)	((u8)((u8)parm8 & 0x0F))
+#define MSB(parm16)	((u8)((u16)(parm16) >> 8))
+#define LSB(parm16)	((u8)(parm16))
+#define MSW(parm32)	((u16)((u32)(parm32) >> 16))
+#define LSW(parm32)	((u16)(parm32))
+#define MSD(parm64)	((u32)((u64)(parm64) >> 32))
+#define LSD(parm64)	((u32)(parm64))
+#define PORT_NPCM	101
+
+/* Debug messages */
+#ifdef DEBUG_NPCM_UART
+#define NPCM_SERIAL_MSG(format, arg...) pr_notice(format, ## arg)
+#else
+#define NPCM_SERIAL_MSG(format, arg...) do { } while (0)
+#endif
+
+#define NPCM_UART_NUM_OF_MODULES	4
+
+#define _1Hz_	1UL
+#define _1KHz_	(1000*_1Hz_)
+#define _1MHz_	(1000*_1KHz_)
+#define _1GHz_	(1000*_1MHz_)
+
+typedef struct bit_field {
+	u8 offset;
+	u8 size;
+} bit_field_t;
+
+/* UART REGS */
+
+/* Receive Buffer Register (RBR) */
+#define UART_RBR(n)	(npcm_serial_ports[n].port.membase + 0x0)
+static const bit_field_t RBR_Transmit = { 0, 8 };
+
+/* Transmit Holding Register (THR) */
+#define UART_THR(n)	(npcm_serial_ports[n].port.membase + 0x0)
+
+/* Interrupt Enable Register (IER) */
+#define UART_IER(n)	(npcm_serial_ports[n].port.membase + 0x4)
+static const bit_field_t IER_nDBGACK_EN =	{ 4, 1 };
+static const bit_field_t IER_MSIE =		{ 3, 1 };
+static const bit_field_t IER_RLSIE =		{ 2, 1 };
+static const bit_field_t IER_THREIE =		{ 1, 1 };
+static const bit_field_t IER_RDAIE =		{ 0, 1 };
+
+/* Divisor Latch (Low Byte) Register (DLL) */
+#define UART_DLL(n)	(npcm_serial_ports[n].port.membase + 0x0)
+
+/* Divisor Latch (High Byte) Register (DLM) */
+#define UART_DLM(n)	(npcm_serial_ports[n].port.membase + 0x4)
+static const bit_field_t DLM_Baud =	{ 0, 8 };
+
+/* Interrupt Identification Register (IIR) */
+#define UART_IIR(n)	(npcm_serial_ports[n].port.membase + 0x8)
+static const bit_field_t IIR_FMES =	{ 7, 1 };
+static const bit_field_t IIR_RFTLS =	{ 5, 2 };
+static const bit_field_t IIR_DMS =	{ 4, 1 };
+static const bit_field_t IIR_IID =	{ 1, 3 };
+static const bit_field_t IIR_NIP =	{ 0, 1 };
+
+/* FIFO Control Register (FCR) */
+#define UART_FCR(n)	(npcm_serial_ports[n].port.membase + 0x8)
+static const bit_field_t FCR_RFITL =      { 4, 4 };
+static const bit_field_t FCR_DMS =        { 3, 1 };
+static const bit_field_t FCR_TFR =        { 2, 1 };
+static const bit_field_t FCR_RFR =        { 1, 1 };
+static const bit_field_t FCR_FME =        { 0, 1 };
+
+/* Line Control Register (LCR) */
+#define UART_LCR(n)	(npcm_serial_ports[n].port.membase + 0xc)
+static const bit_field_t LCR_DLAB =       { 7, 1 };
+static const bit_field_t LCR_BCB =        { 6, 1 };
+static const bit_field_t LCR_SPE =        { 5, 1 };
+static const bit_field_t LCR_EPE =        { 4, 1 };
+static const bit_field_t LCR_PBE =        { 3, 1 };
+static const bit_field_t LCR_NSB =        { 2, 1 };
+static const bit_field_t LCR_WLS =        { 0, 2 };
+static const bit_field_t LCR_Word =       { 10, 1 };
+
+/* Modem Control Register (MCR) */
+#define UART_MCR(n)	(npcm_serial_ports[n].port.membase + 0x10)
+static const bit_field_t MCR_LBME =       { 4, 1 };
+static const bit_field_t MCR_OUT2 =       { 3, 1 };
+static const bit_field_t MCR_RTS =        { 1, 1 };
+static const bit_field_t MCR_DTR =        { 0, 1 };
+
+/* Line Status Control Register (LSR) */
+#define UART_LSR(n)	(npcm_serial_ports[n].port.membase + 0x14)
+static const bit_field_t LSR_ERR_Rx =     { 7, 1 };
+static const bit_field_t LSR_TE =         { 6, 1 };
+static const bit_field_t LSR_THRE =       { 5, 1 };
+static const bit_field_t LSR_BII =        { 4, 1 };
+static const bit_field_t LSR_FEI =        { 3, 1 };
+static const bit_field_t LSR_PEI =        { 2, 1 };
+static const bit_field_t LSR_OEI =        { 1, 1 };
+static const bit_field_t LSR_RFDR =       { 0, 1 };
+
+/* Modem Status Register (MSR) */
+#define UART_MSR(n)	(npcm_serial_ports[n].port.membase + 0x18)
+static const bit_field_t MSR_DCD =        { 7, 1 };
+static const bit_field_t MSR_RI =         { 6, 1 };
+static const bit_field_t MSR_DSR =        { 5, 1 };
+static const bit_field_t MSR_CTS =        { 4, 1 };
+static const bit_field_t MSR_DDCD =       { 3, 1 };
+static const bit_field_t MSR_DRI =        { 2, 1 };
+static const bit_field_t MSR_DDSR =       { 1, 1 };
+static const bit_field_t MSR_DCTS =       { 0, 1 };
+
+/* Timeout Register (TOR) */
+#define UART_TOR(n)	(npcm_serial_ports[n].port.membase + 0x1C)
+static const bit_field_t TOR_TOIE =       { 7, 1 };
+static const bit_field_t TOR_TOIC =       { 0, 7 };
+
+enum FCR_RFITL_type {
+	FCR_RFITL_1B    = 0x0,
+	FCR_RFITL_4B    = 0x4,
+	FCR_RFITL_8B    = 0x8,
+	FCR_RFITL_14B   = 0xC,
+};
+
+enum LCR_WLS_type {
+	LCR_WLS_5bit    = 0x0,
+	LCR_WLS_6bit    = 0x1,
+	LCR_WLS_7bit    = 0x2,
+	LCR_WLS_8bit    = 0x3,
+};
+
+enum IIR_IID_type {
+	IIR_IID_MODEM = 0x0,
+	IIR_IID_THRE  = 0x1,
+	IIR_IID_TOUT  = 0x5,
+	IIR_IID_RDA   = 0x2,
+	IIR_IID_RLS   = 0x3,
+};
+
+/* UART ports definition */
+typedef enum {
+	NPCM_UART0_DEV = 0,
+	NPCM_UART1_DEV = 1,
+	NPCM_UART2_DEV = 2,
+	NPCM_UART3_DEV = 3,
+} NPCM_UART_DEV_T;
+
+#ifdef CONFIG_MACH_NPCM650
+/* Uart Mux modes definitions */
+enum {
+	NPCM_UART_MUX_CORE_SNOOP        = 0,
+	NPCM_UART_MUX_CORE_TAKEOVER     = 1,
+	NPCM_UART_MUX_CORE_SP2__SP1_SI1 = 2,
+	NPCM_UART_MUX_CORE_SP2__SP1_SI2 = 3,
+	NPCM_UART_MUX_SKIP_CONFIG       = 4,
+} NPCM_UART_MUX_T;
+#endif
+
+#ifdef CONFIG_ARCH_NPCM7XX
+/*
+ * Uart Mux modes definitions. These numbers match the register field value.
+ * Do not change !
+ * s == snoop
+ */
+typedef enum NPCM_UART_MUX_T_ {
+	NPCM_UART_MUX_MODE1_HSP1_SI2____HSP2_UART2__UART1_s_HSP1__UART3_s_SI2                = 0,
+	NPCM_UART_MUX_MODE2_HSP1_UART1__HSP2_SI2____UART2_s_HSP2__UART3_s_SI2                = 1,
+	NPCM_UART_MUX_MODE3_HSP1_UART1__HSP2_UART2__UART3_SI2                                = 2,
+	NPCM_UART_MUX_MODE4_HSP1_SI1____HSP2_SI2____UART1_s_SI1___UART3_s_SI2__UART2_s_HSP1  = 3,
+	NPCM_UART_MUX_MODE5_HSP1_SI1____HSP2_UART2__UART1_s_HSP1__UART3_s_SI1                = 4,
+	NPCM_UART_MUX_MODE6_HSP1_SI1____HSP2_SI2____UART1_s_SI1___UART3_s_SI2__UART2_s_HSP2  = 5,
+	NPCM_UART_MUX_MODE7_HSP1_SI1____HSP2_UART2__UART1_s_HSP1__UART3_SI2                  = 6,
+	NPCM_UART_MUX_RESERVED                                                               = 7,
+	NPCM_UART_MUX_SKIP_CONFIG                                                            = 8
+} NPCM_UART_MUX_T;
+#endif
+
+/* Common baudrate definitions */
+typedef enum {
+	NPCM_UART_BAUDRATE_110       = 110,
+	NPCM_UART_BAUDRATE_300       = 300,
+	NPCM_UART_BAUDRATE_600       = 600,
+	NPCM_UART_BAUDRATE_1200      = 1200,
+	NPCM_UART_BAUDRATE_2400      = 2400,
+	NPCM_UART_BAUDRATE_4800      = 4800,
+	NPCM_UART_BAUDRATE_9600      = 9600,
+	NPCM_UART_BAUDRATE_14400     = 14400,
+	NPCM_UART_BAUDRATE_19200     = 19200,
+	NPCM_UART_BAUDRATE_38400     = 38400,
+	NPCM_UART_BAUDRATE_57600     = 57600,
+	NPCM_UART_BAUDRATE_115200    = 115200,
+	NPCM_UART_BAUDRATE_230400    = 230400,
+	NPCM_UART_BAUDRATE_380400    = 380400,
+	NPCM_UART_BAUDRATE_460800    = 460800,
+} NPCM_UART_BAUDRATE_T;
+
+/* Uart Rx Fifo Trigger level definitions */
+typedef enum {
+	NPCM_UART_RXFIFO_TRIGGER_1B      = 0x0,
+	NPCM_UART_RXFIFO_TRIGGER_4B      = 0x1,
+	NPCM_UART_RXFIFO_TRIGGER_8B      = 0x2,
+	NPCM_UART_RXFIFO_TRIGGER_14B     = 0x3,
+} NPCM_UART_RXFIFO_TRIGGER_T;
+
+/* UART parity types */
+typedef enum {
+	NPCM_UART_PARITY_NONE    = 0x00,
+	NPCM_UART_PARITY_EVEN    = 0x01,
+	NPCM_UART_PARITY_ODD     = 0x02,
+} NPCM_UART_PARITY_T;
+
+/* Uart stop bits */
+typedef enum {
+	NPCM_UART_STOPBIT_1          = 0x00,
+	NPCM_UART_STOPBIT_DYNAMIC    = 0x01,
+} NPCM_UART_STOPBIT_T;
+
+/* Callback functions for UART IRQ handler */
+typedef void (*UART_irq_callback_t)(u8 devNum, void *args);
+
+/* Default UART PORT configurations */
+#ifdef _PALLADIUM_
+#define NPCM_SERIAL_BAUD     NPCM_UART_BAUDRATE_600
+#else
+#define NPCM_SERIAL_BAUD     NPCM_UART_BAUDRATE_115200
+#endif
+#define NPCM_SERIAL_BITS     8
+#define NPCM_SERIAL_PARITY   'n'
+
+/* UART driver name and definitions */
+#define NPCM_SERIAL_NAME     "ttyS"
+#define NPCM_SERIAL_MAJOR    4
+#define NPCM_SERIAL_MINOR    64
+
+/* Default configurations for Rx and Tx FIFOs */
+#define NPCM_SERIAL_RX_TIMEOUT       0x20
+#define NPCM_SERIAL_RX_THRES         NPCM_UART_RXFIFO_TRIGGER_1B
+#define NPCM_SERIAL_TX_FIFO_SIZE     16
+
+/* Default configurations for Console */
+#define NPCM_SERIAL_CONSOLE_PORT     NPCM_UART3_DEV
+
+/* Our port definitions and structures */
+struct npcm_uart_port {
+	unsigned char      rx_claimed;
+	unsigned char      tx_claimed;
+	unsigned int       type;
+	struct uart_port   port;
+};
+
+static int npcm_uart_init(NPCM_UART_DEV_T devNum,
+			     NPCM_UART_MUX_T muxMode,
+			     NPCM_UART_BAUDRATE_T baudRate);
+static int npcm_uart_putc(NPCM_UART_DEV_T devNum, const u8 c);
+static int npcm_uart_putc_NB(NPCM_UART_DEV_T devNum, const u8 c);
+static int npcm_uart_getc_NB(NPCM_UART_DEV_T devNum, u8 *c);
+static bool npcm_uart_test_rx(NPCM_UART_DEV_T devNum);
+static bool npcm_uart_test_tx(NPCM_UART_DEV_T devNum);
+static int npcm_uart_reset_fifo(NPCM_UART_DEV_T devNum, bool txFifo,
+			    bool rxFifo);
+static int npcm_uart_set_rx_irq_state(NPCM_UART_DEV_T devNum, bool On);
+static int npcm_uart_set_rx_config(NPCM_UART_DEV_T devNum, u8 timeout,
+				    NPCM_UART_RXFIFO_TRIGGER_T triggerLevel);
+static int npcm_uart_set_parity(NPCM_UART_DEV_T devNum,
+				   NPCM_UART_PARITY_T parity);
+static int npcm_uart_set_bits_per_char(NPCM_UART_DEV_T devNum, u32 bits);
+static int npcm_uart_set_baud_rate(NPCM_UART_DEV_T devNum,
+				      NPCM_UART_BAUDRATE_T baudrate);
+static int npcm_uart_set_stop_bit(NPCM_UART_DEV_T devNum,
+				     NPCM_UART_STOPBIT_T stopbit);
+static int npcm_uart_set_break(NPCM_UART_DEV_T devNum, bool state);
+static int npcm_uart_isr(NPCM_UART_DEV_T devNum,
+			    UART_irq_callback_t rxCallback,
+			    void *rxParam, UART_irq_callback_t txCallback,
+			    void *txParam);
+static void npcm_serial_stop_tx(struct uart_port *port);
+static void npcm_serial_start_tx(struct uart_port *port);
+static void npcm_serial_stop_rx(struct uart_port *port);
+static void npcm_serial_tx_irq(u8 devNum, void *args);
+static void npcm_serial_rx_irq(u8 devNum, void *args);
+static irqreturn_t npcm_serial_irq(int irq, void *dev_id);
+static unsigned int npcm_serial_tx_empty(struct uart_port *port);
+static void npcm_serial_break_ctl(struct uart_port *port, int break_state);
+static void npcm_serial_shutdown(struct uart_port *port);
+static int npcm_serial_startup(struct uart_port *port);
+static void npcm_serial_set_termios(struct uart_port *port,
+				       struct ktermios *new,
+				       struct ktermios *old);
+static const char *npcm_serial_type(struct uart_port *port);
+static void npcm_serial_config_port(struct uart_port *port, int flags);
+static int npcm_serial_verify_port(struct uart_port *port,
+				      struct serial_struct *ser);
+static void npcm_serial_set_mctrl(struct uart_port *port,
+				     unsigned int mctrl);
+static unsigned int npcm_serial_get_mctrl(struct uart_port *port);
+static void npcm_serial_flush_buffer(struct uart_port *port);
+static void npcm_serial_set_ldisc(struct uart_port *port,
+				     struct ktermios *new);
+static void npcm_serial_pm(struct uart_port *port, unsigned int state,
+			      unsigned int oldstate);
+static void npcm_serial_release_port(struct uart_port *port);
+static int npcm_serial_request_port(struct uart_port *port);
+static int npcm_serial_init_port(struct npcm_uart_port *ourport,
+				    struct platform_device *platdev);
+static int npcm_serial_probe(struct platform_device *dev);
+static int npcm_serial_remove(struct platform_device *dev);
+static int __init npcm_serial_modinit(void);
+static void __exit npcm_serial_modexit(void);
+static void npcm_console_putchar(struct uart_port *port, int ch);
+static int __init npcm_console_setup(struct console *co, char *options);
+static void npcm_console_write(struct console *co, const char *s,
+				  unsigned int count);
+static int npcm_console_init(void);
+
+#define regwrite8(mem, val) iowrite8(val, mem)
+
+static inline void set_reg_field8(unsigned char __iomem *mem,
+				  bit_field_t bit_field, u8 val) {
+	u8 tmp = ioread8(mem);
+
+	tmp &= ~(((1 << bit_field.size) - 1) << bit_field.offset);
+	tmp |= val << bit_field.offset;
+	iowrite8(tmp, mem);
+}
+
+#define set_var_field(var, bit_field, value) {				\
+	typeof(var) tmp = var;						\
+	tmp &= ~(((1 << bit_field.size) - 1) << bit_field.offset);	\
+	tmp |= value << bit_field.offset;				\
+	var = tmp;							\
+}
+
+static inline u8 read_reg_field8(unsigned char __iomem *mem,
+				 bit_field_t bit_field) {
+	u8 tmp = ioread8(mem);
+
+	tmp = tmp >> bit_field.offset;
+	tmp &= (1 << bit_field.size) - 1;
+	return tmp;
+}
+
+#define read_var_field(var, bit_field) ({	\
+	typeof(var) tmp = var;			\
+	tmp = tmp >> bit_field.offset;		\
+	tmp &= (1 << bit_field.size) - 1;	\
+	tmp;					\
+})
+
+#ifdef CONFIG_OF
+static const struct of_device_id uart_dt_id[];
+#endif
+
+static struct platform_driver npcm_serial_drv;
+static struct uart_port *npcm_console_port;
+
+/* Forward declaration of driver structs */
+static struct uart_ops          npcm_serial_ops;
+static struct platform_driver   npcm_serial_drv;
+static struct console           npcm_serial_console;
+
+static struct npcm_uart_port
+npcm_serial_ports[NPCM_UART_NUM_OF_MODULES] = {
+	/* Uart0 port */
+	{
+		.port = {
+			.lock       =
+			__SPIN_LOCK_UNLOCKED(npcm_serial_ports[0].port.lock),
+			.iotype     = UPIO_MEM,
+			.fifosize   = NPCM_SERIAL_TX_FIFO_SIZE,
+			.ops        = &npcm_serial_ops,
+			.flags      = UPF_SPD_VHI | UPF_BOOT_AUTOCONF,
+			.line       = 0,
+		},
+		.type = PORT_NPCM,
+	},
+
+	/* Uart1 port */
+	{
+		.port = {
+			.lock       =
+			__SPIN_LOCK_UNLOCKED(npcm_serial_ports[1].port.lock),
+			.iotype     = UPIO_MEM,
+			.fifosize   = NPCM_SERIAL_TX_FIFO_SIZE,
+			.ops        = &npcm_serial_ops,
+			.flags      = UPF_SPD_VHI | UPF_BOOT_AUTOCONF,
+			.line       = 1,
+		},
+		.type = PORT_NPCM,
+	},
+
+	/* Uart2 port */
+	{
+		.port = {
+			.lock       =
+			__SPIN_LOCK_UNLOCKED(npcm_serial_ports[2].port.lock),
+			.iotype     = UPIO_MEM,
+			.fifosize   = NPCM_SERIAL_TX_FIFO_SIZE,
+			.ops        = &npcm_serial_ops,
+			.flags      = UPF_SPD_VHI | UPF_BOOT_AUTOCONF,
+			.line       = 2,
+		},
+		.type = PORT_NPCM,
+	},
+
+	/* Uart3 port */
+	{
+		.port = {
+			.lock       =
+			__SPIN_LOCK_UNLOCKED(npcm_serial_ports[3].port.lock),
+			.iotype     = UPIO_MEM,
+			.fifosize   = NPCM_SERIAL_TX_FIFO_SIZE,
+			.ops        = &npcm_serial_ops,
+			.flags      = UPF_SPD_VHI | UPF_BOOT_AUTOCONF,
+			.line       = 3,
+		},
+		.type = PORT_NPCM,
+	},
+};
+
+
+/* Interrupt handling */
+#define tx_enabled(port)    ((port)->unused[0])
+#define rx_enabled(port)    ((port)->unused[1])
+
+/* conversion functions between various structures */
+#define npcm_convert_port_to_ourport(port)	\
+		container_of(port, struct npcm_uart_port, port)
+#define npcm_convert_port_to_portname(port)	\
+		to_platform_device(port->dev)->name
+
+static int npcm_uart_init(NPCM_UART_DEV_T devNum,
+			     NPCM_UART_MUX_T muxMode,
+			     NPCM_UART_BAUDRATE_T baudRate)
+{
+	u32 FCR_Val      = 0;
+	bool CoreSP  = false;
+	/*bool sp1     = false;
+	bool sp2     = false;*/
+	u32  ret     = 0;
+
+	if (devNum >= NPCM_UART_NUM_OF_MODULES)
+		return -EINVAL;
+
+	if (devNum == NPCM_UART0_DEV)
+		CoreSP = true;
+
+	#if defined NPCM650
+	else if (devNum == NPCM_UART1_DEV) {
+		CoreSP = false;
+
+		switch (muxMode) {
+		case NPCM_UART_MUX_CORE_SNOOP:
+		case NPCM_UART_MUX_CORE_TAKEOVER:
+			sp1 = true;
+			sp2 = true;
+			break;
+		case NPCM_UART_MUX_CORE_SP2__SP1_SI1:
+			sp1 = true;
+			break;
+		case NPCM_UART_MUX_CORE_SP2__SP1_SI2:
+			sp2 = true;
+			break;
+		case NPCM_UART_MUX_SKIP_CONFIG:
+			break;
+		default:
+			return HAL_ERROR_BAD_PARAM;
+		}
+	}
+#elif (defined NPCM750_CHIP || defined NPCM750_CP)
+	switch (muxMode) {
+	case NPCM_UART_MUX_MODE4_HSP1_SI1____HSP2_SI2____UART1_s_SI1___UART3_s_SI2__UART2_s_HSP1:
+	case NPCM_UART_MUX_MODE6_HSP1_SI1____HSP2_SI2____UART1_s_SI1___UART3_s_SI2__UART2_s_HSP2:
+	case NPCM_UART_MUX_MODE7_HSP1_SI1____HSP2_UART2__UART1_s_HSP1__UART3_SI2:
+		sp1 = true;
+		sp2 = true;
+		break;
+	case NPCM_UART_MUX_MODE5_HSP1_SI1____HSP2_UART2__UART1_s_HSP1__UART3_s_SI1:
+		sp1 = true;
+		break;
+	case NPCM_UART_MUX_MODE1_HSP1_SI2____HSP2_UART2__UART1_s_HSP1__UART3_s_SI2:
+	case NPCM_UART_MUX_MODE2_HSP1_UART1__HSP2_SI2____UART2_s_HSP2__UART3_s_SI2:
+	case NPCM_UART_MUX_MODE3_HSP1_UART1__HSP2_UART2__UART3_SI2:
+		sp2 = true;
+		break;
+	case NPCM_UART_MUX_SKIP_CONFIG:
+		break;
+	default:
+		return -1;
+	}
+#endif
+
+	if (muxMode != NPCM_UART_MUX_SKIP_CONFIG) {
+		if (muxMode < 7) {
+			/*regmap_update_bits(gcr_regmap, SPSWC_OFFSET, (0x7 << 0)
+				, muxMode & 0x7);
+
+			if (CoreSP)
+			{
+			    regmap_update_bits(gcr_regmap, MFSEL1_OFFSET, (0x1 << 9), (0x1 << 9));
+			    regmap_update_bits(gcr_regmap, MFSEL4_OFFSET, (0x1 << 1), (0x1 << 1));
+			}
+			if (sp1)
+			{
+			    regmap_update_bits(gcr_regmap, MFSEL1_OFFSET, (0x1 << 10), (0x1 << 10));
+			    regmap_update_bits(gcr_regmap, MFSEL4_OFFSET, (0x1 << 1), 0);
+			}
+			if (sp2)
+			{
+			    regmap_update_bits(gcr_regmap, MFSEL1_OFFSET, (0x1 << 11), (0x1 << 11));
+			    regmap_update_bits(gcr_regmap, MFSEL4_OFFSET, (0x1 << 1), 0);
+			}*/
+		}
+	}
+
+	regwrite8(UART_LCR(devNum), 0);            // prepare to Init UART
+	regwrite8(UART_IER(devNum), 0x0);          // Disable all UART interrupt
+
+	ret += npcm_uart_set_baud_rate(devNum, baudRate);
+
+	ret += npcm_uart_set_bits_per_char(devNum, 8);
+	ret += npcm_uart_set_stop_bit(devNum, NPCM_UART_STOPBIT_1);
+	ret += npcm_uart_set_parity(devNum, NPCM_UART_PARITY_NONE);
+
+	FCR_Val = 0;
+	set_var_field(FCR_Val, FCR_RFITL, FCR_RFITL_4B);
+	set_var_field(FCR_Val, FCR_TFR, 1);
+	set_var_field(FCR_Val, FCR_RFR, 1);
+	set_var_field(FCR_Val, FCR_FME, 1);
+
+	regwrite8(UART_FCR(devNum), FCR_Val);
+	regwrite8(UART_TOR(devNum), 0x0);
+
+	if (ret > 0)
+		return -1;
+	else
+		return 0;
+}
+
+static int npcm_uart_putc(NPCM_UART_DEV_T devNum, const u8 c)
+{
+
+	if (devNum >= NPCM_UART_NUM_OF_MODULES)
+		return -EINVAL;
+
+	while
+		(!read_reg_field8(UART_LSR(devNum), LSR_THRE));
+	regwrite8(UART_THR(devNum), (c & 0xFF));
+
+	return 0;
+}
+
+static int npcm_uart_putc_NB(NPCM_UART_DEV_T devNum, const u8 c)
+{
+	if (devNum >= NPCM_UART_NUM_OF_MODULES)
+		return -EINVAL;
+
+	regwrite8(UART_THR(devNum), (c & 0xFF));
+
+	return 0;
+}
+
+static int npcm_uart_getc_NB(NPCM_UART_DEV_T devNum, u8 *c)
+{
+	if (devNum >= NPCM_UART_NUM_OF_MODULES)
+		return -EINVAL;
+
+	if (!npcm_uart_test_rx(devNum))
+		return -1;
+
+	*c = (ioread8(UART_RBR(devNum)) & 0xFF);
+
+	return 0;
+}
+
+static bool npcm_uart_test_rx(NPCM_UART_DEV_T devNum)
+{
+	if (read_reg_field8(UART_LSR(devNum), LSR_RFDR))
+		return true;
+	else
+		return false;
+}
+
+static bool npcm_uart_test_tx(NPCM_UART_DEV_T devNum)
+{
+	if (!read_reg_field8(UART_LSR(devNum), LSR_THRE))
+		return true;
+	else
+		return false;
+}
+
+static int npcm_uart_reset_fifo(NPCM_UART_DEV_T devNum, bool txFifo,
+				   bool rxFifo)
+{
+	if (devNum >= NPCM_UART_NUM_OF_MODULES)
+		return -EINVAL;
+
+	if (txFifo)
+		set_reg_field8(UART_FCR(devNum), FCR_TFR, 1);
+
+	if (rxFifo)
+		set_reg_field8(UART_FCR(devNum), FCR_RFR, 1);
+
+	return 0;
+}
+
+static int npcm_uart_set_tx_irq_state(NPCM_UART_DEV_T devNum, bool On)
+{
+	if (devNum >= NPCM_UART_NUM_OF_MODULES)
+		return -EINVAL;
+
+	if (On)
+		set_reg_field8(UART_IER(devNum), IER_THREIE, 1);
+	else
+		set_reg_field8(UART_IER(devNum), IER_THREIE, 0);
+
+	return 0;
+}
+
+static int npcm_uart_set_rx_irq_state(NPCM_UART_DEV_T devNum, bool On)
+{
+	if (devNum >= NPCM_UART_NUM_OF_MODULES)
+		return -EINVAL;
+
+	if (On) {
+		set_reg_field8(UART_IER(devNum), IER_RDAIE, 1);
+		set_reg_field8(UART_TOR(devNum), TOR_TOIE, 1);
+	} else {
+		set_reg_field8(UART_IER(devNum), IER_RDAIE, 0);
+		set_reg_field8(UART_TOR(devNum), TOR_TOIE, 0);
+	}
+
+	return 0;
+}
+
+static int npcm_uart_set_rx_config(NPCM_UART_DEV_T devNum,
+				      u8 timeout,
+				      NPCM_UART_RXFIFO_TRIGGER_T triggerLevel)
+{
+	if (devNum >= NPCM_UART_NUM_OF_MODULES)
+		return -EINVAL;
+
+	set_reg_field8(UART_TOR(devNum), TOR_TOIC, (timeout & 0x7F));
+	set_reg_field8(UART_FCR(devNum), FCR_RFITL, (triggerLevel << 2));
+
+	return 0;
+}
+
+static int npcm_uart_set_parity(NPCM_UART_DEV_T devNum,
+				   NPCM_UART_PARITY_T parity)
+{
+	if (devNum >= NPCM_UART_NUM_OF_MODULES)
+		return -EINVAL;
+
+	if (parity != NPCM_UART_PARITY_NONE) {
+
+		set_reg_field8(UART_LCR(devNum), LCR_PBE, 1);
+
+		if (parity == NPCM_UART_PARITY_EVEN)
+			set_reg_field8(UART_LCR(devNum), LCR_EPE, 1);
+		else if (parity == NPCM_UART_PARITY_ODD)
+			set_reg_field8(UART_LCR(devNum), LCR_EPE, 0);
+		else
+			return -EINVAL;
+	} else
+		set_reg_field8(UART_LCR(devNum), LCR_PBE, 0);
+
+	return 0;
+}
+
+static int npcm_uart_set_bits_per_char(NPCM_UART_DEV_T devNum, u32 bits)
+{
+	if (devNum >= NPCM_UART_NUM_OF_MODULES)
+		return -EINVAL;
+
+	switch (bits) {
+	case 5:
+		set_reg_field8(UART_LCR(devNum), LCR_WLS, LCR_WLS_5bit);
+		break;
+	case 6:
+		set_reg_field8(UART_LCR(devNum), LCR_WLS, LCR_WLS_6bit);
+		break;
+	case 7:
+		set_reg_field8(UART_LCR(devNum), LCR_WLS, LCR_WLS_7bit);
+		break;
+	default:
+	case 8:
+		set_reg_field8(UART_LCR(devNum), LCR_WLS, LCR_WLS_8bit);
+		break;
+	}
+
+	return 0;
+}
+
+static int npcm_uart_set_baud_rate(NPCM_UART_DEV_T devNum,
+				      NPCM_UART_BAUDRATE_T baudrate)
+{
+	int               divisor     = 0;
+	u32               uart_clock  = 0;
+	int               ret         = 0;
+
+	if (devNum >= NPCM_UART_NUM_OF_MODULES)
+		return -EINVAL;
+
+	if (npcm_serial_ports[devNum].port.uartclk != 0)
+		uart_clock = npcm_serial_ports[devNum].port.uartclk;
+	else {
+		NPCM_SERIAL_MSG("%s: warning, uart clock unknown!\n",
+				   __func__);
+		uart_clock = 24 * _1MHz_;
+	}
+
+	divisor = ((int)uart_clock / ((int)baudrate * 16)) - 2;
+
+	/* since divisor is rounded down check
+	 * if it is better when rounded up
+	 */
+	if (((int)uart_clock / (16 * (divisor + 2)) - (int)baudrate) >
+		((int)baudrate - (int)uart_clock / (16 * ((divisor + 1) + 2))))
+		divisor++;
+
+	if (divisor < 0) {
+		divisor = 0;
+		ret = EINVAL;
+	}
+
+	/* Set baud rate to baudRate bps */
+	set_reg_field8(UART_LCR(devNum), LCR_DLAB, 1);
+	regwrite8(UART_DLL(devNum), LSB(divisor));
+	regwrite8(UART_DLM(devNum), MSB(divisor));
+	set_reg_field8(UART_LCR(devNum), LCR_DLAB, 0);
+
+	return ret;
+}
+
+static int npcm_uart_set_stop_bit(NPCM_UART_DEV_T devNum,
+				     NPCM_UART_STOPBIT_T stopbit)
+{
+	if (devNum >= NPCM_UART_NUM_OF_MODULES)
+		return -EINVAL;
+
+	if (stopbit == NPCM_UART_STOPBIT_1)
+		set_reg_field8(UART_LCR(devNum), LCR_NSB, 0);
+	else if (stopbit == NPCM_UART_STOPBIT_DYNAMIC)
+		set_reg_field8(UART_LCR(devNum), LCR_NSB, 1);
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static int npcm_uart_set_break(NPCM_UART_DEV_T devNum, bool state)
+{
+	if (devNum >= NPCM_UART_NUM_OF_MODULES)
+		return -EINVAL;
+
+	if (state)
+		set_reg_field8(UART_LCR(devNum), LCR_BCB, 1);
+	else
+		set_reg_field8(UART_LCR(devNum), LCR_BCB, 0);
+
+	return 0;
+}
+
+static int npcm_uart_isr(NPCM_UART_DEV_T devNum,
+			    UART_irq_callback_t rxCallback, void *rxParam,
+			    UART_irq_callback_t txCallback, void *txParam)
+{
+	int  ret = 0;
+	u32      iir = ioread8(UART_IIR(devNum)) & 0xF;
+
+	if (read_var_field(iir, IIR_NIP)) {
+		ret =  -ENXIO;
+	} else {
+		switch (read_var_field(iir, IIR_IID)) {
+		case IIR_IID_MODEM:
+			break;
+			/* Tx Interrupt */
+		case IIR_IID_THRE:
+			txCallback(devNum, txParam);    break;
+			/* Rx Interrupts */
+		case IIR_IID_TOUT:
+		case IIR_IID_RDA:
+			rxCallback(devNum, rxParam);    break;
+		default:
+			break;
+			/* Error interrupts */
+		case IIR_IID_RLS:
+			{
+				u32 lsr = ioread8(UART_LSR(devNum));
+				if (read_var_field(lsr, LSR_OEI))
+					ret = -EOVERFLOW;
+				else if (read_var_field(lsr, LSR_PEI))
+					ret = -EILSEQ;
+				else if (read_var_field(lsr, LSR_FEI))
+					ret = -EMSGSIZE;
+				else if (read_var_field(lsr, LSR_BII))
+					ret = -EIO;
+				else
+					ret = -1;
+				break;
+			}
+		}
+	}
+
+	return ret;
+}
+
+static void npcm_serial_stop_tx(struct uart_port *port)
+{
+	if (tx_enabled(port)) {
+		npcm_uart_set_tx_irq_state((NPCM_UART_DEV_T)port->line,
+					      false);
+		tx_enabled(port) = 0;
+	}
+}
+
+static void npcm_serial_start_tx(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->state->xmit;
+
+	if ((!tx_enabled(port)) && (!uart_circ_empty(xmit))) {
+		npcm_uart_set_tx_irq_state((NPCM_UART_DEV_T)port->line,
+					      true);
+		tx_enabled(port) = 1;
+	}
+}
+
+static void npcm_serial_stop_rx(struct uart_port *port)
+{
+	if (rx_enabled(port)) {
+		npcm_uart_set_rx_irq_state((NPCM_UART_DEV_T)port->line,
+					      false);
+		rx_enabled(port) = 0;
+	}
+}
+
+static void npcm_serial_tx_irq(u8 devNum, void *args)
+{
+	struct npcm_uart_port *ourport = (struct npcm_uart_port *)args;
+	struct uart_port *port = &ourport->port;
+	struct circ_buf *xmit = &port->state->xmit;
+
+	int count = NPCM_SERIAL_TX_FIFO_SIZE;
+
+	if (port->x_char) {
+		if (!npcm_uart_test_tx((NPCM_UART_DEV_T)port->line)) {
+			npcm_uart_putc_NB((NPCM_UART_DEV_T)port->line,
+					     port->x_char);
+			port->icount.tx++;
+			port->x_char = 0;
+		}
+
+		return;
+	}
+
+	/*
+	 * if there isnt anything more to transmit, or the uart is now
+	 * stopped, disable the uart and exit
+	 */
+	if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+		npcm_serial_stop_tx(port);
+		return;
+	}
+
+	/*
+	 * try and drain the buffer
+	 */
+	while (!uart_circ_empty(xmit) && count-- > 0) {
+		npcm_uart_putc_NB((NPCM_UART_DEV_T)port->line,
+				     xmit->buf[xmit->tail]);
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		port->icount.tx++;
+	}
+
+	/*
+	 * if the queue is not empty, we schedule late
+	 * processing after the interrupt
+	 */
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+
+	/*
+	 * if the queue is empty we stop TX
+	 */
+	if (uart_circ_empty(xmit))
+		npcm_serial_stop_tx(port);
+}
+
+static void npcm_serial_rx_irq(u8 devNum, void *args)
+{
+	struct npcm_uart_port *ourport   = (struct npcm_uart_port *)args;
+	struct uart_port *port              = &ourport->port;
+	unsigned char   ch;
+	int             status;
+	int             max_count = NPCM_SERIAL_TX_FIFO_SIZE;
+
+	while ((max_count-- > 0) && npcm_uart_test_rx(devNum)) {
+		status = npcm_uart_getc_NB(devNum, &ch);
+
+		port->icount.rx++;
+		if (!uart_handle_sysrq_char(port, ch) && (status == 0))
+			uart_insert_char(port, 0, 0, ch, TTY_NORMAL);
+	}
+
+	tty_flip_buffer_push(&port->state->port);
+}
+
+static irqreturn_t npcm_serial_irq(int irq, void *dev_id)
+{
+	struct npcm_uart_port *ourport = (struct npcm_uart_port *)dev_id;
+	struct uart_port *port    = &ourport->port;
+	int                         ret;
+
+	ret = npcm_uart_isr((NPCM_UART_DEV_T)port->line,
+			       npcm_serial_rx_irq, dev_id,
+			       npcm_serial_tx_irq, dev_id);
+
+	if (ret == (-ENXIO))
+		return IRQ_NONE;
+
+	else if (ret != 0) {
+		NPCM_SERIAL_MSG("NPCM Serial: IRQ Error\n");
+		if (ret == (-EIO)) {
+			NPCM_SERIAL_MSG("NPCM Serial: break!\n");
+			port->icount.brk++;
+			uart_handle_break(port);
+		} else if (ret == (-EMSGSIZE)) {
+			port->icount.frame++;
+			NPCM_SERIAL_MSG("NPCM Serial: frame error!\n");
+		} else if (ret == (-EOVERFLOW)) {
+			port->icount.overrun++;
+			NPCM_SERIAL_MSG("NPCM Serial: overrun error!\n");
+		} else if (ret == (-EILSEQ)) {
+			port->icount.parity++;
+			NPCM_SERIAL_MSG("NPCM Serial: parity error!\n");
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+static unsigned int npcm_serial_tx_empty(struct uart_port *port)
+{
+	return !npcm_uart_test_tx((NPCM_UART_DEV_T)port->line);
+}
+
+static void npcm_serial_break_ctl(struct uart_port *port, int break_state)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+	npcm_uart_set_break((NPCM_UART_DEV_T)port->line, break_state);
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void npcm_serial_shutdown(struct uart_port *port)
+{
+	struct npcm_uart_port *ourport =
+		npcm_convert_port_to_ourport(port);
+
+	NPCM_SERIAL_MSG("NPCM Serial: Called function %s\n", __func__);
+
+	if (ourport->tx_claimed || ourport->rx_claimed)
+		free_irq(port->irq, ourport);
+
+	if (ourport->tx_claimed) {
+		npcm_uart_set_tx_irq_state((NPCM_UART_DEV_T)port->line,
+					      false);
+		tx_enabled(port) = 0;
+		ourport->tx_claimed = 0;
+	}
+
+	if (ourport->rx_claimed) {
+		npcm_uart_set_rx_irq_state((NPCM_UART_DEV_T)port->line,
+					      false);
+		ourport->rx_claimed = 0;
+		rx_enabled(port) = 0;
+	}
+}
+
+static int npcm_serial_startup(struct uart_port *port)
+{
+	struct npcm_uart_port *ourport =
+		npcm_convert_port_to_ourport(port);
+	int ret;
+
+	NPCM_SERIAL_MSG("NPCM Serial: Called function %s\n", __func__);
+
+#ifndef CONFIG_SERIAL_NPCM_CONSOLE
+	npcm_uart_init((NPCM_UART_DEV_T)port->line,
+			  NPCM_UART_MUX_MODE3_HSP1_UART1__HSP2_UART2__UART3_SI2,
+			  NPCM_SERIAL_BAUD);
+#endif
+
+	npcm_uart_reset_fifo((NPCM_UART_DEV_T)port->line, true, true);
+
+	npcm_uart_set_rx_config((NPCM_UART_DEV_T)port->line,
+				   (u8)NPCM_SERIAL_RX_TIMEOUT,
+				   NPCM_SERIAL_RX_THRES);
+
+	ret = request_irq(port->irq, npcm_serial_irq, 0,
+			  npcm_convert_port_to_portname(port),
+			  (void *)ourport);
+
+	if (ret != 0) {
+		pr_err("NPCM Serial: cannot get irq %d\n", port->irq);
+		npcm_serial_shutdown(port);
+		return ret;
+	}
+
+	npcm_uart_set_rx_irq_state((NPCM_UART_DEV_T)port->line, true);
+	rx_enabled(port) = 1;
+
+	ourport->rx_claimed = 1;
+	ourport->tx_claimed = 1;
+
+	NPCM_SERIAL_MSG("NPCM Serial: Port %d started with flags 0x%X\n",
+			   port->line, port->flags);
+
+	return 0;
+}
+
+static void npcm_serial_set_termios(struct uart_port *port,
+				       struct ktermios *new,
+				       struct ktermios *old)
+{
+	unsigned int bits   = 0;
+	unsigned int baud   = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	NPCM_SERIAL_MSG("NPCM Serial: Called function %s\n", __func__);
+	NPCM_SERIAL_MSG("NPCM Serial: Flags NEW = iflags[0x%X], "
+			   "oflags[0x%X], cflags[0x%X], lflags[0x%X]\n",
+			   new->c_iflag, new->c_oflag,
+			   new->c_cflag, new->c_lflag);
+
+	/* We don't support modem control lines */
+	new->c_cflag &= ~(HUPCL | CMSPAR);
+	new->c_cflag |= CLOCAL;
+
+	switch (new->c_cflag & CSIZE) {
+	case CS5:
+		bits = 5;      break;
+	case CS6:
+		bits = 6;      break;
+	case CS7:
+		bits = 7;      break;
+	case CS8:
+	default:
+		bits = 8;      break;
+	}
+
+	npcm_uart_set_bits_per_char((NPCM_UART_DEV_T)port->line, bits);
+
+	NPCM_SERIAL_MSG("NPCM Serial: %dbits/char\n", bits);
+
+	if (new->c_cflag & CSTOPB) {
+		npcm_uart_set_stop_bit((NPCM_UART_DEV_T)port->line,
+					  NPCM_UART_STOPBIT_DYNAMIC);
+		NPCM_SERIAL_MSG("NPCM Serial: Stop Bits dynamic\n");
+	} else {
+		npcm_uart_set_stop_bit((NPCM_UART_DEV_T)port->line,
+					  NPCM_UART_STOPBIT_1);
+		NPCM_SERIAL_MSG("NPCM Serial: 1 Stop Bit\n");
+	}
+
+	if (new->c_cflag & PARENB) {
+		if (new->c_cflag & PARODD) {
+			npcm_uart_set_parity((NPCM_UART_DEV_T)port->line,
+						NPCM_UART_PARITY_ODD);
+			NPCM_SERIAL_MSG("NPCM Serial: ODD  parity\n");
+		} else {
+			npcm_uart_set_parity((NPCM_UART_DEV_T)port->line,
+						NPCM_UART_PARITY_EVEN);
+			NPCM_SERIAL_MSG("NPCM Serial: EVEN parity\n");
+		}
+	} else {
+		npcm_uart_set_parity((NPCM_UART_DEV_T)port->line,
+					NPCM_UART_PARITY_NONE);
+		NPCM_SERIAL_MSG("NPCM Serial: NO parity\n");
+	}
+
+	switch (new->c_cflag & CBAUD) {
+	case  B110:
+		npcm_uart_set_baud_rate((NPCM_UART_DEV_T)port->line,
+					   NPCM_UART_BAUDRATE_110);
+		baud = 110;
+		break;
+	case  B300:
+		npcm_uart_set_baud_rate((NPCM_UART_DEV_T)port->line,
+					   NPCM_UART_BAUDRATE_300);
+		baud = 300;
+		break;
+	case  B600:
+		npcm_uart_set_baud_rate((NPCM_UART_DEV_T)port->line,
+					   NPCM_UART_BAUDRATE_600);
+		baud = 600;
+		break;
+	case  B1200:
+		npcm_uart_set_baud_rate((NPCM_UART_DEV_T)port->line,
+					   NPCM_UART_BAUDRATE_1200);
+		baud = 1200;
+		break;
+	case  B2400:
+		npcm_uart_set_baud_rate((NPCM_UART_DEV_T)port->line,
+					   NPCM_UART_BAUDRATE_2400);
+		baud = 2400;
+		break;
+	case  B4800:
+		npcm_uart_set_baud_rate((NPCM_UART_DEV_T)port->line,
+					   NPCM_UART_BAUDRATE_4800);
+		baud = 4800;
+		break;
+	case  B9600:
+		npcm_uart_set_baud_rate((NPCM_UART_DEV_T)port->line,
+					   NPCM_UART_BAUDRATE_9600);
+		baud = 9600;
+		break;
+	case  B19200:
+		npcm_uart_set_baud_rate((NPCM_UART_DEV_T)port->line,
+					   NPCM_UART_BAUDRATE_19200);
+		baud = 19200;
+		break;
+	case  B38400:
+		npcm_uart_set_baud_rate((NPCM_UART_DEV_T)port->line,
+					   NPCM_UART_BAUDRATE_38400);
+		baud = 38400;
+		break;
+	case  B57600:
+		npcm_uart_set_baud_rate((NPCM_UART_DEV_T)port->line,
+					   NPCM_UART_BAUDRATE_57600);
+		baud = 57600;
+		break;
+	default:
+	case  B115200:
+		npcm_uart_set_baud_rate((NPCM_UART_DEV_T)port->line,
+					   NPCM_UART_BAUDRATE_115200);
+		baud = 115200;
+		break;
+	case  B230400:
+		npcm_uart_set_baud_rate((NPCM_UART_DEV_T)port->line,
+					   NPCM_UART_BAUDRATE_230400);
+		baud = 230400;
+		break;
+	case  B460800:
+		npcm_uart_set_baud_rate((NPCM_UART_DEV_T)port->line,
+					   NPCM_UART_BAUDRATE_460800);
+		baud = 460800;
+		break;
+	}
+
+	NPCM_SERIAL_MSG("NPCM Serial: Baudrate %d\n", baud);
+
+	uart_update_timeout(port, new->c_cflag, baud);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *npcm_serial_type(struct uart_port *port)
+{
+	NPCM_SERIAL_MSG("NPCM Serial: Called function %s\n", __func__);
+
+	if (port->type == PORT_NPCM)
+		return npcm_convert_port_to_portname(port);
+	else
+		return NULL;
+}
+
+static void npcm_serial_config_port(struct uart_port *port, int flags)
+{
+	unsigned long lock_flags;
+
+	spin_lock_irqsave(&port->lock, lock_flags);
+
+	if (flags & UART_CONFIG_TYPE)
+		port->type = PORT_NPCM;
+
+	spin_unlock_irqrestore(&port->lock, lock_flags);
+}
+
+static int npcm_serial_verify_port(struct uart_port *port,
+				      struct serial_struct *ser)
+{
+	NPCM_SERIAL_MSG("NPCM Serial: Called function %s\n", __func__);
+
+	if (ser->type != PORT_UNKNOWN && ser->type != PORT_NPCM)
+		return -EINVAL;
+
+	return 0;
+}
+
+static void npcm_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	NPCM_SERIAL_MSG("NPCM Serial: Called function %s\n", __func__);
+}
+
+static unsigned int npcm_serial_get_mctrl(struct uart_port *port)
+{
+	NPCM_SERIAL_MSG("NPCM Serial: Called function %s\n", __func__);
+	return 0;
+}
+
+static void npcm_serial_flush_buffer(struct uart_port *port)
+{
+	NPCM_SERIAL_MSG("NPCM Serial: Called function %s\n", __func__);
+}
+
+static void npcm_serial_set_ldisc(struct uart_port *port,
+				     struct ktermios *new)
+{
+	NPCM_SERIAL_MSG("NPCM Serial: Called function %s\n", __func__);
+}
+
+static void npcm_serial_pm(struct uart_port *port, unsigned int state,
+			      unsigned int oldstate)
+{
+	NPCM_SERIAL_MSG("NPCM Serial: Called function %s\n", __func__);
+}
+
+static void npcm_serial_release_port(struct uart_port *port)
+{
+	NPCM_SERIAL_MSG("NPCM Serial: Called function %s\n", __func__);
+}
+
+static int npcm_serial_request_port(struct uart_port *port)
+{
+	NPCM_SERIAL_MSG("NPCM Serial: Called function %s\n", __func__);
+	return 0;
+}
+
+/*
+ * Uart port driver structure
+ */
+static struct uart_ops npcm_serial_ops = {
+	.startup        = npcm_serial_startup,
+	.shutdown       = npcm_serial_shutdown,
+	.tx_empty       = npcm_serial_tx_empty,
+	.stop_tx        = npcm_serial_stop_tx,
+	.start_tx       = npcm_serial_start_tx,
+	.stop_rx        = npcm_serial_stop_rx,
+	.break_ctl      = npcm_serial_break_ctl,
+	.type           = npcm_serial_type,
+	.config_port    = npcm_serial_config_port,
+	.verify_port    = npcm_serial_verify_port,
+	.set_termios    = npcm_serial_set_termios,
+	.set_mctrl      = npcm_serial_set_mctrl,
+	.get_mctrl      = npcm_serial_get_mctrl,
+	.flush_buffer   = npcm_serial_flush_buffer,
+	.set_ldisc      = npcm_serial_set_ldisc,
+	.pm             = npcm_serial_pm,
+	.release_port   = npcm_serial_release_port,
+	.request_port   = npcm_serial_request_port,
+
+};
+
+#ifdef CONFIG_SERIAL_NPCM_CONSOLE
+#define NPCM_SERIAL_CONSOLE (&npcm_serial_console)
+#else
+#define NPCM_SERIAL_CONSOLE NULL
+#endif
+
+static struct uart_driver npcm_uart_drv = {
+	.owner          = THIS_MODULE,
+	.dev_name       = NPCM_SERIAL_NAME,
+	.nr             = NPCM_UART_NUM_OF_MODULES,
+	.cons           = NPCM_SERIAL_CONSOLE,
+	.driver_name    = NPCM_SERIAL_NAME,
+	.major          = NPCM_SERIAL_MAJOR,
+	.minor          = NPCM_SERIAL_MINOR,
+};
+
+
+static int npcm_serial_init_port(struct npcm_uart_port *ourport,
+				    struct platform_device *platdev)
+{
+	struct uart_port *port      = &ourport->port;
+	int ret = 0;
+
+#ifdef CONFIG_OF
+	struct resource *res;
+	struct clk *ser_clk = NULL;
+#endif
+
+	NPCM_SERIAL_MSG("NPCM Serial platform: Called function %s\n", __func__);
+
+	if (platdev == NULL)
+		return -ENODEV;
+	port->dev   = &platdev->dev;
+
+#ifdef CONFIG_OF
+	ser_clk = devm_clk_get(&platdev->dev, NULL);
+	if (IS_ERR(ser_clk))
+		return PTR_ERR(ser_clk);
+	NPCM_SERIAL_MSG("\tserial clock is %ld\n", clk_get_rate(ser_clk));
+	port->uartclk = clk_get_rate(ser_clk);
+#else
+	port->uartclk = 24 * _1MHz_;
+#endif // CONFIG_OF
+
+#ifdef CONFIG_OF
+	res = platform_get_resource(platdev, IORESOURCE_MEM, 0);
+	NPCM_SERIAL_MSG("\tmemory resource is 0x%lx,"
+			   " statically it was 0x%lx\n", (unsigned long)res,
+			   (unsigned long)port->membase);
+	if (!request_mem_region(res->start, resource_size(res), platdev->name))
+		ret = -EBUSY;
+	else {
+		dev_set_drvdata(&platdev->dev, res);
+		port->membase = ioremap(res->start, resource_size(res));
+	}
+#else
+	port->membase = (void *)UART_VIRT_BASE_ADDR(port->line);
+#endif
+
+	NPCM_SERIAL_MSG("\tmemory resource is 0x%lx\n",
+			   (unsigned long)port->membase);
+	port->irq       = platform_get_irq(platdev, 0);
+	port->fifosize  = NPCM_SERIAL_TX_FIFO_SIZE;
+	NPCM_SERIAL_MSG("NPCM Serial platform: Port %2d initialized mem=%08x, "
+			"irq=%d, clock=%d\n", port->line,
+			(int)npcm_serial_ports[port->line].port.membase,
+			port->irq, port->uartclk);
+
+	return ret;
+}
+
+static int npcm_serial_probe(struct platform_device *dev)
+{
+	struct npcm_uart_port *ourport;
+	int ret;
+
+#ifdef CONFIG_OF
+	struct device_node *np;
+#endif
+
+	if (dev == NULL)
+		return -ENODEV;
+	NPCM_SERIAL_MSG("NPCM Serial platform: Called function %s with ID=%d\n"
+			, __func__, dev->id);
+
+#ifdef CONFIG_OF
+	np = dev->dev.of_node;
+	dev->id = of_alias_get_id(np, "serial");
+	if (dev->id < 0)
+		dev->id = 0;
+#endif
+	ourport = &npcm_serial_ports[dev->id];
+	ret = npcm_serial_init_port(ourport, dev);
+	if (ret < 0)
+		return ret;
+	NPCM_SERIAL_MSG("NPCM Serial platform: adding port number %d\n",
+			   ourport->port.line);
+	npcm_uart_drv.minor = NPCM_SERIAL_MINOR +  dev->id;
+	uart_add_one_port(&npcm_uart_drv, &ourport->port);
+	platform_set_drvdata(dev, &ourport->port);
+	gcr_regmap = syscon_regmap_lookup_by_compatible("nuvoton,npcm750-gcr");
+
+	if (IS_ERR(gcr_regmap)) {
+		pr_err("%s: failed to find nuvoton,npcm750-gcr\n", __func__);
+		return IS_ERR(gcr_regmap);
+	}
+
+	return 0;
+}
+
+static int npcm_serial_remove(struct platform_device *dev)
+{
+	struct uart_port *port = platform_get_drvdata(dev);
+
+	NPCM_SERIAL_MSG("NPCM Serial platform: Called function %s\n",
+			   __func__);
+	if (port)
+		uart_remove_one_port(&npcm_uart_drv, port);
+
+	return 0;
+}
+
+static const struct of_device_id uart_dt_id[] = {
+	{ .compatible = "nuvoton,npcm750-uart",  },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, uart_dt_id);
+
+static struct platform_driver npcm_serial_drv = {
+	.probe      = npcm_serial_probe,
+	.remove     = npcm_serial_remove,
+	.suspend    = NULL,
+	.resume     = NULL,
+	.driver     = {
+		.name   = "npcm-uart",
+		.owner  = THIS_MODULE,
+		.of_match_table = of_match_ptr(uart_dt_id),
+	},
+};
+
+static int __init npcm_serial_modinit(void)
+{
+	NPCM_SERIAL_MSG("NPCM Serial platform: Called function %s\n",
+			   __func__);
+
+#ifndef CONFIG_OF
+	platform_add_devices(npcm_uart_devs, ARRAY_SIZE(npcm_uart_devs));
+#endif
+
+	if (uart_register_driver(&npcm_uart_drv) < 0) {
+		pr_err("NPCM Serial platform:"
+		       " failed to register UART driver\n");
+		return -1;
+	}
+
+	platform_driver_register(&npcm_serial_drv);
+
+	return 0;
+}
+
+static void __exit npcm_serial_modexit(void)
+{
+	NPCM_SERIAL_MSG("NPCM Serial platform: Called function %s\n",
+			   __func__);
+	platform_driver_unregister(&npcm_serial_drv);
+	uart_unregister_driver(&npcm_uart_drv);
+}
+
+module_init(npcm_serial_modinit);
+module_exit(npcm_serial_modexit);
+
+#ifdef CONFIG_SERIAL_NPCM_CONSOLE
+
+static struct uart_port *npcm_console_port;
+
+static void npcm_console_putchar(struct uart_port *port, int ch)
+{
+	npcm_uart_putc((NPCM_UART_DEV_T)port->line, ch);
+}
+
+static int __init npcm_console_setup(struct console *co, char *options)
+{
+	struct uart_port *port;
+	int baud    = NPCM_SERIAL_BAUD;
+	int bits    = NPCM_SERIAL_BITS;
+	int parity  = NPCM_SERIAL_PARITY;
+	int flow    = 0;
+
+	NPCM_SERIAL_MSG("NPCM Serial Console: Called function %s\n",
+			   __func__);
+
+	if (co->index == -1 || co->index >= NPCM_UART_NUM_OF_MODULES)
+		co->index = NPCM_SERIAL_CONSOLE_PORT;
+	port = &npcm_serial_ports[co->index].port;
+
+	npcm_uart_init((NPCM_UART_DEV_T)co->index,
+			  NPCM_UART_MUX_MODE3_HSP1_UART1__HSP2_UART2__UART3_SI2,
+			  NPCM_SERIAL_BAUD);
+	npcm_console_port = port;
+
+	NPCM_SERIAL_MSG("NPCM Serial Console: Using port %d\n",
+			   port->line);
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+	return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static void npcm_console_write(struct console *co, const char *s,
+				  unsigned int count)
+{
+	uart_console_write(npcm_console_port, s, count,
+			   npcm_console_putchar);
+}
+
+static struct console npcm_serial_console = {
+	.name       = NPCM_SERIAL_NAME,
+	.device     = uart_console_device,
+	.flags      = CON_PRINTBUFFER,
+	.index      = -1,
+	.write      = npcm_console_write,
+	.setup      = npcm_console_setup,
+	.data       = &npcm_uart_drv,
+};
+
+static int npcm_console_init(void)
+{
+	int    rc = 0;
+
+#ifdef CONFIG_OF
+	struct resource res;
+	struct device_node *np = NULL;
+
+#ifdef CLK_TREE_SUPPORT_IN_EARLY_INIT
+	struct platform_device *pdev = NULL;
+	struct clk *ser_clk = NULL;
+#else
+	npcm_serial_ports[NPCM_SERIAL_CONSOLE_PORT].port.uartclk = 24 * _1MHz_;
+#endif
+
+	np = of_find_node_by_name(NULL, "serial3");
+	if (np == NULL)
+		pr_err("%s- can't get device tree node\n", __func__);
+
+	rc = of_address_to_resource(np, 0, &res);
+	if (rc) {
+		pr_info("%s: of_address_to_resource fail ret %d\n",
+			__func__, rc);
+		return -EINVAL;
+	}
+
+	npcm_serial_ports[NPCM_SERIAL_CONSOLE_PORT].port.membase =
+		ioremap(res.start, resource_size(&res));
+
+	if (!npcm_serial_ports[NPCM_SERIAL_CONSOLE_PORT].port.membase) {
+		pr_info("%s:serial_virt_addr fail\n", __func__);
+		return -ENOMEM;
+	}
+
+	NPCM_SERIAL_MSG("%s: console UART base is 0x%08X\n", __func__,
+			   (u32)npcm_serial_ports[NPCM_SERIAL_CONSOLE_PORT].port.membase);
+
+#ifdef CLK_TREE_SUPPORT_IN_EARLY_INIT
+	pdev = of_find_device_by_node(np);
+	ser_clk = devm_clk_get(&pdev->dev, NULL);
+
+	if (IS_ERR(ser_clk))
+		return PTR_ERR(ser_clk);
+
+	NPCM_SERIAL_MSG("%s: serial clock is %ld\n", __func__,
+			    clk_get_rate(ser_clk));
+
+	npcm_serial_ports[NPCM_SERIAL_CONSOLE_PORT].port.uartclk =
+		clk_get_rate(ser_clk);
+#endif
+
+#else
+	npcm_serial_ports[NPCM_SERIAL_CONSOLE_PORT].port.uartclk =
+		24 * _1MHz_;
+	npcm_serial_ports[0].port.membase =
+		(unsigned char *)UART_VIRT_BASE_ADDR(0);
+	npcm_serial_ports[1].port.membase =
+		(unsigned char *)UART_VIRT_BASE_ADDR(1);
+	npcm_serial_ports[2].port.membase =
+		(unsigned char *)UART_VIRT_BASE_ADDR(2);
+	npcm_serial_ports[3].port.membase =
+		(unsigned char *)UART_VIRT_BASE_ADDR(3);
+#endif // CONFIG_OF
+
+	register_console(&npcm_serial_console);
+	pr_err("NPCM Console Initialized\n");
+
+	return 0;
+}
+
+console_initcall(npcm_console_init);
+
+#endif /* CONFIG_SERIAL_NPCM_CONSOLE */
+
+
-- 
2.14.1



More information about the openbmc mailing list