xref: /linux/drivers/tty/serial/qcom_geni_serial.c (revision c4f528795d1add8b63652673f7262729f679c6c1)
1*c4f52879SKarthikeyan Ramasubramanian // SPDX-License-Identifier: GPL-2.0
2*c4f52879SKarthikeyan Ramasubramanian // Copyright (c) 2017-2018, The Linux foundation. All rights reserved.
3*c4f52879SKarthikeyan Ramasubramanian 
4*c4f52879SKarthikeyan Ramasubramanian #include <linux/clk.h>
5*c4f52879SKarthikeyan Ramasubramanian #include <linux/console.h>
6*c4f52879SKarthikeyan Ramasubramanian #include <linux/io.h>
7*c4f52879SKarthikeyan Ramasubramanian #include <linux/iopoll.h>
8*c4f52879SKarthikeyan Ramasubramanian #include <linux/module.h>
9*c4f52879SKarthikeyan Ramasubramanian #include <linux/of.h>
10*c4f52879SKarthikeyan Ramasubramanian #include <linux/of_device.h>
11*c4f52879SKarthikeyan Ramasubramanian #include <linux/platform_device.h>
12*c4f52879SKarthikeyan Ramasubramanian #include <linux/qcom-geni-se.h>
13*c4f52879SKarthikeyan Ramasubramanian #include <linux/serial.h>
14*c4f52879SKarthikeyan Ramasubramanian #include <linux/serial_core.h>
15*c4f52879SKarthikeyan Ramasubramanian #include <linux/slab.h>
16*c4f52879SKarthikeyan Ramasubramanian #include <linux/tty.h>
17*c4f52879SKarthikeyan Ramasubramanian #include <linux/tty_flip.h>
18*c4f52879SKarthikeyan Ramasubramanian 
19*c4f52879SKarthikeyan Ramasubramanian /* UART specific GENI registers */
20*c4f52879SKarthikeyan Ramasubramanian #define SE_UART_TX_TRANS_CFG		0x25c
21*c4f52879SKarthikeyan Ramasubramanian #define SE_UART_TX_WORD_LEN		0x268
22*c4f52879SKarthikeyan Ramasubramanian #define SE_UART_TX_STOP_BIT_LEN		0x26c
23*c4f52879SKarthikeyan Ramasubramanian #define SE_UART_TX_TRANS_LEN		0x270
24*c4f52879SKarthikeyan Ramasubramanian #define SE_UART_RX_TRANS_CFG		0x280
25*c4f52879SKarthikeyan Ramasubramanian #define SE_UART_RX_WORD_LEN		0x28c
26*c4f52879SKarthikeyan Ramasubramanian #define SE_UART_RX_STALE_CNT		0x294
27*c4f52879SKarthikeyan Ramasubramanian #define SE_UART_TX_PARITY_CFG		0x2a4
28*c4f52879SKarthikeyan Ramasubramanian #define SE_UART_RX_PARITY_CFG		0x2a8
29*c4f52879SKarthikeyan Ramasubramanian 
30*c4f52879SKarthikeyan Ramasubramanian /* SE_UART_TRANS_CFG */
31*c4f52879SKarthikeyan Ramasubramanian #define UART_TX_PAR_EN		BIT(0)
32*c4f52879SKarthikeyan Ramasubramanian #define UART_CTS_MASK		BIT(1)
33*c4f52879SKarthikeyan Ramasubramanian 
34*c4f52879SKarthikeyan Ramasubramanian /* SE_UART_TX_WORD_LEN */
35*c4f52879SKarthikeyan Ramasubramanian #define TX_WORD_LEN_MSK		GENMASK(9, 0)
36*c4f52879SKarthikeyan Ramasubramanian 
37*c4f52879SKarthikeyan Ramasubramanian /* SE_UART_TX_STOP_BIT_LEN */
38*c4f52879SKarthikeyan Ramasubramanian #define TX_STOP_BIT_LEN_MSK	GENMASK(23, 0)
39*c4f52879SKarthikeyan Ramasubramanian #define TX_STOP_BIT_LEN_1	0
40*c4f52879SKarthikeyan Ramasubramanian #define TX_STOP_BIT_LEN_1_5	1
41*c4f52879SKarthikeyan Ramasubramanian #define TX_STOP_BIT_LEN_2	2
42*c4f52879SKarthikeyan Ramasubramanian 
43*c4f52879SKarthikeyan Ramasubramanian /* SE_UART_TX_TRANS_LEN */
44*c4f52879SKarthikeyan Ramasubramanian #define TX_TRANS_LEN_MSK	GENMASK(23, 0)
45*c4f52879SKarthikeyan Ramasubramanian 
46*c4f52879SKarthikeyan Ramasubramanian /* SE_UART_RX_TRANS_CFG */
47*c4f52879SKarthikeyan Ramasubramanian #define UART_RX_INS_STATUS_BIT	BIT(2)
48*c4f52879SKarthikeyan Ramasubramanian #define UART_RX_PAR_EN		BIT(3)
49*c4f52879SKarthikeyan Ramasubramanian 
50*c4f52879SKarthikeyan Ramasubramanian /* SE_UART_RX_WORD_LEN */
51*c4f52879SKarthikeyan Ramasubramanian #define RX_WORD_LEN_MASK	GENMASK(9, 0)
52*c4f52879SKarthikeyan Ramasubramanian 
53*c4f52879SKarthikeyan Ramasubramanian /* SE_UART_RX_STALE_CNT */
54*c4f52879SKarthikeyan Ramasubramanian #define RX_STALE_CNT		GENMASK(23, 0)
55*c4f52879SKarthikeyan Ramasubramanian 
56*c4f52879SKarthikeyan Ramasubramanian /* SE_UART_TX_PARITY_CFG/RX_PARITY_CFG */
57*c4f52879SKarthikeyan Ramasubramanian #define PAR_CALC_EN		BIT(0)
58*c4f52879SKarthikeyan Ramasubramanian #define PAR_MODE_MSK		GENMASK(2, 1)
59*c4f52879SKarthikeyan Ramasubramanian #define PAR_MODE_SHFT		1
60*c4f52879SKarthikeyan Ramasubramanian #define PAR_EVEN		0x00
61*c4f52879SKarthikeyan Ramasubramanian #define PAR_ODD			0x01
62*c4f52879SKarthikeyan Ramasubramanian #define PAR_SPACE		0x10
63*c4f52879SKarthikeyan Ramasubramanian #define PAR_MARK		0x11
64*c4f52879SKarthikeyan Ramasubramanian 
65*c4f52879SKarthikeyan Ramasubramanian /* UART M_CMD OP codes */
66*c4f52879SKarthikeyan Ramasubramanian #define UART_START_TX		0x1
67*c4f52879SKarthikeyan Ramasubramanian #define UART_START_BREAK	0x4
68*c4f52879SKarthikeyan Ramasubramanian #define UART_STOP_BREAK		0x5
69*c4f52879SKarthikeyan Ramasubramanian /* UART S_CMD OP codes */
70*c4f52879SKarthikeyan Ramasubramanian #define UART_START_READ		0x1
71*c4f52879SKarthikeyan Ramasubramanian #define UART_PARAM		0x1
72*c4f52879SKarthikeyan Ramasubramanian 
73*c4f52879SKarthikeyan Ramasubramanian #define UART_OVERSAMPLING	32
74*c4f52879SKarthikeyan Ramasubramanian #define STALE_TIMEOUT		16
75*c4f52879SKarthikeyan Ramasubramanian #define DEFAULT_BITS_PER_CHAR	10
76*c4f52879SKarthikeyan Ramasubramanian #define GENI_UART_CONS_PORTS	1
77*c4f52879SKarthikeyan Ramasubramanian #define DEF_FIFO_DEPTH_WORDS	16
78*c4f52879SKarthikeyan Ramasubramanian #define DEF_TX_WM		2
79*c4f52879SKarthikeyan Ramasubramanian #define DEF_FIFO_WIDTH_BITS	32
80*c4f52879SKarthikeyan Ramasubramanian #define UART_CONSOLE_RX_WM	2
81*c4f52879SKarthikeyan Ramasubramanian 
82*c4f52879SKarthikeyan Ramasubramanian #ifdef CONFIG_CONSOLE_POLL
83*c4f52879SKarthikeyan Ramasubramanian #define RX_BYTES_PW 1
84*c4f52879SKarthikeyan Ramasubramanian #else
85*c4f52879SKarthikeyan Ramasubramanian #define RX_BYTES_PW 4
86*c4f52879SKarthikeyan Ramasubramanian #endif
87*c4f52879SKarthikeyan Ramasubramanian 
88*c4f52879SKarthikeyan Ramasubramanian struct qcom_geni_serial_port {
89*c4f52879SKarthikeyan Ramasubramanian 	struct uart_port uport;
90*c4f52879SKarthikeyan Ramasubramanian 	struct geni_se se;
91*c4f52879SKarthikeyan Ramasubramanian 	char name[20];
92*c4f52879SKarthikeyan Ramasubramanian 	u32 tx_fifo_depth;
93*c4f52879SKarthikeyan Ramasubramanian 	u32 tx_fifo_width;
94*c4f52879SKarthikeyan Ramasubramanian 	u32 rx_fifo_depth;
95*c4f52879SKarthikeyan Ramasubramanian 	u32 tx_wm;
96*c4f52879SKarthikeyan Ramasubramanian 	u32 rx_wm;
97*c4f52879SKarthikeyan Ramasubramanian 	u32 rx_rfr;
98*c4f52879SKarthikeyan Ramasubramanian 	enum geni_se_xfer_mode xfer_mode;
99*c4f52879SKarthikeyan Ramasubramanian 	bool setup;
100*c4f52879SKarthikeyan Ramasubramanian 	int (*handle_rx)(struct uart_port *uport, u32 bytes, bool drop);
101*c4f52879SKarthikeyan Ramasubramanian 	unsigned int xmit_size;
102*c4f52879SKarthikeyan Ramasubramanian 	unsigned int baud;
103*c4f52879SKarthikeyan Ramasubramanian 	unsigned int tx_bytes_pw;
104*c4f52879SKarthikeyan Ramasubramanian 	unsigned int rx_bytes_pw;
105*c4f52879SKarthikeyan Ramasubramanian 	bool brk;
106*c4f52879SKarthikeyan Ramasubramanian };
107*c4f52879SKarthikeyan Ramasubramanian 
108*c4f52879SKarthikeyan Ramasubramanian static const struct uart_ops qcom_geni_serial_pops;
109*c4f52879SKarthikeyan Ramasubramanian static struct uart_driver qcom_geni_console_driver;
110*c4f52879SKarthikeyan Ramasubramanian static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop);
111*c4f52879SKarthikeyan Ramasubramanian static unsigned int qcom_geni_serial_tx_empty(struct uart_port *port);
112*c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_stop_rx(struct uart_port *uport);
113*c4f52879SKarthikeyan Ramasubramanian 
114*c4f52879SKarthikeyan Ramasubramanian static const unsigned long root_freq[] = {7372800, 14745600, 19200000, 29491200,
115*c4f52879SKarthikeyan Ramasubramanian 					32000000, 48000000, 64000000, 80000000,
116*c4f52879SKarthikeyan Ramasubramanian 					96000000, 100000000};
117*c4f52879SKarthikeyan Ramasubramanian 
118*c4f52879SKarthikeyan Ramasubramanian #define to_dev_port(ptr, member) \
119*c4f52879SKarthikeyan Ramasubramanian 		container_of(ptr, struct qcom_geni_serial_port, member)
120*c4f52879SKarthikeyan Ramasubramanian 
121*c4f52879SKarthikeyan Ramasubramanian static struct qcom_geni_serial_port qcom_geni_console_port;
122*c4f52879SKarthikeyan Ramasubramanian 
123*c4f52879SKarthikeyan Ramasubramanian static int qcom_geni_serial_request_port(struct uart_port *uport)
124*c4f52879SKarthikeyan Ramasubramanian {
125*c4f52879SKarthikeyan Ramasubramanian 	struct platform_device *pdev = to_platform_device(uport->dev);
126*c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
127*c4f52879SKarthikeyan Ramasubramanian 	struct resource *res;
128*c4f52879SKarthikeyan Ramasubramanian 
129*c4f52879SKarthikeyan Ramasubramanian 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
130*c4f52879SKarthikeyan Ramasubramanian 	uport->membase = devm_ioremap_resource(&pdev->dev, res);
131*c4f52879SKarthikeyan Ramasubramanian 	if (IS_ERR(uport->membase))
132*c4f52879SKarthikeyan Ramasubramanian 		return PTR_ERR(uport->membase);
133*c4f52879SKarthikeyan Ramasubramanian 	port->se.base = uport->membase;
134*c4f52879SKarthikeyan Ramasubramanian 	return 0;
135*c4f52879SKarthikeyan Ramasubramanian }
136*c4f52879SKarthikeyan Ramasubramanian 
137*c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_config_port(struct uart_port *uport, int cfg_flags)
138*c4f52879SKarthikeyan Ramasubramanian {
139*c4f52879SKarthikeyan Ramasubramanian 	if (cfg_flags & UART_CONFIG_TYPE) {
140*c4f52879SKarthikeyan Ramasubramanian 		uport->type = PORT_MSM;
141*c4f52879SKarthikeyan Ramasubramanian 		qcom_geni_serial_request_port(uport);
142*c4f52879SKarthikeyan Ramasubramanian 	}
143*c4f52879SKarthikeyan Ramasubramanian }
144*c4f52879SKarthikeyan Ramasubramanian 
145*c4f52879SKarthikeyan Ramasubramanian static unsigned int qcom_geni_cons_get_mctrl(struct uart_port *uport)
146*c4f52879SKarthikeyan Ramasubramanian {
147*c4f52879SKarthikeyan Ramasubramanian 	return TIOCM_DSR | TIOCM_CAR | TIOCM_CTS;
148*c4f52879SKarthikeyan Ramasubramanian }
149*c4f52879SKarthikeyan Ramasubramanian 
150*c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_cons_set_mctrl(struct uart_port *uport,
151*c4f52879SKarthikeyan Ramasubramanian 							unsigned int mctrl)
152*c4f52879SKarthikeyan Ramasubramanian {
153*c4f52879SKarthikeyan Ramasubramanian }
154*c4f52879SKarthikeyan Ramasubramanian 
155*c4f52879SKarthikeyan Ramasubramanian static const char *qcom_geni_serial_get_type(struct uart_port *uport)
156*c4f52879SKarthikeyan Ramasubramanian {
157*c4f52879SKarthikeyan Ramasubramanian 	return "MSM";
158*c4f52879SKarthikeyan Ramasubramanian }
159*c4f52879SKarthikeyan Ramasubramanian 
160*c4f52879SKarthikeyan Ramasubramanian static struct qcom_geni_serial_port *get_port_from_line(int line)
161*c4f52879SKarthikeyan Ramasubramanian {
162*c4f52879SKarthikeyan Ramasubramanian 	if (line < 0 || line >= GENI_UART_CONS_PORTS)
163*c4f52879SKarthikeyan Ramasubramanian 		return ERR_PTR(-ENXIO);
164*c4f52879SKarthikeyan Ramasubramanian 	return &qcom_geni_console_port;
165*c4f52879SKarthikeyan Ramasubramanian }
166*c4f52879SKarthikeyan Ramasubramanian 
167*c4f52879SKarthikeyan Ramasubramanian static bool qcom_geni_serial_poll_bit(struct uart_port *uport,
168*c4f52879SKarthikeyan Ramasubramanian 				int offset, int field, bool set)
169*c4f52879SKarthikeyan Ramasubramanian {
170*c4f52879SKarthikeyan Ramasubramanian 	u32 reg;
171*c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port;
172*c4f52879SKarthikeyan Ramasubramanian 	unsigned int baud;
173*c4f52879SKarthikeyan Ramasubramanian 	unsigned int fifo_bits;
174*c4f52879SKarthikeyan Ramasubramanian 	unsigned long timeout_us = 20000;
175*c4f52879SKarthikeyan Ramasubramanian 
176*c4f52879SKarthikeyan Ramasubramanian 	/* Ensure polling is not re-ordered before the prior writes/reads */
177*c4f52879SKarthikeyan Ramasubramanian 	mb();
178*c4f52879SKarthikeyan Ramasubramanian 
179*c4f52879SKarthikeyan Ramasubramanian 	if (uport->private_data) {
180*c4f52879SKarthikeyan Ramasubramanian 		port = to_dev_port(uport, uport);
181*c4f52879SKarthikeyan Ramasubramanian 		baud = port->baud;
182*c4f52879SKarthikeyan Ramasubramanian 		if (!baud)
183*c4f52879SKarthikeyan Ramasubramanian 			baud = 115200;
184*c4f52879SKarthikeyan Ramasubramanian 		fifo_bits = port->tx_fifo_depth * port->tx_fifo_width;
185*c4f52879SKarthikeyan Ramasubramanian 		/*
186*c4f52879SKarthikeyan Ramasubramanian 		 * Total polling iterations based on FIFO worth of bytes to be
187*c4f52879SKarthikeyan Ramasubramanian 		 * sent at current baud. Add a little fluff to the wait.
188*c4f52879SKarthikeyan Ramasubramanian 		 */
189*c4f52879SKarthikeyan Ramasubramanian 		timeout_us = ((fifo_bits * USEC_PER_SEC) / baud) + 500;
190*c4f52879SKarthikeyan Ramasubramanian 	}
191*c4f52879SKarthikeyan Ramasubramanian 
192*c4f52879SKarthikeyan Ramasubramanian 	return !readl_poll_timeout_atomic(uport->membase + offset, reg,
193*c4f52879SKarthikeyan Ramasubramanian 			 (bool)(reg & field) == set, 10, timeout_us);
194*c4f52879SKarthikeyan Ramasubramanian }
195*c4f52879SKarthikeyan Ramasubramanian 
196*c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_setup_tx(struct uart_port *uport, u32 xmit_size)
197*c4f52879SKarthikeyan Ramasubramanian {
198*c4f52879SKarthikeyan Ramasubramanian 	u32 m_cmd;
199*c4f52879SKarthikeyan Ramasubramanian 
200*c4f52879SKarthikeyan Ramasubramanian 	writel_relaxed(xmit_size, uport->membase + SE_UART_TX_TRANS_LEN);
201*c4f52879SKarthikeyan Ramasubramanian 	m_cmd = UART_START_TX << M_OPCODE_SHFT;
202*c4f52879SKarthikeyan Ramasubramanian 	writel(m_cmd, uport->membase + SE_GENI_M_CMD0);
203*c4f52879SKarthikeyan Ramasubramanian }
204*c4f52879SKarthikeyan Ramasubramanian 
205*c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_poll_tx_done(struct uart_port *uport)
206*c4f52879SKarthikeyan Ramasubramanian {
207*c4f52879SKarthikeyan Ramasubramanian 	int done;
208*c4f52879SKarthikeyan Ramasubramanian 	u32 irq_clear = M_CMD_DONE_EN;
209*c4f52879SKarthikeyan Ramasubramanian 
210*c4f52879SKarthikeyan Ramasubramanian 	done = qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
211*c4f52879SKarthikeyan Ramasubramanian 						M_CMD_DONE_EN, true);
212*c4f52879SKarthikeyan Ramasubramanian 	if (!done) {
213*c4f52879SKarthikeyan Ramasubramanian 		writel_relaxed(M_GENI_CMD_ABORT, uport->membase +
214*c4f52879SKarthikeyan Ramasubramanian 						SE_GENI_M_CMD_CTRL_REG);
215*c4f52879SKarthikeyan Ramasubramanian 		irq_clear |= M_CMD_ABORT_EN;
216*c4f52879SKarthikeyan Ramasubramanian 		qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
217*c4f52879SKarthikeyan Ramasubramanian 							M_CMD_ABORT_EN, true);
218*c4f52879SKarthikeyan Ramasubramanian 	}
219*c4f52879SKarthikeyan Ramasubramanian 	writel_relaxed(irq_clear, uport->membase + SE_GENI_M_IRQ_CLEAR);
220*c4f52879SKarthikeyan Ramasubramanian }
221*c4f52879SKarthikeyan Ramasubramanian 
222*c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_abort_rx(struct uart_port *uport)
223*c4f52879SKarthikeyan Ramasubramanian {
224*c4f52879SKarthikeyan Ramasubramanian 	u32 irq_clear = S_CMD_DONE_EN | S_CMD_ABORT_EN;
225*c4f52879SKarthikeyan Ramasubramanian 
226*c4f52879SKarthikeyan Ramasubramanian 	writel(S_GENI_CMD_ABORT, uport->membase + SE_GENI_S_CMD_CTRL_REG);
227*c4f52879SKarthikeyan Ramasubramanian 	qcom_geni_serial_poll_bit(uport, SE_GENI_S_CMD_CTRL_REG,
228*c4f52879SKarthikeyan Ramasubramanian 					S_GENI_CMD_ABORT, false);
229*c4f52879SKarthikeyan Ramasubramanian 	writel_relaxed(irq_clear, uport->membase + SE_GENI_S_IRQ_CLEAR);
230*c4f52879SKarthikeyan Ramasubramanian 	writel_relaxed(FORCE_DEFAULT, uport->membase + GENI_FORCE_DEFAULT_REG);
231*c4f52879SKarthikeyan Ramasubramanian }
232*c4f52879SKarthikeyan Ramasubramanian 
233*c4f52879SKarthikeyan Ramasubramanian #ifdef CONFIG_CONSOLE_POLL
234*c4f52879SKarthikeyan Ramasubramanian static int qcom_geni_serial_get_char(struct uart_port *uport)
235*c4f52879SKarthikeyan Ramasubramanian {
236*c4f52879SKarthikeyan Ramasubramanian 	u32 rx_fifo;
237*c4f52879SKarthikeyan Ramasubramanian 	u32 status;
238*c4f52879SKarthikeyan Ramasubramanian 
239*c4f52879SKarthikeyan Ramasubramanian 	status = readl_relaxed(uport->membase + SE_GENI_M_IRQ_STATUS);
240*c4f52879SKarthikeyan Ramasubramanian 	writel_relaxed(status, uport->membase + SE_GENI_M_IRQ_CLEAR);
241*c4f52879SKarthikeyan Ramasubramanian 
242*c4f52879SKarthikeyan Ramasubramanian 	status = readl_relaxed(uport->membase + SE_GENI_S_IRQ_STATUS);
243*c4f52879SKarthikeyan Ramasubramanian 	writel_relaxed(status, uport->membase + SE_GENI_S_IRQ_CLEAR);
244*c4f52879SKarthikeyan Ramasubramanian 
245*c4f52879SKarthikeyan Ramasubramanian 	/*
246*c4f52879SKarthikeyan Ramasubramanian 	 * Ensure the writes to clear interrupts is not re-ordered after
247*c4f52879SKarthikeyan Ramasubramanian 	 * reading the data.
248*c4f52879SKarthikeyan Ramasubramanian 	 */
249*c4f52879SKarthikeyan Ramasubramanian 	mb();
250*c4f52879SKarthikeyan Ramasubramanian 
251*c4f52879SKarthikeyan Ramasubramanian 	status = readl_relaxed(uport->membase + SE_GENI_RX_FIFO_STATUS);
252*c4f52879SKarthikeyan Ramasubramanian 	if (!(status & RX_FIFO_WC_MSK))
253*c4f52879SKarthikeyan Ramasubramanian 		return NO_POLL_CHAR;
254*c4f52879SKarthikeyan Ramasubramanian 
255*c4f52879SKarthikeyan Ramasubramanian 	rx_fifo = readl(uport->membase + SE_GENI_RX_FIFOn);
256*c4f52879SKarthikeyan Ramasubramanian 	return rx_fifo & 0xff;
257*c4f52879SKarthikeyan Ramasubramanian }
258*c4f52879SKarthikeyan Ramasubramanian 
259*c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_poll_put_char(struct uart_port *uport,
260*c4f52879SKarthikeyan Ramasubramanian 							unsigned char c)
261*c4f52879SKarthikeyan Ramasubramanian {
262*c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
263*c4f52879SKarthikeyan Ramasubramanian 
264*c4f52879SKarthikeyan Ramasubramanian 	writel_relaxed(port->tx_wm, uport->membase + SE_GENI_TX_WATERMARK_REG);
265*c4f52879SKarthikeyan Ramasubramanian 	qcom_geni_serial_setup_tx(uport, 1);
266*c4f52879SKarthikeyan Ramasubramanian 	WARN_ON(!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
267*c4f52879SKarthikeyan Ramasubramanian 						M_TX_FIFO_WATERMARK_EN, true));
268*c4f52879SKarthikeyan Ramasubramanian 	writel_relaxed(c, uport->membase + SE_GENI_TX_FIFOn);
269*c4f52879SKarthikeyan Ramasubramanian 	writel_relaxed(M_TX_FIFO_WATERMARK_EN, uport->membase +
270*c4f52879SKarthikeyan Ramasubramanian 							SE_GENI_M_IRQ_CLEAR);
271*c4f52879SKarthikeyan Ramasubramanian 	qcom_geni_serial_poll_tx_done(uport);
272*c4f52879SKarthikeyan Ramasubramanian }
273*c4f52879SKarthikeyan Ramasubramanian #endif
274*c4f52879SKarthikeyan Ramasubramanian 
275*c4f52879SKarthikeyan Ramasubramanian #ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE
276*c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_wr_char(struct uart_port *uport, int ch)
277*c4f52879SKarthikeyan Ramasubramanian {
278*c4f52879SKarthikeyan Ramasubramanian 	writel_relaxed(ch, uport->membase + SE_GENI_TX_FIFOn);
279*c4f52879SKarthikeyan Ramasubramanian }
280*c4f52879SKarthikeyan Ramasubramanian 
281*c4f52879SKarthikeyan Ramasubramanian static void
282*c4f52879SKarthikeyan Ramasubramanian __qcom_geni_serial_console_write(struct uart_port *uport, const char *s,
283*c4f52879SKarthikeyan Ramasubramanian 				 unsigned int count)
284*c4f52879SKarthikeyan Ramasubramanian {
285*c4f52879SKarthikeyan Ramasubramanian 	int i;
286*c4f52879SKarthikeyan Ramasubramanian 	u32 bytes_to_send = count;
287*c4f52879SKarthikeyan Ramasubramanian 
288*c4f52879SKarthikeyan Ramasubramanian 	for (i = 0; i < count; i++) {
289*c4f52879SKarthikeyan Ramasubramanian 		if (s[i] == '\n')
290*c4f52879SKarthikeyan Ramasubramanian 			bytes_to_send++;
291*c4f52879SKarthikeyan Ramasubramanian 	}
292*c4f52879SKarthikeyan Ramasubramanian 
293*c4f52879SKarthikeyan Ramasubramanian 	writel_relaxed(DEF_TX_WM, uport->membase + SE_GENI_TX_WATERMARK_REG);
294*c4f52879SKarthikeyan Ramasubramanian 	qcom_geni_serial_setup_tx(uport, bytes_to_send);
295*c4f52879SKarthikeyan Ramasubramanian 	for (i = 0; i < count; ) {
296*c4f52879SKarthikeyan Ramasubramanian 		size_t chars_to_write = 0;
297*c4f52879SKarthikeyan Ramasubramanian 		size_t avail = DEF_FIFO_DEPTH_WORDS - DEF_TX_WM;
298*c4f52879SKarthikeyan Ramasubramanian 
299*c4f52879SKarthikeyan Ramasubramanian 		/*
300*c4f52879SKarthikeyan Ramasubramanian 		 * If the WM bit never set, then the Tx state machine is not
301*c4f52879SKarthikeyan Ramasubramanian 		 * in a valid state, so break, cancel/abort any existing
302*c4f52879SKarthikeyan Ramasubramanian 		 * command. Unfortunately the current data being written is
303*c4f52879SKarthikeyan Ramasubramanian 		 * lost.
304*c4f52879SKarthikeyan Ramasubramanian 		 */
305*c4f52879SKarthikeyan Ramasubramanian 		if (!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
306*c4f52879SKarthikeyan Ramasubramanian 						M_TX_FIFO_WATERMARK_EN, true))
307*c4f52879SKarthikeyan Ramasubramanian 			break;
308*c4f52879SKarthikeyan Ramasubramanian 		chars_to_write = min_t(size_t, (size_t)(count - i), avail / 2);
309*c4f52879SKarthikeyan Ramasubramanian 		uart_console_write(uport, s + i, chars_to_write,
310*c4f52879SKarthikeyan Ramasubramanian 						qcom_geni_serial_wr_char);
311*c4f52879SKarthikeyan Ramasubramanian 		writel_relaxed(M_TX_FIFO_WATERMARK_EN, uport->membase +
312*c4f52879SKarthikeyan Ramasubramanian 							SE_GENI_M_IRQ_CLEAR);
313*c4f52879SKarthikeyan Ramasubramanian 		i += chars_to_write;
314*c4f52879SKarthikeyan Ramasubramanian 	}
315*c4f52879SKarthikeyan Ramasubramanian 	qcom_geni_serial_poll_tx_done(uport);
316*c4f52879SKarthikeyan Ramasubramanian }
317*c4f52879SKarthikeyan Ramasubramanian 
318*c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_console_write(struct console *co, const char *s,
319*c4f52879SKarthikeyan Ramasubramanian 			      unsigned int count)
320*c4f52879SKarthikeyan Ramasubramanian {
321*c4f52879SKarthikeyan Ramasubramanian 	struct uart_port *uport;
322*c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port;
323*c4f52879SKarthikeyan Ramasubramanian 	bool locked = true;
324*c4f52879SKarthikeyan Ramasubramanian 	unsigned long flags;
325*c4f52879SKarthikeyan Ramasubramanian 
326*c4f52879SKarthikeyan Ramasubramanian 	WARN_ON(co->index < 0 || co->index >= GENI_UART_CONS_PORTS);
327*c4f52879SKarthikeyan Ramasubramanian 
328*c4f52879SKarthikeyan Ramasubramanian 	port = get_port_from_line(co->index);
329*c4f52879SKarthikeyan Ramasubramanian 	if (IS_ERR(port))
330*c4f52879SKarthikeyan Ramasubramanian 		return;
331*c4f52879SKarthikeyan Ramasubramanian 
332*c4f52879SKarthikeyan Ramasubramanian 	uport = &port->uport;
333*c4f52879SKarthikeyan Ramasubramanian 	if (oops_in_progress)
334*c4f52879SKarthikeyan Ramasubramanian 		locked = spin_trylock_irqsave(&uport->lock, flags);
335*c4f52879SKarthikeyan Ramasubramanian 	else
336*c4f52879SKarthikeyan Ramasubramanian 		spin_lock_irqsave(&uport->lock, flags);
337*c4f52879SKarthikeyan Ramasubramanian 
338*c4f52879SKarthikeyan Ramasubramanian 	/* Cancel the current write to log the fault */
339*c4f52879SKarthikeyan Ramasubramanian 	if (!locked) {
340*c4f52879SKarthikeyan Ramasubramanian 		geni_se_cancel_m_cmd(&port->se);
341*c4f52879SKarthikeyan Ramasubramanian 		if (!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
342*c4f52879SKarthikeyan Ramasubramanian 						M_CMD_CANCEL_EN, true)) {
343*c4f52879SKarthikeyan Ramasubramanian 			geni_se_abort_m_cmd(&port->se);
344*c4f52879SKarthikeyan Ramasubramanian 			qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
345*c4f52879SKarthikeyan Ramasubramanian 							M_CMD_ABORT_EN, true);
346*c4f52879SKarthikeyan Ramasubramanian 			writel_relaxed(M_CMD_ABORT_EN, uport->membase +
347*c4f52879SKarthikeyan Ramasubramanian 							SE_GENI_M_IRQ_CLEAR);
348*c4f52879SKarthikeyan Ramasubramanian 		}
349*c4f52879SKarthikeyan Ramasubramanian 		writel_relaxed(M_CMD_CANCEL_EN, uport->membase +
350*c4f52879SKarthikeyan Ramasubramanian 							SE_GENI_M_IRQ_CLEAR);
351*c4f52879SKarthikeyan Ramasubramanian 	}
352*c4f52879SKarthikeyan Ramasubramanian 
353*c4f52879SKarthikeyan Ramasubramanian 	__qcom_geni_serial_console_write(uport, s, count);
354*c4f52879SKarthikeyan Ramasubramanian 	if (locked)
355*c4f52879SKarthikeyan Ramasubramanian 		spin_unlock_irqrestore(&uport->lock, flags);
356*c4f52879SKarthikeyan Ramasubramanian }
357*c4f52879SKarthikeyan Ramasubramanian 
358*c4f52879SKarthikeyan Ramasubramanian static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop)
359*c4f52879SKarthikeyan Ramasubramanian {
360*c4f52879SKarthikeyan Ramasubramanian 	u32 i;
361*c4f52879SKarthikeyan Ramasubramanian 	unsigned char buf[sizeof(u32)];
362*c4f52879SKarthikeyan Ramasubramanian 	struct tty_port *tport;
363*c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
364*c4f52879SKarthikeyan Ramasubramanian 
365*c4f52879SKarthikeyan Ramasubramanian 	tport = &uport->state->port;
366*c4f52879SKarthikeyan Ramasubramanian 	for (i = 0; i < bytes; ) {
367*c4f52879SKarthikeyan Ramasubramanian 		int c;
368*c4f52879SKarthikeyan Ramasubramanian 		int chunk = min_t(int, bytes - i, port->rx_bytes_pw);
369*c4f52879SKarthikeyan Ramasubramanian 
370*c4f52879SKarthikeyan Ramasubramanian 		ioread32_rep(uport->membase + SE_GENI_RX_FIFOn, buf, 1);
371*c4f52879SKarthikeyan Ramasubramanian 		i += chunk;
372*c4f52879SKarthikeyan Ramasubramanian 		if (drop)
373*c4f52879SKarthikeyan Ramasubramanian 			continue;
374*c4f52879SKarthikeyan Ramasubramanian 
375*c4f52879SKarthikeyan Ramasubramanian 		for (c = 0; c < chunk; c++) {
376*c4f52879SKarthikeyan Ramasubramanian 			int sysrq;
377*c4f52879SKarthikeyan Ramasubramanian 
378*c4f52879SKarthikeyan Ramasubramanian 			uport->icount.rx++;
379*c4f52879SKarthikeyan Ramasubramanian 			if (port->brk && buf[c] == 0) {
380*c4f52879SKarthikeyan Ramasubramanian 				port->brk = false;
381*c4f52879SKarthikeyan Ramasubramanian 				if (uart_handle_break(uport))
382*c4f52879SKarthikeyan Ramasubramanian 					continue;
383*c4f52879SKarthikeyan Ramasubramanian 			}
384*c4f52879SKarthikeyan Ramasubramanian 
385*c4f52879SKarthikeyan Ramasubramanian 			sysrq = uart_handle_sysrq_char(uport, buf[c]);
386*c4f52879SKarthikeyan Ramasubramanian 			if (!sysrq)
387*c4f52879SKarthikeyan Ramasubramanian 				tty_insert_flip_char(tport, buf[c], TTY_NORMAL);
388*c4f52879SKarthikeyan Ramasubramanian 		}
389*c4f52879SKarthikeyan Ramasubramanian 	}
390*c4f52879SKarthikeyan Ramasubramanian 	if (!drop)
391*c4f52879SKarthikeyan Ramasubramanian 		tty_flip_buffer_push(tport);
392*c4f52879SKarthikeyan Ramasubramanian 	return 0;
393*c4f52879SKarthikeyan Ramasubramanian }
394*c4f52879SKarthikeyan Ramasubramanian #else
395*c4f52879SKarthikeyan Ramasubramanian static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop)
396*c4f52879SKarthikeyan Ramasubramanian {
397*c4f52879SKarthikeyan Ramasubramanian 	return -EPERM;
398*c4f52879SKarthikeyan Ramasubramanian }
399*c4f52879SKarthikeyan Ramasubramanian 
400*c4f52879SKarthikeyan Ramasubramanian #endif /* CONFIG_SERIAL_QCOM_GENI_CONSOLE */
401*c4f52879SKarthikeyan Ramasubramanian 
402*c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_start_tx(struct uart_port *uport)
403*c4f52879SKarthikeyan Ramasubramanian {
404*c4f52879SKarthikeyan Ramasubramanian 	u32 irq_en;
405*c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
406*c4f52879SKarthikeyan Ramasubramanian 	u32 status;
407*c4f52879SKarthikeyan Ramasubramanian 
408*c4f52879SKarthikeyan Ramasubramanian 	if (port->xfer_mode == GENI_SE_FIFO) {
409*c4f52879SKarthikeyan Ramasubramanian 		status = readl_relaxed(uport->membase + SE_GENI_STATUS);
410*c4f52879SKarthikeyan Ramasubramanian 		if (status & M_GENI_CMD_ACTIVE)
411*c4f52879SKarthikeyan Ramasubramanian 			return;
412*c4f52879SKarthikeyan Ramasubramanian 
413*c4f52879SKarthikeyan Ramasubramanian 		if (!qcom_geni_serial_tx_empty(uport))
414*c4f52879SKarthikeyan Ramasubramanian 			return;
415*c4f52879SKarthikeyan Ramasubramanian 
416*c4f52879SKarthikeyan Ramasubramanian 		/*
417*c4f52879SKarthikeyan Ramasubramanian 		 * Ensure writing to IRQ_EN & watermark registers are not
418*c4f52879SKarthikeyan Ramasubramanian 		 * re-ordered before checking the status of the Serial
419*c4f52879SKarthikeyan Ramasubramanian 		 * Engine and TX FIFO
420*c4f52879SKarthikeyan Ramasubramanian 		 */
421*c4f52879SKarthikeyan Ramasubramanian 		mb();
422*c4f52879SKarthikeyan Ramasubramanian 
423*c4f52879SKarthikeyan Ramasubramanian 		irq_en = readl_relaxed(uport->membase +	SE_GENI_M_IRQ_EN);
424*c4f52879SKarthikeyan Ramasubramanian 		irq_en |= M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN;
425*c4f52879SKarthikeyan Ramasubramanian 
426*c4f52879SKarthikeyan Ramasubramanian 		writel_relaxed(port->tx_wm, uport->membase +
427*c4f52879SKarthikeyan Ramasubramanian 						SE_GENI_TX_WATERMARK_REG);
428*c4f52879SKarthikeyan Ramasubramanian 		writel_relaxed(irq_en, uport->membase +	SE_GENI_M_IRQ_EN);
429*c4f52879SKarthikeyan Ramasubramanian 	}
430*c4f52879SKarthikeyan Ramasubramanian }
431*c4f52879SKarthikeyan Ramasubramanian 
432*c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_stop_tx(struct uart_port *uport)
433*c4f52879SKarthikeyan Ramasubramanian {
434*c4f52879SKarthikeyan Ramasubramanian 	u32 irq_en;
435*c4f52879SKarthikeyan Ramasubramanian 	u32 status;
436*c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
437*c4f52879SKarthikeyan Ramasubramanian 
438*c4f52879SKarthikeyan Ramasubramanian 	irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN);
439*c4f52879SKarthikeyan Ramasubramanian 	irq_en &= ~M_CMD_DONE_EN;
440*c4f52879SKarthikeyan Ramasubramanian 	if (port->xfer_mode == GENI_SE_FIFO) {
441*c4f52879SKarthikeyan Ramasubramanian 		irq_en &= ~M_TX_FIFO_WATERMARK_EN;
442*c4f52879SKarthikeyan Ramasubramanian 		writel_relaxed(0, uport->membase +
443*c4f52879SKarthikeyan Ramasubramanian 				     SE_GENI_TX_WATERMARK_REG);
444*c4f52879SKarthikeyan Ramasubramanian 	}
445*c4f52879SKarthikeyan Ramasubramanian 	port->xmit_size = 0;
446*c4f52879SKarthikeyan Ramasubramanian 	writel_relaxed(irq_en, uport->membase + SE_GENI_M_IRQ_EN);
447*c4f52879SKarthikeyan Ramasubramanian 	status = readl_relaxed(uport->membase + SE_GENI_STATUS);
448*c4f52879SKarthikeyan Ramasubramanian 	/* Possible stop tx is called multiple times. */
449*c4f52879SKarthikeyan Ramasubramanian 	if (!(status & M_GENI_CMD_ACTIVE))
450*c4f52879SKarthikeyan Ramasubramanian 		return;
451*c4f52879SKarthikeyan Ramasubramanian 
452*c4f52879SKarthikeyan Ramasubramanian 	/*
453*c4f52879SKarthikeyan Ramasubramanian 	 * Ensure cancel command write is not re-ordered before checking
454*c4f52879SKarthikeyan Ramasubramanian 	 * the status of the Primary Sequencer.
455*c4f52879SKarthikeyan Ramasubramanian 	 */
456*c4f52879SKarthikeyan Ramasubramanian 	mb();
457*c4f52879SKarthikeyan Ramasubramanian 
458*c4f52879SKarthikeyan Ramasubramanian 	geni_se_cancel_m_cmd(&port->se);
459*c4f52879SKarthikeyan Ramasubramanian 	if (!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
460*c4f52879SKarthikeyan Ramasubramanian 						M_CMD_CANCEL_EN, true)) {
461*c4f52879SKarthikeyan Ramasubramanian 		geni_se_abort_m_cmd(&port->se);
462*c4f52879SKarthikeyan Ramasubramanian 		qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
463*c4f52879SKarthikeyan Ramasubramanian 						M_CMD_ABORT_EN, true);
464*c4f52879SKarthikeyan Ramasubramanian 		writel_relaxed(M_CMD_ABORT_EN, uport->membase +
465*c4f52879SKarthikeyan Ramasubramanian 							SE_GENI_M_IRQ_CLEAR);
466*c4f52879SKarthikeyan Ramasubramanian 	}
467*c4f52879SKarthikeyan Ramasubramanian 	writel_relaxed(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
468*c4f52879SKarthikeyan Ramasubramanian }
469*c4f52879SKarthikeyan Ramasubramanian 
470*c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_start_rx(struct uart_port *uport)
471*c4f52879SKarthikeyan Ramasubramanian {
472*c4f52879SKarthikeyan Ramasubramanian 	u32 irq_en;
473*c4f52879SKarthikeyan Ramasubramanian 	u32 status;
474*c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
475*c4f52879SKarthikeyan Ramasubramanian 
476*c4f52879SKarthikeyan Ramasubramanian 	status = readl_relaxed(uport->membase + SE_GENI_STATUS);
477*c4f52879SKarthikeyan Ramasubramanian 	if (status & S_GENI_CMD_ACTIVE)
478*c4f52879SKarthikeyan Ramasubramanian 		qcom_geni_serial_stop_rx(uport);
479*c4f52879SKarthikeyan Ramasubramanian 
480*c4f52879SKarthikeyan Ramasubramanian 	/*
481*c4f52879SKarthikeyan Ramasubramanian 	 * Ensure setup command write is not re-ordered before checking
482*c4f52879SKarthikeyan Ramasubramanian 	 * the status of the Secondary Sequencer.
483*c4f52879SKarthikeyan Ramasubramanian 	 */
484*c4f52879SKarthikeyan Ramasubramanian 	mb();
485*c4f52879SKarthikeyan Ramasubramanian 
486*c4f52879SKarthikeyan Ramasubramanian 	geni_se_setup_s_cmd(&port->se, UART_START_READ, 0);
487*c4f52879SKarthikeyan Ramasubramanian 
488*c4f52879SKarthikeyan Ramasubramanian 	if (port->xfer_mode == GENI_SE_FIFO) {
489*c4f52879SKarthikeyan Ramasubramanian 		irq_en = readl_relaxed(uport->membase + SE_GENI_S_IRQ_EN);
490*c4f52879SKarthikeyan Ramasubramanian 		irq_en |= S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN;
491*c4f52879SKarthikeyan Ramasubramanian 		writel_relaxed(irq_en, uport->membase + SE_GENI_S_IRQ_EN);
492*c4f52879SKarthikeyan Ramasubramanian 
493*c4f52879SKarthikeyan Ramasubramanian 		irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN);
494*c4f52879SKarthikeyan Ramasubramanian 		irq_en |= M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN;
495*c4f52879SKarthikeyan Ramasubramanian 		writel_relaxed(irq_en, uport->membase + SE_GENI_M_IRQ_EN);
496*c4f52879SKarthikeyan Ramasubramanian 	}
497*c4f52879SKarthikeyan Ramasubramanian }
498*c4f52879SKarthikeyan Ramasubramanian 
499*c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_stop_rx(struct uart_port *uport)
500*c4f52879SKarthikeyan Ramasubramanian {
501*c4f52879SKarthikeyan Ramasubramanian 	u32 irq_en;
502*c4f52879SKarthikeyan Ramasubramanian 	u32 status;
503*c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
504*c4f52879SKarthikeyan Ramasubramanian 	u32 irq_clear = S_CMD_DONE_EN;
505*c4f52879SKarthikeyan Ramasubramanian 
506*c4f52879SKarthikeyan Ramasubramanian 	if (port->xfer_mode == GENI_SE_FIFO) {
507*c4f52879SKarthikeyan Ramasubramanian 		irq_en = readl_relaxed(uport->membase + SE_GENI_S_IRQ_EN);
508*c4f52879SKarthikeyan Ramasubramanian 		irq_en &= ~(S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN);
509*c4f52879SKarthikeyan Ramasubramanian 		writel_relaxed(irq_en, uport->membase + SE_GENI_S_IRQ_EN);
510*c4f52879SKarthikeyan Ramasubramanian 
511*c4f52879SKarthikeyan Ramasubramanian 		irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN);
512*c4f52879SKarthikeyan Ramasubramanian 		irq_en &= ~(M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN);
513*c4f52879SKarthikeyan Ramasubramanian 		writel_relaxed(irq_en, uport->membase + SE_GENI_M_IRQ_EN);
514*c4f52879SKarthikeyan Ramasubramanian 	}
515*c4f52879SKarthikeyan Ramasubramanian 
516*c4f52879SKarthikeyan Ramasubramanian 	status = readl_relaxed(uport->membase + SE_GENI_STATUS);
517*c4f52879SKarthikeyan Ramasubramanian 	/* Possible stop rx is called multiple times. */
518*c4f52879SKarthikeyan Ramasubramanian 	if (!(status & S_GENI_CMD_ACTIVE))
519*c4f52879SKarthikeyan Ramasubramanian 		return;
520*c4f52879SKarthikeyan Ramasubramanian 
521*c4f52879SKarthikeyan Ramasubramanian 	/*
522*c4f52879SKarthikeyan Ramasubramanian 	 * Ensure cancel command write is not re-ordered before checking
523*c4f52879SKarthikeyan Ramasubramanian 	 * the status of the Secondary Sequencer.
524*c4f52879SKarthikeyan Ramasubramanian 	 */
525*c4f52879SKarthikeyan Ramasubramanian 	mb();
526*c4f52879SKarthikeyan Ramasubramanian 
527*c4f52879SKarthikeyan Ramasubramanian 	geni_se_cancel_s_cmd(&port->se);
528*c4f52879SKarthikeyan Ramasubramanian 	qcom_geni_serial_poll_bit(uport, SE_GENI_S_CMD_CTRL_REG,
529*c4f52879SKarthikeyan Ramasubramanian 					S_GENI_CMD_CANCEL, false);
530*c4f52879SKarthikeyan Ramasubramanian 	status = readl_relaxed(uport->membase + SE_GENI_STATUS);
531*c4f52879SKarthikeyan Ramasubramanian 	writel_relaxed(irq_clear, uport->membase + SE_GENI_S_IRQ_CLEAR);
532*c4f52879SKarthikeyan Ramasubramanian 	if (status & S_GENI_CMD_ACTIVE)
533*c4f52879SKarthikeyan Ramasubramanian 		qcom_geni_serial_abort_rx(uport);
534*c4f52879SKarthikeyan Ramasubramanian }
535*c4f52879SKarthikeyan Ramasubramanian 
536*c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_handle_rx(struct uart_port *uport, bool drop)
537*c4f52879SKarthikeyan Ramasubramanian {
538*c4f52879SKarthikeyan Ramasubramanian 	u32 status;
539*c4f52879SKarthikeyan Ramasubramanian 	u32 word_cnt;
540*c4f52879SKarthikeyan Ramasubramanian 	u32 last_word_byte_cnt;
541*c4f52879SKarthikeyan Ramasubramanian 	u32 last_word_partial;
542*c4f52879SKarthikeyan Ramasubramanian 	u32 total_bytes;
543*c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
544*c4f52879SKarthikeyan Ramasubramanian 
545*c4f52879SKarthikeyan Ramasubramanian 	status = readl_relaxed(uport->membase +	SE_GENI_RX_FIFO_STATUS);
546*c4f52879SKarthikeyan Ramasubramanian 	word_cnt = status & RX_FIFO_WC_MSK;
547*c4f52879SKarthikeyan Ramasubramanian 	last_word_partial = status & RX_LAST;
548*c4f52879SKarthikeyan Ramasubramanian 	last_word_byte_cnt = (status & RX_LAST_BYTE_VALID_MSK) >>
549*c4f52879SKarthikeyan Ramasubramanian 						RX_LAST_BYTE_VALID_SHFT;
550*c4f52879SKarthikeyan Ramasubramanian 
551*c4f52879SKarthikeyan Ramasubramanian 	if (!word_cnt)
552*c4f52879SKarthikeyan Ramasubramanian 		return;
553*c4f52879SKarthikeyan Ramasubramanian 	total_bytes = port->rx_bytes_pw * (word_cnt - 1);
554*c4f52879SKarthikeyan Ramasubramanian 	if (last_word_partial && last_word_byte_cnt)
555*c4f52879SKarthikeyan Ramasubramanian 		total_bytes += last_word_byte_cnt;
556*c4f52879SKarthikeyan Ramasubramanian 	else
557*c4f52879SKarthikeyan Ramasubramanian 		total_bytes += port->rx_bytes_pw;
558*c4f52879SKarthikeyan Ramasubramanian 	port->handle_rx(uport, total_bytes, drop);
559*c4f52879SKarthikeyan Ramasubramanian }
560*c4f52879SKarthikeyan Ramasubramanian 
561*c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_handle_tx(struct uart_port *uport)
562*c4f52879SKarthikeyan Ramasubramanian {
563*c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
564*c4f52879SKarthikeyan Ramasubramanian 	struct circ_buf *xmit = &uport->state->xmit;
565*c4f52879SKarthikeyan Ramasubramanian 	size_t avail;
566*c4f52879SKarthikeyan Ramasubramanian 	size_t remaining;
567*c4f52879SKarthikeyan Ramasubramanian 	int i;
568*c4f52879SKarthikeyan Ramasubramanian 	u32 status;
569*c4f52879SKarthikeyan Ramasubramanian 	unsigned int chunk;
570*c4f52879SKarthikeyan Ramasubramanian 	int tail;
571*c4f52879SKarthikeyan Ramasubramanian 
572*c4f52879SKarthikeyan Ramasubramanian 	chunk = uart_circ_chars_pending(xmit);
573*c4f52879SKarthikeyan Ramasubramanian 	status = readl_relaxed(uport->membase + SE_GENI_TX_FIFO_STATUS);
574*c4f52879SKarthikeyan Ramasubramanian 	/* Both FIFO and framework buffer are drained */
575*c4f52879SKarthikeyan Ramasubramanian 	if (chunk == port->xmit_size && !status) {
576*c4f52879SKarthikeyan Ramasubramanian 		port->xmit_size = 0;
577*c4f52879SKarthikeyan Ramasubramanian 		uart_circ_clear(xmit);
578*c4f52879SKarthikeyan Ramasubramanian 		qcom_geni_serial_stop_tx(uport);
579*c4f52879SKarthikeyan Ramasubramanian 		goto out_write_wakeup;
580*c4f52879SKarthikeyan Ramasubramanian 	}
581*c4f52879SKarthikeyan Ramasubramanian 	chunk -= port->xmit_size;
582*c4f52879SKarthikeyan Ramasubramanian 
583*c4f52879SKarthikeyan Ramasubramanian 	avail = (port->tx_fifo_depth - port->tx_wm) * port->tx_bytes_pw;
584*c4f52879SKarthikeyan Ramasubramanian 	tail = (xmit->tail + port->xmit_size) & (UART_XMIT_SIZE - 1);
585*c4f52879SKarthikeyan Ramasubramanian 	if (chunk > (UART_XMIT_SIZE - tail))
586*c4f52879SKarthikeyan Ramasubramanian 		chunk = UART_XMIT_SIZE - tail;
587*c4f52879SKarthikeyan Ramasubramanian 	if (chunk > avail)
588*c4f52879SKarthikeyan Ramasubramanian 		chunk = avail;
589*c4f52879SKarthikeyan Ramasubramanian 
590*c4f52879SKarthikeyan Ramasubramanian 	if (!chunk)
591*c4f52879SKarthikeyan Ramasubramanian 		goto out_write_wakeup;
592*c4f52879SKarthikeyan Ramasubramanian 
593*c4f52879SKarthikeyan Ramasubramanian 	qcom_geni_serial_setup_tx(uport, chunk);
594*c4f52879SKarthikeyan Ramasubramanian 
595*c4f52879SKarthikeyan Ramasubramanian 	remaining = chunk;
596*c4f52879SKarthikeyan Ramasubramanian 	for (i = 0; i < chunk; ) {
597*c4f52879SKarthikeyan Ramasubramanian 		unsigned int tx_bytes;
598*c4f52879SKarthikeyan Ramasubramanian 		unsigned int buf = 0;
599*c4f52879SKarthikeyan Ramasubramanian 		int c;
600*c4f52879SKarthikeyan Ramasubramanian 
601*c4f52879SKarthikeyan Ramasubramanian 		tx_bytes = min_t(size_t, remaining, (size_t)port->tx_bytes_pw);
602*c4f52879SKarthikeyan Ramasubramanian 		for (c = 0; c < tx_bytes ; c++)
603*c4f52879SKarthikeyan Ramasubramanian 			buf |= (xmit->buf[tail + c] << (c * BITS_PER_BYTE));
604*c4f52879SKarthikeyan Ramasubramanian 
605*c4f52879SKarthikeyan Ramasubramanian 		writel_relaxed(buf, uport->membase + SE_GENI_TX_FIFOn);
606*c4f52879SKarthikeyan Ramasubramanian 
607*c4f52879SKarthikeyan Ramasubramanian 		i += tx_bytes;
608*c4f52879SKarthikeyan Ramasubramanian 		tail = (tail + tx_bytes) & (UART_XMIT_SIZE - 1);
609*c4f52879SKarthikeyan Ramasubramanian 		uport->icount.tx += tx_bytes;
610*c4f52879SKarthikeyan Ramasubramanian 		remaining -= tx_bytes;
611*c4f52879SKarthikeyan Ramasubramanian 	}
612*c4f52879SKarthikeyan Ramasubramanian 	qcom_geni_serial_poll_tx_done(uport);
613*c4f52879SKarthikeyan Ramasubramanian 	port->xmit_size += chunk;
614*c4f52879SKarthikeyan Ramasubramanian out_write_wakeup:
615*c4f52879SKarthikeyan Ramasubramanian 	uart_write_wakeup(uport);
616*c4f52879SKarthikeyan Ramasubramanian }
617*c4f52879SKarthikeyan Ramasubramanian 
618*c4f52879SKarthikeyan Ramasubramanian static irqreturn_t qcom_geni_serial_isr(int isr, void *dev)
619*c4f52879SKarthikeyan Ramasubramanian {
620*c4f52879SKarthikeyan Ramasubramanian 	unsigned int m_irq_status;
621*c4f52879SKarthikeyan Ramasubramanian 	unsigned int s_irq_status;
622*c4f52879SKarthikeyan Ramasubramanian 	struct uart_port *uport = dev;
623*c4f52879SKarthikeyan Ramasubramanian 	unsigned long flags;
624*c4f52879SKarthikeyan Ramasubramanian 	unsigned int m_irq_en;
625*c4f52879SKarthikeyan Ramasubramanian 	bool drop_rx = false;
626*c4f52879SKarthikeyan Ramasubramanian 	struct tty_port *tport = &uport->state->port;
627*c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
628*c4f52879SKarthikeyan Ramasubramanian 
629*c4f52879SKarthikeyan Ramasubramanian 	if (uport->suspended)
630*c4f52879SKarthikeyan Ramasubramanian 		return IRQ_HANDLED;
631*c4f52879SKarthikeyan Ramasubramanian 
632*c4f52879SKarthikeyan Ramasubramanian 	spin_lock_irqsave(&uport->lock, flags);
633*c4f52879SKarthikeyan Ramasubramanian 	m_irq_status = readl_relaxed(uport->membase + SE_GENI_M_IRQ_STATUS);
634*c4f52879SKarthikeyan Ramasubramanian 	s_irq_status = readl_relaxed(uport->membase + SE_GENI_S_IRQ_STATUS);
635*c4f52879SKarthikeyan Ramasubramanian 	m_irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN);
636*c4f52879SKarthikeyan Ramasubramanian 	writel_relaxed(m_irq_status, uport->membase + SE_GENI_M_IRQ_CLEAR);
637*c4f52879SKarthikeyan Ramasubramanian 	writel_relaxed(s_irq_status, uport->membase + SE_GENI_S_IRQ_CLEAR);
638*c4f52879SKarthikeyan Ramasubramanian 
639*c4f52879SKarthikeyan Ramasubramanian 	if (WARN_ON(m_irq_status & M_ILLEGAL_CMD_EN))
640*c4f52879SKarthikeyan Ramasubramanian 		goto out_unlock;
641*c4f52879SKarthikeyan Ramasubramanian 
642*c4f52879SKarthikeyan Ramasubramanian 	if (s_irq_status & S_RX_FIFO_WR_ERR_EN) {
643*c4f52879SKarthikeyan Ramasubramanian 		uport->icount.overrun++;
644*c4f52879SKarthikeyan Ramasubramanian 		tty_insert_flip_char(tport, 0, TTY_OVERRUN);
645*c4f52879SKarthikeyan Ramasubramanian 	}
646*c4f52879SKarthikeyan Ramasubramanian 
647*c4f52879SKarthikeyan Ramasubramanian 	if (m_irq_status & (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN) &&
648*c4f52879SKarthikeyan Ramasubramanian 	    m_irq_en & (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN))
649*c4f52879SKarthikeyan Ramasubramanian 		qcom_geni_serial_handle_tx(uport);
650*c4f52879SKarthikeyan Ramasubramanian 
651*c4f52879SKarthikeyan Ramasubramanian 	if (s_irq_status & S_GP_IRQ_0_EN || s_irq_status & S_GP_IRQ_1_EN) {
652*c4f52879SKarthikeyan Ramasubramanian 		if (s_irq_status & S_GP_IRQ_0_EN)
653*c4f52879SKarthikeyan Ramasubramanian 			uport->icount.parity++;
654*c4f52879SKarthikeyan Ramasubramanian 		drop_rx = true;
655*c4f52879SKarthikeyan Ramasubramanian 	} else if (s_irq_status & S_GP_IRQ_2_EN ||
656*c4f52879SKarthikeyan Ramasubramanian 					s_irq_status & S_GP_IRQ_3_EN) {
657*c4f52879SKarthikeyan Ramasubramanian 		uport->icount.brk++;
658*c4f52879SKarthikeyan Ramasubramanian 		port->brk = true;
659*c4f52879SKarthikeyan Ramasubramanian 	}
660*c4f52879SKarthikeyan Ramasubramanian 
661*c4f52879SKarthikeyan Ramasubramanian 	if (s_irq_status & S_RX_FIFO_WATERMARK_EN ||
662*c4f52879SKarthikeyan Ramasubramanian 					s_irq_status & S_RX_FIFO_LAST_EN)
663*c4f52879SKarthikeyan Ramasubramanian 		qcom_geni_serial_handle_rx(uport, drop_rx);
664*c4f52879SKarthikeyan Ramasubramanian 
665*c4f52879SKarthikeyan Ramasubramanian out_unlock:
666*c4f52879SKarthikeyan Ramasubramanian 	spin_unlock_irqrestore(&uport->lock, flags);
667*c4f52879SKarthikeyan Ramasubramanian 	return IRQ_HANDLED;
668*c4f52879SKarthikeyan Ramasubramanian }
669*c4f52879SKarthikeyan Ramasubramanian 
670*c4f52879SKarthikeyan Ramasubramanian static int get_tx_fifo_size(struct qcom_geni_serial_port *port)
671*c4f52879SKarthikeyan Ramasubramanian {
672*c4f52879SKarthikeyan Ramasubramanian 	struct uart_port *uport;
673*c4f52879SKarthikeyan Ramasubramanian 
674*c4f52879SKarthikeyan Ramasubramanian 	if (!port)
675*c4f52879SKarthikeyan Ramasubramanian 		return -ENODEV;
676*c4f52879SKarthikeyan Ramasubramanian 
677*c4f52879SKarthikeyan Ramasubramanian 	uport = &port->uport;
678*c4f52879SKarthikeyan Ramasubramanian 	port->tx_fifo_depth = geni_se_get_tx_fifo_depth(&port->se);
679*c4f52879SKarthikeyan Ramasubramanian 	port->tx_fifo_width = geni_se_get_tx_fifo_width(&port->se);
680*c4f52879SKarthikeyan Ramasubramanian 	port->rx_fifo_depth = geni_se_get_rx_fifo_depth(&port->se);
681*c4f52879SKarthikeyan Ramasubramanian 	uport->fifosize =
682*c4f52879SKarthikeyan Ramasubramanian 		(port->tx_fifo_depth * port->tx_fifo_width) / BITS_PER_BYTE;
683*c4f52879SKarthikeyan Ramasubramanian 	return 0;
684*c4f52879SKarthikeyan Ramasubramanian }
685*c4f52879SKarthikeyan Ramasubramanian 
686*c4f52879SKarthikeyan Ramasubramanian static void set_rfr_wm(struct qcom_geni_serial_port *port)
687*c4f52879SKarthikeyan Ramasubramanian {
688*c4f52879SKarthikeyan Ramasubramanian 	/*
689*c4f52879SKarthikeyan Ramasubramanian 	 * Set RFR (Flow off) to FIFO_DEPTH - 2.
690*c4f52879SKarthikeyan Ramasubramanian 	 * RX WM level at 10% RX_FIFO_DEPTH.
691*c4f52879SKarthikeyan Ramasubramanian 	 * TX WM level at 10% TX_FIFO_DEPTH.
692*c4f52879SKarthikeyan Ramasubramanian 	 */
693*c4f52879SKarthikeyan Ramasubramanian 	port->rx_rfr = port->rx_fifo_depth - 2;
694*c4f52879SKarthikeyan Ramasubramanian 	port->rx_wm = UART_CONSOLE_RX_WM;
695*c4f52879SKarthikeyan Ramasubramanian 	port->tx_wm = DEF_TX_WM;
696*c4f52879SKarthikeyan Ramasubramanian }
697*c4f52879SKarthikeyan Ramasubramanian 
698*c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_shutdown(struct uart_port *uport)
699*c4f52879SKarthikeyan Ramasubramanian {
700*c4f52879SKarthikeyan Ramasubramanian 	unsigned long flags;
701*c4f52879SKarthikeyan Ramasubramanian 
702*c4f52879SKarthikeyan Ramasubramanian 	/* Stop the console before stopping the current tx */
703*c4f52879SKarthikeyan Ramasubramanian 	console_stop(uport->cons);
704*c4f52879SKarthikeyan Ramasubramanian 
705*c4f52879SKarthikeyan Ramasubramanian 	disable_irq(uport->irq);
706*c4f52879SKarthikeyan Ramasubramanian 	free_irq(uport->irq, uport);
707*c4f52879SKarthikeyan Ramasubramanian 	spin_lock_irqsave(&uport->lock, flags);
708*c4f52879SKarthikeyan Ramasubramanian 	qcom_geni_serial_stop_tx(uport);
709*c4f52879SKarthikeyan Ramasubramanian 	qcom_geni_serial_stop_rx(uport);
710*c4f52879SKarthikeyan Ramasubramanian 	spin_unlock_irqrestore(&uport->lock, flags);
711*c4f52879SKarthikeyan Ramasubramanian }
712*c4f52879SKarthikeyan Ramasubramanian 
713*c4f52879SKarthikeyan Ramasubramanian static int qcom_geni_serial_port_setup(struct uart_port *uport)
714*c4f52879SKarthikeyan Ramasubramanian {
715*c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
716*c4f52879SKarthikeyan Ramasubramanian 	unsigned int rxstale = DEFAULT_BITS_PER_CHAR * STALE_TIMEOUT;
717*c4f52879SKarthikeyan Ramasubramanian 
718*c4f52879SKarthikeyan Ramasubramanian 	set_rfr_wm(port);
719*c4f52879SKarthikeyan Ramasubramanian 	writel_relaxed(rxstale, uport->membase + SE_UART_RX_STALE_CNT);
720*c4f52879SKarthikeyan Ramasubramanian 	/*
721*c4f52879SKarthikeyan Ramasubramanian 	 * Make an unconditional cancel on the main sequencer to reset
722*c4f52879SKarthikeyan Ramasubramanian 	 * it else we could end up in data loss scenarios.
723*c4f52879SKarthikeyan Ramasubramanian 	 */
724*c4f52879SKarthikeyan Ramasubramanian 	port->xfer_mode = GENI_SE_FIFO;
725*c4f52879SKarthikeyan Ramasubramanian 	qcom_geni_serial_poll_tx_done(uport);
726*c4f52879SKarthikeyan Ramasubramanian 	geni_se_config_packing(&port->se, BITS_PER_BYTE, port->tx_bytes_pw,
727*c4f52879SKarthikeyan Ramasubramanian 						false, true, false);
728*c4f52879SKarthikeyan Ramasubramanian 	geni_se_config_packing(&port->se, BITS_PER_BYTE, port->rx_bytes_pw,
729*c4f52879SKarthikeyan Ramasubramanian 						false, false, true);
730*c4f52879SKarthikeyan Ramasubramanian 	geni_se_init(&port->se, port->rx_wm, port->rx_rfr);
731*c4f52879SKarthikeyan Ramasubramanian 	geni_se_select_mode(&port->se, port->xfer_mode);
732*c4f52879SKarthikeyan Ramasubramanian 	port->setup = true;
733*c4f52879SKarthikeyan Ramasubramanian 	return 0;
734*c4f52879SKarthikeyan Ramasubramanian }
735*c4f52879SKarthikeyan Ramasubramanian 
736*c4f52879SKarthikeyan Ramasubramanian static int qcom_geni_serial_startup(struct uart_port *uport)
737*c4f52879SKarthikeyan Ramasubramanian {
738*c4f52879SKarthikeyan Ramasubramanian 	int ret;
739*c4f52879SKarthikeyan Ramasubramanian 	u32 proto;
740*c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
741*c4f52879SKarthikeyan Ramasubramanian 
742*c4f52879SKarthikeyan Ramasubramanian 	scnprintf(port->name, sizeof(port->name),
743*c4f52879SKarthikeyan Ramasubramanian 		  "qcom_serial_geni%d",	uport->line);
744*c4f52879SKarthikeyan Ramasubramanian 
745*c4f52879SKarthikeyan Ramasubramanian 	proto = geni_se_read_proto(&port->se);
746*c4f52879SKarthikeyan Ramasubramanian 	if (proto != GENI_SE_UART) {
747*c4f52879SKarthikeyan Ramasubramanian 		dev_err(uport->dev, "Invalid FW loaded, proto: %d\n", proto);
748*c4f52879SKarthikeyan Ramasubramanian 		return -ENXIO;
749*c4f52879SKarthikeyan Ramasubramanian 	}
750*c4f52879SKarthikeyan Ramasubramanian 
751*c4f52879SKarthikeyan Ramasubramanian 	get_tx_fifo_size(port);
752*c4f52879SKarthikeyan Ramasubramanian 	if (!port->setup) {
753*c4f52879SKarthikeyan Ramasubramanian 		ret = qcom_geni_serial_port_setup(uport);
754*c4f52879SKarthikeyan Ramasubramanian 		if (ret)
755*c4f52879SKarthikeyan Ramasubramanian 			return ret;
756*c4f52879SKarthikeyan Ramasubramanian 	}
757*c4f52879SKarthikeyan Ramasubramanian 
758*c4f52879SKarthikeyan Ramasubramanian 	ret = request_irq(uport->irq, qcom_geni_serial_isr, IRQF_TRIGGER_HIGH,
759*c4f52879SKarthikeyan Ramasubramanian 							port->name, uport);
760*c4f52879SKarthikeyan Ramasubramanian 	if (ret)
761*c4f52879SKarthikeyan Ramasubramanian 		dev_err(uport->dev, "Failed to get IRQ ret %d\n", ret);
762*c4f52879SKarthikeyan Ramasubramanian 	return ret;
763*c4f52879SKarthikeyan Ramasubramanian }
764*c4f52879SKarthikeyan Ramasubramanian 
765*c4f52879SKarthikeyan Ramasubramanian static unsigned long get_clk_cfg(unsigned long clk_freq)
766*c4f52879SKarthikeyan Ramasubramanian {
767*c4f52879SKarthikeyan Ramasubramanian 	int i;
768*c4f52879SKarthikeyan Ramasubramanian 
769*c4f52879SKarthikeyan Ramasubramanian 	for (i = 0; i < ARRAY_SIZE(root_freq); i++) {
770*c4f52879SKarthikeyan Ramasubramanian 		if (!(root_freq[i] % clk_freq))
771*c4f52879SKarthikeyan Ramasubramanian 			return root_freq[i];
772*c4f52879SKarthikeyan Ramasubramanian 	}
773*c4f52879SKarthikeyan Ramasubramanian 	return 0;
774*c4f52879SKarthikeyan Ramasubramanian }
775*c4f52879SKarthikeyan Ramasubramanian 
776*c4f52879SKarthikeyan Ramasubramanian static unsigned long get_clk_div_rate(unsigned int baud, unsigned int *clk_div)
777*c4f52879SKarthikeyan Ramasubramanian {
778*c4f52879SKarthikeyan Ramasubramanian 	unsigned long ser_clk;
779*c4f52879SKarthikeyan Ramasubramanian 	unsigned long desired_clk;
780*c4f52879SKarthikeyan Ramasubramanian 
781*c4f52879SKarthikeyan Ramasubramanian 	desired_clk = baud * UART_OVERSAMPLING;
782*c4f52879SKarthikeyan Ramasubramanian 	ser_clk = get_clk_cfg(desired_clk);
783*c4f52879SKarthikeyan Ramasubramanian 	if (!ser_clk) {
784*c4f52879SKarthikeyan Ramasubramanian 		pr_err("%s: Can't find matching DFS entry for baud %d\n",
785*c4f52879SKarthikeyan Ramasubramanian 								__func__, baud);
786*c4f52879SKarthikeyan Ramasubramanian 		return ser_clk;
787*c4f52879SKarthikeyan Ramasubramanian 	}
788*c4f52879SKarthikeyan Ramasubramanian 
789*c4f52879SKarthikeyan Ramasubramanian 	*clk_div = ser_clk / desired_clk;
790*c4f52879SKarthikeyan Ramasubramanian 	return ser_clk;
791*c4f52879SKarthikeyan Ramasubramanian }
792*c4f52879SKarthikeyan Ramasubramanian 
793*c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_set_termios(struct uart_port *uport,
794*c4f52879SKarthikeyan Ramasubramanian 				struct ktermios *termios, struct ktermios *old)
795*c4f52879SKarthikeyan Ramasubramanian {
796*c4f52879SKarthikeyan Ramasubramanian 	unsigned int baud;
797*c4f52879SKarthikeyan Ramasubramanian 	unsigned int bits_per_char;
798*c4f52879SKarthikeyan Ramasubramanian 	unsigned int tx_trans_cfg;
799*c4f52879SKarthikeyan Ramasubramanian 	unsigned int tx_parity_cfg;
800*c4f52879SKarthikeyan Ramasubramanian 	unsigned int rx_trans_cfg;
801*c4f52879SKarthikeyan Ramasubramanian 	unsigned int rx_parity_cfg;
802*c4f52879SKarthikeyan Ramasubramanian 	unsigned int stop_bit_len;
803*c4f52879SKarthikeyan Ramasubramanian 	unsigned int clk_div;
804*c4f52879SKarthikeyan Ramasubramanian 	unsigned long ser_clk_cfg;
805*c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
806*c4f52879SKarthikeyan Ramasubramanian 	unsigned long clk_rate;
807*c4f52879SKarthikeyan Ramasubramanian 
808*c4f52879SKarthikeyan Ramasubramanian 	qcom_geni_serial_stop_rx(uport);
809*c4f52879SKarthikeyan Ramasubramanian 	/* baud rate */
810*c4f52879SKarthikeyan Ramasubramanian 	baud = uart_get_baud_rate(uport, termios, old, 300, 4000000);
811*c4f52879SKarthikeyan Ramasubramanian 	port->baud = baud;
812*c4f52879SKarthikeyan Ramasubramanian 	clk_rate = get_clk_div_rate(baud, &clk_div);
813*c4f52879SKarthikeyan Ramasubramanian 	if (!clk_rate)
814*c4f52879SKarthikeyan Ramasubramanian 		goto out_restart_rx;
815*c4f52879SKarthikeyan Ramasubramanian 
816*c4f52879SKarthikeyan Ramasubramanian 	uport->uartclk = clk_rate;
817*c4f52879SKarthikeyan Ramasubramanian 	clk_set_rate(port->se.clk, clk_rate);
818*c4f52879SKarthikeyan Ramasubramanian 	ser_clk_cfg = SER_CLK_EN;
819*c4f52879SKarthikeyan Ramasubramanian 	ser_clk_cfg |= clk_div << CLK_DIV_SHFT;
820*c4f52879SKarthikeyan Ramasubramanian 
821*c4f52879SKarthikeyan Ramasubramanian 	/* parity */
822*c4f52879SKarthikeyan Ramasubramanian 	tx_trans_cfg = readl_relaxed(uport->membase + SE_UART_TX_TRANS_CFG);
823*c4f52879SKarthikeyan Ramasubramanian 	tx_parity_cfg = readl_relaxed(uport->membase + SE_UART_TX_PARITY_CFG);
824*c4f52879SKarthikeyan Ramasubramanian 	rx_trans_cfg = readl_relaxed(uport->membase + SE_UART_RX_TRANS_CFG);
825*c4f52879SKarthikeyan Ramasubramanian 	rx_parity_cfg = readl_relaxed(uport->membase + SE_UART_RX_PARITY_CFG);
826*c4f52879SKarthikeyan Ramasubramanian 	if (termios->c_cflag & PARENB) {
827*c4f52879SKarthikeyan Ramasubramanian 		tx_trans_cfg |= UART_TX_PAR_EN;
828*c4f52879SKarthikeyan Ramasubramanian 		rx_trans_cfg |= UART_RX_PAR_EN;
829*c4f52879SKarthikeyan Ramasubramanian 		tx_parity_cfg |= PAR_CALC_EN;
830*c4f52879SKarthikeyan Ramasubramanian 		rx_parity_cfg |= PAR_CALC_EN;
831*c4f52879SKarthikeyan Ramasubramanian 		if (termios->c_cflag & PARODD) {
832*c4f52879SKarthikeyan Ramasubramanian 			tx_parity_cfg |= PAR_ODD;
833*c4f52879SKarthikeyan Ramasubramanian 			rx_parity_cfg |= PAR_ODD;
834*c4f52879SKarthikeyan Ramasubramanian 		} else if (termios->c_cflag & CMSPAR) {
835*c4f52879SKarthikeyan Ramasubramanian 			tx_parity_cfg |= PAR_SPACE;
836*c4f52879SKarthikeyan Ramasubramanian 			rx_parity_cfg |= PAR_SPACE;
837*c4f52879SKarthikeyan Ramasubramanian 		} else {
838*c4f52879SKarthikeyan Ramasubramanian 			tx_parity_cfg |= PAR_EVEN;
839*c4f52879SKarthikeyan Ramasubramanian 			rx_parity_cfg |= PAR_EVEN;
840*c4f52879SKarthikeyan Ramasubramanian 		}
841*c4f52879SKarthikeyan Ramasubramanian 	} else {
842*c4f52879SKarthikeyan Ramasubramanian 		tx_trans_cfg &= ~UART_TX_PAR_EN;
843*c4f52879SKarthikeyan Ramasubramanian 		rx_trans_cfg &= ~UART_RX_PAR_EN;
844*c4f52879SKarthikeyan Ramasubramanian 		tx_parity_cfg &= ~PAR_CALC_EN;
845*c4f52879SKarthikeyan Ramasubramanian 		rx_parity_cfg &= ~PAR_CALC_EN;
846*c4f52879SKarthikeyan Ramasubramanian 	}
847*c4f52879SKarthikeyan Ramasubramanian 
848*c4f52879SKarthikeyan Ramasubramanian 	/* bits per char */
849*c4f52879SKarthikeyan Ramasubramanian 	switch (termios->c_cflag & CSIZE) {
850*c4f52879SKarthikeyan Ramasubramanian 	case CS5:
851*c4f52879SKarthikeyan Ramasubramanian 		bits_per_char = 5;
852*c4f52879SKarthikeyan Ramasubramanian 		break;
853*c4f52879SKarthikeyan Ramasubramanian 	case CS6:
854*c4f52879SKarthikeyan Ramasubramanian 		bits_per_char = 6;
855*c4f52879SKarthikeyan Ramasubramanian 		break;
856*c4f52879SKarthikeyan Ramasubramanian 	case CS7:
857*c4f52879SKarthikeyan Ramasubramanian 		bits_per_char = 7;
858*c4f52879SKarthikeyan Ramasubramanian 		break;
859*c4f52879SKarthikeyan Ramasubramanian 	case CS8:
860*c4f52879SKarthikeyan Ramasubramanian 	default:
861*c4f52879SKarthikeyan Ramasubramanian 		bits_per_char = 8;
862*c4f52879SKarthikeyan Ramasubramanian 		break;
863*c4f52879SKarthikeyan Ramasubramanian 	}
864*c4f52879SKarthikeyan Ramasubramanian 
865*c4f52879SKarthikeyan Ramasubramanian 	/* stop bits */
866*c4f52879SKarthikeyan Ramasubramanian 	if (termios->c_cflag & CSTOPB)
867*c4f52879SKarthikeyan Ramasubramanian 		stop_bit_len = TX_STOP_BIT_LEN_2;
868*c4f52879SKarthikeyan Ramasubramanian 	else
869*c4f52879SKarthikeyan Ramasubramanian 		stop_bit_len = TX_STOP_BIT_LEN_1;
870*c4f52879SKarthikeyan Ramasubramanian 
871*c4f52879SKarthikeyan Ramasubramanian 	/* flow control, clear the CTS_MASK bit if using flow control. */
872*c4f52879SKarthikeyan Ramasubramanian 	if (termios->c_cflag & CRTSCTS)
873*c4f52879SKarthikeyan Ramasubramanian 		tx_trans_cfg &= ~UART_CTS_MASK;
874*c4f52879SKarthikeyan Ramasubramanian 	else
875*c4f52879SKarthikeyan Ramasubramanian 		tx_trans_cfg |= UART_CTS_MASK;
876*c4f52879SKarthikeyan Ramasubramanian 
877*c4f52879SKarthikeyan Ramasubramanian 	if (baud)
878*c4f52879SKarthikeyan Ramasubramanian 		uart_update_timeout(uport, termios->c_cflag, baud);
879*c4f52879SKarthikeyan Ramasubramanian 
880*c4f52879SKarthikeyan Ramasubramanian 	writel_relaxed(tx_trans_cfg, uport->membase + SE_UART_TX_TRANS_CFG);
881*c4f52879SKarthikeyan Ramasubramanian 	writel_relaxed(tx_parity_cfg, uport->membase + SE_UART_TX_PARITY_CFG);
882*c4f52879SKarthikeyan Ramasubramanian 	writel_relaxed(rx_trans_cfg, uport->membase + SE_UART_RX_TRANS_CFG);
883*c4f52879SKarthikeyan Ramasubramanian 	writel_relaxed(rx_parity_cfg, uport->membase + SE_UART_RX_PARITY_CFG);
884*c4f52879SKarthikeyan Ramasubramanian 	writel_relaxed(bits_per_char, uport->membase + SE_UART_TX_WORD_LEN);
885*c4f52879SKarthikeyan Ramasubramanian 	writel_relaxed(bits_per_char, uport->membase + SE_UART_RX_WORD_LEN);
886*c4f52879SKarthikeyan Ramasubramanian 	writel_relaxed(stop_bit_len, uport->membase + SE_UART_TX_STOP_BIT_LEN);
887*c4f52879SKarthikeyan Ramasubramanian 	writel_relaxed(ser_clk_cfg, uport->membase + GENI_SER_M_CLK_CFG);
888*c4f52879SKarthikeyan Ramasubramanian 	writel_relaxed(ser_clk_cfg, uport->membase + GENI_SER_S_CLK_CFG);
889*c4f52879SKarthikeyan Ramasubramanian out_restart_rx:
890*c4f52879SKarthikeyan Ramasubramanian 	qcom_geni_serial_start_rx(uport);
891*c4f52879SKarthikeyan Ramasubramanian }
892*c4f52879SKarthikeyan Ramasubramanian 
893*c4f52879SKarthikeyan Ramasubramanian static unsigned int qcom_geni_serial_tx_empty(struct uart_port *uport)
894*c4f52879SKarthikeyan Ramasubramanian {
895*c4f52879SKarthikeyan Ramasubramanian 	return !readl_relaxed(uport->membase + SE_GENI_TX_FIFO_STATUS);
896*c4f52879SKarthikeyan Ramasubramanian }
897*c4f52879SKarthikeyan Ramasubramanian 
898*c4f52879SKarthikeyan Ramasubramanian #ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE
899*c4f52879SKarthikeyan Ramasubramanian static int __init qcom_geni_console_setup(struct console *co, char *options)
900*c4f52879SKarthikeyan Ramasubramanian {
901*c4f52879SKarthikeyan Ramasubramanian 	struct uart_port *uport;
902*c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port;
903*c4f52879SKarthikeyan Ramasubramanian 	int baud;
904*c4f52879SKarthikeyan Ramasubramanian 	int bits = 8;
905*c4f52879SKarthikeyan Ramasubramanian 	int parity = 'n';
906*c4f52879SKarthikeyan Ramasubramanian 	int flow = 'n';
907*c4f52879SKarthikeyan Ramasubramanian 
908*c4f52879SKarthikeyan Ramasubramanian 	if (co->index >= GENI_UART_CONS_PORTS  || co->index < 0)
909*c4f52879SKarthikeyan Ramasubramanian 		return -ENXIO;
910*c4f52879SKarthikeyan Ramasubramanian 
911*c4f52879SKarthikeyan Ramasubramanian 	port = get_port_from_line(co->index);
912*c4f52879SKarthikeyan Ramasubramanian 	if (IS_ERR(port)) {
913*c4f52879SKarthikeyan Ramasubramanian 		pr_err("Invalid line %d(%d)\n", co->index, (int)PTR_ERR(port));
914*c4f52879SKarthikeyan Ramasubramanian 		return PTR_ERR(port);
915*c4f52879SKarthikeyan Ramasubramanian 	}
916*c4f52879SKarthikeyan Ramasubramanian 
917*c4f52879SKarthikeyan Ramasubramanian 	uport = &port->uport;
918*c4f52879SKarthikeyan Ramasubramanian 
919*c4f52879SKarthikeyan Ramasubramanian 	if (unlikely(!uport->membase))
920*c4f52879SKarthikeyan Ramasubramanian 		return -ENXIO;
921*c4f52879SKarthikeyan Ramasubramanian 
922*c4f52879SKarthikeyan Ramasubramanian 	if (geni_se_resources_on(&port->se)) {
923*c4f52879SKarthikeyan Ramasubramanian 		dev_err(port->se.dev, "Error turning on resources\n");
924*c4f52879SKarthikeyan Ramasubramanian 		return -ENXIO;
925*c4f52879SKarthikeyan Ramasubramanian 	}
926*c4f52879SKarthikeyan Ramasubramanian 
927*c4f52879SKarthikeyan Ramasubramanian 	if (unlikely(geni_se_read_proto(&port->se) != GENI_SE_UART)) {
928*c4f52879SKarthikeyan Ramasubramanian 		geni_se_resources_off(&port->se);
929*c4f52879SKarthikeyan Ramasubramanian 		return -ENXIO;
930*c4f52879SKarthikeyan Ramasubramanian 	}
931*c4f52879SKarthikeyan Ramasubramanian 
932*c4f52879SKarthikeyan Ramasubramanian 	if (!port->setup) {
933*c4f52879SKarthikeyan Ramasubramanian 		port->tx_bytes_pw = 1;
934*c4f52879SKarthikeyan Ramasubramanian 		port->rx_bytes_pw = RX_BYTES_PW;
935*c4f52879SKarthikeyan Ramasubramanian 		qcom_geni_serial_stop_rx(uport);
936*c4f52879SKarthikeyan Ramasubramanian 		qcom_geni_serial_port_setup(uport);
937*c4f52879SKarthikeyan Ramasubramanian 	}
938*c4f52879SKarthikeyan Ramasubramanian 
939*c4f52879SKarthikeyan Ramasubramanian 	if (options)
940*c4f52879SKarthikeyan Ramasubramanian 		uart_parse_options(options, &baud, &parity, &bits, &flow);
941*c4f52879SKarthikeyan Ramasubramanian 
942*c4f52879SKarthikeyan Ramasubramanian 	return uart_set_options(uport, co, baud, parity, bits, flow);
943*c4f52879SKarthikeyan Ramasubramanian }
944*c4f52879SKarthikeyan Ramasubramanian 
945*c4f52879SKarthikeyan Ramasubramanian static int __init console_register(struct uart_driver *drv)
946*c4f52879SKarthikeyan Ramasubramanian {
947*c4f52879SKarthikeyan Ramasubramanian 	return uart_register_driver(drv);
948*c4f52879SKarthikeyan Ramasubramanian }
949*c4f52879SKarthikeyan Ramasubramanian 
950*c4f52879SKarthikeyan Ramasubramanian static void console_unregister(struct uart_driver *drv)
951*c4f52879SKarthikeyan Ramasubramanian {
952*c4f52879SKarthikeyan Ramasubramanian 	uart_unregister_driver(drv);
953*c4f52879SKarthikeyan Ramasubramanian }
954*c4f52879SKarthikeyan Ramasubramanian 
955*c4f52879SKarthikeyan Ramasubramanian static struct console cons_ops = {
956*c4f52879SKarthikeyan Ramasubramanian 	.name = "ttyMSM",
957*c4f52879SKarthikeyan Ramasubramanian 	.write = qcom_geni_serial_console_write,
958*c4f52879SKarthikeyan Ramasubramanian 	.device = uart_console_device,
959*c4f52879SKarthikeyan Ramasubramanian 	.setup = qcom_geni_console_setup,
960*c4f52879SKarthikeyan Ramasubramanian 	.flags = CON_PRINTBUFFER,
961*c4f52879SKarthikeyan Ramasubramanian 	.index = -1,
962*c4f52879SKarthikeyan Ramasubramanian 	.data = &qcom_geni_console_driver,
963*c4f52879SKarthikeyan Ramasubramanian };
964*c4f52879SKarthikeyan Ramasubramanian 
965*c4f52879SKarthikeyan Ramasubramanian static struct uart_driver qcom_geni_console_driver = {
966*c4f52879SKarthikeyan Ramasubramanian 	.owner = THIS_MODULE,
967*c4f52879SKarthikeyan Ramasubramanian 	.driver_name = "qcom_geni_console",
968*c4f52879SKarthikeyan Ramasubramanian 	.dev_name = "ttyMSM",
969*c4f52879SKarthikeyan Ramasubramanian 	.nr =  GENI_UART_CONS_PORTS,
970*c4f52879SKarthikeyan Ramasubramanian 	.cons = &cons_ops,
971*c4f52879SKarthikeyan Ramasubramanian };
972*c4f52879SKarthikeyan Ramasubramanian #else
973*c4f52879SKarthikeyan Ramasubramanian static int console_register(struct uart_driver *drv)
974*c4f52879SKarthikeyan Ramasubramanian {
975*c4f52879SKarthikeyan Ramasubramanian 	return 0;
976*c4f52879SKarthikeyan Ramasubramanian }
977*c4f52879SKarthikeyan Ramasubramanian 
978*c4f52879SKarthikeyan Ramasubramanian static void console_unregister(struct uart_driver *drv)
979*c4f52879SKarthikeyan Ramasubramanian {
980*c4f52879SKarthikeyan Ramasubramanian }
981*c4f52879SKarthikeyan Ramasubramanian #endif /* CONFIG_SERIAL_QCOM_GENI_CONSOLE */
982*c4f52879SKarthikeyan Ramasubramanian 
983*c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_cons_pm(struct uart_port *uport,
984*c4f52879SKarthikeyan Ramasubramanian 		unsigned int new_state, unsigned int old_state)
985*c4f52879SKarthikeyan Ramasubramanian {
986*c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
987*c4f52879SKarthikeyan Ramasubramanian 
988*c4f52879SKarthikeyan Ramasubramanian 	if (unlikely(!uart_console(uport)))
989*c4f52879SKarthikeyan Ramasubramanian 		return;
990*c4f52879SKarthikeyan Ramasubramanian 
991*c4f52879SKarthikeyan Ramasubramanian 	if (new_state == UART_PM_STATE_ON && old_state == UART_PM_STATE_OFF)
992*c4f52879SKarthikeyan Ramasubramanian 		geni_se_resources_on(&port->se);
993*c4f52879SKarthikeyan Ramasubramanian 	else if (new_state == UART_PM_STATE_OFF &&
994*c4f52879SKarthikeyan Ramasubramanian 			old_state == UART_PM_STATE_ON)
995*c4f52879SKarthikeyan Ramasubramanian 		geni_se_resources_off(&port->se);
996*c4f52879SKarthikeyan Ramasubramanian }
997*c4f52879SKarthikeyan Ramasubramanian 
998*c4f52879SKarthikeyan Ramasubramanian static const struct uart_ops qcom_geni_console_pops = {
999*c4f52879SKarthikeyan Ramasubramanian 	.tx_empty = qcom_geni_serial_tx_empty,
1000*c4f52879SKarthikeyan Ramasubramanian 	.stop_tx = qcom_geni_serial_stop_tx,
1001*c4f52879SKarthikeyan Ramasubramanian 	.start_tx = qcom_geni_serial_start_tx,
1002*c4f52879SKarthikeyan Ramasubramanian 	.stop_rx = qcom_geni_serial_stop_rx,
1003*c4f52879SKarthikeyan Ramasubramanian 	.set_termios = qcom_geni_serial_set_termios,
1004*c4f52879SKarthikeyan Ramasubramanian 	.startup = qcom_geni_serial_startup,
1005*c4f52879SKarthikeyan Ramasubramanian 	.request_port = qcom_geni_serial_request_port,
1006*c4f52879SKarthikeyan Ramasubramanian 	.config_port = qcom_geni_serial_config_port,
1007*c4f52879SKarthikeyan Ramasubramanian 	.shutdown = qcom_geni_serial_shutdown,
1008*c4f52879SKarthikeyan Ramasubramanian 	.type = qcom_geni_serial_get_type,
1009*c4f52879SKarthikeyan Ramasubramanian 	.set_mctrl = qcom_geni_cons_set_mctrl,
1010*c4f52879SKarthikeyan Ramasubramanian 	.get_mctrl = qcom_geni_cons_get_mctrl,
1011*c4f52879SKarthikeyan Ramasubramanian #ifdef CONFIG_CONSOLE_POLL
1012*c4f52879SKarthikeyan Ramasubramanian 	.poll_get_char	= qcom_geni_serial_get_char,
1013*c4f52879SKarthikeyan Ramasubramanian 	.poll_put_char	= qcom_geni_serial_poll_put_char,
1014*c4f52879SKarthikeyan Ramasubramanian #endif
1015*c4f52879SKarthikeyan Ramasubramanian 	.pm = qcom_geni_serial_cons_pm,
1016*c4f52879SKarthikeyan Ramasubramanian };
1017*c4f52879SKarthikeyan Ramasubramanian 
1018*c4f52879SKarthikeyan Ramasubramanian static int qcom_geni_serial_probe(struct platform_device *pdev)
1019*c4f52879SKarthikeyan Ramasubramanian {
1020*c4f52879SKarthikeyan Ramasubramanian 	int ret = 0;
1021*c4f52879SKarthikeyan Ramasubramanian 	int line = -1;
1022*c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port;
1023*c4f52879SKarthikeyan Ramasubramanian 	struct uart_port *uport;
1024*c4f52879SKarthikeyan Ramasubramanian 	struct resource *res;
1025*c4f52879SKarthikeyan Ramasubramanian 
1026*c4f52879SKarthikeyan Ramasubramanian 	if (pdev->dev.of_node)
1027*c4f52879SKarthikeyan Ramasubramanian 		line = of_alias_get_id(pdev->dev.of_node, "serial");
1028*c4f52879SKarthikeyan Ramasubramanian 	else
1029*c4f52879SKarthikeyan Ramasubramanian 		line = pdev->id;
1030*c4f52879SKarthikeyan Ramasubramanian 
1031*c4f52879SKarthikeyan Ramasubramanian 	if (line < 0 || line >= GENI_UART_CONS_PORTS)
1032*c4f52879SKarthikeyan Ramasubramanian 		return -ENXIO;
1033*c4f52879SKarthikeyan Ramasubramanian 	port = get_port_from_line(line);
1034*c4f52879SKarthikeyan Ramasubramanian 	if (IS_ERR(port)) {
1035*c4f52879SKarthikeyan Ramasubramanian 		ret = PTR_ERR(port);
1036*c4f52879SKarthikeyan Ramasubramanian 		dev_err(&pdev->dev, "Invalid line %d(%d)\n", line, ret);
1037*c4f52879SKarthikeyan Ramasubramanian 		return ret;
1038*c4f52879SKarthikeyan Ramasubramanian 	}
1039*c4f52879SKarthikeyan Ramasubramanian 
1040*c4f52879SKarthikeyan Ramasubramanian 	uport = &port->uport;
1041*c4f52879SKarthikeyan Ramasubramanian 	/* Don't allow 2 drivers to access the same port */
1042*c4f52879SKarthikeyan Ramasubramanian 	if (uport->private_data)
1043*c4f52879SKarthikeyan Ramasubramanian 		return -ENODEV;
1044*c4f52879SKarthikeyan Ramasubramanian 
1045*c4f52879SKarthikeyan Ramasubramanian 	uport->dev = &pdev->dev;
1046*c4f52879SKarthikeyan Ramasubramanian 	port->se.dev = &pdev->dev;
1047*c4f52879SKarthikeyan Ramasubramanian 	port->se.wrapper = dev_get_drvdata(pdev->dev.parent);
1048*c4f52879SKarthikeyan Ramasubramanian 	port->se.clk = devm_clk_get(&pdev->dev, "se");
1049*c4f52879SKarthikeyan Ramasubramanian 	if (IS_ERR(port->se.clk)) {
1050*c4f52879SKarthikeyan Ramasubramanian 		ret = PTR_ERR(port->se.clk);
1051*c4f52879SKarthikeyan Ramasubramanian 		dev_err(&pdev->dev, "Err getting SE Core clk %d\n", ret);
1052*c4f52879SKarthikeyan Ramasubramanian 		return ret;
1053*c4f52879SKarthikeyan Ramasubramanian 	}
1054*c4f52879SKarthikeyan Ramasubramanian 
1055*c4f52879SKarthikeyan Ramasubramanian 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1056*c4f52879SKarthikeyan Ramasubramanian 	if (IS_ERR(res))
1057*c4f52879SKarthikeyan Ramasubramanian 		return PTR_ERR(res);
1058*c4f52879SKarthikeyan Ramasubramanian 	uport->mapbase = res->start;
1059*c4f52879SKarthikeyan Ramasubramanian 
1060*c4f52879SKarthikeyan Ramasubramanian 	port->tx_fifo_depth = DEF_FIFO_DEPTH_WORDS;
1061*c4f52879SKarthikeyan Ramasubramanian 	port->rx_fifo_depth = DEF_FIFO_DEPTH_WORDS;
1062*c4f52879SKarthikeyan Ramasubramanian 	port->tx_fifo_width = DEF_FIFO_WIDTH_BITS;
1063*c4f52879SKarthikeyan Ramasubramanian 
1064*c4f52879SKarthikeyan Ramasubramanian 	uport->irq = platform_get_irq(pdev, 0);
1065*c4f52879SKarthikeyan Ramasubramanian 	if (uport->irq < 0) {
1066*c4f52879SKarthikeyan Ramasubramanian 		dev_err(&pdev->dev, "Failed to get IRQ %d\n", uport->irq);
1067*c4f52879SKarthikeyan Ramasubramanian 		return uport->irq;
1068*c4f52879SKarthikeyan Ramasubramanian 	}
1069*c4f52879SKarthikeyan Ramasubramanian 
1070*c4f52879SKarthikeyan Ramasubramanian 	uport->private_data = &qcom_geni_console_driver;
1071*c4f52879SKarthikeyan Ramasubramanian 	platform_set_drvdata(pdev, port);
1072*c4f52879SKarthikeyan Ramasubramanian 	port->handle_rx = handle_rx_console;
1073*c4f52879SKarthikeyan Ramasubramanian 	port->setup = false;
1074*c4f52879SKarthikeyan Ramasubramanian 	return uart_add_one_port(&qcom_geni_console_driver, uport);
1075*c4f52879SKarthikeyan Ramasubramanian }
1076*c4f52879SKarthikeyan Ramasubramanian 
1077*c4f52879SKarthikeyan Ramasubramanian static int qcom_geni_serial_remove(struct platform_device *pdev)
1078*c4f52879SKarthikeyan Ramasubramanian {
1079*c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port = platform_get_drvdata(pdev);
1080*c4f52879SKarthikeyan Ramasubramanian 	struct uart_driver *drv = port->uport.private_data;
1081*c4f52879SKarthikeyan Ramasubramanian 
1082*c4f52879SKarthikeyan Ramasubramanian 	uart_remove_one_port(drv, &port->uport);
1083*c4f52879SKarthikeyan Ramasubramanian 	return 0;
1084*c4f52879SKarthikeyan Ramasubramanian }
1085*c4f52879SKarthikeyan Ramasubramanian 
1086*c4f52879SKarthikeyan Ramasubramanian static int __maybe_unused qcom_geni_serial_sys_suspend_noirq(struct device *dev)
1087*c4f52879SKarthikeyan Ramasubramanian {
1088*c4f52879SKarthikeyan Ramasubramanian 	struct platform_device *pdev = to_platform_device(dev);
1089*c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port = platform_get_drvdata(pdev);
1090*c4f52879SKarthikeyan Ramasubramanian 	struct uart_port *uport = &port->uport;
1091*c4f52879SKarthikeyan Ramasubramanian 
1092*c4f52879SKarthikeyan Ramasubramanian 	uart_suspend_port(uport->private_data, uport);
1093*c4f52879SKarthikeyan Ramasubramanian 	return 0;
1094*c4f52879SKarthikeyan Ramasubramanian }
1095*c4f52879SKarthikeyan Ramasubramanian 
1096*c4f52879SKarthikeyan Ramasubramanian static int __maybe_unused qcom_geni_serial_sys_resume_noirq(struct device *dev)
1097*c4f52879SKarthikeyan Ramasubramanian {
1098*c4f52879SKarthikeyan Ramasubramanian 	struct platform_device *pdev = to_platform_device(dev);
1099*c4f52879SKarthikeyan Ramasubramanian 	struct qcom_geni_serial_port *port = platform_get_drvdata(pdev);
1100*c4f52879SKarthikeyan Ramasubramanian 	struct uart_port *uport = &port->uport;
1101*c4f52879SKarthikeyan Ramasubramanian 
1102*c4f52879SKarthikeyan Ramasubramanian 	if (console_suspend_enabled && uport->suspended) {
1103*c4f52879SKarthikeyan Ramasubramanian 		uart_resume_port(uport->private_data, uport);
1104*c4f52879SKarthikeyan Ramasubramanian 		disable_irq(uport->irq);
1105*c4f52879SKarthikeyan Ramasubramanian 	}
1106*c4f52879SKarthikeyan Ramasubramanian 	return 0;
1107*c4f52879SKarthikeyan Ramasubramanian }
1108*c4f52879SKarthikeyan Ramasubramanian 
1109*c4f52879SKarthikeyan Ramasubramanian static const struct dev_pm_ops qcom_geni_serial_pm_ops = {
1110*c4f52879SKarthikeyan Ramasubramanian 	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(qcom_geni_serial_sys_suspend_noirq,
1111*c4f52879SKarthikeyan Ramasubramanian 					qcom_geni_serial_sys_resume_noirq)
1112*c4f52879SKarthikeyan Ramasubramanian };
1113*c4f52879SKarthikeyan Ramasubramanian 
1114*c4f52879SKarthikeyan Ramasubramanian static const struct of_device_id qcom_geni_serial_match_table[] = {
1115*c4f52879SKarthikeyan Ramasubramanian 	{ .compatible = "qcom,geni-debug-uart", },
1116*c4f52879SKarthikeyan Ramasubramanian 	{}
1117*c4f52879SKarthikeyan Ramasubramanian };
1118*c4f52879SKarthikeyan Ramasubramanian MODULE_DEVICE_TABLE(of, qcom_geni_serial_match_table);
1119*c4f52879SKarthikeyan Ramasubramanian 
1120*c4f52879SKarthikeyan Ramasubramanian static struct platform_driver qcom_geni_serial_platform_driver = {
1121*c4f52879SKarthikeyan Ramasubramanian 	.remove = qcom_geni_serial_remove,
1122*c4f52879SKarthikeyan Ramasubramanian 	.probe = qcom_geni_serial_probe,
1123*c4f52879SKarthikeyan Ramasubramanian 	.driver = {
1124*c4f52879SKarthikeyan Ramasubramanian 		.name = "qcom_geni_serial",
1125*c4f52879SKarthikeyan Ramasubramanian 		.of_match_table = qcom_geni_serial_match_table,
1126*c4f52879SKarthikeyan Ramasubramanian 		.pm = &qcom_geni_serial_pm_ops,
1127*c4f52879SKarthikeyan Ramasubramanian 	},
1128*c4f52879SKarthikeyan Ramasubramanian };
1129*c4f52879SKarthikeyan Ramasubramanian 
1130*c4f52879SKarthikeyan Ramasubramanian static int __init qcom_geni_serial_init(void)
1131*c4f52879SKarthikeyan Ramasubramanian {
1132*c4f52879SKarthikeyan Ramasubramanian 	int ret;
1133*c4f52879SKarthikeyan Ramasubramanian 
1134*c4f52879SKarthikeyan Ramasubramanian 	qcom_geni_console_port.uport.iotype = UPIO_MEM;
1135*c4f52879SKarthikeyan Ramasubramanian 	qcom_geni_console_port.uport.ops = &qcom_geni_console_pops;
1136*c4f52879SKarthikeyan Ramasubramanian 	qcom_geni_console_port.uport.flags = UPF_BOOT_AUTOCONF;
1137*c4f52879SKarthikeyan Ramasubramanian 	qcom_geni_console_port.uport.line = 0;
1138*c4f52879SKarthikeyan Ramasubramanian 
1139*c4f52879SKarthikeyan Ramasubramanian 	ret = console_register(&qcom_geni_console_driver);
1140*c4f52879SKarthikeyan Ramasubramanian 	if (ret)
1141*c4f52879SKarthikeyan Ramasubramanian 		return ret;
1142*c4f52879SKarthikeyan Ramasubramanian 
1143*c4f52879SKarthikeyan Ramasubramanian 	ret = platform_driver_register(&qcom_geni_serial_platform_driver);
1144*c4f52879SKarthikeyan Ramasubramanian 	if (ret)
1145*c4f52879SKarthikeyan Ramasubramanian 		console_unregister(&qcom_geni_console_driver);
1146*c4f52879SKarthikeyan Ramasubramanian 	return ret;
1147*c4f52879SKarthikeyan Ramasubramanian }
1148*c4f52879SKarthikeyan Ramasubramanian module_init(qcom_geni_serial_init);
1149*c4f52879SKarthikeyan Ramasubramanian 
1150*c4f52879SKarthikeyan Ramasubramanian static void __exit qcom_geni_serial_exit(void)
1151*c4f52879SKarthikeyan Ramasubramanian {
1152*c4f52879SKarthikeyan Ramasubramanian 	platform_driver_unregister(&qcom_geni_serial_platform_driver);
1153*c4f52879SKarthikeyan Ramasubramanian 	console_unregister(&qcom_geni_console_driver);
1154*c4f52879SKarthikeyan Ramasubramanian }
1155*c4f52879SKarthikeyan Ramasubramanian module_exit(qcom_geni_serial_exit);
1156*c4f52879SKarthikeyan Ramasubramanian 
1157*c4f52879SKarthikeyan Ramasubramanian MODULE_DESCRIPTION("Serial driver for GENI based QUP cores");
1158*c4f52879SKarthikeyan Ramasubramanian MODULE_LICENSE("GPL v2");
1159