286 lines
7.0 KiB
C
286 lines
7.0 KiB
C
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
/*
|
|
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
|
|
*/
|
|
/*
|
|
* Copyright (C) 2014-2017 Amlogic, Inc. All rights reserved.
|
|
*
|
|
* All information contained herein is Amlogic confidential.
|
|
*
|
|
* This software is provided to you pursuant to Software License Agreement
|
|
* (SLA) with Amlogic Inc ("Amlogic"). This software may be used
|
|
* only in accordance with the terms of this agreement.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification is strictly prohibited without prior written permission from
|
|
* Amlogic.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <serial.h>
|
|
#include <io.h>
|
|
#include <stdint.h>
|
|
#include "platform_def.h"
|
|
#include "regs.h"
|
|
#include "register.h"
|
|
|
|
static int g_serial_disable;
|
|
|
|
int serial_disable(void)
|
|
{
|
|
g_serial_disable = 1;
|
|
return 0;
|
|
}
|
|
|
|
void __attribute__((weak)) plat_serial_setup(void)
|
|
{
|
|
serial_init(0);
|
|
}
|
|
|
|
int serial_tx_is_empty(void)
|
|
{
|
|
return (readl(P_UART_STATUS(UART_PORT_CONS)) & UART_STAT_MASK_TFIFO_EMPTY);
|
|
}
|
|
|
|
void serial_init(unsigned set)
|
|
{
|
|
/*
|
|
* Set UART MODE:
|
|
*
|
|
* - Stop bit = 1 bit
|
|
* - Parity check = disable
|
|
* - Character lengther = 8bit
|
|
* - TX, RX enable
|
|
* - Hold reset signals
|
|
*/
|
|
writel(0 | UART_STP_BIT | UART_PRTY_BIT | UART_CHAR_LEN
|
|
| UART_MODE_MASK_TX_EN | UART_MODE_MASK_RX_EN
|
|
| UART_MODE_RESET_MASK | UART_MODE_MASK_TWO_WIRE
|
|
, P_UART_MODE(UART_PORT_CONS));
|
|
|
|
if (set == 1) {
|
|
/*
|
|
* Set UART Baud rate = 115200
|
|
* - Use 24M XTAL clock /2 as ref clock
|
|
* - Enable New baud rete setting
|
|
* - XTAL clock sel = XTAL / 2
|
|
* - 104 = (24,000,000 / 2) / 115200 (Error = +0.16%)
|
|
*/
|
|
writel(readl(REG_MDUMP_TIMEBASE_CNTL) | BIT(0), REG_MDUMP_TIMEBASE_CNTL);
|
|
writel(104 | UART_CTRL_USE_XTAL_CLK | UART_CTRL_USE_NEW_BAUD_RATE
|
|
| UART_CTRL_XTAL_CLK_DIV2
|
|
, P_UART_CTRL(UART_PORT_CONS));
|
|
} else {
|
|
/*
|
|
* Set UART Baud rate = 921600
|
|
* - Use 24M XTAL clock /2 as ref clock
|
|
* - Enable New baud rete setting
|
|
* - XTAL clock sel = XTAL (1)
|
|
* - 13 = 12,000,000 / 921600 (Error = +0.16%)
|
|
*/
|
|
writel(readl(REG_MDUMP_TIMEBASE_CNTL) | BIT(0), REG_MDUMP_TIMEBASE_CNTL);
|
|
writel(13 | UART_CTRL_USE_XTAL_CLK | UART_CTRL_USE_NEW_BAUD_RATE
|
|
| UART_CTRL_XTAL_CLK_DIV2
|
|
, P_UART_CTRL(UART_PORT_CONS));
|
|
}
|
|
|
|
/*
|
|
* Enable pinmux
|
|
*/
|
|
setbits_le32(REG_MDUMP_SERIAL_PINMUX, 0x11);
|
|
|
|
/*
|
|
* Release UART reset signals, enable UART
|
|
*/
|
|
clrbits_le32(P_UART_MODE(UART_PORT_CONS), UART_MODE_RESET_MASK);
|
|
}
|
|
|
|
/*
|
|
* Read a single byte from the serial port. Returns 1 on success, 0
|
|
* otherwise 0.
|
|
*/
|
|
int serial_tstc(void)
|
|
{
|
|
return (readl(P_UART_STATUS(UART_PORT_CONS)) & UART_STAT_MASK_RFIFO_CNT);
|
|
}
|
|
|
|
int serial_putc(int c)
|
|
{
|
|
if (0)
|
|
return c;
|
|
|
|
if (readl(SYSCTRL_SEC_STATUS_REG4) & ACS_DIS_PRINT_FLAG)
|
|
return c;
|
|
|
|
if (c == '\n') {
|
|
while ((readl(P_UART_STATUS(UART_PORT_CONS)) & UART_STAT_MASK_TFIFO_FULL)) {
|
|
};
|
|
writel('\r', P_UART_WFIFO(UART_PORT_CONS));
|
|
}
|
|
|
|
/* Wait till dataTx register is not full */
|
|
while ((readl(P_UART_STATUS(UART_PORT_CONS)) & UART_STAT_MASK_TFIFO_FULL)) {
|
|
};
|
|
writel(c, P_UART_WFIFO(UART_PORT_CONS));
|
|
|
|
/* Wait till dataTx register is empty */
|
|
return c;
|
|
}
|
|
|
|
int serial_getc(void)
|
|
{
|
|
unsigned char ch = 0;
|
|
|
|
if (g_serial_disable)
|
|
return ch;
|
|
|
|
/* Wait till character is placed in fifo */
|
|
while ((readl(P_UART_STATUS(UART_PORT_CONS)) & UART_STAT_MASK_RFIFO_CNT) == 0) {
|
|
};
|
|
|
|
/* Also check for overflow errors */
|
|
if (readl(P_UART_STATUS(UART_PORT_CONS)) &
|
|
(UART_STAT_MASK_PRTY_ERR | UART_STAT_MASK_FRAM_ERR)) {
|
|
setbits_le32(P_UART_CONTROL(UART_PORT_CONS), UART_CNTL_MASK_CLR_ERR);
|
|
clrbits_le32(P_UART_CONTROL(UART_PORT_CONS), UART_CNTL_MASK_CLR_ERR);
|
|
}
|
|
|
|
ch = readl(P_UART_RFIFO(UART_PORT_CONS)) & 0x00ff;
|
|
return ((int)ch);
|
|
}
|
|
|
|
int serial_puts(const char *s)
|
|
{
|
|
while (*s)
|
|
serial_putc(*s++);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void serial_put_hex(unsigned long data, unsigned int bitlen)
|
|
{
|
|
int i;
|
|
unsigned char s;
|
|
|
|
for (i = bitlen - 4; i >= 0; i -= 4) {
|
|
s = (data >> i) & 0xf;
|
|
if (s < 10)
|
|
serial_putc(0x30 + s);
|
|
else if (s < 16)
|
|
serial_putc(0x61 + s - 10);
|
|
}
|
|
}
|
|
|
|
void serial_put_dec(unsigned long data)
|
|
{
|
|
int i = 0;
|
|
char buff[32];
|
|
|
|
do {
|
|
buff[i++] = (data % 10) + 0x30;
|
|
data = data / 10;
|
|
} while (data && (i < (sizeof(buff) / sizeof(buff[0]))));
|
|
|
|
for (--i; i >= 0; --i)
|
|
serial_putc(buff[i]);
|
|
}
|
|
|
|
void bl2_print(const char *info, unsigned int value, unsigned int is_dec, const char *info2)
|
|
{
|
|
if (info)
|
|
serial_puts(info);
|
|
|
|
if (is_dec)
|
|
serial_put_dec(value);
|
|
else
|
|
serial_put_hex(value, 32);
|
|
|
|
if (info2)
|
|
serial_puts(info2);
|
|
}
|
|
|
|
#ifdef CONFIG_TEST_SERIAL_PRINT
|
|
typedef struct serial_print_test_pattern_s {
|
|
unsigned char t_uchar;
|
|
unsigned int t_uint;
|
|
unsigned long t_ulong;
|
|
} serial_print_test_pattern_t;
|
|
|
|
serial_print_test_pattern_t test_data[] = {
|
|
{ 0, 0, 0 },
|
|
{ 0xf, 0xf, 0xf },
|
|
{ 0xff, 0xff, 0xff },
|
|
{ ~0, 0xffff, 0xffff },
|
|
{ ~0, ~0, 0xffffffff },
|
|
{ ~0, ~0, ~0 },
|
|
};
|
|
|
|
void serial_print_test(void)
|
|
{
|
|
int i;
|
|
unsigned char t_uchar = 0;
|
|
unsigned int t_uint = 0;
|
|
unsigned long t_ulong = 0;
|
|
|
|
serial_puts("\nSerial Print Test\n");
|
|
serial_puts("sizeof(t_uchar)=");
|
|
serial_put_dec(sizeof(t_uchar));
|
|
serial_puts("\n");
|
|
serial_puts("sizeof(t_uint)=");
|
|
serial_put_dec(sizeof(t_uint));
|
|
serial_puts("\n");
|
|
serial_puts("sizeof(t_ulong)=");
|
|
serial_put_dec(sizeof(t_ulong));
|
|
serial_puts("\n");
|
|
|
|
for (i = 0; i < sizeof(test_data) / sizeof(serial_print_test_pattern_t); i++) {
|
|
bl2_print("\nTest Data #", i, VALUE_DEC, "\n");
|
|
|
|
t_uchar = test_data[i].t_uchar;
|
|
t_uint = test_data[i].t_uint;
|
|
t_ulong = test_data[i].t_ulong;
|
|
|
|
serial_puts("printf(t_uchar=%x)=");
|
|
serial_put_hex(t_uchar, 32);
|
|
serial_puts("\n");
|
|
serial_puts("printf(t_uchar=%x)=");
|
|
serial_put_hex(t_uchar, 64);
|
|
serial_puts("\n");
|
|
serial_puts("printf(t_uchar=%d)=");
|
|
serial_put_dec(t_uchar);
|
|
serial_puts("\n");
|
|
|
|
serial_puts("printf(t_uint=%x)=");
|
|
serial_put_hex(t_uint, 32);
|
|
serial_puts("\n");
|
|
serial_puts("printf(t_uint=%x)=");
|
|
serial_put_hex(t_uint, 64);
|
|
serial_puts("\n");
|
|
serial_puts("printf(t_uint=%d)=");
|
|
serial_put_dec(t_uint);
|
|
serial_puts("\n");
|
|
|
|
serial_puts("printf(t_ulong=%x)=");
|
|
serial_put_hex(t_ulong, 32);
|
|
serial_puts("\n");
|
|
serial_puts("printf(t_ulong=%x)=");
|
|
serial_put_hex(t_ulong, 64);
|
|
serial_puts("\n");
|
|
serial_puts("printf(t_ulong=%d)=");
|
|
serial_put_dec(t_ulong);
|
|
serial_puts("\n");
|
|
}
|
|
}
|
|
#endif /* CONFIG_TEST_SERIAL_PRINT */
|