xref: /rk3399_rockchip-uboot/drivers/serial/serial_sh.c (revision ec3fd68952662b1badb02caab9705eb93bdc4f1b)
129592ecbSNobuhiro Iwamatsu /*
229592ecbSNobuhiro Iwamatsu  * SuperH SCIF device driver.
33f6c8e36SNobuhiro Iwamatsu  * Copyright (C) 2007,2008,2010 Nobuhiro Iwamatsu
43f6c8e36SNobuhiro 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>
243f6c8e36SNobuhiro Iwamatsu #include "serial_sh.h"
258bdd7efaSMarek Vasut #include <serial.h>
268bdd7efaSMarek Vasut #include <linux/compiler.h>
2729565326SJohn Rigby 
2829592ecbSNobuhiro Iwamatsu #if defined(CONFIG_CONS_SCIF0)
2929592ecbSNobuhiro Iwamatsu # define SCIF_BASE	SCIF0_BASE
3029592ecbSNobuhiro Iwamatsu #elif defined(CONFIG_CONS_SCIF1)
3129592ecbSNobuhiro Iwamatsu # define SCIF_BASE	SCIF1_BASE
3208c5fabeSNobuhiro Iwamatsu #elif defined(CONFIG_CONS_SCIF2)
3308c5fabeSNobuhiro Iwamatsu # define SCIF_BASE	SCIF2_BASE
34ab09f433SNobuhiro Iwamatsu #elif defined(CONFIG_CONS_SCIF3)
35ab09f433SNobuhiro Iwamatsu # define SCIF_BASE	SCIF3_BASE
36ab09f433SNobuhiro Iwamatsu #elif defined(CONFIG_CONS_SCIF4)
37ab09f433SNobuhiro Iwamatsu # define SCIF_BASE	SCIF4_BASE
38ab09f433SNobuhiro Iwamatsu #elif defined(CONFIG_CONS_SCIF5)
39ab09f433SNobuhiro Iwamatsu # define SCIF_BASE	SCIF5_BASE
4099744b7eSPhil Edworthy #elif defined(CONFIG_CONS_SCIF6)
4199744b7eSPhil Edworthy # define SCIF_BASE	SCIF6_BASE
4299744b7eSPhil Edworthy #elif defined(CONFIG_CONS_SCIF7)
4399744b7eSPhil Edworthy # define SCIF_BASE	SCIF7_BASE
4429592ecbSNobuhiro Iwamatsu #else
4529592ecbSNobuhiro Iwamatsu # error "Default SCIF doesn't set....."
4629592ecbSNobuhiro Iwamatsu #endif
4729592ecbSNobuhiro Iwamatsu 
48a03c09c5SNobuhiro Iwamatsu #if defined(CONFIG_SCIF_A)
493f6c8e36SNobuhiro Iwamatsu 	#define SCIF_BASE_PORT	PORT_SCIFA
50ab09f433SNobuhiro Iwamatsu #else
513f6c8e36SNobuhiro Iwamatsu 	#define SCIF_BASE_PORT	PORT_SCIF
52ac331da0SNobuhiro Iwamatsu #endif
53ac331da0SNobuhiro Iwamatsu 
543f6c8e36SNobuhiro Iwamatsu static struct uart_port sh_sci = {
553f6c8e36SNobuhiro Iwamatsu 	.membase	= (unsigned char*)SCIF_BASE,
563f6c8e36SNobuhiro Iwamatsu 	.mapbase	= SCIF_BASE,
573f6c8e36SNobuhiro Iwamatsu 	.type		= SCIF_BASE_PORT,
583f6c8e36SNobuhiro Iwamatsu };
5929592ecbSNobuhiro Iwamatsu 
608bdd7efaSMarek Vasut static void sh_serial_setbrg(void)
6129592ecbSNobuhiro Iwamatsu {
623f6c8e36SNobuhiro Iwamatsu 	DECLARE_GLOBAL_DATA_PTR;
633f6c8e36SNobuhiro Iwamatsu 	sci_out(&sh_sci, SCBRR, SCBRR_VALUE(gd->baudrate, CONFIG_SYS_CLK_FREQ));
6429592ecbSNobuhiro Iwamatsu }
6529592ecbSNobuhiro Iwamatsu 
668bdd7efaSMarek Vasut static int sh_serial_init(void)
6729592ecbSNobuhiro Iwamatsu {
683f6c8e36SNobuhiro Iwamatsu 	sci_out(&sh_sci, SCSCR , SCSCR_INIT(&sh_sci));
693f6c8e36SNobuhiro Iwamatsu 	sci_out(&sh_sci, SCSCR , SCSCR_INIT(&sh_sci));
703f6c8e36SNobuhiro Iwamatsu 	sci_out(&sh_sci, SCSMR, 0);
713f6c8e36SNobuhiro Iwamatsu 	sci_out(&sh_sci, SCSMR, 0);
723f6c8e36SNobuhiro Iwamatsu 	sci_out(&sh_sci, SCFCR, SCFCR_RFRST|SCFCR_TFRST);
733f6c8e36SNobuhiro Iwamatsu 	sci_in(&sh_sci, SCFCR);
743f6c8e36SNobuhiro Iwamatsu 	sci_out(&sh_sci, SCFCR, 0);
7529592ecbSNobuhiro Iwamatsu 
7629592ecbSNobuhiro Iwamatsu 	serial_setbrg();
7729592ecbSNobuhiro Iwamatsu 	return 0;
7829592ecbSNobuhiro Iwamatsu }
7929592ecbSNobuhiro Iwamatsu 
803f6c8e36SNobuhiro Iwamatsu #if defined(CONFIG_CPU_SH7760) || \
813f6c8e36SNobuhiro Iwamatsu 	defined(CONFIG_CPU_SH7780) || \
823f6c8e36SNobuhiro Iwamatsu 	defined(CONFIG_CPU_SH7785) || \
833f6c8e36SNobuhiro Iwamatsu 	defined(CONFIG_CPU_SH7786)
843f6c8e36SNobuhiro Iwamatsu static int scif_rxfill(struct uart_port *port)
853f6c8e36SNobuhiro Iwamatsu {
863f6c8e36SNobuhiro Iwamatsu 	return sci_in(port, SCRFDR) & 0xff;
873f6c8e36SNobuhiro Iwamatsu }
883f6c8e36SNobuhiro Iwamatsu #elif defined(CONFIG_CPU_SH7763)
893f6c8e36SNobuhiro Iwamatsu static int scif_rxfill(struct uart_port *port)
903f6c8e36SNobuhiro Iwamatsu {
913f6c8e36SNobuhiro Iwamatsu 	if ((port->mapbase == 0xffe00000) ||
923f6c8e36SNobuhiro Iwamatsu 		(port->mapbase == 0xffe08000)) {
933f6c8e36SNobuhiro Iwamatsu 		/* SCIF0/1*/
943f6c8e36SNobuhiro Iwamatsu 		return sci_in(port, SCRFDR) & 0xff;
953f6c8e36SNobuhiro Iwamatsu 	} else {
963f6c8e36SNobuhiro Iwamatsu 		/* SCIF2 */
973f6c8e36SNobuhiro Iwamatsu 		return sci_in(port, SCFDR) & SCIF2_RFDC_MASK;
983f6c8e36SNobuhiro Iwamatsu 	}
993f6c8e36SNobuhiro Iwamatsu }
1003f6c8e36SNobuhiro Iwamatsu #elif defined(CONFIG_ARCH_SH7372)
1013f6c8e36SNobuhiro Iwamatsu static int scif_rxfill(struct uart_port *port)
1023f6c8e36SNobuhiro Iwamatsu {
1033f6c8e36SNobuhiro Iwamatsu 	if (port->type == PORT_SCIFA)
1043f6c8e36SNobuhiro Iwamatsu 		return sci_in(port, SCFDR) & SCIF_RFDC_MASK;
1053f6c8e36SNobuhiro Iwamatsu 	else
1063f6c8e36SNobuhiro Iwamatsu 		return sci_in(port, SCRFDR);
1073f6c8e36SNobuhiro Iwamatsu }
1083f6c8e36SNobuhiro Iwamatsu #else
1093f6c8e36SNobuhiro Iwamatsu static int scif_rxfill(struct uart_port *port)
1103f6c8e36SNobuhiro Iwamatsu {
1113f6c8e36SNobuhiro Iwamatsu 	return sci_in(port, SCFDR) & SCIF_RFDC_MASK;
1123f6c8e36SNobuhiro Iwamatsu }
1133f6c8e36SNobuhiro Iwamatsu #endif
1143f6c8e36SNobuhiro Iwamatsu 
11529592ecbSNobuhiro Iwamatsu static int serial_rx_fifo_level(void)
11629592ecbSNobuhiro Iwamatsu {
1173f6c8e36SNobuhiro Iwamatsu 	return scif_rxfill(&sh_sci);
11829592ecbSNobuhiro Iwamatsu }
11929592ecbSNobuhiro Iwamatsu 
12029592ecbSNobuhiro Iwamatsu void serial_raw_putc(const char c)
12129592ecbSNobuhiro Iwamatsu {
12229592ecbSNobuhiro Iwamatsu 	while (1) {
1233f6c8e36SNobuhiro Iwamatsu 		/* Tx fifo is empty */
1243f6c8e36SNobuhiro Iwamatsu 		if (sci_in(&sh_sci, SCxSR) & SCxSR_TEND(&sh_sci))
12529592ecbSNobuhiro Iwamatsu 			break;
12629592ecbSNobuhiro Iwamatsu 	}
12729592ecbSNobuhiro Iwamatsu 
1283f6c8e36SNobuhiro Iwamatsu 	sci_out(&sh_sci, SCxTDR, c);
1293f6c8e36SNobuhiro Iwamatsu 	sci_out(&sh_sci, SCxSR, sci_in(&sh_sci, SCxSR) & ~SCxSR_TEND(&sh_sci));
13029592ecbSNobuhiro Iwamatsu }
13129592ecbSNobuhiro Iwamatsu 
1328bdd7efaSMarek Vasut static void sh_serial_putc(const char c)
13329592ecbSNobuhiro Iwamatsu {
13429592ecbSNobuhiro Iwamatsu 	if (c == '\n')
13529592ecbSNobuhiro Iwamatsu 		serial_raw_putc('\r');
13629592ecbSNobuhiro Iwamatsu 	serial_raw_putc(c);
13729592ecbSNobuhiro Iwamatsu }
13829592ecbSNobuhiro Iwamatsu 
1398bdd7efaSMarek Vasut static int sh_serial_tstc(void)
14029592ecbSNobuhiro Iwamatsu {
14129592ecbSNobuhiro Iwamatsu 	return serial_rx_fifo_level() ? 1 : 0;
14229592ecbSNobuhiro Iwamatsu }
14329592ecbSNobuhiro Iwamatsu 
14408c5fabeSNobuhiro Iwamatsu void handle_error(void)
14508c5fabeSNobuhiro Iwamatsu {
1463f6c8e36SNobuhiro Iwamatsu 	sci_in(&sh_sci, SCxSR);
1473f6c8e36SNobuhiro Iwamatsu 	sci_out(&sh_sci, SCxSR, SCxSR_ERROR_CLEAR(&sh_sci));
1483f6c8e36SNobuhiro Iwamatsu 	sci_in(&sh_sci, SCLSR);
1493f6c8e36SNobuhiro Iwamatsu 	sci_out(&sh_sci, SCLSR, 0x00);
15029592ecbSNobuhiro Iwamatsu }
15129592ecbSNobuhiro Iwamatsu 
15208c5fabeSNobuhiro Iwamatsu int serial_getc_check(void)
15308c5fabeSNobuhiro Iwamatsu {
15429592ecbSNobuhiro Iwamatsu 	unsigned short status;
15529592ecbSNobuhiro Iwamatsu 
1563f6c8e36SNobuhiro Iwamatsu 	status = sci_in(&sh_sci, SCxSR);
15729592ecbSNobuhiro Iwamatsu 
1583f6c8e36SNobuhiro Iwamatsu 	if (status & SCIF_ERRORS)
15929592ecbSNobuhiro Iwamatsu 		handle_error();
1603f6c8e36SNobuhiro Iwamatsu 	if (sci_in(&sh_sci, SCLSR) & SCxSR_ORER(&sh_sci))
16129592ecbSNobuhiro Iwamatsu 		handle_error();
1623f6c8e36SNobuhiro Iwamatsu 	return status & (SCIF_DR | SCxSR_RDxF(&sh_sci));
16329592ecbSNobuhiro Iwamatsu }
16429592ecbSNobuhiro Iwamatsu 
1658bdd7efaSMarek Vasut static int sh_serial_getc(void)
16629592ecbSNobuhiro Iwamatsu {
16729592ecbSNobuhiro Iwamatsu 	unsigned short status;
16829592ecbSNobuhiro Iwamatsu 	char ch;
169ab09f433SNobuhiro Iwamatsu 
170ab09f433SNobuhiro Iwamatsu 	while (!serial_getc_check())
171ab09f433SNobuhiro Iwamatsu 		;
17229592ecbSNobuhiro Iwamatsu 
1733f6c8e36SNobuhiro Iwamatsu 	ch = sci_in(&sh_sci, SCxRDR);
1743f6c8e36SNobuhiro Iwamatsu 	status = sci_in(&sh_sci, SCxSR);
17529592ecbSNobuhiro Iwamatsu 
1763f6c8e36SNobuhiro Iwamatsu 	sci_out(&sh_sci, SCxSR, SCxSR_RDxF_CLEAR(&sh_sci));
17729592ecbSNobuhiro Iwamatsu 
1783f6c8e36SNobuhiro Iwamatsu 	if (status & SCIF_ERRORS)
17929592ecbSNobuhiro Iwamatsu 			handle_error();
18029592ecbSNobuhiro Iwamatsu 
1813f6c8e36SNobuhiro Iwamatsu 	if (sci_in(&sh_sci, SCLSR) & SCxSR_ORER(&sh_sci))
18229592ecbSNobuhiro Iwamatsu 		handle_error();
18329592ecbSNobuhiro Iwamatsu 	return ch;
18429592ecbSNobuhiro Iwamatsu }
1858bdd7efaSMarek Vasut 
1868bdd7efaSMarek Vasut static struct serial_device sh_serial_drv = {
1878bdd7efaSMarek Vasut 	.name	= "sh_serial",
1888bdd7efaSMarek Vasut 	.start	= sh_serial_init,
1898bdd7efaSMarek Vasut 	.stop	= NULL,
1908bdd7efaSMarek Vasut 	.setbrg	= sh_serial_setbrg,
1918bdd7efaSMarek Vasut 	.putc	= sh_serial_putc,
192*ec3fd689SMarek Vasut 	.puts	= default_serial_puts,
1938bdd7efaSMarek Vasut 	.getc	= sh_serial_getc,
1948bdd7efaSMarek Vasut 	.tstc	= sh_serial_tstc,
1958bdd7efaSMarek Vasut };
1968bdd7efaSMarek Vasut 
1978bdd7efaSMarek Vasut void sh_serial_initialize(void)
1988bdd7efaSMarek Vasut {
1998bdd7efaSMarek Vasut 	serial_register(&sh_serial_drv);
2008bdd7efaSMarek Vasut }
2018bdd7efaSMarek Vasut 
2028bdd7efaSMarek Vasut __weak struct serial_device *default_serial_console(void)
2038bdd7efaSMarek Vasut {
2048bdd7efaSMarek Vasut 	return &sh_serial_drv;
2058bdd7efaSMarek Vasut }
206