1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-11-16 GuEe-GUI first version
*/
#include "8250.h"
struct serial8250 early_serial8250 = { 0 };
static rt_uint32_t serial8250_early_in(struct serial8250 *serial, int offset)
{
return serial8250_in(serial, offset);
}
static void serial8250_early_out(struct serial8250 *serial, int offset, int value)
{
serial8250_out(serial, offset, value);
}
int serial8250_early_putc(struct rt_serial_device *raw_serial, char c)
{
if (raw_serial)
{
/* FIFO and shifting register empty */
const int uart_lsr_both_empty = (UART_LSR_TEMT | UART_LSR_THRE);
struct serial8250 *serial = rt_container_of(raw_serial, struct serial8250, parent);
serial8250_early_out(serial, UART_TX, c);
while ((serial8250_early_in(serial, UART_LSR) & uart_lsr_both_empty) != uart_lsr_both_empty)
{
rt_hw_cpu_relax();
}
}
return 1;
}
static void init_serial(struct serial8250 *serial)
{
unsigned char c;
rt_uint32_t ier, divisor;
serial8250_early_out(serial, UART_LCR, 0x3); /* 8n1 */
ier = serial8250_early_in(serial, UART_IER);
serial8250_early_out(serial, UART_IER, ier & UART_IER_UUE); /* No interrupt */
serial8250_early_out(serial, UART_FCR, 0); /* No fifo */
serial8250_early_out(serial, UART_MCR, 0x3); /* DTR + RTS */
if (serial->freq)
{
divisor = RT_DIV_ROUND_CLOSEST(serial->freq, 16 * serial->parent.config.baud_rate);
c = serial8250_early_in(serial, UART_LCR);
serial8250_early_out(serial, UART_LCR, c | UART_LCR_DLAB);
serial8250_early_out(serial, UART_DLL, divisor & 0xff);
serial8250_early_out(serial, UART_DLM, (divisor >> 8) & 0xff);
serial8250_early_out(serial, UART_LCR, c & ~UART_LCR_DLAB);
}
}
static void serial8250_early_kick(struct rt_fdt_earlycon *con, int why)
{
struct serial8250 *serial = raw_to_serial8250(con->data);
switch (why)
{
case FDT_EARLYCON_KICK_UPDATE:
serial->base = rt_ioremap((void *)con->mmio, con->size);
break;
case FDT_EARLYCON_KICK_COMPLETED:
rt_iounmap(serial->base);
break;
default:
break;
}
}
rt_err_t serial8250_early_fdt_setup(struct serial8250 *serial, struct rt_fdt_earlycon *con, const char *options)
{
rt_err_t ret = RT_EOK;
if (!serial->base && con)
{
serial8250_config(serial, options);
con->mmio = (rt_ubase_t)serial->base;
con->size = serial->size;
}
if (serial->base && con)
{
serial->base = rt_ioremap_early((void *)serial->base, serial->size);
}
if (serial->base && con)
{
con->console_putc = (typeof(con->console_putc))&serial8250_early_putc;
con->console_kick = serial8250_early_kick;
con->data = &serial->parent;
if (!serial->parent.config.baud_rate)
{
/* Assume the device was initialized, only mask interrupts */
rt_uint32_t ier = serial8250_early_in(serial, UART_IER);
serial8250_early_out(serial, UART_IER, ier & UART_IER_UUE);
}
else
{
init_serial(serial);
}
}
else
{
ret = -RT_ERROR;
}
return ret;
}
static void common_init(struct serial8250 *serial, struct rt_fdt_earlycon *con)
{
serial->base = (void *)con->mmio;
serial->size = con->size;
serial->iotype = PORT_MMIO32;
}
static rt_err_t common_early_setup(struct rt_fdt_earlycon *con, const char *options)
{
struct serial8250 *serial = &early_serial8250;
common_init(serial, con);
serial->regshift = 2;
fdt_getprop_u32(con->fdt, con->nodeoffset, "reg-shift", &serial->regshift, RT_NULL);
return serial8250_early_fdt_setup(serial, con, options);
}
RT_FDT_EARLYCON_EXPORT(bcm2835aux, "uart8250", "brcm,bcm2835-aux-uart", common_early_setup);
RT_FDT_EARLYCON_EXPORT(tegra20, "uart8250", "nvidia,tegra20-uart", common_early_setup);
RT_FDT_EARLYCON_EXPORT(dw8250, "uart8250", "snps,dw-apb-uart", common_early_setup);
RT_FDT_EARLYCON_EXPORT(ns16550a, "uart8250", "ns16550a", common_early_setup);
RT_FDT_EARLYCON_EXPORT(ns16550, "uart8250", "ns16550", common_early_setup);
#ifdef RT_USING_8250_OMAP
static rt_err_t omap8250_early_setup(struct rt_fdt_earlycon *con, const char *options)
{
struct serial8250 *serial = &early_serial8250;
common_init(serial, con);
serial->regshift = 2;
return serial8250_early_fdt_setup(serial, con, options);
}
RT_FDT_EARLYCON_EXPORT(omap8250, "uart8250", "ti,omap2-uart", omap8250_early_setup);
RT_FDT_EARLYCON_EXPORT(omap8250, "uart8250", "ti,omap3-uart", omap8250_early_setup);
RT_FDT_EARLYCON_EXPORT(omap8250, "uart8250", "ti,omap4-uart", omap8250_early_setup);
#endif /* RT_USING_8250_OMAP */
|