unplugged-kernel/drivers/misc/mediatek/uart/mt6739/platform_uart.c

2498 lines
74 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
/*---------------------------------------------------------------------------*/
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#if defined(CONFIG_MTK_LEGACY) && !defined(CONFIG_FPGA_EARLY_PORTING)
#include "mach/mt_gpio.h"
#include <cust_gpio_usage.h>
#endif /* defined(CONFIG_MTK_LEGACY) && !defined (CONFIG_FPGA_EARLY_PORTING)*/
#include <linux/delay.h>
#include "include/mtk_uart.h"
#include "include/mtk_uart_intf.h"
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/ratelimit.h>
#include <mt-plat/mtk_lpae.h>
#include "mtk_spm_resource_req.h"
#if !defined(CONFIG_MTK_LEGACY)
/* #include <mach/mt_typedefs.h> */
struct pinctrl *ppinctrl_uart[UART_NR];
/* pinctrl-names from dtsi.GPIO operations: rx set, rx clear, tx set, tx clear */
char *uart_gpio_cmds[UART_NR][4] = {
{"uart0_rx_set", "uart0_rx_clear", "uart0_tx_set", "uart0_tx_clear"},
{"uart1_rx_set", "uart1_rx_clear", "uart1_tx_set", "uart1_tx_clear"},
#if 0
#if !defined(CONFIG_FPGA_EARLY_PORTING)
{"uart2_rx_set", "uart2_rx_clear", "uart2_tx_set", "uart2_tx_clear"},
{"uart3_rx_set", "uart3_rx_clear", "uart3_tx_set", "uart3_tx_clear"},
#endif /* !defined (CONFIG_FPGA_EARLY_PORTING) */
#endif
};
void set_uart_pinctrl(int idx, struct pinctrl *ppinctrl)
{
pr_debug("[UART%d][CCF]%s(%d,%p), UART_NR:%d\n", idx, __func__, idx, ppinctrl, UART_NR);
if (idx >= UART_NR)
return;
ppinctrl_uart[idx] = ppinctrl;
}
#endif /* !defined(CONFIG_MTK_LEGACY) */
#if !defined(CONFIG_FPGA_EARLY_PORTING)
/* struct clk *clk_uart_main; */
struct clk *clk_uart_dma;
void set_uart_dma_clk(int idx, struct clk *dma_clk)
{
pr_debug("[UART%d][CCF]enabled clk_uart_dma:%p\n", idx, dma_clk);
clk_uart_dma = dma_clk;
}
#endif
#ifdef ENABLE_RAW_DATA_DUMP
static void save_tx_raw_data(struct mtk_uart *uart, void *addr);
static void reset_rx_raw_data(struct mtk_uart *uart);
static void save_rx_raw_data(struct mtk_uart *uart, const unsigned char *chars, size_t size);
volatile unsigned int stop_update;
unsigned int curr_record = -1;
volatile unsigned int curr_idx;
#define RECORD_NUMBER 10
#define RECORD_LENGTH 1032
unsigned char uart_history[RECORD_NUMBER][RECORD_LENGTH];
unsigned int uart_history_cnt[RECORD_NUMBER];
spinlock_t tx_history_lock, rx_history_lock;
unsigned int curr_rx_record = -1;
volatile unsigned int curr_rx_idx;
unsigned char uart_rx_history[RECORD_NUMBER][RECORD_LENGTH];
unsigned int uart_rx_history_cnt[RECORD_NUMBER];
#endif
/*---------------------------------------------------------------------------*/
static struct mtk_uart_setting mtk_uart_default_settings[] = {
{
/* .tx_mode = UART_NON_DMA, .rx_mode = UART_RX_VFIFO_DMA, .dma_mode = UART_DMA_MODE_0, */
.tx_mode = UART_TX_VFIFO_DMA, .rx_mode = UART_RX_VFIFO_DMA, .dma_mode = UART_DMA_MODE_0,
/* .tx_mode = UART_NON_DMA, .rx_mode = UART_NON_DMA, .dma_mode = UART_DMA_MODE_0, */
.tx_trig = UART_FCR_TXFIFO_1B_TRI, .rx_trig = UART_FCR_RXFIFO_12B_TRI,
/* .uart_base = AP_UART0_BASE, .irq_num = UART0_IRQ_BIT_ID, .irq_sen = MT_LEVEL_SENSITIVE, */
.sysrq = FALSE, .hw_flow = TRUE, .vff = TRUE,
},
{
.tx_mode = UART_NON_DMA, .rx_mode = UART_NON_DMA, .dma_mode = UART_DMA_MODE_0,
.tx_trig = UART_FCR_TXFIFO_1B_TRI, .rx_trig = UART_FCR_RXFIFO_12B_TRI,
/* .uart_base = AP_UART1_BASE, .irq_num = UART1_IRQ_BIT_ID, .irq_sen = MT_LEVEL_SENSITIVE, */
.sysrq = FALSE, .hw_flow = TRUE, .vff = TRUE,
},
#if 0
{
.tx_mode = UART_TX_VFIFO_DMA, .rx_mode = UART_RX_VFIFO_DMA, .dma_mode = UART_DMA_MODE_0,
.tx_trig = UART_FCR_TXFIFO_1B_TRI, .rx_trig = UART_FCR_RXFIFO_12B_TRI,
/* .uart_base = AP_UART2_BASE, .irq_num = UART2_IRQ_BIT_ID, .irq_sen = MT_LEVEL_SENSITIVE, */
.set_bit = PDN_FOR_UART3, .clr_bit = PDN_FOR_UART3, .pll_id = PDN_FOR_UART3,
.sysrq = FALSE, .hw_flow = FALSE, .vff = TRUE, /* UART3 */
},
{
.tx_mode = UART_NON_DMA, .rx_mode = UART_NON_DMA, .dma_mode = UART_DMA_MODE_0,
.tx_trig = UART_FCR_TXFIFO_1B_TRI, .rx_trig = UART_FCR_RXFIFO_12B_TRI,
/* .uart_base = AP_UART3_BASE, .irq_num = UART3_IRQ_BIT_ID, .irq_sen = MT_LEVEL_SENSITIVE, */
.set_bit = PDN_FOR_UART4, .clr_bit = PDN_FOR_UART4, .pll_id = PDN_FOR_UART4,
.sysrq = FALSE, .hw_flow = FALSE, .vff = FALSE, /* UART4 */
},
#endif
};
/*---------------------------------------------------------------------------*/
static unsigned long mtk_uart_evt_mask[] = {
DBG_EVT_NONE,
DBG_EVT_NONE,
DBG_EVT_NONE,
DBG_EVT_NONE,
};
/*---------------------------------------------------------------------------*/
static unsigned long mtk_uart_lsr_status[] = {
0, /* UART1 */
0, /* UART2 */
0, /* UART3 */
0, /* UART4 */
};
/*---------------------------------------------------------------------------*/
#if defined(CONFIG_MTK_SERIAL_MODEM_TEST)
/* #define HW_MISC (CONFIG_BASE+0x0020) // mtk does NOT has this register */
/* unsigned char mask[UART_NR] = { 1 << 3, 1 << 4, 1 << 5, 1 << 6}; */
static unsigned int modem_uart[UART_NR] = { 1, 0, 0, 1 };
#endif
/*---------------------------------------------------------------------------*/
/* uart control blocks */
/*---------------------------------------------------------------------------*/
struct mtk_uart_setting *get_uart_default_settings(int idx)
{
return &mtk_uart_default_settings[idx];
}
/*---------------------------------------------------------------------------*/
void set_uart_default_settings(int idx)
{
struct device_node *node = NULL;
unsigned int irq_info[3] = { 0, 0, 0 };
u32 phys_base;
switch (idx) {
case 0:
node = of_find_node_by_name(NULL, "apuart0");
break;
case 1:
node = of_find_node_by_name(NULL, "apuart1");
break;
#if (UART_NR > 2)
case 2:
node = of_find_node_by_name(NULL, "apuart2");
break;
#endif
#if (UART_NR > 3)
case 3:
node = of_find_node_by_name(NULL, "apuart3");
break;
#endif
default:
break;
}
if (node) {
/* iomap registers */
mtk_uart_default_settings[idx].uart_base = (unsigned long)of_iomap(node, 0);
/* get IRQ ID */
mtk_uart_default_settings[idx].irq_num = irq_of_parse_and_map(node, 0);
}
/* phys registers */
if (of_property_read_u32_index(node, "reg", 0, &phys_base))
pr_debug("[UART%d] get phys regs from DTS fail!!\n", idx);
mtk_uart_default_settings[idx].uart_phys_base = phys_base;
/* get the interrupt line behaviour */
if (of_property_read_u32_array(node, "interrupts", irq_info, ARRAY_SIZE(irq_info)))
pr_debug("[UART%d] get irq flags from DTS fail!!\n", idx);
mtk_uart_default_settings[idx].irq_flags = (unsigned long)irq_info[2];
pr_debug("[UART%d] phys_regs=0x%lx, regs=0x%lx, irq=%d, irq_flags=0x%lx\n", idx,
mtk_uart_default_settings[idx].uart_phys_base, mtk_uart_default_settings[idx].uart_base,
mtk_uart_default_settings[idx].irq_num, mtk_uart_default_settings[idx].irq_flags);
}
/*---------------------------------------------------------------------------*/
void *get_apdma_uart0_base(void)
{
struct device_node *node = NULL;
void *base;
node = of_find_node_by_name(NULL, "apuart0");
base = of_iomap(node, 1);
pr_debug("[UART] apdma uart0 base=0x%p\n", base);
return base;
}
/*---------------------------------------------------------------------------*/
unsigned int get_uart_vfifo_irq_id(int idx)
{
struct device_node *node = NULL;
unsigned int irq_id;
switch (idx) {
case 0:
case 1:
node = of_find_node_by_name(NULL, "apuart0");
break;
case 2:
case 3:
node = of_find_node_by_name(NULL, "apuart1");
break;
case 4:
case 5:
node = of_find_node_by_name(NULL, "apuart2");
break;
case 6:
case 7:
node = of_find_node_by_name(NULL, "apuart3");
break;
default:
break;
}
if (idx % 2 == 0)
irq_id = irq_of_parse_and_map(node, 1);
else
irq_id = irq_of_parse_and_map(node, 2);
pr_debug("[UART_DMA%d] irq=%d\n", idx, irq_id);
return irq_id;
}
/*---------------------------------------------------------------------------*/
unsigned long get_uart_evt_mask(int idx)
{
return mtk_uart_evt_mask[idx];
}
/*---------------------------------------------------------------------------*/
void set_uart_evt_mask(int idx, int value)
{
mtk_uart_evt_mask[idx] = value;
}
/*---------------------------------------------------------------------------*/
unsigned long get_uart_lsr_status(int idx)
{
return mtk_uart_lsr_status[idx];
}
/*---------------------------------------------------------------------------*/
void set_uart_lsr_status(int idx, int value)
{
mtk_uart_lsr_status[idx] = value;
}
/*---------------------------------------------------------------------------*/
unsigned int get_modem_uart(int idx)
{
#if defined(CONFIG_MTK_SERIAL_MODEM_TEST)
return modem_uart[idx];
#else
return 0;
#endif
}
/*---------------------------------------------------------------------------*/
#ifdef UART_FCR_USING_SW_BACK_UP
static inline void __write_fcr_register(struct mtk_uart *uart, u32 data)
{
unsigned long base = uart->base;
uart->fcr_back_up = data & (~(3 << 1));
reg_sync_writel(data, UART_FCR);
}
static inline void sync_write_fcr_register(struct mtk_uart *uart, u32 data)
{
unsigned long base = uart->base;
uart->fcr_back_up = data & (~(3 << 1));
reg_sync_writel(data, UART_FCR);
}
static inline u32 __read_fcr_register(struct mtk_uart *uart)
{
return uart->fcr_back_up;
}
static inline void __set_fcr_register(struct mtk_uart *uart, u32 mask)
{
unsigned long base = uart->base;
u32 new_setting = (uart->fcr_back_up) | mask;
uart->fcr_back_up = new_setting & (~(3 << 1));
reg_sync_writel(new_setting, UART_FCR);
}
static inline void __clr_fcr_register(struct mtk_uart *uart, u32 mask)
{
unsigned long base = uart->base;
u32 new_setting = (uart->fcr_back_up) & (~mask);
uart->fcr_back_up = new_setting & (~(3 << 1));
reg_sync_writel(new_setting, UART_FCR);
}
#else
static inline void __write_fcr_register(struct mtk_uart *uart, u32 data)
{
unsigned long base = uart->base;
reg_sync_writel(data, UART_FCR);
}
static inline void sync_write_fcr_register(struct mtk_uart *uart, u32 data)
{
unsigned long base = uart->base;
reg_sync_writel(data, UART_FCR);
}
static inline u32 __read_fcr_register(struct mtk_uart *uart)
{
unsigned long base = uart->base;
return UART_READ32(UART_FCR_RD);
}
static inline void __set_fcr_register(struct mtk_uart *uart, u32 mask)
{
unsigned long base = uart->base;
u32 new_setting = UART_READ32(UART_FCR_RD) | mask;
reg_sync_writel(new_setting, UART_FCR);
}
static inline void __clr_fcr_register(struct mtk_uart *uart, u32 mask)
{
unsigned long base = uart->base;
u32 new_setting = UART_READ32(UART_FCR_RD) & (~mask);
reg_sync_writel(new_setting, UART_FCR);
}
#endif /* End of UART_FCR_USING_SW_BACK_UP */
/*---------------------------------------------------------------------------*/
static inline void dump_reg(struct mtk_uart *uart, const char *caller)
{
#ifdef ENABLE_DEBUG
unsigned long flags;
unsigned long base = uart->base;
u32 lcr = UART_READ32(UART_LCR);
u32 uratefix = UART_READ32(UART_RATE_FIX_AD);
u32 uhspeed = UART_READ32(UART_HIGHSPEED);
u32 usamplecnt = UART_READ32(UART_SAMPLE_COUNT);
u32 usamplepnt = UART_READ32(UART_SAMPLE_POINT);
u32 udll, udlh;
u32 ier = UART_READ32(UART_IER);
spin_lock_irqsave(&mtk_console_lock, flags);
reg_sync_writel((lcr | UART_LCR_DLAB), UART_LCR);
udll = UART_READ32(UART_DLL);
udlh = UART_READ32(UART_DLH);
mb(); /* make sure the DLL/DLH have been read */
reg_sync_writel(lcr, UART_LCR); /* DLAB end */
spin_unlock_irqrestore(&mtk_console_lock, flags);
mb();
MSG(CFG, "%s: RATEFIX(%02X); HSPEED(%02X); CNT(%02X); PNT(%02X); DLH(%02X), DLL(%02X), IER(%02X)\n",
caller, uratefix, uhspeed, usamplecnt, usamplepnt, udlh, udll, ier);
#endif
}
void dump_uart_reg(void)
{
struct mtk_uart *uart;
unsigned int i;
unsigned long base;
u32 lsr, escape_en;
for (i = 0; i < UART_NR; i++) {
uart = &mtk_uarts[i];
base = uart->base;
if (uart->poweron_count > 0) {
lsr = UART_READ32(UART_LSR);
escape_en = UART_READ32(UART_ESCAPE_EN);
pr_debug("[UART%d] LSR=0x%x ESCAPE_EN=0x%x\n", uart->nport, lsr, escape_en);
} else
pr_debug("[UART%d] clock is off\n", uart->nport);
}
}
/*---------------------------------------------------------------------------*/
void mtk_uart_console_setting_switch(struct mtk_uart *uart)
{
#ifdef CONFIG_MTK_SERIAL_CONSOLE
/* if(uart->nport == 0){ */ /* UART1 as log port */
uart->setting->tx_mode = UART_NON_DMA;
uart->setting->rx_mode = UART_NON_DMA;
uart->tx_mode = UART_NON_DMA;
uart->rx_mode = UART_NON_DMA;
mtk_uart_enable_dpidle(uart);
/* } */
#endif
}
/******************************************************************************
* Virtual FIFO implementation
******************************************************************************/
#if defined(ENABLE_VFIFO)
/*---------------------------------------------------------------------------*/
int mtk_uart_vfifo_enable(struct mtk_uart *uart, struct mtk_uart_vfifo *vfifo)
{
unsigned long base = uart->base;
if (!vfifo) {
MSG(ERR, "null\n");
return -EINVAL;
} else if (vfifo->type != UART_RX_VFIFO && vfifo->type != UART_TX_VFIFO) {
MSG(ERR, "unknown type: %d\n", vfifo->type);
return -EINVAL;
}
/*
* NOTE: For FCR is a read only register reason,
* special read/write/set/clr function need to use
*/
/*UART_SET_BITS(UART_FCR_FIFO_INIT, UART_FCR);*/
/*UART_CLR_BITS(UART_FCR_DMA1, UART_FCR);*/
__set_fcr_register(uart, UART_FCR_FIFO_INIT);
__clr_fcr_register(uart, UART_FCR_DMA1);
if (vfifo->type == UART_RX_VFIFO)
UART_SET_BITS(UART_RX_DMA_EN | UART_TO_CNT_AUTORST, UART_DMA_EN);
else if (vfifo->type == UART_TX_VFIFO)
UART_SET_BITS(UART_TX_DMA_EN, UART_DMA_EN);
mb();
return 0;
}
/*---------------------------------------------------------------------------*/
int mtk_uart_vfifo_disable(struct mtk_uart *uart, struct mtk_uart_vfifo *vfifo)
{
unsigned long base = uart->base;
if (!vfifo) {
MSG(ERR, "null\n");
return -EINVAL;
} else if (vfifo->type != UART_RX_VFIFO && vfifo->type != UART_TX_VFIFO) {
MSG(ERR, "unknown type: %d\n", vfifo->type);
return -EINVAL;
} else if (vfifo->type == UART_RX_VFIFO) {
UART_CLR_BITS(UART_RX_DMA_EN | UART_TO_CNT_AUTORST, UART_DMA_EN);
} else if (vfifo->type == UART_TX_VFIFO) {
UART_CLR_BITS(UART_TX_DMA_EN, UART_DMA_EN);
}
mb();
return 0;
}
/*---------------------------------------------------------------------------*/
void mtk_uart_vfifo_enable_tx_intr(struct mtk_uart *uart)
{
reg_sync_writel(VFF_TX_INT_EN_B, VFF_INT_EN(uart->tx_vfifo->base));
}
/*---------------------------------------------------------------------------*/
void mtk_uart_vfifo_disable_tx_intr(struct mtk_uart *uart)
{
reg_sync_writel(0x00, VFF_INT_EN(uart->tx_vfifo->base));
}
/*---------------------------------------------------------------------------*/
void mtk_uart_vfifo_clear_tx_intr(struct mtk_uart_vfifo *vfifo)
{
reg_sync_writel(0x00, VFF_INT_FLAG(vfifo->base));
}
/*---------------------------------------------------------------------------*/
void mtk_uart_vfifo_clear_rx_intr(struct mtk_uart_vfifo *vfifo)
{
reg_sync_writel(0x03, VFF_INT_FLAG(vfifo->base));
}
/*---------------------------------------------------------------------------*/
void mtk_uart_vfifo_enable_rx_intr(struct mtk_uart *uart)
{
reg_sync_writel(VFF_RX_INT_EN0_B | VFF_RX_INT_EN1_B, VFF_INT_EN(uart->rx_vfifo->base));
}
/*---------------------------------------------------------------------------*/
void mtk_uart_vfifo_disable_rx_intr(struct mtk_uart *uart)
{
reg_sync_writel(0x00, VFF_INT_EN(uart->rx_vfifo->base));
}
/*---------------------------------------------------------------------------*/
int mtk_uart_vfifo_is_full(struct mtk_uart_vfifo *vfifo)
{
return (UART_READ32(VFF_LEFT_SIZE(vfifo->base)) <= 16) ? (1) : (0);
}
/*---------------------------------------------------------------------------*/
int mtk_uart_vfifo_is_empty(struct mtk_uart_vfifo *vfifo)
{
return (UART_READ32(VFF_VALID_SIZE(vfifo->base)) == 0) ? (1) : (0);
}
/*---------------------------------------------------------------------------*/
void mtk_uart_vfifo_write_byte(struct mtk_uart *uart, unsigned int byte)
{
void *addr, *base = uart->tx_vfifo->base;
unsigned int wpt = UART_READ32(VFF_WPT(base));
addr = (void *)((wpt & 0xffff) + uart->tx_vfifo->addr);
reg_sync_writeb((unsigned char)byte, addr);
mb(); /* make sure write point updated after VFIFO written. */
#ifdef ENABLE_RAW_DATA_DUMP
save_tx_raw_data(uart, addr);
#endif
if ((wpt & 0xffff) == (UART_READ32(VFF_LEN(base)) - 1))
reg_sync_writel((~wpt) & 0x10000, VFF_WPT(base));
else
reg_sync_writel(wpt + 1, VFF_WPT(base));
}
/*---------------------------------------------------------------------------*/
unsigned int mtk_uart_vfifo_read_byte(struct mtk_uart *uart)
{
void *addr, *base = uart->rx_vfifo->base;
unsigned int ch;
addr = (void *)(UART_READ16(VFF_RPT(base)) + uart->rx_vfifo->addr);
ch = UART_READ8(addr);
mb(); /* make sure read point updated after VFIFO read. */
if (UART_READ16(VFF_RPT(base)) == (UART_READ32(VFF_LEN(base)) - 1))
reg_sync_writel(~(UART_READ32(VFF_RPT(base))) & 0x10000, VFF_RPT(base));
else
reg_sync_writel(UART_READ32(VFF_RPT(base)) + 1, VFF_RPT(base));
return ch;
}
/*---------------------------------------------------------------------------*/
int mtk_uart_vfifo_get_counts(struct mtk_uart_vfifo *vfifo)
{
return UART_READ32(VFF_VALID_SIZE(vfifo->base));
}
/*---------------------------------------------------------------------------*/
void mtk_uart_tx_vfifo_flush(struct mtk_uart *uart, int timeout)
{
struct mtk_uart_dma *dma = &uart->dma_tx;
struct mtk_uart_vfifo *vfifo = dma->vfifo;
void *base = vfifo->base;
#ifdef ENABE_HRTIMER_FLUSH
if (UART_READ32(VFF_FLUSH(base)) == 0) {
reg_sync_writel(VFF_FLUSH_B, VFF_FLUSH(base));
if (!timeout)
hrtimer_try_to_cancel(&vfifo->flush);
MSG(MSC, "flush [%5X.%5X]\n", UART_READ32(VFF_RPT(base)), UART_READ32(VFF_WPT(base)));
} else {
/*the ns used to transfer the data in TX VFIFO */
u32 size = UART_READ32(VFF_VALID_SIZE(base));
s64 t = size * 10 * (NSEC_PER_SEC / uart->baudrate);
ktime_t cur = ktime_get();
ktime_t nxt = ktime_add_ns(cur, t);
hrtimer_try_to_cancel(&vfifo->flush);
hrtimer_start(&vfifo->flush, nxt, HRTIMER_MODE_ABS);
#if defined(ENABLE_VFIFO_DEBUG)
{
struct timespec a = ktime_to_timespec(cur);
struct timespec b = ktime_to_timespec(nxt);
MSG(MSC, "start: [%ld %ld] [%ld %ld] [%d %lld]\n",
a.tv_sec, a.tv_nsec, b.tv_sec, b.tv_nsec, size, t);
}
#endif
}
#else
if (UART_READ32(VFF_FLUSH(base)) == 0) {
reg_sync_writel(VFF_FLUSH_B, VFF_FLUSH(base));
MSG(MSC, "flush [%5X.%5X]\n", UART_READ32(VFF_RPT(base)), UART_READ32(VFF_WPT(base)));
}
#endif /* ENABE_HRTIMER_FLUSH */
}
/*---------------------------------------------------------------------------*/
static void mtk_uart_dma_vfifo_tx_tasklet_byte(unsigned long arg)
{
struct mtk_uart *uart = (struct mtk_uart *)arg;
struct uart_port *port = &uart->port;
/* struct mtk_uart_dma *dma = &uart->dma_tx; */
struct mtk_uart_vfifo *vfifo = uart->tx_vfifo;
struct circ_buf *xmit = &port->state->xmit;
unsigned int len, count, size, left, chk = 0;
ktime_t begin, end;
struct timespec a, b;
size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
left = vfifo->size - mtk_uart_vfifo_get_counts(vfifo);
left = (left > 16) ? (left - 16) : (0); /*prevent from CPU lock */
len = count = left < size ? left : size;
if (!len) {
chk = 1;
MSG(DMA, ">>>>> zero size <<<<<\n");
}
DGBUF_INIT(vfifo);
begin = ktime_get();
a = ktime_to_timespec(begin);
while (len--) {
/*DMA limitation.
* Workaround: Polling flush bit to zero, set 1s timeout
*/
while (UART_READ32(VFF_FLUSH(vfifo->base))) {
end = ktime_get();
b = ktime_to_timespec(end);
if ((b.tv_sec - a.tv_sec) > 1 || ((b.tv_sec - a.tv_sec) == 1 && b.tv_nsec > a.tv_nsec)) {
pr_debug("[UART%d] Polling flush timeout\n", port->line);
return;
}
}
DGBUF_PUSH_CH(vfifo, (char)xmit->buf[xmit->tail]);
uart->write_byte(uart, xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
}
#if defined(ENABLE_VFIFO_DEBUG)
if (UART_DEBUG_EVT(DBG_EVT_DMA) && UART_DEBUG_EVT(DBG_EVT_BUF)) {
char str[4] = { 0 };
if (count >= 4) {
str[0] = vfifo->cur->dat[0];
str[1] = vfifo->cur->dat[1];
str[2] = vfifo->cur->dat[vfifo->cur->idx - 2];
str[3] = vfifo->cur->dat[vfifo->cur->idx - 1];
} else {
int idx;
for (idx = 0; idx < count; idx++)
str[idx] = vfifo->cur->dat[idx];
for (; idx < 4; idx++)
str[idx] = 0;
}
MSG(DMA, "TX[%4d]: %4d/%4d [%05X-%05X] (%02X %02X .. %02X %02X)\n",
size, count, left, UART_READ32(VFF_WPT(vfifo->base)), UART_READ32(VFF_RPT(vfifo->base)),
str[0], str[1], str[2], str[3]);
} else {
MSG(DMA, "TX[%4d]: %4d/%4d [%05X-%05X]\n",
size, count, left, UART_READ32(VFF_WPT(vfifo->base)), UART_READ32(VFF_RPT(vfifo->base)));
}
#endif
#if defined(ENABLE_VFIFO_DEBUG)
if (UART_DEBUG_EVT(DBG_EVT_DAT) && UART_DEBUG_EVT(DBG_EVT_BUF)) {
int i;
pr_debug("[UART%d_TX] %4d bytes:", uart->nport, vfifo->cur->idx);
for (i = 0; i < vfifo->cur->idx; i++) {
if (i % 16 == 0)
pr_debug("\n");
pr_debug("%.2x ", (unsigned char)vfifo->cur->dat[i]);
}
pr_debug("\n");
}
#endif
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
}
/*---------------------------------------------------------------------------*/
/*static int mtk_uart_vfifo_write_string(struct mtk_uart *uart, const unsigned char *chars, size_t size)
*{
* void *addr, *base = uart->tx_vfifo->base;
* unsigned int wpt = UART_READ32(VFF_WPT(base));
* unsigned int num_to_end;
*
* addr = (void*)((wpt&0xffff)+uart->tx_vfifo->addr);
* num_to_end = UART_READ32(VFF_LEN(base)) - (wpt&0xffff);
* if(num_to_end >= size){
* memcpy(addr, chars, size);
* mb(); //make sure write point updated after VFIFO written.
* reg_sync_writel( wpt+(unsigned int)size, VFF_WPT(base));
* }else{
* memcpy(addr, chars, num_to_end);
* memcpy(uart->tx_vfifo->addr, &chars[num_to_end], (unsigned int)size - num_to_end);
* mb(); //make sure write point updated after VFIFO written.
* wpt = ((~wpt)&0x10000)+ (unsigned int)size - num_to_end;
* reg_sync_writel(wpt, VFF_WPT(base));
* }
*
* return size;
*}
*/
/*---------------------------------------------------------------------------*/
/*static void mtk_uart_dma_vfifo_tx_tasklet_str(unsigned long arg)
*{
* struct mtk_uart *uart = (struct mtk_uart *)arg;
* struct uart_port *port = &uart->port;
* //struct mtk_uart_dma *dma = &uart->dma_tx;
* struct mtk_uart_vfifo *vfifo = uart->tx_vfifo;
* struct circ_buf *xmit = &port->state->xmit;
* unsigned int len, count, size, left, chk = 0;
*
* size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
* left = vfifo->size - mtk_uart_vfifo_get_counts(vfifo);
* left = (left > 16) ? (left-16) : (0);
* len = count = left < size ? left : size;
*
* if (!len) {
* chk = 1;
* MSG(DMA,">>>>> zero size <<<<<\n");
* }
*
* DGBUF_INIT(vfifo);
*
* mtk_uart_vfifo_write_string(uart, &xmit->buf[xmit->tail], size);
* DGBUF_PUSH_STR(vfifo, &xmit->buf[xmit->tail], size);
* xmit->tail = (xmit->tail+size) & (UART_XMIT_SIZE - 1);
* port->icount.tx += size;
*
*#if defined(ENABLE_VFIFO_DEBUG)
* if (UART_DEBUG_EVT(DBG_EVT_DMA) && UART_DEBUG_EVT(DBG_EVT_BUF)) {
* char str[4] = {0};
* if (count >= 4) {
* str[0] = vfifo->cur->dat[0];
* str[1] = vfifo->cur->dat[1];
* str[2] = vfifo->cur->dat[vfifo->cur->idx-2];
* str[3] = vfifo->cur->dat[vfifo->cur->idx-1];
* } else {
* int idx;
* for (idx = 0; idx < count; idx++)
* str[idx] = vfifo->cur->dat[idx];
* for (; idx < 4; idx++)
* str[idx] = 0;
* }
* MSG(DMA, "TX[%4d]: %4d/%4d [%05X-%05X] (%02X %02X .. %02X %02X)\n",
* size, count, left, UART_READ32(VFF_WPT(vfifo->base)), UART_READ32(VFF_RPT(vfifo->base)),
* str[0], str[1], str[2], str[3]);
* } else {
* MSG(DMA, "TX[%4d]: %4d/%4d [%05X-%05X]\n",
* size, count, left, UART_READ32(VFF_WPT(vfifo->base)), UART_READ32(VFF_RPT(vfifo->base)));
* }
*#endif
*
*#if defined(ENABLE_VFIFO_DEBUG)
* if (UART_DEBUG_EVT(DBG_EVT_DAT) && UART_DEBUG_EVT(DBG_EVT_BUF)) {
* int i;
* pr_debug("[UART%d_TX] %4d bytes:", uart->nport, vfifo->cur->idx);
* for (i = 0; i < vfifo->cur->idx; i++) {
* if (i % 16 == 0)
* pr_debug("\n");
* pr_debug("%.2x ", (unsigned char)vfifo->cur->dat[i]);
* }
* pr_debug("\n");
* }
*#endif
*
* if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
* uart_write_wakeup(port);
*
*}
*/
/*---------------------------------------------------------------------------*/
void mtk_uart_dma_vfifo_tx_tasklet(unsigned long arg)
{
struct mtk_uart *uart = (struct mtk_uart *)arg;
struct uart_port *port = &uart->port;
struct mtk_uart_dma *dma = &uart->dma_tx;
struct mtk_uart_vfifo *vfifo = uart->tx_vfifo;
struct circ_buf *xmit = &port->state->xmit;
int txcount = port->icount.tx;
void *base = vfifo->base;
unsigned long flags;
spin_lock_irqsave(&vfifo->iolock, flags);
atomic_inc(&vfifo->entry);
while (UART_READ32(VFF_LEFT_SIZE(base)) >= vfifo->trig) {
/* deal with x_char first */
if (unlikely(port->x_char)) {
MSG(INFO, "detect x_char!!\n");
uart->write_byte(uart, port->x_char);
port->icount.tx++;
port->x_char = 0;
break;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
uart->pending_tx_reqs = 0;
atomic_set(&dma->free, 1);
complete(&dma->done);
break;
}
mtk_uart_dma_vfifo_tx_tasklet_byte(arg);
}
if (txcount != port->icount.tx) {
mtk_uart_vfifo_enable_tx_intr(uart);
mtk_uart_tx_vfifo_flush(uart, 0);
}
atomic_dec(&vfifo->entry);
spin_unlock_irqrestore(&vfifo->iolock, flags);
}
/*---------------------------------------------------------------------------*/
/*static void mtk_uart_dma_vfifo_rx_tasklet_byte(unsigned long arg)
*{
* struct mtk_uart *uart = (struct mtk_uart*)arg;
* struct uart_port *port = &uart->port;
* struct mtk_uart_vfifo *vfifo = uart->rx_vfifo;
* struct tty_struct *tty = uart->port.state->port.tty;
* int count, left;
* unsigned int ch, flag, status;
* unsigned long flags;
*
* MSG_FUNC_ENTRY();
*
* count = left = mtk_uart_vfifo_get_counts(vfifo);
*
* spin_lock_irqsave(&port->lock, flags);
*
* DGBUF_INIT(vfifo);
* while (!mtk_uart_vfifo_is_empty(vfifo) && count > 0) {
*
* status = uart->read_status(uart);
* status = mtk_uart_filter_line_status(uart);
*
* ch = uart->read_byte(uart);
* flag = TTY_NORMAL;
*
* if (status & UART_LSR_BI) {
* MSG(INFO, "Break Interrupt!!!\n");
* port->icount.brk++;
* if (uart_handle_break(port))
* continue;
* flag = TTY_BREAK;
* } else if (status & UART_LSR_PE) {
* MSG(INFO, "Parity Error!!!\n");
* port->icount.parity++;
* flag = TTY_PARITY;
* } else if (status & UART_LSR_FE) {
* MSG(INFO, "Frame Error!!!\n");
* port->icount.frame++;
* flag = TTY_FRAME;
* } else if (status & UART_LSR_OE) {
* MSG(INFO, "Overrun!!!\n");
* port->icount.overrun++;
* flag = TTY_OVERRUN;
* }
* port->icount.rx++;
* count--;
* DGBUF_PUSH_CH(vfifo, ch);
* if (!tty_insert_flip_char(tty, ch, flag))
* MSG(ERR, "tty_insert_flip_char: no space\n");
* }
* tty_flip_buffer_push(tty);
*
*#if defined(ENABLE_VFIFO_DEBUG)
* if (UART_DEBUG_EVT(DBG_EVT_DMA) && UART_DEBUG_EVT(DBG_EVT_BUF)) {
* char str[4] = {0};
* if (count >= 4) {
* str[0] = vfifo->cur->dat[0];
* str[1] = vfifo->cur->dat[1];
* str[2] = vfifo->cur->dat[vfifo->cur->idx-2];
* str[3] = vfifo->cur->dat[vfifo->cur->idx-1];
* } else {
* int idx;
* for (idx = 0; idx < count; idx++)
* str[idx] = vfifo->cur->dat[idx];
* for (; idx < 4; idx++)
* str[idx] = 0;
* }
* MSG(DMA, "RX[%4d]: %4d bytes from VFIFO [%4d] (%02X %02X .. %02X %02X) %d\n",
* left, left - count, mtk_uart_vfifo_get_counts(vfifo), str[0], str[1], str[2], str[3],
* UART_READ32(VFF_VALID_SIZE(vfifo->base)));
* } else {
* MSG(DMA, "RX[%4d]: %4d bytes from VFIFO [%4d] %d\n",
* left, left - count, mtk_uart_vfifo_get_counts(vfifo),
* UART_READ32(VFF_VALID_SIZE(vfifo->base)));
* }
*#endif
*
* spin_unlock_irqrestore(&port->lock, flags);
*
*#if defined(ENABLE_VFIFO_DEBUG)
* if (UART_DEBUG_EVT(DBG_EVT_DAT) && UART_DEBUG_EVT(DBG_EVT_BUF)) {
* int i;
* pr_debug("[UART%d_RX] %4d bytes:", uart->nport, vfifo->cur->idx);
*
* for (i = 0; i < vfifo->cur->idx; i++) {
* if (i % 16 == 0)
* pr_debug("\n");
* pr_debug("%.2x ", (unsigned char)vfifo->cur->dat[i]);
* }
* pr_debug("\n");
*
* }
*#endif
*}
*/
/*---------------------------------------------------------------------------*/
/* A duplicate of tty_insert_flip_string. */
/* The only difference is the function will accept one extra variable for */
/* indicating the current line status. */
/*---------------------------------------------------------------------------*/
static int mtk_uart_tty_insert_flip_string(struct mtk_uart *uart, const unsigned char *chars, size_t size)
{
struct tty_struct *tty = uart->port.state->port.tty;
struct uart_port *port = &uart->port;
u32 status, flag;
int copied = 0;
status = uart->read_status(uart);
status = mtk_uart_filter_line_status(uart);
flag = TTY_NORMAL;
/* error handling routine */
if (status & UART_LSR_BI) {
MSG(ERR, "Break Interrupt!!\n");
port->icount.brk++;
if (uart_handle_break(port))
return 0;
flag = TTY_BREAK;
} else if (status & UART_LSR_PE) {
MSG(ERR, "Parity Error!!!\n");
port->icount.parity++;
flag = TTY_PARITY;
} else if (status & UART_LSR_FE) {
MSG(ERR, "Frame Error!!!\n");
port->icount.frame++;
flag = TTY_FRAME;
} else if (status & UART_LSR_OE) {
MSG(ERR, "Overrun!!!\n");
port->icount.overrun++;
flag = TTY_OVERRUN;
}
#ifdef ENABLE_RAW_DATA_DUMP
save_rx_raw_data(uart, chars, size);
#endif
if (flag == TTY_NORMAL) {
copied = tty_insert_flip_string(tty->port, chars, size);
} else {
MSG(ERR, "error occurs\n");
copied += tty_insert_flip_string(tty->port, chars, size - 1);
copied += tty_insert_flip_char(tty->port, chars[size - 1], flag);
}
port->icount.rx += copied;
return copied;
}
/*---------------------------------------------------------------------------*/
static void mtk_uart_dma_vfifo_rx_tasklet_str(unsigned long arg)
{
struct mtk_uart *uart = (struct mtk_uart *)arg;
struct uart_port *port = &uart->port;
struct mtk_uart_vfifo *vfifo = uart->rx_vfifo;
struct tty_struct *tty = uart->port.state->port.tty;
int count, left;
unsigned int rxptr, txptr, txreg, rxreg;
unsigned long flags;
unsigned char *ptr;
void *base = vfifo->base;
MSG_FUNC_ENTRY();
spin_lock_irqsave(&port->lock, flags);
rxreg = UART_READ32(VFF_RPT(base));
txreg = UART_READ32(VFF_WPT(base));
rxptr = rxreg & 0x0000FFFF;
txptr = txreg & 0x0000FFFF;
count = left = ((rxreg ^ txreg) & 0x00010000) ? (txptr + vfifo->size - rxptr) : (txptr - rxptr);
DGBUF_INIT(vfifo);
#ifdef ENABLE_RAW_DATA_DUMP
reset_rx_raw_data(uart);
#endif
if ((rxptr + count) <= txptr) {
ptr = (unsigned char *)(rxptr + vfifo->addr);
mtk_uart_tty_insert_flip_string(uart, ptr, count);
DGBUF_PUSH_STR(vfifo, ptr, count);
} else {
ptr = (unsigned char *)(rxptr + vfifo->addr);
mtk_uart_tty_insert_flip_string(uart, ptr, vfifo->size - rxptr);
DGBUF_PUSH_STR(vfifo, ptr, vfifo->size - rxptr);
if (txptr) {
ptr = (unsigned char *)(vfifo->addr);
mtk_uart_tty_insert_flip_string(uart, ptr, txptr);
DGBUF_PUSH_STR(vfifo, ptr, txptr);
}
}
mb(); /* make sure read point updated after VFIFO read. */
reg_sync_writel(txreg, VFF_RPT(base));
tty_flip_buffer_push(tty->port);
#if defined(ENABLE_VFIFO_DEBUG)
if (UART_DEBUG_EVT(DBG_EVT_DMA) && UART_DEBUG_EVT(DBG_EVT_BUF)) {
char str[4] = { 0 };
if (count >= 4) {
str[0] = vfifo->cur->dat[0];
str[1] = vfifo->cur->dat[1];
str[2] = vfifo->cur->dat[vfifo->cur->idx - 2];
str[3] = vfifo->cur->dat[vfifo->cur->idx - 1];
} else {
int idx;
for (idx = 0; idx < count; idx++)
str[idx] = vfifo->cur->dat[idx];
for (; idx < 4; idx++)
str[idx] = 0;
}
MSG(DMA, "RX[%4d]: [%5X..%5X] [%5X..%5X] (%02X %02X .. %02X %02X) [%d]\n",
left, rxreg, txreg, UART_READ32(VFF_RPT(base)), UART_READ32(VFF_WPT(base)),
str[0], str[1], str[2], str[3], UART_READ32(VFF_FLUSH(base)));
} else {
MSG(DMA, "RX[%4d]: [%5X..%5X] [%5X..%5X] [%d] [%4X.%4X]\n",
left, rxreg, txreg, UART_READ32(VFF_RPT(base)), UART_READ32(VFF_WPT(base)),
UART_READ32(VFF_FLUSH(base)), UART_READ32(VFF_VALID_SIZE(base)), UART_READ32(VFF_LEFT_SIZE(base)));
}
#endif
spin_unlock_irqrestore(&port->lock, flags);
#if defined(ENABLE_VFIFO_DEBUG)
if (UART_DEBUG_EVT(DBG_EVT_DAT) && UART_DEBUG_EVT(DBG_EVT_BUF)) {
int i;
pr_debug("[UART%d_RX] %4d bytes:", uart->nport, vfifo->cur->idx);
for (i = 0; i < vfifo->cur->idx; i++) {
if (i % 16 == 0)
pr_debug("\n");
pr_debug("%.2x ", (unsigned char)vfifo->cur->dat[i]);
}
pr_debug("\n");
}
#endif
}
/*---------------------------------------------------------------------------*/
void mtk_uart_dma_vfifo_rx_tasklet(unsigned long arg)
{ /*the function will be called through dma irq or tasklet_schedule */
struct mtk_uart *uart = (struct mtk_uart *)arg;
struct mtk_uart_vfifo *vfifo = uart->rx_vfifo;
unsigned long flags;
MSG(DMA, "%d, %x, %x\n", uart->read_allow(uart), UART_READ32(VFF_VALID_SIZE(vfifo->base)), vfifo->trig);
spin_lock_irqsave(&vfifo->iolock, flags);
atomic_inc(&vfifo->entry);
if (uart->read_allow(uart))
mtk_uart_dma_vfifo_rx_tasklet_str(arg);
atomic_dec(&vfifo->entry);
spin_unlock_irqrestore(&vfifo->iolock, flags);
}
/*---------------------------------------------------------------------------*/
void mtk_uart_dma_setup(struct mtk_uart *uart, struct mtk_uart_dma *dma)
{
void *base;
if (!dma)
return;
if (dma->mode == UART_RX_VFIFO_DMA || dma->mode == UART_TX_VFIFO_DMA) {
if (!dma->vfifo) {
MSG(ERR, "null\n");
return;
}
base = dma->vfifo->base;
reg_sync_writel(dma->vfifo->dmahd, VFF_ADDR(base));
reg_sync_writel(dma->vfifo->trig, VFF_THRE(base));
reg_sync_writel(dma->vfifo->size, VFF_LEN(base));
if (enable_4G())
reg_sync_writel(0x01, VFF_4G_DRAM_SUPPORT(base));
if (dma->vfifo->type == UART_RX_VFIFO)
/* reg_sync_writel(VFF_RX_INT_EN0_B, VFF_INT_EN(base)); */
reg_sync_writel(VFF_RX_INT_EN0_B | VFF_RX_INT_EN1_B, VFF_INT_EN(base));
mb();
}
}
/*---------------------------------------------------------------------------*/
int mtk_uart_dma_start(struct mtk_uart *uart, struct mtk_uart_dma *dma)
{
void *base;
MSG_FUNC_ENTRY();
if (!dma)
return -1;
if (!atomic_read(&dma->free))
return -1;
if (dma->mode == UART_TX_VFIFO_DMA || dma->mode == UART_RX_VFIFO_DMA) {
if (!dma->vfifo) {
MSG(ERR, "null\n");
return -EINVAL;
}
base = dma->vfifo->base;
reg_sync_writel(VFF_INT_FLAG_CLR_B, VFF_INT_FLAG(base));
reg_sync_writel(VFF_EN_B, VFF_EN(base));
if (UART_READ32(VFF_EN(base)) != VFF_EN_B)
MSG(ERR, "Start DMA fail\n");
}
atomic_set(&dma->free, 0);
init_completion(&dma->done);
return 0;
}
/*---------------------------------------------------------------------------*/
void mtk_uart_stop_dma(struct mtk_uart_dma *dma)
{
int polling_cnt = 0;
struct mtk_uart *uart = dma->uart;
void *base;
if (dma->mode == UART_RX_VFIFO_DMA || dma->mode == UART_TX_VFIFO_DMA) {
MSG(DMA, "stop dma (%d)\n", dma->mode);
if (!dma->vfifo) {
MSG(ERR, "null\n");
return;
}
base = dma->vfifo->base;
/*set flush as 1 -> wait until flush is 0 */
reg_sync_writel(VFF_FLUSH_CLR_B, VFF_FLUSH(base));
while (UART_READ32(VFF_FLUSH(base))) {
polling_cnt++;
if (polling_cnt > 10000) {
pr_debug("mtk_uart_stop_dma: polling VFF_FLUSH fail VFF_DEBUG_STATUS=0x%x\n",
UART_READ32(VFF_DEBUG_STATUS(base)));
break;
}
}
polling_cnt = 0;
/*set stop as 1 -> wait until en is 0 -> set stop as 0 */
reg_sync_writel(VFF_STOP_B, VFF_STOP(base));
while (UART_READ32(VFF_EN(base))) {
polling_cnt++;
if (polling_cnt > 10000) {
pr_debug("mtk_uart_stop_dma: polling VFF_EN fail VFF_DEBUG_STATUS=0x%x\n",
UART_READ32(VFF_DEBUG_STATUS(base)));
break;
}
}
reg_sync_writel(VFF_STOP_CLR_B, VFF_STOP(base));
reg_sync_writel(VFF_INT_EN_CLR_B, VFF_INT_EN(base));
reg_sync_writel(VFF_INT_FLAG_CLR_B, VFF_INT_FLAG(base));
} else {
MSG(ERR, "unknown mode: %d\n", dma->mode);
}
}
/*---------------------------------------------------------------------------*/
void mtk_uart_reset_dma(struct mtk_uart_dma *dma)
{
struct mtk_uart *uart = dma->uart;
void *base;
if (dma->mode == UART_RX_VFIFO_DMA || dma->mode == UART_TX_VFIFO_DMA) {
if (!dma->vfifo) {
MSG(ERR, "null\n");
return;
}
base = dma->vfifo->base;
/* mt65xx_req_vff_dma(dma->vfifo->ch, NULL, NULL); */
reg_sync_writel(0, VFF_ADDR(base));
reg_sync_writel(0, VFF_THRE(base));
reg_sync_writel(0, VFF_LEN(base));
/*set warm_rst as 1 -> wait until en is 0 */
reg_sync_writel(VFF_WARM_RST_B, VFF_RST(base));
while (UART_READ32(VFF_EN(base)))
;
/* Reset write point for tx dma */
if (dma->mode == UART_TX_VFIFO_DMA)
reg_sync_writel(0, VFF_WPT(base));
else if (dma->mode == UART_RX_VFIFO_DMA)
reg_sync_writel(0, VFF_RPT(base));
} else
MSG(ERR, "unknown mode: %d\n", dma->mode);
}
#endif /*defined(ENABLE_VFIFO) */
/*---------------------------------------------------------------------------*/
void mtk_uart_fifo_init(struct mtk_uart *uart)
{
/*
* NOTE: For FCR is a read only register reason,
* special read/write/set/clr function need to use
*/
/* UART_SET_BITS(UART_FCR_FIFO_INIT, UART_FCR); */
__set_fcr_register(uart, UART_FCR_FIFO_INIT);
mb();
}
/*---------------------------------------------------------------------------*/
void mtk_uart_fifo_flush(struct mtk_uart *uart)
{
/*
* NOTE: For FCR is a read only register reason,
* special read/write/set/clr function need to use
*/
/* UART_SET_BITS(UART_FCR_CLRR | UART_FCR_CLRT, UART_FCR); */
__set_fcr_register(uart, UART_FCR_CLRR | UART_FCR_CLRT);
mb();
}
/*---------------------------------------------------------------------------*/
int mtk_uart_data_ready(struct mtk_uart *uart)
{
if ((uart->read_status(uart) & UART_LSR_DR))
return 1;
else
return 0;
}
/*---------------------------------------------------------------------------*/
void mtk_uart_fifo_set_trig(struct mtk_uart *uart, int tx_level, int rx_level)
{
unsigned long base = uart->base;
unsigned long tmp1;
unsigned long flags;
tmp1 = UART_READ32(UART_LCR);
spin_lock_irqsave(&mtk_console_lock, flags);
reg_sync_writel(0xbf, UART_LCR);
UART_SET_BITS(UART_EFR_EN, UART_EFR);
reg_sync_writel(tmp1, UART_LCR);
spin_unlock_irqrestore(&mtk_console_lock, flags);
MSG(INFO, "%s(EFR) = %04X\n", __func__, UART_READ32(UART_EFR));
/*
* NOTE: For FCR is a read only register reason,
* special read/write/set/clr function need to use
*/
/* reg_sync_writel(UART_FCR_FIFO_INIT|tx_level|rx_level, UART_FCR); */
sync_write_fcr_register(uart, UART_FCR_FIFO_INIT | tx_level | rx_level);
}
/*---------------------------------------------------------------------------*/
void mtk_uart_set_mode(struct mtk_uart *uart, int mode)
{
/*
* NOTE: For FCR is a read only register reason,
* special read/write/set/clr function need to use
*/
if (mode == UART_DMA_MODE_0) {
/* UART_CLR_BITS(UART_FCR_DMA1, UART_FCR); */
__clr_fcr_register(uart, UART_FCR_DMA1);
} else if (mode == UART_DMA_MODE_1) {
/* UART_SET_BITS(UART_FCR_DMA1, UART_FCR); */
__set_fcr_register(uart, UART_FCR_DMA1);
}
mb();
}
/*---------------------------------------------------------------------------*/
void mtk_uart_set_auto_baud(struct mtk_uart *uart)
{
unsigned long base = uart->base;
MSG_FUNC_ENTRY();
switch (uart->sysclk) {
case MTK_SYSCLK_13:
reg_sync_writel(UART_AUTOBADUSAM_13M, UART_AUTOBAUD_SAMPLE);
break;
case MTK_SYSCLK_26:
reg_sync_writel(UART_AUTOBADUSAM_26M, UART_AUTOBAUD_SAMPLE);
break;
case MTK_SYSCLK_52:
reg_sync_writel(UART_AUTOBADUSAM_52M, UART_AUTOBAUD_SAMPLE);
break;
default:
pr_notice("SYSCLK = %ldMHZ doesn't support autobaud\n", uart->sysclk);
return;
}
reg_sync_writel(0x01, UART_AUTOBAUD_EN); /* Enable Auto Baud */
}
/*---------------------------------------------------------------------------*/
static void mtk_uart_cal_baud(struct mtk_uart *uart, int baudrate, int highspeed)
{
unsigned long base = uart->base;
u32 remainder, uartclk = 0, divisor = 0;
u32 lcr = UART_READ32(UART_LCR);
unsigned long flags;
#ifdef UART_USING_FIX_CLK_ENABLE
if (baudrate <= 1000000) { /* Using 16.25 fix clock */
uartclk = uart->sysclk >> 2;
reg_sync_writel(0x03, UART_RATE_FIX_AD);
} else { /* >1M, Using 65 clock */
uartclk = uart->sysclk;
reg_sync_writel(0x00, UART_RATE_FIX_AD);
}
if (highspeed == 3)
UART_SET_BITS(UART_MCR_DCM_EN, UART_MCR); /* Enable UART DCM */
else
UART_CLR_BITS(UART_MCR_DCM_EN, UART_MCR); /* Disable UART DCM */
#else /* UART_Fix_clk_DISABLE */
uartclk = uart->sysclk;
reg_sync_writel(0x00, UART_RATE_FIX_AD);
#endif /* UART_USING_FIX_CLK_ENABLE */
spin_lock_irqsave(&mtk_console_lock, flags);
if (highspeed == 0) {
/* uartclk = uart->sysclk; */
/* reg_sync_writel(0x00, UART_RATE_FIX_AD); */
reg_sync_writel(0x00, UART_HIGHSPEED); /*divider is 16 */
divisor = (uartclk >> 4) / (u32) baudrate;
remainder = (uartclk >> 4) % (u32) baudrate;
if (remainder >= (u32) (baudrate * 8))
divisor += 1;
reg_sync_writel(lcr | UART_LCR_DLAB, UART_LCR);
reg_sync_writel((divisor & 0xFF), UART_DLL);
reg_sync_writel(((divisor >> 8) & 0xFF), UART_DLH);
reg_sync_writel(lcr, UART_LCR);
} else if (highspeed == 1) {
/* uartclk = uart->sysclk; */
/* reg_sync_writel(0x00, UART_RATE_FIX_AD); */
reg_sync_writel(0x01, UART_HIGHSPEED); /*divider is 8 */
divisor = (uartclk >> 3) / (u32) baudrate;
remainder = (uartclk >> 3) % (u32) baudrate;
if (remainder >= (u32) (baudrate * 4))
divisor += 1;
reg_sync_writel(lcr | UART_LCR_DLAB, UART_LCR);
reg_sync_writel((divisor & 0xFF), UART_DLL);
reg_sync_writel(((divisor >> 8) & 0xFF), UART_DLH);
reg_sync_writel(lcr, UART_LCR);
} else if (highspeed == 2) {
/* uartclk = uart->sysclk; */
/* reg_sync_writel(0x00, UART_RATE_FIX_AD); */
reg_sync_writel(0x02, UART_HIGHSPEED); /*divider is 4 */
divisor = (uartclk >> 2) / (u32) baudrate;
remainder = (uartclk >> 2) % (u32) baudrate;
if (remainder >= (u32) (baudrate * 2))
divisor += 1;
reg_sync_writel(lcr | UART_LCR_DLAB, UART_LCR);
reg_sync_writel((divisor & 0x00FF), UART_DLL);
reg_sync_writel(((divisor >> 8) & 0x00FF), UART_DLH);
reg_sync_writel(lcr, UART_LCR);
} else if (highspeed == 3) {
u32 sample_count, sample_point, high_div, tmp;
#if defined(ENABLE_FRACTIONAL)
u32 fraction;
u16 fraction_L_mapping[] = { 0, 1, 0x5, 0x15, 0x55, 0x57, 0x57, 0x77, 0x7F, 0xFF, 0xFF };
u16 fraction_M_mapping[] = { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0x3 };
#endif
/* uartclk = uart->sysclk; */
/* reg_sync_writel(0x00, UART_RATE_FIX_AD); */
reg_sync_writel(0x03, UART_HIGHSPEED);
tmp = (uartclk) / (u32) baudrate;
high_div = (tmp >> 8) + 1;
divisor = (uartclk) / (baudrate * high_div);
#if defined(ENABLE_FRACTIONAL)
fraction = ((uartclk * 10) / baudrate) % 10; /*count fraction to set fractoin register */
reg_sync_writel(fraction_L_mapping[fraction], UART_FRACDIV_L);
reg_sync_writel(fraction_M_mapping[fraction], UART_FRACDIV_M);
#else
remainder = (uartclk) % (baudrate * high_div);
if (remainder >= ((baudrate * high_div) >> 1))
divisor += 1;
#endif
sample_count = divisor - 1;
sample_point = (sample_count - 1) >> 1;
reg_sync_writel(lcr | UART_LCR_DLAB, UART_LCR);
reg_sync_writel((high_div & 0x00FF), UART_DLL);
reg_sync_writel(((high_div >> 8) & 0x00FF), UART_DLH);
reg_sync_writel(lcr, UART_LCR);
reg_sync_writel(sample_count, UART_SAMPLE_COUNT);
reg_sync_writel(sample_point, UART_SAMPLE_POINT);
/*
* NOTICE: We found some chip, that is using lower clock, may not have enough time to check stop bit.
* In order to improve compatibility, the guard time register
* is enabled which is used to extend the stop bit.
*/
if (baudrate >= 3000000)
reg_sync_writel(0x12, UART_GUARD);
}
spin_unlock_irqrestore(&mtk_console_lock, flags);
MSG(CFG, "BaudRate = %d, SysClk = %d, Divisor = %d, %04X/%04X\n", baudrate, uartclk, divisor,
UART_READ32(UART_IER), UART_READ32(UART_LCR));
dump_reg(uart, __func__);
mb(); /*to ensure the setting is written */
}
/*---------------------------------------------------------------------------*/
void mtk_uart_baud_setting(struct mtk_uart *uart, int baudrate)
{
u32 uartclk;
#if defined(CONFIG_FPGA_EARLY_PORTING)
u32 tmp_div;
#endif
uartclk = uart->sysclk;
#if defined(CONFIG_FPGA_EARLY_PORTING)
tmp_div = (uartclk) / (unsigned int)baudrate;
if (tmp_div > 255)
mtk_uart_cal_baud(uart, baudrate, 2);
else
mtk_uart_cal_baud(uart, baudrate, 3);
#else
/* Fix clock, using new settings */
#ifdef UART_USING_FIX_CLK_ENABLE
if (baudrate < 115200)
mtk_uart_cal_baud(uart, baudrate, 0);
else
mtk_uart_cal_baud(uart, baudrate, 3);
#else /* UART_Fix_Clock_DISABLE */
if (baudrate <= 115200)
mtk_uart_cal_baud(uart, baudrate, 0);
else if (baudrate <= 460800)
mtk_uart_cal_baud(uart, baudrate, 2);
else
mtk_uart_cal_baud(uart, baudrate, 3);
#endif /* End of UART_DCM_CONFIG */
#endif
}
/*---------------------------------------------------------------------------*/
#if defined(ENABLE_DEBUG)
/*---------------------------------------------------------------------------*/
static u32 UART_READ_EFR(struct mtk_uart *uart)
{
unsigned long base = uart->base;
u32 efr, lcr = UART_READ32(UART_LCR);
unsigned long flags;
spin_lock_irqsave(&mtk_console_lock, flags);
reg_sync_writel(0xbf, UART_LCR);
efr = UART_READ32(UART_EFR);
reg_sync_writel(lcr, UART_LCR);
spin_unlock_irqrestore(&mtk_console_lock, flags);
return efr;
}
/*---------------------------------------------------------------------------*/
#endif
/*---------------------------------------------------------------------------*/
void mtk_uart_set_flow_ctrl(struct mtk_uart *uart, int mode)
{
unsigned long base = uart->base, old;
unsigned int tmp = UART_READ32(UART_LCR);
unsigned long flags;
MSG(CFG, "%s: %04X\n", __func__, UART_READ_EFR(uart));
spin_lock_irqsave(&mtk_console_lock, flags);
switch (mode) {
case UART_FC_NONE:
reg_sync_writel(UART_ESCAPE_CH, UART_ESCAPE_DAT);
reg_sync_writel(0x00, UART_ESCAPE_EN);
reg_sync_writel(0xbf, UART_LCR);
old = UART_READ32(UART_EFR);
old &= ~(UART_EFR_AUTO_RTSCTS | UART_EFR_XON12_XOFF12);
reg_sync_writel(old, UART_EFR);
reg_sync_writel(tmp, UART_LCR);
mtk_uart_disable_intrs(uart, UART_IER_XOFFI | UART_IER_RTSI | UART_IER_CTSI);
break;
case UART_FC_HW:
reg_sync_writel(UART_ESCAPE_CH, UART_ESCAPE_DAT);
reg_sync_writel(0x00, UART_ESCAPE_EN);
UART_SET_BITS(UART_MCR_RTS, UART_MCR);
reg_sync_writel(0xbf, UART_LCR);
/*disable all flow control setting */
old = UART_READ32(UART_EFR);
old &= ~(UART_EFR_AUTO_RTSCTS | UART_EFR_XON12_XOFF12);
reg_sync_writel(old, UART_EFR);
/*enable hw flow control */
old = UART_READ32(UART_EFR);
reg_sync_writel(old | UART_EFR_AUTO_RTSCTS, UART_EFR);
reg_sync_writel(tmp, UART_LCR);
mtk_uart_disable_intrs(uart, UART_IER_XOFFI);
mtk_uart_enable_intrs(uart, UART_IER_CTSI | UART_IER_RTSI);
break;
case UART_FC_SW: /*MTK software flow control */
reg_sync_writel(UART_ESCAPE_CH, UART_ESCAPE_DAT);
reg_sync_writel(0x01, UART_ESCAPE_EN);
reg_sync_writel(0xbf, UART_LCR);
/*dsiable all flow control setting */
old = UART_READ32(UART_EFR);
old &= ~(UART_EFR_AUTO_RTSCTS | UART_EFR_XON12_XOFF12);
reg_sync_writel(old, UART_EFR);
/*enable sw flow control */
old = UART_READ32(UART_EFR);
reg_sync_writel(old | UART_EFR_XON1_XOFF1, UART_EFR);
reg_sync_writel(START_CHAR(uart->port.state->port.tty), UART_XON1);
reg_sync_writel(STOP_CHAR(uart->port.state->port.tty), UART_XOFF1);
reg_sync_writel(tmp, UART_LCR);
mtk_uart_disable_intrs(uart, UART_IER_CTSI | UART_IER_RTSI);
mtk_uart_enable_intrs(uart, UART_IER_XOFFI);
break;
}
spin_unlock_irqrestore(&mtk_console_lock, flags);
mb(); /*to ensure the setting is written */
uart->fctl_mode = mode;
}
/*---------------------------------------------------------------------------*/
void mtk_uart_power_up(struct mtk_uart *uart)
{
#ifndef CONFIG_FPGA_EARLY_PORTING
struct mtk_uart_setting *setting;
int clk_en_ret = 0;
static DEFINE_RATELIMIT_STATE(ratelimit, 5 * HZ, 5);
if (!uart || uart->nport >= UART_NR)
return;
setting = uart->setting;
if (uart->poweron_count > 0) {
MSG(FUC, "%s(%d)\n", __func__, uart->poweron_count);
} else {
#ifdef POWER_FEATURE
clk_en_ret = clk_enable(setting->clk_uart_main);
if (clk_en_ret) {
pr_notice("[UART%d][CCF]enable clk_uart_main failed. ret:%d, clk_main:%p\n", uart->nport,
clk_en_ret, setting->clk_uart_main);
} else {
if (__ratelimit(&ratelimit)) {
pr_debug("[UART%d][CCF]enabled clk_uart_main:%p\n", uart->nport,
setting->clk_uart_main);
}
if ((uart != console_port)
&& (uart->tx_mode == UART_TX_VFIFO_DMA || uart->rx_mode == UART_RX_VFIFO_DMA)) {
clk_en_ret = clk_enable(clk_uart_dma);
if (clk_en_ret) {
pr_notice("[UART%d][CCF]enable clk_uart_main failed. ret:%d, clk_dma:%p\n",
uart->nport, clk_en_ret, clk_uart_dma);
} else {
pr_debug("[UART%d][CCF]enabled clk_uart_dma:%p\n", uart->nport, clk_uart_dma);
}
}
}
uart->poweron_count++;
#endif
}
MSG(FUC, "%s(%d) => up\n", __func__, uart->poweron_count);
#endif /* End of CONFIG_FPGA_EARLY_PORTING */
}
/*---------------------------------------------------------------------------*/
void mtk_uart_power_down(struct mtk_uart *uart)
{
#ifndef CONFIG_FPGA_EARLY_PORTING
struct mtk_uart_setting *setting;
static DEFINE_RATELIMIT_STATE(ratelimit, 5 * HZ, 5);
setting = uart->setting;
if (uart->nport >= UART_NR)
return;
if (uart->poweron_count == 0) {
MSG(FUC, "%s(%d)\n", __func__, uart->poweron_count);
} else {
#ifdef POWER_FEATURE
if (__ratelimit(&ratelimit)) {
pr_debug("[UART%d][CCF]disable clk_uart_main:%p\n", uart->nport,
setting->clk_uart_main);
}
clk_disable(setting->clk_uart_main);
if ((uart != console_port)
&& (uart->tx_mode == UART_TX_VFIFO_DMA || uart->rx_mode == UART_RX_VFIFO_DMA)) {
clk_disable(clk_uart_dma);
pr_debug("[UART%d][CCF]disable clk_uart_dma:%p\n", uart->nport, clk_uart_dma);
}
uart->poweron_count--;
#endif
MSG(FUC, "%s(%d) => dn\n", __func__, uart->poweron_count);
}
#endif /* End of CONFIG_FPGA_EARLY_PORTING */
}
/*---------------------------------------------------------------------------*/
void mtk_uart_config(struct mtk_uart *uart, int datalen, int stop, int parity)
{
unsigned long base = uart->base;
unsigned int val = 0;
switch (datalen) {
case 5:
val |= UART_WLS_5;
break;
case 6:
val |= UART_WLS_6;
break;
case 7:
val |= UART_WLS_7;
break;
case 8:
default:
val |= UART_WLS_8;
break;
}
if (stop == 2 || (datalen == 5 && stop == 1))
val |= UART_2_STOP;
if (parity == 1)
val |= UART_ODD_PARITY;
else if (parity == 2)
val |= UART_EVEN_PARITY;
reg_sync_writel(val, UART_LCR);
}
/*---------------------------------------------------------------------------*/
unsigned int mtk_uart_read_status(struct mtk_uart *uart)
{
unsigned long base = uart->base;
uart->line_status = UART_READ32(UART_LSR);
return uart->line_status;
}
/*---------------------------------------------------------------------------*/
unsigned int mtk_uart_read_allow(struct mtk_uart *uart)
{
return uart->line_status & UART_LSR_DR;
}
/*---------------------------------------------------------------------------*/
/* Note:
* 1. FIFO mode:
* -THRE=1 : when free space in FIFO is reduced blow its trigger level
* -THRE=0 : when free space in FIFO is more than its trigger level
* 2. non-FIFO mode:
* -THRE=1 : when tx holding register is empty
* -THRE=0 : when tx holding register is not empty
*/
unsigned int mtk_uart_write_allow(struct mtk_uart *uart)
{
unsigned long base = uart->base;
return UART_READ32(UART_LSR) & UART_LSR_THRE;
}
/*---------------------------------------------------------------------------*/
void mtk_uart_enable_intrs(struct mtk_uart *uart, long mask)
{ /*assume UART_EFR_EN is on */
unsigned long base = uart->base;
UART_SET_BITS(mask, UART_IER);
mb();
}
/*---------------------------------------------------------------------------*/
void mtk_uart_disable_intrs(struct mtk_uart *uart, long mask)
{ /*assume UART_EFR_EN is on */
unsigned long base = uart->base;
UART_CLR_BITS(mask, UART_IER);
mb();
}
/*---------------------------------------------------------------------------*/
unsigned int mtk_uart_read_byte(struct mtk_uart *uart)
{
unsigned long base = uart->base;
return UART_READ32(UART_RBR);
}
/*---------------------------------------------------------------------------*/
void mtk_uart_write_byte(struct mtk_uart *uart, unsigned int byte)
{
unsigned long base = uart->base;
reg_sync_writel(byte, UART_THR);
}
/*---------------------------------------------------------------------------*/
void mtk_uart_usb_rx_sel(unsigned int uart_port, unsigned int enable)
{
unsigned long base = mtk_uart_default_settings[uart_port - 1].uart_base;
reg_sync_writel(enable, UART_RX_SEL);
}
/*---------------------------------------------------------------------------*/
unsigned int mtk_uart_filter_line_status(struct mtk_uart *uart)
{
struct uart_port *port = &uart->port;
unsigned int status;
unsigned int lsr = uart->line_status;
mtk_uart_lsr_status[uart->nport] |= lsr;
status = UART_LSR_BI | UART_LSR_PE | UART_LSR_FE | UART_LSR_OE;
#ifdef ENABLE_DEBUG
if ((lsr & UART_LSR_BI) || (lsr & UART_LSR_PE) || (lsr & UART_LSR_FE) || (lsr & UART_LSR_OE)) {
MSG(ERR, "LSR: BI=%d, FE=%d, PE=%d, OE=%d, DR=%d\n",
(lsr & UART_LSR_BI) >> 4, (lsr & UART_LSR_FE) >> 3,
(lsr & UART_LSR_PE) >> 2, (lsr & UART_LSR_OE) >> 1, lsr & UART_LSR_DR);
}
#endif
status &= port->read_status_mask;
status &= ~port->ignore_status_mask;
status &= lsr;
return status;
}
/*---------------------------------------------------------------------------*/
int mtk_uart_get_interrupt(struct mtk_uart *uart)
{
unsigned int intrs;
unsigned long base = uart->base;
intrs = UART_READ32(UART_IIR);
return intrs;
}
/*---------------------------------------------------------------------------*/
void mtk_uart_intr_last_check(struct mtk_uart *uart, int intrs)
{
}
/*---------------------------------------------------------------------------*/
void mtk_uart_get_modem_status(struct mtk_uart *uart)
{
unsigned long base = uart->base;
struct uart_port *port = &uart->port;
unsigned int status, delta;
status = UART_READ32(UART_MSR);
status &= UART_MSR_DSR | UART_MSR_CTS | UART_MSR_DCD | UART_MSR_RI;
MSG(INFO, "MSR: DCD(%d), RI(%d), DSR(%d), CTS(%d)\n",
status & UART_MSR_DCD ? 1 : 0,
status & UART_MSR_RI ? 1 : 0, status & UART_MSR_DSR ? 1 : 0, status & UART_MSR_CTS ? 1 : 0);
delta = status ^ uart->old_status;
if (!delta)
return;
if (uart->ms_enable) {
if (delta & UART_MSR_DCD)
uart_handle_dcd_change(port, status & UART_MSR_DCD);
if (delta & UART_MSR_CTS)
uart_handle_cts_change(port, status & UART_MSR_CTS);
if (delta & UART_MSR_DSR)
port->icount.dsr++;
if (delta & UART_MSR_RI)
port->icount.rng++;
}
uart->old_status = status;
}
/*---------------------------------------------------------------------------*/
void mtk_uart_rx_pre_handler(struct mtk_uart *uart, int intrs)
{
unsigned long base = uart->base;
u32 tmp, lsr_status;
if (intrs == UART_IIR_CTI) {
/* IMPORTANT: this is a fix for HW Bug.
* Without the function call, the RX data timeout interrupt will be
* triggered again and again.Hence, the purpose of this function call
* is to clear Rx data timeout interrupt
*/
tmp = UART_READ32(UART_DMA_EN);
#if defined(ENABLE_VFIFO)
MSG(DMA, "rx timeout: %x, %4d\n", tmp, mtk_uart_vfifo_get_counts(uart->rx_vfifo));
#endif
/* mtk_uart_dma_vfifo_rx_tasklet((unsigned long)uart); */
} else if ((intrs == UART_IIR_RLS) && !uart->read_allow(uart)) {
tmp = UART_READ32(UART_LSR);
MSG(DMA, "LSR=%X\n", tmp);
lsr_status = get_uart_lsr_status(uart->nport);
lsr_status |= tmp;
set_uart_lsr_status(uart->nport, lsr_status);
} else {
#if defined(ENABLE_VFIFO)
MSG(DMA, "RX = %4d, [%4x]\n", mtk_uart_vfifo_get_counts(uart->rx_vfifo), intrs);
#endif
}
}
/* set the modem control lines. */
void mtk_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct mtk_uart *uart = (struct mtk_uart *)port;
unsigned long base = uart->base;
unsigned int val;
val = UART_READ32(UART_MCR);
if (mctrl & TIOCM_DTR)
val |= UART_MCR_DTR;
else
val &= ~UART_MCR_DTR;
if (mctrl & TIOCM_RTS)
val |= UART_MCR_RTS;
else
val &= ~UART_MCR_RTS;
if (mctrl & TIOCM_OUT1)
val |= UART_MCR_OUT1;
else
val &= ~UART_MCR_OUT1;
if (mctrl & TIOCM_OUT2)
val |= UART_MCR_OUT2;
else
val &= ~UART_MCR_OUT2;
if (mctrl & TIOCM_LOOP)
val |= UART_MCR_LOOP;
else
val &= ~UART_MCR_LOOP;
reg_sync_writel(val, UART_MCR);
MSG(CFG, "MCR: DTR(%d), RTS(%d), OUT1(%d), OUT2(%d), LOOP(%d)\n",
val & UART_MCR_DTR ? 1 : 0,
val & UART_MCR_RTS ? 1 : 0,
val & UART_MCR_OUT1 ? 1 : 0, val & UART_MCR_OUT2 ? 1 : 0, val & UART_MCR_LOOP ? 1 : 0);
}
/*---------------------------------------------------------------------------*/
/* return the current state of modem contrl inputs */
unsigned int mtk_uart_get_mctrl(struct uart_port *port)
{
struct mtk_uart *uart = (struct mtk_uart *)port;
unsigned long base = uart->base;
unsigned int status;
unsigned int result = 0;
status = UART_READ32(UART_MSR);
MSG(INFO, "MSR: DCD(%d), RI(%d), DSR(%d), CTS(%d)\n",
status & UART_MSR_DCD ? 1 : 0,
status & UART_MSR_RI ? 1 : 0, status & UART_MSR_DSR ? 1 : 0, status & UART_MSR_CTS ? 1 : 0);
if (status & UART_MSR_DCD)
result |= TIOCM_CAR; /* DCD. (data carrier detect) */
if (status & UART_MSR_RI)
result |= TIOCM_RI;
if (status & UART_MSR_DSR)
result |= TIOCM_DSR;
if (status & UART_MSR_CTS)
result |= TIOCM_CTS;
status = UART_READ32(UART_MCR);
MSG(INFO, "MSR: OUT1(%d), OUT2(%d), LOOP(%d)\n",
status & UART_MCR_OUT1 ? 1 : 0, status & UART_MCR_OUT2 ? 1 : 0, status & UART_MCR_LOOP ? 1 : 0);
if (status & UART_MCR_OUT2)
result |= TIOCM_OUT2;
if (status & UART_MCR_OUT1)
result |= TIOCM_OUT1;
if (status & UART_MCR_LOOP)
result |= TIOCM_LOOP;
return result;
}
/*---------------------------------------------------------------------------*/
/* stop receiving characters
* note: port->lock has been taken by serial core layer
*/
void mtk_uart_stop_rx(struct uart_port *port)
{
struct mtk_uart *uart = (struct mtk_uart *)port;
struct mtk_uart_dma *dma = &uart->dma_rx;
MSG_FUNC_ENTRY();
if (uart->rx_mode == UART_NON_DMA) {
mtk_uart_disable_intrs(uart, UART_IER_ERBFI);
} else {
#if defined(ENABLE_VFIFO)
/* According to serial_core.c, stop_rx is to stop interrupt
* Hence, RX received interrupt and dma interrupt is clear
*/
mtk_uart_disable_intrs(uart, UART_IER_ERBFI);
reg_sync_writel(VFF_INT_EN_CLR_B, VFF_INT_EN(dma->vfifo->base));
atomic_set(&dma->free, 1);
complete(&dma->done);
#endif
}
uart->rx_stop = 1;
}
/*---------------------------------------------------------------------------*/
/* control the transmission of a break signal */
void mtk_uart_break_ctl(struct uart_port *port, int break_state)
{
struct mtk_uart *uart = (struct mtk_uart *)port;
unsigned long base = uart->base;
unsigned long flags;
MSG_FUNC_ENTRY();
spin_lock_irqsave(&port->lock, flags);
if (break_state)
UART_SET_BITS(UART_LCR_BREAK, UART_LCR);
else
UART_CLR_BITS(UART_LCR_BREAK, UART_LCR);
mb();
spin_unlock_irqrestore(&port->lock, flags);
}
/*---------------------------------------------------------------------------*/
#ifdef ATE_FACTORY_ENABLE
void mtk_uart_is_ate_factory_mode(struct mtk_uart *uart)
{
if ((uart->nport == 0) && (get_boot_mode() == ATE_FACTORY_MODE)) {
unsigned long base = uart->base;
/* MD may set these bit, reset it */
UART_CLR_BITS(UART_RX_DMA_EN | UART_TO_CNT_AUTORST | UART_TX_DMA_EN, UART_DMA_EN);
mb();
}
}
#endif /* ATE_FACTORY_ENABLE */
/*---------------------------------------------------------------------------*/
void mtk_uart_enable_sleep(struct mtk_uart *uart)
{
unsigned long base = uart->base;
reg_sync_writel(0x1, UART_SLEEP_EN);
pr_debug("SLEEP_EN = 0x%x\n", UART_READ32(UART_SLEEP_EN));
}
/*---------------------------------------------------------------------------*/
#ifdef ENABLE_RAW_DATA_DUMP
void mtk_uart_init_debug_spinlock(void)
{
spin_lock_init(&tx_history_lock);
spin_lock_init(&rx_history_lock);
}
void reset_tx_raw_data(struct mtk_uart *uart)
{
unsigned long flags;
if (uart->nport == 2) {
spin_lock_irqsave(&tx_history_lock, flags);
if (!stop_update) {
curr_record++;
curr_idx = 0;
if (curr_record >= RECORD_NUMBER)
curr_record = 0;
uart_history_cnt[curr_record] = 0;
for (curr_idx = 0; curr_idx < RECORD_LENGTH; curr_idx++)
uart_history[curr_record][curr_idx] = 0;
curr_idx = 0;
}
spin_unlock_irqrestore(&tx_history_lock, flags);
}
}
static void save_tx_raw_data(struct mtk_uart *uart, void *addr)
{
unsigned long flags;
if (uart->nport == 2) {
spin_lock_irqsave(&tx_history_lock, flags);
if (!stop_update) {
if (curr_idx < RECORD_LENGTH) {
uart_history[curr_record][curr_idx] = UART_READ8(addr);
curr_idx++;
uart_history_cnt[curr_record] = curr_idx;
}
}
spin_unlock_irqrestore(&tx_history_lock, flags);
}
}
static void reset_rx_raw_data(struct mtk_uart *uart)
{
unsigned long flags;
if (uart->nport == 2) {
spin_lock_irqsave(&rx_history_lock, flags);
if (!stop_update) {
curr_rx_record++;
curr_rx_idx = 0;
if (curr_rx_record >= RECORD_NUMBER)
curr_rx_record = 0;
uart_rx_history_cnt[curr_rx_record] = 0;
for (curr_rx_idx = 0; curr_rx_idx < RECORD_LENGTH; curr_rx_idx++)
uart_rx_history[curr_rx_record][curr_rx_idx] = 0;
curr_rx_idx = 0;
}
spin_unlock_irqrestore(&rx_history_lock, flags);
}
}
static void save_rx_raw_data(struct mtk_uart *uart, const unsigned char *chars, size_t size)
{
unsigned long flags;
int i;
if (uart->nport == 2) {
spin_lock_irqsave(&rx_history_lock, flags);
if (!stop_update) {
for (i = 0; (curr_rx_idx < RECORD_LENGTH) && (i < size); i++, curr_rx_idx++)
uart_rx_history[curr_rx_record][curr_rx_idx] = chars[i];
uart_rx_history_cnt[curr_rx_record] = curr_rx_idx;
}
spin_unlock_irqrestore(&rx_history_lock, flags);
}
}
void stop_log(void)
{
unsigned long flags;
unsigned long rx_flags;
spin_lock_irqsave(&tx_history_lock, flags);
spin_lock_irqsave(&rx_history_lock, rx_flags);
stop_update = 1;
spin_unlock_irqrestore(&rx_history_lock, rx_flags);
spin_unlock_irqrestore(&tx_history_lock, flags);
}
EXPORT_SYMBOL(stop_log);
void dump_uart_history(void)
{
int i, j;
unsigned long flags;
unsigned long rx_flags;
int curr, rx_curr;
spin_lock_irqsave(&tx_history_lock, flags);
spin_lock_irqsave(&rx_history_lock, rx_flags);
stop_update = 1;
spin_unlock_irqrestore(&rx_history_lock, rx_flags);
spin_unlock_irqrestore(&tx_history_lock, flags);
curr = curr_record + 1;
if (curr >= RECORD_NUMBER)
curr = 0;
rx_curr = curr_rx_record + 1;
if (rx_curr >= RECORD_NUMBER)
rx_curr = 0;
for (i = 0; i < RECORD_NUMBER; i++) {
pr_debug("\nTX rec%03d:", i);
for (j = 0; j < uart_history_cnt[curr]; j++) {
if ((j % 0xF) == 0)
pr_debug("\n");
pr_debug("%02x ", uart_history[curr][j]);
}
msleep(20);
curr++;
if (curr >= RECORD_NUMBER)
curr = 0;
}
for (i = 0; i < RECORD_NUMBER; i++) {
pr_debug("\nRX rec%03d:", i);
for (j = 0; j < uart_rx_history_cnt[rx_curr]; j++) {
if ((j % 0xF) == 0)
pr_debug("\n");
pr_debug("%02x ", uart_rx_history[rx_curr][j]);
}
msleep(20);
rx_curr++;
if (rx_curr >= RECORD_NUMBER)
rx_curr = 0;
}
}
EXPORT_SYMBOL(dump_uart_history);
#else
void stop_log(void)
{
/* dummy API */
}
void dump_uart_history(void)
{
/* dummy API */
}
#endif
/*---------------------------------------------------------------------------*/
void mtk_uart_save(struct mtk_uart *uart)
{
#ifdef CONFIG_PM
unsigned long base;
unsigned long flags;
/* UART never power on, no need save */
if (uart->poweron_count == 0)
return;
base = uart->base;
/* DLL may be changed by console write. To avoid this, use spinlock */
spin_lock_irqsave(&mtk_console_lock, flags);
uart->registers.lcr = UART_READ32(UART_LCR);
reg_sync_writel(0xbf, UART_LCR);
uart->registers.efr = UART_READ32(UART_EFR);
reg_sync_writel(uart->registers.lcr, UART_LCR);
uart->registers.fcr = UART_READ32(UART_FCR_RD);
/* baudrate */
uart->registers.highspeed = UART_READ32(UART_HIGHSPEED);
uart->registers.fracdiv_l = UART_READ32(UART_FRACDIV_L);
uart->registers.fracdiv_m = UART_READ32(UART_FRACDIV_M);
reg_sync_writel(uart->registers.lcr | UART_LCR_DLAB, UART_LCR);
uart->registers.dll = UART_READ32(UART_DLL);
uart->registers.dlh = UART_READ32(UART_DLH);
reg_sync_writel(uart->registers.lcr, UART_LCR);
uart->registers.sample_count = UART_READ32(UART_SAMPLE_COUNT);
uart->registers.sample_point = UART_READ32(UART_SAMPLE_POINT);
uart->registers.guard = UART_READ32(UART_GUARD);
/* flow control */
uart->registers.escape_en = UART_READ32(UART_ESCAPE_EN);
uart->registers.mcr = UART_READ32(UART_MCR);
uart->registers.ier = UART_READ32(UART_IER);
uart->registers.rx_sel = UART_READ32(UART_RX_SEL);
spin_unlock_irqrestore(&mtk_console_lock, flags);
#endif
}
void mtk_uart_restore(void)
{
#ifdef CONFIG_PM
unsigned long base;
unsigned long flags;
struct mtk_uart *uart;
uart = console_port;
base = uart->base;
mtk_uart_power_up(uart);
spin_lock_irqsave(&mtk_console_lock, flags);
reg_sync_writel(0xbf, UART_LCR);
reg_sync_writel(uart->registers.efr, UART_EFR);
reg_sync_writel(uart->registers.lcr, UART_LCR);
reg_sync_writel(uart->registers.fcr, UART_FCR);
/* baudrate */
reg_sync_writel(uart->registers.highspeed, UART_HIGHSPEED);
reg_sync_writel(uart->registers.fracdiv_l, UART_FRACDIV_L);
reg_sync_writel(uart->registers.fracdiv_m, UART_FRACDIV_M);
reg_sync_writel(uart->registers.lcr | UART_LCR_DLAB, UART_LCR);
reg_sync_writel(uart->registers.dll, UART_DLL);
reg_sync_writel(uart->registers.dlh, UART_DLH);
reg_sync_writel(uart->registers.lcr, UART_LCR);
reg_sync_writel(uart->registers.sample_count, UART_SAMPLE_COUNT);
reg_sync_writel(uart->registers.sample_point, UART_SAMPLE_POINT);
reg_sync_writel(uart->registers.guard, UART_GUARD);
/* flow control */
reg_sync_writel(uart->registers.escape_en, UART_ESCAPE_EN);
reg_sync_writel(uart->registers.mcr, UART_MCR);
reg_sync_writel(uart->registers.ier, UART_IER);
reg_sync_writel(uart->registers.rx_sel, UART_RX_SEL);
spin_unlock_irqrestore(&mtk_console_lock, flags);
#endif
}
#if !defined(CONFIG_MTK_LEGACY) && !defined(CONFIG_FPGA_EARLY_PORTING)
void switch_uart_gpio(int uartport, int gpioopid)
{
struct pinctrl *ppinctrl = NULL;
struct pinctrl_state *pins_uart = NULL;
static DEFINE_RATELIMIT_STATE(ratelimit, 5 * HZ, 5);
if ((uartport >= UART_NR) || (uartport > 3) || (uartport < 0)) {
pr_notice("[UART%d][PinC]%s: port error!!\n", uartport, __func__);
return;
}
ppinctrl = ppinctrl_uart[uartport];
if (IS_ERR(ppinctrl)) {
pr_notice("[UART%d][PinC]%s get pinctrl fail!! err:%ld\n", uartport, __func__, PTR_ERR(ppinctrl));
return;
}
pins_uart = pinctrl_lookup_state(ppinctrl, uart_gpio_cmds[uartport][gpioopid]);
if (IS_ERR(pins_uart)) {
if (__ratelimit(&ratelimit)) {
pr_notice("[UART%d][PinC]%s pinctrl_lockup(%d, %s) fail!! pctrl:%p, err:%ld\n", uartport,
__func__, uartport, uart_gpio_cmds[uartport][gpioopid], ppinctrl, PTR_ERR(pins_uart));
}
return;
}
pinctrl_select_state(ppinctrl, pins_uart);
}
#endif /* !defined(CONFIG_MTK_LEGACY) && !defined(CONFIG_FPGA_EARLY_PORTING) */
void mtk_uart_switch_tx_to_gpio(struct mtk_uart *uart)
{
#if defined(CONFIG_PM) && !defined(CONFIG_FPGA_EARLY_PORTING) && !defined(CONFIG_MTK_LEGACY)
int uart_gpio_op = 0; /* URAT RX SET */
#endif /* defined(CONFIG_PM) && !defined(CONFIG_FPGA_EARLY_PORTING) && !defined(CONFIG_MTK_LEGACY) */
int uartport = uart->nport;
/* pr_debug("[UART]%s port:0x%x\n", __func__, uartport); */
if (uartport > 3) {
pr_notice("[UART%d] %s fail!! port:%d", uartport, __func__, uartport);
return;
}
#ifdef CONFIG_PM
#ifndef CONFIG_FPGA_EARLY_PORTING
#if defined(CONFIG_MTK_LEGACY)
switch (uart->nport) {
case 0:
#ifdef GPIO_UART_UTXD0_PIN
mt_set_gpio_out(GPIO_UART_UTXD0_PIN, GPIO_OUT_ONE);
mt_set_gpio_mode(GPIO_UART_UTXD0_PIN, GPIO_UART_UTXD0_PIN_M_GPIO);
#else
/*pr_debug("GPIO_UART_UTXD0_PIN is not properly set\n");*/
#endif
break;
case 1:
#ifdef GPIO_UART_UTXD1_PIN
mt_set_gpio_out(GPIO_UART_UTXD1_PIN, GPIO_OUT_ONE);
mt_set_gpio_mode(GPIO_UART_UTXD1_PIN, GPIO_UART_UTXD1_PIN_M_GPIO);
#else
/*pr_debug("GPIO_UART_UTXD1_PIN is not properly set\n");*/
#endif
break;
case 2:
#ifdef GPIO_UART_UTXD2_PIN
mt_set_gpio_out(GPIO_UART_UTXD2_PIN, GPIO_OUT_ONE);
mt_set_gpio_mode(GPIO_UART_UTXD2_PIN, GPIO_UART_UTXD2_PIN_M_GPIO);
#else
/*pr_debug("GPIO_UART_UTXD2_PIN is not properly set\n");*/
#endif
break;
case 3:
#ifdef GPIO_UART_UTXD3_PIN
mt_set_gpio_out(GPIO_UART_UTXD3_PIN, GPIO_OUT_ONE);
mt_set_gpio_mode(GPIO_UART_UTXD3_PIN, GPIO_UART_UTXD3_PIN_M_GPIO);
#else
/*pr_debug("GPIO_UART_UTXD3_PIN is not properly set\n");*/
#endif
break;
default:
break;
}
#else /* defined(CONFIG_MTK_LEGACY)*/
/*pr_debug("[UART%d][PinC]%s call switch_uart_gpio(%d, %d)\n", uartport, __func__, uartport, uart_gpio_op);*/
switch_uart_gpio(uartport, uart_gpio_op);
#endif /* defined(CONFIG_MTK_LEGACY) */
#endif
#endif
}
/*---------------------------------------------------------------------------*/
void mtk_uart_switch_to_tx(struct mtk_uart *uart)
{
#if defined(CONFIG_PM) && !defined(CONFIG_FPGA_EARLY_PORTING) && !defined(CONFIG_MTK_LEGACY)
int uart_gpio_op = 0; /* URAT RX SET */
#endif /* defined(CONFIG_PM) && !defined(CONFIG_FPGA_EARLY_PORTING) && !defined(CONFIG_MTK_LEGACY) */
int uartport = uart->nport;
/* pr_debug("[UART]%s port:0x%x\n", __func__, uartport);*/
if (uartport > 3) {
pr_notice("[UART%d] %s fail!! port:%d", uartport, __func__, uartport);
return;
}
#ifdef CONFIG_PM
#ifndef CONFIG_FPGA_EARLY_PORTING
#if defined(CONFIG_MTK_LEGACY)
switch (uart->nport) {
case 0:
#ifdef GPIO_UART_UTXD0_PIN
mt_set_gpio_mode(GPIO_UART_UTXD0_PIN, GPIO_UART_UTXD0_PIN_M_UTXD);
#else
/*pr_debug("GPIO_UART_UTXD0_PIN is not properly set p2\n");*/
#endif
break;
case 1:
#ifdef GPIO_UART_UTXD1_PIN
mt_set_gpio_mode(GPIO_UART_UTXD1_PIN, GPIO_UART_UTXD1_PIN_M_UTXD);
#else
/*pr_debug("GPIO_UART_UTXD1_PIN is not properly set p2\n");*/
#endif
break;
case 2:
#ifdef GPIO_UART_UTXD2_PIN
mt_set_gpio_mode(GPIO_UART_UTXD2_PIN, GPIO_UART_UTXD2_PIN_M_UTXD);
#else
/*pr_debug("GPIO_UART_UTXD2_PIN is not properly set p2\n");*/
#endif
break;
case 3:
#ifdef GPIO_UART_UTXD3_PIN
mt_set_gpio_mode(GPIO_UART_UTXD3_PIN, GPIO_UART_UTXD3_PIN_M_UTXD);
#else
/*pr_debug("GPIO_UART_UTXD3_PIN is not properly set p3\n");*/
#endif
break;
default:
break;
}
#else /* defined(CONFIG_MTK_LEGACY) */
/*pr_debug("[UART%d][PinC]%s call switch_uart_gpio(%d, %d)\n", uartport, __func__, uartport, uart_gpio_op);*/
switch_uart_gpio(uartport, uart_gpio_op);
#endif /* defined(CONFIG_MTK_LEGACY) */
#endif
#endif
}
/*---------------------------------------------------------------------------*/
void mtk_uart_switch_rx_to_gpio(struct mtk_uart *uart)
{
#if defined(CONFIG_PM) && !defined(CONFIG_FPGA_EARLY_PORTING) && !defined(CONFIG_MTK_LEGACY)
int uart_gpio_op = 1; /* URAT RX Clear */
#endif /* !defined(CONFIG_MTK_LEGACY) */
int uartport = uart->nport;
/* pr_debug("[UART]%s port:0x%x\n", __func__, uartport); */
if (uartport > 3) {
pr_notice("[UART%d] %s fail!! port:%d", uartport, __func__, uartport);
return;
}
#ifdef CONFIG_PM
#ifndef CONFIG_FPGA_EARLY_PORTING
#if defined(CONFIG_MTK_LEGACY)
switch (uart->nport) {
case 0:
#ifdef GPIO_UART_URXD0_PIN
mt_set_gpio_mode(GPIO_UART_URXD0_PIN, GPIO_UART_URXD0_PIN_M_GPIO);
#else
/*pr_debug("GPIO_UART_URXD0_PIN is not properly set\n");*/
#endif
break;
case 1:
#ifdef GPIO_UART_URXD1_PIN
mt_set_gpio_mode(GPIO_UART_URXD1_PIN, GPIO_UART_URXD1_PIN_M_GPIO);
#else
/*pr_debug("GPIO_UART_URXD1_PIN is not properly set\n");*/
#endif
break;
case 2:
#ifdef GPIO_UART_URXD2_PIN
mt_set_gpio_mode(GPIO_UART_URXD2_PIN, GPIO_UART_URXD2_PIN_M_GPIO);
#else
/*pr_debug("GPIO_UART_URXD2_PIN is not properly set\n");*/
#endif
break;
case 3:
#ifdef GPIO_UART_URXD3_PIN
mt_set_gpio_mode(GPIO_UART_URXD3_PIN, GPIO_UART_URXD3_PIN_M_GPIO);
#else
/*pr_debug("GPIO_UART_URXD3_PIN is not properly set\n");*/
#endif
break;
default:
break;
}
#else /* defined(CONFIG_MTK_LEGACY) */
/*pr_debug("[UART%d][PinC]%s call switch_uart_gpio(%d, %d)\n", uartport, __func__, uartport, uart_gpio_op);*/
switch_uart_gpio(uartport, uart_gpio_op);
#endif /* defined(CONFIG_MTK_LEGACY) */
#endif
#endif
}
/*---------------------------------------------------------------------------*/
void mtk_uart_switch_to_rx(struct mtk_uart *uart)
{
#if defined(CONFIG_PM) && !defined(CONFIG_FPGA_EARLY_PORTING) && !defined(CONFIG_MTK_LEGACY)
int uart_gpio_op = 0; /* URAT RX SET */
#endif /* !defined(CONFIG_MTK_LEGACY) */
int uartport = uart->nport;
/* pr_debug("[UART]%s port:0x%x\n", __func__, uartport);*/
if (uartport > 3) {
pr_notice("[UART%d] %s fail!! port:%d", uartport, __func__, uartport);
return;
}
#ifdef CONFIG_PM
#ifndef CONFIG_FPGA_EARLY_PORTING
#if defined(CONFIG_MTK_LEGACY)
switch (uartport) {
case 0:
#ifdef GPIO_UART_URXD0_PIN
mt_set_gpio_mode(GPIO_UART_URXD0_PIN, GPIO_UART_URXD0_PIN_M_URXD);
#else /* GPIO_UART_URXD0_PIN */
/*pr_debug("GPIO_UART_URXD0_PIN is not properly set p2\n");*/
#endif /* GPIO_UART_URXD0_PIN */
break;
case 1:
#ifdef GPIO_UART_URXD1_PIN
mt_set_gpio_mode(GPIO_UART_URXD1_PIN, GPIO_UART_URXD1_PIN_M_URXD);
#else /* GPIO_UART_URXD1_PIN */
/*pr_debug("GPIO_UART_URXD1_PIN is not properly set p2\n");*/
#endif /* GPIO_UART_URXD1_PIN */
break;
case 2:
#ifdef GPIO_UART_URXD2_PIN
mt_set_gpio_mode(GPIO_UART_URXD2_PIN, GPIO_UART_URXD2_PIN_M_URXD);
#else
/*pr_debug("GPIO_UART_URXD2_PIN is not properly set p2\n");*/
#endif
break;
case 3:
#ifdef GPIO_UART_URXD3_PIN
mt_set_gpio_mode(GPIO_UART_URXD3_PIN, GPIO_UART_URXD3_PIN_M_URXD);
#else
/*pr_debug("GPIO_UART_URXD3_PIN is not properly set p2\n");*/
#endif
break;
default:
break;
}
#else /* defined(CONFIG_MTK_LEGACY) */
/*pr_debug("[UART%d][PinC]%s call switch_uart_gpio(%d, %d)\n", uartport, __func__, uartport, uart_gpio_op);*/
switch_uart_gpio(uartport, uart_gpio_op);
#endif /* defined(CONFIG_MTK_LEGACY) */
#endif
#endif
}
/*---------------------------------------------------------------------------*/
void mtk_uart_enable_dpidle(struct mtk_uart *uart)
{
/* FIX-ME early porting */
#ifndef CONFIG_FPGA_EARLY_PORTING
spm_resource_req(SPM_RESOURCE_USER_UART, SPM_RESOURCE_RELEASE);
#endif
}
/*---------------------------------------------------------------------------*/
void mtk_uart_disable_dpidle(struct mtk_uart *uart)
{
/* FIX-ME early porting */
#ifndef CONFIG_FPGA_EARLY_PORTING
spm_resource_req(SPM_RESOURCE_USER_UART, SPM_RESOURCE_ALL);
#endif
}
/*---------------------------------------------------------------------------*/
int mtk_uart_plat_info_query(const char str[])
{
return 0;
}