18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/************************************************************************
38c2ecf20Sopenharmony_ci * Copyright 2003 Digi International (www.digi.com)
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2004 IBM Corporation. All rights reserved.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Contact Information:
88c2ecf20Sopenharmony_ci * Scott H Kilau <Scott_Kilau@digi.com>
98c2ecf20Sopenharmony_ci * Wendy Xiong   <wendyx@us.ibm.com>
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci ***********************************************************************/
128c2ecf20Sopenharmony_ci#include <linux/delay.h>	/* For udelay */
138c2ecf20Sopenharmony_ci#include <linux/serial_reg.h>	/* For the various UART offsets */
148c2ecf20Sopenharmony_ci#include <linux/tty.h>
158c2ecf20Sopenharmony_ci#include <linux/pci.h>
168c2ecf20Sopenharmony_ci#include <asm/io.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include "jsm.h"		/* Driver main header file */
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic u32 jsm_offset_table[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci/*
238c2ecf20Sopenharmony_ci * This function allows calls to ensure that all outstanding
248c2ecf20Sopenharmony_ci * PCI writes have been completed, by doing a PCI read against
258c2ecf20Sopenharmony_ci * a non-destructive, read-only location on the Neo card.
268c2ecf20Sopenharmony_ci *
278c2ecf20Sopenharmony_ci * In this case, we are reading the DVID (Read-only Device Identification)
288c2ecf20Sopenharmony_ci * value of the Neo card.
298c2ecf20Sopenharmony_ci */
308c2ecf20Sopenharmony_cistatic inline void neo_pci_posting_flush(struct jsm_board *bd)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci      readb(bd->re_map_membase + 0x8D);
338c2ecf20Sopenharmony_ci}
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistatic void neo_set_cts_flow_control(struct jsm_channel *ch)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	u8 ier, efr;
388c2ecf20Sopenharmony_ci	ier = readb(&ch->ch_neo_uart->ier);
398c2ecf20Sopenharmony_ci	efr = readb(&ch->ch_neo_uart->efr);
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	jsm_dbg(PARAM, &ch->ch_bd->pci_dev, "Setting CTSFLOW\n");
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	/* Turn on auto CTS flow control */
448c2ecf20Sopenharmony_ci	ier |= (UART_17158_IER_CTSDSR);
458c2ecf20Sopenharmony_ci	efr |= (UART_17158_EFR_ECB | UART_17158_EFR_CTSDSR);
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	/* Turn off auto Xon flow control */
488c2ecf20Sopenharmony_ci	efr &= ~(UART_17158_EFR_IXON);
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	/* Why? Becuz Exar's spec says we have to zero it out before setting it */
518c2ecf20Sopenharmony_ci	writeb(0, &ch->ch_neo_uart->efr);
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	/* Turn on UART enhanced bits */
548c2ecf20Sopenharmony_ci	writeb(efr, &ch->ch_neo_uart->efr);
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	/* Turn on table D, with 8 char hi/low watermarks */
578c2ecf20Sopenharmony_ci	writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_4DELAY), &ch->ch_neo_uart->fctr);
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	/* Feed the UART our trigger levels */
608c2ecf20Sopenharmony_ci	writeb(8, &ch->ch_neo_uart->tfifo);
618c2ecf20Sopenharmony_ci	ch->ch_t_tlevel = 8;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	writeb(ier, &ch->ch_neo_uart->ier);
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic void neo_set_rts_flow_control(struct jsm_channel *ch)
678c2ecf20Sopenharmony_ci{
688c2ecf20Sopenharmony_ci	u8 ier, efr;
698c2ecf20Sopenharmony_ci	ier = readb(&ch->ch_neo_uart->ier);
708c2ecf20Sopenharmony_ci	efr = readb(&ch->ch_neo_uart->efr);
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	jsm_dbg(PARAM, &ch->ch_bd->pci_dev, "Setting RTSFLOW\n");
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	/* Turn on auto RTS flow control */
758c2ecf20Sopenharmony_ci	ier |= (UART_17158_IER_RTSDTR);
768c2ecf20Sopenharmony_ci	efr |= (UART_17158_EFR_ECB | UART_17158_EFR_RTSDTR);
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	/* Turn off auto Xoff flow control */
798c2ecf20Sopenharmony_ci	ier &= ~(UART_17158_IER_XOFF);
808c2ecf20Sopenharmony_ci	efr &= ~(UART_17158_EFR_IXOFF);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	/* Why? Becuz Exar's spec says we have to zero it out before setting it */
838c2ecf20Sopenharmony_ci	writeb(0, &ch->ch_neo_uart->efr);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	/* Turn on UART enhanced bits */
868c2ecf20Sopenharmony_ci	writeb(efr, &ch->ch_neo_uart->efr);
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_4DELAY), &ch->ch_neo_uart->fctr);
898c2ecf20Sopenharmony_ci	ch->ch_r_watermark = 4;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	writeb(56, &ch->ch_neo_uart->rfifo);
928c2ecf20Sopenharmony_ci	ch->ch_r_tlevel = 56;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	writeb(ier, &ch->ch_neo_uart->ier);
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	/*
978c2ecf20Sopenharmony_ci	 * From the Neo UART spec sheet:
988c2ecf20Sopenharmony_ci	 * The auto RTS/DTR function must be started by asserting
998c2ecf20Sopenharmony_ci	 * RTS/DTR# output pin (MCR bit-0 or 1 to logic 1 after
1008c2ecf20Sopenharmony_ci	 * it is enabled.
1018c2ecf20Sopenharmony_ci	 */
1028c2ecf20Sopenharmony_ci	ch->ch_mostat |= (UART_MCR_RTS);
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic void neo_set_ixon_flow_control(struct jsm_channel *ch)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	u8 ier, efr;
1098c2ecf20Sopenharmony_ci	ier = readb(&ch->ch_neo_uart->ier);
1108c2ecf20Sopenharmony_ci	efr = readb(&ch->ch_neo_uart->efr);
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	jsm_dbg(PARAM, &ch->ch_bd->pci_dev, "Setting IXON FLOW\n");
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	/* Turn off auto CTS flow control */
1158c2ecf20Sopenharmony_ci	ier &= ~(UART_17158_IER_CTSDSR);
1168c2ecf20Sopenharmony_ci	efr &= ~(UART_17158_EFR_CTSDSR);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	/* Turn on auto Xon flow control */
1198c2ecf20Sopenharmony_ci	efr |= (UART_17158_EFR_ECB | UART_17158_EFR_IXON);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	/* Why? Becuz Exar's spec says we have to zero it out before setting it */
1228c2ecf20Sopenharmony_ci	writeb(0, &ch->ch_neo_uart->efr);
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	/* Turn on UART enhanced bits */
1258c2ecf20Sopenharmony_ci	writeb(efr, &ch->ch_neo_uart->efr);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr);
1288c2ecf20Sopenharmony_ci	ch->ch_r_watermark = 4;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	writeb(32, &ch->ch_neo_uart->rfifo);
1318c2ecf20Sopenharmony_ci	ch->ch_r_tlevel = 32;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	/* Tell UART what start/stop chars it should be looking for */
1348c2ecf20Sopenharmony_ci	writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1);
1358c2ecf20Sopenharmony_ci	writeb(0, &ch->ch_neo_uart->xonchar2);
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1);
1388c2ecf20Sopenharmony_ci	writeb(0, &ch->ch_neo_uart->xoffchar2);
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	writeb(ier, &ch->ch_neo_uart->ier);
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic void neo_set_ixoff_flow_control(struct jsm_channel *ch)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	u8 ier, efr;
1468c2ecf20Sopenharmony_ci	ier = readb(&ch->ch_neo_uart->ier);
1478c2ecf20Sopenharmony_ci	efr = readb(&ch->ch_neo_uart->efr);
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	jsm_dbg(PARAM, &ch->ch_bd->pci_dev, "Setting IXOFF FLOW\n");
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	/* Turn off auto RTS flow control */
1528c2ecf20Sopenharmony_ci	ier &= ~(UART_17158_IER_RTSDTR);
1538c2ecf20Sopenharmony_ci	efr &= ~(UART_17158_EFR_RTSDTR);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	/* Turn on auto Xoff flow control */
1568c2ecf20Sopenharmony_ci	ier |= (UART_17158_IER_XOFF);
1578c2ecf20Sopenharmony_ci	efr |= (UART_17158_EFR_ECB | UART_17158_EFR_IXOFF);
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	/* Why? Becuz Exar's spec says we have to zero it out before setting it */
1608c2ecf20Sopenharmony_ci	writeb(0, &ch->ch_neo_uart->efr);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	/* Turn on UART enhanced bits */
1638c2ecf20Sopenharmony_ci	writeb(efr, &ch->ch_neo_uart->efr);
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	/* Turn on table D, with 8 char hi/low watermarks */
1668c2ecf20Sopenharmony_ci	writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr);
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	writeb(8, &ch->ch_neo_uart->tfifo);
1698c2ecf20Sopenharmony_ci	ch->ch_t_tlevel = 8;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	/* Tell UART what start/stop chars it should be looking for */
1728c2ecf20Sopenharmony_ci	writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1);
1738c2ecf20Sopenharmony_ci	writeb(0, &ch->ch_neo_uart->xonchar2);
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1);
1768c2ecf20Sopenharmony_ci	writeb(0, &ch->ch_neo_uart->xoffchar2);
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	writeb(ier, &ch->ch_neo_uart->ier);
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_cistatic void neo_set_no_input_flow_control(struct jsm_channel *ch)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	u8 ier, efr;
1848c2ecf20Sopenharmony_ci	ier = readb(&ch->ch_neo_uart->ier);
1858c2ecf20Sopenharmony_ci	efr = readb(&ch->ch_neo_uart->efr);
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	jsm_dbg(PARAM, &ch->ch_bd->pci_dev, "Unsetting Input FLOW\n");
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	/* Turn off auto RTS flow control */
1908c2ecf20Sopenharmony_ci	ier &= ~(UART_17158_IER_RTSDTR);
1918c2ecf20Sopenharmony_ci	efr &= ~(UART_17158_EFR_RTSDTR);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	/* Turn off auto Xoff flow control */
1948c2ecf20Sopenharmony_ci	ier &= ~(UART_17158_IER_XOFF);
1958c2ecf20Sopenharmony_ci	if (ch->ch_c_iflag & IXON)
1968c2ecf20Sopenharmony_ci		efr &= ~(UART_17158_EFR_IXOFF);
1978c2ecf20Sopenharmony_ci	else
1988c2ecf20Sopenharmony_ci		efr &= ~(UART_17158_EFR_ECB | UART_17158_EFR_IXOFF);
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	/* Why? Becuz Exar's spec says we have to zero it out before setting it */
2018c2ecf20Sopenharmony_ci	writeb(0, &ch->ch_neo_uart->efr);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	/* Turn on UART enhanced bits */
2048c2ecf20Sopenharmony_ci	writeb(efr, &ch->ch_neo_uart->efr);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	/* Turn on table D, with 8 char hi/low watermarks */
2078c2ecf20Sopenharmony_ci	writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr);
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	ch->ch_r_watermark = 0;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	writeb(16, &ch->ch_neo_uart->tfifo);
2128c2ecf20Sopenharmony_ci	ch->ch_t_tlevel = 16;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	writeb(16, &ch->ch_neo_uart->rfifo);
2158c2ecf20Sopenharmony_ci	ch->ch_r_tlevel = 16;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	writeb(ier, &ch->ch_neo_uart->ier);
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_cistatic void neo_set_no_output_flow_control(struct jsm_channel *ch)
2218c2ecf20Sopenharmony_ci{
2228c2ecf20Sopenharmony_ci	u8 ier, efr;
2238c2ecf20Sopenharmony_ci	ier = readb(&ch->ch_neo_uart->ier);
2248c2ecf20Sopenharmony_ci	efr = readb(&ch->ch_neo_uart->efr);
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	jsm_dbg(PARAM, &ch->ch_bd->pci_dev, "Unsetting Output FLOW\n");
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	/* Turn off auto CTS flow control */
2298c2ecf20Sopenharmony_ci	ier &= ~(UART_17158_IER_CTSDSR);
2308c2ecf20Sopenharmony_ci	efr &= ~(UART_17158_EFR_CTSDSR);
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	/* Turn off auto Xon flow control */
2338c2ecf20Sopenharmony_ci	if (ch->ch_c_iflag & IXOFF)
2348c2ecf20Sopenharmony_ci		efr &= ~(UART_17158_EFR_IXON);
2358c2ecf20Sopenharmony_ci	else
2368c2ecf20Sopenharmony_ci		efr &= ~(UART_17158_EFR_ECB | UART_17158_EFR_IXON);
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	/* Why? Becuz Exar's spec says we have to zero it out before setting it */
2398c2ecf20Sopenharmony_ci	writeb(0, &ch->ch_neo_uart->efr);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	/* Turn on UART enhanced bits */
2428c2ecf20Sopenharmony_ci	writeb(efr, &ch->ch_neo_uart->efr);
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	/* Turn on table D, with 8 char hi/low watermarks */
2458c2ecf20Sopenharmony_ci	writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr);
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	ch->ch_r_watermark = 0;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	writeb(16, &ch->ch_neo_uart->tfifo);
2508c2ecf20Sopenharmony_ci	ch->ch_t_tlevel = 16;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	writeb(16, &ch->ch_neo_uart->rfifo);
2538c2ecf20Sopenharmony_ci	ch->ch_r_tlevel = 16;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	writeb(ier, &ch->ch_neo_uart->ier);
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_cistatic inline void neo_set_new_start_stop_chars(struct jsm_channel *ch)
2598c2ecf20Sopenharmony_ci{
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	/* if hardware flow control is set, then skip this whole thing */
2628c2ecf20Sopenharmony_ci	if (ch->ch_c_cflag & CRTSCTS)
2638c2ecf20Sopenharmony_ci		return;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	jsm_dbg(PARAM, &ch->ch_bd->pci_dev, "start\n");
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	/* Tell UART what start/stop chars it should be looking for */
2688c2ecf20Sopenharmony_ci	writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1);
2698c2ecf20Sopenharmony_ci	writeb(0, &ch->ch_neo_uart->xonchar2);
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1);
2728c2ecf20Sopenharmony_ci	writeb(0, &ch->ch_neo_uart->xoffchar2);
2738c2ecf20Sopenharmony_ci}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_cistatic void neo_copy_data_from_uart_to_queue(struct jsm_channel *ch)
2768c2ecf20Sopenharmony_ci{
2778c2ecf20Sopenharmony_ci	int qleft = 0;
2788c2ecf20Sopenharmony_ci	u8 linestatus = 0;
2798c2ecf20Sopenharmony_ci	u8 error_mask = 0;
2808c2ecf20Sopenharmony_ci	int n = 0;
2818c2ecf20Sopenharmony_ci	int total = 0;
2828c2ecf20Sopenharmony_ci	u16 head;
2838c2ecf20Sopenharmony_ci	u16 tail;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	/* cache head and tail of queue */
2868c2ecf20Sopenharmony_ci	head = ch->ch_r_head & RQUEUEMASK;
2878c2ecf20Sopenharmony_ci	tail = ch->ch_r_tail & RQUEUEMASK;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	/* Get our cached LSR */
2908c2ecf20Sopenharmony_ci	linestatus = ch->ch_cached_lsr;
2918c2ecf20Sopenharmony_ci	ch->ch_cached_lsr = 0;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	/* Store how much space we have left in the queue */
2948c2ecf20Sopenharmony_ci	if ((qleft = tail - head - 1) < 0)
2958c2ecf20Sopenharmony_ci		qleft += RQUEUEMASK + 1;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	/*
2988c2ecf20Sopenharmony_ci	 * If the UART is not in FIFO mode, force the FIFO copy to
2998c2ecf20Sopenharmony_ci	 * NOT be run, by setting total to 0.
3008c2ecf20Sopenharmony_ci	 *
3018c2ecf20Sopenharmony_ci	 * On the other hand, if the UART IS in FIFO mode, then ask
3028c2ecf20Sopenharmony_ci	 * the UART to give us an approximation of data it has RX'ed.
3038c2ecf20Sopenharmony_ci	 */
3048c2ecf20Sopenharmony_ci	if (!(ch->ch_flags & CH_FIFO_ENABLED))
3058c2ecf20Sopenharmony_ci		total = 0;
3068c2ecf20Sopenharmony_ci	else {
3078c2ecf20Sopenharmony_ci		total = readb(&ch->ch_neo_uart->rfifo);
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci		/*
3108c2ecf20Sopenharmony_ci		 * EXAR chip bug - RX FIFO COUNT - Fudge factor.
3118c2ecf20Sopenharmony_ci		 *
3128c2ecf20Sopenharmony_ci		 * This resolves a problem/bug with the Exar chip that sometimes
3138c2ecf20Sopenharmony_ci		 * returns a bogus value in the rfifo register.
3148c2ecf20Sopenharmony_ci		 * The count can be any where from 0-3 bytes "off".
3158c2ecf20Sopenharmony_ci		 * Bizarre, but true.
3168c2ecf20Sopenharmony_ci		 */
3178c2ecf20Sopenharmony_ci		total -= 3;
3188c2ecf20Sopenharmony_ci	}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	/*
3218c2ecf20Sopenharmony_ci	 * Finally, bound the copy to make sure we don't overflow
3228c2ecf20Sopenharmony_ci	 * our own queue...
3238c2ecf20Sopenharmony_ci	 * The byte by byte copy loop below this loop this will
3248c2ecf20Sopenharmony_ci	 * deal with the queue overflow possibility.
3258c2ecf20Sopenharmony_ci	 */
3268c2ecf20Sopenharmony_ci	total = min(total, qleft);
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	while (total > 0) {
3298c2ecf20Sopenharmony_ci		/*
3308c2ecf20Sopenharmony_ci		 * Grab the linestatus register, we need to check
3318c2ecf20Sopenharmony_ci		 * to see if there are any errors in the FIFO.
3328c2ecf20Sopenharmony_ci		 */
3338c2ecf20Sopenharmony_ci		linestatus = readb(&ch->ch_neo_uart->lsr);
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci		/*
3368c2ecf20Sopenharmony_ci		 * Break out if there is a FIFO error somewhere.
3378c2ecf20Sopenharmony_ci		 * This will allow us to go byte by byte down below,
3388c2ecf20Sopenharmony_ci		 * finding the exact location of the error.
3398c2ecf20Sopenharmony_ci		 */
3408c2ecf20Sopenharmony_ci		if (linestatus & UART_17158_RX_FIFO_DATA_ERROR)
3418c2ecf20Sopenharmony_ci			break;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci		/* Make sure we don't go over the end of our queue */
3448c2ecf20Sopenharmony_ci		n = min(((u32) total), (RQUEUESIZE - (u32) head));
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci		/*
3478c2ecf20Sopenharmony_ci		 * Cut down n even further if needed, this is to fix
3488c2ecf20Sopenharmony_ci		 * a problem with memcpy_fromio() with the Neo on the
3498c2ecf20Sopenharmony_ci		 * IBM pSeries platform.
3508c2ecf20Sopenharmony_ci		 * 15 bytes max appears to be the magic number.
3518c2ecf20Sopenharmony_ci		 */
3528c2ecf20Sopenharmony_ci		n = min((u32) n, (u32) 12);
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci		/*
3558c2ecf20Sopenharmony_ci		 * Since we are grabbing the linestatus register, which
3568c2ecf20Sopenharmony_ci		 * will reset some bits after our read, we need to ensure
3578c2ecf20Sopenharmony_ci		 * we don't miss our TX FIFO emptys.
3588c2ecf20Sopenharmony_ci		 */
3598c2ecf20Sopenharmony_ci		if (linestatus & (UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR))
3608c2ecf20Sopenharmony_ci			ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci		linestatus = 0;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci		/* Copy data from uart to the queue */
3658c2ecf20Sopenharmony_ci		memcpy_fromio(ch->ch_rqueue + head, &ch->ch_neo_uart->txrxburst, n);
3668c2ecf20Sopenharmony_ci		/*
3678c2ecf20Sopenharmony_ci		 * Since RX_FIFO_DATA_ERROR was 0, we are guaranteed
3688c2ecf20Sopenharmony_ci		 * that all the data currently in the FIFO is free of
3698c2ecf20Sopenharmony_ci		 * breaks and parity/frame/orun errors.
3708c2ecf20Sopenharmony_ci		 */
3718c2ecf20Sopenharmony_ci		memset(ch->ch_equeue + head, 0, n);
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci		/* Add to and flip head if needed */
3748c2ecf20Sopenharmony_ci		head = (head + n) & RQUEUEMASK;
3758c2ecf20Sopenharmony_ci		total -= n;
3768c2ecf20Sopenharmony_ci		qleft -= n;
3778c2ecf20Sopenharmony_ci		ch->ch_rxcount += n;
3788c2ecf20Sopenharmony_ci	}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	/*
3818c2ecf20Sopenharmony_ci	 * Create a mask to determine whether we should
3828c2ecf20Sopenharmony_ci	 * insert the character (if any) into our queue.
3838c2ecf20Sopenharmony_ci	 */
3848c2ecf20Sopenharmony_ci	if (ch->ch_c_iflag & IGNBRK)
3858c2ecf20Sopenharmony_ci		error_mask |= UART_LSR_BI;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	/*
3888c2ecf20Sopenharmony_ci	 * Now cleanup any leftover bytes still in the UART.
3898c2ecf20Sopenharmony_ci	 * Also deal with any possible queue overflow here as well.
3908c2ecf20Sopenharmony_ci	 */
3918c2ecf20Sopenharmony_ci	while (1) {
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci		/*
3948c2ecf20Sopenharmony_ci		 * Its possible we have a linestatus from the loop above
3958c2ecf20Sopenharmony_ci		 * this, so we "OR" on any extra bits.
3968c2ecf20Sopenharmony_ci		 */
3978c2ecf20Sopenharmony_ci		linestatus |= readb(&ch->ch_neo_uart->lsr);
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci		/*
4008c2ecf20Sopenharmony_ci		 * If the chip tells us there is no more data pending to
4018c2ecf20Sopenharmony_ci		 * be read, we can then leave.
4028c2ecf20Sopenharmony_ci		 * But before we do, cache the linestatus, just in case.
4038c2ecf20Sopenharmony_ci		 */
4048c2ecf20Sopenharmony_ci		if (!(linestatus & UART_LSR_DR)) {
4058c2ecf20Sopenharmony_ci			ch->ch_cached_lsr = linestatus;
4068c2ecf20Sopenharmony_ci			break;
4078c2ecf20Sopenharmony_ci		}
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci		/* No need to store this bit */
4108c2ecf20Sopenharmony_ci		linestatus &= ~UART_LSR_DR;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci		/*
4138c2ecf20Sopenharmony_ci		 * Since we are grabbing the linestatus register, which
4148c2ecf20Sopenharmony_ci		 * will reset some bits after our read, we need to ensure
4158c2ecf20Sopenharmony_ci		 * we don't miss our TX FIFO emptys.
4168c2ecf20Sopenharmony_ci		 */
4178c2ecf20Sopenharmony_ci		if (linestatus & (UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR)) {
4188c2ecf20Sopenharmony_ci			linestatus &= ~(UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR);
4198c2ecf20Sopenharmony_ci			ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
4208c2ecf20Sopenharmony_ci		}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci		/*
4238c2ecf20Sopenharmony_ci		 * Discard character if we are ignoring the error mask.
4248c2ecf20Sopenharmony_ci		 */
4258c2ecf20Sopenharmony_ci		if (linestatus & error_mask) {
4268c2ecf20Sopenharmony_ci			u8 discard;
4278c2ecf20Sopenharmony_ci			linestatus = 0;
4288c2ecf20Sopenharmony_ci			memcpy_fromio(&discard, &ch->ch_neo_uart->txrxburst, 1);
4298c2ecf20Sopenharmony_ci			continue;
4308c2ecf20Sopenharmony_ci		}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci		/*
4338c2ecf20Sopenharmony_ci		 * If our queue is full, we have no choice but to drop some data.
4348c2ecf20Sopenharmony_ci		 * The assumption is that HWFLOW or SWFLOW should have stopped
4358c2ecf20Sopenharmony_ci		 * things way way before we got to this point.
4368c2ecf20Sopenharmony_ci		 *
4378c2ecf20Sopenharmony_ci		 * I decided that I wanted to ditch the oldest data first,
4388c2ecf20Sopenharmony_ci		 * I hope thats okay with everyone? Yes? Good.
4398c2ecf20Sopenharmony_ci		 */
4408c2ecf20Sopenharmony_ci		while (qleft < 1) {
4418c2ecf20Sopenharmony_ci			jsm_dbg(READ, &ch->ch_bd->pci_dev,
4428c2ecf20Sopenharmony_ci				"Queue full, dropping DATA:%x LSR:%x\n",
4438c2ecf20Sopenharmony_ci				ch->ch_rqueue[tail], ch->ch_equeue[tail]);
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci			ch->ch_r_tail = tail = (tail + 1) & RQUEUEMASK;
4468c2ecf20Sopenharmony_ci			ch->ch_err_overrun++;
4478c2ecf20Sopenharmony_ci			qleft++;
4488c2ecf20Sopenharmony_ci		}
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci		memcpy_fromio(ch->ch_rqueue + head, &ch->ch_neo_uart->txrxburst, 1);
4518c2ecf20Sopenharmony_ci		ch->ch_equeue[head] = (u8) linestatus;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci		jsm_dbg(READ, &ch->ch_bd->pci_dev, "DATA/LSR pair: %x %x\n",
4548c2ecf20Sopenharmony_ci			ch->ch_rqueue[head], ch->ch_equeue[head]);
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci		/* Ditch any remaining linestatus value. */
4578c2ecf20Sopenharmony_ci		linestatus = 0;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci		/* Add to and flip head if needed */
4608c2ecf20Sopenharmony_ci		head = (head + 1) & RQUEUEMASK;
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci		qleft--;
4638c2ecf20Sopenharmony_ci		ch->ch_rxcount++;
4648c2ecf20Sopenharmony_ci	}
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	/*
4678c2ecf20Sopenharmony_ci	 * Write new final heads to channel structure.
4688c2ecf20Sopenharmony_ci	 */
4698c2ecf20Sopenharmony_ci	ch->ch_r_head = head & RQUEUEMASK;
4708c2ecf20Sopenharmony_ci	ch->ch_e_head = head & EQUEUEMASK;
4718c2ecf20Sopenharmony_ci	jsm_input(ch);
4728c2ecf20Sopenharmony_ci}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_cistatic void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch)
4758c2ecf20Sopenharmony_ci{
4768c2ecf20Sopenharmony_ci	u16 head;
4778c2ecf20Sopenharmony_ci	u16 tail;
4788c2ecf20Sopenharmony_ci	int n;
4798c2ecf20Sopenharmony_ci	int s;
4808c2ecf20Sopenharmony_ci	int qlen;
4818c2ecf20Sopenharmony_ci	u32 len_written = 0;
4828c2ecf20Sopenharmony_ci	struct circ_buf *circ;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	if (!ch)
4858c2ecf20Sopenharmony_ci		return;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	circ = &ch->uart_port.state->xmit;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	/* No data to write to the UART */
4908c2ecf20Sopenharmony_ci	if (uart_circ_empty(circ))
4918c2ecf20Sopenharmony_ci		return;
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	/* If port is "stopped", don't send any data to the UART */
4948c2ecf20Sopenharmony_ci	if ((ch->ch_flags & CH_STOP) || (ch->ch_flags & CH_BREAK_SENDING))
4958c2ecf20Sopenharmony_ci		return;
4968c2ecf20Sopenharmony_ci	/*
4978c2ecf20Sopenharmony_ci	 * If FIFOs are disabled. Send data directly to txrx register
4988c2ecf20Sopenharmony_ci	 */
4998c2ecf20Sopenharmony_ci	if (!(ch->ch_flags & CH_FIFO_ENABLED)) {
5008c2ecf20Sopenharmony_ci		u8 lsrbits = readb(&ch->ch_neo_uart->lsr);
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci		ch->ch_cached_lsr |= lsrbits;
5038c2ecf20Sopenharmony_ci		if (ch->ch_cached_lsr & UART_LSR_THRE) {
5048c2ecf20Sopenharmony_ci			ch->ch_cached_lsr &= ~(UART_LSR_THRE);
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci			writeb(circ->buf[circ->tail], &ch->ch_neo_uart->txrx);
5078c2ecf20Sopenharmony_ci			jsm_dbg(WRITE, &ch->ch_bd->pci_dev,
5088c2ecf20Sopenharmony_ci				"Tx data: %x\n", circ->buf[circ->tail]);
5098c2ecf20Sopenharmony_ci			circ->tail = (circ->tail + 1) & (UART_XMIT_SIZE - 1);
5108c2ecf20Sopenharmony_ci			ch->ch_txcount++;
5118c2ecf20Sopenharmony_ci		}
5128c2ecf20Sopenharmony_ci		return;
5138c2ecf20Sopenharmony_ci	}
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	/*
5168c2ecf20Sopenharmony_ci	 * We have to do it this way, because of the EXAR TXFIFO count bug.
5178c2ecf20Sopenharmony_ci	 */
5188c2ecf20Sopenharmony_ci	if (!(ch->ch_flags & (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM)))
5198c2ecf20Sopenharmony_ci		return;
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	n = UART_17158_TX_FIFOSIZE - ch->ch_t_tlevel;
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	/* cache head and tail of queue */
5248c2ecf20Sopenharmony_ci	head = circ->head & (UART_XMIT_SIZE - 1);
5258c2ecf20Sopenharmony_ci	tail = circ->tail & (UART_XMIT_SIZE - 1);
5268c2ecf20Sopenharmony_ci	qlen = uart_circ_chars_pending(circ);
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	/* Find minimum of the FIFO space, versus queue length */
5298c2ecf20Sopenharmony_ci	n = min(n, qlen);
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	while (n > 0) {
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci		s = ((head >= tail) ? head : UART_XMIT_SIZE) - tail;
5348c2ecf20Sopenharmony_ci		s = min(s, n);
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci		if (s <= 0)
5378c2ecf20Sopenharmony_ci			break;
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci		memcpy_toio(&ch->ch_neo_uart->txrxburst, circ->buf + tail, s);
5408c2ecf20Sopenharmony_ci		/* Add and flip queue if needed */
5418c2ecf20Sopenharmony_ci		tail = (tail + s) & (UART_XMIT_SIZE - 1);
5428c2ecf20Sopenharmony_ci		n -= s;
5438c2ecf20Sopenharmony_ci		ch->ch_txcount += s;
5448c2ecf20Sopenharmony_ci		len_written += s;
5458c2ecf20Sopenharmony_ci	}
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	/* Update the final tail */
5488c2ecf20Sopenharmony_ci	circ->tail = tail & (UART_XMIT_SIZE - 1);
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	if (len_written >= ch->ch_t_tlevel)
5518c2ecf20Sopenharmony_ci		ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	if (uart_circ_empty(circ))
5548c2ecf20Sopenharmony_ci		uart_write_wakeup(&ch->uart_port);
5558c2ecf20Sopenharmony_ci}
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_cistatic void neo_parse_modem(struct jsm_channel *ch, u8 signals)
5588c2ecf20Sopenharmony_ci{
5598c2ecf20Sopenharmony_ci	u8 msignals = signals;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	jsm_dbg(MSIGS, &ch->ch_bd->pci_dev,
5628c2ecf20Sopenharmony_ci		"neo_parse_modem: port: %d msignals: %x\n",
5638c2ecf20Sopenharmony_ci		ch->ch_portnum, msignals);
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	/* Scrub off lower bits. They signify delta's, which I don't care about */
5668c2ecf20Sopenharmony_ci	/* Keep DDCD and DDSR though */
5678c2ecf20Sopenharmony_ci	msignals &= 0xf8;
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	if (msignals & UART_MSR_DDCD)
5708c2ecf20Sopenharmony_ci		uart_handle_dcd_change(&ch->uart_port, msignals & UART_MSR_DCD);
5718c2ecf20Sopenharmony_ci	if (msignals & UART_MSR_DDSR)
5728c2ecf20Sopenharmony_ci		uart_handle_cts_change(&ch->uart_port, msignals & UART_MSR_CTS);
5738c2ecf20Sopenharmony_ci	if (msignals & UART_MSR_DCD)
5748c2ecf20Sopenharmony_ci		ch->ch_mistat |= UART_MSR_DCD;
5758c2ecf20Sopenharmony_ci	else
5768c2ecf20Sopenharmony_ci		ch->ch_mistat &= ~UART_MSR_DCD;
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	if (msignals & UART_MSR_DSR)
5798c2ecf20Sopenharmony_ci		ch->ch_mistat |= UART_MSR_DSR;
5808c2ecf20Sopenharmony_ci	else
5818c2ecf20Sopenharmony_ci		ch->ch_mistat &= ~UART_MSR_DSR;
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	if (msignals & UART_MSR_RI)
5848c2ecf20Sopenharmony_ci		ch->ch_mistat |= UART_MSR_RI;
5858c2ecf20Sopenharmony_ci	else
5868c2ecf20Sopenharmony_ci		ch->ch_mistat &= ~UART_MSR_RI;
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	if (msignals & UART_MSR_CTS)
5898c2ecf20Sopenharmony_ci		ch->ch_mistat |= UART_MSR_CTS;
5908c2ecf20Sopenharmony_ci	else
5918c2ecf20Sopenharmony_ci		ch->ch_mistat &= ~UART_MSR_CTS;
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	jsm_dbg(MSIGS, &ch->ch_bd->pci_dev,
5948c2ecf20Sopenharmony_ci		"Port: %d DTR: %d RTS: %d CTS: %d DSR: %d " "RI: %d CD: %d\n",
5958c2ecf20Sopenharmony_ci		ch->ch_portnum,
5968c2ecf20Sopenharmony_ci		!!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_DTR),
5978c2ecf20Sopenharmony_ci		!!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_RTS),
5988c2ecf20Sopenharmony_ci		!!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_CTS),
5998c2ecf20Sopenharmony_ci		!!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DSR),
6008c2ecf20Sopenharmony_ci		!!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_RI),
6018c2ecf20Sopenharmony_ci		!!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DCD));
6028c2ecf20Sopenharmony_ci}
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci/* Make the UART raise any of the output signals we want up */
6058c2ecf20Sopenharmony_cistatic void neo_assert_modem_signals(struct jsm_channel *ch)
6068c2ecf20Sopenharmony_ci{
6078c2ecf20Sopenharmony_ci	if (!ch)
6088c2ecf20Sopenharmony_ci		return;
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	writeb(ch->ch_mostat, &ch->ch_neo_uart->mcr);
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	/* flush write operation */
6138c2ecf20Sopenharmony_ci	neo_pci_posting_flush(ch->ch_bd);
6148c2ecf20Sopenharmony_ci}
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci/*
6178c2ecf20Sopenharmony_ci * Flush the WRITE FIFO on the Neo.
6188c2ecf20Sopenharmony_ci *
6198c2ecf20Sopenharmony_ci * NOTE: Channel lock MUST be held before calling this function!
6208c2ecf20Sopenharmony_ci */
6218c2ecf20Sopenharmony_cistatic void neo_flush_uart_write(struct jsm_channel *ch)
6228c2ecf20Sopenharmony_ci{
6238c2ecf20Sopenharmony_ci	u8 tmp = 0;
6248c2ecf20Sopenharmony_ci	int i = 0;
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	if (!ch)
6278c2ecf20Sopenharmony_ci		return;
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_XMIT), &ch->ch_neo_uart->isr_fcr);
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	for (i = 0; i < 10; i++) {
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci		/* Check to see if the UART feels it completely flushed the FIFO. */
6348c2ecf20Sopenharmony_ci		tmp = readb(&ch->ch_neo_uart->isr_fcr);
6358c2ecf20Sopenharmony_ci		if (tmp & UART_FCR_CLEAR_XMIT) {
6368c2ecf20Sopenharmony_ci			jsm_dbg(IOCTL, &ch->ch_bd->pci_dev,
6378c2ecf20Sopenharmony_ci				"Still flushing TX UART... i: %d\n", i);
6388c2ecf20Sopenharmony_ci			udelay(10);
6398c2ecf20Sopenharmony_ci		}
6408c2ecf20Sopenharmony_ci		else
6418c2ecf20Sopenharmony_ci			break;
6428c2ecf20Sopenharmony_ci	}
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
6458c2ecf20Sopenharmony_ci}
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci/*
6498c2ecf20Sopenharmony_ci * Flush the READ FIFO on the Neo.
6508c2ecf20Sopenharmony_ci *
6518c2ecf20Sopenharmony_ci * NOTE: Channel lock MUST be held before calling this function!
6528c2ecf20Sopenharmony_ci */
6538c2ecf20Sopenharmony_cistatic void neo_flush_uart_read(struct jsm_channel *ch)
6548c2ecf20Sopenharmony_ci{
6558c2ecf20Sopenharmony_ci	u8 tmp = 0;
6568c2ecf20Sopenharmony_ci	int i = 0;
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	if (!ch)
6598c2ecf20Sopenharmony_ci		return;
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci	writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR), &ch->ch_neo_uart->isr_fcr);
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	for (i = 0; i < 10; i++) {
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci		/* Check to see if the UART feels it completely flushed the FIFO. */
6668c2ecf20Sopenharmony_ci		tmp = readb(&ch->ch_neo_uart->isr_fcr);
6678c2ecf20Sopenharmony_ci		if (tmp & 2) {
6688c2ecf20Sopenharmony_ci			jsm_dbg(IOCTL, &ch->ch_bd->pci_dev,
6698c2ecf20Sopenharmony_ci				"Still flushing RX UART... i: %d\n", i);
6708c2ecf20Sopenharmony_ci			udelay(10);
6718c2ecf20Sopenharmony_ci		}
6728c2ecf20Sopenharmony_ci		else
6738c2ecf20Sopenharmony_ci			break;
6748c2ecf20Sopenharmony_ci	}
6758c2ecf20Sopenharmony_ci}
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci/*
6788c2ecf20Sopenharmony_ci * No locks are assumed to be held when calling this function.
6798c2ecf20Sopenharmony_ci */
6808c2ecf20Sopenharmony_cistatic void neo_clear_break(struct jsm_channel *ch)
6818c2ecf20Sopenharmony_ci{
6828c2ecf20Sopenharmony_ci	unsigned long lock_flags;
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ch->ch_lock, lock_flags);
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	/* Turn break off, and unset some variables */
6878c2ecf20Sopenharmony_ci	if (ch->ch_flags & CH_BREAK_SENDING) {
6888c2ecf20Sopenharmony_ci		u8 temp = readb(&ch->ch_neo_uart->lcr);
6898c2ecf20Sopenharmony_ci		writeb((temp & ~UART_LCR_SBC), &ch->ch_neo_uart->lcr);
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci		ch->ch_flags &= ~(CH_BREAK_SENDING);
6928c2ecf20Sopenharmony_ci		jsm_dbg(IOCTL, &ch->ch_bd->pci_dev,
6938c2ecf20Sopenharmony_ci			"clear break Finishing UART_LCR_SBC! finished: %lx\n",
6948c2ecf20Sopenharmony_ci			jiffies);
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci		/* flush write operation */
6978c2ecf20Sopenharmony_ci		neo_pci_posting_flush(ch->ch_bd);
6988c2ecf20Sopenharmony_ci	}
6998c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
7008c2ecf20Sopenharmony_ci}
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci/*
7038c2ecf20Sopenharmony_ci * Parse the ISR register.
7048c2ecf20Sopenharmony_ci */
7058c2ecf20Sopenharmony_cistatic void neo_parse_isr(struct jsm_board *brd, u32 port)
7068c2ecf20Sopenharmony_ci{
7078c2ecf20Sopenharmony_ci	struct jsm_channel *ch;
7088c2ecf20Sopenharmony_ci	u8 isr;
7098c2ecf20Sopenharmony_ci	u8 cause;
7108c2ecf20Sopenharmony_ci	unsigned long lock_flags;
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	if (!brd)
7138c2ecf20Sopenharmony_ci		return;
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	if (port >= brd->maxports)
7168c2ecf20Sopenharmony_ci		return;
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	ch = brd->channels[port];
7198c2ecf20Sopenharmony_ci	if (!ch)
7208c2ecf20Sopenharmony_ci		return;
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	/* Here we try to figure out what caused the interrupt to happen */
7238c2ecf20Sopenharmony_ci	while (1) {
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci		isr = readb(&ch->ch_neo_uart->isr_fcr);
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci		/* Bail if no pending interrupt */
7288c2ecf20Sopenharmony_ci		if (isr & UART_IIR_NO_INT)
7298c2ecf20Sopenharmony_ci			break;
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci		/*
7328c2ecf20Sopenharmony_ci		 * Yank off the upper 2 bits, which just show that the FIFO's are enabled.
7338c2ecf20Sopenharmony_ci		 */
7348c2ecf20Sopenharmony_ci		isr &= ~(UART_17158_IIR_FIFO_ENABLED);
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci		jsm_dbg(INTR, &ch->ch_bd->pci_dev, "%s:%d isr: %x\n",
7378c2ecf20Sopenharmony_ci			__FILE__, __LINE__, isr);
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci		if (isr & (UART_17158_IIR_RDI_TIMEOUT | UART_IIR_RDI)) {
7408c2ecf20Sopenharmony_ci			/* Read data from uart -> queue */
7418c2ecf20Sopenharmony_ci			neo_copy_data_from_uart_to_queue(ch);
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci			/* Call our tty layer to enforce queue flow control if needed. */
7448c2ecf20Sopenharmony_ci			spin_lock_irqsave(&ch->ch_lock, lock_flags);
7458c2ecf20Sopenharmony_ci			jsm_check_queue_flow_control(ch);
7468c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
7478c2ecf20Sopenharmony_ci		}
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci		if (isr & UART_IIR_THRI) {
7508c2ecf20Sopenharmony_ci			/* Transfer data (if any) from Write Queue -> UART. */
7518c2ecf20Sopenharmony_ci			spin_lock_irqsave(&ch->ch_lock, lock_flags);
7528c2ecf20Sopenharmony_ci			ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
7538c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
7548c2ecf20Sopenharmony_ci			neo_copy_data_from_queue_to_uart(ch);
7558c2ecf20Sopenharmony_ci		}
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci		if (isr & UART_17158_IIR_XONXOFF) {
7588c2ecf20Sopenharmony_ci			cause = readb(&ch->ch_neo_uart->xoffchar1);
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci			jsm_dbg(INTR, &ch->ch_bd->pci_dev,
7618c2ecf20Sopenharmony_ci				"Port %d. Got ISR_XONXOFF: cause:%x\n",
7628c2ecf20Sopenharmony_ci				port, cause);
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci			/*
7658c2ecf20Sopenharmony_ci			 * Since the UART detected either an XON or
7668c2ecf20Sopenharmony_ci			 * XOFF match, we need to figure out which
7678c2ecf20Sopenharmony_ci			 * one it was, so we can suspend or resume data flow.
7688c2ecf20Sopenharmony_ci			 */
7698c2ecf20Sopenharmony_ci			spin_lock_irqsave(&ch->ch_lock, lock_flags);
7708c2ecf20Sopenharmony_ci			if (cause == UART_17158_XON_DETECT) {
7718c2ecf20Sopenharmony_ci				/* Is output stopped right now, if so, resume it */
7728c2ecf20Sopenharmony_ci				if (brd->channels[port]->ch_flags & CH_STOP) {
7738c2ecf20Sopenharmony_ci					ch->ch_flags &= ~(CH_STOP);
7748c2ecf20Sopenharmony_ci				}
7758c2ecf20Sopenharmony_ci				jsm_dbg(INTR, &ch->ch_bd->pci_dev,
7768c2ecf20Sopenharmony_ci					"Port %d. XON detected in incoming data\n",
7778c2ecf20Sopenharmony_ci					port);
7788c2ecf20Sopenharmony_ci			}
7798c2ecf20Sopenharmony_ci			else if (cause == UART_17158_XOFF_DETECT) {
7808c2ecf20Sopenharmony_ci				if (!(brd->channels[port]->ch_flags & CH_STOP)) {
7818c2ecf20Sopenharmony_ci					ch->ch_flags |= CH_STOP;
7828c2ecf20Sopenharmony_ci					jsm_dbg(INTR, &ch->ch_bd->pci_dev,
7838c2ecf20Sopenharmony_ci						"Setting CH_STOP\n");
7848c2ecf20Sopenharmony_ci				}
7858c2ecf20Sopenharmony_ci				jsm_dbg(INTR, &ch->ch_bd->pci_dev,
7868c2ecf20Sopenharmony_ci					"Port: %d. XOFF detected in incoming data\n",
7878c2ecf20Sopenharmony_ci					port);
7888c2ecf20Sopenharmony_ci			}
7898c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
7908c2ecf20Sopenharmony_ci		}
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci		if (isr & UART_17158_IIR_HWFLOW_STATE_CHANGE) {
7938c2ecf20Sopenharmony_ci			/*
7948c2ecf20Sopenharmony_ci			 * If we get here, this means the hardware is doing auto flow control.
7958c2ecf20Sopenharmony_ci			 * Check to see whether RTS/DTR or CTS/DSR caused this interrupt.
7968c2ecf20Sopenharmony_ci			 */
7978c2ecf20Sopenharmony_ci			cause = readb(&ch->ch_neo_uart->mcr);
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci			/* Which pin is doing auto flow? RTS or DTR? */
8008c2ecf20Sopenharmony_ci			spin_lock_irqsave(&ch->ch_lock, lock_flags);
8018c2ecf20Sopenharmony_ci			if ((cause & 0x4) == 0) {
8028c2ecf20Sopenharmony_ci				if (cause & UART_MCR_RTS)
8038c2ecf20Sopenharmony_ci					ch->ch_mostat |= UART_MCR_RTS;
8048c2ecf20Sopenharmony_ci				else
8058c2ecf20Sopenharmony_ci					ch->ch_mostat &= ~(UART_MCR_RTS);
8068c2ecf20Sopenharmony_ci			} else {
8078c2ecf20Sopenharmony_ci				if (cause & UART_MCR_DTR)
8088c2ecf20Sopenharmony_ci					ch->ch_mostat |= UART_MCR_DTR;
8098c2ecf20Sopenharmony_ci				else
8108c2ecf20Sopenharmony_ci					ch->ch_mostat &= ~(UART_MCR_DTR);
8118c2ecf20Sopenharmony_ci			}
8128c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
8138c2ecf20Sopenharmony_ci		}
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ci		/* Parse any modem signal changes */
8168c2ecf20Sopenharmony_ci		jsm_dbg(INTR, &ch->ch_bd->pci_dev,
8178c2ecf20Sopenharmony_ci			"MOD_STAT: sending to parse_modem_sigs\n");
8188c2ecf20Sopenharmony_ci		spin_lock_irqsave(&ch->uart_port.lock, lock_flags);
8198c2ecf20Sopenharmony_ci		neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr));
8208c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ch->uart_port.lock, lock_flags);
8218c2ecf20Sopenharmony_ci	}
8228c2ecf20Sopenharmony_ci}
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_cistatic inline void neo_parse_lsr(struct jsm_board *brd, u32 port)
8258c2ecf20Sopenharmony_ci{
8268c2ecf20Sopenharmony_ci	struct jsm_channel *ch;
8278c2ecf20Sopenharmony_ci	int linestatus;
8288c2ecf20Sopenharmony_ci	unsigned long lock_flags;
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	if (!brd)
8318c2ecf20Sopenharmony_ci		return;
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	if (port >= brd->maxports)
8348c2ecf20Sopenharmony_ci		return;
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci	ch = brd->channels[port];
8378c2ecf20Sopenharmony_ci	if (!ch)
8388c2ecf20Sopenharmony_ci		return;
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	linestatus = readb(&ch->ch_neo_uart->lsr);
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	jsm_dbg(INTR, &ch->ch_bd->pci_dev, "%s:%d port: %d linestatus: %x\n",
8438c2ecf20Sopenharmony_ci		__FILE__, __LINE__, port, linestatus);
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	ch->ch_cached_lsr |= linestatus;
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	if (ch->ch_cached_lsr & UART_LSR_DR) {
8488c2ecf20Sopenharmony_ci		/* Read data from uart -> queue */
8498c2ecf20Sopenharmony_ci		neo_copy_data_from_uart_to_queue(ch);
8508c2ecf20Sopenharmony_ci		spin_lock_irqsave(&ch->ch_lock, lock_flags);
8518c2ecf20Sopenharmony_ci		jsm_check_queue_flow_control(ch);
8528c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
8538c2ecf20Sopenharmony_ci	}
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci	/*
8568c2ecf20Sopenharmony_ci	 * This is a special flag. It indicates that at least 1
8578c2ecf20Sopenharmony_ci	 * RX error (parity, framing, or break) has happened.
8588c2ecf20Sopenharmony_ci	 * Mark this in our struct, which will tell me that I have
8598c2ecf20Sopenharmony_ci	 *to do the special RX+LSR read for this FIFO load.
8608c2ecf20Sopenharmony_ci	 */
8618c2ecf20Sopenharmony_ci	if (linestatus & UART_17158_RX_FIFO_DATA_ERROR)
8628c2ecf20Sopenharmony_ci		jsm_dbg(INTR, &ch->ch_bd->pci_dev,
8638c2ecf20Sopenharmony_ci			"%s:%d Port: %d Got an RX error, need to parse LSR\n",
8648c2ecf20Sopenharmony_ci			__FILE__, __LINE__, port);
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	/*
8678c2ecf20Sopenharmony_ci	 * The next 3 tests should *NOT* happen, as the above test
8688c2ecf20Sopenharmony_ci	 * should encapsulate all 3... At least, thats what Exar says.
8698c2ecf20Sopenharmony_ci	 */
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	if (linestatus & UART_LSR_PE) {
8728c2ecf20Sopenharmony_ci		ch->ch_err_parity++;
8738c2ecf20Sopenharmony_ci		jsm_dbg(INTR, &ch->ch_bd->pci_dev, "%s:%d Port: %d. PAR ERR!\n",
8748c2ecf20Sopenharmony_ci			__FILE__, __LINE__, port);
8758c2ecf20Sopenharmony_ci	}
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	if (linestatus & UART_LSR_FE) {
8788c2ecf20Sopenharmony_ci		ch->ch_err_frame++;
8798c2ecf20Sopenharmony_ci		jsm_dbg(INTR, &ch->ch_bd->pci_dev, "%s:%d Port: %d. FRM ERR!\n",
8808c2ecf20Sopenharmony_ci			__FILE__, __LINE__, port);
8818c2ecf20Sopenharmony_ci	}
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci	if (linestatus & UART_LSR_BI) {
8848c2ecf20Sopenharmony_ci		ch->ch_err_break++;
8858c2ecf20Sopenharmony_ci		jsm_dbg(INTR, &ch->ch_bd->pci_dev,
8868c2ecf20Sopenharmony_ci			"%s:%d Port: %d. BRK INTR!\n",
8878c2ecf20Sopenharmony_ci			__FILE__, __LINE__, port);
8888c2ecf20Sopenharmony_ci	}
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	if (linestatus & UART_LSR_OE) {
8918c2ecf20Sopenharmony_ci		/*
8928c2ecf20Sopenharmony_ci		 * Rx Oruns. Exar says that an orun will NOT corrupt
8938c2ecf20Sopenharmony_ci		 * the FIFO. It will just replace the holding register
8948c2ecf20Sopenharmony_ci		 * with this new data byte. So basically just ignore this.
8958c2ecf20Sopenharmony_ci		 * Probably we should eventually have an orun stat in our driver...
8968c2ecf20Sopenharmony_ci		 */
8978c2ecf20Sopenharmony_ci		ch->ch_err_overrun++;
8988c2ecf20Sopenharmony_ci		jsm_dbg(INTR, &ch->ch_bd->pci_dev,
8998c2ecf20Sopenharmony_ci			"%s:%d Port: %d. Rx Overrun!\n",
9008c2ecf20Sopenharmony_ci			__FILE__, __LINE__, port);
9018c2ecf20Sopenharmony_ci	}
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	if (linestatus & UART_LSR_THRE) {
9048c2ecf20Sopenharmony_ci		spin_lock_irqsave(&ch->ch_lock, lock_flags);
9058c2ecf20Sopenharmony_ci		ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
9068c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci		/* Transfer data (if any) from Write Queue -> UART. */
9098c2ecf20Sopenharmony_ci		neo_copy_data_from_queue_to_uart(ch);
9108c2ecf20Sopenharmony_ci	}
9118c2ecf20Sopenharmony_ci	else if (linestatus & UART_17158_TX_AND_FIFO_CLR) {
9128c2ecf20Sopenharmony_ci		spin_lock_irqsave(&ch->ch_lock, lock_flags);
9138c2ecf20Sopenharmony_ci		ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
9148c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci		/* Transfer data (if any) from Write Queue -> UART. */
9178c2ecf20Sopenharmony_ci		neo_copy_data_from_queue_to_uart(ch);
9188c2ecf20Sopenharmony_ci	}
9198c2ecf20Sopenharmony_ci}
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci/*
9228c2ecf20Sopenharmony_ci * neo_param()
9238c2ecf20Sopenharmony_ci * Send any/all changes to the line to the UART.
9248c2ecf20Sopenharmony_ci */
9258c2ecf20Sopenharmony_cistatic void neo_param(struct jsm_channel *ch)
9268c2ecf20Sopenharmony_ci{
9278c2ecf20Sopenharmony_ci	u8 lcr = 0;
9288c2ecf20Sopenharmony_ci	u8 uart_lcr, ier;
9298c2ecf20Sopenharmony_ci	u32 baud;
9308c2ecf20Sopenharmony_ci	int quot;
9318c2ecf20Sopenharmony_ci	struct jsm_board *bd;
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	bd = ch->ch_bd;
9348c2ecf20Sopenharmony_ci	if (!bd)
9358c2ecf20Sopenharmony_ci		return;
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci	/*
9388c2ecf20Sopenharmony_ci	 * If baud rate is zero, flush queues, and set mval to drop DTR.
9398c2ecf20Sopenharmony_ci	 */
9408c2ecf20Sopenharmony_ci	if ((ch->ch_c_cflag & (CBAUD)) == 0) {
9418c2ecf20Sopenharmony_ci		ch->ch_r_head = ch->ch_r_tail = 0;
9428c2ecf20Sopenharmony_ci		ch->ch_e_head = ch->ch_e_tail = 0;
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci		neo_flush_uart_write(ch);
9458c2ecf20Sopenharmony_ci		neo_flush_uart_read(ch);
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci		ch->ch_flags |= (CH_BAUD0);
9488c2ecf20Sopenharmony_ci		ch->ch_mostat &= ~(UART_MCR_RTS | UART_MCR_DTR);
9498c2ecf20Sopenharmony_ci		neo_assert_modem_signals(ch);
9508c2ecf20Sopenharmony_ci		return;
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci	} else {
9538c2ecf20Sopenharmony_ci		int i;
9548c2ecf20Sopenharmony_ci		unsigned int cflag;
9558c2ecf20Sopenharmony_ci		static struct {
9568c2ecf20Sopenharmony_ci			unsigned int rate;
9578c2ecf20Sopenharmony_ci			unsigned int cflag;
9588c2ecf20Sopenharmony_ci		} baud_rates[] = {
9598c2ecf20Sopenharmony_ci			{ 921600, B921600 },
9608c2ecf20Sopenharmony_ci			{ 460800, B460800 },
9618c2ecf20Sopenharmony_ci			{ 230400, B230400 },
9628c2ecf20Sopenharmony_ci			{ 115200, B115200 },
9638c2ecf20Sopenharmony_ci			{  57600, B57600  },
9648c2ecf20Sopenharmony_ci			{  38400, B38400  },
9658c2ecf20Sopenharmony_ci			{  19200, B19200  },
9668c2ecf20Sopenharmony_ci			{   9600, B9600   },
9678c2ecf20Sopenharmony_ci			{   4800, B4800   },
9688c2ecf20Sopenharmony_ci			{   2400, B2400   },
9698c2ecf20Sopenharmony_ci			{   1200, B1200   },
9708c2ecf20Sopenharmony_ci			{    600, B600    },
9718c2ecf20Sopenharmony_ci			{    300, B300    },
9728c2ecf20Sopenharmony_ci			{    200, B200    },
9738c2ecf20Sopenharmony_ci			{    150, B150    },
9748c2ecf20Sopenharmony_ci			{    134, B134    },
9758c2ecf20Sopenharmony_ci			{    110, B110    },
9768c2ecf20Sopenharmony_ci			{     75, B75     },
9778c2ecf20Sopenharmony_ci			{     50, B50     },
9788c2ecf20Sopenharmony_ci		};
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci		cflag = C_BAUD(ch->uart_port.state->port.tty);
9818c2ecf20Sopenharmony_ci		baud = 9600;
9828c2ecf20Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(baud_rates); i++) {
9838c2ecf20Sopenharmony_ci			if (baud_rates[i].cflag == cflag) {
9848c2ecf20Sopenharmony_ci				baud = baud_rates[i].rate;
9858c2ecf20Sopenharmony_ci				break;
9868c2ecf20Sopenharmony_ci			}
9878c2ecf20Sopenharmony_ci		}
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci		if (ch->ch_flags & CH_BAUD0)
9908c2ecf20Sopenharmony_ci			ch->ch_flags &= ~(CH_BAUD0);
9918c2ecf20Sopenharmony_ci	}
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci	if (ch->ch_c_cflag & PARENB)
9948c2ecf20Sopenharmony_ci		lcr |= UART_LCR_PARITY;
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci	if (!(ch->ch_c_cflag & PARODD))
9978c2ecf20Sopenharmony_ci		lcr |= UART_LCR_EPAR;
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci	/*
10008c2ecf20Sopenharmony_ci	 * Not all platforms support mark/space parity,
10018c2ecf20Sopenharmony_ci	 * so this will hide behind an ifdef.
10028c2ecf20Sopenharmony_ci	 */
10038c2ecf20Sopenharmony_ci#ifdef CMSPAR
10048c2ecf20Sopenharmony_ci	if (ch->ch_c_cflag & CMSPAR)
10058c2ecf20Sopenharmony_ci		lcr |= UART_LCR_SPAR;
10068c2ecf20Sopenharmony_ci#endif
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	if (ch->ch_c_cflag & CSTOPB)
10098c2ecf20Sopenharmony_ci		lcr |= UART_LCR_STOP;
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci	switch (ch->ch_c_cflag & CSIZE) {
10128c2ecf20Sopenharmony_ci	case CS5:
10138c2ecf20Sopenharmony_ci		lcr |= UART_LCR_WLEN5;
10148c2ecf20Sopenharmony_ci		break;
10158c2ecf20Sopenharmony_ci	case CS6:
10168c2ecf20Sopenharmony_ci		lcr |= UART_LCR_WLEN6;
10178c2ecf20Sopenharmony_ci		break;
10188c2ecf20Sopenharmony_ci	case CS7:
10198c2ecf20Sopenharmony_ci		lcr |= UART_LCR_WLEN7;
10208c2ecf20Sopenharmony_ci		break;
10218c2ecf20Sopenharmony_ci	case CS8:
10228c2ecf20Sopenharmony_ci	default:
10238c2ecf20Sopenharmony_ci		lcr |= UART_LCR_WLEN8;
10248c2ecf20Sopenharmony_ci	break;
10258c2ecf20Sopenharmony_ci	}
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	ier = readb(&ch->ch_neo_uart->ier);
10288c2ecf20Sopenharmony_ci	uart_lcr = readb(&ch->ch_neo_uart->lcr);
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	quot = ch->ch_bd->bd_dividend / baud;
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci	if (quot != 0) {
10338c2ecf20Sopenharmony_ci		writeb(UART_LCR_DLAB, &ch->ch_neo_uart->lcr);
10348c2ecf20Sopenharmony_ci		writeb((quot & 0xff), &ch->ch_neo_uart->txrx);
10358c2ecf20Sopenharmony_ci		writeb((quot >> 8), &ch->ch_neo_uart->ier);
10368c2ecf20Sopenharmony_ci		writeb(lcr, &ch->ch_neo_uart->lcr);
10378c2ecf20Sopenharmony_ci	}
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci	if (uart_lcr != lcr)
10408c2ecf20Sopenharmony_ci		writeb(lcr, &ch->ch_neo_uart->lcr);
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_ci	if (ch->ch_c_cflag & CREAD)
10438c2ecf20Sopenharmony_ci		ier |= (UART_IER_RDI | UART_IER_RLSI);
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci	ier |= (UART_IER_THRI | UART_IER_MSI);
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	writeb(ier, &ch->ch_neo_uart->ier);
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	/* Set new start/stop chars */
10508c2ecf20Sopenharmony_ci	neo_set_new_start_stop_chars(ch);
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci	if (ch->ch_c_cflag & CRTSCTS)
10538c2ecf20Sopenharmony_ci		neo_set_cts_flow_control(ch);
10548c2ecf20Sopenharmony_ci	else if (ch->ch_c_iflag & IXON) {
10558c2ecf20Sopenharmony_ci		/* If start/stop is set to disable, then we should disable flow control */
10568c2ecf20Sopenharmony_ci		if ((ch->ch_startc == __DISABLED_CHAR) || (ch->ch_stopc == __DISABLED_CHAR))
10578c2ecf20Sopenharmony_ci			neo_set_no_output_flow_control(ch);
10588c2ecf20Sopenharmony_ci		else
10598c2ecf20Sopenharmony_ci			neo_set_ixon_flow_control(ch);
10608c2ecf20Sopenharmony_ci	}
10618c2ecf20Sopenharmony_ci	else
10628c2ecf20Sopenharmony_ci		neo_set_no_output_flow_control(ch);
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	if (ch->ch_c_cflag & CRTSCTS)
10658c2ecf20Sopenharmony_ci		neo_set_rts_flow_control(ch);
10668c2ecf20Sopenharmony_ci	else if (ch->ch_c_iflag & IXOFF) {
10678c2ecf20Sopenharmony_ci		/* If start/stop is set to disable, then we should disable flow control */
10688c2ecf20Sopenharmony_ci		if ((ch->ch_startc == __DISABLED_CHAR) || (ch->ch_stopc == __DISABLED_CHAR))
10698c2ecf20Sopenharmony_ci			neo_set_no_input_flow_control(ch);
10708c2ecf20Sopenharmony_ci		else
10718c2ecf20Sopenharmony_ci			neo_set_ixoff_flow_control(ch);
10728c2ecf20Sopenharmony_ci	}
10738c2ecf20Sopenharmony_ci	else
10748c2ecf20Sopenharmony_ci		neo_set_no_input_flow_control(ch);
10758c2ecf20Sopenharmony_ci	/*
10768c2ecf20Sopenharmony_ci	 * Adjust the RX FIFO Trigger level if baud is less than 9600.
10778c2ecf20Sopenharmony_ci	 * Not exactly elegant, but this is needed because of the Exar chip's
10788c2ecf20Sopenharmony_ci	 * delay on firing off the RX FIFO interrupt on slower baud rates.
10798c2ecf20Sopenharmony_ci	 */
10808c2ecf20Sopenharmony_ci	if (baud < 9600) {
10818c2ecf20Sopenharmony_ci		writeb(1, &ch->ch_neo_uart->rfifo);
10828c2ecf20Sopenharmony_ci		ch->ch_r_tlevel = 1;
10838c2ecf20Sopenharmony_ci	}
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	neo_assert_modem_signals(ch);
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci	/* Get current status of the modem signals now */
10888c2ecf20Sopenharmony_ci	neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr));
10898c2ecf20Sopenharmony_ci	return;
10908c2ecf20Sopenharmony_ci}
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_ci/*
10938c2ecf20Sopenharmony_ci * jsm_neo_intr()
10948c2ecf20Sopenharmony_ci *
10958c2ecf20Sopenharmony_ci * Neo specific interrupt handler.
10968c2ecf20Sopenharmony_ci */
10978c2ecf20Sopenharmony_cistatic irqreturn_t neo_intr(int irq, void *voidbrd)
10988c2ecf20Sopenharmony_ci{
10998c2ecf20Sopenharmony_ci	struct jsm_board *brd = voidbrd;
11008c2ecf20Sopenharmony_ci	struct jsm_channel *ch;
11018c2ecf20Sopenharmony_ci	int port = 0;
11028c2ecf20Sopenharmony_ci	int type = 0;
11038c2ecf20Sopenharmony_ci	int current_port;
11048c2ecf20Sopenharmony_ci	u32 tmp;
11058c2ecf20Sopenharmony_ci	u32 uart_poll;
11068c2ecf20Sopenharmony_ci	unsigned long lock_flags;
11078c2ecf20Sopenharmony_ci	unsigned long lock_flags2;
11088c2ecf20Sopenharmony_ci	int outofloop_count = 0;
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_ci	/* Lock out the slow poller from running on this board. */
11118c2ecf20Sopenharmony_ci	spin_lock_irqsave(&brd->bd_intr_lock, lock_flags);
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_ci	/*
11148c2ecf20Sopenharmony_ci	 * Read in "extended" IRQ information from the 32bit Neo register.
11158c2ecf20Sopenharmony_ci	 * Bits 0-7: What port triggered the interrupt.
11168c2ecf20Sopenharmony_ci	 * Bits 8-31: Each 3bits indicate what type of interrupt occurred.
11178c2ecf20Sopenharmony_ci	 */
11188c2ecf20Sopenharmony_ci	uart_poll = readl(brd->re_map_membase + UART_17158_POLL_ADDR_OFFSET);
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci	jsm_dbg(INTR, &brd->pci_dev, "%s:%d uart_poll: %x\n",
11218c2ecf20Sopenharmony_ci		__FILE__, __LINE__, uart_poll);
11228c2ecf20Sopenharmony_ci
11238c2ecf20Sopenharmony_ci	if (!uart_poll) {
11248c2ecf20Sopenharmony_ci		jsm_dbg(INTR, &brd->pci_dev,
11258c2ecf20Sopenharmony_ci			"Kernel interrupted to me, but no pending interrupts...\n");
11268c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags);
11278c2ecf20Sopenharmony_ci		return IRQ_NONE;
11288c2ecf20Sopenharmony_ci	}
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_ci	/* At this point, we have at least SOMETHING to service, dig further... */
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci	current_port = 0;
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci	/* Loop on each port */
11358c2ecf20Sopenharmony_ci	while (((uart_poll & 0xff) != 0) && (outofloop_count < 0xff)){
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_ci		tmp = uart_poll;
11388c2ecf20Sopenharmony_ci		outofloop_count++;
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_ci		/* Check current port to see if it has interrupt pending */
11418c2ecf20Sopenharmony_ci		if ((tmp & jsm_offset_table[current_port]) != 0) {
11428c2ecf20Sopenharmony_ci			port = current_port;
11438c2ecf20Sopenharmony_ci			type = tmp >> (8 + (port * 3));
11448c2ecf20Sopenharmony_ci			type &= 0x7;
11458c2ecf20Sopenharmony_ci		} else {
11468c2ecf20Sopenharmony_ci			current_port++;
11478c2ecf20Sopenharmony_ci			continue;
11488c2ecf20Sopenharmony_ci		}
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_ci		jsm_dbg(INTR, &brd->pci_dev, "%s:%d port: %x type: %x\n",
11518c2ecf20Sopenharmony_ci			__FILE__, __LINE__, port, type);
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_ci		/* Remove this port + type from uart_poll */
11548c2ecf20Sopenharmony_ci		uart_poll &= ~(jsm_offset_table[port]);
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_ci		if (!type) {
11578c2ecf20Sopenharmony_ci			/* If no type, just ignore it, and move onto next port */
11588c2ecf20Sopenharmony_ci			jsm_dbg(INTR, &brd->pci_dev,
11598c2ecf20Sopenharmony_ci				"Interrupt with no type! port: %d\n", port);
11608c2ecf20Sopenharmony_ci			continue;
11618c2ecf20Sopenharmony_ci		}
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_ci		/* Switch on type of interrupt we have */
11648c2ecf20Sopenharmony_ci		switch (type) {
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci		case UART_17158_RXRDY_TIMEOUT:
11678c2ecf20Sopenharmony_ci			/*
11688c2ecf20Sopenharmony_ci			 * RXRDY Time-out is cleared by reading data in the
11698c2ecf20Sopenharmony_ci			* RX FIFO until it falls below the trigger level.
11708c2ecf20Sopenharmony_ci			 */
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_ci			/* Verify the port is in range. */
11738c2ecf20Sopenharmony_ci			if (port >= brd->nasync)
11748c2ecf20Sopenharmony_ci				continue;
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ci			ch = brd->channels[port];
11778c2ecf20Sopenharmony_ci			if (!ch)
11788c2ecf20Sopenharmony_ci				continue;
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci			neo_copy_data_from_uart_to_queue(ch);
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci			/* Call our tty layer to enforce queue flow control if needed. */
11838c2ecf20Sopenharmony_ci			spin_lock_irqsave(&ch->ch_lock, lock_flags2);
11848c2ecf20Sopenharmony_ci			jsm_check_queue_flow_control(ch);
11858c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci			continue;
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_ci		case UART_17158_RX_LINE_STATUS:
11908c2ecf20Sopenharmony_ci			/*
11918c2ecf20Sopenharmony_ci			 * RXRDY and RX LINE Status (logic OR of LSR[4:1])
11928c2ecf20Sopenharmony_ci			 */
11938c2ecf20Sopenharmony_ci			neo_parse_lsr(brd, port);
11948c2ecf20Sopenharmony_ci			continue;
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_ci		case UART_17158_TXRDY:
11978c2ecf20Sopenharmony_ci			/*
11988c2ecf20Sopenharmony_ci			 * TXRDY interrupt clears after reading ISR register for the UART channel.
11998c2ecf20Sopenharmony_ci			 */
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_ci			/*
12028c2ecf20Sopenharmony_ci			 * Yes, this is odd...
12038c2ecf20Sopenharmony_ci			 * Why would I check EVERY possibility of type of
12048c2ecf20Sopenharmony_ci			 * interrupt, when we know its TXRDY???
12058c2ecf20Sopenharmony_ci			 * Becuz for some reason, even tho we got triggered for TXRDY,
12068c2ecf20Sopenharmony_ci			 * it seems to be occasionally wrong. Instead of TX, which
12078c2ecf20Sopenharmony_ci			 * it should be, I was getting things like RXDY too. Weird.
12088c2ecf20Sopenharmony_ci			 */
12098c2ecf20Sopenharmony_ci			neo_parse_isr(brd, port);
12108c2ecf20Sopenharmony_ci			continue;
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci		case UART_17158_MSR:
12138c2ecf20Sopenharmony_ci			/*
12148c2ecf20Sopenharmony_ci			 * MSR or flow control was seen.
12158c2ecf20Sopenharmony_ci			 */
12168c2ecf20Sopenharmony_ci			neo_parse_isr(brd, port);
12178c2ecf20Sopenharmony_ci			continue;
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci		default:
12208c2ecf20Sopenharmony_ci			/*
12218c2ecf20Sopenharmony_ci			 * The UART triggered us with a bogus interrupt type.
12228c2ecf20Sopenharmony_ci			 * It appears the Exar chip, when REALLY bogged down, will throw
12238c2ecf20Sopenharmony_ci			 * these once and awhile.
12248c2ecf20Sopenharmony_ci			 * Its harmless, just ignore it and move on.
12258c2ecf20Sopenharmony_ci			 */
12268c2ecf20Sopenharmony_ci			jsm_dbg(INTR, &brd->pci_dev,
12278c2ecf20Sopenharmony_ci				"%s:%d Unknown Interrupt type: %x\n",
12288c2ecf20Sopenharmony_ci				__FILE__, __LINE__, type);
12298c2ecf20Sopenharmony_ci			continue;
12308c2ecf20Sopenharmony_ci		}
12318c2ecf20Sopenharmony_ci	}
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags);
12348c2ecf20Sopenharmony_ci
12358c2ecf20Sopenharmony_ci	jsm_dbg(INTR, &brd->pci_dev, "finish\n");
12368c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
12378c2ecf20Sopenharmony_ci}
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_ci/*
12408c2ecf20Sopenharmony_ci * Neo specific way of turning off the receiver.
12418c2ecf20Sopenharmony_ci * Used as a way to enforce queue flow control when in
12428c2ecf20Sopenharmony_ci * hardware flow control mode.
12438c2ecf20Sopenharmony_ci */
12448c2ecf20Sopenharmony_cistatic void neo_disable_receiver(struct jsm_channel *ch)
12458c2ecf20Sopenharmony_ci{
12468c2ecf20Sopenharmony_ci	u8 tmp = readb(&ch->ch_neo_uart->ier);
12478c2ecf20Sopenharmony_ci	tmp &= ~(UART_IER_RDI);
12488c2ecf20Sopenharmony_ci	writeb(tmp, &ch->ch_neo_uart->ier);
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_ci	/* flush write operation */
12518c2ecf20Sopenharmony_ci	neo_pci_posting_flush(ch->ch_bd);
12528c2ecf20Sopenharmony_ci}
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_ci/*
12568c2ecf20Sopenharmony_ci * Neo specific way of turning on the receiver.
12578c2ecf20Sopenharmony_ci * Used as a way to un-enforce queue flow control when in
12588c2ecf20Sopenharmony_ci * hardware flow control mode.
12598c2ecf20Sopenharmony_ci */
12608c2ecf20Sopenharmony_cistatic void neo_enable_receiver(struct jsm_channel *ch)
12618c2ecf20Sopenharmony_ci{
12628c2ecf20Sopenharmony_ci	u8 tmp = readb(&ch->ch_neo_uart->ier);
12638c2ecf20Sopenharmony_ci	tmp |= (UART_IER_RDI);
12648c2ecf20Sopenharmony_ci	writeb(tmp, &ch->ch_neo_uart->ier);
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci	/* flush write operation */
12678c2ecf20Sopenharmony_ci	neo_pci_posting_flush(ch->ch_bd);
12688c2ecf20Sopenharmony_ci}
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_cistatic void neo_send_start_character(struct jsm_channel *ch)
12718c2ecf20Sopenharmony_ci{
12728c2ecf20Sopenharmony_ci	if (!ch)
12738c2ecf20Sopenharmony_ci		return;
12748c2ecf20Sopenharmony_ci
12758c2ecf20Sopenharmony_ci	if (ch->ch_startc != __DISABLED_CHAR) {
12768c2ecf20Sopenharmony_ci		ch->ch_xon_sends++;
12778c2ecf20Sopenharmony_ci		writeb(ch->ch_startc, &ch->ch_neo_uart->txrx);
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci		/* flush write operation */
12808c2ecf20Sopenharmony_ci		neo_pci_posting_flush(ch->ch_bd);
12818c2ecf20Sopenharmony_ci	}
12828c2ecf20Sopenharmony_ci}
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_cistatic void neo_send_stop_character(struct jsm_channel *ch)
12858c2ecf20Sopenharmony_ci{
12868c2ecf20Sopenharmony_ci	if (!ch)
12878c2ecf20Sopenharmony_ci		return;
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci	if (ch->ch_stopc != __DISABLED_CHAR) {
12908c2ecf20Sopenharmony_ci		ch->ch_xoff_sends++;
12918c2ecf20Sopenharmony_ci		writeb(ch->ch_stopc, &ch->ch_neo_uart->txrx);
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci		/* flush write operation */
12948c2ecf20Sopenharmony_ci		neo_pci_posting_flush(ch->ch_bd);
12958c2ecf20Sopenharmony_ci	}
12968c2ecf20Sopenharmony_ci}
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci/*
12998c2ecf20Sopenharmony_ci * neo_uart_init
13008c2ecf20Sopenharmony_ci */
13018c2ecf20Sopenharmony_cistatic void neo_uart_init(struct jsm_channel *ch)
13028c2ecf20Sopenharmony_ci{
13038c2ecf20Sopenharmony_ci	writeb(0, &ch->ch_neo_uart->ier);
13048c2ecf20Sopenharmony_ci	writeb(0, &ch->ch_neo_uart->efr);
13058c2ecf20Sopenharmony_ci	writeb(UART_EFR_ECB, &ch->ch_neo_uart->efr);
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_ci	/* Clear out UART and FIFO */
13088c2ecf20Sopenharmony_ci	readb(&ch->ch_neo_uart->txrx);
13098c2ecf20Sopenharmony_ci	writeb((UART_FCR_ENABLE_FIFO|UART_FCR_CLEAR_RCVR|UART_FCR_CLEAR_XMIT), &ch->ch_neo_uart->isr_fcr);
13108c2ecf20Sopenharmony_ci	readb(&ch->ch_neo_uart->lsr);
13118c2ecf20Sopenharmony_ci	readb(&ch->ch_neo_uart->msr);
13128c2ecf20Sopenharmony_ci
13138c2ecf20Sopenharmony_ci	ch->ch_flags |= CH_FIFO_ENABLED;
13148c2ecf20Sopenharmony_ci
13158c2ecf20Sopenharmony_ci	/* Assert any signals we want up */
13168c2ecf20Sopenharmony_ci	writeb(ch->ch_mostat, &ch->ch_neo_uart->mcr);
13178c2ecf20Sopenharmony_ci}
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_ci/*
13208c2ecf20Sopenharmony_ci * Make the UART completely turn off.
13218c2ecf20Sopenharmony_ci */
13228c2ecf20Sopenharmony_cistatic void neo_uart_off(struct jsm_channel *ch)
13238c2ecf20Sopenharmony_ci{
13248c2ecf20Sopenharmony_ci	/* Turn off UART enhanced bits */
13258c2ecf20Sopenharmony_ci	writeb(0, &ch->ch_neo_uart->efr);
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci	/* Stop all interrupts from occurring. */
13288c2ecf20Sopenharmony_ci	writeb(0, &ch->ch_neo_uart->ier);
13298c2ecf20Sopenharmony_ci}
13308c2ecf20Sopenharmony_ci
13318c2ecf20Sopenharmony_cistatic u32 neo_get_uart_bytes_left(struct jsm_channel *ch)
13328c2ecf20Sopenharmony_ci{
13338c2ecf20Sopenharmony_ci	u8 left = 0;
13348c2ecf20Sopenharmony_ci	u8 lsr = readb(&ch->ch_neo_uart->lsr);
13358c2ecf20Sopenharmony_ci
13368c2ecf20Sopenharmony_ci	/* We must cache the LSR as some of the bits get reset once read... */
13378c2ecf20Sopenharmony_ci	ch->ch_cached_lsr |= lsr;
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_ci	/* Determine whether the Transmitter is empty or not */
13408c2ecf20Sopenharmony_ci	if (!(lsr & UART_LSR_TEMT))
13418c2ecf20Sopenharmony_ci		left = 1;
13428c2ecf20Sopenharmony_ci	else {
13438c2ecf20Sopenharmony_ci		ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
13448c2ecf20Sopenharmony_ci		left = 0;
13458c2ecf20Sopenharmony_ci	}
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci	return left;
13488c2ecf20Sopenharmony_ci}
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_ci/* Channel lock MUST be held by the calling function! */
13518c2ecf20Sopenharmony_cistatic void neo_send_break(struct jsm_channel *ch)
13528c2ecf20Sopenharmony_ci{
13538c2ecf20Sopenharmony_ci	/*
13548c2ecf20Sopenharmony_ci	 * Set the time we should stop sending the break.
13558c2ecf20Sopenharmony_ci	 * If we are already sending a break, toss away the existing
13568c2ecf20Sopenharmony_ci	 * time to stop, and use this new value instead.
13578c2ecf20Sopenharmony_ci	 */
13588c2ecf20Sopenharmony_ci
13598c2ecf20Sopenharmony_ci	/* Tell the UART to start sending the break */
13608c2ecf20Sopenharmony_ci	if (!(ch->ch_flags & CH_BREAK_SENDING)) {
13618c2ecf20Sopenharmony_ci		u8 temp = readb(&ch->ch_neo_uart->lcr);
13628c2ecf20Sopenharmony_ci		writeb((temp | UART_LCR_SBC), &ch->ch_neo_uart->lcr);
13638c2ecf20Sopenharmony_ci		ch->ch_flags |= (CH_BREAK_SENDING);
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci		/* flush write operation */
13668c2ecf20Sopenharmony_ci		neo_pci_posting_flush(ch->ch_bd);
13678c2ecf20Sopenharmony_ci	}
13688c2ecf20Sopenharmony_ci}
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci/*
13718c2ecf20Sopenharmony_ci * neo_send_immediate_char.
13728c2ecf20Sopenharmony_ci *
13738c2ecf20Sopenharmony_ci * Sends a specific character as soon as possible to the UART,
13748c2ecf20Sopenharmony_ci * jumping over any bytes that might be in the write queue.
13758c2ecf20Sopenharmony_ci *
13768c2ecf20Sopenharmony_ci * The channel lock MUST be held by the calling function.
13778c2ecf20Sopenharmony_ci */
13788c2ecf20Sopenharmony_cistatic void neo_send_immediate_char(struct jsm_channel *ch, unsigned char c)
13798c2ecf20Sopenharmony_ci{
13808c2ecf20Sopenharmony_ci	if (!ch)
13818c2ecf20Sopenharmony_ci		return;
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ci	writeb(c, &ch->ch_neo_uart->txrx);
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_ci	/* flush write operation */
13868c2ecf20Sopenharmony_ci	neo_pci_posting_flush(ch->ch_bd);
13878c2ecf20Sopenharmony_ci}
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_cistruct board_ops jsm_neo_ops = {
13908c2ecf20Sopenharmony_ci	.intr				= neo_intr,
13918c2ecf20Sopenharmony_ci	.uart_init			= neo_uart_init,
13928c2ecf20Sopenharmony_ci	.uart_off			= neo_uart_off,
13938c2ecf20Sopenharmony_ci	.param				= neo_param,
13948c2ecf20Sopenharmony_ci	.assert_modem_signals		= neo_assert_modem_signals,
13958c2ecf20Sopenharmony_ci	.flush_uart_write		= neo_flush_uart_write,
13968c2ecf20Sopenharmony_ci	.flush_uart_read		= neo_flush_uart_read,
13978c2ecf20Sopenharmony_ci	.disable_receiver		= neo_disable_receiver,
13988c2ecf20Sopenharmony_ci	.enable_receiver		= neo_enable_receiver,
13998c2ecf20Sopenharmony_ci	.send_break			= neo_send_break,
14008c2ecf20Sopenharmony_ci	.clear_break			= neo_clear_break,
14018c2ecf20Sopenharmony_ci	.send_start_character		= neo_send_start_character,
14028c2ecf20Sopenharmony_ci	.send_stop_character		= neo_send_stop_character,
14038c2ecf20Sopenharmony_ci	.copy_data_from_queue_to_uart	= neo_copy_data_from_queue_to_uart,
14048c2ecf20Sopenharmony_ci	.get_uart_bytes_left		= neo_get_uart_bytes_left,
14058c2ecf20Sopenharmony_ci	.send_immediate_char		= neo_send_immediate_char
14068c2ecf20Sopenharmony_ci};
1407