903 lines · 21.3 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0+/* *  Based on drivers/serial/8250.c by Russell King. * *  Author:	Nicolas Pitre *  Created:	Feb 20, 2003 *  Copyright:	(C) 2003 Monta Vista Software, Inc. * * Note 1: This driver is made separate from the already too overloaded * 8250.c because it needs some kirks of its own and that'll make it * easier to add DMA support. * * Note 2: I'm too sick of device allocation policies for serial ports. * If someone else wants to request an "official" allocation of major/minor * for this driver please be my guest.  And don't forget that new hardware * to come from Intel might have more than 3 or 4 of those UARTs.  Let's * hope for a better port registration and dynamic device allocation scheme * with the serial core maintainer satisfaction to appear soon. */  #include <linux/ioport.h>#include <linux/init.h>#include <linux/console.h>#include <linux/sysrq.h>#include <linux/serial.h>#include <linux/serial_reg.h>#include <linux/circ_buf.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/of.h>#include <linux/platform_device.h>#include <linux/tty.h>#include <linux/tty_flip.h>#include <linux/serial_core.h>#include <linux/clk.h>#include <linux/io.h>#include <linux/slab.h> #define PXA_NAME_LEN		8 struct uart_pxa_port {	struct uart_port        port;	unsigned char           ier;	unsigned char           lcr;	unsigned char           mcr;	unsigned int            lsr_break_flag;	struct clk		*clk;	char			name[PXA_NAME_LEN];}; static inline unsigned int serial_in(struct uart_pxa_port *up, int offset){	offset <<= 2;	return readl(up->port.membase + offset);} static inline void serial_out(struct uart_pxa_port *up, int offset, int value){	offset <<= 2;	writel(value, up->port.membase + offset);} static void serial_pxa_enable_ms(struct uart_port *port){	struct uart_pxa_port *up = (struct uart_pxa_port *)port; 	up->ier |= UART_IER_MSI;	serial_out(up, UART_IER, up->ier);} static void serial_pxa_stop_tx(struct uart_port *port){	struct uart_pxa_port *up = (struct uart_pxa_port *)port; 	if (up->ier & UART_IER_THRI) {		up->ier &= ~UART_IER_THRI;		serial_out(up, UART_IER, up->ier);	}} static void serial_pxa_stop_rx(struct uart_port *port){	struct uart_pxa_port *up = (struct uart_pxa_port *)port; 	up->ier &= ~UART_IER_RLSI;	up->port.read_status_mask &= ~UART_LSR_DR;	serial_out(up, UART_IER, up->ier);} static inline void receive_chars(struct uart_pxa_port *up, int *status){	u8 ch, flag;	int max_count = 256; 	do {		/* work around Errata #20 according to		 * Intel(R) PXA27x Processor Family		 * Specification Update (May 2005)		 *		 * Step 2		 * Disable the Reciever Time Out Interrupt via IER[RTOEI]		 */		up->ier &= ~UART_IER_RTOIE;		serial_out(up, UART_IER, up->ier); 		ch = serial_in(up, UART_RX);		flag = TTY_NORMAL;		up->port.icount.rx++; 		if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |				       UART_LSR_FE | UART_LSR_OE))) {			/*			 * For statistics only			 */			if (*status & UART_LSR_BI) {				*status &= ~(UART_LSR_FE | UART_LSR_PE);				up->port.icount.brk++;				/*				 * We do the SysRQ and SAK checking				 * here because otherwise the break				 * may get masked by ignore_status_mask				 * or read_status_mask.				 */				if (uart_handle_break(&up->port))					goto ignore_char;			} else if (*status & UART_LSR_PE)				up->port.icount.parity++;			else if (*status & UART_LSR_FE)				up->port.icount.frame++;			if (*status & UART_LSR_OE)				up->port.icount.overrun++; 			/*			 * Mask off conditions which should be ignored.			 */			*status &= up->port.read_status_mask; #ifdef CONFIG_SERIAL_PXA_CONSOLE			if (up->port.line == up->port.cons->index) {				/* Recover the break flag from console xmit */				*status |= up->lsr_break_flag;				up->lsr_break_flag = 0;			}#endif			if (*status & UART_LSR_BI) {				flag = TTY_BREAK;			} else if (*status & UART_LSR_PE)				flag = TTY_PARITY;			else if (*status & UART_LSR_FE)				flag = TTY_FRAME;		} 		if (uart_prepare_sysrq_char(&up->port, ch))			goto ignore_char; 		uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag); 	ignore_char:		*status = serial_in(up, UART_LSR);	} while ((*status & UART_LSR_DR) && (max_count-- > 0));	tty_flip_buffer_push(&up->port.state->port); 	/* work around Errata #20 according to	 * Intel(R) PXA27x Processor Family	 * Specification Update (May 2005)	 *	 * Step 6:	 * No more data in FIFO: Re-enable RTO interrupt via IER[RTOIE]	 */	up->ier |= UART_IER_RTOIE;	serial_out(up, UART_IER, up->ier);} static void transmit_chars(struct uart_pxa_port *up){	u8 ch; 	uart_port_tx_limited(&up->port, ch, up->port.fifosize / 2,		true,		serial_out(up, UART_TX, ch),		({}));} static void serial_pxa_start_tx(struct uart_port *port){	struct uart_pxa_port *up = (struct uart_pxa_port *)port; 	if (!(up->ier & UART_IER_THRI)) {		up->ier |= UART_IER_THRI;		serial_out(up, UART_IER, up->ier);	}} /* should hold up->port.lock */static inline void check_modem_status(struct uart_pxa_port *up){	int status; 	status = serial_in(up, UART_MSR); 	if ((status & UART_MSR_ANY_DELTA) == 0)		return; 	if (status & UART_MSR_TERI)		up->port.icount.rng++;	if (status & UART_MSR_DDSR)		up->port.icount.dsr++;	if (status & UART_MSR_DDCD)		uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);	if (status & UART_MSR_DCTS)		uart_handle_cts_change(&up->port, status & UART_MSR_CTS); 	wake_up_interruptible(&up->port.state->port.delta_msr_wait);} /* * This handles the interrupt from one port. */static inline irqreturn_t serial_pxa_irq(int irq, void *dev_id){	struct uart_pxa_port *up = dev_id;	unsigned int iir, lsr; 	iir = serial_in(up, UART_IIR);	if (iir & UART_IIR_NO_INT)		return IRQ_NONE;	uart_port_lock(&up->port);	lsr = serial_in(up, UART_LSR);	if (lsr & UART_LSR_DR)		receive_chars(up, &lsr);	check_modem_status(up);	if (lsr & UART_LSR_THRE)		transmit_chars(up);	uart_unlock_and_check_sysrq(&up->port);	return IRQ_HANDLED;} static unsigned int serial_pxa_tx_empty(struct uart_port *port){	struct uart_pxa_port *up = (struct uart_pxa_port *)port;	unsigned long flags;	unsigned int ret; 	uart_port_lock_irqsave(&up->port, &flags);	ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;	uart_port_unlock_irqrestore(&up->port, flags); 	return ret;} static unsigned int serial_pxa_get_mctrl(struct uart_port *port){	struct uart_pxa_port *up = (struct uart_pxa_port *)port;	unsigned char status;	unsigned int ret; 	status = serial_in(up, UART_MSR); 	ret = 0;	if (status & UART_MSR_DCD)		ret |= TIOCM_CAR;	if (status & UART_MSR_RI)		ret |= TIOCM_RNG;	if (status & UART_MSR_DSR)		ret |= TIOCM_DSR;	if (status & UART_MSR_CTS)		ret |= TIOCM_CTS;	return ret;} static void serial_pxa_set_mctrl(struct uart_port *port, unsigned int mctrl){	struct uart_pxa_port *up = (struct uart_pxa_port *)port;	unsigned char mcr = 0; 	if (mctrl & TIOCM_RTS)		mcr |= UART_MCR_RTS;	if (mctrl & TIOCM_DTR)		mcr |= UART_MCR_DTR;	if (mctrl & TIOCM_OUT1)		mcr |= UART_MCR_OUT1;	if (mctrl & TIOCM_OUT2)		mcr |= UART_MCR_OUT2;	if (mctrl & TIOCM_LOOP)		mcr |= UART_MCR_LOOP; 	mcr |= up->mcr; 	serial_out(up, UART_MCR, mcr);} static void serial_pxa_break_ctl(struct uart_port *port, int break_state){	struct uart_pxa_port *up = (struct uart_pxa_port *)port;	unsigned long flags; 	uart_port_lock_irqsave(&up->port, &flags);	if (break_state == -1)		up->lcr |= UART_LCR_SBC;	else		up->lcr &= ~UART_LCR_SBC;	serial_out(up, UART_LCR, up->lcr);	uart_port_unlock_irqrestore(&up->port, flags);} static int serial_pxa_startup(struct uart_port *port){	struct uart_pxa_port *up = (struct uart_pxa_port *)port;	unsigned long flags;	int retval; 	if (port->line == 3) /* HWUART */		up->mcr |= UART_MCR_AFE;	else		up->mcr = 0; 	up->port.uartclk = clk_get_rate(up->clk); 	/*	 * Allocate the IRQ	 */	retval = request_irq(up->port.irq, serial_pxa_irq, 0, up->name, up);	if (retval)		return retval; 	/*	 * Clear the FIFO buffers and disable them.	 * (they will be reenabled in set_termios())	 */	serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);	serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |			UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);	serial_out(up, UART_FCR, 0); 	/*	 * Clear the interrupt registers.	 */	(void) serial_in(up, UART_LSR);	(void) serial_in(up, UART_RX);	(void) serial_in(up, UART_IIR);	(void) serial_in(up, UART_MSR); 	/*	 * Now, initialize the UART	 */	serial_out(up, UART_LCR, UART_LCR_WLEN8); 	uart_port_lock_irqsave(&up->port, &flags);	up->port.mctrl |= TIOCM_OUT2;	serial_pxa_set_mctrl(&up->port, up->port.mctrl);	uart_port_unlock_irqrestore(&up->port, flags); 	/*	 * Finally, enable interrupts.  Note: Modem status interrupts	 * are set via set_termios(), which will be occurring imminently	 * anyway, so we don't enable them here.	 */	up->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE | UART_IER_UUE;	serial_out(up, UART_IER, up->ier); 	/*	 * And clear the interrupt registers again for luck.	 */	(void) serial_in(up, UART_LSR);	(void) serial_in(up, UART_RX);	(void) serial_in(up, UART_IIR);	(void) serial_in(up, UART_MSR); 	return 0;} static void serial_pxa_shutdown(struct uart_port *port){	struct uart_pxa_port *up = (struct uart_pxa_port *)port;	unsigned long flags; 	free_irq(up->port.irq, up); 	/*	 * Disable interrupts from this port	 */	up->ier = 0;	serial_out(up, UART_IER, 0); 	uart_port_lock_irqsave(&up->port, &flags);	up->port.mctrl &= ~TIOCM_OUT2;	serial_pxa_set_mctrl(&up->port, up->port.mctrl);	uart_port_unlock_irqrestore(&up->port, flags); 	/*	 * Disable break condition and FIFOs	 */	serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC);	serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |				  UART_FCR_CLEAR_RCVR |				  UART_FCR_CLEAR_XMIT);	serial_out(up, UART_FCR, 0);} static voidserial_pxa_set_termios(struct uart_port *port, struct ktermios *termios,		       const struct ktermios *old){	struct uart_pxa_port *up = (struct uart_pxa_port *)port;	unsigned char cval, fcr = 0;	unsigned long flags;	unsigned int baud, quot;	unsigned int dll; 	cval = UART_LCR_WLEN(tty_get_char_size(termios->c_cflag)); 	if (termios->c_cflag & CSTOPB)		cval |= UART_LCR_STOP;	if (termios->c_cflag & PARENB)		cval |= UART_LCR_PARITY;	if (!(termios->c_cflag & PARODD))		cval |= UART_LCR_EPAR; 	/*	 * Ask the core to calculate the divisor for us.	 */	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);	quot = uart_get_divisor(port, baud); 	if ((up->port.uartclk / quot) < (2400 * 16))		fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR1;	else if ((up->port.uartclk / quot) < (230400 * 16))		fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR8;	else		fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR32; 	/*	 * Ok, we're now changing the port state.  Do it with	 * interrupts disabled.	 */	uart_port_lock_irqsave(&up->port, &flags); 	/*	 * Ensure the port will be enabled.	 * This is required especially for serial console.	 */	up->ier |= UART_IER_UUE; 	/*	 * Update the per-port timeout.	 */	uart_update_timeout(port, termios->c_cflag, baud); 	up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;	if (termios->c_iflag & INPCK)		up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))		up->port.read_status_mask |= UART_LSR_BI; 	/*	 * Characters to ignore	 */	up->port.ignore_status_mask = 0;	if (termios->c_iflag & IGNPAR)		up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;	if (termios->c_iflag & IGNBRK) {		up->port.ignore_status_mask |= UART_LSR_BI;		/*		 * If we're ignoring parity and break indicators,		 * ignore overruns too (for real raw support).		 */		if (termios->c_iflag & IGNPAR)			up->port.ignore_status_mask |= UART_LSR_OE;	} 	/*	 * ignore all characters if CREAD is not set	 */	if ((termios->c_cflag & CREAD) == 0)		up->port.ignore_status_mask |= UART_LSR_DR; 	/*	 * CTS flow control flag and modem status interrupts	 */	up->ier &= ~UART_IER_MSI;	if (UART_ENABLE_MS(&up->port, termios->c_cflag))		up->ier |= UART_IER_MSI; 	serial_out(up, UART_IER, up->ier); 	if (termios->c_cflag & CRTSCTS)		up->mcr |= UART_MCR_AFE;	else		up->mcr &= ~UART_MCR_AFE; 	serial_out(up, UART_LCR, cval | UART_LCR_DLAB);	/* set DLAB */	serial_out(up, UART_DLL, quot & 0xff);		/* LS of divisor */ 	/*	 * work around Errata #75 according to Intel(R) PXA27x Processor Family	 * Specification Update (Nov 2005)	 */	dll = serial_in(up, UART_DLL);	WARN_ON(dll != (quot & 0xff));

Lines 1–500 of 903.