blob: 4be4c03c00298445d3037592d9471c073c2a448d [file] [log] [blame]
Qiufang Dai141086d2020-05-29 17:16:41 +08001/*
2 * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
3 *
4 * All information contained herein is Amlogic confidential.
5 *
6 * This software is provided to you pursuant to Software License Agreement
7 * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
8 * only in accordance with the terms of this agreement.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification is strictly prohibited without prior written permission from
12 * Amlogic.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27/*
28 * UART driver
29 */
30
Yao Jie99f7bdc2024-10-18 10:37:36 +080031#include "FreeRTOS.h"
32#include "timers.h"
Qiufang Dai141086d2020-05-29 17:16:41 +080033#include "common.h"
bangzheng.liu42627892024-03-25 14:31:19 +080034#include "FreeRTOSConfig.h"
Qiufang Dai141086d2020-05-29 17:16:41 +080035#include "uart.h"
36#include "register.h"
Jianxiong Pan5e711c12020-11-19 13:42:23 +080037#include "soc.h"
Yao Jie99f7bdc2024-10-18 10:37:36 +080038#include "string.h"
39#include "timer_source.h"
Qiufang Dai141086d2020-05-29 17:16:41 +080040
Jianxiong Pan5e711c12020-11-19 13:42:23 +080041//#define UART_PORT_CONS UART_B_WFIFO
Qiufang Dai141086d2020-05-29 17:16:41 +080042
43#define UART_STP_BIT UART_MODE_MASK_STP_1BIT
44#define UART_PRTY_BIT 0
45#define UART_CHAR_LEN UART_MODE_MASK_CHAR_8BIT
46#define UART_MODE_RESET_MASK \
47 (UART_MODE_MASK_RST_TX \
48 | UART_MODE_MASK_RST_RX \
49 | UART_MODE_MASK_CLR_ERR)
50
51#define UART_WFIFO (0<<2)
52#define UART_RFIFO (1<<2)
53#define UART_MODE (2<<2)
54#define UART_STATUS (3<<2)
55#define UART_IRQCTL (4<<2)
56#define UART_CTRL (5<<2)
57#define UART_MODE_MASK_STP_1BIT (0<<16)
58#define UART_MODE_MASK_CHAR_8BIT (0<<20)
59#define UART_MODE_MASK_TX_EN (1<<12)
60#define UART_MODE_MASK_RX_EN (1<<13)
61#define UART_MODE_MASK_RST_TX (1<<22)
62#define UART_MODE_MASK_RST_RX (1<<23)
63#define UART_MODE_MASK_CLR_ERR (1<<24)
64#define UART_CTRL_USE_XTAL_CLK (1<<24)
65#define UART_CTRL_USE_NEW_BAUD_RATE (1<<23)
66
67#define UART_STAT_MASK_RFIFO_FULL (1<<19)
68#define UART_STAT_MASK_RFIFO_EMPTY (1<<20)
69#define UART_STAT_MASK_TFIFO_FULL (1<<21)
70#define UART_STAT_MASK_TFIFO_EMPTY (1<<22)
71
72#define P_UART(uart_base, reg) (uart_base+reg)
73#define P_UART_WFIFO(uart_base) P_UART(uart_base, UART_WFIFO)
74#define P_UART_MODE(uart_base) P_UART(uart_base, UART_MODE)
75#define P_UART_CTRL(uart_base) P_UART(uart_base, UART_CTRL)
76#define P_UART_STATUS(uart_base) P_UART(uart_base, UART_STATUS)
77
Yao Jie99f7bdc2024-10-18 10:37:36 +080078#define UART_TX_BUF_SIZE (512)
79#define POLL_TX_FIFO_PRD (portTICK_PERIOD_MS)
80#define POLL_TX_BUF_PRD (portTICK_PERIOD_MS * 10)
81#define UART_TXBUF_TASK_PRI (3)
82#define UART_TX_FIFO_FULL_WAIT (5000) //us
83
84struct xUartTxBuf_t {
85 char *pcTxBuf;
86 uint32_t ulRdPtr;
87 uint32_t ulWrPtr;
88 uint32_t ulBufCnt;
89 uint32_t ulTimerPeriod;
90 TimerHandle_t xTimer;
91 uint8_t ucWarnMsgPrtEn;
92 uint8_t ucBufReady;
93};
94
95static const char cWarnMsg[] = "\r\nWarning: AOCPU log is lost due to TX FIFO full!\n";
96static struct xUartTxBuf_t xUartTxBuf;
97
bangzheng.liu42627892024-03-25 14:31:19 +080098#ifdef ACS_DIS_PRINT_FLAG
bangzheng.liu5f8b4c92024-02-26 13:38:08 +080099static uint8_t bl30_print_en;
100void enable_bl30_print(uint8_t enable)
101{
102 /* Applied to output important logs */
103 bl30_print_en = enable;
104}
105
bangzheng.liu42627892024-03-25 14:31:19 +0800106#if configSUPPORT_STICK_MEM
107#include "stick_mem.h"
108#include "mailbox-api.h"
bangzheng.liu5f8b4c92024-02-26 13:38:08 +0800109/* Applied to enable or disable bl30 start logs before first
110 * suspend or shutdown when compile with '--noverbose'.
111 */
112static void *xMboxBL30PrintEn(void *msg)
113{
114 stick_mem_write(STICK_BL30_PRINT_EN, *(uint32_t *)msg);
115
116 return NULL;
117}
118
119void vBL30PrintControlInit(void)
120{
121 xInstallRemoteMessageCallbackFeedBack(AOREE_CHANNEL,
122 MBX_CMD_SET_BL30_PRINT, xMboxBL30PrintEn, 0);
123}
124#endif
bangzheng.liu42627892024-03-25 14:31:19 +0800125#endif /* ACS_DIS_PRINT_FLAG */
bangzheng.liu5f8b4c92024-02-26 13:38:08 +0800126
Qiufang Dai141086d2020-05-29 17:16:41 +0800127static int prvUartTxIsFull(void)
128{
129 return REG32(P_UART_STATUS(UART_PORT_CONS)) & UART_STAT_MASK_TFIFO_FULL;
130}
131
132void vUartTxFlush(void)
133{
134 while (!
135 (REG32(P_UART_STATUS(UART_PORT_CONS)) &
136 UART_STAT_MASK_TFIFO_EMPTY));
137}
138
Yao Jie99f7bdc2024-10-18 10:37:36 +0800139static int prvFillTxBuf(char c)
140{
141 char *pcBuf;
142
143 taskENTER_CRITICAL();
144 if (xUartTxBuf.ulBufCnt >= UART_TX_BUF_SIZE) {
145 xUartTxBuf.ucWarnMsgPrtEn = 1;
146 taskEXIT_CRITICAL();
147 return 1;
148 }
149
150 pcBuf = xUartTxBuf.pcTxBuf;
151 pcBuf[xUartTxBuf.ulWrPtr] = c;
152 xUartTxBuf.ulWrPtr++;
153 xUartTxBuf.ulBufCnt++;
154 if (xUartTxBuf.ulWrPtr >= UART_TX_BUF_SIZE)
155 xUartTxBuf.ulWrPtr = 0;
156 taskEXIT_CRITICAL();
157 return 0;
158}
159
160static int prvFillTxBufStr(const char *s)
161{
162 const char *pcChar = s;
163 int iCnt = 0;
164
165 while (*pcChar) {
166 if ('\n' == *pcChar) {
167 prvFillTxBuf('\r');
168 iCnt++;
169 }
170 prvFillTxBuf(*s);
171 iCnt++;
172 pcChar++;
173 }
174
175 return iCnt;
176}
177
178static uint8_t prvChkTxFifoBusy(void)
179{
180 uint8_t ucIsTxBusy = 0;
181 uint32_t time_start;
182 uint32_t time_end;
183 uint32_t time_elapse;
184
185 /* Check if UART TX FIFO is busy */
186 time_start = timere_read_us();
187 while (prvUartTxIsFull()) {
188 time_end = timere_read_us();
189 time_elapse = time_end - time_start;
190 if (time_elapse > UART_TX_FIFO_FULL_WAIT) {
191 ucIsTxBusy = 1;
192 break;
193 }
194 }
195
196 return ucIsTxBusy;
197}
198
Qiufang Dai141086d2020-05-29 17:16:41 +0800199void vUartPutc(const char c)
200{
bangzheng.liu42627892024-03-25 14:31:19 +0800201#ifdef ACS_DIS_PRINT_FLAG
202#if configSUPPORT_STICK_MEM
bangzheng.liu5f8b4c92024-02-26 13:38:08 +0800203 unsigned int stick_mem_bl30_print_en;
204
205 stick_mem_read(STICK_BL30_PRINT_EN, &stick_mem_bl30_print_en);
bangzheng.liu5f8b4c92024-02-26 13:38:08 +0800206#endif
bangzheng.liu42627892024-03-25 14:31:19 +0800207
208 if ((REG32(ACS_DIS_PRINT_REG) & ACS_DIS_PRINT_FLAG) && !bl30_print_en
209#if configSUPPORT_STICK_MEM
210 && (stick_mem_bl30_print_en != STICK_MEM_EN_BL30_PRINT_FLAG)
211#endif
212 )
213 return;
214#endif /* ACS_DIS_PRINT_FLAG */
215
Qiufang Dai141086d2020-05-29 17:16:41 +0800216 if (c == '\n')
217 vUartPutc('\r');
218
219 while (prvUartTxIsFull());
220 REG32(P_UART_WFIFO(UART_PORT_CONS)) = (char)c;
Qiufang Dai141086d2020-05-29 17:16:41 +0800221}
222
223void vUartPuts(const char *s)
224{
Yao Jie99f7bdc2024-10-18 10:37:36 +0800225 uint8_t ucIsTxBusy;
226
227 while (*s) {
228 ucIsTxBusy = prvChkTxFifoBusy();
229 /* If Uart TX FIFO is busy, send string to TX Buffer */
230 if (ucIsTxBusy && xUartTxBuf.ucBufReady) {
231 prvFillTxBufStr(s);
232 break;
233 }
234
235 if (!ucIsTxBusy || !xUartTxBuf.ucBufReady) {
236 vUartPutc(*s);
237 s++;
238 }
239 }
Qiufang Dai141086d2020-05-29 17:16:41 +0800240}
241
242void vUartTxStart(void)
243{
244 /* Do not allow deep sleep while transmit in progress */
245#ifdef CONFIG_LOW_POWER_IDLE
246 disable_sleep(SLEEP_MASK_UART);
247#endif
248
249 //uart_flush_output();
250}
251
252void vUartTxStop(void)
253{
254
255}
256
257long lUartTxReady(void)
258{
259 return !(REG32(P_UART_STATUS(UART_PORT_CONS)) &
260 UART_STAT_MASK_TFIFO_FULL);
261}
262#if 0
263void vUartWriteChar(char c)
264{
265 vUartPutc(c);
266}
267
268int uart_tx_char(int c)
269{
270 vUartPutc(c);
271
272 return c;
273}
274/*print BCD*/
275void print_u32_dec(unsigned int num) {
276 char buf[16];
277 char *s = buf + (sizeof(buf) / sizeof(buf[0])) - 1;
278 char *e = s;
279
280 do {
281 *--s = '0' + num % 10;
282 } while (num /= 10);
283
284 while (s < e)
285 uart_tx_char(*s++);
286}
287
288void serial_put_hex(unsigned long data, unsigned int bitlen)
289{
290 int i;
291 unsigned char s;
292
293 for (i = bitlen - 4; i >= 0; i -= 4)
294 {
295 s = (data >> i) & 0xf;
296 if (s < 10)
297 vUartPutc(0x30 + s);
298 else if (s < 16)
299 vUartPutc(0x61 + s - 10);
300 }
301}
302#endif
303#if 0
304/* Interrupt handler for console UART */
305void uart_interrupt(void)
306{
307 /* Fill output FIFO */
308 uart_process_output();
309}
310
311DECLARE_IRQ(IRQ_AO_UART_NUM, uart_interrupt, 1);
312#endif
313
Yao Jie99f7bdc2024-10-18 10:37:36 +0800314static void prvUartTxBufHandle(TimerHandle_t xTimer)
315{
316 char cTxChar;
317 uint32_t ulIsTxFifoEmpty;
318
319 (void)xTimer;
320 taskENTER_CRITICAL();
321 if (xUartTxBuf.ulBufCnt == 0) {
322 if (xUartTxBuf.ulTimerPeriod != POLL_TX_BUF_PRD) {
323 xUartTxBuf.ulTimerPeriod = POLL_TX_BUF_PRD;
324 xTimerChangePeriod(xUartTxBuf.xTimer, xUartTxBuf.ulTimerPeriod, 0);
325 }
326 ulIsTxFifoEmpty = (REG32(P_UART_STATUS(UART_PORT_CONS)) &
327 UART_STAT_MASK_TFIFO_EMPTY);
328 if (ulIsTxFifoEmpty && xUartTxBuf.ucWarnMsgPrtEn) {
329 xUartTxBuf.ucWarnMsgPrtEn = 0;
330 vUartPuts(cWarnMsg);
331 }
332 } else {
333 if (xUartTxBuf.ulTimerPeriod != POLL_TX_FIFO_PRD) {
334 xUartTxBuf.ulTimerPeriod = POLL_TX_FIFO_PRD;
335 xTimerChangePeriod(xUartTxBuf.xTimer, xUartTxBuf.ulTimerPeriod, 0);
336 }
337 while (xUartTxBuf.ulBufCnt) {
338 cTxChar = xUartTxBuf.pcTxBuf[xUartTxBuf.ulRdPtr];
339 vUartPutc(cTxChar);
340 xUartTxBuf.ulRdPtr++;
341 xUartTxBuf.ulBufCnt--;
342 if (xUartTxBuf.ulRdPtr >= UART_TX_BUF_SIZE)
343 xUartTxBuf.ulRdPtr = 0;
344 }
345 }
346 taskEXIT_CRITICAL();
347}
348
Qiufang Dai141086d2020-05-29 17:16:41 +0800349/*
350 * Set UART to 115200-8-N-1
351 *
352 * Using 24M XTAL as UART reference clock, *NOT* clk81
353 * So the clk81 can be dynamically changed and not
Yao Jie0ba0c412022-09-05 11:11:37 +0800354 * disturb UART transfers.
Qiufang Dai141086d2020-05-29 17:16:41 +0800355 */
356void vUartInit(void)
357{
Yao Jie99f7bdc2024-10-18 10:37:36 +0800358 TimerHandle_t xUartTimer = NULL;
359
360 xUartTxBuf.pcTxBuf = pvPortMalloc(UART_TX_BUF_SIZE);
361 if (xUartTxBuf.pcTxBuf) {
362 memset(xUartTxBuf.pcTxBuf, 0, UART_TX_BUF_SIZE);
363 xUartTimer = xTimerCreate("UartTimer", pdMS_TO_TICKS(POLL_TX_BUF_PRD),
364 pdTRUE, NULL, prvUartTxBufHandle);
365 if (xUartTimer) {
366 xUartTxBuf.ulRdPtr = 0;
367 xUartTxBuf.ulWrPtr = 0;
368 xUartTxBuf.ulBufCnt = 0;
369 xUartTxBuf.ucWarnMsgPrtEn = 0;
370 xUartTxBuf.ucBufReady = 1;
371 xUartTxBuf.xTimer = xUartTimer;
372 xUartTxBuf.ulTimerPeriod = POLL_TX_BUF_PRD;
373 xTimerStart(xUartTxBuf.xTimer, 0);
374 } else {
375 vPortFree(xUartTxBuf.pcTxBuf);
376 vUartPuts("Warning: xUartTimer create fail\n");
377 }
378 }
Qiufang Dai141086d2020-05-29 17:16:41 +0800379}