huangcm
2025-07-03 a76b2fadf6ad4adf86e241e3753a63efe03ef80c
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
/*
 * drivers/uart/uart.c
 *
 * Copyright (C) 2012-2016 AllWinnertech Ltd.
 * Author: Sunny <Sunny@allwinnertech.com>
 *
 */
#include "uart_i.h"
 
volatile u32 uart_pin_not_used = 1;
volatile u32 uart_lock = 1;
volatile static u32 uart_rate;
 
#define IS_TX_FIFO_EMPTY  (readl(UART_REG_USR) & (0x1 << 2))
 
s32 uart_clkchangecb(u32 command, u32 freq)
{
   if (uart_pin_not_used)
       return -EACCES;
 
   switch (command) {
   case CCU_CLK_CLKCHG_REQ:
       {
           /* clock will be change */
           INF("uart source clock change request\n");
           /* wait uart transmit fifo empty */
           while (!IS_TX_FIFO_EMPTY)
               continue;
           /* lock uart */
           uart_lock = 1;
           return OK;
       }
   case CCU_CLK_CLKCHG_DONE:
       {
           /* reconfig uart current baudrate */
           uart_set_baudrate(uart_rate);
           uart_lock = 0;
           INF("uart buadrate change done\n");
           return OK;
       }
   }
 
   return -ESRCH;
}
 
/*
 * uart_init() - initialize uart.
 *
 * @return: OK if initialize uart succeeded, others if failed.
 * @note: initialize uart.
 */
s32 uart_init(void)
{
   u32 div;
   u32 lcr;
   u32 apb0_clk;
 
   /* uart_pin_not_used may parse from dts */
   uart_pin_not_used = 0;
   if (uart_pin_not_used)
       return -EACCES;
 
   uart_rate = UART_BAUDRATE;
#ifndef CFG_FPGA_PLATFORM
   pin_set_multi_sel(PIN_GRP_PL, 2, 2);
   pin_set_multi_sel(PIN_GRP_PL, 3, 2);
   /* set reset as assert state. */
   ccu_set_mclk_reset(CCU_MOD_CLK_R_UART, CCU_CLK_NRESET),
 
   /* set uart clock, open apb0 uart gating. */
   ccu_set_mclk_onoff(CCU_MOD_CLK_R_UART, CCU_CLK_ON);
 
   /* the baud rate divisor */
   apb0_clk = ccu_get_sclk_freq(CCU_SYS_CLK_APBS2);
   div = (apb0_clk + (uart_rate << 3)) / (uart_rate << 4);
#else
   /* set reset as assert state. */
   ccu_set_mclk_reset(CCU_MOD_CLK_R_UART, CCU_CLK_NRESET),
   /* set uart clock, open apb0 uart gating. */
   ccu_set_mclk_onoff(CCU_MOD_CLK_R_UART, CCU_CLK_ON);
   apb0_clk = 24000000;
   div = (apb0_clk + (uart_rate << 3)) / (uart_rate << 4);
 
   pin_set_multi_sel(PIN_GRP_PL, 2, 2);
   pin_set_multi_sel(PIN_GRP_PL, 3, 2);
#endif
 
   /* initialize uart controller */
   lcr = readl(UART_REG_LCR);
   writel(lcr | 0x80, UART_REG_LCR);  /* select the Divsor Latch Low Register and Divsor Latch High Register */
   writel(div & 0xff, UART_REG_DLL);
   writel((div >> 8) & 0xff, UART_REG_DLH);
#ifdef CFG_SHELL_USED
   writel(lcr & (~0x80), UART_REG_LCR);
#endif
   writel(0, UART_REG_HALT);
   writel(3, UART_REG_LCR);           /* set mode, 8bit charset */
   writel(7, UART_REG_FCR);           /* enable and reset transmit/receive fifo */
#ifdef CFG_SHELL_USED
   writel(1, UART_REG_IER);       /* enable receiver interrupt */
#endif
   /* ensure uart is unlock */
   uart_lock = 0;
 
   /* uart initialize succeeded */
   return OK;
}
 
