xref: /openbmc/u-boot/drivers/serial/serial_arc.c (revision 94b5400e76f6a5100e2af88de274b0a6881bf94d)
122a240c3SAlexey Brodkin /*
222a240c3SAlexey Brodkin  * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com)
322a240c3SAlexey Brodkin  *
422a240c3SAlexey Brodkin  * This program is free software; you can redistribute it and/or modify
522a240c3SAlexey Brodkin  * it under the terms of the GNU General Public License version 2 as
622a240c3SAlexey Brodkin  * published by the Free Software Foundation.
722a240c3SAlexey Brodkin  *
822a240c3SAlexey Brodkin  */
922a240c3SAlexey Brodkin 
1022a240c3SAlexey Brodkin #include <common.h>
1122a240c3SAlexey Brodkin #include <serial.h>
1222a240c3SAlexey Brodkin 
1322a240c3SAlexey Brodkin DECLARE_GLOBAL_DATA_PTR;
1422a240c3SAlexey Brodkin 
1522a240c3SAlexey Brodkin struct arc_serial_regs {
1622a240c3SAlexey Brodkin 	unsigned int id0;
1722a240c3SAlexey Brodkin 	unsigned int id1;
1822a240c3SAlexey Brodkin 	unsigned int id2;
1922a240c3SAlexey Brodkin 	unsigned int id3;
2022a240c3SAlexey Brodkin 	unsigned int data;
2122a240c3SAlexey Brodkin 	unsigned int status;
2222a240c3SAlexey Brodkin 	unsigned int baudl;
2322a240c3SAlexey Brodkin 	unsigned int baudh;
2422a240c3SAlexey Brodkin };
2522a240c3SAlexey Brodkin 
2622a240c3SAlexey Brodkin /* Bit definitions of STATUS register */
2722a240c3SAlexey Brodkin #define UART_RXEMPTY		(1 << 5)
2822a240c3SAlexey Brodkin #define UART_OVERFLOW_ERR	(1 << 1)
2922a240c3SAlexey Brodkin #define UART_TXEMPTY		(1 << 7)
3022a240c3SAlexey Brodkin 
3122a240c3SAlexey Brodkin struct arc_serial_regs *regs;
3222a240c3SAlexey Brodkin 
3322a240c3SAlexey Brodkin static void arc_serial_setbrg(void)
3422a240c3SAlexey Brodkin {
3522a240c3SAlexey Brodkin 	int arc_console_baud;
3622a240c3SAlexey Brodkin 
3722a240c3SAlexey Brodkin 	if (!gd->baudrate)
3822a240c3SAlexey Brodkin 		gd->baudrate = CONFIG_BAUDRATE;
3922a240c3SAlexey Brodkin 
4022a240c3SAlexey Brodkin 	arc_console_baud = gd->cpu_clk / (gd->baudrate * 4) - 1;
41*94b5400eSAlexey Brodkin 	writeb(arc_console_baud & 0xff, &regs->baudl);
421d568c76SAlexey Brodkin 
431d568c76SAlexey Brodkin #ifdef CONFIG_ARC
441d568c76SAlexey Brodkin 	/*
451d568c76SAlexey Brodkin 	 * UART ISS(Instruction Set simulator) emulation has a subtle bug:
461d568c76SAlexey Brodkin 	 * A existing value of Baudh = 0 is used as a indication to startup
471d568c76SAlexey Brodkin 	 * it's internal state machine.
481d568c76SAlexey Brodkin 	 * Thus if baudh is set to 0, 2 times, it chokes.
491d568c76SAlexey Brodkin 	 * This happens with BAUD=115200 and the formaula above
501d568c76SAlexey Brodkin 	 * Until that is fixed, when running on ISS, we will set baudh to !0
511d568c76SAlexey Brodkin 	 */
521d568c76SAlexey Brodkin 	if (gd->arch.running_on_hw)
53*94b5400eSAlexey Brodkin 		writeb((arc_console_baud & 0xff00) >> 8, &regs->baudh);
541d568c76SAlexey Brodkin 	else
55*94b5400eSAlexey Brodkin 		writeb(1, &regs->baudh);
561d568c76SAlexey Brodkin #else
57*94b5400eSAlexey Brodkin 	writeb((arc_console_baud & 0xff00) >> 8, &regs->baudh);
581d568c76SAlexey Brodkin #endif
5922a240c3SAlexey Brodkin }
6022a240c3SAlexey Brodkin 
6122a240c3SAlexey Brodkin static int arc_serial_init(void)
6222a240c3SAlexey Brodkin {
6322a240c3SAlexey Brodkin 	regs = (struct arc_serial_regs *)CONFIG_ARC_UART_BASE;
6422a240c3SAlexey Brodkin 	serial_setbrg();
6522a240c3SAlexey Brodkin 	return 0;
6622a240c3SAlexey Brodkin }
6722a240c3SAlexey Brodkin 
6822a240c3SAlexey Brodkin static void arc_serial_putc(const char c)
6922a240c3SAlexey Brodkin {
7022a240c3SAlexey Brodkin 	if (c == '\n')
7122a240c3SAlexey Brodkin 		arc_serial_putc('\r');
7222a240c3SAlexey Brodkin 
73*94b5400eSAlexey Brodkin 	while (!(readb(&regs->status) & UART_TXEMPTY))
7422a240c3SAlexey Brodkin 		;
7522a240c3SAlexey Brodkin 
76*94b5400eSAlexey Brodkin 	writeb(c, &regs->data);
7722a240c3SAlexey Brodkin }
7822a240c3SAlexey Brodkin 
7922a240c3SAlexey Brodkin static int arc_serial_tstc(void)
8022a240c3SAlexey Brodkin {
81*94b5400eSAlexey Brodkin 	return !(readb(&regs->status) & UART_RXEMPTY);
8222a240c3SAlexey Brodkin }
8322a240c3SAlexey Brodkin 
8422a240c3SAlexey Brodkin static int arc_serial_getc(void)
8522a240c3SAlexey Brodkin {
8622a240c3SAlexey Brodkin 	while (!arc_serial_tstc())
8722a240c3SAlexey Brodkin 		;
8822a240c3SAlexey Brodkin 
8922a240c3SAlexey Brodkin 	/* Check for overflow errors */
90*94b5400eSAlexey Brodkin 	if (readb(&regs->status) & UART_OVERFLOW_ERR)
9122a240c3SAlexey Brodkin 		return 0;
9222a240c3SAlexey Brodkin 
93*94b5400eSAlexey Brodkin 	return readb(&regs->data) & 0xFF;
9422a240c3SAlexey Brodkin }
9522a240c3SAlexey Brodkin 
9622a240c3SAlexey Brodkin static void arc_serial_puts(const char *s)
9722a240c3SAlexey Brodkin {
9822a240c3SAlexey Brodkin 	while (*s)
9922a240c3SAlexey Brodkin 		arc_serial_putc(*s++);
10022a240c3SAlexey Brodkin }
10122a240c3SAlexey Brodkin 
10222a240c3SAlexey Brodkin static struct serial_device arc_serial_drv = {
10322a240c3SAlexey Brodkin 	.name	= "arc_serial",
10422a240c3SAlexey Brodkin 	.start	= arc_serial_init,
10522a240c3SAlexey Brodkin 	.stop	= NULL,
10622a240c3SAlexey Brodkin 	.setbrg	= arc_serial_setbrg,
10722a240c3SAlexey Brodkin 	.putc	= arc_serial_putc,
10822a240c3SAlexey Brodkin 	.puts	= arc_serial_puts,
10922a240c3SAlexey Brodkin 	.getc	= arc_serial_getc,
11022a240c3SAlexey Brodkin 	.tstc	= arc_serial_tstc,
11122a240c3SAlexey Brodkin };
11222a240c3SAlexey Brodkin 
11322a240c3SAlexey Brodkin void arc_serial_initialize(void)
11422a240c3SAlexey Brodkin {
11522a240c3SAlexey Brodkin 	serial_register(&arc_serial_drv);
11622a240c3SAlexey Brodkin }
11722a240c3SAlexey Brodkin 
11822a240c3SAlexey Brodkin __weak struct serial_device *default_serial_console(void)
11922a240c3SAlexey Brodkin {
12022a240c3SAlexey Brodkin 	return &arc_serial_drv;
12122a240c3SAlexey Brodkin }
122