aboutsummaryrefslogtreecommitdiff
path: root/drivers/misc/mediatek/uart
diff options
context:
space:
mode:
authorMeizu OpenSource <patchwork@meizu.com>2016-08-15 10:19:42 +0800
committerMeizu OpenSource <patchwork@meizu.com>2016-08-15 10:19:42 +0800
commitd2e1446d81725c351dc73a03b397ce043fb18452 (patch)
tree4dbc616b7f92aea39cd697a9084205ddb805e344 /drivers/misc/mediatek/uart
first commit
Diffstat (limited to 'drivers/misc/mediatek/uart')
-rw-r--r--drivers/misc/mediatek/uart/Makefile7
-rw-r--r--drivers/misc/mediatek/uart/mt6735/Makefile4
-rw-r--r--drivers/misc/mediatek/uart/mt6735/platform_fiq_debugger.c198
-rw-r--r--drivers/misc/mediatek/uart/mt6735/platform_uart.c2334
-rw-r--r--drivers/misc/mediatek/uart/mt6735/platform_uart.h462
-rw-r--r--drivers/misc/mediatek/uart/mt_fiq_debugger.c83
-rw-r--r--drivers/misc/mediatek/uart/uart.c2834
7 files changed, 5922 insertions, 0 deletions
diff --git a/drivers/misc/mediatek/uart/Makefile b/drivers/misc/mediatek/uart/Makefile
new file mode 100644
index 000000000..4e57ba6ca
--- /dev/null
+++ b/drivers/misc/mediatek/uart/Makefile
@@ -0,0 +1,7 @@
+include $(srctree)/drivers/misc/mediatek/Makefile.custom
+
+obj-$(CONFIG_MTK_SERIAL) := uart.o
+obj-$(CONFIG_FIQ_DEBUGGER) += mt_fiq_debugger.o
+
+obj-y += $(subst ",,$(CONFIG_MTK_PLATFORM))/
+
diff --git a/drivers/misc/mediatek/uart/mt6735/Makefile b/drivers/misc/mediatek/uart/mt6735/Makefile
new file mode 100644
index 000000000..23f247c66
--- /dev/null
+++ b/drivers/misc/mediatek/uart/mt6735/Makefile
@@ -0,0 +1,4 @@
+include $(srctree)/drivers/misc/mediatek/Makefile.custom
+
+obj-$(CONFIG_MTK_SERIAL) := platform_uart.o
+obj-$(CONFIG_FIQ_DEBUGGER) += platform_fiq_debugger.o
diff --git a/drivers/misc/mediatek/uart/mt6735/platform_fiq_debugger.c b/drivers/misc/mediatek/uart/mt6735/platform_fiq_debugger.c
new file mode 100644
index 000000000..98e4179ec
--- /dev/null
+++ b/drivers/misc/mediatek/uart/mt6735/platform_fiq_debugger.c
@@ -0,0 +1,198 @@
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <asm/thread_info.h>
+#include <asm/fiq.h>
+#include <asm/fiq_glue.h>
+#include <asm/fiq_debugger.h>
+#include <mach/irqs.h>
+#include <mach/mt_reg_base.h>
+#include <linux/uart/mtk_uart.h>
+#include <linux/uart/mtk_uart_intf.h>
+
+#define THREAD_INFO(sp) ((struct thread_info *) \
+ ((unsigned long)(sp) & ~(THREAD_SIZE - 1)))
+#define REG_UART_BASE *((volatile unsigned int*)(console_base_addr + 0x00))
+#define REG_UART_STATUS *((volatile unsigned int*)(console_base_addr + 0x14))
+#define REG_UART_IIR *((volatile unsigned int*)(console_base_addr + 0x08))
+#define FIQ_DEBUGGER_BREAK_CH 6 /* CTRL + F */
+#define MAX_FIQ_DBG_EVENT 1024
+
+static struct fiq_dbg_event fiq_dbg_events[MAX_FIQ_DBG_EVENT];
+static int fiq_dbg_event_rd, fiq_dbg_event_wr;
+static unsigned int fiq_dbg_event_ov;
+static int console_base_addr = AP_UART1_BASE;
+static int ret_FIQ_DEBUGGER_BREAK;
+static int uart_irq_number = -1;
+
+extern struct mtk_uart *mt_console_uart;
+extern int is_fiq_debug_console_enable(void *argv);
+extern bool debug_handle_uart_interrupt(void *state, int this_cpu, void *regs, void *svc_sp);
+extern void mtk_uart_tx_handler(struct mtk_uart *uart);
+extern void mtk_uart_get_modem_status(struct mtk_uart *uart);
+extern void debug_handle_irq_context(void *arg);
+
+int fiq_uart_getc(struct platform_device *pdev)
+{
+ int ch;
+
+ if (ret_FIQ_DEBUGGER_BREAK) {
+ ret_FIQ_DEBUGGER_BREAK = 0;
+ return FIQ_DEBUGGER_BREAK;
+ }
+
+ if (!(REG_UART_STATUS & 0x01))
+ return FIQ_DEBUGGER_NO_CHAR;
+
+ ch = REG_UART_BASE & 0xFF;
+
+ if (ch == FIQ_DEBUGGER_BREAK_CH)
+ return FIQ_DEBUGGER_BREAK;
+
+ return ch;
+}
+
+void fiq_uart_putc(struct platform_device *pdev, unsigned int c)
+{
+ while (! (REG_UART_STATUS & 0x20));
+
+ REG_UART_BASE = c & 0xFF;
+}
+
+void fiq_uart_fixup(int uart_port)
+{
+ switch (uart_port) {
+ case 0:
+ console_base_addr = AP_UART0_BASE;
+ fiq_resource[1].start = UART0_IRQ_BIT_ID;
+ fiq_resource[1].end = UART0_IRQ_BIT_ID;
+ uart_irq_number = UART0_IRQ_BIT_ID;
+ break;
+ case 1:
+ console_base_addr = AP_UART1_BASE;
+ fiq_resource[1].start = UART1_IRQ_BIT_ID;
+ fiq_resource[1].end = UART1_IRQ_BIT_ID;
+ uart_irq_number = UART1_IRQ_BIT_ID;
+ break;
+ case 2:
+ console_base_addr = AP_UART2_BASE;
+ fiq_resource[1].start = UART2_IRQ_BIT_ID;
+ fiq_resource[1].end = UART2_IRQ_BIT_ID;
+ uart_irq_number = UART2_IRQ_BIT_ID;
+ break;
+ case 3:
+ console_base_addr = AP_UART3_BASE;
+ fiq_resource[1].start = UART3_IRQ_BIT_ID;
+ fiq_resource[1].end = UART3_IRQ_BIT_ID;
+ uart_irq_number = UART3_IRQ_BIT_ID;
+ break;
+ default:
+ break;
+ }
+}
+
+static void __push_event(u32 iir, int data)
+{
+ if (((fiq_dbg_event_wr + 1) % MAX_FIQ_DBG_EVENT) == fiq_dbg_event_rd) {
+ /* full */
+ fiq_dbg_event_ov++;
+ } else {
+ fiq_dbg_events[fiq_dbg_event_wr].iir = iir;
+ fiq_dbg_events[fiq_dbg_event_wr].data = data;
+ fiq_dbg_event_wr++;
+ fiq_dbg_event_wr %= MAX_FIQ_DBG_EVENT;
+ }
+}
+
+static int __pop_event(u32 *iir, int *data)
+{
+ if (fiq_dbg_event_rd == fiq_dbg_event_wr) {
+ /* empty */
+ return -1;
+ } else {
+ *iir = fiq_dbg_events[fiq_dbg_event_rd].iir;
+ *data = fiq_dbg_events[fiq_dbg_event_rd].data;
+ fiq_dbg_event_rd++;
+ fiq_dbg_event_rd %= MAX_FIQ_DBG_EVENT;
+ return 0;
+ }
+}
+
+static void mt_debug_fiq(void *arg, void *regs, void *svc_sp)
+{
+ u32 iir;
+ int data = -1;
+ int max_count = UART_FIFO_SIZE;
+ unsigned int this_cpu;
+ int need_irq = 1;
+
+ iir = REG_UART_IIR;
+ iir &= UART_IIR_INT_MASK;
+ if (iir == UART_IIR_NO_INT_PENDING)
+ return ;
+ if (iir == UART_IIR_THRE) {
+ }
+ __push_event(iir, data);
+
+ while (max_count-- > 0) {
+ if (!(REG_UART_STATUS & 0x01)) {
+ break;
+ }
+
+ if (is_fiq_debug_console_enable(arg)) {
+ data = mt_console_uart->read_byte(mt_console_uart);
+ if (data == FIQ_DEBUGGER_BREAK_CH) {
+ /* enter FIQ debugger mode */
+ ret_FIQ_DEBUGGER_BREAK = 1;
+ this_cpu = THREAD_INFO(svc_sp)->cpu;
+ debug_handle_uart_interrupt(arg, this_cpu, regs, svc_sp);
+ return ;
+ }
+ __push_event(UART_IIR_NO_INT_PENDING, data);
+ /*why need_irq?*/
+ need_irq = 1;
+ } else {
+ this_cpu = THREAD_INFO(svc_sp)->cpu;
+ need_irq = debug_handle_uart_interrupt(arg, this_cpu, regs, svc_sp);
+ }
+ }
+
+ if (need_irq) {
+ mt_disable_fiq(uart_irq_number);
+ trigger_sw_irq(FIQ_DBG_SGI);
+ }
+}
+
+irqreturn_t mt_debug_signal_irq(int irq, void *dev_id)
+{
+ struct tty_struct *tty = mt_console_uart->port.state->port.tty;
+ u32 iir;
+ int data;
+
+ while (__pop_event(&iir, &data) >= 0) {
+ if (iir == UART_IIR_MS) {
+ mtk_uart_get_modem_status(mt_console_uart);
+ } else if (iir == UART_IIR_THRE) {
+ mtk_uart_tx_handler(mt_console_uart);
+ }
+ if (data != -1) {
+ if (!tty_insert_flip_char(tty->port, data, TTY_NORMAL)) {
+ }
+ }
+ }
+ tty_flip_buffer_push(tty->port);
+
+ /* handle commands which can only be handled in the IRQ context */
+ debug_handle_irq_context(dev_id);
+
+ mt_enable_fiq(uart_irq_number);
+
+ return IRQ_HANDLED;
+}
+
+int mt_fiq_init(void *arg)
+{
+ return request_fiq(uart_irq_number, (fiq_isr_handler)mt_debug_fiq, IRQF_TRIGGER_LOW, arg);
+}
diff --git a/drivers/misc/mediatek/uart/mt6735/platform_uart.c b/drivers/misc/mediatek/uart/mt6735/platform_uart.c
new file mode 100644
index 000000000..548034959
--- /dev/null
+++ b/drivers/misc/mediatek/uart/mt6735/platform_uart.c
@@ -0,0 +1,2334 @@
+/* mediatek/platform/mt6589/kernel/drivers/uart/uart.c
+ *
+ * (C) Copyright 2008
+ * MediaTek <www.mediatek.com>
+ * MingHsien Hsieh <minghsien.hsieh@mediatek.com>
+ *
+ * MT6589 UART Driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*---------------------------------------------------------------------------*/
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <mach/mt_clkmgr.h>
+#include "mach/mt_gpio.h"
+#include "linux/delay.h"
+#include "mach/mt_idle.h"
+#include <cust_gpio_usage.h>
+#include <linux/uart/mtk_uart.h>
+#include <linux/uart/mtk_uart_intf.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+
+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);
+#ifdef ENABLE_RAW_DATA_DUMP
+volatile unsigned int stop_update = 0;
+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,
+ .set_bit = PDN_FOR_UART1, .clr_bit = PDN_FOR_UART1, .pll_id = PDN_FOR_UART1,
+ .sysrq = TRUE, .hw_flow = TRUE, .vff = TRUE,
+ },
+ {
+ .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_UART1_BASE, .irq_num = UART1_IRQ_BIT_ID, .irq_sen = MT_LEVEL_SENSITIVE,
+ .set_bit = PDN_FOR_UART2, .clr_bit = PDN_FOR_UART2, .pll_id = PDN_FOR_UART2,
+ .sysrq = FALSE, .hw_flow = TRUE, .vff = TRUE,
+ },
+ {
+ .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 */
+ },
+#ifndef CONFIG_DENALI_2
+ {
+ .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_UART5, .clr_bit = PDN_FOR_UART5, .pll_id = PDN_FOR_UART5,
+ .sysrq = FALSE, .hw_flow = FALSE, .vff = FALSE, /* UART5 */
+ },
+#endif // CONFIG_DENALI_2
+};
+/*---------------------------------------------------------------------------*/
+static unsigned long mtk_uart_evt_mask[] = {
+ DBG_EVT_NONE,
+ DBG_EVT_NONE,
+ DBG_EVT_NONE,
+ DBG_EVT_NONE,
+#ifndef CONFIG_DENALI_2
+ DBG_EVT_NONE,
+#endif // CONFIG_DENALI_2
+};
+/*---------------------------------------------------------------------------*/
+static unsigned long mtk_uart_lsr_status[] = {
+ 0, /* UART1 */
+ 0, /* UART2 */
+ 0, /* UART3 */
+ 0, /* UART4 */
+#ifndef CONFIG_DENALI_2
+ 0, /* UART5 */
+#endif // CONFIG_DENALI_2
+};
+/*---------------------------------------------------------------------------*/
+#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
+#ifndef CONFIG_DENALI_2
+ , 1
+#endif // CONFIG_DENALI_2
+};
+#endif
+/*---------------------------------------------------------------------------*/
+/* uart control blocks */
+static struct mtk_uart mtk_uarts[UART_NR];
+/*---------------------------------------------------------------------------*/
+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_compatible_node(NULL, NULL, "mediatek,AP_UART0");
+ break;
+ case 1:
+ node = of_find_compatible_node(NULL, NULL, "mediatek,AP_UART1");
+ break;
+ case 2:
+ node = of_find_compatible_node(NULL, NULL, "mediatek,AP_UART2");
+ break;
+ case 3:
+ node = of_find_compatible_node(NULL, NULL, "mediatek,AP_UART3");
+ break;
+#ifndef CONFIG_DENALI_2
+ case 4:
+ node = of_find_compatible_node(NULL, NULL, "mediatek,AP_UART4");
+ break;
+#endif // CONFIG_DENALI_2
+ 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)){
+ printk("[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))){
+ printk("[UART%d] get irq flags from DTS fail!!\n", idx);
+ }
+ mtk_uart_default_settings[idx].irq_flags = (unsigned long)irq_info[2];
+ printk("[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;
+ struct device_node *apdma_uart0_node = NULL;
+ void *base;
+ unsigned int apdma_reg;
+ unsigned int apdma_uart0_reg;
+ unsigned int apdma_uart0_offset;
+
+ node = of_find_compatible_node(NULL, NULL, "mediatek,AP_DMA");
+ apdma_uart0_node = of_find_compatible_node(NULL, NULL, "mediatek,AP_DMA_UART0_TX");
+
+ base = of_iomap(node, 0);
+
+ if (of_property_read_u32_index(node, "reg", 0, &apdma_reg)){
+ printk("[UART] get AP_DMA reg from DTS fail!!\n");
+ }
+ if (of_property_read_u32_index(apdma_uart0_node, "reg", 0, &apdma_uart0_reg)){
+ printk("[UART] get AP_DMA_UART0_TX reg from DTS fail!!\n");
+ }
+
+ apdma_uart0_offset = apdma_uart0_reg - apdma_reg;
+ base += apdma_uart0_offset;
+ printk("[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:
+ node = of_find_compatible_node(NULL, NULL, "mediatek,AP_DMA_UART0_TX");
+ break;
+ case 1:
+ node = of_find_compatible_node(NULL, NULL, "mediatek,AP_DMA_UART0_RX");
+ break;
+ case 2:
+ node = of_find_compatible_node(NULL, NULL, "mediatek,AP_DMA_UART1_TX");
+ break;
+ case 3:
+ node = of_find_compatible_node(NULL, NULL, "mediatek,AP_DMA_UART1_RX");
+ break;
+ case 4:
+ node = of_find_compatible_node(NULL, NULL, "mediatek,AP_DMA_UART2_TX");
+ break;
+ case 5:
+ node = of_find_compatible_node(NULL, NULL, "mediatek,AP_DMA_UART2_RX");
+ break;
+ case 6:
+ node = of_find_compatible_node(NULL, NULL, "mediatek,AP_DMA_UART3_TX");
+ break;
+ case 7:
+ node = of_find_compatible_node(NULL, NULL, "mediatek,AP_DMA_UART3_RX");
+ break;
+#ifndef CONFIG_DENALI_2
+ case 8:
+ node = of_find_compatible_node(NULL, NULL, "mediatek,AP_DMA_UART4_TX");
+ break;
+ case 9:
+ node = of_find_compatible_node(NULL, NULL, "mediatek,AP_DMA_UART4_RX");
+ break;
+#endif // CONFIG_DENALI_2
+ default:
+ break;
+ }
+ irq_id = irq_of_parse_and_map(node, 0);
+ printk("[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;
+ return;
+}
+/*---------------------------------------------------------------------------*/
+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;
+ return;
+}
+/*---------------------------------------------------------------------------*/
+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
+inline static 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);
+}
+
+inline static 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);
+}
+
+inline static u32 __read_fcr_register(struct mtk_uart *uart)
+{
+ return uart->fcr_back_up;
+}
+
+inline static 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);
+}
+
+inline static 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
+inline static void __write_fcr_register(struct mtk_uart *uart, u32 data)
+{
+ unsigned long base = uart->base;
+ reg_sync_writel(data, UART_FCR);
+}
+
+inline static void sync_write_fcr_register(struct mtk_uart *uart, u32 data)
+{
+ unsigned long base = uart->base;
+ reg_sync_writel(data, UART_FCR);
+}
+
+inline static u32 __read_fcr_register(struct mtk_uart *uart)
+{
+ unsigned long base = uart->base;
+ return UART_READ32(UART_FCR_RD);
+}
+
+inline static 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);
+}
+
+inline static 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 */
+/*---------------------------------------------------------------------------*/
+inline static 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);
+ dsb();
+
+ 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);
+ printk("[UART%d] LSR=0x%x ESCAPE_EN=0x%x\n", uart->nport, lsr, escape_en);
+ }else
+ printk("[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;
+ } else {
+ /*
+ * 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);
+ dsb();
+ }
+ 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);
+ }
+ dsb();
+ 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);
+ dsb(); //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 (dma && uart) {
+ 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 {
+ MSG(ERR, "%p, %p\n", dma, uart);
+ //del_timer(&dma->vfifo->timer);
+ }
+#else
+ if(dma && uart){
+ 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)));
+ }
+ }else{
+ MSG(ERR, "%p, %p\n", dma, uart);
+ }
+#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_notice("[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;
+ printk("[UART%d_TX] %4d bytes:", uart->nport, vfifo->cur->idx);
+ for (i = 0; i < vfifo->cur->idx; i++) {
+ if (i % 16 == 0)
+ printk("\n");
+ printk("%.2x ", (unsigned char)vfifo->cur->dat[i]);
+ }
+ printk("\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;
+ printk("[UART%d_TX] %4d bytes:", uart->nport, vfifo->cur->idx);
+ for (i = 0; i < vfifo->cur->idx; i++) {
+ if (i % 16 == 0)
+ printk("\n");
+ printk("%.2x ", (unsigned char)vfifo->cur->dat[i]);
+ }
+ printk("\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);
+ if (atomic_inc_and_test(&vfifo->entry) > 1) {
+ MSG(ERR, "tx entry!!\n");
+ tasklet_schedule(&vfifo->dma->tasklet);
+ } else {
+ 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;
+ printk("[UART%d_RX] %4d bytes:", uart->nport, vfifo->cur->idx);
+
+ for (i = 0; i < vfifo->cur->idx; i++) {
+ if (i % 16 == 0)
+ printk("\n");
+ printk("%.2x ", (unsigned char)vfifo->cur->dat[i]);
+ }
+ printk("\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);
+ }
+ }
+ dsb(); //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;
+ printk("[UART%d_RX] %4d bytes:", uart->nport, vfifo->cur->idx);
+
+ for (i = 0; i < vfifo->cur->idx; i++) {
+ if (i % 16 == 0)
+ printk("\n");
+ printk("%.2x ", (unsigned char)vfifo->cur->dat[i]);
+ }
+ printk("\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);
+ if (atomic_inc_and_test(&vfifo->entry) > 1) {
+ MSG(ERR, "rx entry!!\n");
+ tasklet_schedule(&vfifo->dma->tasklet);
+ } else {
+ 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 (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));
+ dsb();
+ }
+}
+/*---------------------------------------------------------------------------*/
+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)
+ return;
+ 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){
+ printk("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){
+ printk("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)
+ 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;
+ //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);
+ dsb();
+}
+/*---------------------------------------------------------------------------*/
+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);
+ dsb();
+}
+/*---------------------------------------------------------------------------*/
+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);
+ }
+ dsb();
+}
+/*---------------------------------------------------------------------------*/
+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:
+ dev_err(uart->port.dev, "SYSCLK = %ldMHZ doesn't support autobaud\n",
+ uart->sysclk);
+ return;
+ }
+ reg_sync_writel(0x01, UART_AUTOBAUD_EN); /* Enable Auto Baud */
+ return;
+}
+/*---------------------------------------------------------------------------*/
+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(3 == highspeed)
+ 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 compatibilty, 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__);
+ dsb(); /*to ensure the setting is written*/
+}
+/*---------------------------------------------------------------------------*/
+void mtk_uart_baud_setting(struct mtk_uart *uart , int baudrate)
+{
+ u32 uartclk;
+#if defined(CONFIG_MTK_FPGA)
+ u32 tmp_div;
+#endif
+ uartclk = uart->sysclk;
+
+#if defined(CONFIG_MTK_FPGA)
+ 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);
+ dsb(); /*to ensure the setting is written*/
+ uart->fctl_mode = mode;
+}
+/*---------------------------------------------------------------------------*/
+void mtk_uart_power_up(struct mtk_uart *uart)
+{
+#ifndef CONFIG_MTK_FPGA
+ struct mtk_uart_setting *setting;
+ setting = uart->setting;
+
+ if (!uart || uart->nport >= UART_NR)
+ return;
+
+ if (uart->poweron_count > 0) {
+ MSG(FUC, "%s(%d)\n", __func__, uart->poweron_count);
+ } else {
+ #ifdef POWER_FEATURE
+ if (0 != enable_clock(setting->pll_id,"UART"))
+ MSG(ERR, "power on fail!!\n");
+ if ((uart != console_port) && (uart->tx_mode == UART_TX_VFIFO_DMA || uart->rx_mode == UART_RX_VFIFO_DMA)){
+ if (0 != enable_clock(PDN_FOR_DMA, "VFIFO") )
+ MSG(ERR, "power on dma fail!\n");
+ }
+ uart->poweron_count++;
+ #endif
+ }
+ MSG(FUC, "%s(%d) => up \n", __func__, uart->poweron_count);
+#endif /* End of CONFIG_MTK_FPGA */
+}
+/*---------------------------------------------------------------------------*/
+void mtk_uart_power_down(struct mtk_uart *uart)
+{
+#ifndef CONFIG_MTK_FPGA
+ struct mtk_uart_setting *setting;
+ setting = uart->setting;
+
+ if (!uart || uart->nport >= UART_NR)
+ return;
+
+ if (uart->poweron_count == 0) {
+ MSG(FUC, "%s(%d)\n", __func__, uart->poweron_count);
+ } else {
+ #ifdef POWER_FEATURE
+ if (0 != disable_clock(setting->pll_id,"UART"))
+ MSG(ERR, "power off fail!!\n");
+ if ((uart != console_port) && (uart->tx_mode == UART_TX_VFIFO_DMA || uart->rx_mode == UART_RX_VFIFO_DMA)){
+ if (0 != disable_clock(PDN_FOR_DMA, "VFIFO") )
+ MSG(ERR, "power off dma fail!\n");
+ }
+ uart->poweron_count--;
+ #endif
+ MSG(FUC, "%s(%d) => dn \n", __func__, uart->poweron_count);
+ }
+#endif /* End of CONFIG_MTK_FPGA */
+}
+/*---------------------------------------------------------------------------*/
+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);
+ dsb();
+}
+/*---------------------------------------------------------------------------*/
+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);
+ dsb();
+}
+/*---------------------------------------------------------------------------*/
+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)
+{
+ return;
+}
+/*---------------------------------------------------------------------------*/
+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);
+ dsb();
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+/*---------------------------------------------------------------------------*/
+#ifdef ATE_FACTORY_ENABLE
+void mtk_uart_is_ate_factory_mode(struct mtk_uart *uart)
+{
+ if((0 == uart->nport)&&(ATE_FACTORY_MODE == get_boot_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);
+ dsb();
+ }
+}
+#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);
+ printk("SLEEP_EN = 0x%x\n",UART_READ32(UART_SLEEP_EN));
+}
+/*---------------------------------------------------------------------------*/
+
+void mtk_uart_init_debug_spinlock(void)
+{
+#ifdef ENABLE_RAW_DATA_DUMP
+ spin_lock_init(&tx_history_lock);
+ spin_lock_init(&rx_history_lock);
+#endif
+}
+void reset_tx_raw_data(struct mtk_uart *uart)
+{
+#ifdef ENABLE_RAW_DATA_DUMP
+ 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);
+ }
+#endif
+}
+static void save_tx_raw_data(struct mtk_uart *uart,void *addr)
+{
+#ifdef ENABLE_RAW_DATA_DUMP
+ 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);
+ }
+#endif
+}
+static void reset_rx_raw_data(struct mtk_uart *uart)
+{
+#ifdef ENABLE_RAW_DATA_DUMP
+ 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);
+ }
+#endif
+}
+static void save_rx_raw_data(struct mtk_uart *uart, const unsigned char *chars, size_t size)
+{
+#ifdef ENABLE_RAW_DATA_DUMP
+ 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);
+ }
+#endif
+}
+
+void stop_log(void)
+{
+#ifdef ENABLE_RAW_DATA_DUMP
+ 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);
+#endif
+}
+EXPORT_SYMBOL(stop_log);
+void dump_uart_history(void)
+{
+#ifdef ENABLE_RAW_DATA_DUMP
+ 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++){
+ printk("\nTX rec%03d:", i);
+ for(j=0; j<uart_history_cnt[curr]; j++){
+ if((j%0xF)==0)
+ printk("\n");
+ printk("%02x ", uart_history[curr][j]);
+ }
+ msleep(20);
+ curr++;
+ if(curr>=RECORD_NUMBER)
+ curr=0;
+ }
+ for(i=0; i<RECORD_NUMBER; i++){
+ printk("\nRX rec%03d:", i);
+ for(j=0; j<uart_rx_history_cnt[rx_curr]; j++){
+ if((j%0xF)==0)
+ printk("\n");
+ printk("%02x ", uart_rx_history[rx_curr][j]);
+ }
+ msleep(20);
+ rx_curr++;
+ if(rx_curr>=RECORD_NUMBER)
+ rx_curr=0;
+ }
+#endif
+}
+EXPORT_SYMBOL(dump_uart_history);
+
+
+/*---------------------------------------------------------------------------*/
+void mtk_uart_save(struct mtk_uart *uart)
+{
+#ifdef CONFIG_PM
+ unsigned long base;
+ unsigned long flags;
+ 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
+}
+
+void mtk_uart_switch_tx_to_gpio(struct mtk_uart *uart)
+{
+ printk(KERN_ERR "%s port:0x%x\n", __FUNCTION__, uart->nport);
+#ifdef CONFIG_PM
+#ifndef CONFIG_MTK_FPGA
+ 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
+ printk(KERN_ERR "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
+ printk(KERN_ERR "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
+ printk(KERN_ERR "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
+ printk(KERN_ERR "GPIO_UART_UTXD3_PIN is not properly set\n");
+ #endif
+ break;
+ default:
+ break;
+ }
+ return;
+#endif
+#endif
+}
+/*---------------------------------------------------------------------------*/
+void mtk_uart_switch_to_tx(struct mtk_uart *uart)
+{
+ printk(KERN_ERR "%s port:0x%x\n", __FUNCTION__, uart->nport);
+#ifdef CONFIG_PM
+#ifndef CONFIG_MTK_FPGA
+ 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
+ printk(KERN_ERR "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
+ printk(KERN_ERR "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
+ printk(KERN_ERR "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
+ printk(KERN_ERR "GPIO_UART_UTXD3_PIN is not properly set p3\n");
+ #endif
+ break;
+ default:
+ break;
+ }
+ return;
+#endif
+#endif
+}
+/*---------------------------------------------------------------------------*/
+void mtk_uart_switch_rx_to_gpio(struct mtk_uart *uart)
+{
+ printk(KERN_ERR "%s port:0x%x\n", __FUNCTION__, uart->nport);
+#ifdef CONFIG_PM
+#ifndef CONFIG_MTK_FPGA
+ 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
+ printk(KERN_ERR "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
+ printk(KERN_ERR "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
+ printk(KERN_ERR "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
+ printk(KERN_ERR "GPIO_UART_URXD3_PIN is not properly set\n");
+ #endif
+ break;
+ default:
+ break;
+ }
+ return;
+#endif
+#endif
+}
+/*---------------------------------------------------------------------------*/
+void mtk_uart_switch_to_rx(struct mtk_uart *uart)
+{
+ printk(KERN_ERR "%s port:0x%x\n", __FUNCTION__, uart->nport);
+#ifdef CONFIG_PM
+#ifndef CONFIG_MTK_FPGA
+ switch(uart->nport){
+ case 0:
+ #ifdef GPIO_UART_URXD0_PIN
+ mt_set_gpio_mode(GPIO_UART_URXD0_PIN, GPIO_UART_URXD0_PIN_M_URXD);
+ #else
+ printk(KERN_ERR "GPIO_UART_URXD0_PIN is not properly set p2\n");
+ #endif
+ break;
+ case 1:
+ #ifdef GPIO_UART_URXD1_PIN
+ mt_set_gpio_mode(GPIO_UART_URXD1_PIN, GPIO_UART_URXD1_PIN_M_URXD);
+ #else
+ printk(KERN_ERR "GPIO_UART_URXD1_PIN is not properly set p2\n");
+ #endif
+ break;
+ case 2:
+ #ifdef GPIO_UART_URXD2_PIN
+ mt_set_gpio_mode(GPIO_UART_URXD2_PIN, GPIO_UART_URXD2_PIN_M_URXD);
+ #else
+ printk(KERN_ERR "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
+ printk(KERN_ERR "GPIO_UART_URXD3_PIN is not properly set p2\n");
+ #endif
+ break;
+ default:
+ break;
+ }
+ return;
+#endif
+#endif
+}
+/*---------------------------------------------------------------------------*/
+void mtk_uart_enable_dpidle(struct mtk_uart *uart)
+{
+//FIX-ME early porting
+#ifndef CONFIG_MTK_FPGA
+ enable_dpidle_by_bit(uart->setting->pll_id);
+ enable_soidle_by_bit(uart->setting->pll_id);
+#endif
+ return;
+}
+/*---------------------------------------------------------------------------*/
+void mtk_uart_disable_dpidle(struct mtk_uart *uart)
+{
+//FIX-ME early porting
+#ifndef CONFIG_MTK_FPGA
+ disable_dpidle_by_bit(uart->setting->pll_id);
+ disable_soidle_by_bit(uart->setting->pll_id);
+#endif
+ return;
+}
+/*---------------------------------------------------------------------------*/
+int mtk_uart_plat_info_query(const char str[])
+{
+ return 0;
+}
diff --git a/drivers/misc/mediatek/uart/mt6735/platform_uart.h b/drivers/misc/mediatek/uart/mt6735/platform_uart.h
new file mode 100644
index 000000000..937528eb3
--- /dev/null
+++ b/drivers/misc/mediatek/uart/mt6735/platform_uart.h
@@ -0,0 +1,462 @@
+#ifndef __MTK_PLAT_UART_H__
+#define __MTK_PLAT_UART_H__
+
+#include <asm/irq.h>
+#include <linux/irq.h>
+/******************************************************************************
+ * Function Configuration
+******************************************************************************/
+#define ENABLE_DEBUG
+#define ENABLE_VFIFO
+// Fix-me: marked for early porting
+#define POWER_FEATURE /*control power-on/power-off*/
+#define ENABLE_FRACTIONAL
+#define ENABLE_SYSFS
+//#define UART_USING_FIX_CLK_ENABLE
+#define UART_FCR_USING_SW_BACK_UP
+#define ENABLE_UART_SLEEP
+/*---------------------------------------------------------------------------*/
+#if defined(WMT_PLAT_ALPS)
+#define ENABLE_RAW_DATA_DUMP
+#endif
+/*---------------------------------------------------------------------------*/
+#if defined(ENABLE_VFIFO) && defined(ENABLE_DEBUG)
+#define ENABLE_VFIFO_DEBUG
+#endif
+/******************************************************************************
+ * MACRO & CONSTANT
+******************************************************************************/
+#define DBG_TAG "[UART] "
+#define CFG_UART_AUTOBAUD 0
+/*---------------------------------------------------------------------------*/
+#define UART_VFIFO_SIZE 8192
+#define UART_VFIFO_ALERT_LEN 0x3f
+/*---------------------------------------------------------------------------*/
+#define UART_MAX_TX_PENDING 1024
+/*---------------------------------------------------------------------------*/
+#define UART_MAJOR 204
+#define UART_MINOR 209
+
+#ifdef CONFIG_ARCH_MT6735M
+#define CONFIG_DENALI_2
+#endif // CONFIG_ARCH_MT6735M
+
+#if defined (CONFIG_MTK_FPGA)
+#define UART_NR 2
+#else
+#ifndef CONFIG_DENALI_2
+#define UART_NR 5
+#else // CONFIG_DENALI_2
+#define UART_NR 4
+#endif // CONFIG_DENALI_2
+#endif
+
+/*---------------------------------------------------------------------------*/
+#define WAIT_UART_ACK_TIMES 10
+/*---------------------------------------------------------------------------*/
+#define IRQF_LEVEL_TRIGGER_POLARITY IRQF_TRIGGER_LOW
+#define IRQF_EDGE_TRIGGER_POLARITY IRQF_TRIGGER_FALLING
+/*---- Macro defination remap -----------------------------------------------*/
+/*------ IRQ Section -----------------------*/
+#ifndef CONFIG_OF
+#define UART1_IRQ_ID UART0_IRQ_BIT_ID
+#define UART2_IRQ_ID UART1_IRQ_BIT_ID
+#define UART3_IRQ_ID UART2_IRQ_BIT_ID
+#define UART4_IRQ_ID UART3_IRQ_BIT_ID
+#ifndef CONFIG_DENALI_2
+#define UART5_IRQ_ID UART4_IRQ_BIT_ID
+#endif // CONFIG_DENALI_2
+
+#define UART1_VFF_TX_IRQ_ID AP_DMA_UART0_TX_IRQ_BIT_ID
+#define UART1_VFF_RX_IRQ_ID AP_DMA_UART0_RX_IRQ_BIT_ID
+#define UART2_VFF_TX_IRQ_ID AP_DMA_UART1_TX_IRQ_BIT_ID
+#define UART2_VFF_RX_IRQ_ID AP_DMA_UART1_RX_IRQ_BIT_ID
+#define UART3_VFF_TX_IRQ_ID AP_DMA_UART2_TX_IRQ_BIT_ID
+#define UART3_VFF_RX_IRQ_ID AP_DMA_UART2_RX_IRQ_BIT_ID
+#define UART4_VFF_TX_IRQ_ID AP_DMA_UART3_TX_IRQ_BIT_ID
+#define UART4_VFF_RX_IRQ_ID AP_DMA_UART3_RX_IRQ_BIT_ID
+#ifndef CONFIG_DENALI_2
+#define UART5_VFF_TX_IRQ_ID AP_DMA_UART4_TX_IRQ_BIT_ID
+#define UART5_VFF_RX_IRQ_ID AP_DMA_UART4_RX_IRQ_BIT_ID
+#endif // CONFIG_DENALI_2
+#endif
+/*------ PDN Section -----------------------*/
+#define PDN_FOR_UART1 MT_CG_PERI_UART0
+#define PDN_FOR_UART2 MT_CG_PERI_UART1
+#define PDN_FOR_UART3 MT_CG_PERI_UART2
+#define PDN_FOR_UART4 MT_CG_PERI_UART3
+#ifndef CONFIG_DENALI_2
+#define PDN_FOR_UART5 MT_CG_PERI_UART4
+#endif // CONFIG_DENALI_2
+
+#define PDN_FOR_DMA MT_CG_PERI_APDMA
+
+#if (defined(CONFIG_FIQ_DEBUGGER_CONSOLE) && defined(CONFIG_FIQ_DEBUGGER))
+#define DEFAULT_FIQ_UART_PORT (3)
+#endif
+
+/* For ATE factory feature */
+#ifdef ATE_FACTORY_ENABLE
+#define ATE_FACTORY_MODE 6
+#endif
+/*---------------------------------------------------------------------------*/
+#define MTK_SYSCLK_65 65000000
+#define MTK_SYSCLK_49_4 49400000
+#define MTK_SYSCLK_58_5 58500000
+#define MTK_SYSCLK_52 52000000
+#define MTK_SYSCLK_26 26000000
+#define MTK_SYSCLK_13 13000000
+#define MTK_SYSCLK_6144 61440000
+#define MTK_SYSCLK_3072 30720000
+#define MTK_SYSCLK_1536 15360000
+/*---------------------------------------------------------------------------*/
+/*FIXME: MT6593 FPGA porting*/
+#ifdef CONFIG_MTK_FPGA
+#define UART_SYSCLK 12000000
+#else
+#define UART_SYSCLK MTK_SYSCLK_26
+#endif
+
+/*---------------------------------------------------------------------------*/
+#define ISWEXT (0x80000000) /*extended bit in c_iflag*/
+/*---------------------------------------------------------------------------*/
+/*the size definition of VFF*/
+#define C_UART1_VFF_TX_SIZE (1024) /*the size must be 8-byte alignment*/
+#define C_UART1_VFF_RX_SIZE (1024) /*the size must be 8-byte alignment*/
+#define C_UART2_VFF_TX_SIZE (8192) /*the size must be 8-byte alignment*/
+#define C_UART2_VFF_RX_SIZE (8192) /*the size must be 8-byte alignment*/
+#define C_UART3_VFF_TX_SIZE (8192) /*the size must be 8-byte alignment*/
+#define C_UART3_VFF_RX_SIZE (8192) /*the size must be 8-byte alignment*/
+#define C_UART4_VFF_TX_SIZE (1024) /*the size must be 8-byte alignment*/
+#define C_UART4_VFF_RX_SIZE (1024) /*the size must be 8-byte alignment*/
+#ifndef CONFIG_DENALI_2
+#define C_UART5_VFF_TX_SIZE (1024) /*the size must be 8-byte alignment*/
+#define C_UART5_VFF_RX_SIZE (1024) /*the size must be 8-byte alignment*/
+#endif // CONFIG_DENALI_2
+/******************************************************************************
+ * LOG SETTING
+******************************************************************************/
+/* Debug message event */
+#define DBG_EVT_NONE 0x00000000 /* No event */
+#define DBG_EVT_DMA 0x00000001 /* DMA related event */
+#define DBG_EVT_INT 0x00000002 /* UART INT event */
+#define DBG_EVT_CFG 0x00000004 /* UART CFG event */
+#define DBG_EVT_FUC 0x00000008 /* Function event */
+#define DBG_EVT_INFO 0x00000010 /* information event */
+#define DBG_EVT_ERR 0x00000020 /* Error event */
+#define DBG_EVT_DAT 0x00000040 /* data dump to uart*/
+#define DBG_EVT_BUF 0x00000080 /* data dump to buffer */
+#define DBG_EVT_MSC 0x00000100 /* misc log*/
+#define DBG_EVT_ALL 0xffffffff
+/*---------------------------------------------------------------------------*/
+#ifdef ENABLE_DEBUG
+/*---------------------------------------------------------------------------*/
+#define MSG(evt, fmt, args...) \
+do { \
+ if ((DBG_EVT_##evt) & uart->evt_mask) { \
+ const char *s = #evt; \
+ if (DBG_EVT_##evt & DBG_EVT_ERR) \
+ pr_err(" [UART%d]:%c:%4d: " fmt , \
+ uart->nport, s[0], __LINE__, ##args); \
+ else \
+ pr_notice(" [UART%d]:%c: " fmt , uart->nport, s[0], ##args); \
+ } \
+} while(0)
+/*---------------------------------------------------------------------------*/
+#define UART_DEBUG_EVT(evt) ((evt) & uart->evt_mask)
+/*---------------------------------------------------------------------------*/
+#define MSG_FUNC_ENTRY(f) MSG(FUC, "%s\n", __FUNCTION__)
+#define MSG_RAW pr_notice
+/*---------------------------------------------------------------------------*/
+#else /*release mode: only enable error log*/
+#define MSG(evt, fmt, args...) MSG##evt(fmt, ##args)
+#define MSGERR(fmt, args...) pr_err(" [UART%d]:E:%4d: " fmt, uart->nport, __LINE__, ##args)
+#define MSGDMA(fmt, args...)
+#define MSGCFG(fmt, args...)
+#define MSGFUC(fmt, args...)
+#define MSGINFO(fmt, args...)
+#define MSGDAT(fmt, args...)
+#define MSGMSC(fmt, args...)
+#define MSG_RAW(fmt, args...)
+#define MSG_FUNC_ENTRY(f) do{}while(0)
+#endif /**/
+#define MSG_ERR(fmt, args...) pr_err("[UARTX]:E:%4d: " fmt, __LINE__, ##args)
+#define MSG_TRC(fmt, args...) pr_notice("[UARTX]:T: " fmt, ##args)
+#define DEV_TRC(fmt, args...) pr_notice("[UART%d]:T: " fmt, uart->nport, ##args)
+#define DEV_ERR(fmt, args...) pr_err("[UART%d]:E: " fmt, uart->nport, ##args)
+/*---------------------------------------------------------------------------*/
+#define DRV_NAME "mtk-uart"
+/*---------------------------------------------------------------------------*/
+/******************************************************************************
+ * ENUM & STRUCT
+******************************************************************************/
+/* uart port ids */
+enum {
+ UART_PORT0 = 0,
+ UART_PORT1,
+ UART_PORT2,
+ UART_PORT3,
+#ifndef CONFIG_DENALI_2
+ UART_PORT4,
+#endif // CONFIG_DENALI_2
+ UART_PORT_NUM,
+};
+/*---------------------------------------------------------------------------*/
+#define UART_FIFO_SIZE (16)
+/*---------------------------------------------------------------------------*/
+#define UART_RBR (unsigned long)(base+0x00) /* Read only */
+#define UART_THR (unsigned long)(base+0x00) /* Write only */
+#define UART_IER (unsigned long)(base+0x04)
+#define UART_IIR (unsigned long)(base+0x08) /* Read only */
+#define UART_FCR (unsigned long)(base+0x08) /* Write only */
+#define UART_LCR (unsigned long)(base+0x0c)
+#define UART_MCR (unsigned long)(base+0x10)
+#define UART_LSR (unsigned long)(base+0x14)
+#define UART_MSR (unsigned long)(base+0x18)
+#define UART_SCR (unsigned long)(base+0x1c)
+#define UART_DLL (unsigned long)(base+0x00) /* Only when LCR.DLAB = 1 */
+#define UART_DLH (unsigned long)(base+0x04) /* Only when LCR.DLAB = 1 */
+#define UART_EFR (unsigned long)(base+0x08) /* Only when LCR = 0xbf */
+#define UART_XON1 (unsigned long)(base+0x10) /* Only when LCR = 0xbf */
+#define UART_XON2 (unsigned long)(base+0x14) /* Only when LCR = 0xbf */
+#define UART_XOFF1 (unsigned long)(base+0x18) /* Only when LCR = 0xbf */
+#define UART_XOFF2 (unsigned long)(base+0x1c) /* Only when LCR = 0xbf */
+#define UART_AUTOBAUD_EN (unsigned long)(base+0x20)
+#define UART_HIGHSPEED (unsigned long)(base+0x24)
+#define UART_SAMPLE_COUNT (unsigned long)(base+0x28)
+#define UART_SAMPLE_POINT (unsigned long)(base+0x2c)
+#define UART_AUTOBAUD_REG (unsigned long)(base+0x30)
+#define UART_RATE_FIX_AD (unsigned long)(base+0x34)
+#define UART_AUTOBAUD_SAMPLE (unsigned long)(base+0x38)
+#define UART_GUARD (unsigned long)(base+0x3c)
+#define UART_ESCAPE_DAT (unsigned long)(base+0x40)
+#define UART_ESCAPE_EN (unsigned long)(base+0x44)
+#define UART_SLEEP_EN (unsigned long)(base+0x48)
+#define UART_DMA_EN (unsigned long)(base+0x4c)
+#define UART_RXTRI_AD (unsigned long)(base+0x50)
+#define UART_FRACDIV_L (unsigned long)(base+0x54)
+#define UART_FRACDIV_M (unsigned long)(base+0x58)
+#define UART_FCR_RD (unsigned long)(base+0x5C)
+#define UART_ACTIVE_EN (unsigned long)(base+0x60)
+#define UART_RX_SEL (unsigned long)(base+0xB0)
+#define UART_SLEEP_REQ (unsigned long)(base+0xB4)
+#define UART_SLEEP_ACK (unsigned long)(base+0xB8)
+
+/* system level, not related to hardware */
+#define UST_DUMMY_READ (1 << 31)
+/*---------------------------------------------------------------------------*/
+/* For MT6589, both RX and TX will not use port to send or receive data */
+/* IER */
+#define UART_IER_ERBFI (1 << 0) /* RX buffer conatins data int. */
+#define UART_IER_ETBEI (1 << 1) /* TX FIFO threshold trigger int. */
+#define UART_IER_ELSI (1 << 2) /* BE, FE, PE, or OE int. */
+#define UART_IER_EDSSI (1 << 3) /* CTS change (DCTS) int. */
+#define UART_IER_VFF_FC_EN (1 << 4) /* When set "1", enable flow control triggered by RX FIFO full when VFIFO_EN is set.*/
+#define UART_IER_XOFFI (1 << 5)
+#define UART_IER_RTSI (1 << 6)
+#define UART_IER_CTSI (1 << 7)
+
+#define UART_IER_ALL_INTS (UART_IER_ERBFI|UART_IER_ETBEI|UART_IER_ELSI|\
+ UART_IER_EDSSI|UART_IER_XOFFI|UART_IER_RTSI|\
+ UART_IER_CTSI)
+#define UART_IER_HW_NORMALINTS (UART_IER_ERBFI|UART_IER_ELSI|UART_IER_EDSSI|UART_IER_VFF_FC_EN)
+#define UART_IER_HW_ALLINTS (UART_IER_ERBFI|UART_IER_ETBEI| \
+ UART_IER_ELSI|UART_IER_EDSSI)
+/*---------------------------------------------------------------------------*/
+/* FCR */
+#define UART_FCR_FIFOE (1 << 0)
+#define UART_FCR_CLRR (1 << 1)
+#define UART_FCR_CLRT (1 << 2)
+#define UART_FCR_DMA1 (1 << 3)
+#define UART_FCR_RXFIFO_1B_TRI (0 << 6)
+#define UART_FCR_RXFIFO_6B_TRI (1 << 6)
+#define UART_FCR_RXFIFO_12B_TRI (2 << 6)
+#define UART_FCR_RXFIFO_RX_TRI (3 << 6)
+#define UART_FCR_TXFIFO_1B_TRI (0 << 4)
+#define UART_FCR_TXFIFO_4B_TRI (1 << 4)
+#define UART_FCR_TXFIFO_8B_TRI (2 << 4)
+#define UART_FCR_TXFIFO_14B_TRI (3 << 4)
+
+#define UART_FCR_FIFO_INIT (UART_FCR_FIFOE|UART_FCR_CLRR|UART_FCR_CLRT)
+#define UART_FCR_NORMAL (UART_FCR_FIFO_INIT | \
+ UART_FCR_TXFIFO_4B_TRI| \
+ UART_FCR_RXFIFO_12B_TRI)
+/*---------------------------------------------------------------------------*/
+/* LCR */
+#define UART_LCR_BREAK (1 << 6)
+#define UART_LCR_DLAB (1 << 7)
+
+#define UART_WLS_5 (0 << 0)
+#define UART_WLS_6 (1 << 0)
+#define UART_WLS_7 (2 << 0)
+#define UART_WLS_8 (3 << 0)
+#define UART_WLS_MASK (3 << 0)
+
+#define UART_1_STOP (0 << 2)
+#define UART_2_STOP (1 << 2)
+#define UART_1_5_STOP (1 << 2) /* Only when WLS=5 */
+#define UART_STOP_MASK (1 << 2)
+
+#define UART_NONE_PARITY (0 << 3)
+#define UART_ODD_PARITY (0x1 << 3)
+#define UART_EVEN_PARITY (0x3 << 3)
+#define UART_MARK_PARITY (0x5 << 3)
+#define UART_SPACE_PARITY (0x7 << 3)
+#define UART_PARITY_MASK (0x7 << 3)
+/*---------------------------------------------------------------------------*/
+/* MCR */
+#define UART_MCR_DTR (1 << 0)
+#define UART_MCR_RTS (1 << 1)
+#define UART_MCR_OUT1 (1 << 2)
+#define UART_MCR_OUT2 (1 << 3)
+#define UART_MCR_LOOP (1 << 4)
+#define UART_MCR_DCM_EN (1 << 5) /* MT6589 move to bit5 */
+#define UART_MCR_XOFF (1 << 7) /* read only */
+#define UART_MCR_NORMAL (UART_MCR_DTR|UART_MCR_RTS)
+/*---------------------------------------------------------------------------*/
+/* LSR */
+#define UART_LSR_DR (1 << 0)
+#define UART_LSR_OE (1 << 1)
+#define UART_LSR_PE (1 << 2)
+#define UART_LSR_FE (1 << 3)
+#define UART_LSR_BI (1 << 4)
+#define UART_LSR_THRE (1 << 5)
+#define UART_LSR_TEMT (1 << 6)
+#define UART_LSR_FIFOERR (1 << 7)
+/*---------------------------------------------------------------------------*/
+/* MSR */
+#define UART_MSR_DCTS (1 << 0)
+#define UART_MSR_DDSR (1 << 1)
+#define UART_MSR_TERI (1 << 2)
+#define UART_MSR_DDCD (1 << 3)
+#define UART_MSR_CTS (1 << 4)
+#define UART_MSR_DSR (1 << 5)
+#define UART_MSR_RI (1 << 6)
+#define UART_MSR_DCD (1 << 7)
+/*---------------------------------------------------------------------------*/
+/* EFR */
+#define UART_EFR_EN (1 << 4)
+#define UART_EFR_AUTO_RTS (1 << 6)
+#define UART_EFR_AUTO_CTS (1 << 7)
+#define UART_EFR_SW_CTRL_MASK (0xf << 0)
+
+#define UART_EFR_NO_SW_CTRL (0)
+#define UART_EFR_NO_FLOW_CTRL (0)
+#define UART_EFR_AUTO_RTSCTS (UART_EFR_AUTO_RTS|UART_EFR_AUTO_CTS)
+#define UART_EFR_XON1_XOFF1 (0xa) /* TX/RX XON1/XOFF1 flow control */
+#define UART_EFR_XON2_XOFF2 (0x5) /* TX/RX XON2/XOFF2 flow control */
+#define UART_EFR_XON12_XOFF12 (0xf) /* TX/RX XON1,2/XOFF1,2 flow control */
+
+#define UART_EFR_XON1_XOFF1_MASK (0xa)
+#define UART_EFR_XON2_XOFF2_MASK (0x5)
+/*---------------------------------------------------------------------------*/
+/* IIR (Read Only) */
+#define UART_IIR_NO_INT_PENDING (0x01)
+#define UART_IIR_RLS (0x06) /* Receiver Line Status */
+#define UART_IIR_RDA (0x04) /* Receive Data Available */
+#define UART_IIR_CTI (0x0C) /* Character Timeout Indicator */
+#define UART_IIR_THRE (0x02) /* Transmit Holding Register Empty */
+#define UART_IIR_MS (0x00) /* Check Modem Status Register */
+#define UART_IIR_SW_FLOW_CTRL (0x10) /* Receive XOFF characters */
+#define UART_IIR_HW_FLOW_CTRL (0x20) /* CTS or RTS Rising Edge */
+#define UART_IIR_FIFO_EN (0xc0)
+#define UART_IIR_INT_MASK (0x3f)
+/*---------------------------------------------------------------------------*/
+/* RateFix */
+#define UART_RATE_FIX (1 << 0)
+//#define UART_AUTORATE_FIX (1 << 1)
+#define UART_FREQ_SEL (1 << 1)
+
+#define UART_RATE_FIX_13M (1 << 0) /* means UARTclk = APBclk / 4 */
+#define UART_AUTORATE_FIX_13M (1 << 1)
+#define UART_FREQ_SEL_13M (1 << 2)
+#define UART_RATE_FIX_ALL_13M (UART_RATE_FIX_13M|UART_AUTORATE_FIX_13M| \
+ UART_FREQ_SEL_13M)
+
+#define UART_RATE_FIX_26M (0 << 0) /* means UARTclk = APBclk / 2 */
+#define UART_AUTORATE_FIX_26M (0 << 1)
+#define UART_FREQ_SEL_26M (0 << 2)
+
+#define UART_RATE_FIX_16M25 (UART_FREQ_SEL|UART_RATE_FIX)
+
+#define UART_RATE_FIX_32M5 (UART_RATE_FIX)
+/*---------------------------------------------------------------------------*/
+/* Autobaud sample */
+#define UART_AUTOBADUSAM_13M 7
+#define UART_AUTOBADUSAM_26M 15
+#define UART_AUTOBADUSAM_52M 31
+//#define UART_AUTOBADUSAM_52M 29 /* CHECKME! 28 or 29 ? */
+#define UART_AUTOBAUDSAM_58_5M 31 /* CHECKME! 31 or 32 ? */
+/*---------------------------------------------------------------------------*/
+/* DMA enable */
+#define UART_RX_DMA_EN (1 << 0)
+#define UART_TX_DMA_EN (1 << 1)
+#define UART_TO_CNT_AUTORST (1 << 2)
+/*---------------------------------------------------------------------------*/
+/* Escape character*/
+#define UART_ESCAPE_CH 0x77
+/*---------------------------------------------------------------------------*/
+/* Request UART to sleep*/
+#define UART_CLK_OFF_REQ (1 << 0)
+/*---------------------------------------------------------------------------*/
+/* UART sleep ack*/
+#define UART_CLK_OFF_ACK (1 << 0)
+/*---------------------------------------------------------------------------*/
+/* Debugging */
+typedef struct {
+ u32 NINT:1;
+ u32 ID:5;
+ u32 FIFOE:2;
+ u32 dummy:24;
+} UART_IIR_REG;
+/*---------------------------------------------------------------------------*/
+#ifndef CONFIG_OF
+#define VFF_BASE_CH_S (6)
+#define VFF_BASE_CH(n) (AP_DMA_BASE+0x0080*(n+1+VFF_BASE_CH_S))
+#endif
+#define VFF_INT_FLAG(_b) (_b+0x0000)
+#define VFF_INT_EN(_b) (_b+0x0004)
+#define VFF_EN(_b) (_b+0x0008)
+#define VFF_RST(_b) (_b+0x000C)
+#define VFF_STOP(_b) (_b+0x0010)
+#define VFF_FLUSH(_b) (_b+0x0014)
+#define VFF_ADDR(_b) (_b+0x001C)
+#define VFF_LEN(_b) (_b+0x0024)
+#define VFF_THRE(_b) (_b+0x0028)
+#define VFF_WPT(_b) (_b+0x002C)
+#define VFF_RPT(_b) (_b+0x0030)
+#define VFF_W_INT_BUF_SIZE(_b) (_b+0x0034)
+#define VFF_INT_BUF_SIZE(_b) (_b+0x0038)
+#define VFF_VALID_SIZE(_b) (_b+0x003C)
+#define VFF_LEFT_SIZE(_b) (_b+0x0040)
+#define VFF_DEBUG_STATUS(_b) (_b+0x0050)
+#define VFF_4G_DRAM_SUPPORT(_b) (_b+0x0054)
+#define VFF_VPORT_BASE 0xF7070000
+#define VFF_VPORT_CH(id) (VFF_VPORT_BASE + (id) * 0x00000080)
+/*---------------------------------------------------------------------------*/
+/*VFF_INT_FLAG */
+#define VFF_RX_INT_FLAG0_B (1 << 0) /*rx_vff_valid_size >= rx_vff_thre*/
+#define VFF_RX_INT_FLAG1_B (1 << 1) /*when UART issues flush to DMA and all data in UART VFIFO is transferred to VFF*/
+#define VFF_TX_INT_FLAG0_B (1 << 0) /*tx_vff_left_size >= tx_vff_thrs*/
+#define VFF_INT_FLAG_CLR_B (0 << 0)
+/*VFF_INT_EN*/
+#define VFF_RX_INT_EN0_B (1 << 0) /*rx_vff_valid_size >= rx_vff_thre*/
+#define VFF_RX_INT_EN1_B (1 << 1) /*when UART issues flush to DMA and all data in UART VFIFO is transferred to VFF*/
+#define VFF_TX_INT_EN_B (1 << 0) /*tx_vff_left_size >= tx_vff_thrs*/
+#define VFF_INT_EN_CLR_B (0 << 0)
+/*VFF_RST*/
+#define VFF_WARM_RST_B (1 << 0)
+#define VFF_HARD_RST_B (1 << 1)
+/*VFF_EN*/
+#define VFF_EN_B (1 << 0)
+/*VFF_STOP*/
+#define VFF_STOP_B (1 << 0)
+#define VFF_STOP_CLR_B (0 << 0)
+/*VFF_FLUSH*/
+#define VFF_FLUSH_B (1 << 0)
+#define VFF_FLUSH_CLR_B (0 << 0)
+
+#define VFF_TX_THRE(n) ((n)*7/8) /*tx_vff_left_size >= tx_vff_thrs*/
+#define VFF_RX_THRE(n) ((n)*3/4) // trigger level of rx vfifo
+/*---------------------------------------------------------------------------*/
+#endif /* MTK_UART_H */
diff --git a/drivers/misc/mediatek/uart/mt_fiq_debugger.c b/drivers/misc/mediatek/uart/mt_fiq_debugger.c
new file mode 100644
index 000000000..c4423be2f
--- /dev/null
+++ b/drivers/misc/mediatek/uart/mt_fiq_debugger.c
@@ -0,0 +1,83 @@
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <asm/fiq.h>
+#include <asm/fiq_glue.h>
+#include <asm/fiq_debugger.h>
+#include <mach/irqs.h>
+#include <mach/mt_reg_base.h>
+#include <linux/uart/mtk_uart.h>
+#include <linux/uart/mtk_uart_intf.h>
+
+#define MT_UART_FIQ_ID MT_UART4_IRQ_ID
+
+static void fiq_enable(struct platform_device *pdev, unsigned int fiq, bool enable)
+{
+ if (enable)
+ enable_fiq(fiq);
+ else
+ disable_fiq(fiq);
+}
+
+static void fiq_dbg_force_irq(struct platform_device *pdev, unsigned int irq)
+{
+ trigger_sw_irq(irq);
+}
+
+struct fiq_debugger_pdata fiq_serial_data = {
+ .uart_getc = &fiq_uart_getc,
+ .uart_putc = &fiq_uart_putc,
+ .fiq_enable = &fiq_enable,
+ .fiq_ack = 0,
+ .force_irq = &fiq_dbg_force_irq,
+ .force_irq_ack = 0,
+};
+
+struct resource fiq_resource[] = {
+ [0] = {
+ .start = FIQ_DBG_SGI,
+ .end = FIQ_DBG_SGI,
+ .flags = IORESOURCE_IRQ,
+ .name = "signal",
+ },
+ [1] = {
+ .start = MT_UART_FIQ_ID,
+ .end = MT_UART_FIQ_ID,
+ .flags = IORESOURCE_IRQ,
+ .name = "fiq",
+ },
+};
+
+struct platform_device mt_fiq_debugger = {
+ .name = "fiq_debugger",
+ .id = -1,
+ .dev = {
+ .platform_data = &fiq_serial_data,
+ },
+ .num_resources = ARRAY_SIZE(fiq_resource),
+ .resource = fiq_resource,
+};
+
+void mt_fiq_printf(const char *fmt, ...)
+{
+ char buf[256];
+ va_list ap;
+ unsigned c;
+ char *s;
+
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+
+ s = (char *)buf;
+ while ((c = *s++)) {
+#if 0
+ if (c == '\n') {
+ fiq_uart_putc(NULL, '\r');
+ }
+#endif
+ fiq_uart_putc(NULL, c);
+ }
+}
diff --git a/drivers/misc/mediatek/uart/uart.c b/drivers/misc/mediatek/uart/uart.c
new file mode 100644
index 000000000..b6ede0ce1
--- /dev/null
+++ b/drivers/misc/mediatek/uart/uart.c
@@ -0,0 +1,2834 @@
+/* mediatek/kernel/drivers/uart/uart.c
+ *
+ * (C) Copyright 2008
+ * MediaTek <www.mediatek.com>
+ * MingHsien Hsieh <minghsien.hsieh@mediatek.com>
+ *
+ * MTK UART Driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/******************************************************************************
+ * Dependency
+******************************************************************************/
+#if defined(CONFIG_MTK_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ /*used in serial_core.h*/
+#endif
+/*---------------------------------------------------------------------------*/
+#include <generated/autoconf.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/timer.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/platform_device.h>
+#include <linux/hrtimer.h>
+#include <linux/uaccess.h>
+#include <asm/atomic.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <linux/irq.h>
+#include <asm/scatterlist.h>
+#include <mach/dma.h>
+#include <mach/mt_typedefs.h>
+#include <mach/irqs.h>
+//#include <mach/mt_clkmgr.h>
+#include <linux/slab.h>
+#include "linux/delay.h"
+#include <linux/syscore_ops.h>
+#include <linux/uart/mtk_uart.h>
+#include <linux/uart/mtk_uart_intf.h>
+#include <linux/version.h>
+#include <linux/suspend.h>
+#ifdef CONFIG_OF
+#include <linux/of.h>
+#endif
+
+#if defined(CONFIG_MTK_HDMI_SUPPORT)
+#include "hdmi_cust.h"
+extern bool is_hdmi_active(void);
+extern void hdmi_force_on(int from_uart_drv);
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)
+#define TTY_FLIP_ARG(a) (a)
+#else
+#define TTY_FLIP_ARG(a) ((a)->port)
+#endif
+
+spinlock_t mtk_console_lock;
+spinlock_t mtk_uart_bt_lock;
+
+struct mtk_uart *console_port;
+struct mtk_uart *bt_port = NULL;
+/*---------------------------------------------------------------------------*/
+#define HW_FLOW_CTRL_PORT(uart) (uart->setting->hw_flow)
+/*---------------------------------------------------------------------------*/
+#if defined(ENABLE_VFIFO)
+/*---------------------------------------------------------------------------*/
+static DEFINE_SPINLOCK(mtk_uart_vfifo_port_lock);
+/*---------------------------------------------------------------------------*/
+#ifdef CONFIG_OF
+/*---------------------------------------------------------------------------*/
+#define VFIFO_INIT_RX(c, i, n) \
+ {.ch = (c), .size = (n), .trig = VFF_RX_THRE(n), .type = UART_RX_VFIFO, \
+ .port = NULL, .addr = NULL, \
+ .entry = ATOMIC_INIT(0), .reg_cb = ATOMIC_INIT(0), .iolock=__SPIN_LOCK_UNLOCKED(mtk_uart_vfifo_port[i].lock)}
+/*---------------------------------------------------------------------------*/
+#define VFIFO_INIT_TX(c, i, n) \
+ {.ch = (c), .size = (n), .trig = VFF_TX_THRE(n), .type = UART_TX_VFIFO, \
+ .port = NULL, \
+ .addr = NULL, .entry = ATOMIC_INIT(0), .reg_cb = ATOMIC_INIT(0), .iolock=__SPIN_LOCK_UNLOCKED(mtk_uart_vfifo_port[i].lock)}
+/*---------------------------------------------------------------------------*/
+static struct mtk_uart_vfifo mtk_uart_vfifo_port[] = {
+ VFIFO_INIT_TX(P_DMA_UART1_TX, 0, C_UART1_VFF_TX_SIZE),
+ VFIFO_INIT_RX(P_DMA_UART1_RX, 1, C_UART1_VFF_RX_SIZE),
+ VFIFO_INIT_TX(P_DMA_UART2_TX, 2, C_UART2_VFF_TX_SIZE),
+ VFIFO_INIT_RX(P_DMA_UART2_RX, 3, C_UART2_VFF_RX_SIZE),
+ VFIFO_INIT_TX(P_DMA_UART3_TX, 4, C_UART3_VFF_TX_SIZE),
+ VFIFO_INIT_RX(P_DMA_UART3_RX, 5, C_UART3_VFF_RX_SIZE),
+#if 0 /* MT6589 only 6 DMA channel for UART */
+ VFIFO_INIT_TX(P_DMA_UART4_TX, 6, C_UART4_VFF_TX_SIZE),
+ VFIFO_INIT_RX(P_DMA_UART4_RX, 7, C_UART4_VFF_RX_SIZE),
+#endif
+};
+/*---------------------------------------------------------------------------*/
+#else
+/*---------------------------------------------------------------------------*/
+#define VFIFO_INIT_RX(c, i, n, id) \
+ {.ch = (c), .size = (n), .trig = VFF_RX_THRE(n), .type = UART_RX_VFIFO, \
+ .base = (void*)VFF_BASE_CH(i), .port = NULL, .addr = NULL, \
+ .entry = ATOMIC_INIT(0), .reg_cb = ATOMIC_INIT(0), .iolock=__SPIN_LOCK_UNLOCKED(mtk_uart_vfifo_port[i].lock), \
+ .irq_id = id}
+/*---------------------------------------------------------------------------*/
+#define VFIFO_INIT_TX(c, i, n, id) \
+ {.ch = (c), .size = (n), .trig = VFF_TX_THRE(n), .type = UART_TX_VFIFO, \
+ .base = (void*)VFF_BASE_CH(i), .port = NULL, \
+ .addr = NULL, .entry = ATOMIC_INIT(0), .reg_cb = ATOMIC_INIT(0), .iolock=__SPIN_LOCK_UNLOCKED(mtk_uart_vfifo_port[i].lock), \
+ .irq_id = id}
+/*---------------------------------------------------------------------------*/
+static struct mtk_uart_vfifo mtk_uart_vfifo_port[] = {
+ VFIFO_INIT_TX(P_DMA_UART1_TX, 0, C_UART1_VFF_TX_SIZE, UART1_VFF_TX_IRQ_ID),
+ VFIFO_INIT_RX(P_DMA_UART1_RX, 1, C_UART1_VFF_RX_SIZE, UART1_VFF_RX_IRQ_ID),
+ VFIFO_INIT_TX(P_DMA_UART2_TX, 2, C_UART2_VFF_TX_SIZE, UART2_VFF_TX_IRQ_ID),
+ VFIFO_INIT_RX(P_DMA_UART2_RX, 3, C_UART2_VFF_RX_SIZE, UART2_VFF_RX_IRQ_ID),
+ VFIFO_INIT_TX(P_DMA_UART3_TX, 4, C_UART3_VFF_TX_SIZE, UART3_VFF_TX_IRQ_ID),
+ VFIFO_INIT_RX(P_DMA_UART3_RX, 5, C_UART3_VFF_RX_SIZE, UART3_VFF_RX_IRQ_ID),
+#if 0 /* MT6589 only 6 DMA channel for UART */
+ VFIFO_INIT_TX(P_DMA_UART4_TX, 6, C_UART4_VFF_TX_SIZE),
+ VFIFO_INIT_RX(P_DMA_UART4_RX, 7, C_UART4_VFF_RX_SIZE),
+#endif
+};
+/*---------------------------------------------------------------------------*/
+#endif /*CONFIG_OF*/
+/*---------------------------------------------------------------------------*/
+#endif /*ENABLE_VFIFO*/
+/*---------------------------------------------------------------------------*/
+/* uart control blocks */
+static struct mtk_uart mtk_uarts[UART_NR];
+static unsigned int uart_freeze_enable[UART_NR] = {0};
+
+struct uart_history_data {
+ int index;
+ int offset;
+ u64 last_update;
+ unsigned char *buffer;
+};
+#define UART_HISTORY_DATA_SIZE 4096
+static struct uart_history_data tx_history;
+static struct uart_history_data rx_history;
+/*---------------------------------------------------------------------------*/
+static int mtk_uart_init_ports(void);
+static void mtk_uart_stop_tx(struct uart_port *port);
+/******************************************************************************
+ * SYSFS support
+******************************************************************************/
+#if defined(ENABLE_SYSFS)
+/*---------------------------------------------------------------------------*/
+/*define sysfs entry for configuring debug level and sysrq*/
+ssize_t mtk_uart_attr_show(struct kobject *kobj, struct attribute *attr, char *buffer);
+ssize_t mtk_uart_attr_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t size);
+ssize_t mtk_uart_debug_show(struct kobject *kobj, char *page);
+ssize_t mtk_uart_debug_store(struct kobject *kobj, const char *page, size_t size);
+ssize_t mtk_uart_sysrq_show(struct kobject *kobj, char *page);
+ssize_t mtk_uart_sysrq_store(struct kobject *kobj, const char *page, size_t size);
+ssize_t mtk_uart_vffsz_show(struct kobject *kobj, char *page);
+ssize_t mtk_uart_vffsz_store(struct kobject *kobj, const char *page, size_t size);
+ssize_t mtk_uart_conse_show(struct kobject *kobj, char *page);
+ssize_t mtk_uart_conse_store(struct kobject *kobj, const char *page, size_t size);
+ssize_t mtk_uart_vff_en_show(struct kobject *kobj, char *page);
+ssize_t mtk_uart_vff_en_store(struct kobject *kobj, const char *page, size_t size);
+ssize_t mtk_uart_lsr_status_show(struct kobject *kobj, char *page);
+ssize_t mtk_uart_lsr_status_store(struct kobject *kobj, const char *page, size_t size);
+ssize_t mtk_uart_history_show(struct kobject *kobj, char *page);
+ssize_t mtk_uart_history_store(struct kobject *kobj, const char *page, size_t size);
+/*---------------------------------------------------------------------------*/
+struct sysfs_ops mtk_uart_sysfs_ops = {
+ .show = mtk_uart_attr_show,
+ .store = mtk_uart_attr_store,
+};
+/*---------------------------------------------------------------------------*/
+struct mtuart_entry {
+ struct attribute attr;
+ ssize_t (*show)(struct kobject *kobj, char *page);
+ ssize_t (*store)(struct kobject *kobj, const char *page, size_t size);
+};
+/*---------------------------------------------------------------------------*/
+struct mtuart_entry debug_entry = {
+ { .name = "debug", .mode = S_IRUGO | S_IWUSR },
+ mtk_uart_debug_show,
+ mtk_uart_debug_store,
+};
+/*---------------------------------------------------------------------------*/
+struct mtuart_entry sysrq_entry = {
+ { .name = "sysrq", .mode = S_IRUGO | S_IWUSR },
+ mtk_uart_sysrq_show,
+ mtk_uart_sysrq_store,
+};
+/*---------------------------------------------------------------------------*/
+struct mtuart_entry vffsz_entry = {
+ { .name = "vffsz", .mode = S_IRUGO | S_IWUSR },
+ mtk_uart_vffsz_show,
+ mtk_uart_vffsz_store,
+};
+/*---------------------------------------------------------------------------*/
+struct mtuart_entry conse_entry = {
+ { .name = "conse", .mode = S_IRUGO | S_IWUSR },
+ mtk_uart_conse_show,
+ mtk_uart_conse_store,
+};
+/*---------------------------------------------------------------------------*/
+struct mtuart_entry vff_en_entry = {
+ { .name = "vff_en", .mode = S_IRUGO | S_IWUSR },
+ mtk_uart_vff_en_show,
+ mtk_uart_vff_en_store,
+};
+/*---------------------------------------------------------------------------*/
+struct mtuart_entry lsr_status_entry = {
+ { .name = "lsr_status", .mode = S_IRUGO | S_IWUSR },
+ mtk_uart_lsr_status_show,
+ mtk_uart_lsr_status_store,
+};
+/*---------------------------------------------------------------------------*/
+struct mtuart_entry history_entry = {
+ { .name = "history", .mode = S_IRUGO | S_IWUSR },
+ mtk_uart_history_show,
+ mtk_uart_history_store,
+};
+/*---------------------------------------------------------------------------*/
+struct attribute *mtk_uart_attributes[] = {
+ &conse_entry.attr, /*console setting*/
+#if defined(ENABLE_DEBUG)
+ &debug_entry.attr,
+ &sysrq_entry.attr,
+ &vffsz_entry.attr,
+ &vff_en_entry.attr,
+ &lsr_status_entry.attr,
+ &history_entry.attr,
+#endif
+ NULL,
+};
+/*---------------------------------------------------------------------------*/
+struct kobj_type mtk_uart_ktype = {
+ .sysfs_ops = &mtk_uart_sysfs_ops,
+ .default_attrs = mtk_uart_attributes,
+};
+/*---------------------------------------------------------------------------*/
+struct mtuart_sysobj {
+ struct kobject kobj;
+ atomic_t sysrq;
+ atomic_t vffLen[UART_NR*UART_VFIFO_NUM];
+ atomic_t console_enable;
+} mtk_uart_sysobj = {
+ .console_enable = ATOMIC_INIT(1),
+};
+/*---------------------------------------------------------------------------*/
+int mtk_uart_sysfs(void)
+{
+ struct mtuart_sysobj *obj = &mtk_uart_sysobj;
+ int idx;
+
+ memset(&obj->kobj, 0x00, sizeof(obj->kobj));
+#if defined(CONFIG_MAGIC_SYSRQ)
+ atomic_set(&obj->sysrq, 1);
+#else
+ atomic_set(&obj->sysrq, 0);
+#endif
+#if defined(ENABLE_VFIFO)
+ for (idx = 0; idx < ARRAY_SIZE(obj->vffLen) && idx < ARRAY_SIZE(mtk_uart_vfifo_port); idx++)
+ atomic_set(&obj->vffLen[idx], mtk_uart_vfifo_port[idx].size);
+#endif
+ atomic_set(&obj->console_enable, 1);
+
+ obj->kobj.parent = kernel_kobj;
+ if (kobject_init_and_add(&obj->kobj, &mtk_uart_ktype, NULL, "mtuart")) {
+ kobject_put(&obj->kobj);
+ return -ENOMEM;
+ }
+ kobject_uevent(&obj->kobj, KOBJ_ADD);
+ return 0;
+}
+/*---------------------------------------------------------------------------*/
+ssize_t mtk_uart_attr_show(struct kobject *kobj, struct attribute *attr, char *buffer)
+{
+ struct mtuart_entry *entry = container_of(attr, struct mtuart_entry, attr);
+ return entry->show(kobj, buffer);
+}
+/*---------------------------------------------------------------------------*/
+ssize_t mtk_uart_attr_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t size)
+{
+ struct mtuart_entry *entry = container_of(attr, struct mtuart_entry, attr);
+ return entry->store(kobj, buffer, size);
+}
+/*---------------------------------------------------------------------------*/
+ssize_t mtk_uart_debug_show(struct kobject *kobj, char *buffer)
+{
+ int remain = PAGE_SIZE;
+ int len;
+ char *ptr = buffer;
+ int idx;
+ unsigned int evt_mask;
+
+ for (idx = 0; idx < UART_NR; idx++) {
+ evt_mask = (unsigned int)get_uart_evt_mask(idx);
+ len = scnprintf(ptr, remain, "0x%2x\n", evt_mask);
+ ptr += len;
+ remain -= len;
+ }
+ return (PAGE_SIZE-remain);
+}
+/*---------------------------------------------------------------------------*/
+ssize_t mtk_uart_debug_store(struct kobject *kobj, const char *buffer, size_t size)
+{
+#if (UART_NR < 5)
+
+ int a, b, c, d;
+ int res = sscanf(buffer, "0x%x 0x%x 0x%x 0x%x", &a, &b, &c, &d);
+
+ if (res != 4) {
+ MSG_ERR("%s: expect 4 numbers\n", __FUNCTION__);
+ } else {
+ set_uart_evt_mask(0, a);
+ set_uart_evt_mask(1, b);
+ set_uart_evt_mask(2, c);
+ set_uart_evt_mask(3, d);
+ }
+ return size;
+#else
+ int a, b, c, d, e;
+ int res = sscanf(buffer, "0x%x 0x%x 0x%x 0x%x 0x%x", &a, &b, &c, &d, &e);
+
+ if (res != 5) {
+ MSG_ERR("%s: expect 5 numbers\n", __FUNCTION__);
+ } else {
+ set_uart_evt_mask(0, a);
+ set_uart_evt_mask(1, b);
+ set_uart_evt_mask(2, c);
+ set_uart_evt_mask(3, d);
+ set_uart_evt_mask(4, e);
+}
+#endif
+}
+/*---------------------------------------------------------------------------*/
+ssize_t mtk_uart_sysrq_show(struct kobject *kobj, char *buffer)
+{
+ struct mtuart_sysobj *obj = container_of(kobj, struct mtuart_sysobj, kobj);
+ return scnprintf(buffer, PAGE_SIZE, "%d\n", atomic_read(&obj->sysrq));
+}
+/*---------------------------------------------------------------------------*/
+ssize_t mtk_uart_sysrq_store(struct kobject *kobj, const char *buffer, size_t size)
+{
+ struct mtuart_sysobj *obj = container_of(kobj, struct mtuart_sysobj, kobj);
+ int a;
+ int res = sscanf(buffer, "%d\n", &a);
+
+ if (res != 1) {
+ MSG_ERR("%s: expect 1 number\n", __FUNCTION__);
+ } else {
+ atomic_set(&obj->sysrq, a);
+ }
+ return size;
+}
+/*---------------------------------------------------------------------------*/
+ssize_t mtk_uart_vffsz_show(struct kobject *kobj, char *buffer)
+{
+ ssize_t len = 0;
+#if defined(ENABLE_VFIFO)
+ struct mtuart_sysobj *obj = container_of(kobj, struct mtuart_sysobj, kobj);
+ int idx;
+
+ for (idx = 0; idx < ARRAY_SIZE(obj->vffLen); idx++)
+ len += scnprintf(buffer+len, PAGE_SIZE-len, "[%02d] %4d\n", idx,
+ atomic_read(&obj->vffLen[idx]));
+#endif
+ return len;
+}
+/*---------------------------------------------------------------------------*/
+ssize_t mtk_uart_vffsz_store(struct kobject *kobj, const char *buffer, size_t size)
+{
+#if defined(ENABLE_VFIFO)
+ struct mtuart_sysobj *obj = container_of(kobj, struct mtuart_sysobj, kobj);
+ int idx, sz;
+
+ if (2 != sscanf(buffer, "%d %d", &idx, &sz)) {
+ MSG_ERR("%s: expect 2 variables\n", __FUNCTION__);
+ } else if (idx >= ARRAY_SIZE(obj->vffLen) || (sz%8 != 0)) {
+ MSG_ERR("%s: invalid args %d, %d\n", __FUNCTION__, idx, sz);
+ } else {
+ atomic_set(&obj->vffLen[idx], sz);
+ }
+#endif
+ return size;
+}
+/*---------------------------------------------------------------------------*/
+ssize_t mtk_uart_conse_show(struct kobject *kobj, char *buffer)
+{
+ struct mtuart_sysobj *obj = container_of(kobj, struct mtuart_sysobj, kobj);
+ return scnprintf(buffer, PAGE_SIZE, "%d\n", atomic_read(&obj->console_enable));
+}
+/*---------------------------------------------------------------------------*/
+ssize_t mtk_uart_conse_store(struct kobject *kobj, const char *buffer, size_t size)
+{
+ struct mtuart_sysobj *obj = container_of(kobj, struct mtuart_sysobj, kobj);
+ int enable;
+
+ if (1 != sscanf(buffer, "%d", &enable)) {
+ MSG_ERR("%s: expect 1 variables\n", __FUNCTION__);
+ } else {
+ atomic_set(&obj->console_enable, enable);
+ }
+ return size;
+}
+/*---------------------------------------------------------------------------*/
+#endif /*ENABLE_SYSFS*/
+/*---------------------------------------------------------------------------*/
+ssize_t mtk_uart_vff_en_show(struct kobject *kobj, char *buffer)
+{
+ int remain = PAGE_SIZE;
+ int len;
+ char *ptr = buffer;
+ int idx;
+ struct mtk_uart_setting *uart_setting;
+
+ for (idx = 0; idx < UART_NR; idx++) {
+ uart_setting = get_uart_default_settings(idx);
+ len = scnprintf(ptr,
+ remain,
+ "tx%d_m:%2x rx%d_m:%2x\n",
+ idx,
+ (unsigned int)uart_setting->tx_mode,
+ idx,
+ (unsigned int)uart_setting->rx_mode);
+ ptr += len;
+ remain -= len;
+ }
+ return (PAGE_SIZE-remain);
+}
+/*---------------------------------------------------------------------------*/
+ssize_t mtk_uart_vff_en_store(struct kobject *kobj, const char *buffer, size_t size)
+{
+#if (UART_NR < 5)
+ int u1_tx, u1_rx, u2_tx, u2_rx, u3_tx, u3_rx, u4_tx, u4_rx;
+ struct mtk_uart_setting *uart_setting;
+ int res = sscanf(buffer, "%x %x %x %x %x %x %x %x",
+ &u1_tx, &u1_rx, &u2_tx, &u2_rx, &u3_tx, &u3_rx, &u4_tx, &u4_rx);
+
+ if (res != 8) {
+ MSG_ERR("%s: expect 8 numbers\n", __FUNCTION__);
+ } else {
+ uart_setting = get_uart_default_settings(0);
+ uart_setting->tx_mode = u1_tx;
+ uart_setting->rx_mode = u1_rx;
+ uart_setting = get_uart_default_settings(1);
+ uart_setting->tx_mode = u2_tx;
+ uart_setting->rx_mode = u2_rx;
+ uart_setting = get_uart_default_settings(2);
+ uart_setting->tx_mode = u3_tx;
+ uart_setting->rx_mode = u3_rx;
+ uart_setting = get_uart_default_settings(3);
+ uart_setting->tx_mode = u4_tx;
+ uart_setting->rx_mode = u4_rx;
+ }
+ return size;
+#else
+ int u1_tx, u1_rx, u2_tx, u2_rx, u3_tx, u3_rx, u4_tx, u4_rx, u5_tx, u5_rx;
+ struct mtk_uart_setting *uart_setting;
+ int res = sscanf(buffer, "%x %x %x %x %x %x %x %x %x %x",
+ &u1_tx, &u1_rx, &u2_tx, &u2_rx, &u3_tx, &u3_rx, &u4_tx, &u4_rx, &u5_tx, &u5_rx);
+
+ if (res != 8) {
+ MSG_ERR("%s: expect 8 numbers\n", __FUNCTION__);
+ } else {
+ uart_setting = get_uart_default_settings(0);
+ uart_setting->tx_mode = u1_tx;
+ uart_setting->rx_mode = u1_rx;
+
+ uart_setting = get_uart_default_settings(1);
+ uart_setting->tx_mode = u2_tx;
+ uart_setting->rx_mode = u2_rx;
+
+ uart_setting = get_uart_default_settings(2);
+ uart_setting->tx_mode = u3_tx;
+ uart_setting->rx_mode = u3_rx;
+
+ uart_setting = get_uart_default_settings(3);
+ uart_setting->tx_mode = u4_tx;
+ uart_setting->rx_mode = u4_rx;
+
+ uart_setting = get_uart_default_settings(4);
+ uart_setting->tx_mode = u5_tx;
+ uart_setting->rx_mode = u5_rx;
+}
+ return size;
+#endif
+}
+/*---------------------------------------------------------------------------*/
+ssize_t mtk_uart_lsr_status_show(struct kobject *kobj, char *buffer)
+{
+ int remain = PAGE_SIZE;
+ int len;
+ char *ptr = buffer;
+ int idx;
+ unsigned long lsr_status;
+
+ for (idx = 0; idx < UART_NR; idx++) {
+ lsr_status = get_uart_lsr_status(idx);
+ len = scnprintf(ptr,
+ remain,
+ "%04x ",
+ (unsigned int)lsr_status);
+ ptr += len;
+ remain -= len;
+ set_uart_lsr_status(idx, 0);
+ }
+ len = scnprintf(ptr, remain, "\n");
+ ptr += len;
+ remain -= len;
+ return (PAGE_SIZE-remain);
+}
+/*---------------------------------------------------------------------------*/
+ssize_t mtk_uart_lsr_status_store(struct kobject *kobj, const char *buffer, size_t size)
+{
+#if (UART_NR < 5)
+ int u1_lsr, u2_lsr, u3_lsr, u4_lsr;
+ int res = sscanf(buffer, "%x %x %x %x",
+ &u1_lsr, &u2_lsr, &u3_lsr, &u4_lsr);
+
+ if (res != 4) {
+ MSG_ERR("%s: expect 4 numbers\n", __FUNCTION__);
+ } else {
+ set_uart_lsr_status(0, u1_lsr);
+ set_uart_lsr_status(1, u2_lsr);
+ set_uart_lsr_status(2, u3_lsr);
+ set_uart_lsr_status(3, u4_lsr);
+ }
+ return size;
+#else
+ int u1_lsr, u2_lsr, u3_lsr, u4_lsr, u5_lsr;
+ int res = sscanf(buffer, "%x %x %x %x %x",
+ &u1_lsr, &u2_lsr, &u3_lsr, &u4_lsr, &u5_lsr);
+
+ if (res != 5) {
+ MSG_ERR("%s: expect 5 numbers\n", __FUNCTION__);
+ } else {
+ set_uart_lsr_status(0, u1_lsr);
+ set_uart_lsr_status(1, u2_lsr);
+ set_uart_lsr_status(2, u3_lsr);
+ set_uart_lsr_status(3, u4_lsr);
+ set_uart_lsr_status(4, u4_lsr);
+ }
+ return size;
+#endif
+}
+/*---------------------------------------------------------------------------*/
+static void uart_mem_dump(int nport, void *start_addr, int len)
+{
+ unsigned int *curr_p = (unsigned int *)start_addr;
+ unsigned char *curr_ch_p;
+ int _16_fix_num = len/16;
+ int tail_num = len%16;
+ char buf[16];
+ int i,j;
+
+ if(NULL == curr_p) {
+ printk("[UART%d-DUMP]NULL point to dump!\n", nport);
+ return;
+ }
+ if(0 == len){
+ printk("[UART%d-DUMP]Not need to dump\n", nport);
+ return;
+ }
+
+ printk("[UART%d-DUMP]Base: %p\n", nport, start_addr);
+ // Fix section
+ for(i=0; i<_16_fix_num; i++){
+ printk("[UART%d-DUMP]%03X: %08X %08X %08X %08X\n",
+ nport, i*16, *curr_p, *(curr_p+1), *(curr_p+2), *(curr_p+3));
+ curr_p+=4;
+ }
+
+ // Tail section
+ if(tail_num > 0){
+ curr_ch_p = (unsigned char*)curr_p;
+ for(j=0; j<tail_num; j++){
+ buf[j] = *curr_ch_p;
+ curr_ch_p++;
+ }
+ for(; j<16; j++)
+ buf[j] = 0;
+ curr_p = (unsigned int*)buf;
+ printk("[UART%d-DUMP]%03X: %08X %08X %08X %08X\n",
+ nport, i*16, *curr_p, *(curr_p+1), *(curr_p+2), *(curr_p+3));
+ }
+}
+
+void mtk_uart_dump_history(void)
+{
+ u64 ts_nsec;
+ unsigned long rem_nsec;
+
+ ts_nsec = tx_history.last_update;
+ rem_nsec = do_div(ts_nsec, 1000000000);
+
+ printk("UART Tx port %d: %d/%d @[%5lu.%06lu]\n",
+ tx_history.index, tx_history.offset, UART_HISTORY_DATA_SIZE,
+ (unsigned long)ts_nsec, rem_nsec/1000);
+ uart_mem_dump(tx_history.index, tx_history.buffer, UART_HISTORY_DATA_SIZE);
+
+ ts_nsec = rx_history.last_update;
+ rem_nsec = do_div(ts_nsec, 1000000000);
+
+ printk("UART Rx port %d: %d/%d @[%5lu.%06lu]\n",
+ rx_history.index, rx_history.offset, UART_HISTORY_DATA_SIZE,
+ (unsigned long)ts_nsec, rem_nsec/1000);
+ uart_mem_dump(rx_history.index, rx_history.buffer, UART_HISTORY_DATA_SIZE);
+}
+
+void update_history_byte(char is_tx, int nport, unsigned char byte)
+{
+ struct uart_history_data *x_history;
+
+ x_history = is_tx?&tx_history:&rx_history;
+
+ if(nport == x_history->index) {
+ *(x_history->buffer+x_history->offset) = byte;
+ x_history->offset++;
+ if(x_history->offset == UART_HISTORY_DATA_SIZE)
+ x_history->offset = 0;
+ }
+}
+
+void update_history_time(char is_tx, int nport)
+{
+ struct uart_history_data *x_history;
+
+ x_history = is_tx?&tx_history:&rx_history;
+
+ if(nport == x_history->index)
+ x_history->last_update = local_clock();
+}
+
+void update_history_bulk(char is_tx, int nport, unsigned char *chars, int count)
+{
+ int room;
+ struct uart_history_data *x_history;
+
+ x_history = is_tx?&tx_history:&rx_history;
+ room = UART_HISTORY_DATA_SIZE - x_history->offset;
+
+ if(nport == x_history->index) {
+ if(count <= room) {
+ memcpy(x_history->buffer+x_history->offset, chars, count);
+ x_history->offset += count;
+ if(x_history->offset == UART_HISTORY_DATA_SIZE)
+ x_history->offset = 0;
+ } else {
+ memcpy(x_history->buffer+x_history->offset, chars, room);
+ memcpy(x_history->buffer, chars, count-room);
+ x_history->offset = count-room;
+ if(x_history->offset == UART_HISTORY_DATA_SIZE)
+ x_history->offset = 0;
+ }
+ }
+ x_history->last_update = local_clock();
+}
+
+ssize_t mtk_uart_history_show(struct kobject *kobj, char *buffer)
+{
+ int remain = PAGE_SIZE;
+ int len;
+ char *ptr = buffer;
+
+ len = scnprintf(ptr, remain, "tx(%d):%d; rx(%d):%d\n",
+ tx_history.index, tx_history.offset,
+ rx_history.index, rx_history.offset);
+ ptr += len;
+ remain -= len;
+ mtk_uart_dump_history();
+ return (PAGE_SIZE-remain);
+}
+/*---------------------------------------------------------------------------*/
+ssize_t mtk_uart_history_store(struct kobject *kobj, const char *buffer, size_t size)
+{
+ int tx_index, rx_index;
+ int res = sscanf(buffer, "%d %d", &tx_index, &rx_index);
+
+ tx_history.index = tx_index;
+ rx_history.index = rx_index;
+ tx_history.offset = 0;
+ tx_history.offset = 0;
+ memset(tx_history.buffer, 0, UART_HISTORY_DATA_SIZE);
+ memset(rx_history.buffer, 0, UART_HISTORY_DATA_SIZE);
+ return size;
+}
+//================================ FIQ ==========================================
+#if (defined(CONFIG_FIQ_DEBUGGER_CONSOLE) && defined(CONFIG_FIQ_DEBUGGER))
+#define DEFAULT_FIQ_UART_PORT (3)
+int fiq_console_port = DEFAULT_FIQ_UART_PORT;
+//struct uart_port *p_mtk_uart_port = &(mtk_uarts[DEFAULT_FIQ_UART_PORT].port);
+//EXPORT_SYMBOL(p_mtk_uart_port);
+struct mtk_uart *mt_console_uart = &(mtk_uarts[DEFAULT_FIQ_UART_PORT]);
+#endif
+//==============================================================================
+/*---------------------------------------------------------------------------*/
+/* UART Log port switch feature */
+static int find_string(char str[], const char* fingerprint, int *offset)
+{
+ char *curr=str;
+ int i = 0;
+ int str_len;
+ int fingerprint_len;
+ if( (NULL == str)||(NULL == fingerprint) )
+ return 0;
+ str_len = strlen(str);
+ fingerprint_len = strlen(fingerprint);
+ if(str_len < fingerprint_len)
+ return 0;
+ for(i=0; i<=(str_len-fingerprint_len); i++){
+ if( strncmp(curr, fingerprint, fingerprint_len) == 0 ){
+ if(NULL != offset)
+ *offset = i;
+ return 1;
+ }
+ curr++;
+ }
+ return 0;
+}
+
+static int find_fingerprint(char str[], int *offset)
+{
+ /**
+ * This function limitation:
+ * If the ttyMT number large than 9, this function will work abnormal.
+ * For example, ttyMT12 will be recoginzed as ttyMT1
+ */
+ const char* fingerprint[] =
+ {
+ "console=/dev/null",
+ "console=ttyMT0",
+ "console=ttyMT1",
+ "console=ttyMT2",
+ "console=ttyMT3",
+#if (UART_NR > 4)
+ "console=ttyMT4",
+#endif
+ };
+ int i;
+ for(i=0; i<sizeof(fingerprint)/sizeof(char*); i++){
+ if(find_string(str, fingerprint[i], offset) != 0)
+ return i; // Find it.
+ }
+ return -1; // Not find
+}
+
+static int modify_fingerprint(char str[], int offset, char new_val)
+{
+ if(NULL == str)
+ return 0;
+ str[offset+14-1] = new_val; // 14 = strlen("console=ttyMTx"), we modify x to 1~3
+ return 1;
+}
+
+void adjust_kernel_cmd_line_setting_for_console(char *u_boot_cmd_line, char *kernel_cmd_line)
+{
+ int offset = 0;
+ int kernel_console_port_setting = -1;
+ int u_boot_console_port_setting = -1;
+
+ /* Check u-boot command line setting */
+ u_boot_console_port_setting = find_fingerprint(u_boot_cmd_line, 0);
+ if(-1 == u_boot_console_port_setting){
+ //printf("U-boot does not have console setting, return\n");
+ return;
+ }
+
+ /* U-boot has console setting, check kernel console setting */
+ kernel_console_port_setting = find_fingerprint(kernel_cmd_line, &offset);
+ if(-1 == kernel_console_port_setting){
+ //printf("Kernel does not have console setting, return\n");
+ goto _Exit;
+ }
+
+ /**
+ * Both U-boot and Kernel has console setting.
+ * 1. If the settings are same, return directly;
+ * 2. If kernel console setting is null, then use kernel setting
+ * 3. If u-boot console setting is null, then use kernel setting
+ * 4. If kernel console setting is not null, then use u-boot setting
+ */
+ if(u_boot_console_port_setting == kernel_console_port_setting){
+ //printf("Same console setting, return\n");
+ goto _Exit;
+ }
+ if(0 == kernel_console_port_setting){
+ //printf("Kernel console setting is null, use kernel setting, return\n");
+ goto _Exit;
+ }
+ if(0 == u_boot_console_port_setting){
+ //printf("U-boot console setting is null, use kernel setting, return\n");
+ goto _Exit;
+ }
+ /* Enter here, it means both kernel and u-boot console setting are not null, using u-boot setting */
+ switch(u_boot_console_port_setting){
+ case 1: // Using ttyMT0
+ modify_fingerprint(kernel_cmd_line, offset, '0');
+ break;
+ case 2: // Using ttyMT1
+ modify_fingerprint(kernel_cmd_line, offset, '1');
+ break;
+ case 3: // Using ttyMT2
+ modify_fingerprint(kernel_cmd_line, offset, '2');
+ break;
+ case 4: // Using ttyMT3
+ modify_fingerprint(kernel_cmd_line, offset, '3');
+ break;
+ case 5: // Using ttyMT4
+ modify_fingerprint(kernel_cmd_line, offset, '4');
+ break;
+ default:
+ /* Do nothing */
+ break;
+ }
+
+_Exit:
+#if (defined(CONFIG_FIQ_DEBUGGER_CONSOLE) && defined(CONFIG_FIQ_DEBUGGER))
+ kernel_console_port_setting = find_fingerprint(kernel_cmd_line, &offset);
+ if(-1 == kernel_console_port_setting){
+ //printf("Kernel does not have console setting, return\n");
+ return;
+ }
+
+ if(kernel_console_port_setting > 0) {
+ fiq_console_port = (kernel_console_port_setting-1);
+ mt_console_uart = &(mtk_uarts[fiq_console_port]);
+ }
+#endif
+ return;
+}
+//==============================================================================
+/*-------------------------------- PDN ---------------------------------------*/
+unsigned int mtk_uart_pdn_enable(char *port, int enable)
+{
+ int str_len;
+ int port_num;
+
+ if (port == NULL)
+ return -1;
+
+ str_len = strlen(port);
+ if (str_len != 6) {
+ MSG_ERR( "Length mismatch! len=%d\n", str_len);
+ return -1;
+ }
+
+ if(find_string(port, "ttyMT", 0) == 0) {
+ MSG_ERR( "Format mismatch! str=%s\n", port);
+ return -1;
+ }
+
+ port_num = port[str_len-1]-'0';
+ if (port_num >= UART_NR) {
+ MSG_ERR( "wrong port:%d\n", port_num);
+ return -1;
+ }
+ bt_port = &mtk_uarts[port_num];
+ if (enable)
+ mtk_uart_enable_dpidle(bt_port);
+ else
+ mtk_uart_disable_dpidle(bt_port);
+ return 0;
+}
+
+unsigned int mtk_uart_freeze_enable(char *port, int enable)
+{
+ int str_len;
+ int port_num;
+
+ if (port == NULL)
+ return -1;
+
+ str_len = strlen(port);
+ if (str_len != 6) {
+ MSG_ERR( "Length mismatch! len=%d\n", str_len);
+ return -1;
+ }
+
+ if(find_string(port, "ttyMT", 0) == 0) {
+ MSG_ERR( "Format mismatch! str=%s\n", port);
+ return -1;
+ }
+
+ port_num = port[str_len-1]-'0';
+ if (port_num >= UART_NR) {
+ MSG_ERR( "wrong port:%d\n", port_num);
+ return -1;
+ }
+
+ if (enable)
+ uart_freeze_enable[port_num] = 1;
+ else
+ uart_freeze_enable[port_num] = 0;
+ return 0;
+}
+EXPORT_SYMBOL(mtk_uart_freeze_enable);
+
+/*---------------------------------------------------------------------------*/
+#ifdef CONFIG_MTK_SERIAL_CONSOLE
+/*---------------------------------------------------------------------------*/
+static void mtk_uart_console_write(struct console *co, const char *s,
+ unsigned int count)
+{
+ /* Notice:
+ * (1) The function is called by printk, hence, spin lock can not be used
+ * (2) don't care vfifo setting
+ */
+ #define CONSOLE_RETRY (5000)
+ int i;
+ struct mtk_uart *uart;
+ u32 cnt = 0;
+ unsigned long flags;
+
+
+ if (co->index >= UART_NR || !(co->flags & CON_ENABLED) || !atomic_read(&mtk_uart_sysobj.console_enable))
+ return;
+
+ uart = &mtk_uarts[co->index];
+ for (i = 0; i < (int)count; i++) {
+ cnt = 0;
+ while (!mtk_uart_write_allow(uart)) {
+ barrier();
+ if (cnt++ >= CONSOLE_RETRY) {
+ uart->timeout_count++;
+ return;
+ }
+ }
+ spin_lock_irqsave(&mtk_console_lock, flags);
+ mtk_uart_write_byte(uart, s[i]);
+ spin_unlock_irqrestore(&mtk_console_lock, flags);
+
+ if (s[i] == '\n') {
+ cnt = 0;
+ while (!mtk_uart_write_allow(uart)) {
+ barrier();
+ if (cnt++ >= CONSOLE_RETRY) {
+ uart->timeout_count++;
+ return;
+ }
+ }
+ spin_lock_irqsave(&mtk_console_lock, flags);
+ mtk_uart_write_byte(uart, '\r');
+ spin_unlock_irqrestore(&mtk_console_lock, flags);
+ }
+ }
+}
+/*---------------------------------------------------------------------------*/
+static int __init mtk_uart_console_setup(struct console *co, char *options)
+{
+ struct mtk_uart *uart;
+ struct uart_port *port;
+ int baud = 115200;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+ int ret;
+
+ printk(KERN_ALERT DBG_TAG "mtk console setup : co->index %d options:%s\n",
+ co->index, options);
+
+ if (co->index >= UART_NR)
+ co->index = 0;
+
+ uart = &mtk_uarts[co->index];
+ port = (struct uart_port *)uart;
+
+ console_port = uart;
+
+ mtk_uart_console_setting_switch(uart);
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+ ret = uart_set_options(port, co, baud, parity, bits, flow);
+ printk(KERN_ALERT DBG_TAG "mtk console setup : uart_set_option port(%d) "
+ "baud(%d) parity(%c) bits(%d) flow(%c) - ret(%d)\n",
+ co->index, baud, parity, bits, flow, ret);
+
+ printk(KERN_ALERT DBG_TAG "mtk setting: (%d, %d, %d, %lu, %lu)\n",
+ uart->tx_mode, uart->rx_mode,
+ uart->dma_mode,uart->tx_trig,
+ uart->rx_trig);
+ //mtk_uart_power_up(uart);
+ return ret;
+}
+/*---------------------------------------------------------------------------*/
+static struct uart_driver mtk_uart_drv;
+static struct console mtk_uart_console =
+{
+ .name = "ttyMT",
+#if !defined(CONFIG_MTK_SERIAL_MODEM_TEST)
+ /*don't configure UART4 as console*/
+ .write = mtk_uart_console_write,
+ .setup = mtk_uart_console_setup,
+#endif
+ .device = uart_console_device,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &mtk_uart_drv,
+};
+/*---------------------------------------------------------------------------*/
+static int __init mtk_uart_console_init(void)
+{
+ int err = mtk_uart_init_ports();
+ if (!err)
+ register_console(&mtk_uart_console);
+ return err;
+}
+/*---------------------------------------------------------------------------*/
+console_initcall(mtk_uart_console_init);
+/*---------------------------------------------------------------------------*/
+static int __init mtk_late_console_init(void)
+{
+ if (!(mtk_uart_console.flags & CON_ENABLED))
+ {
+ register_console(&mtk_uart_console);
+ }
+ return 0;
+}
+/*---------------------------------------------------------------------------*/
+late_initcall(mtk_late_console_init);
+/*---------------------------------------------------------------------------*/
+#endif /* CONFIG_MTK_SERIAL_CONSOLE */
+/******************************************************************************
+ * Virtual FIFO implementation
+******************************************************************************/
+#if defined(ENABLE_VFIFO)
+/*---------------------------------------------------------------------------*/
+static int mtk_uart_vfifo_del_dbgbuf(struct mtk_uart_vfifo *vfifo)
+{
+#if defined(ENABLE_VFIFO_DEBUG)
+ int idx;
+ for (idx = 0; idx < ARRAY_SIZE(vfifo->dbg); idx++) {
+ if (vfifo->dbg[idx].dat != 0)
+ kfree(vfifo->dbg[idx].dat);
+ vfifo->dbg[idx].dat = NULL;
+ vfifo->dbg[idx].idx = 0;
+ vfifo->dbg[idx].len = 0;
+ }
+#endif
+ return 0;
+}
+/*---------------------------------------------------------------------------*/
+static int mtk_uart_vfifo_new_dbgbuf(struct mtk_uart_vfifo *vfifo)
+{
+#if defined(ENABLE_VFIFO_DEBUG)
+ int idx;
+ for (idx = 0; idx < ARRAY_SIZE(vfifo->dbg); idx++) {
+ if (vfifo->dbg[idx].dat != 0)
+ kfree(vfifo->dbg[idx].dat);
+ vfifo->dbg[idx].idx = 0;
+ vfifo->dbg[idx].len = vfifo->size;
+ vfifo->dbg[idx].dat = kzalloc(vfifo->dbg[idx].len, GFP_ATOMIC);
+ if (!vfifo->dbg[idx].dat) {
+ mtk_uart_vfifo_del_dbgbuf(vfifo);
+ return -ENOMEM;
+ }
+ }
+#endif
+ return 0;
+}
+/*---------------------------------------------------------------------------*/
+static int mtk_uart_vfifo_create(struct mtk_uart *uart)
+{ /*NOTE: please save the phyiscal address in vff->dmahd*/
+ struct mtk_uart_vfifo *vfifo;
+ int idx, err = 0;
+
+ MSG_FUNC_ENTRY();
+
+ if(!uart->setting->vff){
+ MSG_RAW("[UART%2d] not support VFF, Cancel alloc\n", uart->nport);
+ return err;
+ }
+
+ MSG_RAW("[UART%2d] create\n", uart->nport);
+
+ for (idx = uart->nport*2; idx < uart->nport*2 + 2; idx++) {
+ vfifo = &mtk_uart_vfifo_port[idx];
+ MSG_RAW("[UART%2d] idx=%2d\n", uart->nport, idx);
+ if (vfifo->size){
+ vfifo->addr = dma_alloc_coherent(uart->port.dev, vfifo->size, &vfifo->dmahd, GFP_DMA);
+ //MSG_RAW("Address: virt = 0x%p, phys = 0x%llx\n", vfifo->addr, vfifo->dmahd);
+ }
+ else
+ vfifo->addr = NULL;
+ if (vfifo->size && !vfifo->addr) {
+ err = -ENOMEM;
+ break;
+ } else if ((err = mtk_uart_vfifo_new_dbgbuf(vfifo))) {
+ break;
+ }
+ MSG_RAW("[%2d] %p (%04d) ;\n", idx, vfifo->addr, vfifo->size);
+ }
+ MSG_RAW("\n");
+ return err;
+}
+/*---------------------------------------------------------------------------*/
+static int mtk_uart_vfifo_delete(struct mtk_uart *uart)
+{
+ struct mtk_uart_vfifo *vfifo;
+ int idx;
+
+ MSG_FUNC_ENTRY();
+
+ if(!uart->setting->vff){
+ MSG_RAW("[UART%2d] not support VFF, Cancel free\n", uart->nport);
+ return 0;
+ }
+
+ MSG_RAW("[UART%2d] delete", uart->nport);
+ for (idx = uart->nport*2; idx < uart->nport*2 + 2; idx++) {
+ vfifo = &mtk_uart_vfifo_port[idx];
+ if (vfifo->addr)
+ dma_free_coherent(NULL, vfifo->size, vfifo->addr, vfifo->dmahd);
+ mtk_uart_vfifo_del_dbgbuf(vfifo);
+ MSG_RAW("[%2d] %p (%04d) ;", idx, vfifo->addr, vfifo->size);
+ vfifo->addr = NULL;
+ }
+ MSG_RAW("\n");
+ return 0;
+}
+/*---------------------------------------------------------------------------*/
+int mtk_uart_vfifo_prepare(struct mtk_uart *uart)
+{
+ struct mtuart_sysobj *obj = &mtk_uart_sysobj;
+ struct mtk_uart_vfifo *tport, *rport;
+ int tx = uart->nport << 1;
+ int rx = tx + 1;
+
+ MSG_FUNC_ENTRY();
+
+ if (uart->nport >= UART_NR) {
+ MSG_ERR( "wrong port:%d\n", uart->nport);
+ return -EINVAL;
+ } else if(FALSE ==uart->setting->vff){
+ MSG_ERR( "Port :%d not support vfifo\n", uart->nport);
+ return -EINVAL;
+ }else {
+ tport = &mtk_uart_vfifo_port[tx];
+ rport = &mtk_uart_vfifo_port[rx];
+ }
+ if ((atomic_read(&obj->vffLen[tx]) == tport->size) &&
+ (atomic_read(&obj->vffLen[rx]) == rport->size))
+ return 0;
+ MSG_RAW("re-alloc +\n");
+ mtk_uart_vfifo_delete(uart);
+ tport->size = atomic_read(&obj->vffLen[tx]);
+ tport->trig = VFF_TX_THRE(tport->size);
+ rport->size = atomic_read(&obj->vffLen[rx]);
+ rport->trig = VFF_RX_THRE(rport->size);
+ mtk_uart_vfifo_create(uart);
+ MSG_RAW("re-alloc -\n");
+ return 0;
+}
+/*---------------------------------------------------------------------------*/
+static struct mtk_uart_vfifo *mtk_uart_vfifo_alloc(struct mtk_uart *uart, UART_VFF_TYPE type)
+{
+ struct mtk_uart_vfifo *vfifo = NULL;
+ unsigned long flags;
+ spin_lock_irqsave(&mtk_uart_vfifo_port_lock, flags);
+
+ MSG(INFO, "(%d, %d)", uart->nport, type);
+
+ if ((uart->nport >= UART_NR) || (type >= UART_VFIFO_NUM))
+ vfifo = NULL;
+ else {
+ vfifo = &mtk_uart_vfifo_port[2*uart->nport+type];
+ }
+
+ if (vfifo && vfifo->addr == NULL)
+ vfifo = NULL;
+ MSG(INFO, "alloc vfifo-%d[%d](%p)\n", uart->nport, vfifo->size, vfifo->addr);
+
+ spin_unlock_irqrestore(&mtk_uart_vfifo_port_lock, flags);
+ return vfifo;
+
+}
+/*---------------------------------------------------------------------------*/
+static void mtk_uart_vfifo_free(struct mtk_uart *uart,
+ struct mtk_uart_vfifo *vfifo)
+{
+ unsigned long flags;
+ if (vfifo) {
+ spin_lock_irqsave(&mtk_uart_vfifo_port_lock, flags);
+ vfifo->dma = NULL;
+ vfifo->cur = NULL;
+ vfifo->dbgidx = 0;
+ spin_unlock_irqrestore(&mtk_uart_vfifo_port_lock, flags);
+ }
+}
+/*---------------------------------------------------------------------------*/
+static unsigned int mtk_uart_vfifo_write_allow(struct mtk_uart *uart)
+{
+ return !mtk_uart_vfifo_is_full(uart->tx_vfifo);
+}
+/*---------------------------------------------------------------------------*/
+static unsigned int mtk_uart_vfifo_read_allow(struct mtk_uart *uart)
+{
+ return !mtk_uart_vfifo_is_empty(uart->rx_vfifo);
+}
+/*---------------------------------------------------------------------------*/
+inline static unsigned short mtk_uart_vfifo_get_trig(
+ struct mtk_uart *uart,
+ struct mtk_uart_vfifo *vfifo)
+{
+ return vfifo->trig;
+}
+/*---------------------------------------------------------------------------*/
+#define get_mtk_uart(ptr, type, member) (type *)( (char *)ptr - offsetof(type,member))
+/*---------------------------------------------------------------------------*/
+static enum hrtimer_restart mtk_uart_tx_vfifo_timeout(struct hrtimer *hrt)
+{
+ struct mtk_uart_vfifo *vfifo = container_of(hrt, struct mtk_uart_vfifo, flush);
+ struct mtk_uart_dma *dma = (struct mtk_uart_dma*)vfifo->dma;
+ struct mtk_uart *uart = dma->uart;
+#if defined(ENABLE_VFIFO_DEBUG)
+ ktime_t cur = ktime_get();
+ struct timespec a = ktime_to_timespec(cur);
+
+ MSG(MSC, "flush timeout [%ld %ld]\n", a.tv_sec, a.tv_nsec);
+#endif
+ mtk_uart_tx_vfifo_flush(uart, 1);
+ return HRTIMER_NORESTART;
+}
+/*---------------------------------------------------------------------------*/
+static void mtk_uart_dma_vfifo_callback(void *data)
+{
+ struct mtk_uart_dma *dma = (struct mtk_uart_dma*)data;
+ struct mtk_uart *uart = dma->uart;
+
+ MSG(DMA, "%s VFIFO CB: %4d/%4d\n", dma->dir == DMA_TO_DEVICE ? "TX" : "RX",
+ mtk_uart_vfifo_get_counts(dma->vfifo), dma->vfifo->size);
+
+ if (dma->dir == DMA_FROM_DEVICE) {
+ /*the data must be read before return from callback, otherwise, the interrupt
+ will be triggered again and again*/
+ mtk_uart_dma_vfifo_rx_tasklet((unsigned long)uart);
+ //return; [ALPS00031975]
+ } else if (dma->dir == DMA_TO_DEVICE) {
+ }
+ tasklet_schedule(&dma->tasklet);
+}
+/*---------------------------------------------------------------------------*/
+//static __tcmfunc irqreturn_t mtk_vfifo_irq_handler(int irq, void *dev_id)
+static irqreturn_t mtk_vfifo_irq_handler(int irq, void *dev_id)
+{
+ struct mtk_uart_vfifo *vfifo;
+ vfifo = (struct mtk_uart_vfifo *)dev_id;
+
+ if (!vfifo){
+ printk(KERN_ERR "mtk_vfifo_irq_handler: vfifo is NULL\n");
+ return IRQ_NONE;
+ }
+ if (!vfifo->dma){
+ printk(KERN_ERR "mtk_vfifo_irq_handler: dma is NULL\n");
+ return IRQ_NONE;
+ }
+
+ /* Call call back function */
+ mtk_uart_dma_vfifo_callback(vfifo->dma);
+
+ /* Clear interrupt flag */
+ if(vfifo->type == UART_RX_VFIFO)
+ mtk_uart_vfifo_clear_rx_intr(vfifo);
+ else
+ mtk_uart_vfifo_clear_tx_intr(vfifo);
+
+ return IRQ_HANDLED;
+}
+/*---------------------------------------------------------------------------*/
+static int mtk_uart_dma_alloc(struct mtk_uart *uart,
+ struct mtk_uart_dma *dma, int mode,
+ struct mtk_uart_vfifo *vfifo)
+{
+ int ret = 0;
+
+ MSG_FUNC_ENTRY();
+
+ if (mode == UART_NON_DMA)
+ return -1;
+
+ switch (mode) {
+ case UART_TX_VFIFO_DMA:
+ if (!vfifo) {
+ MSG(ERR, "fail due to NULL tx_vfifo\n");
+ ret = -1;
+ break;
+ }
+
+ vfifo->dma = dma;
+ dma->dir = DMA_TO_DEVICE;
+ dma->mode = mode;
+ dma->vfifo = vfifo;
+ dma->uart = uart;
+
+ init_completion(&dma->done);
+ tasklet_init(&dma->tasklet, mtk_uart_dma_vfifo_tx_tasklet, (unsigned long)uart);
+
+ if (!atomic_read(&vfifo->reg_cb)) {
+ /* disable interrupts */
+ /* FIXME */
+ mtk_uart_vfifo_disable_tx_intr(uart);
+
+ ret = request_irq(vfifo->irq_id, (irq_handler_t)mtk_vfifo_irq_handler, IRQF_LEVEL_TRIGGER_POLARITY, DRV_NAME, vfifo);
+ if (ret)
+ return ret;
+ atomic_set(&vfifo->reg_cb, 1);
+ }
+
+ atomic_set(&dma->free, 1);
+
+ break;
+
+ case UART_RX_VFIFO_DMA:
+ if (!vfifo) {
+ MSG(ERR, "fail due to NULL rx_vfifo\n");
+ ret = -1;
+ break;
+ }
+
+ vfifo->dma = dma;
+ dma->dir = DMA_FROM_DEVICE;
+ dma->mode = mode;
+ dma->vfifo = vfifo;
+ dma->uart = uart;
+
+ init_completion(&dma->done);
+ tasklet_init(&dma->tasklet, mtk_uart_dma_vfifo_rx_tasklet, (unsigned long)uart);
+
+ if (!atomic_read(&vfifo->reg_cb)) {
+ /* disable interrupts */
+ mtk_uart_vfifo_disable_rx_intr(uart);
+
+ ret = request_irq(vfifo->irq_id, (irq_handler_t)mtk_vfifo_irq_handler, IRQF_LEVEL_TRIGGER_POLARITY, DRV_NAME, vfifo);
+ if (ret)
+ return ret;
+ atomic_set(&vfifo->reg_cb, 1);
+ }
+
+ atomic_set(&dma->free, 1);
+
+ break;
+ }
+ return ret;
+}
+/*---------------------------------------------------------------------------*/
+void mtk_uart_dma_stop(struct mtk_uart *uart,
+ struct mtk_uart_dma *dma)
+{
+ MSG_FUNC_ENTRY();
+ if (!dma)
+ return;
+
+ mtk_uart_stop_dma(dma);
+ atomic_set(&dma->free, 1);
+ complete(&dma->done);
+}
+/*---------------------------------------------------------------------------*/
+static void mtk_uart_dma_free(struct mtk_uart *uart,
+ struct mtk_uart_dma *dma)
+{
+ unsigned long flags;
+
+ MSG_FUNC_ENTRY();
+
+ if (!dma)
+ return;
+
+ if (dma->mode == UART_NON_DMA)
+ return;
+
+ if ((dma->mode == UART_RX_VFIFO_DMA || dma->mode == UART_TX_VFIFO_DMA) && (!dma->vfifo))
+ return;
+
+ if (dma->vfifo && !mtk_uart_vfifo_is_empty(dma->vfifo)) {
+ tasklet_schedule(&dma->tasklet);
+ MSG(DMA, "wait for %s vfifo dma completed!!!\n",
+ dma->dir == DMA_TO_DEVICE ? "TX" : "RX");
+ wait_for_completion(&dma->done);
+ }
+ spin_lock_irqsave(&uart->port.lock, flags);
+ mtk_uart_stop_dma(dma);
+ if (dma->vfifo && timer_pending(&dma->vfifo->timer))
+ del_timer_sync(&dma->vfifo->timer);
+ if (dma->vfifo && hrtimer_active(&dma->vfifo->flush))
+ hrtimer_cancel(&dma->vfifo->flush);
+ /* [ALPS00030487] tasklet_kill function may schedule, so release spin lock first,
+ * after release, set spin lock again.
+ */
+ spin_unlock_irqrestore(&uart->port.lock, flags); /* [ALPS00030487] Add this */
+ tasklet_kill(&dma->tasklet);
+ spin_lock_irqsave(&uart->port.lock, flags); /* [ALPS00030487] Add this */
+ mtk_uart_reset_dma(dma);
+ mtk_uart_vfifo_disable(uart, dma->vfifo);
+ mtk_uart_vfifo_free(uart, dma->vfifo);
+ MSG(INFO, "free %s dma completed!!!\n",
+ dma->dir == DMA_TO_DEVICE ? "TX" : "RX");
+ memset(dma, 0, sizeof(struct mtk_uart_dma));
+ spin_unlock_irqrestore(&uart->port.lock, flags);
+
+}
+#endif /*defined(ENABLE_VFIFO)*/
+/*---------------------------------------------------------------------------*/
+static void mtk_uart_set_baud(struct mtk_uart *uart , int baudrate)
+{
+ if (uart->port.flags & ASYNC_SPD_CUST) {
+ /**
+ * [ALPS00137126] Begin
+ * Because the origin design of custom baudrate in linux is for low speed case, we add some
+ * modify to support high speed case.
+ * NOTE: If the highest bit of "custom_divisor" is ONE, we will use custom_divisor store baudrate
+ * directly. That means(we suppose unsigned int is 32 bits):
+ * custom_divisor[31] == 1, then custom_divisor[30..0] == custom baud rate
+ * custom_divisor[31] == 0, then custom_divisor[30..0] == sysclk/16/baudrate
+ */
+ if(uart->port.custom_divisor & (1<<31) ){
+ baudrate = uart->port.custom_divisor&(~(1<<31));
+ if( baudrate > (uart->sysclk>>2) ) /* Baud rate should not more than sysclk/4 */
+ baudrate = 9600;
+ }else{
+ /*the baud_base gotten in user space eqauls to sysclk/16.
+ hence, we need to restore the difference when calculating custom baudrate */
+ if (!uart->custom_baud) {
+ baudrate = uart->sysclk/16;
+ baudrate = baudrate/uart->port.custom_divisor;
+ } else {
+ baudrate = uart->custom_baud;
+ }
+ /* [ALPS00137126] End */
+ }
+ MSG(CFG, "CUSTOM, baudrate = %d, divisor = %d\n", baudrate, uart->port.custom_divisor);
+ }
+
+ if (uart->auto_baud)
+ mtk_uart_set_auto_baud(uart);
+
+ mtk_uart_baud_setting(uart, baudrate);
+
+ uart->baudrate = baudrate;
+}
+/*---------------------------------------------------------------------------*/
+static inline bool mtk_uart_enable_sysrq(struct mtk_uart *uart)
+{
+ return uart->setting->sysrq;
+}
+/*---------------------------------------------------------------------------*/
+static void mtk_uart_rx_chars(struct mtk_uart *uart)
+{
+ struct uart_port *port = &uart->port;
+ struct tty_struct *tty = uart->port.state->port.tty;
+ int max_count = UART_FIFO_SIZE;
+ unsigned int data_byte, status;
+ unsigned int flag;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ //MSG_FUNC_ENTRY();
+ while (max_count-- > 0) {
+
+ /* check status */
+ if (!mtk_uart_data_ready(uart))
+ break;
+#if 0
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+ if (tty->low_latency) {
+ /*
+ * If this failed then we will throw away the
+ * bytes but must do so to clear interrupts
+ */
+ tty_flip_buffer_push(tty);
+ }
+ }
+#endif
+ /* read the byte */
+ data_byte = uart->read_byte(uart);
+ port->icount.rx++;
+ flag = TTY_NORMAL;
+
+ update_history_byte(0, uart->nport, data_byte);
+
+ status = mtk_uart_filter_line_status(uart);
+
+ /* error handling routine */
+ 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;
+ }
+
+#ifdef CONFIG_MAGIC_SYSRQ
+ if (mtk_uart_enable_sysrq(uart))
+ {
+ if (uart_handle_sysrq_char(port, data_byte))
+ continue;
+
+ /* FIXME. Infinity, 20081002, 'BREAK' char to enable sysrq handler { */
+ if (data_byte == 0)
+ uart->port.sysrq = jiffies + HZ * 2;
+ /* FIXME. Infinity, 20081002, 'BREAK' char to enable sysrq handler } */
+ }
+#endif
+
+ if (!tty_insert_flip_char(TTY_FLIP_ARG(tty), data_byte, flag))
+ MSG(ERR, "tty_insert_flip_char: no space");
+ }
+ tty_flip_buffer_push(TTY_FLIP_ARG(tty));
+ update_history_time(0, uart->nport);
+ spin_unlock_irqrestore(&port->lock, flags);
+ MSG(FUC, "%s (%2d)\n", __FUNCTION__, UART_FIFO_SIZE - max_count - 1);
+#if defined(CONFIG_MTK_HDMI_SUPPORT)
+#ifdef MHL_UART_SHARE_PIN
+ if((UART_FIFO_SIZE - max_count - 1) > 0)
+ {
+ hdmi_force_on(UART_FIFO_SIZE - max_count - 1);
+ }
+#endif
+#endif
+}
+/*---------------------------------------------------------------------------*/
+static void mtk_uart_tx_chars(struct mtk_uart *uart)
+{
+ /* Notice:
+ * The function is called by uart_start, which is protected by spin lock,
+ * Hence, no spin-lock is required in the functions
+ */
+
+ struct uart_port *port = &uart->port;
+ struct circ_buf *xmit = &port->state->xmit;
+ int count;
+
+ /* 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;
+ return;
+ }
+
+ /* stop tx if circular buffer is empty or this port is stopped */
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+ {
+ struct tty_struct *tty = port->state->port.tty;
+ if (!uart_circ_empty(xmit))
+ MSG(ERR, "\t\tstopped: empty: %d %d %d\n", uart_circ_empty(xmit), tty->stopped, tty->hw_stopped);
+ mtk_uart_stop_tx(port);
+ return;
+ }
+
+ count = port->fifosize - 1;
+
+ do {
+ if (uart_circ_empty(xmit))
+ break;
+ if ((count == 1) || (!uart->write_allow(uart))) {
+ //to avoid the interrupt is not enable.
+ mtk_uart_enable_intrs(uart, UART_IER_ETBEI);
+ break;
+ }
+ uart->write_byte(uart, xmit->buf[xmit->tail]);
+
+ update_history_byte(1, uart->nport, xmit->buf[xmit->tail]);
+
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+
+ } while (--count > 0);
+
+ MSG(INFO, "TX %d chars\n", port->fifosize - 1 - count);
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+
+ if (uart_circ_empty(xmit))
+ mtk_uart_stop_tx(port);
+
+ update_history_time(1, uart->nport);
+}
+/*---------------------------------------------------------------------------*/
+static void mtk_uart_rx_handler(struct mtk_uart *uart, int intrs)
+{
+ if (uart->rx_mode == UART_NON_DMA) {
+ mtk_uart_rx_chars(uart);
+ } else if (uart->rx_mode == UART_RX_VFIFO_DMA) {
+#if defined(ENABLE_VFIFO)
+ mtk_uart_rx_pre_handler(uart, intrs);
+ mtk_uart_dma_vfifo_rx_tasklet((unsigned long)uart);
+#endif
+ }
+}
+/*---------------------------------------------------------------------------*/
+void mtk_uart_tx_handler(struct mtk_uart *uart)
+{
+ struct uart_port *port = &uart->port;
+ unsigned long flags;
+ if (uart->tx_mode == UART_NON_DMA) {
+ spin_lock_irqsave(&port->lock, flags);
+ mtk_uart_tx_chars(uart);
+ spin_unlock_irqrestore(&port->lock, flags);
+ } else if (uart->tx_mode == UART_TX_VFIFO_DMA) {
+ tasklet_schedule(&uart->dma_tx.tasklet);
+ }
+}
+/*---------------------------------------------------------------------------*/
+#ifdef ENABLE_DEBUG
+/*---------------------------------------------------------------------------*/
+static const char *fifo[] = {"No FIFO", "Unstable FIFO",
+ "Unknown", "FIFO Enabled"};
+static const char *intrrupt[] = {"Modem Status Chg", "Tx Buffer Empty",
+ "Rx Data Received", "BI, FE, PE, or OE",
+ "0x04", "0x05", "Rx Data Timeout", "0x07",
+ "SW Flow Control", "0x09", "0x10", "0x11", "0x12",
+ "0x13", "0x14", "0x15", "HW Flow Control"};
+/*---------------------------------------------------------------------------*/
+#endif
+
+#ifndef CONFIG_FIQ_DEBUGGER
+#ifdef CONFIG_MT_PRINTK_UART_CONSOLE
+extern bool printk_disable_uart;
+extern int mt_need_uart_console;
+#endif
+#endif
+
+/*---------------------------------------------------------------------------*/
+//static __tcmfunc irqreturn_t mtk_uart_irq(int irq, void *dev_id)
+static irqreturn_t mtk_uart_irq(int irq, void *dev_id)
+{
+ unsigned int intrs, timeout = 0;
+ struct mtk_uart *uart = (struct mtk_uart *)dev_id;
+
+#ifndef CONFIG_FIQ_DEBUGGER
+#ifdef CONFIG_MT_PRINTK_UART_CONSOLE
+ unsigned long base;
+ base = uart->base;
+ //do not print something when enter char into console uart. by hujian@BSP.
+ //if ((uart == console_port) && (UART_READ32(UART_LSR) & 0x01))
+ // printk_disable_uart = 0;
+#endif
+#endif
+
+ intrs = mtk_uart_get_interrupt(uart);
+
+#ifdef ENABLE_DEBUG
+ {
+ UART_IIR_REG *iir = (UART_IIR_REG *)&intrs;
+ if (iir->NINT)
+ MSG(INT, "No interrupt (%s)\n", fifo[iir->FIFOE]);
+ else if (iir->ID < ARRAY_SIZE(intrrupt))
+ MSG(INT, "%02x %s (%s)\n", iir->ID, intrrupt[iir->ID], fifo[iir->FIFOE]);
+ else
+ MSG(INT, "%2x\n", iir->ID);
+ }
+#endif
+ intrs &= UART_IIR_INT_MASK;
+
+ if (intrs == UART_IIR_NO_INT_PENDING)
+ return IRQ_HANDLED;
+
+ if (intrs == UART_IIR_RLS) {
+ /* BE, FE, PE, or OE occurs */
+ } else if (intrs == UART_IIR_RDA) {
+ } else if (intrs == UART_IIR_CTI) {
+ timeout = 1;
+ } else if (intrs == UART_IIR_THRE) {
+ mtk_uart_tx_handler(uart);
+ } else if (intrs == UART_IIR_MS) {
+ mtk_uart_get_modem_status(uart);
+ } else if (intrs == UART_IIR_SW_FLOW_CTRL) {
+ /* XOFF is received */
+ } else if (intrs == UART_IIR_HW_FLOW_CTRL) {
+ /* CTS or RTS is in rising edge */
+ }
+ mtk_uart_intr_last_check(uart, intrs);
+ mtk_uart_rx_handler(uart, intrs);
+ return IRQ_HANDLED;
+}
+/*---------------------------------------------------------------------------*/
+/* test whether the transmitter fifo and shifter for the port is empty. */
+static unsigned int mtk_uart_tx_empty(struct uart_port *port)
+{
+ struct mtk_uart *uart = (struct mtk_uart *)port;
+
+ MSG_FUNC_ENTRY();
+
+#if defined(ENABLE_VFIFO)
+ if (uart->tx_mode == UART_TX_VFIFO_DMA)
+ return mtk_uart_vfifo_is_empty(uart->dma_tx.vfifo) ? TIOCSER_TEMT : 0;
+ else
+#endif
+ return uart->write_allow(uart) ? TIOCSER_TEMT : 0;
+}
+/*---------------------------------------------------------------------------*/
+/* FIXME */
+/* stop transmitting characters
+ * Note: this function is call with interrupt disabled
+ */
+static void mtk_uart_stop_tx(struct uart_port *port)
+{
+ struct mtk_uart *uart = (struct mtk_uart *)port;
+
+ MSG_FUNC_ENTRY();
+#if defined(ENABLE_VFIFO)
+ if (uart->tx_mode == UART_TX_VFIFO_DMA){
+ /*1. UART_IER_ETBEI can't be disabled or zero data appears in TX*/
+ /*2. TX_INT_EN.INTEN will be reset automatically by HW*/
+ } else
+#endif
+ /* disable tx interrupt */
+ mtk_uart_disable_intrs(uart, UART_IER_ETBEI);
+ uart->tx_stop = 1;
+}
+/*---------------------------------------------------------------------------*/
+/* FIXME */
+/* start transmitting characters.
+ * Note: this function is call with interrupt disabled
+ */
+static void mtk_uart_start_tx(struct uart_port *port)
+{
+ struct mtk_uart *uart = (struct mtk_uart *)port;
+ struct circ_buf *xmit = &port->state->xmit;
+ unsigned long size;
+
+ size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+
+ if (!size)
+ return;
+
+ uart->tx_stop = 0;
+ reset_tx_raw_data(uart);
+
+#if defined(ENABLE_VFIFO)
+ if (uart->tx_mode == UART_TX_VFIFO_DMA) {
+ if (UART_DEBUG_EVT(DBG_EVT_BUF))
+ printk("[UART%d] mtk_uart_start_tx\n", uart->nport);
+ if (!uart->write_allow(uart))
+ mtk_uart_vfifo_enable_tx_intr(uart);
+ else
+ mtk_uart_dma_vfifo_tx_tasklet((unsigned long)uart);
+ }
+ else {
+#else
+ {
+#endif
+ if (uart->write_allow(uart))
+ mtk_uart_tx_chars(uart);
+ }
+}
+/*---------------------------------------------------------------------------*/
+static void mtk_uart_send_xchar(struct uart_port *port, char ch)
+{
+ struct mtk_uart *uart = (struct mtk_uart *)port;
+ unsigned long flags;
+
+ MSG_FUNC_ENTRY();
+
+ if (uart->tx_stop)
+ return;
+
+ spin_lock_irqsave(&port->lock, flags);
+ while (!mtk_uart_write_allow(uart));
+ mtk_uart_write_byte(uart, (unsigned char)ch);
+ port->icount.tx++;
+ spin_unlock_irqrestore(&port->lock, flags);
+ return;
+}
+/*---------------------------------------------------------------------------*/
+/* enable the modem status interrupts */
+static void mtk_uart_enable_ms(struct uart_port *port)
+{
+ struct mtk_uart *uart = (struct mtk_uart *)port;
+
+ MSG_FUNC_ENTRY();
+ uart->ms_enable = 1;
+}
+/*---------------------------------------------------------------------------*/
+/* grab any interrupt resources and initialize any low level driver state */
+static int mtk_uart_startup(struct uart_port *port)
+{
+ struct mtk_uart *uart = (struct mtk_uart *)port;
+ int ret;
+ long mask = UART_IER_HW_NORMALINTS;
+
+ MSG_FUNC_ENTRY();
+
+ /*the uart port is power up in power_mgnt*/
+
+ /*Reset default flag when the uart starts up, or the previous setting,
+ *such as custom baudrate will be still applied even it is ever closed
+ */
+ //uart->port.flags = UPF_BOOT_AUTOCONF;
+ //uart->port.custom_divisor = 1;
+
+ /* Check whether is ATE_Factory mode */
+ #ifdef ATE_FACTORY_ENABLE
+ mtk_uart_is_ate_factory_mode(uart);
+ #endif /* ATE_FACTORY_ENABLE */
+
+ uart->fctl_mode = UART_FC_NONE;
+
+ /* disable interrupts */
+ mtk_uart_disable_intrs(uart, UART_IER_ALL_INTS);
+
+ /* allocate irq line */
+ //ret = request_irq(port->irq, mtk_uart_irq, 0, DRV_NAME, uart);
+#ifdef CONFIG_OF
+ ret = request_irq(port->irq, (irq_handler_t)mtk_uart_irq, uart->setting->irq_flags, DRV_NAME, uart); /* [ALPS00142658] Fix incompatible pointer type waning */
+#else
+ ret = request_irq(port->irq, (irq_handler_t)mtk_uart_irq, IRQF_LEVEL_TRIGGER_POLARITY, DRV_NAME, uart); /* [ALPS00142658] Fix incompatible pointer type waning */
+#endif
+ if (ret)
+ return ret;
+
+#if defined(ENABLE_VFIFO)
+#if defined(ENABLE_VFIFO_DEBUG)
+ mtk_uart_vfifo_prepare(uart);
+ uart->dma_mode = uart->setting->dma_mode;
+ uart->tx_mode = uart->setting->tx_mode;
+ uart->rx_mode = uart->setting->rx_mode;
+ uart->tx_trig = uart->setting->tx_trig;
+ uart->rx_trig = uart->setting->rx_trig;
+#endif
+ /* allocate vfifo */
+ if (uart->rx_mode == UART_RX_VFIFO_DMA) {
+ uart->rx_vfifo = mtk_uart_vfifo_alloc(uart, UART_RX_VFIFO);
+ ret = mtk_uart_dma_alloc(uart, &uart->dma_rx, uart->rx_mode, uart->rx_vfifo);
+ if (!uart->rx_vfifo || ret) {
+ uart->rx_mode = UART_NON_DMA;
+ MSG(ERR, "RX DMA alloc fail [%d]\n", ret);
+ }
+ }
+ if (uart->tx_mode == UART_TX_VFIFO_DMA) {
+ uart->tx_vfifo = mtk_uart_vfifo_alloc(uart, UART_TX_VFIFO);
+ ret = mtk_uart_dma_alloc(uart, &uart->dma_tx, uart->tx_mode, uart->tx_vfifo);
+ if (!uart->tx_vfifo || ret) {
+ uart->tx_mode = UART_NON_DMA;
+ MSG(ERR, "TX DMA alloc fail [%d]\n", ret);
+ }
+ }
+
+ /* start vfifo dma */
+ if (uart->tx_mode == UART_TX_VFIFO_DMA) {
+ uart->write_allow = mtk_uart_vfifo_write_allow;
+ uart->write_byte = mtk_uart_vfifo_write_byte;
+ mtk_uart_vfifo_enable(uart, uart->tx_vfifo);
+ mtk_uart_dma_setup(uart, &uart->dma_tx);
+ if (mtk_uart_dma_start(uart, &uart->dma_tx))
+ MSG(ERR,"mtk_uart_dma_start fails\n");
+
+ hrtimer_init(&uart->tx_vfifo->flush, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+ uart->tx_vfifo->flush.function = mtk_uart_tx_vfifo_timeout;
+ } else if (uart->tx_mode == UART_NON_DMA) {
+ uart->write_allow = mtk_uart_write_allow;
+ uart->write_byte = mtk_uart_write_byte;
+ }
+ if (uart->rx_mode == UART_RX_VFIFO_DMA) {
+ uart->read_allow = mtk_uart_vfifo_read_allow;
+ uart->read_byte = mtk_uart_vfifo_read_byte;
+ mtk_uart_vfifo_enable(uart, uart->rx_vfifo);
+ mtk_uart_dma_setup(uart, &uart->dma_rx);
+ if (mtk_uart_dma_start(uart, &uart->dma_rx))
+ MSG(ERR,"mtk_uart_dma_start fails\n");
+ } else if (uart->rx_mode == UART_NON_DMA) {
+ uart->read_allow = mtk_uart_read_allow;
+ uart->read_byte = mtk_uart_read_byte;
+ }
+#endif
+ if (uart->tx_mode == UART_TX_VFIFO_DMA || uart->rx_mode == UART_RX_VFIFO_DMA){
+ if (!bt_port || (bt_port && (uart != bt_port)))
+ mtk_uart_disable_dpidle(uart);
+ } else if (uart->tx_mode == UART_NON_DMA && uart->rx_mode == UART_NON_DMA){
+ mtk_uart_enable_dpidle(uart);
+ }
+
+ uart->tx_stop = 0;
+ uart->rx_stop = 0;
+
+ /* After applying UART as Level-Triggered IRQ, the function must be called or
+ * the interrupt will be incorrect activated.
+ */
+ mtk_uart_fifo_set_trig(uart, uart->tx_trig, uart->rx_trig);
+ mtk_uart_enable_sleep(uart);
+
+ /* enable interrupts */
+ mtk_uart_enable_intrs(uart, mask);
+ return 0;
+}
+/*---------------------------------------------------------------------------*/
+/* disable the port, disable any break condition that may be in effect, and
+ * free any interrupt resources
+ */
+static void mtk_uart_shutdown(struct uart_port *port)
+{
+ struct mtk_uart *uart = (struct mtk_uart *)port;
+
+ MSG_FUNC_ENTRY();
+
+ /* disable interrupts */
+ mtk_uart_disable_intrs(uart, UART_IER_ALL_INTS);
+
+#if defined(ENABLE_VFIFO)
+ /* free dma channels and vfifo */
+ mtk_uart_dma_free(uart, &uart->dma_tx);
+ mtk_uart_dma_free(uart, &uart->dma_rx);
+#endif
+
+ mdelay(1);
+ mtk_uart_fifo_flush(uart);
+
+ /* release irq line */
+ free_irq(port->irq, port);
+
+ mtk_uart_enable_dpidle(uart);
+ /* the uart port will be powered off in power_mgnt */
+}
+/*---------------------------------------------------------------------------*/
+static void mtk_uart_flush_buffer(struct uart_port *port)
+{
+#if defined(ENABLE_DEBUG)
+ struct mtk_uart *uart = (struct mtk_uart *)port;
+
+ MSG_FUNC_ENTRY();
+#endif
+ //mtk_uart_fifo_flush(uart);
+}
+/*---------------------------------------------------------------------------*/
+/*
+ * For stability test
+ */
+void mtk_uart_update_sysclk(void)
+{
+ int i;
+ unsigned long flags;
+ struct mtk_uart *uart;
+ struct uart_port *port;
+ unsigned int baud;
+
+ for (i = 0; i < UART_NR; i++) {
+ uart = &mtk_uarts[i];
+ port = &uart->port;
+ baud = uart->baudrate;
+ port->uartclk = UART_SYSCLK; //mt6575_get_bus_freq()*1000/4;
+ uart->sysclk = UART_SYSCLK; //mt6575_get_bus_freq()*1000/4;
+ if(baud == 0) continue; //The istance is not initialized yet.
+ spin_lock_irqsave(&port->lock, flags);
+ mtk_uart_set_baud(uart, baud);
+ spin_unlock_irqrestore(&port->lock, flags);
+ }
+}
+EXPORT_SYMBOL(mtk_uart_update_sysclk);
+/*---------------------------------------------------------------------------*/
+/* change the port parameters, including word length, parity, stop bits.
+ * update read_status_mask and ignore_status_mask to indicate the types of
+ * events we are interrested in receiving
+ */
+static void mtk_uart_set_termios(struct uart_port *port,
+ struct ktermios *termios, struct ktermios *old)
+{
+ struct mtk_uart *uart = (struct mtk_uart *)port;
+ unsigned long flags;
+ unsigned int baud;
+ int datalen, mode;
+ int parity = 0;
+ int stopbit = 1;
+
+ MSG_FUNC_ENTRY();
+
+ /* datalen : default 8bits */
+ switch (termios->c_cflag & CSIZE) {
+ case CS5:
+ datalen = 5;
+ break;
+ case CS6:
+ datalen = 6;
+ break;
+ case CS7:
+ datalen = 7;
+ break;
+ case CS8:
+ default:
+ datalen = 8;
+ break;
+ }
+
+ /* stopbit : default 1 */
+ if (termios->c_cflag & CSTOPB)
+ stopbit = 2;
+
+ /* parity : default none */
+ if (termios->c_cflag & PARENB) {
+ if (termios->c_cflag & PARODD)
+ parity = 1; /* odd */
+ else
+ parity = 2; /* even */
+ }
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ /* read status mask */
+ port->read_status_mask = 0;
+ if (termios->c_iflag & INPCK) {
+ /* frame error, parity error */
+ port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+ }
+ if (termios->c_iflag & (BRKINT | PARMRK)) {
+ /* break error */
+ port->read_status_mask |= UART_LSR_BI;
+ }
+
+ port->ignore_status_mask = 0;
+ if (termios->c_iflag & IGNPAR) {
+ /* ignore parity and framing errors */
+ port->ignore_status_mask |= UART_LSR_FE | UART_LSR_PE;
+ }
+ if (termios->c_iflag & IGNBRK) {
+ /* ignore break errors. */
+ port->ignore_status_mask |= UART_LSR_BI;
+ if (termios->c_iflag & IGNPAR) {
+ /* ignore overrun errors */
+ port->ignore_status_mask |= UART_LSR_OE;
+ }
+ }
+
+ /* ignore all characters if CREAD is not set */
+ if ((termios->c_cflag & CREAD) == 0) {
+ uart->ignore_rx = 1;
+ }
+
+ /* update per port timeout */
+ baud = uart_get_baud_rate(port, termios, old, 0, uart->sysclk); /*when dividor is 1, baudrate = clock*/
+ uart_update_timeout(port, termios->c_cflag, baud);
+ mtk_uart_config(uart, datalen, stopbit, parity);
+ mtk_uart_set_baud(uart, baud);
+
+ /* setup fifo trigger level */
+ mtk_uart_fifo_set_trig(uart, uart->tx_trig, uart->rx_trig);
+
+ /* setup hw flow control: only port 0 ~1 support hw rts/cts */
+ MSG(CFG, "c_lflag:%X, c_iflag:%X, c_oflag:%X, c_cflag:%X\n", termios->c_lflag, termios->c_iflag, termios->c_oflag, termios->c_cflag);
+ if (HW_FLOW_CTRL_PORT(uart) && (termios->c_cflag & CRTSCTS) && (!(termios->c_iflag&0x80000000))) {
+ printk(KERN_NOTICE "Hardware Flow Control\n");
+ mode = UART_FC_HW;
+ } else if (termios->c_iflag & 0x80000000) {
+ printk(KERN_NOTICE "MTK Software Flow Control\n");
+ mode = UART_FC_SW;
+ } else if (termios->c_iflag & (IXON | IXOFF | IXANY)) {
+ printk(KERN_NOTICE "Linux default SW Flow Control\n");
+ mode = UART_FC_NONE;
+ } else {
+ printk(KERN_NOTICE "No Flow Control\n");
+ mode = UART_FC_NONE;
+ }
+ mtk_uart_set_flow_ctrl(uart, mode);
+
+ /* determine if port should enable modem status interrupt */
+ if (UART_ENABLE_MS(port, termios->c_cflag))
+ uart->ms_enable = 1;
+ else
+ uart->ms_enable = 0;
+
+ if (console_port && (uart == console_port) && uart->port.cons)
+ {
+ uart->port.cons->cflag = termios->c_cflag;
+ }
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+/*---------------------------------------------------------------------------*/
+/* perform any power management related activities on the port */
+static void mtk_uart_power_mgnt(struct uart_port *port, unsigned int state,
+ unsigned int oldstate)
+{
+ struct mtk_uart *uart = (struct mtk_uart *)port;
+
+ MSG(FUC, "%s(%d->%d)\n", __func__, oldstate, state);
+
+ switch (state) {
+ case 0:
+ mtk_uart_power_up(uart);
+ break;
+ case 3:
+ mtk_uart_power_down(uart);
+ break;
+ default:
+ MSG(ERR, "unkown pm: %d\n", state);
+ }
+}
+/*---------------------------------------------------------------------------*/
+static int mtk_uart_set_wake(struct uart_port *port, unsigned int state)
+{
+ return 0; /* Not used in current kernel version */
+}
+/*---------------------------------------------------------------------------*/
+/* return a pointer to a string constant describing the port */
+static const char *mtk_uart_type(struct uart_port *port)
+{
+ return "MTK UART";
+}
+/*---------------------------------------------------------------------------*/
+/* release any memory and io region resources currently in used by the port */
+static void mtk_uart_release_port(struct uart_port *port)
+{
+ return;
+}
+/*---------------------------------------------------------------------------*/
+/* request any memory and io region resources required by the port */
+static int mtk_uart_request_port(struct uart_port *port)
+{
+ return 0;
+}
+/*---------------------------------------------------------------------------*/
+/* perform any autoconfiguration steps required by the port.
+ * it's expected to claim the resources and map the port.
+ */
+static void mtk_uart_config_port(struct uart_port *port, int flags)
+{
+ struct mtk_uart* uart = (struct mtk_uart*)port;
+ if (flags & UART_CONFIG_TYPE) {
+ if (mtk_uart_request_port(port))
+ MSG(ERR, "mtk_uart_request_port fail\n");
+ port->type = PORT_MTK;
+ }
+}
+/*---------------------------------------------------------------------------*/
+/* verify if the new serial information contained within 'ser' is suitable */
+static int mtk_uart_verify_port(struct uart_port *port,
+ struct serial_struct *ser)
+{
+#if ( defined(ENABLE_DEBUG)||defined(SERIAL_STRUCT_EXT) ) /* [ALPS00142658] Fix unused variable waring */
+ struct mtk_uart* uart = (struct mtk_uart*)port;
+#endif
+ int ret = 0;
+ MSG(FUC, "%s: %8x, %d, %d\n", __func__, ser->flags, ser->custom_divisor, uart->custom_baud);
+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_MTK)
+ ret = -EINVAL;
+ if (ser->irq != port->irq)
+ ret = -EINVAL;
+ if (ser->baud_base < 110)
+ ret = -EINVAL;
+#if defined(SERIAL_STRUCT_EXT)
+ /*EXtension: the custom baudrate is stored in reserved field*/
+ uart->custom_baud = ser->reserved[0];
+#endif
+ return ret;
+}
+/*---------------------------------------------------------------------------*/
+/* perform any port specific IOCTLs */
+static int mtk_uart_ioctl(struct uart_port *port, unsigned int cmd,
+ unsigned long arg)
+{
+#if defined(ENABLE_DEBUG)
+ struct mtk_uart* uart = (struct mtk_uart*)port;
+ MSG(FUC, "IOCTL: %8X\n", cmd);
+#endif
+ return -ENOIOCTLCMD;
+}
+/*---------------------------------------------------------------------------*/
+#ifdef CONFIG_CONSOLE_POLL
+/*---------------------------------------------------------------------------*/
+static int mtk_uart_get_poll_char(struct uart_port *port)
+{ /* don't care vfifo setting */
+ struct mtk_uart *uart = (struct mtk_uart *)port;
+
+ /* [ALPS00033048] For Linux 2.6.35 kgdb chagne, using while loop may block kgdb,
+ * return NO_POLL_CHAR directly if no data to read */
+ #if 0
+ while (!(uart->read_status(uart) & UART_LSR_DR))
+ cpu_relax();
+ #else
+ if (!mtk_uart_data_ready(uart))
+ return NO_POLL_CHAR;
+ #endif
+ /* End of [ALPS00033048] */
+
+ return mtk_uart_read_byte(uart);
+}
+/*---------------------------------------------------------------------------*/
+static void mtk_uart_put_poll_char(struct uart_port *port, unsigned char c)
+{ /* don't care vfifo setting */
+ struct mtk_uart *uart = (struct mtk_uart *)port;
+ while (!mtk_uart_write_allow(uart))
+ barrier();
+ mtk_uart_write_byte(uart, c);
+}
+/*---------------------------------------------------------------------------*/
+#endif
+/*---------------------------------------------------------------------------*/
+static struct uart_ops mtk_uart_ops =
+{
+ .tx_empty = mtk_uart_tx_empty,
+ .set_mctrl = mtk_uart_set_mctrl,
+ .get_mctrl = mtk_uart_get_mctrl,
+ .stop_tx = mtk_uart_stop_tx,
+ .start_tx = mtk_uart_start_tx,
+ .stop_rx = mtk_uart_stop_rx,
+ .send_xchar = mtk_uart_send_xchar,
+ .enable_ms = mtk_uart_enable_ms,
+ .break_ctl = mtk_uart_break_ctl,
+ .startup = mtk_uart_startup,
+ .shutdown = mtk_uart_shutdown,
+ .flush_buffer = mtk_uart_flush_buffer,
+ .set_termios = mtk_uart_set_termios,
+ .pm = mtk_uart_power_mgnt,
+ .set_wake = mtk_uart_set_wake,
+ .type = mtk_uart_type,
+ .release_port = mtk_uart_release_port,
+ .request_port = mtk_uart_request_port,
+ .config_port = mtk_uart_config_port,
+ .verify_port = mtk_uart_verify_port,
+ .ioctl = mtk_uart_ioctl,
+#ifdef CONFIG_CONSOLE_POLL
+ .poll_get_char = mtk_uart_get_poll_char,
+ .poll_put_char = mtk_uart_put_poll_char,
+#endif
+};
+/*---------------------------------------------------------------------------*/
+static struct uart_driver mtk_uart_drv =
+{
+ .owner = THIS_MODULE,
+ .driver_name = DRV_NAME,
+ .dev_name = "ttyMT",
+ .major = UART_MAJOR,
+ .minor = UART_MINOR,
+ .nr = UART_NR,
+#if defined(CONFIG_MTK_SERIAL_CONSOLE) && !defined(CONFIG_MTK_SERIAL_MODEM_TEST)
+ .cons = &mtk_uart_console,
+#endif
+};
+/*---------------------------------------------------------------------------*/
+static int mtk_uart_probe(struct platform_device *pdev)
+{
+ struct mtk_uart *uart;
+ int err;
+
+#ifdef CONFIG_OF
+ if (pdev->dev.of_node) {
+ struct device_node *node = pdev->dev.of_node;
+ err = of_property_read_u32(node, "cell-index", &pdev->id);
+ if (err){
+ printk("[DTS] get uart platform_device id fail!!\n");
+ }
+ }
+#endif
+
+ uart = &mtk_uarts[pdev->id];
+
+
+ MSG_FUNC_ENTRY();
+
+ if(mtk_uart_plat_info_query("ADD_DMA_BIT_MASK_32"))
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
+ uart->port.dev = &pdev->dev;
+ err = uart_add_one_port(&mtk_uart_drv, &uart->port);
+ if (!err)
+ platform_set_drvdata(pdev, uart);
+
+#if defined(ENABLE_VFIFO)
+ if ((err = mtk_uart_vfifo_create(uart))) {
+ mtk_uart_vfifo_delete(uart);
+ DEV_ERR("create vff buffer fail:%d\n", err);
+ }
+#endif
+ return err;
+}
+/*---------------------------------------------------------------------------*/
+static int mtk_uart_remove(struct platform_device *pdev)
+{
+ struct mtk_uart *uart = platform_get_drvdata(pdev);
+ int err;
+
+ platform_set_drvdata(pdev, NULL);
+
+ if (!uart)
+ return -EINVAL;
+
+ err = uart_remove_one_port(&mtk_uart_drv, &uart->port);
+
+#if defined(ENABLE_VFIFO)
+ mtk_uart_vfifo_delete(uart);
+#endif
+ return err;
+}
+/*---------------------------------------------------------------------------*/
+#ifdef CONFIG_PM
+/*---------------------------------------------------------------------------*/
+static int mtk_uart_syscore_suspend(void)
+{
+ int ret = 0;
+ unsigned long flags;
+ if (bt_port)
+ {
+ struct mtk_uart *uart = bt_port;
+ spin_lock_irqsave(&mtk_uart_bt_lock, flags);
+ ret = uart_suspend_port(&mtk_uart_drv, &uart->port);
+ //To keeping uart idle state
+ //tx pin: idle->high power down->low
+ mtk_uart_switch_tx_to_gpio(uart);
+ spin_unlock_irqrestore(&mtk_uart_bt_lock, flags);
+ printk(KERN_NOTICE "[UART%d] Suspend(%d)!\n", uart->nport, ret);
+ }
+ return ret;
+}
+/*---------------------------------------------------------------------------*/
+static void mtk_uart_syscore_resume(void)
+{
+ int ret = 0;
+ unsigned long flags;
+ if (bt_port)
+ {
+ struct mtk_uart *uart = bt_port;
+ spin_lock_irqsave(&mtk_uart_bt_lock, flags);
+ mtk_uart_switch_to_tx(uart);
+ ret = uart_resume_port(&mtk_uart_drv, &uart->port);
+ spin_unlock_irqrestore(&mtk_uart_bt_lock, flags);
+ disable_irq(uart->port.irq);
+ printk(KERN_NOTICE "[UART%d] Resume(%d)!\n", uart->nport, ret);
+ }
+}
+/*---------------------------------------------------------------------------*/
+static int mtk_uart_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ int ret = 0;
+ struct mtk_uart *uart = platform_get_drvdata(pdev);
+ if (console_suspend_enabled == 0 && uart == console_port && uart->poweron_count > 0) //For console_suspend_enabled=0
+ mtk_uart_save(uart);
+ if(uart && (uart->nport < UART_NR) && (uart != bt_port)){
+ ret = uart_suspend_port(&mtk_uart_drv, &uart->port);
+ printk(KERN_NOTICE "[UART%d] Suspend(%d)!\n", uart->nport, ret);
+ mtk_uart_switch_rx_to_gpio(uart);
+ }
+ return ret;
+}
+/*---------------------------------------------------------------------------*/
+static int mtk_uart_resume(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct mtk_uart *uart = platform_get_drvdata(pdev);
+ if (uart && (uart->nport < UART_NR) && (uart != bt_port)) {
+ mtk_uart_switch_to_rx(uart);
+ ret = uart_resume_port(&mtk_uart_drv, &uart->port);
+ printk(KERN_NOTICE "[UART%d] Resume(%d)!\n", uart->nport, ret);
+ }
+ return ret;
+}
+/*---------------------------------------------------------------------------*/
+static int mtk_uart_pm_suspend(struct device *device)
+{
+ struct platform_device *pdev;
+ pr_debug("calling %s()\n", __func__);
+
+ pdev = to_platform_device(device);
+ BUG_ON(pdev == NULL);
+
+ return mtk_uart_suspend(pdev, PMSG_SUSPEND);
+}
+
+static int mtk_uart_pm_resume(struct device *device)
+{
+ struct platform_device *pdev;
+ pr_debug("calling %s()\n", __func__);
+
+ pdev = to_platform_device(device);
+ BUG_ON(pdev == NULL);
+
+ return mtk_uart_resume(pdev);
+}
+
+
+static int mtk_uart_pm_freeze(struct device *device)
+{
+ struct platform_device *pdev;
+ struct mtk_uart *uart = NULL;
+ int ret = 0;
+ int port_idx = 0;
+
+ pdev = to_platform_device(device);
+ BUG_ON(pdev == NULL);
+ uart = platform_get_drvdata(pdev);
+
+ port_idx = uart->nport;
+ if (uart_freeze_enable[port_idx])
+ {
+ ret = uart_suspend_port(&mtk_uart_drv, &uart->port);
+ pr_warn("[%s] here.\n", __func__);
+ //To keeping uart idle state
+ //tx pin: idle->high power down->low
+ mtk_uart_switch_tx_to_gpio(uart);
+ pr_warn("[%s] done.\n", __func__);
+ }
+
+ return 0;//mtk_uart_suspend(pdev, PMSG_SUSPEND);
+}
+
+static int mtk_uart_pm_restore(struct device *device)
+{
+ struct platform_device *pdev;
+ struct mtk_uart *uart;
+ int ret = 0;
+ int port_idx = 0;
+
+ pdev = to_platform_device(device);
+ BUG_ON(pdev == NULL);
+ uart = platform_get_drvdata(pdev);
+
+ port_idx = uart->nport;
+ if (uart_freeze_enable[port_idx])
+ {
+ mtk_uart_switch_to_tx(uart);
+ ret = uart_resume_port(&mtk_uart_drv, &uart->port);
+ pr_warn("[%s] uart (%p) base: 0x%lx, nport %d, dma mode: %d\n", __func__,
+ uart, uart->base, uart->nport, uart->dma_mode);
+ }
+
+ return mtk_uart_resume(pdev);
+}
+
+static int mtk_uart_pm_restore_noirq(struct device *device)
+{
+/* FIXME. not get GIC_DIST_BASE from DTS */
+#ifndef CONFIG_OF
+ unsigned int gic_pending;
+#endif
+ struct mtk_uart *uart;
+ //pr_warn("calling %s()\n", __func__);
+
+ uart = dev_get_drvdata(device);
+ if (!uart || !uart->setting) {
+ pr_warn("[%s] uart (%p) or uart->setting (%p) is null!!\n", __func__, uart, uart->setting);
+ return 0;
+ }
+ mtk_uart_fifo_set_trig(uart, uart->tx_trig, uart->rx_trig);
+#ifdef CONFIG_OF
+ irq_set_irq_type(uart->setting->irq_num, uart->setting->irq_flags);
+#else
+ if (uart->setting->irq_sen == MT_EDGE_SENSITIVE) {
+ irq_set_irq_type(uart->setting->irq_num, IRQF_TRIGGER_FALLING);
+ } else {
+ irq_set_irq_type(uart->setting->irq_num, IRQF_LEVEL_TRIGGER_POLARITY);
+ }
+#endif
+
+#define GIC_DIST_PENDING_SET 0x200
+ if (uart->tx_vfifo && uart->tx_mode == UART_TX_VFIFO_DMA) {
+ irq_set_irq_type(uart->tx_vfifo->irq_id, IRQF_LEVEL_TRIGGER_POLARITY);
+/* FIXME. not get GIC_DIST_BASE from DTS */
+#ifndef CONFIG_OF
+ gic_pending = DRV_Reg32(GIC_DIST_BASE + GIC_DIST_PENDING_SET + uart->tx_vfifo->irq_id/32*4);
+ pr_warn("[%s] tx_vfifo(%p) gic_pending_mask(0x%08x)\n",
+ __func__, uart->tx_vfifo->base, gic_pending);
+#endif
+ }
+ if (uart->rx_vfifo && uart->rx_mode == UART_RX_VFIFO_DMA) {
+ irq_set_irq_type(uart->rx_vfifo->irq_id, IRQF_LEVEL_TRIGGER_POLARITY);
+/* FIXME. not get GIC_DIST_BASE from DTS */
+#ifndef CONFIG_OF
+ gic_pending = DRV_Reg32(GIC_DIST_BASE + GIC_DIST_PENDING_SET + uart->rx_vfifo->irq_id/32*4);
+ pr_warn("[%s] rx_vfifo(%p) gic_pending_mask(0x%08x)\n",
+ __func__, uart->rx_vfifo->base, gic_pending);
+#endif
+ }
+ return 0;
+}
+
+/*---------------------------------------------------------------------------*/
+#else /*CONFIG_PM*/
+/*---------------------------------------------------------------------------*/
+#define mtk_uart_pm_suspend NULL
+#define mtk_uart_pm_resume NULL
+#define mtk_uart_pm_freeze NULL
+#define mtk_uart_pm_restore NULL
+#define mtk_uart_pm_restore_noirq NULL
+/*---------------------------------------------------------------------------*/
+#endif /*CONFIG_PM*/
+/*---------------------------------------------------------------------------*/
+struct dev_pm_ops mtk_uart_pm_ops = {
+ .suspend = mtk_uart_pm_suspend,
+ .resume = mtk_uart_pm_resume,
+ .freeze = mtk_uart_pm_freeze,
+ .thaw = mtk_uart_pm_restore,
+ .poweroff = mtk_uart_pm_suspend,
+ .restore = mtk_uart_pm_restore,
+ .restore_noirq = mtk_uart_pm_restore_noirq,
+};
+
+
+/*---------------------------------------------------------------------------*/
+static int mtk_uart_init_ports(void)
+{
+ int i;
+#ifdef CONFIG_OF
+ int idx;
+ void __iomem *apdma_uart0_base=0;
+ struct mtk_uart_vfifo *vfifo;
+#endif
+ struct mtk_uart *uart;
+ unsigned long base;
+
+ spin_lock_init(&mtk_console_lock);
+
+#ifdef CONFIG_OF
+ apdma_uart0_base = get_apdma_uart0_base();
+#endif
+ for (i = 0; i < UART_NR; i++) {
+#ifdef CONFIG_OF
+ set_uart_default_settings(i);
+#endif
+ uart = &mtk_uarts[i];
+ uart->setting = get_uart_default_settings(i);
+#ifdef CONFIG_OF
+#if defined(ENABLE_VFIFO)
+ if(uart->setting->vff){
+ if(i*2 < sizeof(mtk_uart_vfifo_port)/sizeof(mtk_uart_vfifo_port[0])){
+ for (idx = i*2; idx < i*2 + 2; idx++) {
+ vfifo = &mtk_uart_vfifo_port[idx];
+ vfifo->base = (apdma_uart0_base+0x0080*idx);
+ vfifo->irq_id = get_uart_vfifo_irq_id(idx);
+ }
+ }
+ }
+#endif
+#endif
+ base = uart->setting->uart_base;
+ uart->port.iotype = UPIO_MEM;
+#ifdef CONFIG_OF
+ uart->port.mapbase = uart->setting->uart_phys_base; /* for ioremap */
+#else
+ uart->port.mapbase = IO_VIRT_TO_PHYS(base); /* for ioremap */
+#endif
+ uart->port.membase = (unsigned char __iomem *)base;
+ uart->port.irq = uart->setting->irq_num;
+ uart->port.fifosize = UART_FIFO_SIZE;
+ uart->port.ops = &mtk_uart_ops;
+ uart->port.flags = UPF_BOOT_AUTOCONF;
+ uart->port.line = i;
+ uart->port.uartclk = UART_SYSCLK;
+ //pll_for_uart = mt6575_get_bus_freq();
+ //uart->port.uartclk = mt6575_get_bus_freq()*1000/4;
+ spin_lock_init(&uart->port.lock);
+ uart->base = base;
+ uart->auto_baud = CFG_UART_AUTOBAUD;
+ uart->nport = i;
+ uart->sysclk = UART_SYSCLK; /* FIXME */
+ //uart->sysclk = mt6575_get_bus_freq()*1000/4;
+ uart->dma_mode = uart->setting->dma_mode;
+ uart->tx_mode = uart->setting->tx_mode;
+ uart->rx_mode = uart->setting->rx_mode;
+ uart->tx_trig = uart->setting->tx_trig;
+ uart->rx_trig = uart->setting->rx_trig;
+ uart->write_allow = mtk_uart_write_allow;
+ uart->read_allow = mtk_uart_read_allow;
+ uart->write_byte = mtk_uart_write_byte;
+ uart->read_byte = mtk_uart_read_byte;
+ uart->read_status = mtk_uart_read_status;
+ uart->poweron_count = 0;
+ uart->timeout_count = 0;
+ uart->baudrate = 0;
+ uart->custom_baud = 0;
+ uart->registers.dll = 1;
+ uart->registers.dlh = 0;
+ uart->registers.ier = 0;
+ uart->registers.lcr = 0;
+ uart->registers.mcr = 0;
+ uart->registers.fcr = 0;
+ uart->registers.lsr = 0x60;
+ uart->registers.efr = 0;
+ uart->registers.highspeed = 0;
+ uart->registers.sample_count = 0;
+ uart->registers.sample_point = 0xff;
+ uart->registers.fracdiv_l = 0;
+ uart->registers.fracdiv_m = 0;
+ uart->registers.escape_en = 0;
+ uart->registers.guard = 0;
+ uart->registers.rx_sel = 0;
+ uart->evt_mask = (unsigned int)get_uart_evt_mask(i);
+
+#if defined(CONFIG_MTK_SERIAL_MODEM_TEST)
+ if (get_modem_uart(i)) {
+ //u32 dat = UART_READ32(HW_MISC); // mtk does NOT has this register
+ mtk_uart_power_up(uart); //power up
+ //reg_sync_writel(dat | mask[i], HW_MISC);
+ continue;
+ }
+#else
+ //mtk_uart_power_up(uart);
+ mtk_uart_disable_intrs(uart, UART_IER_ALL_INTS);
+
+#ifdef CONFIG_OF
+ irq_set_irq_type(uart->setting->irq_num, uart->setting->irq_flags);
+#else
+ if (uart->setting->irq_sen == MT_EDGE_SENSITIVE) {
+ irq_set_irq_type(uart->setting->irq_num, IRQF_EDGE_TRIGGER_POLARITY);
+ } else {
+ irq_set_irq_type(uart->setting->irq_num, IRQF_LEVEL_TRIGGER_POLARITY);
+ }
+#endif
+
+ mtk_uart_fifo_init(uart);
+ mtk_uart_set_mode(uart, uart->dma_mode);
+ //mtk_uart_power_down(uart);
+#endif
+ }
+#if defined(CONFIG_MTK_SERIAL_MODEM_TEST)
+ /*NOTICE: for enabling modem test, UART4 needs to be disabled. Howerver, if CONFIG_MTK_SERIAL_CONSOLE
+ is defined, resume will fail. Since the root cause is not clear, only disable the console-related
+ function.*/
+ //printk("HW_MISC: 0x%08X\n", UART_READ32(HW_MISC)); // mtk does NOT has this register
+#endif
+ return 0;
+}
+/*---------------------------------------------------------------------------*/
+#ifdef CONFIG_OF
+static const struct of_device_id apuart_of_ids[] = {
+ { .compatible = "mediatek,AP_UART0", },
+ { .compatible = "mediatek,AP_UART1", },
+#ifndef CONFIG_MTK_FPGA
+ { .compatible = "mediatek,AP_UART2", },
+ { .compatible = "mediatek,AP_UART3", },
+#if (UART_NR > 4)
+ { .compatible = "mediatek,AP_UART4", },
+#endif
+#endif
+ {}
+};
+#endif
+
+static struct platform_driver mtk_uart_dev_drv =
+{
+ .probe = mtk_uart_probe,
+ .remove = mtk_uart_remove,
+#ifdef CONFIG_PM
+ .suspend = mtk_uart_suspend,
+ .resume = mtk_uart_resume,
+#endif
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+#ifdef CONFIG_OF
+ .of_match_table = apuart_of_ids,
+#endif
+#ifdef CONFIG_PM
+ .pm = &mtk_uart_pm_ops,
+#endif
+
+ }
+};
+
+#ifdef CONFIG_PM
+static struct syscore_ops mtk_uart_syscore_ops = {
+ .suspend = mtk_uart_syscore_suspend,
+ .resume = mtk_uart_syscore_resume,
+};
+
+static int __init mtk_uart_init_ops(void)
+{
+ register_syscore_ops(&mtk_uart_syscore_ops);
+ return 0;
+}
+#endif
+/*---------------------------------------------------------------------------*/
+static int __init mtk_uart_init(void)
+{
+ int ret = 0;
+
+ tx_history.buffer = kzalloc(UART_HISTORY_DATA_SIZE, GFP_KERNEL);
+ rx_history.buffer = kzalloc(UART_HISTORY_DATA_SIZE, GFP_KERNEL);
+ tx_history.index = -1;
+ rx_history.index = -1;
+
+ if(!tx_history.buffer || !rx_history.buffer)
+ return -ENOMEM;
+
+#ifndef CONFIG_MTK_SERIAL_CONSOLE
+ mtk_uart_init_ports();
+#endif
+
+#if defined(ENABLE_SYSFS)
+ mtk_uart_sysfs();
+#endif
+
+ ret = uart_register_driver(&mtk_uart_drv);
+
+ if (ret) return ret;
+
+ ret = platform_driver_register(&mtk_uart_dev_drv);
+
+ if (ret) {
+ uart_unregister_driver(&mtk_uart_drv);
+ return ret;
+ }
+#ifdef CONFIG_PM
+ mtk_uart_init_ops();
+#endif
+
+ mtk_uart_init_debug_spinlock();
+ spin_lock_init(&mtk_uart_bt_lock);
+ return ret;
+}
+/*---------------------------------------------------------------------------*/
+static void __exit mtk_uart_exit(void)
+{
+ platform_driver_unregister(&mtk_uart_dev_drv);
+ uart_unregister_driver(&mtk_uart_drv);
+}
+/*---------------------------------------------------------------------------*/
+#ifdef ENABLE_UART_SLEEP
+int request_uart_to_sleep(void)
+{
+ u32 val1;
+ int i = 0;
+ int uart_idx = 0;
+ struct mtk_uart *uart;
+ unsigned long base;
+
+ for (uart_idx = 0; uart_idx < UART_NR; uart_idx++)
+ {
+ #if defined(CONFIG_MTK_HDMI_SUPPORT)
+ #ifdef MHL_UART_SHARE_PIN
+ {
+ if((is_hdmi_active()== 0) && (uart_idx == 1)) // for K2 uart2 and mhl share pin, if mhl is in low power mode, uart rx is not working, so bypass it.
+ continue;
+ }
+ #endif
+ #endif
+
+ uart = &mtk_uarts[uart_idx];
+ base = uart->base;
+ if (uart->poweron_count > 0)
+ {
+ /* request UART to sleep */
+ val1 = UART_READ32(UART_SLEEP_REQ);
+ reg_sync_writel(val1 | UART_CLK_OFF_REQ, UART_SLEEP_REQ);
+
+ /* wait for UART to ACK */
+ while (!(UART_READ32(UART_SLEEP_ACK) & UART_CLK_OFF_ACK)) {
+ if (i++ >= WAIT_UART_ACK_TIMES) {
+ reg_sync_writel(val1, UART_SLEEP_REQ);
+ printk(KERN_ERR "CANNOT GET UART[%d] SLEEP ACK\n", uart_idx);
+ //dump_uart_reg();
+ return -EBUSY;
+ }
+ udelay(10);
+ }
+ }
+ else
+ {
+ //printk("[UART%d] clock is off\n", uart->nport);
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(request_uart_to_sleep);
+
+
+int request_uart_to_wakeup(void)
+{
+ //printk(KERN_ERR "Request UART sleep\n");
+ u32 val1;
+ int i = 0;
+ int uart_idx = 0;
+ struct mtk_uart *uart;
+ unsigned long base;
+
+ for (uart_idx = 0; uart_idx < UART_NR; uart_idx++)
+ {
+ uart = &mtk_uarts[uart_idx];
+ base = uart->base;
+ if (uart->poweron_count > 0)
+ {
+ /* wakeup uart */
+ val1 = UART_READ32(UART_SLEEP_REQ);
+ reg_sync_writel(val1 & (~UART_CLK_OFF_REQ), UART_SLEEP_REQ);
+
+ /* wait for UART to ACK */
+ while ((UART_READ32(UART_SLEEP_ACK) & UART_CLK_OFF_ACK)) {
+ if (i++ >= WAIT_UART_ACK_TIMES) {
+ reg_sync_writel(val1, UART_SLEEP_REQ);
+ printk(KERN_ERR "CANNOT GET UART[%d] WAKE ACK\n", uart_idx);
+ //dump_uart_reg();
+ return -EBUSY;
+ }
+ udelay(10);
+ }
+ }
+ else
+ {
+ //printk("[UART%d] clock is off\n", uart->nport);
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(request_uart_to_wakeup);
+
+#endif
+/*---------------------------------------------------------------------------*/
+module_init(mtk_uart_init);
+module_exit(mtk_uart_exit);
+/*---------------------------------------------------------------------------*/
+MODULE_AUTHOR("MTK");
+MODULE_DESCRIPTION("MTK Serial Port Driver $Revision$");
+MODULE_LICENSE("GPL");