/*
 * uart_putc() - exit uart.
 *
 * @return: OK if exit uart succeeded, others if failed.
 * @note: exit uart.
 */
s32 uart_exit(void)
{
   uart_lock = 1;
   uart_pin_not_used = 1;
 
   pin_set_multi_sel(PIN_GRP_PL, 2, 7);
   pin_set_multi_sel(PIN_GRP_PL, 3, 7);
 
   /* set uart clock, open apb0 uart gating. */
   ccu_set_mclk_onoff(CCU_MOD_CLK_R_UART, CCU_CLK_OFF);
 
   /* set reset as assert state. */
   ccu_set_mclk_reset(CCU_MOD_CLK_R_UART, CCU_CLK_RESET);
 
   return OK;
}
 
/*
 * uart_putc() - put out a charset.
 *
 * @ch: the charset which we want to put out.
 * @return: OK if put out charset succeeded, others if failed.
 * @note: put out a charset.
 */
s32 uart_putc(char ch)
{
   if (uart_lock || uart_pin_not_used)
       return -EACCES;
 
   while (!(readl(UART_REG_USR) & 2)) /* fifo is full, check again */
       ;
 
   /* write out charset to transmit fifo */
   writel(ch, UART_REG_THR);
 
   return OK;
}
 
/*
 * uart_getc() - get a charset.
 *
 * @return: the charset we read from uart.
 * @note: get a charset.
 */
u32 uart_get(char *buf)
{
   u32 count = 0;
 
   if (uart_lock || uart_pin_not_used)
       return -EACCES;
 
   while (readl(UART_REG_RFL)) {
       *buf++ = (char)(readl(UART_REG_RBR) & 0xff);
       count++;
   }
 
   return count;
}
 
/*
 * uart_puts() - put out a string.
 *
 * @string: the string which we want to put out.
 * @return: OK if put out string succeeded, others if failed.
 * @note: put out a string.
 */
s32 uart_puts(const char *string)
{
   if (uart_lock || uart_pin_not_used)
       return -EACCES;
 
   ASSERT(string != NULL);
 
   while (*string != '\0') {
       if (*string == '\n') /* if current character is '\n', insert output with '\r' */
           uart_putc('\r');
       uart_putc(*string++);
   }
 
   return OK;
}
 
s32 uart_set_baudrate(u32 rate)
{
   u32 freq;
   u32 div;
   u32 lcr;
   u32 halt;
 
   if (uart_pin_not_used)
       return -EACCES;
 
   /* update current uart baudrate */
   LOG("uart buadrate change from [%d] to [%d]\n", uart_rate, rate);
   uart_rate = rate;
 
   /* wait uart transmit fifo empty */
   while (readl(UART_REG_TFL))
       continue;
 
   /* reconfig uart baudrate */
#ifdef CFG_FPGA_PLATFORM
   freq = 24000000;
#else
   freq = ccu_get_sclk_freq(CCU_SYS_CLK_APBS2);
#endif
   div  = (freq + (uart_rate << 3)) / (uart_rate << 4);
   lcr  = readl(UART_REG_LCR);
 
   if (div == 0) /* avoid config invalid value */
       div = 1;
 
   /* enable change when busy */
   halt = readl(UART_REG_HALT) | 0x2;
   writel(halt, UART_REG_HALT);
 
   /* select the divsor latch low register and divsor latch high register */
   writel(lcr | 0x80, UART_REG_LCR);
 
   /* set divsor of uart */
   writel(div & 0xff, UART_REG_DLL);
   writel((div >> 8) & 0xff, UART_REG_DLH);
 
   /* unselect the divsor latch low register and divsor latch high register */
   writel(lcr & (~0x80), UART_REG_LCR);
 
   /* update baudrate */
   halt = readl(UART_REG_HALT) | 0x4;
   writel(halt, UART_REG_HALT);
 
   /* waiting update */
   while (readl(UART_REG_HALT) & 0x4)
       continue;
 
   /* disable change when busy */
   halt = readl(UART_REG_HALT) | 0x4;
   writel(halt & (~0x2), UART_REG_HALT);
 
   return OK;
}
 
u32 uart_get_baudrate(void)
{
   return uart_rate;
}