blob: 01759fe57392bea6a335fbe0d7f4b7a5082e3fcb [file] [log] [blame]
jinkun.hongac490b82014-06-22 20:40:39 -07001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright 2014 Rockchip Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
jinkun.hongac490b82014-06-22 20:40:39 -070020#include <arch/io.h>
21#include <boot/coreboot_tables.h>
22#include <console/console.h> /* for __console definition */
Julius Werner7a453eb2014-10-20 13:14:55 -070023#include <console/uart.h>
jinkun.hongac490b82014-06-22 20:40:39 -070024#include <drivers/uart/uart8250reg.h>
Julius Werner7a453eb2014-10-20 13:14:55 -070025#include <stdint.h>
jinkun.hongac490b82014-06-22 20:40:39 -070026
27/*
28 * TODO: Use DRIVERS_UART_8250MEM driver instead.
29 * There is an issue in the IO call functions where x86 and ARM
30 * ordering is reversed. This 8250MEM driver uses the x86 convention.
31 * This driver can be replaced once the IO calls are sorted.
32 */
33
34struct rk3288_uart {
35 union {
36 uint32_t thr; /* Transmit holding register. */
37 uint32_t rbr; /* Receive buffer register. */
38 uint32_t dll; /* Divisor latch lsb. */
39 };
40 union {
41 uint32_t ier; /* Interrupt enable register. */
42 uint32_t dlm; /* Divisor latch msb. */
43 };
44 union {
45 uint32_t iir; /* Interrupt identification register. */
46 uint32_t fcr; /* FIFO control register. */
47 };
48 uint32_t lcr; /* Line control register. */
49 uint32_t mcr; /* Modem control register. */
50 uint32_t lsr; /* Line status register. */
51 uint32_t msr; /* Modem status register. */
52 uint32_t scr;
53 uint32_t reserved1[(0x30 - 0x20) / 4];
54 uint32_t srbr[(0x70 - 0x30) / 4];
55 uint32_t far;
56 uint32_t tfr;
57 uint32_t rfw;
58 uint32_t usr;
59 uint32_t tfl;
60 uint32_t rfl;
61 uint32_t srr;
62 uint32_t srts;
63 uint32_t sbcr;
64 uint32_t sdmam;
65 uint32_t sfe;
66 uint32_t srt;
67 uint32_t stet;
68 uint32_t htx;
69 uint32_t dmasa;
70 uint32_t reserver2[(0xf4 - 0xac) / 4];
71 uint32_t cpr;
72 uint32_t ucv;
73 uint32_t ctr;
74} __attribute__ ((packed));
75
76
77static struct rk3288_uart * const uart_ptr =
78 (void *)CONFIG_CONSOLE_SERIAL_UART_ADDRESS;
79
80static void rk3288_uart_tx_flush(void);
81static int rk3288_uart_tst_byte(void);
82
83static void rk3288_uart_init(void)
84{
85 /* FIXME: Use a hardcoded divisor for now.
86 * uint16_t divisor = (u16) uart_baudrate_divisor(default_baudrate(),
87 * uart_platform_refclk(), 16)
88 */
89 const unsigned divisor = 13;
90 const uint8_t line_config = UART8250_LCR_WLS_8; // 8n1
91
92 rk3288_uart_tx_flush();
93
94 // Disable interrupts.
95 writel(0, &uart_ptr->ier);
96 // Force DTR and RTS to high.
97 writel(UART8250_MCR_DTR | UART8250_MCR_RTS, &uart_ptr->mcr);
98 // Set line configuration, access divisor latches.
99 writel(UART8250_LCR_DLAB | line_config, &uart_ptr->lcr);
100 // Set the divisor.
101 writel(divisor & 0xff, &uart_ptr->dll);
102 writel((divisor >> 8) & 0xff, &uart_ptr->dlm);
103 // Hide the divisor latches.
104 writel(line_config, &uart_ptr->lcr);
105 // Enable FIFOs, and clear receive and transmit.
106 writel(UART8250_FCR_FIFO_EN |
107 UART8250_FCR_CLEAR_RCVR |
108 UART8250_FCR_CLEAR_XMIT, &uart_ptr->fcr);
109}
110
111static void rk3288_uart_tx_byte(unsigned char data)
112{
113 while (!(readl(&uart_ptr->lsr) & UART8250_LSR_THRE));
114 writel(data, &uart_ptr->thr);
115}
116
117static void rk3288_uart_tx_flush(void)
118{
119 while (!(readl(&uart_ptr->lsr) & UART8250_LSR_TEMT));
120}
121
122static unsigned char rk3288_uart_rx_byte(void)
123{
124 if (!rk3288_uart_tst_byte())
125 return 0;
126 return readl(&uart_ptr->rbr);
127}
128
129static int rk3288_uart_tst_byte(void)
130{
131 return (readl(&uart_ptr->lsr) & UART8250_LSR_DR) == UART8250_LSR_DR;
132}
133
134
135
136void uart_init(int idx)
137{
138 rk3288_uart_init();
139}
140
141unsigned char uart_rx_byte(int idx)
142{
143 return rk3288_uart_rx_byte();
144}
145
146void uart_tx_byte(int idx, unsigned char data)
147{
148 rk3288_uart_tx_byte(data);
149}
150
151void uart_tx_flush(int idx)
152{
153 rk3288_uart_tx_flush();
154}
155
156#ifndef __PRE_RAM__
157void uart_fill_lb(void *data)
158{
159 struct lb_serial serial;
160 serial.type = LB_SERIAL_TYPE_MEMORY_MAPPED;
161 serial.baseaddr = CONFIG_CONSOLE_SERIAL_UART_ADDRESS;
162 serial.baud = default_baudrate();
163 lb_add_serial(&serial, data);
164
165 lb_add_console(LB_TAG_CONSOLE_SERIAL8250MEM, data);
166}
167#endif