blob: 4a4702aab80458d25ef553afb4344f2303f43e8d [file] [log] [blame]
Daisuke Nojiri3a2ac882015-02-09 19:39:39 -08001/*
Daisuke Nojiric047b102015-01-23 10:02:24 -08002 * This file is part of the coreboot project.
Daisuke Nojiri3a2ac882015-02-09 19:39:39 -08003 *
Daisuke Nojiric047b102015-01-23 10:02:24 -08004 * Copyright (C) 2000 Rob Taylor, Flying Pig Systems. robt@flyingpig.com.
5 * Copyright (C) Broadcom Corporation
6 * Copyright (C) 2015 Google Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
Daisuke Nojiri3a2ac882015-02-09 19:39:39 -080017 */
18
Daisuke Nojiric047b102015-01-23 10:02:24 -080019#include <arch/io.h>
20#include <boot/coreboot_tables.h>
21#include <console/console.h> /* for __console definition */
22#include <console/uart.h>
23#include <delay.h>
24#include <soc/ns16550.h>
Daisuke Nojiri3a2ac882015-02-09 19:39:39 -080025
Daisuke Nojiric047b102015-01-23 10:02:24 -080026#define SYS_NS16550_CLK 100000000
27#define SYS_NS16550_BAUDRATE 115200
28#define MODE_X_DIV 16
29#define SINGLE_CHAR_TIMEOUT (50 * 1000)
Daisuke Nojiri3a2ac882015-02-09 19:39:39 -080030
Daisuke Nojiric047b102015-01-23 10:02:24 -080031static struct ns16550 * const regs =
32 (void *)CONFIG_CONSOLE_SERIAL_UART_ADDRESS;
Daisuke Nojiri3a2ac882015-02-09 19:39:39 -080033
Daisuke Nojiric047b102015-01-23 10:02:24 -080034static int calc_divisor(void)
Daisuke Nojiri3a2ac882015-02-09 19:39:39 -080035{
Daisuke Nojiri3a2ac882015-02-09 19:39:39 -080036 /* Compute divisor value. Normally, we should simply return:
Daisuke Nojiric047b102015-01-23 10:02:24 -080037 * ns16550_clk / MODE_X_DIV / baudrate
Daisuke Nojiri3a2ac882015-02-09 19:39:39 -080038 * but we need to round that value by adding 0.5.
39 * Rounding is especially important at high baud rates.
40 */
Daisuke Nojiric047b102015-01-23 10:02:24 -080041 int div = MODE_X_DIV * SYS_NS16550_BAUDRATE;
42 return (SYS_NS16550_CLK + div / 2) / div;
Daisuke Nojiri3a2ac882015-02-09 19:39:39 -080043}
44
Daisuke Nojiric047b102015-01-23 10:02:24 -080045static void ns16550_init(void)
Daisuke Nojiri3a2ac882015-02-09 19:39:39 -080046{
Daisuke Nojiric047b102015-01-23 10:02:24 -080047 int baud_divisor = calc_divisor();
Daisuke Nojiri3a2ac882015-02-09 19:39:39 -080048
Patrick Georgi1abb6002015-04-21 09:28:39 +020049 while (!(read32(&regs->lsr) & UART_LSR_TEMT))
Daisuke Nojiric047b102015-01-23 10:02:24 -080050 ;
51
Patrick Georgi1abb6002015-04-21 09:28:39 +020052 write32(&regs->ier, 0);
53 write32(&regs->lcr, UART_LCR_BKSE | UART_LCR_8N1);
54 write32(&regs->dll, 0);
55 write32(&regs->dlm, 0);
56 write32(&regs->lcr, UART_LCR_8N1);
57 write32(&regs->mcr, UART_MCR_DTR | UART_MCR_RTS);
Daisuke Nojiric047b102015-01-23 10:02:24 -080058 /* clear & enable FIFOs */
Patrick Georgi1abb6002015-04-21 09:28:39 +020059 write32(&regs->fcr, UART_FCR_FIFO_EN | UART_FCR_RXSR | UART_FCR_TXSR);
60 write32(&regs->lcr, UART_LCR_BKSE | UART_LCR_8N1);
61 write32(&regs->dll, baud_divisor & 0xff);
62 write32(&regs->dlm, (baud_divisor >> 8) & 0xff);
63 write32(&regs->lcr, UART_LCR_8N1);
Daisuke Nojiri3a2ac882015-02-09 19:39:39 -080064}
65
Daisuke Nojiric047b102015-01-23 10:02:24 -080066static void ns16550_tx_byte(unsigned char data)
Daisuke Nojiri3a2ac882015-02-09 19:39:39 -080067{
Patrick Georgi1abb6002015-04-21 09:28:39 +020068 while ((read32(&regs->lsr) & UART_LSR_THRE) == 0)
Daisuke Nojiric047b102015-01-23 10:02:24 -080069 ;
Patrick Georgi1abb6002015-04-21 09:28:39 +020070 write32(&regs->thr, data);
Daisuke Nojiri3a2ac882015-02-09 19:39:39 -080071}
72
Daisuke Nojiric047b102015-01-23 10:02:24 -080073static void ns16550_tx_flush(void)
Daisuke Nojiri3a2ac882015-02-09 19:39:39 -080074{
Patrick Georgi1abb6002015-04-21 09:28:39 +020075 while (!(read32(&regs->lsr) & UART_LSR_TEMT))
Daisuke Nojiric047b102015-01-23 10:02:24 -080076 ;
Daisuke Nojiri3a2ac882015-02-09 19:39:39 -080077}
78
Daisuke Nojiric047b102015-01-23 10:02:24 -080079static int ns16550_tst_byte(void)
Daisuke Nojiri3a2ac882015-02-09 19:39:39 -080080{
Patrick Georgi1abb6002015-04-21 09:28:39 +020081 return (read32(&regs->lsr) & UART_LSR_DR) != 0;
Daisuke Nojiri3a2ac882015-02-09 19:39:39 -080082}
83
Daisuke Nojiric047b102015-01-23 10:02:24 -080084static unsigned char ns16550_rx_byte(void)
Daisuke Nojiri3a2ac882015-02-09 19:39:39 -080085{
Daisuke Nojiric047b102015-01-23 10:02:24 -080086 unsigned long int i = SINGLE_CHAR_TIMEOUT;
87 while (i-- && !ns16550_tst_byte())
88 udelay(1);
89 if (i)
Patrick Georgi1abb6002015-04-21 09:28:39 +020090 return read32(&regs->rbr);
Daisuke Nojiric047b102015-01-23 10:02:24 -080091 else
92 return 0x0;
Daisuke Nojiri3a2ac882015-02-09 19:39:39 -080093}
94
Daisuke Nojiric047b102015-01-23 10:02:24 -080095void uart_init(int idx)
Daisuke Nojiri3a2ac882015-02-09 19:39:39 -080096{
Daisuke Nojiric047b102015-01-23 10:02:24 -080097 ns16550_init();
Daisuke Nojiri3a2ac882015-02-09 19:39:39 -080098}
99
Daisuke Nojiric047b102015-01-23 10:02:24 -0800100void uart_tx_byte(int idx, unsigned char data)
Daisuke Nojiri3a2ac882015-02-09 19:39:39 -0800101{
Daisuke Nojiric047b102015-01-23 10:02:24 -0800102 ns16550_tx_byte(data);
Daisuke Nojiri3a2ac882015-02-09 19:39:39 -0800103}
104
Daisuke Nojiric047b102015-01-23 10:02:24 -0800105void uart_tx_flush(int idx)
Daisuke Nojiri3a2ac882015-02-09 19:39:39 -0800106{
Daisuke Nojiric047b102015-01-23 10:02:24 -0800107 ns16550_tx_flush();
Daisuke Nojiri3a2ac882015-02-09 19:39:39 -0800108}
109
Daisuke Nojiric047b102015-01-23 10:02:24 -0800110unsigned char uart_rx_byte(int idx)
Daisuke Nojiri3a2ac882015-02-09 19:39:39 -0800111{
Daisuke Nojiric047b102015-01-23 10:02:24 -0800112 return ns16550_rx_byte();
Daisuke Nojiri3a2ac882015-02-09 19:39:39 -0800113}
114
Daisuke Nojiric047b102015-01-23 10:02:24 -0800115#ifndef __PRE_RAM__
116void uart_fill_lb(void *data)
Daisuke Nojiri3a2ac882015-02-09 19:39:39 -0800117{
Daisuke Nojiric047b102015-01-23 10:02:24 -0800118 struct lb_serial serial;
119 serial.type = LB_SERIAL_TYPE_MEMORY_MAPPED;
120 serial.baseaddr = (uintptr_t)regs;
121 serial.baud = default_baudrate();
122 serial.regwidth = 1;
123 lb_add_serial(&serial, data);
Daisuke Nojiri3a2ac882015-02-09 19:39:39 -0800124
Daisuke Nojiric047b102015-01-23 10:02:24 -0800125 lb_add_console(LB_TAG_CONSOLE_SERIAL8250MEM, data);
Daisuke Nojiri3a2ac882015-02-09 19:39:39 -0800126}
Daisuke Nojiri3a2ac882015-02-09 19:39:39 -0800127#endif