xref: /rk3399_rockchip-uboot/drivers/serial/serial_mpc8xx.c (revision 5bda114b503ca66ef5bbc85a2dec06523bab34ba)
1dd7ff472SChristophe Leroy /*
2dd7ff472SChristophe Leroy  * (C) Copyright 2000
3dd7ff472SChristophe Leroy  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4dd7ff472SChristophe Leroy  *
5dd7ff472SChristophe Leroy  * SPDX-License-Identifier:	GPL-2.0+
6dd7ff472SChristophe Leroy  */
7dd7ff472SChristophe Leroy 
8dd7ff472SChristophe Leroy #include <common.h>
9dd7ff472SChristophe Leroy #include <command.h>
10dd7ff472SChristophe Leroy #include <serial.h>
11dd7ff472SChristophe Leroy #include <watchdog.h>
12*5bda114bSChristophe Leroy #include <asm/cpm_8xx.h>
13dd7ff472SChristophe Leroy #include <linux/compiler.h>
14dd7ff472SChristophe Leroy 
15dd7ff472SChristophe Leroy DECLARE_GLOBAL_DATA_PTR;
16dd7ff472SChristophe Leroy 
17dd7ff472SChristophe Leroy #if defined(CONFIG_8xx_CONS_SMC1)	/* Console on SMC1 */
18dd7ff472SChristophe Leroy #define	SMC_INDEX	0
19dd7ff472SChristophe Leroy #define PROFF_SMC	PROFF_SMC1
20dd7ff472SChristophe Leroy #define CPM_CR_CH_SMC	CPM_CR_CH_SMC1
21dd7ff472SChristophe Leroy #define IOPINS		0xc0
22dd7ff472SChristophe Leroy 
23dd7ff472SChristophe Leroy #elif defined(CONFIG_8xx_CONS_SMC2)	/* Console on SMC2 */
24dd7ff472SChristophe Leroy #define SMC_INDEX	1
25dd7ff472SChristophe Leroy #define PROFF_SMC	PROFF_SMC2
26dd7ff472SChristophe Leroy #define CPM_CR_CH_SMC	CPM_CR_CH_SMC2
27dd7ff472SChristophe Leroy #define IOPINS		0xc00
28dd7ff472SChristophe Leroy 
29dd7ff472SChristophe Leroy #endif /* CONFIG_8xx_CONS_SMCx */
30dd7ff472SChristophe Leroy 
31dd7ff472SChristophe Leroy struct serialbuffer {
32dd7ff472SChristophe Leroy 	cbd_t	rxbd;		/* Rx BD */
33dd7ff472SChristophe Leroy 	cbd_t	txbd;		/* Tx BD */
34dd7ff472SChristophe Leroy 	uint	rxindex;	/* index for next character to read */
35dd7ff472SChristophe Leroy 	uchar	rxbuf[CONFIG_SYS_SMC_RXBUFLEN];/* rx buffers */
36dd7ff472SChristophe Leroy 	uchar	txbuf;	/* tx buffers */
37dd7ff472SChristophe Leroy };
38dd7ff472SChristophe Leroy 
serial_setdivisor(cpm8xx_t __iomem * cp)39dd7ff472SChristophe Leroy static void serial_setdivisor(cpm8xx_t __iomem *cp)
40dd7ff472SChristophe Leroy {
41dd7ff472SChristophe Leroy 	int divisor = (gd->cpu_clk + 8 * gd->baudrate) / 16 / gd->baudrate;
42dd7ff472SChristophe Leroy 
43dd7ff472SChristophe Leroy 	if (divisor / 16 > 0x1000) {
44dd7ff472SChristophe Leroy 		/* bad divisor, assume 50MHz clock and 9600 baud */
45dd7ff472SChristophe Leroy 		divisor = (50 * 1000 * 1000 + 8 * 9600) / 16 / 9600;
46dd7ff472SChristophe Leroy 	}
47dd7ff472SChristophe Leroy 
48dd7ff472SChristophe Leroy 	divisor /= CONFIG_SYS_BRGCLK_PRESCALE;
49dd7ff472SChristophe Leroy 
50dd7ff472SChristophe Leroy 	if (divisor <= 0x1000)
51dd7ff472SChristophe Leroy 		out_be32(&cp->cp_brgc1, ((divisor - 1) << 1) | CPM_BRG_EN);
52dd7ff472SChristophe Leroy 	else
53dd7ff472SChristophe Leroy 		out_be32(&cp->cp_brgc1, ((divisor / 16 - 1) << 1) | CPM_BRG_EN |
54dd7ff472SChristophe Leroy 			 CPM_BRG_DIV16);
55dd7ff472SChristophe Leroy }
56dd7ff472SChristophe Leroy 
57dd7ff472SChristophe Leroy /*
58dd7ff472SChristophe Leroy  * Minimal serial functions needed to use one of the SMC ports
59dd7ff472SChristophe Leroy  * as serial console interface.
60dd7ff472SChristophe Leroy  */
61dd7ff472SChristophe Leroy 
smc_setbrg(void)62dd7ff472SChristophe Leroy static void smc_setbrg(void)
63dd7ff472SChristophe Leroy {
64dd7ff472SChristophe Leroy 	immap_t __iomem *im = (immap_t __iomem *)CONFIG_SYS_IMMR;
65dd7ff472SChristophe Leroy 	cpm8xx_t __iomem *cp = &(im->im_cpm);
66dd7ff472SChristophe Leroy 
67dd7ff472SChristophe Leroy 	/* Set up the baud rate generator.
68dd7ff472SChristophe Leroy 	 * See 8xx_io/commproc.c for details.
69dd7ff472SChristophe Leroy 	 *
70dd7ff472SChristophe Leroy 	 * Wire BRG1 to SMCx
71dd7ff472SChristophe Leroy 	 */
72dd7ff472SChristophe Leroy 
73dd7ff472SChristophe Leroy 	out_be32(&cp->cp_simode, 0);
74dd7ff472SChristophe Leroy 
75dd7ff472SChristophe Leroy 	serial_setdivisor(cp);
76dd7ff472SChristophe Leroy }
77dd7ff472SChristophe Leroy 
smc_init(void)78dd7ff472SChristophe Leroy static int smc_init(void)
79dd7ff472SChristophe Leroy {
80dd7ff472SChristophe Leroy 	immap_t __iomem *im = (immap_t __iomem *)CONFIG_SYS_IMMR;
81dd7ff472SChristophe Leroy 	smc_t __iomem *sp;
82dd7ff472SChristophe Leroy 	smc_uart_t __iomem *up;
83dd7ff472SChristophe Leroy 	cpm8xx_t __iomem *cp = &(im->im_cpm);
84dd7ff472SChristophe Leroy 	struct serialbuffer __iomem *rtx;
85dd7ff472SChristophe Leroy 
86dd7ff472SChristophe Leroy 	/* initialize pointers to SMC */
87dd7ff472SChristophe Leroy 
88dd7ff472SChristophe Leroy 	sp = cp->cp_smc + SMC_INDEX;
89dd7ff472SChristophe Leroy 	up = (smc_uart_t __iomem *)&cp->cp_dparam[PROFF_SMC];
90dd7ff472SChristophe Leroy 	/* Disable relocation */
91dd7ff472SChristophe Leroy 	out_be16(&up->smc_rpbase, 0);
92dd7ff472SChristophe Leroy 
93dd7ff472SChristophe Leroy 	/* Disable transmitter/receiver. */
94dd7ff472SChristophe Leroy 	clrbits_be16(&sp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
95dd7ff472SChristophe Leroy 
96dd7ff472SChristophe Leroy 	/* Enable SDMA. */
97dd7ff472SChristophe Leroy 	out_be32(&im->im_siu_conf.sc_sdcr, 1);
98dd7ff472SChristophe Leroy 
99dd7ff472SChristophe Leroy 	/* clear error conditions */
100dd7ff472SChristophe Leroy 	out_8(&im->im_sdma.sdma_sdsr, CONFIG_SYS_SDSR);
101dd7ff472SChristophe Leroy 
102dd7ff472SChristophe Leroy 	/* clear SDMA interrupt mask */
103dd7ff472SChristophe Leroy 	out_8(&im->im_sdma.sdma_sdmr, CONFIG_SYS_SDMR);
104dd7ff472SChristophe Leroy 
105dd7ff472SChristophe Leroy 	/* Use Port B for SMCx instead of other functions. */
106dd7ff472SChristophe Leroy 	setbits_be32(&cp->cp_pbpar, IOPINS);
107dd7ff472SChristophe Leroy 	clrbits_be32(&cp->cp_pbdir, IOPINS);
108dd7ff472SChristophe Leroy 	clrbits_be16(&cp->cp_pbodr, IOPINS);
109dd7ff472SChristophe Leroy 
110dd7ff472SChristophe Leroy 	/* Set the physical address of the host memory buffers in
111dd7ff472SChristophe Leroy 	 * the buffer descriptors.
112dd7ff472SChristophe Leroy 	 */
113dd7ff472SChristophe Leroy 	rtx = (struct serialbuffer __iomem *)&cp->cp_dpmem[CPM_SERIAL_BASE];
114dd7ff472SChristophe Leroy 	/* Allocate space for two buffer descriptors in the DP ram.
115dd7ff472SChristophe Leroy 	 * For now, this address seems OK, but it may have to
116dd7ff472SChristophe Leroy 	 * change with newer versions of the firmware.
117dd7ff472SChristophe Leroy 	 * damm: allocating space after the two buffers for rx/tx data
118dd7ff472SChristophe Leroy 	 */
119dd7ff472SChristophe Leroy 
120dd7ff472SChristophe Leroy 	out_be32(&rtx->rxbd.cbd_bufaddr, (__force uint)&rtx->rxbuf);
121dd7ff472SChristophe Leroy 	out_be16(&rtx->rxbd.cbd_sc, 0);
122dd7ff472SChristophe Leroy 
123dd7ff472SChristophe Leroy 	out_be32(&rtx->txbd.cbd_bufaddr, (__force uint)&rtx->txbuf);
124dd7ff472SChristophe Leroy 	out_be16(&rtx->txbd.cbd_sc, 0);
125dd7ff472SChristophe Leroy 
126dd7ff472SChristophe Leroy 	/* Set up the uart parameters in the parameter ram. */
127dd7ff472SChristophe Leroy 	out_be16(&up->smc_rbase, CPM_SERIAL_BASE);
128dd7ff472SChristophe Leroy 	out_be16(&up->smc_tbase, CPM_SERIAL_BASE + sizeof(cbd_t));
129dd7ff472SChristophe Leroy 	out_8(&up->smc_rfcr, SMC_EB);
130dd7ff472SChristophe Leroy 	out_8(&up->smc_tfcr, SMC_EB);
131dd7ff472SChristophe Leroy 
132dd7ff472SChristophe Leroy 	/* Set UART mode, 8 bit, no parity, one stop.
133dd7ff472SChristophe Leroy 	 * Enable receive and transmit.
134dd7ff472SChristophe Leroy 	 */
135dd7ff472SChristophe Leroy 	out_be16(&sp->smc_smcmr, smcr_mk_clen(9) | SMCMR_SM_UART);
136dd7ff472SChristophe Leroy 
137dd7ff472SChristophe Leroy 	/* Mask all interrupts and remove anything pending.
138dd7ff472SChristophe Leroy 	*/
139dd7ff472SChristophe Leroy 	out_8(&sp->smc_smcm, 0);
140dd7ff472SChristophe Leroy 	out_8(&sp->smc_smce, 0xff);
141dd7ff472SChristophe Leroy 
142dd7ff472SChristophe Leroy 	/* Set up the baud rate generator */
143dd7ff472SChristophe Leroy 	smc_setbrg();
144dd7ff472SChristophe Leroy 
145dd7ff472SChristophe Leroy 	/* Make the first buffer the only buffer. */
146dd7ff472SChristophe Leroy 	setbits_be16(&rtx->txbd.cbd_sc, BD_SC_WRAP);
147dd7ff472SChristophe Leroy 	setbits_be16(&rtx->rxbd.cbd_sc, BD_SC_EMPTY | BD_SC_WRAP);
148dd7ff472SChristophe Leroy 
149dd7ff472SChristophe Leroy 	/* single/multi character receive. */
150dd7ff472SChristophe Leroy 	out_be16(&up->smc_mrblr, CONFIG_SYS_SMC_RXBUFLEN);
151dd7ff472SChristophe Leroy 	out_be16(&up->smc_maxidl, CONFIG_SYS_MAXIDLE);
152dd7ff472SChristophe Leroy 	out_be32(&rtx->rxindex, 0);
153dd7ff472SChristophe Leroy 
154dd7ff472SChristophe Leroy 	/* Initialize Tx/Rx parameters.	*/
155dd7ff472SChristophe Leroy 	while (in_be16(&cp->cp_cpcr) & CPM_CR_FLG)	/* wait if cp is busy */
156dd7ff472SChristophe Leroy 		;
157dd7ff472SChristophe Leroy 
158dd7ff472SChristophe Leroy 	out_be16(&cp->cp_cpcr,
159dd7ff472SChristophe Leroy 		 mk_cr_cmd(CPM_CR_CH_SMC, CPM_CR_INIT_TRX) | CPM_CR_FLG);
160dd7ff472SChristophe Leroy 
161dd7ff472SChristophe Leroy 	while (in_be16(&cp->cp_cpcr) & CPM_CR_FLG)	/* wait if cp is busy */
162dd7ff472SChristophe Leroy 		;
163dd7ff472SChristophe Leroy 
164dd7ff472SChristophe Leroy 	/* Enable transmitter/receiver.	*/
165dd7ff472SChristophe Leroy 	setbits_be16(&sp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
166dd7ff472SChristophe Leroy 
167dd7ff472SChristophe Leroy 	return 0;
168dd7ff472SChristophe Leroy }
169dd7ff472SChristophe Leroy 
smc_putc(const char c)170dd7ff472SChristophe Leroy static void smc_putc(const char c)
171dd7ff472SChristophe Leroy {
172dd7ff472SChristophe Leroy 	immap_t	__iomem *im = (immap_t __iomem *)CONFIG_SYS_IMMR;
173dd7ff472SChristophe Leroy 	cpm8xx_t	__iomem *cpmp = &(im->im_cpm);
174dd7ff472SChristophe Leroy 	struct serialbuffer	__iomem *rtx;
175dd7ff472SChristophe Leroy 
176dd7ff472SChristophe Leroy 	if (c == '\n')
177dd7ff472SChristophe Leroy 		smc_putc('\r');
178dd7ff472SChristophe Leroy 
179dd7ff472SChristophe Leroy 	rtx = (struct serialbuffer __iomem *)&cpmp->cp_dpmem[CPM_SERIAL_BASE];
180dd7ff472SChristophe Leroy 
181dd7ff472SChristophe Leroy 	/* Wait for last character to go. */
182dd7ff472SChristophe Leroy 	out_8(&rtx->txbuf, c);
183dd7ff472SChristophe Leroy 	out_be16(&rtx->txbd.cbd_datlen, 1);
184dd7ff472SChristophe Leroy 	setbits_be16(&rtx->txbd.cbd_sc, BD_SC_READY);
185dd7ff472SChristophe Leroy 
186dd7ff472SChristophe Leroy 	while (in_be16(&rtx->txbd.cbd_sc) & BD_SC_READY)
187dd7ff472SChristophe Leroy 		WATCHDOG_RESET();
188dd7ff472SChristophe Leroy }
189dd7ff472SChristophe Leroy 
smc_puts(const char * s)190dd7ff472SChristophe Leroy static void smc_puts(const char *s)
191dd7ff472SChristophe Leroy {
192dd7ff472SChristophe Leroy 	while (*s)
193dd7ff472SChristophe Leroy 		smc_putc(*s++);
194dd7ff472SChristophe Leroy }
195dd7ff472SChristophe Leroy 
smc_getc(void)196dd7ff472SChristophe Leroy static int smc_getc(void)
197dd7ff472SChristophe Leroy {
198dd7ff472SChristophe Leroy 	immap_t	__iomem *im = (immap_t __iomem *)CONFIG_SYS_IMMR;
199dd7ff472SChristophe Leroy 	cpm8xx_t	__iomem *cpmp = &(im->im_cpm);
200dd7ff472SChristophe Leroy 	struct serialbuffer	__iomem *rtx;
201dd7ff472SChristophe Leroy 	unsigned char  c;
202dd7ff472SChristophe Leroy 	uint rxindex;
203dd7ff472SChristophe Leroy 
204dd7ff472SChristophe Leroy 	rtx = (struct serialbuffer __iomem *)&cpmp->cp_dpmem[CPM_SERIAL_BASE];
205dd7ff472SChristophe Leroy 
206dd7ff472SChristophe Leroy 	/* Wait for character to show up. */
207dd7ff472SChristophe Leroy 	while (in_be16(&rtx->rxbd.cbd_sc) & BD_SC_EMPTY)
208dd7ff472SChristophe Leroy 		WATCHDOG_RESET();
209dd7ff472SChristophe Leroy 
210dd7ff472SChristophe Leroy 	/* the characters are read one by one,
211dd7ff472SChristophe Leroy 	 * use the rxindex to know the next char to deliver
212dd7ff472SChristophe Leroy 	 */
213dd7ff472SChristophe Leroy 	rxindex = in_be32(&rtx->rxindex);
214dd7ff472SChristophe Leroy 	c = in_8(rtx->rxbuf + rxindex);
215dd7ff472SChristophe Leroy 	rxindex++;
216dd7ff472SChristophe Leroy 
217dd7ff472SChristophe Leroy 	/* check if all char are readout, then make prepare for next receive */
218dd7ff472SChristophe Leroy 	if (rxindex >= in_be16(&rtx->rxbd.cbd_datlen)) {
219dd7ff472SChristophe Leroy 		rxindex = 0;
220dd7ff472SChristophe Leroy 		setbits_be16(&rtx->rxbd.cbd_sc, BD_SC_EMPTY);
221dd7ff472SChristophe Leroy 	}
222dd7ff472SChristophe Leroy 	out_be32(&rtx->rxindex, rxindex);
223dd7ff472SChristophe Leroy 	return c;
224dd7ff472SChristophe Leroy }
225dd7ff472SChristophe Leroy 
smc_tstc(void)226dd7ff472SChristophe Leroy static int smc_tstc(void)
227dd7ff472SChristophe Leroy {
228dd7ff472SChristophe Leroy 	immap_t	__iomem *im = (immap_t __iomem *)CONFIG_SYS_IMMR;
229dd7ff472SChristophe Leroy 	cpm8xx_t	__iomem *cpmp = &(im->im_cpm);
230dd7ff472SChristophe Leroy 	struct serialbuffer	__iomem *rtx;
231dd7ff472SChristophe Leroy 
232dd7ff472SChristophe Leroy 	rtx = (struct serialbuffer __iomem *)&cpmp->cp_dpmem[CPM_SERIAL_BASE];
233dd7ff472SChristophe Leroy 
234dd7ff472SChristophe Leroy 	return !(in_be16(&rtx->rxbd.cbd_sc) & BD_SC_EMPTY);
235dd7ff472SChristophe Leroy }
236dd7ff472SChristophe Leroy 
237dd7ff472SChristophe Leroy struct serial_device serial_smc_device = {
238dd7ff472SChristophe Leroy 	.name	= "serial_smc",
239dd7ff472SChristophe Leroy 	.start	= smc_init,
240dd7ff472SChristophe Leroy 	.stop	= NULL,
241dd7ff472SChristophe Leroy 	.setbrg	= smc_setbrg,
242dd7ff472SChristophe Leroy 	.getc	= smc_getc,
243dd7ff472SChristophe Leroy 	.tstc	= smc_tstc,
244dd7ff472SChristophe Leroy 	.putc	= smc_putc,
245dd7ff472SChristophe Leroy 	.puts	= smc_puts,
246dd7ff472SChristophe Leroy };
247dd7ff472SChristophe Leroy 
default_serial_console(void)248dd7ff472SChristophe Leroy __weak struct serial_device *default_serial_console(void)
249dd7ff472SChristophe Leroy {
250dd7ff472SChristophe Leroy 	return &serial_smc_device;
251dd7ff472SChristophe Leroy }
252dd7ff472SChristophe Leroy 
mpc8xx_serial_initialize(void)253dd7ff472SChristophe Leroy void mpc8xx_serial_initialize(void)
254dd7ff472SChristophe Leroy {
255dd7ff472SChristophe Leroy 	serial_register(&serial_smc_device);
256dd7ff472SChristophe Leroy }
257