xref: /rk3399_rockchip-uboot/drivers/serial/serial_sh.c (revision 3f6c8e36c58736d34a09287f013ee6c5f02ef7aa)
129592ecbSNobuhiro Iwamatsu /*
229592ecbSNobuhiro Iwamatsu  * SuperH SCIF device driver.
3*3f6c8e36SNobuhiro Iwamatsu  * Copyright (C) 2007,2008,2010 Nobuhiro Iwamatsu
4*3f6c8e36SNobuhiro Iwamatsu  * Copyright (C) 2002 - 2008  Paul Mundt
529592ecbSNobuhiro Iwamatsu  *
629592ecbSNobuhiro Iwamatsu  * This program is free software; you can redistribute it and/or modify
729592ecbSNobuhiro Iwamatsu  * it under the terms of the GNU General Public License as published by
829592ecbSNobuhiro Iwamatsu  * the Free Software Foundation; either version 2 of the License, or
929592ecbSNobuhiro Iwamatsu  * (at your option) any later version.
1029592ecbSNobuhiro Iwamatsu  *
1129592ecbSNobuhiro Iwamatsu  * This program is distributed in the hope that it will be useful,
1229592ecbSNobuhiro Iwamatsu  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1329592ecbSNobuhiro Iwamatsu  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1429592ecbSNobuhiro Iwamatsu  * GNU General Public License for more details.
1529592ecbSNobuhiro Iwamatsu  *
1629592ecbSNobuhiro Iwamatsu  * You should have received a copy of the GNU General Public License
1729592ecbSNobuhiro Iwamatsu  * along with this program; if not, write to the Free Software
1829592ecbSNobuhiro Iwamatsu  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
1929592ecbSNobuhiro Iwamatsu  */
2029592ecbSNobuhiro Iwamatsu 
2129592ecbSNobuhiro Iwamatsu #include <common.h>
22fc83c927SJean-Christophe PLAGNIOL-VILLARD #include <asm/io.h>
2329592ecbSNobuhiro Iwamatsu #include <asm/processor.h>
24*3f6c8e36SNobuhiro Iwamatsu #include "serial_sh.h"
2529565326SJohn Rigby 
2629592ecbSNobuhiro Iwamatsu #if defined(CONFIG_CONS_SCIF0)
2729592ecbSNobuhiro Iwamatsu # define SCIF_BASE	SCIF0_BASE
2829592ecbSNobuhiro Iwamatsu #elif defined(CONFIG_CONS_SCIF1)
2929592ecbSNobuhiro Iwamatsu # define SCIF_BASE	SCIF1_BASE
3008c5fabeSNobuhiro Iwamatsu #elif defined(CONFIG_CONS_SCIF2)
3108c5fabeSNobuhiro Iwamatsu # define SCIF_BASE	SCIF2_BASE
32ab09f433SNobuhiro Iwamatsu #elif defined(CONFIG_CONS_SCIF3)
33ab09f433SNobuhiro Iwamatsu # define SCIF_BASE	SCIF3_BASE
34ab09f433SNobuhiro Iwamatsu #elif defined(CONFIG_CONS_SCIF4)
35ab09f433SNobuhiro Iwamatsu # define SCIF_BASE	SCIF4_BASE
36ab09f433SNobuhiro Iwamatsu #elif defined(CONFIG_CONS_SCIF5)
37ab09f433SNobuhiro Iwamatsu # define SCIF_BASE	SCIF5_BASE
3829592ecbSNobuhiro Iwamatsu #else
3929592ecbSNobuhiro Iwamatsu # error "Default SCIF doesn't set....."
4029592ecbSNobuhiro Iwamatsu #endif
4129592ecbSNobuhiro Iwamatsu 
42a03c09c5SNobuhiro Iwamatsu #if defined(CONFIG_SCIF_A)
43*3f6c8e36SNobuhiro Iwamatsu 	#define SCIF_BASE_PORT	PORT_SCIFA
44ab09f433SNobuhiro Iwamatsu #else
45*3f6c8e36SNobuhiro Iwamatsu 	#define SCIF_BASE_PORT	PORT_SCIF
46ac331da0SNobuhiro Iwamatsu #endif
47ac331da0SNobuhiro Iwamatsu 
48*3f6c8e36SNobuhiro Iwamatsu static struct uart_port sh_sci = {
49*3f6c8e36SNobuhiro Iwamatsu 	.membase	= (unsigned char*)SCIF_BASE,
50*3f6c8e36SNobuhiro Iwamatsu 	.mapbase	= SCIF_BASE,
51*3f6c8e36SNobuhiro Iwamatsu 	.type		= SCIF_BASE_PORT,
52*3f6c8e36SNobuhiro Iwamatsu };
5329592ecbSNobuhiro Iwamatsu 
5429592ecbSNobuhiro Iwamatsu void serial_setbrg(void)
5529592ecbSNobuhiro Iwamatsu {
56*3f6c8e36SNobuhiro Iwamatsu 	DECLARE_GLOBAL_DATA_PTR;
57*3f6c8e36SNobuhiro Iwamatsu 	sci_out(&sh_sci, SCBRR, SCBRR_VALUE(gd->baudrate, CONFIG_SYS_CLK_FREQ));
5829592ecbSNobuhiro Iwamatsu }
5929592ecbSNobuhiro Iwamatsu 
6029592ecbSNobuhiro Iwamatsu int serial_init(void)
6129592ecbSNobuhiro Iwamatsu {
62*3f6c8e36SNobuhiro Iwamatsu 	sci_out(&sh_sci, SCSCR , SCSCR_INIT(&sh_sci));
63*3f6c8e36SNobuhiro Iwamatsu 	sci_out(&sh_sci, SCSCR , SCSCR_INIT(&sh_sci));
64*3f6c8e36SNobuhiro Iwamatsu 	sci_out(&sh_sci, SCSMR, 0);
65*3f6c8e36SNobuhiro Iwamatsu 	sci_out(&sh_sci, SCSMR, 0);
66*3f6c8e36SNobuhiro Iwamatsu 	sci_out(&sh_sci, SCFCR, SCFCR_RFRST|SCFCR_TFRST);
67*3f6c8e36SNobuhiro Iwamatsu 	sci_in(&sh_sci, SCFCR);
68*3f6c8e36SNobuhiro Iwamatsu 	sci_out(&sh_sci, SCFCR, 0);
6929592ecbSNobuhiro Iwamatsu 
7029592ecbSNobuhiro Iwamatsu 	serial_setbrg();
7129592ecbSNobuhiro Iwamatsu 	return 0;
7229592ecbSNobuhiro Iwamatsu }
7329592ecbSNobuhiro Iwamatsu 
74*3f6c8e36SNobuhiro Iwamatsu #if defined(CONFIG_CPU_SH7760) || \
75*3f6c8e36SNobuhiro Iwamatsu 	defined(CONFIG_CPU_SH7780) || \
76*3f6c8e36SNobuhiro Iwamatsu 	defined(CONFIG_CPU_SH7785) || \
77*3f6c8e36SNobuhiro Iwamatsu 	defined(CONFIG_CPU_SH7786)
78*3f6c8e36SNobuhiro Iwamatsu static int scif_rxfill(struct uart_port *port)
79*3f6c8e36SNobuhiro Iwamatsu {
80*3f6c8e36SNobuhiro Iwamatsu 	return sci_in(port, SCRFDR) & 0xff;
81*3f6c8e36SNobuhiro Iwamatsu }
82*3f6c8e36SNobuhiro Iwamatsu #elif defined(CONFIG_CPU_SH7763)
83*3f6c8e36SNobuhiro Iwamatsu static int scif_rxfill(struct uart_port *port)
84*3f6c8e36SNobuhiro Iwamatsu {
85*3f6c8e36SNobuhiro Iwamatsu 	if ((port->mapbase == 0xffe00000) ||
86*3f6c8e36SNobuhiro Iwamatsu 		(port->mapbase == 0xffe08000)) {
87*3f6c8e36SNobuhiro Iwamatsu 		/* SCIF0/1*/
88*3f6c8e36SNobuhiro Iwamatsu 		return sci_in(port, SCRFDR) & 0xff;
89*3f6c8e36SNobuhiro Iwamatsu 	} else {
90*3f6c8e36SNobuhiro Iwamatsu 		/* SCIF2 */
91*3f6c8e36SNobuhiro Iwamatsu 		return sci_in(port, SCFDR) & SCIF2_RFDC_MASK;
92*3f6c8e36SNobuhiro Iwamatsu 	}
93*3f6c8e36SNobuhiro Iwamatsu }
94*3f6c8e36SNobuhiro Iwamatsu #elif defined(CONFIG_ARCH_SH7372)
95*3f6c8e36SNobuhiro Iwamatsu static int scif_rxfill(struct uart_port *port)
96*3f6c8e36SNobuhiro Iwamatsu {
97*3f6c8e36SNobuhiro Iwamatsu 	if (port->type == PORT_SCIFA)
98*3f6c8e36SNobuhiro Iwamatsu 		return sci_in(port, SCFDR) & SCIF_RFDC_MASK;
99*3f6c8e36SNobuhiro Iwamatsu 	else
100*3f6c8e36SNobuhiro Iwamatsu 		return sci_in(port, SCRFDR);
101*3f6c8e36SNobuhiro Iwamatsu }
102*3f6c8e36SNobuhiro Iwamatsu #else
103*3f6c8e36SNobuhiro Iwamatsu static int scif_rxfill(struct uart_port *port)
104*3f6c8e36SNobuhiro Iwamatsu {
105*3f6c8e36SNobuhiro Iwamatsu 	return sci_in(port, SCFDR) & SCIF_RFDC_MASK;
106*3f6c8e36SNobuhiro Iwamatsu }
107*3f6c8e36SNobuhiro Iwamatsu #endif
108*3f6c8e36SNobuhiro Iwamatsu 
10929592ecbSNobuhiro Iwamatsu static int serial_rx_fifo_level(void)
11029592ecbSNobuhiro Iwamatsu {
111*3f6c8e36SNobuhiro Iwamatsu 	return scif_rxfill(&sh_sci);
11229592ecbSNobuhiro Iwamatsu }
11329592ecbSNobuhiro Iwamatsu 
11429592ecbSNobuhiro Iwamatsu void serial_raw_putc(const char c)
11529592ecbSNobuhiro Iwamatsu {
11629592ecbSNobuhiro Iwamatsu 	while (1) {
117*3f6c8e36SNobuhiro Iwamatsu 		/* Tx fifo is empty */
118*3f6c8e36SNobuhiro Iwamatsu 		if (sci_in(&sh_sci, SCxSR) & SCxSR_TEND(&sh_sci))
11929592ecbSNobuhiro Iwamatsu 			break;
12029592ecbSNobuhiro Iwamatsu 	}
12129592ecbSNobuhiro Iwamatsu 
122*3f6c8e36SNobuhiro Iwamatsu 	sci_out(&sh_sci, SCxTDR, c);
123*3f6c8e36SNobuhiro Iwamatsu 	sci_out(&sh_sci, SCxSR, sci_in(&sh_sci, SCxSR) & ~SCxSR_TEND(&sh_sci));
12429592ecbSNobuhiro Iwamatsu }
12529592ecbSNobuhiro Iwamatsu 
12629592ecbSNobuhiro Iwamatsu void serial_putc(const char c)
12729592ecbSNobuhiro Iwamatsu {
12829592ecbSNobuhiro Iwamatsu 	if (c == '\n')
12929592ecbSNobuhiro Iwamatsu 		serial_raw_putc('\r');
13029592ecbSNobuhiro Iwamatsu 	serial_raw_putc(c);
13129592ecbSNobuhiro Iwamatsu }
13229592ecbSNobuhiro Iwamatsu 
13329592ecbSNobuhiro Iwamatsu void serial_puts(const char *s)
13429592ecbSNobuhiro Iwamatsu {
13529592ecbSNobuhiro Iwamatsu 	char c;
13629592ecbSNobuhiro Iwamatsu 	while ((c = *s++) != 0)
13729592ecbSNobuhiro Iwamatsu 		serial_putc(c);
13829592ecbSNobuhiro Iwamatsu }
13929592ecbSNobuhiro Iwamatsu 
14029592ecbSNobuhiro Iwamatsu int serial_tstc(void)
14129592ecbSNobuhiro Iwamatsu {
14229592ecbSNobuhiro Iwamatsu 	return serial_rx_fifo_level() ? 1 : 0;
14329592ecbSNobuhiro Iwamatsu }
14429592ecbSNobuhiro Iwamatsu 
14508c5fabeSNobuhiro Iwamatsu void handle_error(void)
14608c5fabeSNobuhiro Iwamatsu {
147*3f6c8e36SNobuhiro Iwamatsu 	sci_in(&sh_sci, SCxSR);
148*3f6c8e36SNobuhiro Iwamatsu 	sci_out(&sh_sci, SCxSR, SCxSR_ERROR_CLEAR(&sh_sci));
149*3f6c8e36SNobuhiro Iwamatsu 	sci_in(&sh_sci, SCLSR);
150*3f6c8e36SNobuhiro Iwamatsu 	sci_out(&sh_sci, SCLSR, 0x00);
15129592ecbSNobuhiro Iwamatsu }
15229592ecbSNobuhiro Iwamatsu 
15308c5fabeSNobuhiro Iwamatsu int serial_getc_check(void)
15408c5fabeSNobuhiro Iwamatsu {
15529592ecbSNobuhiro Iwamatsu 	unsigned short status;
15629592ecbSNobuhiro Iwamatsu 
157*3f6c8e36SNobuhiro Iwamatsu 	status = sci_in(&sh_sci, SCxSR);
15829592ecbSNobuhiro Iwamatsu 
159*3f6c8e36SNobuhiro Iwamatsu 	if (status & SCIF_ERRORS)
16029592ecbSNobuhiro Iwamatsu 		handle_error();
161*3f6c8e36SNobuhiro Iwamatsu 	if (sci_in(&sh_sci, SCLSR) & SCxSR_ORER(&sh_sci))
16229592ecbSNobuhiro Iwamatsu 		handle_error();
163*3f6c8e36SNobuhiro Iwamatsu 	return status & (SCIF_DR | SCxSR_RDxF(&sh_sci));
16429592ecbSNobuhiro Iwamatsu }
16529592ecbSNobuhiro Iwamatsu 
16629592ecbSNobuhiro Iwamatsu int serial_getc(void)
16729592ecbSNobuhiro Iwamatsu {
16829592ecbSNobuhiro Iwamatsu 	unsigned short status;
16929592ecbSNobuhiro Iwamatsu 	char ch;
170ab09f433SNobuhiro Iwamatsu 
171ab09f433SNobuhiro Iwamatsu 	while (!serial_getc_check())
172ab09f433SNobuhiro Iwamatsu 		;
17329592ecbSNobuhiro Iwamatsu 
174*3f6c8e36SNobuhiro Iwamatsu 	ch = sci_in(&sh_sci, SCxRDR);
175*3f6c8e36SNobuhiro Iwamatsu 	status = sci_in(&sh_sci, SCxSR);
17629592ecbSNobuhiro Iwamatsu 
177*3f6c8e36SNobuhiro Iwamatsu 	sci_out(&sh_sci, SCxSR, SCxSR_RDxF_CLEAR(&sh_sci));
17829592ecbSNobuhiro Iwamatsu 
179*3f6c8e36SNobuhiro Iwamatsu 	if (status & SCIF_ERRORS)
18029592ecbSNobuhiro Iwamatsu 			handle_error();
18129592ecbSNobuhiro Iwamatsu 
182*3f6c8e36SNobuhiro Iwamatsu 	if (sci_in(&sh_sci, SCLSR) & SCxSR_ORER(&sh_sci))
18329592ecbSNobuhiro Iwamatsu 		handle_error();
18429592ecbSNobuhiro Iwamatsu 	return ch;
18529592ecbSNobuhiro Iwamatsu }
186