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, ®s->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, ®s->baudh); 541d568c76SAlexey Brodkin else 55*94b5400eSAlexey Brodkin writeb(1, ®s->baudh); 561d568c76SAlexey Brodkin #else 57*94b5400eSAlexey Brodkin writeb((arc_console_baud & 0xff00) >> 8, ®s->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(®s->status) & UART_TXEMPTY)) 7422a240c3SAlexey Brodkin ; 7522a240c3SAlexey Brodkin 76*94b5400eSAlexey Brodkin writeb(c, ®s->data); 7722a240c3SAlexey Brodkin } 7822a240c3SAlexey Brodkin 7922a240c3SAlexey Brodkin static int arc_serial_tstc(void) 8022a240c3SAlexey Brodkin { 81*94b5400eSAlexey Brodkin return !(readb(®s->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(®s->status) & UART_OVERFLOW_ERR) 9122a240c3SAlexey Brodkin return 0; 9222a240c3SAlexey Brodkin 93*94b5400eSAlexey Brodkin return readb(®s->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