// SPDX-License-Identifier: GPL-2.0/* *Copyright (C) 2011 LAPIS Semiconductor Co., Ltd. */#include <linux/kernel.h>#include <linux/serial.h>#include <linux/serial_reg.h>#include <linux/slab.h>#include <linux/module.h>#include <linux/pci.h>#include <linux/console.h>#include <linux/serial_core.h>#include <linux/tty.h>#include <linux/tty_flip.h>#include <linux/interrupt.h>#include <linux/io.h>#include <linux/dmi.h>#include <linux/nmi.h>#include <linux/delay.h>#include <linux/of.h> #include <linux/debugfs.h>#include <linux/dmaengine.h>#include <linux/pch_dma.h> enum { PCH_UART_HANDLED_RX_INT_SHIFT, PCH_UART_HANDLED_TX_INT_SHIFT, PCH_UART_HANDLED_RX_ERR_INT_SHIFT, PCH_UART_HANDLED_RX_TRG_INT_SHIFT, PCH_UART_HANDLED_MS_INT_SHIFT, PCH_UART_HANDLED_LS_INT_SHIFT,}; #define PCH_UART_DRIVER_DEVICE "ttyPCH" /* Set the max number of UART port * Intel EG20T PCH: 4 port * LAPIS Semiconductor ML7213 IOH: 3 port * LAPIS Semiconductor ML7223 IOH: 2 port*/#define PCH_UART_NR 4 #define PCH_UART_HANDLED_RX_INT (1<<((PCH_UART_HANDLED_RX_INT_SHIFT)<<1))#define PCH_UART_HANDLED_TX_INT (1<<((PCH_UART_HANDLED_TX_INT_SHIFT)<<1))#define PCH_UART_HANDLED_RX_ERR_INT (1<<((\ PCH_UART_HANDLED_RX_ERR_INT_SHIFT)<<1))#define PCH_UART_HANDLED_RX_TRG_INT (1<<((\ PCH_UART_HANDLED_RX_TRG_INT_SHIFT)<<1))#define PCH_UART_HANDLED_MS_INT (1<<((PCH_UART_HANDLED_MS_INT_SHIFT)<<1)) #define PCH_UART_HANDLED_LS_INT (1<<((PCH_UART_HANDLED_LS_INT_SHIFT)<<1)) #define PCH_UART_RBR 0x00#define PCH_UART_THR 0x00 #define PCH_UART_IER_MASK (PCH_UART_IER_ERBFI|PCH_UART_IER_ETBEI|\ PCH_UART_IER_ELSI|PCH_UART_IER_EDSSI)#define PCH_UART_IER_ERBFI 0x00000001#define PCH_UART_IER_ETBEI 0x00000002#define PCH_UART_IER_ELSI 0x00000004#define PCH_UART_IER_EDSSI 0x00000008 #define PCH_UART_IIR_IP 0x00000001#define PCH_UART_IIR_IID 0x00000006#define PCH_UART_IIR_MSI 0x00000000#define PCH_UART_IIR_TRI 0x00000002#define PCH_UART_IIR_RRI 0x00000004#define PCH_UART_IIR_REI 0x00000006#define PCH_UART_IIR_TOI 0x00000008#define PCH_UART_IIR_FIFO256 0x00000020#define PCH_UART_IIR_FIFO64 PCH_UART_IIR_FIFO256#define PCH_UART_IIR_FE 0x000000C0 #define PCH_UART_FCR_FIFOE 0x00000001#define PCH_UART_FCR_RFR 0x00000002#define PCH_UART_FCR_TFR 0x00000004#define PCH_UART_FCR_DMS 0x00000008#define PCH_UART_FCR_FIFO256 0x00000020#define PCH_UART_FCR_RFTL 0x000000C0 #define PCH_UART_FCR_RFTL1 0x00000000#define PCH_UART_FCR_RFTL64 0x00000040#define PCH_UART_FCR_RFTL128 0x00000080#define PCH_UART_FCR_RFTL224 0x000000C0#define PCH_UART_FCR_RFTL16 PCH_UART_FCR_RFTL64#define PCH_UART_FCR_RFTL32 PCH_UART_FCR_RFTL128#define PCH_UART_FCR_RFTL56 PCH_UART_FCR_RFTL224#define PCH_UART_FCR_RFTL4 PCH_UART_FCR_RFTL64#define PCH_UART_FCR_RFTL8 PCH_UART_FCR_RFTL128#define PCH_UART_FCR_RFTL14 PCH_UART_FCR_RFTL224#define PCH_UART_FCR_RFTL_SHIFT 6 #define PCH_UART_LCR_WLS 0x00000003#define PCH_UART_LCR_STB 0x00000004#define PCH_UART_LCR_PEN 0x00000008#define PCH_UART_LCR_EPS 0x00000010#define PCH_UART_LCR_SP 0x00000020#define PCH_UART_LCR_SB 0x00000040#define PCH_UART_LCR_DLAB 0x00000080#define PCH_UART_LCR_NP 0x00000000#define PCH_UART_LCR_OP PCH_UART_LCR_PEN#define PCH_UART_LCR_EP (PCH_UART_LCR_PEN | PCH_UART_LCR_EPS)#define PCH_UART_LCR_1P (PCH_UART_LCR_PEN | PCH_UART_LCR_SP)#define PCH_UART_LCR_0P (PCH_UART_LCR_PEN | PCH_UART_LCR_EPS |\ PCH_UART_LCR_SP) #define PCH_UART_LCR_5BIT 0x00000000#define PCH_UART_LCR_6BIT 0x00000001#define PCH_UART_LCR_7BIT 0x00000002#define PCH_UART_LCR_8BIT 0x00000003 #define PCH_UART_MCR_DTR 0x00000001#define PCH_UART_MCR_RTS 0x00000002#define PCH_UART_MCR_OUT 0x0000000C#define PCH_UART_MCR_LOOP 0x00000010#define PCH_UART_MCR_AFE 0x00000020 #define PCH_UART_LSR_DR 0x00000001#define PCH_UART_LSR_ERR (1<<7) #define PCH_UART_MSR_DCTS 0x00000001#define PCH_UART_MSR_DDSR 0x00000002#define PCH_UART_MSR_TERI 0x00000004#define PCH_UART_MSR_DDCD 0x00000008#define PCH_UART_MSR_CTS 0x00000010#define PCH_UART_MSR_DSR 0x00000020#define PCH_UART_MSR_RI 0x00000040#define PCH_UART_MSR_DCD 0x00000080#define PCH_UART_MSR_DELTA (PCH_UART_MSR_DCTS | PCH_UART_MSR_DDSR |\ PCH_UART_MSR_TERI | PCH_UART_MSR_DDCD) #define PCH_UART_DLL 0x00#define PCH_UART_DLM 0x01 #define PCH_UART_BRCSR 0x0E #define PCH_UART_IID_RLS (PCH_UART_IIR_REI)#define PCH_UART_IID_RDR (PCH_UART_IIR_RRI)#define PCH_UART_IID_RDR_TO (PCH_UART_IIR_RRI | PCH_UART_IIR_TOI)#define PCH_UART_IID_THRE (PCH_UART_IIR_TRI)#define PCH_UART_IID_MS (PCH_UART_IIR_MSI) #define PCH_UART_HAL_PARITY_NONE (PCH_UART_LCR_NP)#define PCH_UART_HAL_PARITY_ODD (PCH_UART_LCR_OP)#define PCH_UART_HAL_PARITY_EVEN (PCH_UART_LCR_EP)#define PCH_UART_HAL_PARITY_FIX1 (PCH_UART_LCR_1P)#define PCH_UART_HAL_PARITY_FIX0 (PCH_UART_LCR_0P)#define PCH_UART_HAL_5BIT (PCH_UART_LCR_5BIT)#define PCH_UART_HAL_6BIT (PCH_UART_LCR_6BIT)#define PCH_UART_HAL_7BIT (PCH_UART_LCR_7BIT)#define PCH_UART_HAL_8BIT (PCH_UART_LCR_8BIT)#define PCH_UART_HAL_STB1 0#define PCH_UART_HAL_STB2 (PCH_UART_LCR_STB) #define PCH_UART_HAL_CLR_TX_FIFO (PCH_UART_FCR_TFR)#define PCH_UART_HAL_CLR_RX_FIFO (PCH_UART_FCR_RFR)#define PCH_UART_HAL_CLR_ALL_FIFO (PCH_UART_HAL_CLR_TX_FIFO | \ PCH_UART_HAL_CLR_RX_FIFO) #define PCH_UART_HAL_DMA_MODE0 0#define PCH_UART_HAL_FIFO_DIS 0#define PCH_UART_HAL_FIFO16 (PCH_UART_FCR_FIFOE)#define PCH_UART_HAL_FIFO256 (PCH_UART_FCR_FIFOE | \ PCH_UART_FCR_FIFO256)#define PCH_UART_HAL_FIFO64 (PCH_UART_HAL_FIFO256)#define PCH_UART_HAL_TRIGGER1 (PCH_UART_FCR_RFTL1)#define PCH_UART_HAL_TRIGGER64 (PCH_UART_FCR_RFTL64)#define PCH_UART_HAL_TRIGGER128 (PCH_UART_FCR_RFTL128)#define PCH_UART_HAL_TRIGGER224 (PCH_UART_FCR_RFTL224)#define PCH_UART_HAL_TRIGGER16 (PCH_UART_FCR_RFTL16)#define PCH_UART_HAL_TRIGGER32 (PCH_UART_FCR_RFTL32)#define PCH_UART_HAL_TRIGGER56 (PCH_UART_FCR_RFTL56)#define PCH_UART_HAL_TRIGGER4 (PCH_UART_FCR_RFTL4)#define PCH_UART_HAL_TRIGGER8 (PCH_UART_FCR_RFTL8)#define PCH_UART_HAL_TRIGGER14 (PCH_UART_FCR_RFTL14)#define PCH_UART_HAL_TRIGGER_L (PCH_UART_FCR_RFTL64)#define PCH_UART_HAL_TRIGGER_M (PCH_UART_FCR_RFTL128)#define PCH_UART_HAL_TRIGGER_H (PCH_UART_FCR_RFTL224) #define PCH_UART_HAL_RX_INT (PCH_UART_IER_ERBFI)#define PCH_UART_HAL_TX_INT (PCH_UART_IER_ETBEI)#define PCH_UART_HAL_RX_ERR_INT (PCH_UART_IER_ELSI)#define PCH_UART_HAL_MS_INT (PCH_UART_IER_EDSSI)#define PCH_UART_HAL_ALL_INT (PCH_UART_IER_MASK) #define PCH_UART_HAL_DTR (PCH_UART_MCR_DTR)#define PCH_UART_HAL_RTS (PCH_UART_MCR_RTS)#define PCH_UART_HAL_OUT (PCH_UART_MCR_OUT)#define PCH_UART_HAL_LOOP (PCH_UART_MCR_LOOP)#define PCH_UART_HAL_AFE (PCH_UART_MCR_AFE) #define DEFAULT_UARTCLK 1843200 /* 1.8432 MHz */#define CMITC_UARTCLK 192000000 /* 192.0000 MHz */#define FRI2_64_UARTCLK 64000000 /* 64.0000 MHz */#define FRI2_48_UARTCLK 48000000 /* 48.0000 MHz */#define NTC1_UARTCLK 64000000 /* 64.0000 MHz */#define MINNOW_UARTCLK 50000000 /* 50.0000 MHz */ struct pch_uart_buffer { unsigned char *buf; int size;}; struct eg20t_port { struct uart_port port; int port_type; void __iomem *membase; resource_size_t mapbase; unsigned int iobase; struct pci_dev *pdev; int fifo_size; unsigned int uartclk; int start_tx; int start_rx; int tx_empty; int trigger; int trigger_level; struct pch_uart_buffer rxbuf; unsigned int dmsr; unsigned int fcr; unsigned int mcr; unsigned int use_dma; struct dma_async_tx_descriptor *desc_tx; struct dma_async_tx_descriptor *desc_rx; struct pch_dma_slave param_tx; struct pch_dma_slave param_rx; struct dma_chan *chan_tx; struct dma_chan *chan_rx; struct scatterlist *sg_tx_p; int nent; int orig_nent; struct scatterlist sg_rx; int tx_dma_use; void *rx_buf_virt; dma_addr_t rx_buf_dma; #define IRQ_NAME_SIZE 17 char irq_name[IRQ_NAME_SIZE];}; /** * struct pch_uart_driver_data - private data structure for UART-DMA * @port_type: The type of UART port * @line_no: UART port line number (0, 1, 2...) */struct pch_uart_driver_data { int port_type; int line_no;}; enum pch_uart_num_t { pch_et20t_uart0 = 0, pch_et20t_uart1, pch_et20t_uart2, pch_et20t_uart3, pch_ml7213_uart0, pch_ml7213_uart1, pch_ml7213_uart2, pch_ml7223_uart0, pch_ml7223_uart1, pch_ml7831_uart0, pch_ml7831_uart1,}; static struct pch_uart_driver_data drv_dat[] = { [pch_et20t_uart0] = {PORT_PCH_8LINE, 0}, [pch_et20t_uart1] = {PORT_PCH_2LINE, 1}, [pch_et20t_uart2] = {PORT_PCH_2LINE, 2}, [pch_et20t_uart3] = {PORT_PCH_2LINE, 3}, [pch_ml7213_uart0] = {PORT_PCH_8LINE, 0}, [pch_ml7213_uart1] = {PORT_PCH_2LINE, 1}, [pch_ml7213_uart2] = {PORT_PCH_2LINE, 2}, [pch_ml7223_uart0] = {PORT_PCH_8LINE, 0}, [pch_ml7223_uart1] = {PORT_PCH_2LINE, 1}, [pch_ml7831_uart0] = {PORT_PCH_8LINE, 0}, [pch_ml7831_uart1] = {PORT_PCH_2LINE, 1},}; #ifdef CONFIG_SERIAL_PCH_UART_CONSOLEstatic struct eg20t_port *pch_uart_ports[PCH_UART_NR];#endifstatic unsigned int default_baud = 9600;static unsigned int user_uartclk = 0;static const int trigger_level_256[4] = { 1, 64, 128, 224 };static const int trigger_level_64[4] = { 1, 16, 32, 56 };static const int trigger_level_16[4] = { 1, 4, 8, 14 };static const int trigger_level_1[4] = { 1, 1, 1, 1 }; #define PCH_REGS_BUFSIZE 1024 static ssize_t port_show_regs(struct file *file, char __user *user_buf, size_t count, loff_t *ppos){ struct eg20t_port *priv = file->private_data; char *buf; u32 len = 0; ssize_t ret; unsigned char lcr; buf = kzalloc(PCH_REGS_BUFSIZE, GFP_KERNEL); if (!buf) return 0; len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len, "PCH EG20T port[%d] regs:\n", priv->port.line); len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len, "=================================\n"); len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len, "IER: \t0x%02x\n", ioread8(priv->membase + UART_IER)); len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len, "IIR: \t0x%02x\n", ioread8(priv->membase + UART_IIR)); len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len, "LCR: \t0x%02x\n", ioread8(priv->membase + UART_LCR)); len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len, "MCR: \t0x%02x\n", ioread8(priv->membase + UART_MCR)); len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len, "LSR: \t0x%02x\n", ioread8(priv->membase + UART_LSR)); len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len, "MSR: \t0x%02x\n", ioread8(priv->membase + UART_MSR)); len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len, "BRCSR: \t0x%02x\n", ioread8(priv->membase + PCH_UART_BRCSR)); lcr = ioread8(priv->membase + UART_LCR); iowrite8(PCH_UART_LCR_DLAB, priv->membase + UART_LCR); len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len, "DLL: \t0x%02x\n", ioread8(priv->membase + UART_DLL)); len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len, "DLM: \t0x%02x\n", ioread8(priv->membase + UART_DLM)); iowrite8(lcr, priv->membase + UART_LCR); if (len > PCH_REGS_BUFSIZE) len = PCH_REGS_BUFSIZE; ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); kfree(buf); return ret;} static const struct file_operations port_regs_ops = { .owner = THIS_MODULE, .open = simple_open, .read = port_show_regs, .llseek = default_llseek,}; static const struct dmi_system_id pch_uart_dmi_table[] = { { .ident = "CM-iTC", { DMI_MATCH(DMI_BOARD_NAME, "CM-iTC"), }, (void *)CMITC_UARTCLK, }, { .ident = "FRI2", { DMI_MATCH(DMI_BIOS_VERSION, "FRI2"), }, (void *)FRI2_64_UARTCLK, }, { .ident = "Fish River Island II", { DMI_MATCH(DMI_PRODUCT_NAME, "Fish River Island II"), }, (void *)FRI2_48_UARTCLK, }, { .ident = "COMe-mTT", { DMI_MATCH(DMI_BOARD_NAME, "COMe-mTT"), }, (void *)NTC1_UARTCLK, }, { .ident = "nanoETXexpress-TT", { DMI_MATCH(DMI_BOARD_NAME, "nanoETXexpress-TT"), }, (void *)NTC1_UARTCLK, }, { .ident = "MinnowBoard", { DMI_MATCH(DMI_BOARD_NAME, "MinnowBoard"), }, (void *)MINNOW_UARTCLK, }, { }}; /* Return UART clock, checking for board specific clocks. */static unsigned int pch_uart_get_uartclk(void){ const struct dmi_system_id *d; if (user_uartclk) return user_uartclk; d = dmi_first_match(pch_uart_dmi_table); if (d) return (unsigned long)d->driver_data; return DEFAULT_UARTCLK;} static void pch_uart_hal_enable_interrupt(struct eg20t_port *priv, unsigned int flag){ u8 ier = ioread8(priv->membase + UART_IER); ier |= flag & PCH_UART_IER_MASK; iowrite8(ier, priv->membase + UART_IER);} static void pch_uart_hal_disable_interrupt(struct eg20t_port *priv, unsigned int flag){ u8 ier = ioread8(priv->membase + UART_IER); ier &= ~(flag & PCH_UART_IER_MASK); iowrite8(ier, priv->membase + UART_IER);} static int pch_uart_hal_set_line(struct eg20t_port *priv, unsigned int baud, unsigned int parity, unsigned int bits, unsigned int stb){ unsigned int dll, dlm, lcr; int div; div = DIV_ROUND_CLOSEST(priv->uartclk / 16, baud); if (div < 0 || USHRT_MAX <= div) { dev_err(priv->port.dev, "Invalid Baud(div=0x%x)\n", div); return -EINVAL; } dll = (unsigned int)div & 0x00FFU; dlm = ((unsigned int)div >> 8) & 0x00FFU; if (parity & ~(PCH_UART_LCR_PEN | PCH_UART_LCR_EPS | PCH_UART_LCR_SP)) { dev_err(priv->port.dev, "Invalid parity(0x%x)\n", parity); return -EINVAL; } if (bits & ~PCH_UART_LCR_WLS) { dev_err(priv->port.dev, "Invalid bits(0x%x)\n", bits); return -EINVAL; } if (stb & ~PCH_UART_LCR_STB) { dev_err(priv->port.dev, "Invalid STB(0x%x)\n", stb); return -EINVAL; } lcr = parity; lcr |= bits; lcr |= stb; dev_dbg(priv->port.dev, "%s:baud = %u, div = %04x, lcr = %02x (%lu)\n", __func__, baud, div, lcr, jiffies); iowrite8(PCH_UART_LCR_DLAB, priv->membase + UART_LCR); iowrite8(dll, priv->membase + PCH_UART_DLL); iowrite8(dlm, priv->membase + PCH_UART_DLM); iowrite8(lcr, priv->membase + UART_LCR); return 0;} static int pch_uart_hal_fifo_reset(struct eg20t_port *priv, unsigned int flag){ if (flag & ~(PCH_UART_FCR_TFR | PCH_UART_FCR_RFR)) { dev_err(priv->port.dev, "%s:Invalid flag(0x%x)\n", __func__, flag); return -EINVAL; } iowrite8(PCH_UART_FCR_FIFOE | priv->fcr, priv->membase + UART_FCR); iowrite8(PCH_UART_FCR_FIFOE | priv->fcr | flag, priv->membase + UART_FCR); iowrite8(priv->fcr, priv->membase + UART_FCR); return 0;} static int pch_uart_hal_set_fifo(struct eg20t_port *priv, unsigned int dmamode, unsigned int fifo_size, unsigned int trigger){ u8 fcr; if (dmamode & ~PCH_UART_FCR_DMS) { dev_err(priv->port.dev, "%s:Invalid DMA Mode(0x%x)\n", __func__, dmamode); return -EINVAL; } Lines 1–500 of 1892. Load more
// SPDX-License-Identifier: GPL-2.0 /* *Copyright (C) 2011 LAPIS Semiconductor Co., Ltd. */ #include <linux/kernel.h> #include <linux/serial.h> #include <linux/serial_reg.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/console.h> #include <linux/serial_core.h> #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/dmi.h> #include <linux/nmi.h> #include <linux/delay.h> #include <linux/of.h> #include <linux/debugfs.h> #include <linux/dmaengine.h> #include <linux/pch_dma.h> enum { PCH_UART_HANDLED_RX_INT_SHIFT, PCH_UART_HANDLED_TX_INT_SHIFT, PCH_UART_HANDLED_RX_ERR_INT_SHIFT, PCH_UART_HANDLED_RX_TRG_INT_SHIFT, PCH_UART_HANDLED_MS_INT_SHIFT, PCH_UART_HANDLED_LS_INT_SHIFT, }; #define PCH_UART_DRIVER_DEVICE "ttyPCH" /* Set the max number of UART port * Intel EG20T PCH: 4 port * LAPIS Semiconductor ML7213 IOH: 3 port * LAPIS Semiconductor ML7223 IOH: 2 port */ #define PCH_UART_NR 4 #define PCH_UART_HANDLED_RX_INT (1<<((PCH_UART_HANDLED_RX_INT_SHIFT)<<1)) #define PCH_UART_HANDLED_TX_INT (1<<((PCH_UART_HANDLED_TX_INT_SHIFT)<<1)) #define PCH_UART_HANDLED_RX_ERR_INT (1<<((\ PCH_UART_HANDLED_RX_ERR_INT_SHIFT)<<1)) #define PCH_UART_HANDLED_RX_TRG_INT (1<<((\ PCH_UART_HANDLED_RX_TRG_INT_SHIFT)<<1)) #define PCH_UART_HANDLED_MS_INT (1<<((PCH_UART_HANDLED_MS_INT_SHIFT)<<1)) #define PCH_UART_HANDLED_LS_INT (1<<((PCH_UART_HANDLED_LS_INT_SHIFT)<<1)) #define PCH_UART_RBR 0x00 #define PCH_UART_THR 0x00 #define PCH_UART_IER_MASK (PCH_UART_IER_ERBFI|PCH_UART_IER_ETBEI|\ PCH_UART_IER_ELSI|PCH_UART_IER_EDSSI) #define PCH_UART_IER_ERBFI 0x00000001 #define PCH_UART_IER_ETBEI 0x00000002 #define PCH_UART_IER_ELSI 0x00000004 #define PCH_UART_IER_EDSSI 0x00000008 #define PCH_UART_IIR_IP 0x00000001 #define PCH_UART_IIR_IID 0x00000006 #define PCH_UART_IIR_MSI 0x00000000 #define PCH_UART_IIR_TRI 0x00000002 #define PCH_UART_IIR_RRI 0x00000004 #define PCH_UART_IIR_REI 0x00000006 #define PCH_UART_IIR_TOI 0x00000008 #define PCH_UART_IIR_FIFO256 0x00000020 #define PCH_UART_IIR_FIFO64 PCH_UART_IIR_FIFO256 #define PCH_UART_IIR_FE 0x000000C0 #define PCH_UART_FCR_FIFOE 0x00000001 #define PCH_UART_FCR_RFR 0x00000002 #define PCH_UART_FCR_TFR 0x00000004 #define PCH_UART_FCR_DMS 0x00000008 #define PCH_UART_FCR_FIFO256 0x00000020 #define PCH_UART_FCR_RFTL 0x000000C0 #define PCH_UART_FCR_RFTL1 0x00000000 #define PCH_UART_FCR_RFTL64 0x00000040 #define PCH_UART_FCR_RFTL128 0x00000080 #define PCH_UART_FCR_RFTL224 0x000000C0 #define PCH_UART_FCR_RFTL16 PCH_UART_FCR_RFTL64 #define PCH_UART_FCR_RFTL32 PCH_UART_FCR_RFTL128 #define PCH_UART_FCR_RFTL56 PCH_UART_FCR_RFTL224 #define PCH_UART_FCR_RFTL4 PCH_UART_FCR_RFTL64 #define PCH_UART_FCR_RFTL8 PCH_UART_FCR_RFTL128 #define PCH_UART_FCR_RFTL14 PCH_UART_FCR_RFTL224 #define PCH_UART_FCR_RFTL_SHIFT 6 #define PCH_UART_LCR_WLS 0x00000003 #define PCH_UART_LCR_STB 0x00000004 #define PCH_UART_LCR_PEN 0x00000008 #define PCH_UART_LCR_EPS 0x00000010 #define PCH_UART_LCR_SP 0x00000020 #define PCH_UART_LCR_SB 0x00000040 #define PCH_UART_LCR_DLAB 0x00000080 #define PCH_UART_LCR_NP 0x00000000 #define PCH_UART_LCR_OP PCH_UART_LCR_PEN #define PCH_UART_LCR_EP (PCH_UART_LCR_PEN | PCH_UART_LCR_EPS) #define PCH_UART_LCR_1P (PCH_UART_LCR_PEN | PCH_UART_LCR_SP) #define PCH_UART_LCR_0P (PCH_UART_LCR_PEN | PCH_UART_LCR_EPS |\ PCH_UART_LCR_SP) #define PCH_UART_LCR_5BIT 0x00000000 #define PCH_UART_LCR_6BIT 0x00000001 #define PCH_UART_LCR_7BIT 0x00000002 #define PCH_UART_LCR_8BIT 0x00000003 #define PCH_UART_MCR_DTR 0x00000001 #define PCH_UART_MCR_RTS 0x00000002 #define PCH_UART_MCR_OUT 0x0000000C #define PCH_UART_MCR_LOOP 0x00000010 #define PCH_UART_MCR_AFE 0x00000020 #define PCH_UART_LSR_DR 0x00000001 #define PCH_UART_LSR_ERR (1<<7) #define PCH_UART_MSR_DCTS 0x00000001 #define PCH_UART_MSR_DDSR 0x00000002 #define PCH_UART_MSR_TERI 0x00000004 #define PCH_UART_MSR_DDCD 0x00000008 #define PCH_UART_MSR_CTS 0x00000010 #define PCH_UART_MSR_DSR 0x00000020 #define PCH_UART_MSR_RI 0x00000040 #define PCH_UART_MSR_DCD 0x00000080 #define PCH_UART_MSR_DELTA (PCH_UART_MSR_DCTS | PCH_UART_MSR_DDSR |\ PCH_UART_MSR_TERI | PCH_UART_MSR_DDCD) #define PCH_UART_DLL 0x00 #define PCH_UART_DLM 0x01 #define PCH_UART_BRCSR 0x0E #define PCH_UART_IID_RLS (PCH_UART_IIR_REI) #define PCH_UART_IID_RDR (PCH_UART_IIR_RRI) #define PCH_UART_IID_RDR_TO (PCH_UART_IIR_RRI | PCH_UART_IIR_TOI) #define PCH_UART_IID_THRE (PCH_UART_IIR_TRI) #define PCH_UART_IID_MS (PCH_UART_IIR_MSI) #define PCH_UART_HAL_PARITY_NONE (PCH_UART_LCR_NP) #define PCH_UART_HAL_PARITY_ODD (PCH_UART_LCR_OP) #define PCH_UART_HAL_PARITY_EVEN (PCH_UART_LCR_EP) #define PCH_UART_HAL_PARITY_FIX1 (PCH_UART_LCR_1P) #define PCH_UART_HAL_PARITY_FIX0 (PCH_UART_LCR_0P) #define PCH_UART_HAL_5BIT (PCH_UART_LCR_5BIT) #define PCH_UART_HAL_6BIT (PCH_UART_LCR_6BIT) #define PCH_UART_HAL_7BIT (PCH_UART_LCR_7BIT) #define PCH_UART_HAL_8BIT (PCH_UART_LCR_8BIT) #define PCH_UART_HAL_STB1 0 #define PCH_UART_HAL_STB2 (PCH_UART_LCR_STB) #define PCH_UART_HAL_CLR_TX_FIFO (PCH_UART_FCR_TFR) #define PCH_UART_HAL_CLR_RX_FIFO (PCH_UART_FCR_RFR) #define PCH_UART_HAL_CLR_ALL_FIFO (PCH_UART_HAL_CLR_TX_FIFO | \ PCH_UART_HAL_CLR_RX_FIFO) #define PCH_UART_HAL_DMA_MODE0 0 #define PCH_UART_HAL_FIFO_DIS 0 #define PCH_UART_HAL_FIFO16 (PCH_UART_FCR_FIFOE) #define PCH_UART_HAL_FIFO256 (PCH_UART_FCR_FIFOE | \ PCH_UART_FCR_FIFO256) #define PCH_UART_HAL_FIFO64 (PCH_UART_HAL_FIFO256) #define PCH_UART_HAL_TRIGGER1 (PCH_UART_FCR_RFTL1) #define PCH_UART_HAL_TRIGGER64 (PCH_UART_FCR_RFTL64) #define PCH_UART_HAL_TRIGGER128 (PCH_UART_FCR_RFTL128) #define PCH_UART_HAL_TRIGGER224 (PCH_UART_FCR_RFTL224) #define PCH_UART_HAL_TRIGGER16 (PCH_UART_FCR_RFTL16) #define PCH_UART_HAL_TRIGGER32 (PCH_UART_FCR_RFTL32) #define PCH_UART_HAL_TRIGGER56 (PCH_UART_FCR_RFTL56) #define PCH_UART_HAL_TRIGGER4 (PCH_UART_FCR_RFTL4) #define PCH_UART_HAL_TRIGGER8 (PCH_UART_FCR_RFTL8) #define PCH_UART_HAL_TRIGGER14 (PCH_UART_FCR_RFTL14) #define PCH_UART_HAL_TRIGGER_L (PCH_UART_FCR_RFTL64) #define PCH_UART_HAL_TRIGGER_M (PCH_UART_FCR_RFTL128) #define PCH_UART_HAL_TRIGGER_H (PCH_UART_FCR_RFTL224) #define PCH_UART_HAL_RX_INT (PCH_UART_IER_ERBFI) #define PCH_UART_HAL_TX_INT (PCH_UART_IER_ETBEI) #define PCH_UART_HAL_RX_ERR_INT (PCH_UART_IER_ELSI) #define PCH_UART_HAL_MS_INT (PCH_UART_IER_EDSSI) #define PCH_UART_HAL_ALL_INT (PCH_UART_IER_MASK) #define PCH_UART_HAL_DTR (PCH_UART_MCR_DTR) #define PCH_UART_HAL_RTS (PCH_UART_MCR_RTS) #define PCH_UART_HAL_OUT (PCH_UART_MCR_OUT) #define PCH_UART_HAL_LOOP (PCH_UART_MCR_LOOP) #define PCH_UART_HAL_AFE (PCH_UART_MCR_AFE) #define DEFAULT_UARTCLK 1843200 /* 1.8432 MHz */ #define CMITC_UARTCLK 192000000 /* 192.0000 MHz */ #define FRI2_64_UARTCLK 64000000 /* 64.0000 MHz */ #define FRI2_48_UARTCLK 48000000 /* 48.0000 MHz */ #define NTC1_UARTCLK 64000000 /* 64.0000 MHz */ #define MINNOW_UARTCLK 50000000 /* 50.0000 MHz */ struct pch_uart_buffer { unsigned char *buf; int size; }; struct eg20t_port { struct uart_port port; int port_type; void __iomem *membase; resource_size_t mapbase; unsigned int iobase; struct pci_dev *pdev; int fifo_size; unsigned int uartclk; int start_tx; int start_rx; int tx_empty; int trigger; int trigger_level; struct pch_uart_buffer rxbuf; unsigned int dmsr; unsigned int fcr; unsigned int mcr; unsigned int use_dma; struct dma_async_tx_descriptor *desc_tx; struct dma_async_tx_descriptor *desc_rx; struct pch_dma_slave param_tx; struct pch_dma_slave param_rx; struct dma_chan *chan_tx; struct dma_chan *chan_rx; struct scatterlist *sg_tx_p; int nent; int orig_nent; struct scatterlist sg_rx; int tx_dma_use; void *rx_buf_virt; dma_addr_t rx_buf_dma; #define IRQ_NAME_SIZE 17 char irq_name[IRQ_NAME_SIZE]; }; /** * struct pch_uart_driver_data - private data structure for UART-DMA * @port_type: The type of UART port * @line_no: UART port line number (0, 1, 2...) */ struct pch_uart_driver_data { int port_type; int line_no; }; enum pch_uart_num_t { pch_et20t_uart0 = 0, pch_et20t_uart1, pch_et20t_uart2, pch_et20t_uart3, pch_ml7213_uart0, pch_ml7213_uart1, pch_ml7213_uart2, pch_ml7223_uart0, pch_ml7223_uart1, pch_ml7831_uart0, pch_ml7831_uart1, }; static struct pch_uart_driver_data drv_dat[] = { [pch_et20t_uart0] = {PORT_PCH_8LINE, 0}, [pch_et20t_uart1] = {PORT_PCH_2LINE, 1}, [pch_et20t_uart2] = {PORT_PCH_2LINE, 2}, [pch_et20t_uart3] = {PORT_PCH_2LINE, 3}, [pch_ml7213_uart0] = {PORT_PCH_8LINE, 0}, [pch_ml7213_uart1] = {PORT_PCH_2LINE, 1}, [pch_ml7213_uart2] = {PORT_PCH_2LINE, 2}, [pch_ml7223_uart0] = {PORT_PCH_8LINE, 0}, [pch_ml7223_uart1] = {PORT_PCH_2LINE, 1}, [pch_ml7831_uart0] = {PORT_PCH_8LINE, 0}, [pch_ml7831_uart1] = {PORT_PCH_2LINE, 1}, }; #ifdef CONFIG_SERIAL_PCH_UART_CONSOLE static struct eg20t_port *pch_uart_ports[PCH_UART_NR]; #endif static unsigned int default_baud = 9600; static unsigned int user_uartclk = 0; static const int trigger_level_256[4] = { 1, 64, 128, 224 }; static const int trigger_level_64[4] = { 1, 16, 32, 56 }; static const int trigger_level_16[4] = { 1, 4, 8, 14 }; static const int trigger_level_1[4] = { 1, 1, 1, 1 }; #define PCH_REGS_BUFSIZE 1024 static ssize_t port_show_regs(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct eg20t_port *priv = file->private_data; char *buf; u32 len = 0; ssize_t ret; unsigned char lcr; buf = kzalloc(PCH_REGS_BUFSIZE, GFP_KERNEL); if (!buf) return 0; len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len, "PCH EG20T port[%d] regs:\n", priv->port.line); len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len, "=================================\n"); len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len, "IER: \t0x%02x\n", ioread8(priv->membase + UART_IER)); len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len, "IIR: \t0x%02x\n", ioread8(priv->membase + UART_IIR)); len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len, "LCR: \t0x%02x\n", ioread8(priv->membase + UART_LCR)); len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len, "MCR: \t0x%02x\n", ioread8(priv->membase + UART_MCR)); len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len, "LSR: \t0x%02x\n", ioread8(priv->membase + UART_LSR)); len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len, "MSR: \t0x%02x\n", ioread8(priv->membase + UART_MSR)); len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len, "BRCSR: \t0x%02x\n", ioread8(priv->membase + PCH_UART_BRCSR)); lcr = ioread8(priv->membase + UART_LCR); iowrite8(PCH_UART_LCR_DLAB, priv->membase + UART_LCR); len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len, "DLL: \t0x%02x\n", ioread8(priv->membase + UART_DLL)); len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len, "DLM: \t0x%02x\n", ioread8(priv->membase + UART_DLM)); iowrite8(lcr, priv->membase + UART_LCR); if (len > PCH_REGS_BUFSIZE) len = PCH_REGS_BUFSIZE; ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); kfree(buf); return ret; } static const struct file_operations port_regs_ops = { .owner = THIS_MODULE, .open = simple_open, .read = port_show_regs, .llseek = default_llseek, }; static const struct dmi_system_id pch_uart_dmi_table[] = { { .ident = "CM-iTC", { DMI_MATCH(DMI_BOARD_NAME, "CM-iTC"), }, (void *)CMITC_UARTCLK, }, { .ident = "FRI2", { DMI_MATCH(DMI_BIOS_VERSION, "FRI2"), }, (void *)FRI2_64_UARTCLK, }, { .ident = "Fish River Island II", { DMI_MATCH(DMI_PRODUCT_NAME, "Fish River Island II"), }, (void *)FRI2_48_UARTCLK, }, { .ident = "COMe-mTT", { DMI_MATCH(DMI_BOARD_NAME, "COMe-mTT"), }, (void *)NTC1_UARTCLK, }, { .ident = "nanoETXexpress-TT", { DMI_MATCH(DMI_BOARD_NAME, "nanoETXexpress-TT"), }, (void *)NTC1_UARTCLK, }, { .ident = "MinnowBoard", { DMI_MATCH(DMI_BOARD_NAME, "MinnowBoard"), }, (void *)MINNOW_UARTCLK, }, { } }; /* Return UART clock, checking for board specific clocks. */ static unsigned int pch_uart_get_uartclk(void) { const struct dmi_system_id *d; if (user_uartclk) return user_uartclk; d = dmi_first_match(pch_uart_dmi_table); if (d) return (unsigned long)d->driver_data; return DEFAULT_UARTCLK; } static void pch_uart_hal_enable_interrupt(struct eg20t_port *priv, unsigned int flag) { u8 ier = ioread8(priv->membase + UART_IER); ier |= flag & PCH_UART_IER_MASK; iowrite8(ier, priv->membase + UART_IER); } static void pch_uart_hal_disable_interrupt(struct eg20t_port *priv, unsigned int flag) { u8 ier = ioread8(priv->membase + UART_IER); ier &= ~(flag & PCH_UART_IER_MASK); iowrite8(ier, priv->membase + UART_IER); } static int pch_uart_hal_set_line(struct eg20t_port *priv, unsigned int baud, unsigned int parity, unsigned int bits, unsigned int stb) { unsigned int dll, dlm, lcr; int div; div = DIV_ROUND_CLOSEST(priv->uartclk / 16, baud); if (div < 0 || USHRT_MAX <= div) { dev_err(priv->port.dev, "Invalid Baud(div=0x%x)\n", div); return -EINVAL; } dll = (unsigned int)div & 0x00FFU; dlm = ((unsigned int)div >> 8) & 0x00FFU; if (parity & ~(PCH_UART_LCR_PEN | PCH_UART_LCR_EPS | PCH_UART_LCR_SP)) { dev_err(priv->port.dev, "Invalid parity(0x%x)\n", parity); return -EINVAL; } if (bits & ~PCH_UART_LCR_WLS) { dev_err(priv->port.dev, "Invalid bits(0x%x)\n", bits); return -EINVAL; } if (stb & ~PCH_UART_LCR_STB) { dev_err(priv->port.dev, "Invalid STB(0x%x)\n", stb); return -EINVAL; } lcr = parity; lcr |= bits; lcr |= stb; dev_dbg(priv->port.dev, "%s:baud = %u, div = %04x, lcr = %02x (%lu)\n", __func__, baud, div, lcr, jiffies); iowrite8(PCH_UART_LCR_DLAB, priv->membase + UART_LCR); iowrite8(dll, priv->membase + PCH_UART_DLL); iowrite8(dlm, priv->membase + PCH_UART_DLM); iowrite8(lcr, priv->membase + UART_LCR); return 0; } static int pch_uart_hal_fifo_reset(struct eg20t_port *priv, unsigned int flag) { if (flag & ~(PCH_UART_FCR_TFR | PCH_UART_FCR_RFR)) { dev_err(priv->port.dev, "%s:Invalid flag(0x%x)\n", __func__, flag); return -EINVAL; } iowrite8(PCH_UART_FCR_FIFOE | priv->fcr, priv->membase + UART_FCR); iowrite8(PCH_UART_FCR_FIFOE | priv->fcr | flag, priv->membase + UART_FCR); iowrite8(priv->fcr, priv->membase + UART_FCR); return 0; } static int pch_uart_hal_set_fifo(struct eg20t_port *priv, unsigned int dmamode, unsigned int fifo_size, unsigned int trigger) { u8 fcr; if (dmamode & ~PCH_UART_FCR_DMS) { dev_err(priv->port.dev, "%s:Invalid DMA Mode(0x%x)\n", __func__, dmamode); return -EINVAL; }