1892 lines · 47.0 KB · C
RawDownload
// 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.