/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ /* * drivers/serial/serial_meson.c * * Copyright (C) 2020 Amlogic, Inc. All rights reserved. * */ #include #include //#include //#include #include #include #include DECLARE_GLOBAL_DATA_PTR; int serial_set_pin_port(unsigned long port_base); static void serial_putc_port (unsigned long port_base,const char c); //static unsigned port_base_addrs[]={UART_PORT_0,UART_PORT_1}; #if 0 // due to error static void serial_clr_err (unsigned port_base) { /* write to the register */ if (readl(P_UART_STATUS(port_base))&(UART_STAT_MASK_PRTY_ERR|UART_STAT_MASK_FRAM_ERR)) writel((readl(P_UART_CONTROL(port_base)) | UART_CNTL_MASK_CLR_ERR), P_UART_CONTROL(port_base)); } #endif /* * Sets baud rate */ static void serial_setbrg_port (unsigned long port_base) { unsigned long baud_para; int clk81=clk_get_rate(UART_CLK_SRC); if (clk81<0) return; /* baud rate */ baud_para=clk81/(gd->baudrate*4) -1; baud_para &= UART_CNTL_MASK_BAUD_RATE; /* write to the register */ writel((readl(P_UART_CONTROL(port_base)) & ~UART_CNTL_MASK_BAUD_RATE) | baud_para, P_UART_CONTROL(port_base)); } /* * Sets stop bits * input[0]: stop_bits (1, 2) */ static void serial_set_stop_port (unsigned long port_base,int stop_bits) { unsigned long uart_config; uart_config = readl(P_UART_CONTROL(port_base)) & ~UART_CNTL_MASK_STP_BITS; /* stop bits */ switch (stop_bits) { case 2: uart_config |= UART_CNTL_MASK_STP_2BIT; break; case 1: default: uart_config |= UART_CNTL_MASK_STP_1BIT; break; } /* write to the register */ writel(uart_config, P_UART_CONTROL(port_base)); } /* * Sets parity type * input[0]: 1 -- enable parity, 0 -- disable; * input[1]: 1 -- odd parity, 0 -- even parity; */ static void serial_set_parity_port(unsigned long port_base,int type) { unsigned long uart_config; uart_config = readl(P_UART_CONTROL(port_base)) & ~(UART_CNTL_MASK_PRTY_TYPE | UART_CNTL_MASK_PRTY_EN); #if 0 //changed by Elvis --- disable parity uart_config |= UART_CNTL_MASK_PRTY_EN; /* parity bits */ if (type&2) uart_config |= UART_CNTL_MASK_PRTY_EN; if (type&1) uart_config |= UART_CNTL_MASK_PRTY_ODD; else uart_config |= UART_CNTL_MASK_PRTY_EVEN; #endif /* write to the register */ writel(uart_config, P_UART_CONTROL(port_base)); } /* * Sets data length * input[0]: Character length [5, 6, 7, 8] */ static void serial_set_dlen_port (unsigned long port_base,int data_len) { unsigned long uart_config; uart_config = readl(P_UART_CONTROL(port_base)) & ~UART_CNTL_MASK_CHAR_LEN; /* data bits */ switch (data_len) { case 5: uart_config |= UART_CNTL_MASK_CHAR_5BIT; break; case 6: uart_config |= UART_CNTL_MASK_CHAR_6BIT; break; case 7: uart_config |= UART_CNTL_MASK_CHAR_7BIT; break; case 8: default: uart_config |= UART_CNTL_MASK_CHAR_8BIT; break; } /* write to the register */ writel(uart_config, P_UART_CONTROL(port_base)); } /* * reset the uart state machine */ static void serial_reset_port(unsigned long port_base) { /* write to the register */ writel(readl(P_UART_CONTROL(port_base)) | UART_CNTL_MASK_RST_TX | UART_CNTL_MASK_RST_RX | UART_CNTL_MASK_CLR_ERR, P_UART_CONTROL(port_base)); writel(readl(P_UART_CONTROL(port_base)) & ~(UART_CNTL_MASK_RST_TX | UART_CNTL_MASK_RST_RX | UART_CNTL_MASK_CLR_ERR), P_UART_CONTROL(port_base)); } /* * Initialise the serial port with given baudrate */ static int serial_init_port (unsigned long port_base) { int ret; #ifdef CONFIG_M3 while ((readl(P_UART_STATUS(port_base)) & (UART_STAT_MASK_XMIT_BUSY))) ; #endif writel(0,P_UART_CONTROL(port_base)); ret = serial_set_pin_port(port_base); if (ret < 0) return -1; serial_setbrg_port(port_base); #ifndef CONFIG_SERIAL_STP_BITS #define CONFIG_SERIAL_STP_BITS 1 #endif serial_set_stop_port(port_base,CONFIG_SERIAL_STP_BITS); #ifndef CONFIG_SERIAL_PRTY_TYPE #define CONFIG_SERIAL_PRTY_TYPE 0 #endif serial_set_parity_port(port_base,CONFIG_SERIAL_PRTY_TYPE); #ifndef CONFIG_SERIAL_CHAR_LEN #define CONFIG_SERIAL_CHAR_LEN 8 #endif serial_set_dlen_port(port_base,CONFIG_SERIAL_CHAR_LEN); writel(readl(P_UART_CONTROL(port_base)) | UART_CNTL_MASK_TX_EN | UART_CNTL_MASK_RX_EN, P_UART_CONTROL(port_base)); while (!(readl(P_UART_STATUS(port_base)) & UART_STAT_MASK_TFIFO_EMPTY)) ; serial_reset_port(port_base); #ifdef CONFIG_M3 while ((readl(P_UART_STATUS(port_base)) & (UART_STAT_MASK_XMIT_BUSY))) ; #endif serial_putc_port(port_base,'\n'); return 0; } /* * Output a single byte to the serial port. */ static void serial_putc_port (unsigned long port_base,const char c) { //#ifndef CONFIG_SILENT_CONSOLE #ifndef CONFIG_AML_PRODUCT_MODE if (c == '\n') serial_putc_port(port_base,'\r'); /* Wait till dataTx register is not full */ while ((readl(P_UART_STATUS(port_base)) & UART_STAT_MASK_TFIFO_FULL)); // while(!(readl(P_UART_STATUS(port_base)) & UART_STAT_MASK_TFIFO_EMPTY)); writel(c, P_UART_WFIFO(port_base)); /* Wait till dataTx register is empty */ #if !defined (CONFIG_VLSI_EMULATOR) while (!(readl(P_UART_STATUS(port_base)) & UART_STAT_MASK_TFIFO_EMPTY)) ; #endif //CONFIG_VLSI_EMULATOR #endif } /* * Read a single byte from the serial port. Returns 1 on success, 0 * otherwise 0. */ static int serial_tstc_port (unsigned long port_base) { int i; i=(readl(P_UART_STATUS(port_base)) & UART_STAT_MASK_RFIFO_CNT); return i; } /* * Read a single byte from the serial port. */ static int serial_getc_port (unsigned long port_base) { unsigned char ch; //#ifndef CONFIG_SILENT_CONSOLE #ifndef CONFIG_AML_PRODUCT_MODE /* Wait till character is placed in fifo */ while ((readl(P_UART_STATUS(port_base)) & UART_STAT_MASK_RFIFO_CNT) == 0) ; ch = readl(P_UART_RFIFO(port_base)) & 0x00ff; /* Also check for overflow errors */ if (readl(P_UART_STATUS(port_base)) & (UART_STAT_MASK_PRTY_ERR | UART_STAT_MASK_FRAM_ERR)) { writel(readl(P_UART_CONTROL(port_base)) |UART_CNTL_MASK_CLR_ERR,P_UART_CONTROL(port_base));//clear errors writel(readl(P_UART_CONTROL(port_base)) & (~UART_CNTL_MASK_CLR_ERR),P_UART_CONTROL(port_base)); } return ((int)ch); #else ch = 0; return ((int)ch); #endif } static void serial_puts_port (unsigned long port_base,const char *s) { while (*s) { serial_putc_port(port_base,*s++); } } #if CONFIG_SERIAL_MULTI #include #define DECLARE_UART_FUNCTIONS(port) \ static int uart_##port##_init (void) {\ serial_init_port(port); return(0);}\ static void uart_##port##_setbrg (void) {\ serial_setbrg_port(port);}\ static int uart_##port##_getc (void) {\ return serial_getc_port(port);}\ static int uart_##port##_tstc (void) {\ return serial_tstc_port(port);}\ static void uart_##port##_putc (const char c) {\ serial_putc_port(port, c);}\ static void uart_##port##_puts (const char *s) {\ serial_puts_port(port, s);} #define INIT_UART_STRUCTURE(port,_name,bus) static struct serial_device device_##port={\ .name = _name,\ /*bus,*/\ .start = uart_##port##_init,\ .stop = NULL,\ .setbrg = uart_##port##_setbrg,\ .getc = uart_##port##_getc,\ .tstc = uart_##port##_tstc,\ .putc = uart_##port##_putc,\ .puts = uart_##port##_puts, } DECLARE_UART_FUNCTIONS(UART_PORT_0); INIT_UART_STRUCTURE(UART_PORT_0,"uart0","UART0"); DECLARE_UART_FUNCTIONS(UART_PORT_1); INIT_UART_STRUCTURE(UART_PORT_1,"uart1","UART1"); #ifdef UART_PORT_AO DECLARE_UART_FUNCTIONS(UART_PORT_AO); INIT_UART_STRUCTURE(UART_PORT_AO,"uart_ao","UART_AO"); #endif struct serial_device * default_serial_console (void) { #if (UART_PORT_CONS==UART_PORT_0) return &device_UART_PORT_0; #elif (UART_PORT_CONS==UART_PORT_1) return &device_UART_PORT_1; #else #ifdef UART_PORT_AO #if (UART_PORT_CONS==UART_PORT_AO) return &device_UART_PORT_AO; #else #error "invalid uart port index defined" #endif #endif #endif } void serial_aml_register(void) { serial_register(&device_UART_PORT_0); serial_register(&device_UART_PORT_1); #ifdef UART_PORT_AO serial_register(&device_UART_PORT_AO); #endif } #endif #if !(defined CONFIG_SERIAL_MULTI) int serial_init(void){ return serial_init_port(UART_PORT_CONS); } void serial_putc(const char c){ serial_putc_port(UART_PORT_CONS,c); } int serial_tstc(void){ return serial_tstc_port(UART_PORT_CONS); } int serial_getc(void){ return serial_getc_port(UART_PORT_CONS); } void serial_puts(const char * s){ serial_puts_port(UART_PORT_CONS,s); } void serial_setbrg(void){ serial_setbrg_port(UART_PORT_CONS); } #ifdef CONFIG_CMD_KGDB #if UART_PORT_CONS==UART_PORT_0 #define DEBUG_PORT UART_PORT_1 #else #define DEBUG_PORT UART_PORT_0 #endif int kgdb_serial_init(void){ int ret=serial_init_port(DEBUG_PORT); return ret; } int getDebugChar(void){ return serial_getc_port(DEBUG_PORT); } void putDebugChar(const char c){ serial_putc_port(DEBUG_PORT,c); } void putDebugStr(const char * s){ serial_puts_port(DEBUG_PORT,s); } #endif /* CONFIG_CMD_KGDB */ #endif