// 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 #include #include #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 (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; if (readl(SYSCTRL_SEC_STATUS_REG4) & ACS_DIS_PRINT_FLAG) 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 */