xref: /OK3568_Linux_fs/kernel/drivers/tty/serial/msm_geni_serial_earlycon.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (c) 2020, The Linux Foundation. All rights reserved.
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun #include <linux/console.h>
6*4882a593Smuzhiyun #include <linux/delay.h>
7*4882a593Smuzhiyun #include <linux/io.h>
8*4882a593Smuzhiyun #include <linux/serial_core.h>
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #define SE_GENI_DMA_MODE_EN             0x258
11*4882a593Smuzhiyun #define SE_UART_TX_TRANS_CFG		0x25C
12*4882a593Smuzhiyun #define SE_UART_TX_WORD_LEN		0x268
13*4882a593Smuzhiyun #define SE_UART_TX_STOP_BIT_LEN		0x26C
14*4882a593Smuzhiyun #define SE_UART_TX_TRANS_LEN		0x270
15*4882a593Smuzhiyun #define SE_UART_TX_PARITY_CFG		0x2A4
16*4882a593Smuzhiyun /* SE_UART_TRANS_CFG */
17*4882a593Smuzhiyun #define UART_CTS_MASK		BIT(1)
18*4882a593Smuzhiyun /* UART M_CMD OP codes */
19*4882a593Smuzhiyun #define UART_START_TX		0x1
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun #define UART_OVERSAMPLING	32
22*4882a593Smuzhiyun #define DEF_FIFO_DEPTH_WORDS	16
23*4882a593Smuzhiyun #define DEF_TX_WM		2
24*4882a593Smuzhiyun #define DEF_FIFO_WIDTH_BITS	32
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #define GENI_FORCE_DEFAULT_REG		0x20
27*4882a593Smuzhiyun #define GENI_OUTPUT_CTRL		0x24
28*4882a593Smuzhiyun #define GENI_CGC_CTRL			0x28
29*4882a593Smuzhiyun #define GENI_SER_M_CLK_CFG		0x48
30*4882a593Smuzhiyun #define GENI_FW_REVISION_RO		0x68
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun #define SE_GENI_TX_PACKING_CFG0		0x260
33*4882a593Smuzhiyun #define SE_GENI_TX_PACKING_CFG1		0x264
34*4882a593Smuzhiyun #define SE_GENI_M_CMD0			0x600
35*4882a593Smuzhiyun #define SE_GENI_M_CMD_CTRL_REG		0x604
36*4882a593Smuzhiyun #define SE_GENI_M_IRQ_STATUS		0x610
37*4882a593Smuzhiyun #define SE_GENI_M_IRQ_EN		0x614
38*4882a593Smuzhiyun #define SE_GENI_M_IRQ_CLEAR		0x618
39*4882a593Smuzhiyun #define SE_GENI_TX_FIFOn		0x700
40*4882a593Smuzhiyun #define SE_GENI_TX_WATERMARK_REG	0x80C
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun #define SE_IRQ_EN			0xE1C
43*4882a593Smuzhiyun #define SE_HW_PARAM_0			0xE24
44*4882a593Smuzhiyun #define SE_HW_PARAM_1			0xE28
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun /* GENI_OUTPUT_CTRL fields */
47*4882a593Smuzhiyun #define DEFAULT_IO_OUTPUT_CTRL_MSK	GENMASK(6, 0)
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun /* GENI_FORCE_DEFAULT_REG fields */
50*4882a593Smuzhiyun #define FORCE_DEFAULT	BIT(0)
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun /* GENI_CGC_CTRL fields */
53*4882a593Smuzhiyun #define CFG_AHB_CLK_CGC_ON		BIT(0)
54*4882a593Smuzhiyun #define CFG_AHB_WR_ACLK_CGC_ON		BIT(1)
55*4882a593Smuzhiyun #define DATA_AHB_CLK_CGC_ON		BIT(2)
56*4882a593Smuzhiyun #define SCLK_CGC_ON			BIT(3)
57*4882a593Smuzhiyun #define TX_CLK_CGC_ON			BIT(4)
58*4882a593Smuzhiyun #define RX_CLK_CGC_ON			BIT(5)
59*4882a593Smuzhiyun #define EXT_CLK_CGC_ON			BIT(6)
60*4882a593Smuzhiyun #define PROG_RAM_HCLK_OFF		BIT(8)
61*4882a593Smuzhiyun #define PROG_RAM_SCLK_OFF		BIT(9)
62*4882a593Smuzhiyun #define DEFAULT_CGC_EN			GENMASK(6, 0)
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun /* GENI_STATUS fields */
65*4882a593Smuzhiyun #define M_GENI_CMD_ACTIVE		BIT(0)
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun /* GENI_SER_M_CLK_CFG/GENI_SER_S_CLK_CFG */
68*4882a593Smuzhiyun #define SER_CLK_EN			BIT(0)
69*4882a593Smuzhiyun #define CLK_DIV_MSK			GENMASK(15, 4)
70*4882a593Smuzhiyun #define CLK_DIV_SHFT			4
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun /* CLK_CTRL_RO fields */
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun /* FIFO_IF_DISABLE_RO fields */
75*4882a593Smuzhiyun #define FIFO_IF_DISABLE			BIT(0)
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun /* FW_REVISION_RO fields */
78*4882a593Smuzhiyun #define FW_REV_PROTOCOL_MSK	GENMASK(15, 8)
79*4882a593Smuzhiyun #define FW_REV_PROTOCOL_SHFT	8
80*4882a593Smuzhiyun #define FW_REV_VERSION_MSK	GENMASK(7, 0)
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun /* GENI_CLK_SEL fields */
83*4882a593Smuzhiyun #define CLK_SEL_MSK		GENMASK(2, 0)
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun /* SE_GENI_DMA_MODE_EN */
86*4882a593Smuzhiyun #define GENI_DMA_MODE_EN	BIT(0)
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun /* GENI_M_CMD0 fields */
89*4882a593Smuzhiyun #define M_OPCODE_MSK		GENMASK(31, 27)
90*4882a593Smuzhiyun #define M_OPCODE_SHFT		27
91*4882a593Smuzhiyun #define M_PARAMS_MSK		GENMASK(26, 0)
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun /* GENI_M_CMD_CTRL_REG */
94*4882a593Smuzhiyun #define M_GENI_CMD_CANCEL	BIT(2)
95*4882a593Smuzhiyun #define M_GENI_CMD_ABORT	BIT(1)
96*4882a593Smuzhiyun #define M_GENI_DISABLE		BIT(0)
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun /* GENI_M_IRQ_EN fields */
99*4882a593Smuzhiyun #define M_CMD_DONE_EN		BIT(0)
100*4882a593Smuzhiyun #define M_CMD_OVERRUN_EN	BIT(1)
101*4882a593Smuzhiyun #define M_ILLEGAL_CMD_EN	BIT(2)
102*4882a593Smuzhiyun #define M_CMD_FAILURE_EN	BIT(3)
103*4882a593Smuzhiyun #define M_CMD_CANCEL_EN		BIT(4)
104*4882a593Smuzhiyun #define M_CMD_ABORT_EN		BIT(5)
105*4882a593Smuzhiyun #define M_TIMESTAMP_EN		BIT(6)
106*4882a593Smuzhiyun #define M_GP_SYNC_IRQ_0_EN	BIT(8)
107*4882a593Smuzhiyun #define M_IO_DATA_DEASSERT_EN	BIT(22)
108*4882a593Smuzhiyun #define M_IO_DATA_ASSERT_EN	BIT(23)
109*4882a593Smuzhiyun #define M_TX_FIFO_RD_ERR_EN	BIT(28)
110*4882a593Smuzhiyun #define M_TX_FIFO_WR_ERR_EN	BIT(29)
111*4882a593Smuzhiyun #define M_TX_FIFO_WATERMARK_EN	BIT(30)
112*4882a593Smuzhiyun #define M_SEC_IRQ_EN		BIT(31)
113*4882a593Smuzhiyun #define M_COMMON_GENI_M_IRQ_EN	(GENMASK(6, 1) | \
114*4882a593Smuzhiyun 				M_IO_DATA_DEASSERT_EN | \
115*4882a593Smuzhiyun 				M_IO_DATA_ASSERT_EN | M_TX_FIFO_RD_ERR_EN | \
116*4882a593Smuzhiyun 				M_TX_FIFO_WR_ERR_EN)
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun /* GENI_TX_FIFO_STATUS fields */
119*4882a593Smuzhiyun #define TX_FIFO_WC		GENMASK(27, 0)
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun /* SE_IRQ_EN fields */
122*4882a593Smuzhiyun #define GENI_M_IRQ_EN		BIT(2)
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun #define UART_PROTOCOL	2
125*4882a593Smuzhiyun 
get_se_proto_earlycon(void __iomem * base)126*4882a593Smuzhiyun static int get_se_proto_earlycon(void __iomem *base)
127*4882a593Smuzhiyun {
128*4882a593Smuzhiyun 	int proto;
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	proto = ((readl_relaxed(base + GENI_FW_REVISION_RO)
131*4882a593Smuzhiyun 			& FW_REV_PROTOCOL_MSK) >> FW_REV_PROTOCOL_SHFT);
132*4882a593Smuzhiyun 	return proto;
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun 
se_get_packing_config_earlycon(int bpw,int pack_words,bool msb_to_lsb,unsigned long * cfg0,unsigned long * cfg1)135*4882a593Smuzhiyun static void se_get_packing_config_earlycon(int bpw, int pack_words,
136*4882a593Smuzhiyun 	bool msb_to_lsb, unsigned long *cfg0, unsigned long *cfg1)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun 	u32 cfg[4] = {0};
139*4882a593Smuzhiyun 	int len, i;
140*4882a593Smuzhiyun 	int temp_bpw = bpw;
141*4882a593Smuzhiyun 	int idx_start = (msb_to_lsb ? (bpw - 1) : 0);
142*4882a593Smuzhiyun 	int idx_delta = (msb_to_lsb ? -BITS_PER_BYTE : BITS_PER_BYTE);
143*4882a593Smuzhiyun 	int ceil_bpw = ((bpw & (BITS_PER_BYTE - 1)) ?
144*4882a593Smuzhiyun 			((bpw & ~(BITS_PER_BYTE - 1)) + BITS_PER_BYTE) : bpw);
145*4882a593Smuzhiyun 	int iter = (ceil_bpw * pack_words) >> 3;
146*4882a593Smuzhiyun 	int idx = idx_start;
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	if (iter <= 0 || iter > 4) {
149*4882a593Smuzhiyun 		*cfg0 = 0;
150*4882a593Smuzhiyun 		*cfg1 = 0;
151*4882a593Smuzhiyun 		return;
152*4882a593Smuzhiyun 	}
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	for (i = 0; i < iter; i++) {
155*4882a593Smuzhiyun 		len = (temp_bpw < BITS_PER_BYTE) ?
156*4882a593Smuzhiyun 				(temp_bpw - 1) : BITS_PER_BYTE - 1;
157*4882a593Smuzhiyun 		cfg[i] = ((idx << 5) | (msb_to_lsb << 4) | (len << 1));
158*4882a593Smuzhiyun 		idx = ((temp_bpw - BITS_PER_BYTE) <= 0) ?
159*4882a593Smuzhiyun 				((i + 1) * BITS_PER_BYTE) + idx_start :
160*4882a593Smuzhiyun 				idx + idx_delta;
161*4882a593Smuzhiyun 		temp_bpw = ((temp_bpw - BITS_PER_BYTE) <= 0) ?
162*4882a593Smuzhiyun 				bpw : (temp_bpw - BITS_PER_BYTE);
163*4882a593Smuzhiyun 	}
164*4882a593Smuzhiyun 	cfg[iter - 1] |= 1;
165*4882a593Smuzhiyun 	*cfg0 = cfg[0] | (cfg[1] << 10);
166*4882a593Smuzhiyun 	*cfg1 = cfg[2] | (cfg[3] << 10);
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun 
se_io_init_earlycon(void __iomem * base)169*4882a593Smuzhiyun static void se_io_init_earlycon(void __iomem *base)
170*4882a593Smuzhiyun {
171*4882a593Smuzhiyun 	u32 io_op_ctrl;
172*4882a593Smuzhiyun 	u32 geni_cgc_ctrl;
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	geni_cgc_ctrl = readl_relaxed(base + GENI_CGC_CTRL);
175*4882a593Smuzhiyun 	geni_cgc_ctrl |= DEFAULT_CGC_EN;
176*4882a593Smuzhiyun 	io_op_ctrl = DEFAULT_IO_OUTPUT_CTRL_MSK;
177*4882a593Smuzhiyun 	writel_relaxed(geni_cgc_ctrl, base + GENI_CGC_CTRL);
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 	writel_relaxed(io_op_ctrl, base + GENI_OUTPUT_CTRL);
180*4882a593Smuzhiyun 	writel_relaxed(FORCE_DEFAULT, base + GENI_FORCE_DEFAULT_REG);
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun 
geni_se_select_fifo_mode_earlycon(void __iomem * base)183*4882a593Smuzhiyun static void geni_se_select_fifo_mode_earlycon(void __iomem *base)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun 	u32 val;
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	val = readl_relaxed(base + SE_GENI_DMA_MODE_EN);
188*4882a593Smuzhiyun 	val &= ~GENI_DMA_MODE_EN;
189*4882a593Smuzhiyun 	writel_relaxed(val, base + SE_GENI_M_IRQ_EN);
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun 
msm_geni_serial_wr_char(struct uart_port * uport,int ch)192*4882a593Smuzhiyun static void msm_geni_serial_wr_char(struct uart_port *uport, int ch)
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun 	writel_relaxed(ch, uport->membase + SE_GENI_TX_FIFOn);
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun 
msm_geni_serial_poll_bit(struct uart_port * uport,int offset,int bit_field,bool set)197*4882a593Smuzhiyun static int msm_geni_serial_poll_bit(struct uart_port *uport,
198*4882a593Smuzhiyun 					int offset, int bit_field, bool set)
199*4882a593Smuzhiyun {
200*4882a593Smuzhiyun 	int iter = 0;
201*4882a593Smuzhiyun 	bool met = false, cond = false;
202*4882a593Smuzhiyun 	unsigned int reg, total_iter = 1000;
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	while (iter < total_iter) {
205*4882a593Smuzhiyun 		reg = readl_relaxed(uport->membase + offset);
206*4882a593Smuzhiyun 		cond = reg & bit_field;
207*4882a593Smuzhiyun 		if (cond == set) {
208*4882a593Smuzhiyun 			met = true;
209*4882a593Smuzhiyun 			break;
210*4882a593Smuzhiyun 		}
211*4882a593Smuzhiyun 		udelay(10);
212*4882a593Smuzhiyun 		iter++;
213*4882a593Smuzhiyun 	}
214*4882a593Smuzhiyun 	return met;
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun 
msm_geni_serial_poll_abort_tx(struct uart_port * uport)217*4882a593Smuzhiyun static void msm_geni_serial_poll_abort_tx(struct uart_port *uport)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun 	int done = 0;
220*4882a593Smuzhiyun 	u32 irq_clear = M_CMD_DONE_EN;
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	done = msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
223*4882a593Smuzhiyun 					M_CMD_DONE_EN, true);
224*4882a593Smuzhiyun 	if (!done) {
225*4882a593Smuzhiyun 		writel_relaxed(M_GENI_CMD_ABORT,
226*4882a593Smuzhiyun 				uport->membase + SE_GENI_M_CMD_CTRL_REG);
227*4882a593Smuzhiyun 		irq_clear |= M_CMD_ABORT_EN;
228*4882a593Smuzhiyun 		msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
229*4882a593Smuzhiyun 					M_CMD_ABORT_EN, true);
230*4882a593Smuzhiyun 	}
231*4882a593Smuzhiyun 	writel_relaxed(irq_clear, uport->membase + SE_GENI_M_IRQ_CLEAR);
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun 
msm_geni_serial_setup_tx(struct uart_port * uport,unsigned int xmit_size)234*4882a593Smuzhiyun static void msm_geni_serial_setup_tx(struct uart_port *uport,
235*4882a593Smuzhiyun 				unsigned int xmit_size)
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun 	u32 m_cmd = 0;
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	writel_relaxed(xmit_size, uport->membase + SE_UART_TX_TRANS_LEN);
240*4882a593Smuzhiyun 	m_cmd |= (UART_START_TX << M_OPCODE_SHFT);
241*4882a593Smuzhiyun 	writel_relaxed(m_cmd, uport->membase + SE_GENI_M_CMD0);
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun static void
__msm_geni_serial_console_write(struct uart_port * uport,const char * s,unsigned int count)245*4882a593Smuzhiyun __msm_geni_serial_console_write(struct uart_port *uport, const char *s,
246*4882a593Smuzhiyun 				unsigned int count)
247*4882a593Smuzhiyun {
248*4882a593Smuzhiyun 	int new_line = 0;
249*4882a593Smuzhiyun 	int i;
250*4882a593Smuzhiyun 	int bytes_to_send = count;
251*4882a593Smuzhiyun 	int fifo_depth = DEF_FIFO_DEPTH_WORDS;
252*4882a593Smuzhiyun 	int tx_wm = DEF_TX_WM;
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	for (i = 0; i < count; i++) {
255*4882a593Smuzhiyun 		if (s[i] == '\n')
256*4882a593Smuzhiyun 			new_line++;
257*4882a593Smuzhiyun 	}
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	bytes_to_send += new_line;
260*4882a593Smuzhiyun 	writel_relaxed(tx_wm, uport->membase + SE_GENI_TX_WATERMARK_REG);
261*4882a593Smuzhiyun 	msm_geni_serial_setup_tx(uport, bytes_to_send);
262*4882a593Smuzhiyun 	i = 0;
263*4882a593Smuzhiyun 	while (i < count) {
264*4882a593Smuzhiyun 		u32 chars_to_write = 0;
265*4882a593Smuzhiyun 		u32 avail_fifo_bytes = (fifo_depth - tx_wm);
266*4882a593Smuzhiyun 		/*
267*4882a593Smuzhiyun 		 * If the WM bit never set, then the Tx state machine is not
268*4882a593Smuzhiyun 		 * in a valid state, so break, cancel/abort any existing
269*4882a593Smuzhiyun 		 * command. Unfortunately the current data being written is
270*4882a593Smuzhiyun 		 * lost.
271*4882a593Smuzhiyun 		 */
272*4882a593Smuzhiyun 		while (!msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
273*4882a593Smuzhiyun 						M_TX_FIFO_WATERMARK_EN, true))
274*4882a593Smuzhiyun 			break;
275*4882a593Smuzhiyun 		chars_to_write = min((unsigned int)(count - i),
276*4882a593Smuzhiyun 					avail_fifo_bytes);
277*4882a593Smuzhiyun 		if ((chars_to_write << 1) > avail_fifo_bytes)
278*4882a593Smuzhiyun 			chars_to_write = (avail_fifo_bytes >> 1);
279*4882a593Smuzhiyun 		uart_console_write(uport, (s + i), chars_to_write,
280*4882a593Smuzhiyun 					msm_geni_serial_wr_char);
281*4882a593Smuzhiyun 		writel_relaxed(M_TX_FIFO_WATERMARK_EN,
282*4882a593Smuzhiyun 				uport->membase + SE_GENI_M_IRQ_CLEAR);
283*4882a593Smuzhiyun 		i += chars_to_write;
284*4882a593Smuzhiyun 	}
285*4882a593Smuzhiyun 	msm_geni_serial_poll_abort_tx(uport);
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun static void
msm_geni_serial_early_console_write(struct console * con,const char * s,unsigned int n)289*4882a593Smuzhiyun msm_geni_serial_early_console_write(struct console *con, const char *s,
290*4882a593Smuzhiyun 					unsigned int n)
291*4882a593Smuzhiyun {
292*4882a593Smuzhiyun 	struct earlycon_device *dev = con->data;
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	__msm_geni_serial_console_write(&dev->port, s, n);
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun static int __init
msm_geni_serial_earlycon_setup(struct earlycon_device * dev,const char * opt)298*4882a593Smuzhiyun msm_geni_serial_earlycon_setup(struct earlycon_device *dev,
299*4882a593Smuzhiyun 				const char *opt)
300*4882a593Smuzhiyun {
301*4882a593Smuzhiyun 	int ret = 0;
302*4882a593Smuzhiyun 	u32 tx_trans_cfg = 0;
303*4882a593Smuzhiyun 	u32 tx_parity_cfg = 0;
304*4882a593Smuzhiyun 	u32 stop_bit = 0;
305*4882a593Smuzhiyun 	u32 bits_per_char = 0;
306*4882a593Smuzhiyun 	unsigned long cfg0, cfg1;
307*4882a593Smuzhiyun 	struct uart_port *uport = &dev->port;
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	if (!uport->membase) {
310*4882a593Smuzhiyun 		ret = -ENOMEM;
311*4882a593Smuzhiyun 		goto exit;
312*4882a593Smuzhiyun 	}
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	if (get_se_proto_earlycon(uport->membase) != UART_PROTOCOL) {
315*4882a593Smuzhiyun 		ret = -ENXIO;
316*4882a593Smuzhiyun 		goto exit;
317*4882a593Smuzhiyun 	}
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun 	/*
320*4882a593Smuzhiyun 	 * Ignore Flow control.
321*4882a593Smuzhiyun 	 * Disable Tx Parity.
322*4882a593Smuzhiyun 	 * Don't check Parity during Rx.
323*4882a593Smuzhiyun 	 * Disable Rx Parity.
324*4882a593Smuzhiyun 	 * n = 8.
325*4882a593Smuzhiyun 	 * Stop bit = 0.
326*4882a593Smuzhiyun 	 * Stale timeout in bit-time (3 chars worth).
327*4882a593Smuzhiyun 	 */
328*4882a593Smuzhiyun 	tx_trans_cfg |= UART_CTS_MASK;
329*4882a593Smuzhiyun 	tx_parity_cfg = 0;
330*4882a593Smuzhiyun 	bits_per_char = 0x8;
331*4882a593Smuzhiyun 	stop_bit = 0;
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 	msm_geni_serial_poll_abort_tx(uport);
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	se_get_packing_config_earlycon(8, 1, false, &cfg0, &cfg1);
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	se_io_init_earlycon(uport->membase);
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	geni_se_select_fifo_mode_earlycon(uport->membase);
340*4882a593Smuzhiyun 	writel_relaxed(cfg0, uport->membase + SE_GENI_TX_PACKING_CFG0);
341*4882a593Smuzhiyun 	writel_relaxed(cfg1, uport->membase + SE_GENI_TX_PACKING_CFG1);
342*4882a593Smuzhiyun 	writel_relaxed(tx_trans_cfg, uport->membase + SE_UART_TX_TRANS_CFG);
343*4882a593Smuzhiyun 	writel_relaxed(tx_parity_cfg, uport->membase + SE_UART_TX_PARITY_CFG);
344*4882a593Smuzhiyun 	writel_relaxed(bits_per_char, uport->membase + SE_UART_TX_WORD_LEN);
345*4882a593Smuzhiyun 	writel_relaxed(stop_bit, uport->membase + SE_UART_TX_STOP_BIT_LEN);
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	dev->con->write = msm_geni_serial_early_console_write;
348*4882a593Smuzhiyun 	dev->con->setup = NULL;
349*4882a593Smuzhiyun exit:
350*4882a593Smuzhiyun 	return ret;
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun OF_EARLYCON_DECLARE(msm_geni_serial, "qcom,msm-geni-console",
354*4882a593Smuzhiyun 			msm_geni_serial_earlycon_setup);
355