blob: 79ca07230f0b2d2cef62fa4d86d2a5d3c02610e9 [file] [log] [blame]
Angel Ponse67ab182020-04-04 18:51:11 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Yidi Lin3d7b6062015-07-31 17:10:40 +08002
Kyösti Mälkki13f66502019-03-03 08:01:05 +02003#include <device/mmio.h>
Yidi Lin3d7b6062015-07-31 17:10:40 +08004#include <boot/coreboot_tables.h>
Yidi Lin3d7b6062015-07-31 17:10:40 +08005#include <console/uart.h>
6#include <drivers/uart/uart8250reg.h>
7#include <stdint.h>
8
9#include <soc/addressmap.h>
Tristan Shiehe13a65c2019-07-10 15:02:39 +080010#include <soc/pll.h>
Yidi Lin3d7b6062015-07-31 17:10:40 +080011
12struct mtk_uart {
13 union {
14 uint32_t thr; /* Transmit holding register. */
15 uint32_t rbr; /* Receive buffer register. */
16 uint32_t dll; /* Divisor latch lsb. */
17 };
18 union {
19 uint32_t ier; /* Interrupt enable register. */
20 uint32_t dlm; /* Divisor latch msb. */
21 };
22 union {
23 uint32_t iir; /* Interrupt identification register. */
24 uint32_t fcr; /* FIFO control register. */
25 uint32_t efr; /* Enhanced feature register. */
26 };
27 uint32_t lcr; /* Line control register. */
28 union {
29 uint32_t mcr; /* Modem control register. */
30 uint32_t xn1; /* XON1 */
31 };
32 union {
33 uint32_t lsr; /* Line status register. */
34 uint32_t xn2; /* XON2 */
35 };
36 union {
37 uint32_t msr; /* Modem status register. */
38 uint32_t xf1; /* XOFF1 */
39 };
40 union {
41 uint32_t scr; /* Scratch register. */
42 uint32_t xf2; /* XOFF2 */
43 };
44 uint32_t autobaud_en; /* Enable auto baudrate. */
45 uint32_t highspeed; /* High speed UART. */
Stefan Reinauer6a001132017-07-13 02:20:27 +020046} __packed;
Yidi Lin3d7b6062015-07-31 17:10:40 +080047
48/* Peripheral Reset and Power Down registers */
49struct mtk_peri_globalcon {
50 uint32_t rst0;
51 uint32_t rst1;
52 uint32_t pdn0_set;
53 uint32_t pdn1_set;
54 uint32_t pdn0_clr;
55 uint32_t pdn1_clr;
56 uint32_t pdn0_sta;
57 uint32_t pdn1_sta;
58 uint32_t pdn_md1_set;
59 uint32_t pdn_md2_set;
60 uint32_t pdn_md1_clr;
61 uint32_t pdn_md2_clr;
62 uint32_t pdn_md1_sta;
63 uint32_t pdn_md2_sta;
64 uint32_t pdn_md_mask;
Stefan Reinauer6a001132017-07-13 02:20:27 +020065} __packed;
Yidi Lin3d7b6062015-07-31 17:10:40 +080066
67static struct mtk_uart *const uart_ptr = (void *)UART0_BASE;
68
69static void mtk_uart_tx_flush(void);
70static int mtk_uart_tst_byte(void);
71
72static void mtk_uart_init(void)
73{
74 /* Use a hardcoded divisor for now. */
Tristan Shiehe13a65c2019-07-10 15:02:39 +080075 const unsigned int uartclk = UART_HZ;
Tristan Shiehf42db112018-06-06 12:52:20 +080076 const unsigned int baudrate = get_uart_baudrate();
77 const uint8_t line_config = UART8250_LCR_WLS_8; /* 8n1 */
78 unsigned int highspeed, quot, divisor, remainder;
Yidi Lin3d7b6062015-07-31 17:10:40 +080079
80 if (baudrate <= 115200) {
81 highspeed = 0;
82 quot = 16;
83 } else {
84 highspeed = 2;
85 quot = 4;
86 }
87
88 /* Set divisor DLL and DLH */
89 divisor = uartclk / (quot * baudrate);
90 remainder = uartclk % (quot * baudrate);
91
92 if (remainder >= (quot / 2) * baudrate)
93 divisor += 1;
94
95 mtk_uart_tx_flush();
96
97 /* Disable interrupts. */
98 write8(&uart_ptr->ier, 0);
99 /* Force DTR and RTS to high. */
100 write8(&uart_ptr->mcr, UART8250_MCR_DTR | UART8250_MCR_RTS);
101 /* Set High speed UART register. */
102 write8(&uart_ptr->highspeed, highspeed);
103 /* Set line configuration, access divisor latches. */
104 write8(&uart_ptr->lcr, UART8250_LCR_DLAB | line_config);
105 /* Set the divisor. */
106 write8(&uart_ptr->dll, divisor & 0xff);
107 write8(&uart_ptr->dlm, (divisor >> 8) & 0xff);
108 /* Hide the divisor latches. */
109 write8(&uart_ptr->lcr, line_config);
110 /* Enable FIFOs, and clear receive and transmit. */
111 write8(&uart_ptr->fcr,
112 UART8250_FCR_FIFO_EN | UART8250_FCR_CLEAR_RCVR |
Tristan Shiehf42db112018-06-06 12:52:20 +0800113 UART8250_FCR_CLEAR_XMIT);
Yidi Lin3d7b6062015-07-31 17:10:40 +0800114
115}
116
117static void mtk_uart_tx_byte(unsigned char data)
118{
Tristan Shiehf42db112018-06-06 12:52:20 +0800119 while (!(read8(&uart_ptr->lsr) & UART8250_LSR_THRE))
120 ;
Yidi Lin3d7b6062015-07-31 17:10:40 +0800121 write8(&uart_ptr->thr, data);
122}
123
124static void mtk_uart_tx_flush(void)
125{
Tristan Shiehf42db112018-06-06 12:52:20 +0800126 while (!(read8(&uart_ptr->lsr) & UART8250_LSR_TEMT))
127 ;
Yidi Lin3d7b6062015-07-31 17:10:40 +0800128}
129
130static unsigned char mtk_uart_rx_byte(void)
131{
132 if (!mtk_uart_tst_byte())
133 return 0;
134 return read8(&uart_ptr->rbr);
135}
136
137static int mtk_uart_tst_byte(void)
138{
139 return (read8(&uart_ptr->lsr) & UART8250_LSR_DR) == UART8250_LSR_DR;
140}
141
Felix Helde3a12472020-09-11 15:47:09 +0200142void uart_init(unsigned int idx)
Yidi Lin3d7b6062015-07-31 17:10:40 +0800143{
144 mtk_uart_init();
145}
146
Felix Helde3a12472020-09-11 15:47:09 +0200147unsigned char uart_rx_byte(unsigned int idx)
Yidi Lin3d7b6062015-07-31 17:10:40 +0800148{
149 return mtk_uart_rx_byte();
150}
151
Felix Helde3a12472020-09-11 15:47:09 +0200152void uart_tx_byte(unsigned int idx, unsigned char data)
Yidi Lin3d7b6062015-07-31 17:10:40 +0800153{
154 mtk_uart_tx_byte(data);
155}
156
Felix Helde3a12472020-09-11 15:47:09 +0200157void uart_tx_flush(unsigned int idx)
Yidi Lin3d7b6062015-07-31 17:10:40 +0800158{
159 mtk_uart_tx_flush();
160}
161
Arthur Heymans9948c522022-10-24 14:37:40 +0200162enum cb_err fill_lb_serial(struct lb_serial *serial)
Yidi Lin3d7b6062015-07-31 17:10:40 +0800163{
Arthur Heymans9948c522022-10-24 14:37:40 +0200164 serial->type = LB_SERIAL_TYPE_MEMORY_MAPPED;
165 serial->baseaddr = UART0_BASE;
166 serial->baud = get_uart_baudrate();
167 serial->regwidth = 4;
168 serial->input_hertz = UART_HZ;
Yidi Lin3d7b6062015-07-31 17:10:40 +0800169
Arthur Heymans9948c522022-10-24 14:37:40 +0200170 return CB_SUCCESS;
Yidi Lin3d7b6062015-07-31 17:10:40 +0800171}