diff options
Diffstat (limited to 'ANDROID_3.4.5/drivers/tty/serial/serial_wmt.c')
-rwxr-xr-x | ANDROID_3.4.5/drivers/tty/serial/serial_wmt.c | 2720 |
1 files changed, 0 insertions, 2720 deletions
diff --git a/ANDROID_3.4.5/drivers/tty/serial/serial_wmt.c b/ANDROID_3.4.5/drivers/tty/serial/serial_wmt.c deleted file mode 100755 index 79246cdc..00000000 --- a/ANDROID_3.4.5/drivers/tty/serial/serial_wmt.c +++ /dev/null @@ -1,2720 +0,0 @@ -/*++ -linux/drivers/serial/serial_wmt.c - -Copyright (c) 2008 WonderMedia Technologies, Inc. - -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, see <http://www.gnu.org/licenses/>. - -WonderMedia Technologies, Inc. -10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C. ---*/ - -#include <linux/module.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/ioport.h> -#include <linux/init.h> -#include <linux/serial.h> -#include <linux/console.h> -#include <linux/sysrq.h> -#include <linux/device.h> -#include <linux/delay.h> -#include <linux/cpufreq.h> -#include <linux/platform_device.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <mach/hardware.h> -#include <mach/dma.h> -#include <linux/serial_core.h> -#include <linux/dma-mapping.h> -#include <linux/slab.h> - - -#define PORT_WMT 54 -#if defined(CONFIG_SERIAL_WMT_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - - -#ifdef CONFIG_SERIAL_WMT_DMA -/* * DMA processing */ -#define DMA_RX_REQUEST(s, cb) wmt_request_dma(&s->rx_dmach, s->id, s->dma_rx_dev, cb, s) -#define DMA_RX_FREE(s) {wmt_free_dma(s->rx_dmach); s->rx_dmach = NULL_DMA; } -#define DMA_RX_START(s, d, l) wmt_start_dma(s->rx_dmach, d, 0, l) -#define DMA_RX_POS(s) wmt_get_dma_pos(s->rx_dmach) -#define DMA_RX_STOP(s) wmt_stop_dma(s->rx_dmach) -#define DMA_RX_CLEAR(s) wmt_clear_dma(s->rx_dmach) -#define DMA_RX_RESET(s) wmt_reset_dma(s->rx_dmach) -#define IS_NULLDMA(ch) ((ch) == NULL_DMA) -#define CHK_DMACH(ch) ((ch) != NULL_DMA) -#define DMA_TX_REQUEST(s, cb) wmt_request_dma(&s->tx_dmach, s->id, s->dma_tx_dev, cb, s) -#define DMA_TX_FREE(s) {wmt_free_dma(s->tx_dmach); s->tx_dmach = NULL_DMA; } -#define DMA_TX_START(s, d, l) wmt_start_dma(s->tx_dmach, d, 0, l) -#define DMA_TX_POS(s) wmt_get_dma_pos(s->tx_dmach) -#define DMA_TX_STOP(s) wmt_stop_dma(s->tx_dmach) -#define DMA_TX_CLEAR(s) wmt_clear_dma(s->tx_dmach) -#define DMA_TX_RESET(s) wmt_reset_dma(s->tx_dmach) -#define NULL_DMA ((dmach_t)(-1)) -#endif - - - -#ifdef DEBUG_SERIAL_WMT -#define DEBUG_INTR(fmt...) printk(fmt) -#else -#define DEBUG_INTR(fmt...) do { } while (0) -#endif - - -#define UART_BR_115K2 115200 - -/* - * This is for saving useful I/O registers - */ - -/* - * RS232 on DB9 - * Pin No. Name Notes/Description - * 1 DCD Data Carrier Detect - * 2 RD Receive Data (a.k.a RxD, Rx) - * 3 TD Transmit Data (a.k.a TxD, Tx) - * 4 DTR Data Terminal Ready - * 5 SGND Ground - * 6 DSR Data Set Ready - * 7 RTS Request To Send - * 8 CTS Clear To Send - * 9 RI Ring Indicator - */ - -/* - * We've been assigned a range on the "Low-density serial ports" major - * - * dev Major Minor - * ttyVT0 204 90 - * ttyS0 4 64 - */ -#ifdef CONFIG_SERIAL_WMT_TTYVT - #define SERIAL_WMT_MAJOR 204 - #define MINOR_START 90 /* Start from ttyVT0 */ - #define CALLOUT_WMT_MAJOR 205 /* for callout device */ -#else - #define SERIAL_WMT_MAJOR 4 - #define MINOR_START 64 /* Start from ttyS0 */ - #define CALLOUT_WMT_MAJOR 5 /* for callout device */ -#endif - -#ifdef CONFIG_UART_2_3_ENABLE -#define NR_PORTS 4 -#else -#define NR_PORTS 2 -#endif -#define WMT_ISR_PASS_LIMIT 256 - -struct wmt_port { - struct uart_port port; - struct timer_list timer; - struct timer_list rx_timer; -#ifdef CONFIG_SERIAL_WMT_DMA - /* RX Buffer0 physical address */ - dma_addr_t uart_rx_dma_phy0_org; - /* RX Buffer1 physical address */ - dma_addr_t uart_rx_dma_phy1_org; - /* RX Buffer2 physical address */ - dma_addr_t uart_rx_dma_phy2_org; - /* RX Buffer0 virtual address */ - char *uart_rx_dma_buf0_org; - /* RX Buffer1 virtual address */ - char *uart_rx_dma_buf1_org; - /* RX Buffer2 virtual address */ - char *uart_rx_dma_buf2_org; - /* RX Buffer0 virtual address, this address is the data should be read */ - char *uart_dma_tmp_buf0; - /* RX Buffer1 virtual address, this address is the data should be read */ - char *uart_dma_tmp_buf1; - /* RX Buffer2 virtual address, this address is the data should be read */ - char *uart_dma_tmp_buf2; - /* RX Buffer0 physical address, this address is the data should be read */ - dma_addr_t uart_dma_tmp_phy0; - /* RX Buffer1 physical address, this address is the data should be read */ - dma_addr_t uart_dma_tmp_phy1; - /* RX Buffer2 physical address, this address is the data should be read */ - dma_addr_t uart_dma_tmp_phy2; - /* RX device identifier for DMA */ - enum dma_device_e dma_rx_dev; - /* TX device identifier for DMA */ - enum dma_device_e dma_tx_dev; - /* RX DMA device config */ - struct dma_device_cfg_s dma_rx_cfg; - /* TX DMA device config */ - struct dma_device_cfg_s dma_tx_cfg; - /* RX DMA channel number */ - dmach_t rx_dmach; - /* TX DMA channel number */ - dmach_t tx_dmach; - /* RX dma callback function record which buffer the DMA used */ - unsigned int buffer_used; - /* The buffer rx_char function should used (virtual address) */ - unsigned int buffer_selected; - /* The buffer rx_count function should used (physical address) */ - unsigned int buffer_rx_count_selected; - /* TX Buffer0 virtual address */ - char *uart_tx_dma_buf0_org; - /* TX Buffer0 physical address */ - dma_addr_t uart_tx_dma_phy0_org; - /* Record TX DMA running status : DMA_TX_END, DMA_TX_CHAR, DMA_TX_XMIT */ - unsigned int uart_tx_dma_flag; - /* TX dma transmit counter*/ - unsigned int uart_tx_count; - /* RX dma buffer last position*/ - unsigned int last_pos; - /* Record the number of RX dma timeout function with no data transmit*/ - unsigned int uart_rx_dma_flag; - unsigned int dma_tx_cnt; -#endif - unsigned int old_status; - /* identification string */ - char *id; - unsigned int old_urdiv; - unsigned int old_urlcr; - unsigned int old_urier; - unsigned int old_urfcr; - unsigned int old_urtod; -}; - -#ifdef CONFIG_SERIAL_WMT_DMA -#define DMA_TX_END 0 -#define DMA_TX_CHAR 1 -#define DMA_TX_XMIT 2 -#endif - - -/* - * WMT UART registers set structure. - */ -struct wmt_uart { - unsigned int volatile urtdr; /* 0x00*/ - unsigned int volatile urrdr; /* 0x04*/ - unsigned int volatile urdiv; /* 0x08*/ - unsigned int volatile urlcr; /* 0x0C*/ - unsigned int volatile uricr; /* 0x10*/ - unsigned int volatile urier; /* 0x14*/ - unsigned int volatile urisr; /* 0x18*/ - unsigned int volatile urusr; /* 0x1C*/ - unsigned int volatile urfcr; /* 0x20*/ - unsigned int volatile urfidx; /* 0x24*/ - unsigned int volatile urbkr; /* 0x28*/ - unsigned int volatile urtod; /* 0x2C*/ - unsigned int volatile resv30_FFF[0x3F4]; /* 0x0030 - 0x0FFF Reserved*/ - unsigned char volatile urtxf[32]; /* 0x1000 - 0x101F*/ - unsigned char volatile urrxf[32]; /* 0x1020 - 0x103F*/ -}; - -struct baud_info_s { - unsigned int baud; /* baud rate */ - unsigned int brd; /* baud rate divisor */ - unsigned int bcv; /* break counter value at this baud rate - * simply be calculated by baud * 0.004096 - */ -}; -#ifdef UART_DEBUG -unsigned int *DMA_pbuf =NULL; -unsigned int *COUNT_pbuf =NULL; -unsigned int *CPU_pbuf =NULL; -unsigned int dma_write_index = 0x00; -#endif -int mtk6622_tty = -1; -extern int wmt_getsyspara(char *varname, char *varval, int *varlen); - -static struct baud_info_s baud_table[] = { - { 3600, 0x100FF, 15 }, - { 7600, 0x1007F, 30 }, - { 9600, 0x2003F, 39 }, - { 14400, 0x1003F, 59 }, - { 19200, 0x2001F, 79 }, - { 28800, 0x1001F, 118 }, - { 38400, 0x2000F, 157 }, - { 57600, 0x1000F, 236 }, - { 115200, 0x10007, 472 }, - { 230400, 0x10003, 944 }, - { 460800, 0x10001, 1920 }, - { 921600, 0x10000, 3775 }, -}; - -#define BAUD_TABLE_SIZE ARRAY_SIZE(baud_table) - -#ifdef CONFIG_SERIAL_WMT_DMA -#define UART_BUFFER_SIZE (1024*16) -#endif -/* - * Macros to put URISR and URUSR into a 32-bit status variable - * URISR in bit[ 0:15] - * URUSR in bit[16:31] - */ -#define URISR_TO_SM(x) ((x) & URISR_MASK) -#define URUSR_TO_SM(x) (((x) & URUSR_MASK) << 16) -#define SM_TO_URISR(x) ((x) & 0xffff) -#define SM_TO_URUSR(x) ((x) >> 16) - -/* - * Following is a trick if we're interesting to listen break signal, - * but due to WMT UART doesn't suppout this interrupt status. - * So I make a fake interrupt status and use URISR_FER event to implement - * break signal detect. - */ -#ifdef CONFIG_SERIAL_WMT_BKSIG -#define SW_BKSIG (BIT31 | URISR_FER) -#endif -/* - * Macros to manipulate WMT UART module. - * - * s = sport, o = offset, v = value - * - * registers offset table as follows: - * - * URTDR 0x0000 - * URRDR 0x0004 - * URBRD 0x0008 - * URLCR 0x000C - * URICR 0x0010 - * URIER 0x0014 - * URISR 0x0018 - * URUSR 0x001C - * URFCR 0x0020 - * URFIDX 0x0024 - * URBKR 0x0028 - * - * Offset 0x002C-0x002F reserved - * - * URTXF 0x0030 - * URRXF 0x0040 - */ -#define PORT_TO_BASE(s) ((s)->port.membase) -#define WMT_UART_GET(s, o) __raw_readl((s)->port.membase + o) -#define WMT_UART_PUT(s, o, v) __raw_writel(v, (s)->port.membase + o) -#define WMT_UART_TXFIFO(s) (volatile unsigned char *)((s)->port.membase + URTXF) -#define WMT_UART_RXFIFO(s) (volatile unsigned short *)((s)->port.membase + URRXF) - -/* - * This is the size of our serial port register set. - */ -#define UART_PORT_SIZE 0x1040 - -/* - * This determines how often we check the modem status signals - * for any change. They generally aren't connected to an IRQ - * so we have to poll them. We also check immediately before - * filling the TX fifo incase CTS has been dropped. - */ -#define MCTRL_TIMEOUT (250*HZ/1000) - -/*{2007/11/10 JHT Support the VT8500 Serial Port Driver Because the*/ -/* definition of URSIRT Bit[0] & Bit[3] are different.*/ -/* Before VT8500 these bit are defined as RO, in VT8500*/ -/* they are changed into the W1C. Therefore the xmit function*/ -/* for the FIFO mode should be modified as well.*/ -static void wmt_tx_chars(struct wmt_port *sport); -static void wmt_rx_chars(struct wmt_port *sport, unsigned int status); -static struct wmt_port wmt_ports[NR_PORTS]; - -/*}2007/11/10-JHT*/ - -enum { - SHARE_PIN_UART = 0, - SHARE_PIN_SPI, -}; -static int wmt_uart_spi_sel = SHARE_PIN_UART; /* 0:uart, 1:spi */ - -void uart_dump_reg(struct wmt_port *sport) -{ - struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport); - - unsigned int urtdr = uart->urtdr; /* 0x00*/ - unsigned int urrdr = uart->urrdr; /* 0x04*/ - unsigned int urdiv = uart->urdiv; /* 0x08*/ - unsigned int urlcr = uart->urlcr; /* 0x0C*/ - unsigned int uricr = uart->uricr; /* 0x10*/ - unsigned int urier = uart->urier; /* 0x14*/ - unsigned int urisr = uart->urisr; /* 0x18*/ - unsigned int urusr = uart->urusr; /* 0x1C*/ - unsigned int urfcr = uart->urfcr; /* 0x20*/ - unsigned int urfidx = uart->urfidx; /* 0x24*/ - unsigned int urbkr = uart->urbkr; /* 0x28*/ - unsigned int urtod = uart->urtod; /* 0x2C*/ -#if 1 - - printk("urtdr=0x%.8x urrdr=0x%.8x urdiv=0x%.8x urlcr=0x%.8x\n" \ - "uricr=0x%.8x urier=0x%.8x urisr=0x%.8x urusr=0x%.8x\n" \ - "urfcr=0x%.8x uridx=0x%.8x urbkr=0x%.8x urtod=0x%.8x\n", - urtdr, urrdr, urdiv, urlcr, - uricr, urier, urisr, urusr, - urfcr, urfidx, urbkr, urtod); -#endif -} - -static void wmt_mctrl_check(struct wmt_port *sport) -{ - unsigned int status, changed; - - status = sport->port.ops->get_mctrl(&sport->port); - changed = status ^ sport->old_status; - - if (changed == 0) - return; - - sport->old_status = status; - - if (changed & TIOCM_RI) - sport->port.icount.rng++; - if (changed & TIOCM_DSR) - sport->port.icount.dsr++; - if (changed & TIOCM_CAR) - uart_handle_dcd_change(&sport->port, status & TIOCM_CAR); - if (changed & TIOCM_CTS) - uart_handle_cts_change(&sport->port, status & TIOCM_CTS); - - wake_up_interruptible(&sport->port.state->port.delta_msr_wait); -} - -/* - * This is our per-port timeout handler, for checking the - * modem status signals. - */ -static void wmt_timeout(unsigned long data) -{ - struct wmt_port *sport = (struct wmt_port *)data; - unsigned long flags; - - - - if (sport->port.state) { - spin_lock_irqsave(&sport->port.lock, flags); - wmt_mctrl_check(sport); - spin_unlock_irqrestore(&sport->port.lock, flags); - mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT); - } -} - -unsigned int rx_timeout = 1; - -static void wmt_rx_timeout(unsigned long data) -{ - struct wmt_port *sport = (struct wmt_port *)data; - struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport); - unsigned long flags; - unsigned int status; - unsigned int pos = 0; - - - spin_lock_irqsave(&sport->port.lock, flags); - pos = DMA_RX_POS(sport); - status = URISR_TO_SM(uart->urisr) | URUSR_TO_SM(uart->urusr); - uart->urisr |= SM_TO_URISR(status); - spin_unlock_irqrestore(&sport->port.lock, flags); - - /* DMA didn't transmit any data */ - if (sport->last_pos == pos) { - sport->uart_rx_dma_flag++; - - /* RX DMA didn't trasmit any data in two times, */ - /* enable interrupt and do the last time mod timer */ - if (sport->uart_rx_dma_flag == 2) { - sport->uart_rx_dma_flag++; - uart->urier = URIER_ERXFAF | - URIER_ERXFF | - URIER_ERXTOUT | - URIER_EPER | - URIER_EFER | - URIER_ERXDOVR; - mod_timer(&sport->rx_timer, jiffies + rx_timeout); - return; - } else if (sport->uart_rx_dma_flag == 3) { - sport->uart_rx_dma_flag = 0; - return; - } - mod_timer(&sport->rx_timer, jiffies + rx_timeout); - return; - } - - sport->uart_rx_dma_flag = 0; - - wmt_rx_chars(sport, URISR_RXFAF | URISR_RXFF | status); - - mod_timer(&sport->rx_timer, jiffies + rx_timeout); - -} - - -/* - * Interrupts should be disabled on entry. - */ -static void wmt_stop_tx(struct uart_port *port) -{ - struct wmt_port *sport = (struct wmt_port *)port; - struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport); - - #ifndef CONFIG_SERIAL_WMT_DMA - uart->urier &= ~(URIER_ETXFAE | URIER_ETXFE); - sport->port.read_status_mask &= ~URISR_TO_SM(URISR_TXFAE | URISR_TXFE); - #else - if ((unsigned int)(sport->port.membase) == UART0_BASE_ADDR) { - uart->urier &= ~(URIER_ETXFAE | URIER_ETXFE); - sport->port.read_status_mask &= ~URISR_TO_SM(URISR_TXFAE | URISR_TXFE); - } - #endif -} -/* - * Interrupts may not be disabled on entry. - */ -static void wmt_start_tx(struct uart_port *port) -{ - struct wmt_port *sport = (struct wmt_port *)port; - struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport); - - /*{2007/11/10 JHT Support the VT8500 Serial Port Driver Because the - * definition of URSIRT Bit[0] & Bit[3] are different. - * Before VT8500 these bit are defined as RO, in VT8500 - * they are changed into the W1C. Therefore the xmit function - * for the FIFO mode should be modified as well. - */ -#ifdef CONFIG_SERIAL_WMT_DMA - if ((unsigned int)(sport->port.membase) != UART0_BASE_ADDR) { - uart->urlcr |= URLCR_DMAEN; - uart->urier &= ~(URIER_ETXFAE | URIER_ETXFE); - } else - uart->urier &= ~(URIER_ETXFAE | URIER_ETXFE); -#else - uart->urier &= ~(URIER_ETXFAE | URIER_ETXFE); - #endif - wmt_tx_chars(sport); - /*}2007/11/10-JHT*/ -#ifndef CONFIG_SERIAL_WMT_DMA - sport->port.read_status_mask |= URISR_TO_SM(URISR_TXFAE | URISR_TXFE); - uart->urier |= URIER_ETXFAE | URIER_ETXFE; -#else - if ((unsigned int)(sport->port.membase) == UART0_BASE_ADDR) { - sport->port.read_status_mask |= URISR_TO_SM(URISR_TXFAE | URISR_TXFE); - uart->urier |= URIER_ETXFAE | URIER_ETXFE; - } - #endif -} - -/* - * Interrupts enabled - */ -static void wmt_stop_rx(struct uart_port *port) -{ -/* - struct wmt_port *sport = (struct wmt_port *)port; - struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport); - - - uart->urier &= ~URIER_ERXFAF; -*/ -} - -/* - * No modem control lines - */ -static void wmt_enable_ms(struct uart_port *port) -{ - struct wmt_port *sport = (struct wmt_port *)port; - - mod_timer(&sport->timer, jiffies); -} - -#ifdef CONFIG_SERIAL_WMT_DMA -static unsigned int wmt_rx_count(struct wmt_port *sport) -{ - unsigned int rx_count = 0; - unsigned int pos; - - pos = DMA_RX_POS(sport); - - if (pos == sport->last_pos) /*have no data to drain */ - return 0; - - if (sport->buffer_rx_count_selected == 0) { - sport->buffer_selected = 0; /*shoud read buffer 0*/ - - /*pos in the range of the buffer0*/ - if ((pos >= sport->uart_dma_tmp_phy0) && - (pos <= (sport->uart_rx_dma_phy0_org + UART_BUFFER_SIZE))) { - rx_count = (pos - (unsigned int)sport->uart_dma_tmp_phy0); - } else if (pos == 0) { - if (sport->uart_dma_tmp_phy0 == sport->uart_rx_dma_phy0_org) - rx_count = 0; - else { - rx_count = (sport->uart_rx_dma_phy0_org + UART_BUFFER_SIZE) - - (unsigned int)sport->uart_dma_tmp_phy0; - } - } else if (((pos >= sport->uart_rx_dma_phy1_org) && - (pos <= (sport->uart_rx_dma_phy1_org + UART_BUFFER_SIZE))) - || - ((pos >= sport->uart_rx_dma_phy2_org) && - (pos <= (sport->uart_rx_dma_phy2_org + UART_BUFFER_SIZE)))) { - /* Buffer is full, dma pos in buffer 1 or 2, read all left data*/ - rx_count = (sport->uart_rx_dma_phy0_org + UART_BUFFER_SIZE) - - (unsigned int)sport->uart_dma_tmp_phy0; - } - sport->uart_dma_tmp_phy0 += rx_count; /*update tmp physical address*/ - sport->last_pos = sport->uart_dma_tmp_phy0; - - /* Buffer0 has reach to end*/ - if (sport->uart_dma_tmp_phy0 == (sport->uart_rx_dma_phy0_org + UART_BUFFER_SIZE)) { - sport->buffer_rx_count_selected = 1; - sport->uart_dma_tmp_phy0 = sport->uart_rx_dma_phy0_org; - } - } else if (sport->buffer_rx_count_selected == 1) { - sport->buffer_selected = 1; /*shoud read buffer 1*/ - - /*pos in the range of the buffer1*/ - if ((pos >= sport->uart_dma_tmp_phy1) && - (pos <= (sport->uart_rx_dma_phy1_org + UART_BUFFER_SIZE))) { - rx_count = (pos - (unsigned int)sport->uart_dma_tmp_phy1); - } else if (pos == 0) { - if (sport->uart_dma_tmp_phy1 == sport->uart_rx_dma_phy1_org) - rx_count = 0; - else { - rx_count = (sport->uart_rx_dma_phy1_org + UART_BUFFER_SIZE) - - (unsigned int)sport->uart_dma_tmp_phy1; - } - } else if (((pos >= sport->uart_rx_dma_phy0_org) && - (pos <= (sport->uart_rx_dma_phy0_org + UART_BUFFER_SIZE))) - || - ((pos >= sport->uart_rx_dma_phy2_org) && - (pos <= (sport->uart_rx_dma_phy2_org + UART_BUFFER_SIZE)))) { - /* Buffer is full, dma pos in buffer 0 or 2, read all left data*/ - rx_count = (sport->uart_rx_dma_phy1_org + UART_BUFFER_SIZE) - - (unsigned int)sport->uart_dma_tmp_phy1; - } - sport->uart_dma_tmp_phy1 += rx_count; - sport->last_pos = sport->uart_dma_tmp_phy1; - /* Buffer1 has reach to end*/ - if (sport->uart_dma_tmp_phy1 == (sport->uart_rx_dma_phy1_org + UART_BUFFER_SIZE)) { - sport->buffer_rx_count_selected = 2; - sport->uart_dma_tmp_phy1 = sport->uart_rx_dma_phy1_org; - } - } else if (sport->buffer_rx_count_selected == 2) { - sport->buffer_selected = 2; /*shoud read buffer 2*/ - - /*pos in the range of the buffer1*/ - if ((pos >= sport->uart_dma_tmp_phy2) && - (pos <= (sport->uart_rx_dma_phy2_org + UART_BUFFER_SIZE))) { - rx_count = (pos - (unsigned int)sport->uart_dma_tmp_phy2); - } else if (pos == 0) { - if (sport->uart_dma_tmp_phy2 == sport->uart_rx_dma_phy2_org) - rx_count = 0; - else { - rx_count = (sport->uart_rx_dma_phy2_org + UART_BUFFER_SIZE) - - (unsigned int)sport->uart_dma_tmp_phy2; - } - } else if (((pos >= sport->uart_rx_dma_phy0_org) && - (pos <= (sport->uart_rx_dma_phy0_org + UART_BUFFER_SIZE))) - || - ((pos >= sport->uart_rx_dma_phy1_org) && - (pos <= (sport->uart_rx_dma_phy1_org + UART_BUFFER_SIZE)))) { - /* Buffer is full, dma pos in buffer 0 or 1, read all left data*/ - rx_count = (sport->uart_rx_dma_phy2_org + UART_BUFFER_SIZE) - - (unsigned int)sport->uart_dma_tmp_phy2; - } - sport->uart_dma_tmp_phy2 += rx_count; - sport->last_pos = sport->uart_dma_tmp_phy2; - - /* Buffer2 has reach to end*/ - if (sport->uart_dma_tmp_phy2 == (sport->uart_rx_dma_phy2_org + UART_BUFFER_SIZE)) { - sport->buffer_rx_count_selected = 0; - sport->uart_dma_tmp_phy2 = sport->uart_rx_dma_phy2_org; - } - } - return rx_count; -} -/* -* we can use mu command to check memory content -*/ -int volatile last_submit = 0x0; -void dump_rx_dma_buf(struct wmt_port *sport) -{ - unsigned int rx_count = 0; - unsigned int pos; - int i; - int size=0; - unsigned char *tmpbuf; - pos = DMA_RX_POS(sport); - printk("sport->last_pos:0x%x,pos:0x%x,sport->buffer_rx_count_selected:0x%x,last_submit:0x%x\n",sport->last_pos,pos,sport->buffer_rx_count_selected,last_submit); - if ((sport->uart_rx_dma_phy0_org) <= pos && pos <= (sport->uart_rx_dma_phy0_org + UART_BUFFER_SIZE)){ - i = pos - sport->uart_rx_dma_phy0_org; - tmpbuf = sport->uart_rx_dma_buf0_org + i; - size = (unsigned int)(sport->uart_rx_dma_buf0_org) + UART_BUFFER_SIZE - (unsigned int)tmpbuf; - if(size > 16) - size = 16; - }else if ((sport->uart_rx_dma_phy1_org) <= pos && pos <= (sport->uart_rx_dma_phy1_org + UART_BUFFER_SIZE)){ - i = pos - sport->uart_rx_dma_phy1_org; - tmpbuf = sport->uart_rx_dma_buf1_org + i; - size =(unsigned int)( sport->uart_rx_dma_buf1_org) + UART_BUFFER_SIZE - (unsigned int)tmpbuf; - if(size > 16) - size = 16; - }else if ((sport->uart_rx_dma_phy2_org) <= pos && pos <= (sport->uart_rx_dma_phy2_org + UART_BUFFER_SIZE)){ - i = pos - sport->uart_rx_dma_phy2_org; - tmpbuf = sport->uart_rx_dma_buf2_org + i; - size = (unsigned int)(sport->uart_rx_dma_buf2_org) + UART_BUFFER_SIZE - (unsigned int)tmpbuf; - if(size > 16) - size = 16; - } - - for(i=0;i<size;i++) - printk("0x%x ",*tmpbuf++); - - printk("\nsport->uart_rx_dma_phy0_org:0x%x\n",sport->uart_rx_dma_phy0_org); - printk("sport->uart_rx_dma_phy1_org:0x%x\n",sport->uart_rx_dma_phy1_org); - printk("sport->uart_rx_dma_phy2_org:0x%x\n",sport->uart_rx_dma_phy2_org); -} -#endif -/* - * Inside the UART interrupt service routine dut to following - * reason: - * - * URISR_RXFAF: RX FIFO almost full (FIFO mode) - * URISR_RXDF: RX data register full (Register mode) - * URISR_RXTOUT: RX timeout - */ - -#ifndef CONFIG_SERIAL_WMT_DMA -static void -wmt_rx_chars(struct wmt_port *sport, unsigned int status) -{ - struct tty_struct *tty = sport->port.state->port.tty; - struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport); - unsigned int flg, urfidx, ignored = 0; - char ch; - - urfidx = URFIDX_RXFIDX(uart->urfidx); - - /* - * Check if there is data ready to be read. - * - * Note: We only receive characters. - */ - while ((status & URUSR_TO_SM(URUSR_RXDRDY)) && (URFIDX_RXFIDX(uart->urfidx))) { - ch = (uart->urrxf[0] & 0xFF); - /*urfidx--;*/ - - sport->port.icount.rx++; - - flg = TTY_NORMAL; - - /* - * Check interrupt status information using status[URISR_bits]. - * - * Notice that the error handling code is out of - * the main execution path and the URISR has already - * been read by ISR. - */ - if (status & URISR_TO_SM(URISR_PER | URISR_FER | URISR_RXDOVR)) { - if (urfidx > 1) { - if (uart_handle_sysrq_char(&sport->port, ch)) - goto ignore_char; - /* - * Pop all TTY_NORMAL data. - */ - goto error_return; - } else { - /* - * Now we have poped up to the data with - * parity error or frame error. - */ - goto handle_error; - } - } - - if (uart_handle_sysrq_char(&sport->port, ch)) - goto ignore_char; - -error_return: - - uart_insert_char(&sport->port, (status & 0xFFFF), URISR_TO_SM(URISR_RXDOVR) , ch, flg); - -ignore_char: - status &= 0xffff; /* Keep URISR field*/ - status |= URUSR_TO_SM(uart->urusr); - } -out: - tty_flip_buffer_push(tty); - return; - -handle_error: - /* - * Update error counters. - */ - if (status & URISR_TO_SM(URISR_PER)) - sport->port.icount.parity++; - else - if (status & URISR_TO_SM(URISR_FER)) { - - #ifdef CONFIG_SERIAL_WMT_BKSIG - /* - * Experimental software patch for break signal detection. - * - * When I got there is a frame error in next frame data, - * I check the next data to judge if it is a break signal. - * - * FIXME: Open these if Bluetooth or IrDA need this patch. - * Dec.29.2004 by Harry. - */ - if ((ch & RX_PERMASK) == 0) { - sport->port.icount.brk++; - uart_handle_break(&sport->port); - } else - sport->port.icount.frame++; - - #else /* Don't support break sinal detection */ - - sport->port.icount.frame++; - - #endif - - } - - /* - * RX Over Run event - */ - if (status & URISR_TO_SM(URISR_RXDOVR)) - sport->port.icount.overrun++; - - if (status & sport->port.ignore_status_mask) { - if (++ignored > 100) - goto out; - goto ignore_char; - } - - /* - * Second, handle the events which we're interesting to listen. - */ - status &= sport->port.read_status_mask; - - if (status & URISR_TO_SM(URISR_PER)) - flg = TTY_PARITY; - else - if (status & URISR_TO_SM(URISR_FER)) { - - #ifdef CONFIG_SERIAL_WMT_BKSIG - /* Software patch for break signal detection. - * - * When I got there is a frame error in next frame data, - * I check the next data to judge if it is a break signal. - * - * FIXME: Open these if Bluetooth or IrDA need this patch. - * Dec.29.2004 by Harry. - */ - if (sport->port.read_status_mask & SW_BKSIG) { - if ((ch & RX_PERMASK) == 0) { - DEBUG_INTR("handling break...."); - flg = TTY_BREAK; - /*goto error_return;*/ - } else { - flg = TTY_FRAME; - /*goto error_return;*/ - } - } else { - flg = TTY_FRAME; - /*goto error_return;*/ - } - - #else /* Don't support break sinal detection */ - - flg = TTY_FRAME; - - #endif - } - - if (status & URISR_TO_SM(URISR_RXDOVR)) { - /* - * Overrun is special, since it's reported - * immediately, and doesn't affect the current - * character. - */ - - ch = 0; - flg = TTY_OVERRUN; - } - #ifdef SUPPORT_SYSRQ - sport->port.sysrq = 0; - #endif - goto error_return; -} -#else - - -static inline int put_strings_tty_io(struct tty_struct *tty, - const unsigned char *chars, char flag, size_t size) -{ - int i; - - i = tty_insert_flip_string_fixed_flag(tty, chars, flag, size); - tty_flip_buffer_push(tty); - return i; -} - -static void -wmt_rx_chars(struct wmt_port *sport, unsigned int status) -{ - struct tty_struct *tty = sport->port.state->port.tty; - struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport); - unsigned int receive_rx_count = 0; - unsigned long flags; - - unsigned int flg, urfidx, ignored = 0; - char ch; - char *pchar = NULL; - char rx_flag; - - urfidx = URFIDX_RXFIDX(uart->urfidx); - - /* - * Check if there is data ready to be read. - * - * Note: We only receive characters. - */ - - if ((unsigned int)(sport->port.membase) != UART0_BASE_ADDR) { - - spin_lock_irqsave(&sport->port.lock, flags); - receive_rx_count = wmt_rx_count(sport); - spin_unlock_irqrestore(&sport->port.lock, flags); - - rx_flag = TTY_NORMAL; - - if (status & URISR_TO_SM(URISR_PER)) - rx_flag = TTY_PARITY; - - if (status & URISR_TO_SM(URISR_FER)) - rx_flag = TTY_FRAME; - - if (receive_rx_count > 0) { - if (sport->buffer_selected == 0) { - pchar = sport->uart_dma_tmp_buf0; - sport->uart_dma_tmp_buf0 += receive_rx_count; - put_strings_tty_io(tty, pchar, rx_flag, receive_rx_count); - - if (sport->uart_dma_tmp_buf0 == - (sport->uart_rx_dma_buf0_org + UART_BUFFER_SIZE)) { - sport->uart_dma_tmp_buf0 = sport->uart_rx_dma_buf0_org; - } - - } else if (sport->buffer_selected == 1) { - pchar = sport->uart_dma_tmp_buf1; - sport->uart_dma_tmp_buf1 += receive_rx_count; - put_strings_tty_io(tty, pchar, rx_flag, receive_rx_count); - - if (sport->uart_dma_tmp_buf1 == - (sport->uart_rx_dma_buf1_org + UART_BUFFER_SIZE)) { - sport->uart_dma_tmp_buf1 = sport->uart_rx_dma_buf1_org; - } - } else if (sport->buffer_selected == 2) { - pchar = sport->uart_dma_tmp_buf2; - sport->uart_dma_tmp_buf2 += receive_rx_count ; - put_strings_tty_io(tty, pchar, rx_flag, receive_rx_count); - - if (sport->uart_dma_tmp_buf2 == - (sport->uart_rx_dma_buf2_org + UART_BUFFER_SIZE)) { - sport->uart_dma_tmp_buf2 = sport->uart_rx_dma_buf2_org; - } - } - sport->port.icount.rx += receive_rx_count; - - if (rx_flag == TTY_PARITY) - sport->port.icount.parity += receive_rx_count; - - if (rx_flag == TTY_FRAME) - sport->port.icount.frame += receive_rx_count; - - receive_rx_count = 0; - } - tty_flip_buffer_push(tty); - return; - - } else { - - while ((status & URUSR_TO_SM(URUSR_RXDRDY)) && (URFIDX_RXFIDX(uart->urfidx))) { - - ch = (unsigned int)(uart->urrxf[0] & 0xFF); - sport->port.icount.rx++; - - flg = TTY_NORMAL; - - /* - * Check interrupt status information using status[URISR_bits]. - * - * Notice that the error handling code is out of - * the main execution path and the URISR has already - * been read by ISR. - */ - if (status & URISR_TO_SM(URISR_PER | URISR_FER | URISR_RXDOVR)) { - if (urfidx > 1) { - if (uart_handle_sysrq_char(&sport->port, ch)) - goto ignore_char2; - /* - * Pop all TTY_NORMAL data. - */ - goto error_return2; - } else { - /* - * Now we have poped up to the data with - * parity error or frame error. - */ - goto handle_error2; - } - } - - if (uart_handle_sysrq_char(&sport->port, ch)) - goto ignore_char2; - -error_return2: - uart_insert_char(&sport->port, (status & 0xFFFF), - URISR_TO_SM(URISR_RXDOVR) , ch, flg); -ignore_char2: - status &= 0xffff; /* Keep URISR field*/ - status |= URUSR_TO_SM(uart->urusr); - } -out2: - tty_flip_buffer_push(tty); - return; - -handle_error2: - /* - * Update error counters. - */ - if (status & URISR_TO_SM(URISR_PER)) - sport->port.icount.parity++; - else { - if (status & URISR_TO_SM(URISR_FER)) { -#ifdef CONFIG_SERIAL_WMT_BKSIG - /* - * Experimental software patch for break signal detection. - * - * When I got there is a frame error in next frame data, - * I check the next data to judge if it is a break signal. - * - * FIXME: Open these if Bluetooth or IrDA need this patch. - * Dec.29.2004 by Harry. - */ - if ((ch & RX_PERMASK) == 0) { - sport->port.icount.brk++; - uart_handle_break(&sport->port); - } else - sport->port.icount.frame++; - -#else /* Don't support break sinal detection */ - sport->port.icount.frame++; -#endif - } - } - /* - * RX Over Run event - */ - if (status & URISR_TO_SM(URISR_RXDOVR)) - sport->port.icount.overrun++; - - if (status & sport->port.ignore_status_mask) { - if (++ignored > 100) - goto out2; - goto ignore_char2; - } - - /* - * Second, handle the events which we're interesting to listen. - */ - status &= sport->port.read_status_mask; - - if (status & URISR_TO_SM(URISR_PER)) - flg = TTY_PARITY; - else - if (status & URISR_TO_SM(URISR_FER)) { - -#ifdef CONFIG_SERIAL_WMT_BKSIG - /* Software patch for break signal detection. - * - * When I got there is a frame error in next frame data, - * I check the next data to judge if it is a break signal. - * - * FIXME: Open these if Bluetooth or IrDA need this patch. - * Dec.29.2004 by Harry. - */ - if (sport->port.read_status_mask & SW_BKSIG) { - if ((ch & RX_PERMASK) == 0) { - DEBUG_INTR("handling break...."); - flg = TTY_BREAK; - /*goto error_return;*/ - } else { - flg = TTY_FRAME; - /*goto error_return;*/ - } - } else { - flg = TTY_FRAME; - /*goto error_return;*/ - } -#else /* Don't support break sinal detection */ - flg = TTY_FRAME; -#endif - } - - if (status & URISR_TO_SM(URISR_RXDOVR)) { - /* - * Overrun is special, since it's reported - * immediately, and doesn't affect the current - * character. - */ - - ch = 0; - flg = TTY_OVERRUN; - } - #ifdef SUPPORT_SYSRQ - sport->port.sysrq = 0; - #endif - goto error_return2; - } - -} -#endif -/* - * Inside the UART interrupt service routine dut to following - * reason: - * - * URISR_TXFAE: TX FIFO almost empty (FIFO mode) - * URISR_TXFE: TX FIFO empty(FIFO mode) - */ -#ifndef CONFIG_SERIAL_WMT_DMA -static void wmt_tx_chars(struct wmt_port *sport) -{ - struct circ_buf *xmit = &sport->port.state->xmit; - struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport); - - if (sport->port.x_char) { - /* - * Fill character to the TX FIFO entry. - */ - uart->urtxf[0] = sport->port.x_char; - sport->port.icount.tx++; - sport->port.x_char = 0; - return; - } - - /*Check the modem control lines before transmitting anything.*/ - wmt_mctrl_check(sport); - - if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) { - wmt_stop_tx(&sport->port); - return; - } - - /*{2007/11/10 JHT Support the WMT Serial Port Driver Because the - * definition of URSIRT Bit[0] & Bit[3] are different. - * Before WMT these bit are defined as RO, in WMT - * they are changed into the W1C. Therefore the xmit function - * for the FIFO mode should be modified as well. - */ - while ((uart->urfidx & 0x1F) < 16) { - if (uart_circ_empty(xmit)) - break; - - if (uart->urusr & URUSR_TXDBSY) - continue; - uart->urtxf[0] = xmit->buf[xmit->tail]; - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - sport->port.icount.tx++; - } - /*}2007/11/10-JHT*/ - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&sport->port); - - if (uart_circ_empty(xmit)) - wmt_stop_tx(&sport->port); -} -#else - -static void wmt_tx_chars(struct wmt_port *sport) -{ - struct circ_buf *xmit = &sport->port.state->xmit; - int head = xmit->head; - int tail = xmit->tail; - struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport); - char *dma_buf = sport->uart_tx_dma_buf0_org; - unsigned int tx_count; - - if (sport->port.x_char) { - /* - * Fill character to the TX FIFO entry. - */ - if ((unsigned int)(sport->port.membase) != UART0_BASE_ADDR) { - /*Dma is still running*/ - if (sport->uart_tx_dma_flag != DMA_TX_END) - return; - - *dma_buf = sport->port.x_char; - sport->uart_tx_dma_flag = DMA_TX_CHAR; - DMA_TX_START(sport, sport->uart_tx_dma_phy0_org, 1); - } else { - uart->urtxf[0] = sport->port.x_char; - sport->port.icount.tx++; - sport->port.x_char = 0; - } - return; - } - /*Check the modem control lines before transmitting anything.*/ - wmt_mctrl_check(sport); - - if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) { - wmt_stop_tx(&sport->port); - return; - } - - /*{2007/11/10 JHT Support the WMT Serial Port Driver Because the - * definition of URSIRT Bit[0] & Bit[3] are different. - * Before WMT these bit are defined as RO, in WMT - * they are changed into the W1C. Therefore the xmit function - * for the FIFO mode should be modified as well. - */ - - - if ((unsigned int)(sport->port.membase) != UART0_BASE_ADDR) { - while((uart->urusr & URUSR_TXON)); - if(sport->port.line == mtk6622_tty){ - while ((uart->urusr & URUSR_TXDBSY)); - } - - if (sport->uart_tx_dma_flag == DMA_TX_END) { - sport->uart_tx_dma_flag = DMA_TX_XMIT; - tx_count = 0; - head = xmit->head; - tail = xmit->tail; - sport->uart_tx_count = 0; - while (head != tail) { - *dma_buf = xmit->buf[tail]; - tail = (tail + 1) & (UART_XMIT_SIZE - 1); - dma_buf++; - tx_count++; - sport->uart_tx_count++; - - if (tx_count == UART_BUFFER_SIZE) - break; - } - DMA_TX_START(sport, sport->uart_tx_dma_phy0_org, tx_count); - } - } else { - while ((uart->urfidx & 0x1F) < 16) { - if (uart_circ_empty(xmit)) - break; - - if (uart->urusr & URUSR_TXDBSY) - continue; - uart->urtxf[0] = xmit->buf[xmit->tail]; - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - sport->port.icount.tx++; - } - - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&sport->port); - - if (uart_circ_empty(xmit)) - wmt_stop_tx(&sport->port); - } - -} -#endif - -static irqreturn_t wmt_int(int irq, void *dev_id) -{ - struct wmt_port *sport = dev_id; - struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport); - unsigned int status, pass_counter = 0; - unsigned long flags; - - spin_lock_irqsave(&sport->port.lock, flags); - /* - * Put interrupts status information to status bit[0:15] - * Put UART status register to status bit[16:31]. - */ - - status = URISR_TO_SM(uart->urisr) | URUSR_TO_SM(uart->urusr); - uart->urisr |= SM_TO_URISR(status); - - do { - /* - * First, we handle RX events. - * - * RX FIFO Almost Full. (URUSR_RXFAF) - * RX Timeout. (URISR_RXTOUT) - * Frame error (URISR_FER) - * - * Note that also allow URISR_FER and URISR_PER event to do rx. - */ - - if (status & URISR_TO_SM(URISR_RXFAF | URISR_RXFF | URISR_RXTOUT |\ - URISR_PER | URISR_FER)) { - - if ((unsigned int)(sport->port.membase) == UART0_BASE_ADDR) - wmt_rx_chars(sport, status); - - if ((unsigned int)(sport->port.membase) != UART0_BASE_ADDR) { - uart->urier = 0; /*close uart rx interruption */ - uart->urisr |= SM_TO_URISR(status); /* clear uart rx int status */ - sport->uart_rx_dma_flag = 0; - mod_timer(&sport->rx_timer, jiffies + rx_timeout); - break; - } - } - /* - * Second, we handle TX events. - * - * If there comes a TX FIFO Almost event, try to fill TX FIFO. - */ - -#ifndef CONFIG_SERIAL_WMT_DMA - wmt_tx_chars(sport); -#else - if ((unsigned int)(sport->port.membase) == UART0_BASE_ADDR) - wmt_tx_chars(sport); -#endif - if (pass_counter++ > WMT_ISR_PASS_LIMIT) - break; - - /* - * Update UART interrupt status and general status information. - */ - status = (URISR_TO_SM(uart->urisr) | URUSR_TO_SM(uart->urusr)); - uart->urisr |= SM_TO_URISR(status); - - /* - * Inside the loop, we handle events that we're interesting. - */ - status &= sport->port.read_status_mask; - - /* - * Continue loop while following condition: - * - * TX FIFO Almost Empty. (URISR_TXFAE) - * RX FIFO Almost Full. (URISR_RXFAF) - * RX Receive Time Out. (URISR_RXTOUT) - */ - } while (status & (URISR_TXFE | - URISR_TXFAE | - URISR_RXFAF | - URISR_RXFF | - URISR_RXTOUT | - URISR_RXDOVR)); - - spin_unlock_irqrestore(&sport->port.lock, flags); - return IRQ_HANDLED; -} - -/* wmt_tx_empty() - * - * Return TIOCSER_TEMT when transmitter is not busy. - */ -static unsigned int wmt_tx_empty(struct uart_port *port) -{ - struct wmt_port *sport = (struct wmt_port *)port; - struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport); - - return (uart->urusr & URUSR_TXDBSY) ? 0 : TIOCSER_TEMT; -} - -/* wmt_get_mctrl() - * - * Returns the current state of modem control inputs. - * - * Note: Only support CTS now. - */ -static u_int wmt_get_mctrl(struct uart_port *port) -{ - u_int ret = TIOCM_DSR | TIOCM_CAR; - struct wmt_port *sport = (struct wmt_port *)port; - struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport); - - ret |= (uart->urusr & URUSR_CTS) ? TIOCM_CTS : 0; - - return ret; -} - -/* wmt_set_mctrl() - * - * This function sets the modem control lines for port described - * by 'port' to the state described by mctrl. More detail please - * refer to Documentation/serial/driver. - * - * Note: Only support RTS now. - */ -static void wmt_set_mctrl(struct uart_port *port, u_int mctrl) -{ - struct wmt_port *sport = (struct wmt_port *)port; - struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport); - - if (mctrl & TIOCM_RTS) - uart->urlcr |= URLCR_RTS; - else - uart->urlcr &= ~URLCR_RTS; - -} - -/* - * Interrupts always disabled. - */ -static void wmt_break_ctl(struct uart_port *port, int break_state) -{ - struct wmt_port *sport = (struct wmt_port *)port; - struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport); - unsigned long flags; - - spin_lock_irqsave(&sport->port.lock, flags); - - if (break_state == -1) { - int i; - unsigned int urbrd = URBRD_BRD(uart->urdiv); - - /* - * This looks something tricky. - * Anyway, we need to get current baud rate divisor, - * search bcv in baud_table[], program it into - * URBKR, then generate break signal. - */ - for (i = 0; i < BAUD_TABLE_SIZE; i++) { - if ((baud_table[i].brd & URBRD_BRDMASK) == urbrd) - break; - } - - if (i < BAUD_TABLE_SIZE) { - uart->urbkr = URBKR_BCV(baud_table[i].bcv); - uart->urlcr |= URLCR_BKINIT; - } - } - - spin_unlock_irqrestore(&sport->port.lock, flags); -} - -static char *wmt_uartname[] = { - "uart0", - "uart1", -#ifdef CONFIG_UART_2_3_ENABLE - "uart2", - "uart3", -#endif -}; - -#ifdef CONFIG_SERIAL_WMT_DMA -static void uart_dma_callback_rx(void *data) -{ - struct wmt_port *sport = data; -#ifdef UART_DEBUG - static int out_range =0x00; - if(dma_write_index >=4096){ - printk("out of 4096\n"); - dma_write_index = 0x00; - out_range++; - } -#endif - if (sport->buffer_used == 0) { - sport->buffer_used = 1; - DMA_RX_START(sport, sport->uart_rx_dma_phy0_org, UART_BUFFER_SIZE); - } else if (sport->buffer_used == 1) { - sport->buffer_used = 2; - DMA_RX_START(sport, sport->uart_rx_dma_phy1_org, UART_BUFFER_SIZE); - } else if (sport->buffer_used == 2) { - sport->buffer_used = 0; - DMA_RX_START(sport, sport->uart_rx_dma_phy2_org, UART_BUFFER_SIZE); - } -#ifdef UART_DEBUG - DMA_pbuf[dma_write_index] = sport->buffer_used + (out_range<<24); - //printk("0x%x dma rx DMA_pbuf[%d]:0x%x\n",(unsigned int)DMA_pbuf,dma_write_index,DMA_pbuf[dma_write_index]); - if(sport->buffer_rx_count_selected == 0){ - COUNT_pbuf[dma_write_index] = sport->uart_dma_tmp_phy0; - }else if(sport->buffer_rx_count_selected == 1) { - COUNT_pbuf[dma_write_index] = sport->uart_dma_tmp_phy1; - }else if(sport->buffer_rx_count_selected == 2) { - COUNT_pbuf[dma_write_index] = sport->uart_dma_tmp_phy2; - } - - if(sport->buffer_selected == 0){ - CPU_pbuf[dma_write_index] = sport->uart_dma_tmp_buf0; - }else if(sport->buffer_selected == 1){ - CPU_pbuf[dma_write_index] = sport->uart_dma_tmp_buf1; - }else if(sport->buffer_selected == 2){ - CPU_pbuf[dma_write_index] = sport->uart_dma_tmp_buf2; - } - dma_write_index++; -#endif - -} -#ifdef UART_DEBUG -void print_dma_count_cpu_buf_pos(struct wmt_port *sport) -{ - int i; - for(i=0;i<UART_BUFFER_SIZE;i++){ - //printk("0x%x DMA_pbuf[%d]:0x%x\n",DMA_pbuf,i,DMA_pbuf[i]); - if(DMA_pbuf[i] == 0x5a5a5a5a) - break; - printk("dma buf index:0x%x ",DMA_pbuf[i]); - if((sport->uart_rx_dma_phy0_org <= COUNT_pbuf[i]) && (COUNT_pbuf[i] <= (sport->uart_rx_dma_phy0_org+UART_BUFFER_SIZE))){ - printk("count buf index:0x00 offset:0x%x ",COUNT_pbuf[i]-sport->uart_rx_dma_phy0_org); - }else if((sport->uart_rx_dma_phy1_org <= COUNT_pbuf[i]) && (COUNT_pbuf[i] <= (sport->uart_rx_dma_phy1_org+UART_BUFFER_SIZE))){ - printk("count buf index:0x01 offset:0x%x ",COUNT_pbuf[i]-sport->uart_rx_dma_phy1_org); - }if((sport->uart_rx_dma_phy2_org <= COUNT_pbuf[i]) && (COUNT_pbuf[i] <= (sport->uart_rx_dma_phy2_org+UART_BUFFER_SIZE))){ - printk("count buf index:0x02 offset:0x%x ",COUNT_pbuf[i]-sport->uart_rx_dma_phy2_org); - } - - if((sport->uart_rx_dma_buf0_org <= CPU_pbuf[i]) && (CPU_pbuf[i] <= (sport->uart_rx_dma_buf0_org+UART_BUFFER_SIZE))){ - printk("cpu buf index:0x00 offset:0x%x\n",CPU_pbuf[i]-(unsigned int)sport->uart_rx_dma_buf0_org); - }else if((sport->uart_rx_dma_buf1_org <= CPU_pbuf[i]) && (CPU_pbuf[i] <= (sport->uart_rx_dma_buf1_org+UART_BUFFER_SIZE))){ - printk("cpu buf index:0x01 offset:0x%x\n",CPU_pbuf[i]-(unsigned int)sport->uart_rx_dma_buf1_org); - }if((sport->uart_rx_dma_buf2_org <= CPU_pbuf[i]) && (CPU_pbuf[i] <= (sport->uart_rx_dma_buf2_org+UART_BUFFER_SIZE))){ - printk("cpu buf index:0x02 offset:0x%x\n",CPU_pbuf[i]-(unsigned int)sport->uart_rx_dma_buf2_org); - } - printk("\n"); - } -} -#endif -static void uart_dma_callback_tx(void *data) -{ - struct wmt_port *sport = data; - unsigned long flags; - sport->dma_tx_cnt++; - spin_lock_irqsave(&sport->port.lock, flags); - - if (sport->uart_tx_dma_flag == DMA_TX_CHAR) { - sport->port.icount.tx++; - sport->port.x_char = 0; - } else { - sport->port.state->xmit.tail = - (sport->port.state->xmit.tail + sport->uart_tx_count) & (UART_XMIT_SIZE - 1); - sport->port.icount.tx += sport->uart_tx_count; - } - sport->uart_tx_dma_flag = DMA_TX_END; - - wmt_tx_chars(sport); - - if (uart_circ_chars_pending(&sport->port.state->xmit) < WAKEUP_CHARS) - uart_write_wakeup(&sport->port); - - if (uart_circ_empty(&sport->port.state->xmit)) - wmt_stop_tx(&sport->port); - - spin_unlock_irqrestore(&sport->port.lock, flags); - -} -#endif - -wmt_uart1_pre_init(void) -{ - GPIO_CTRL_GP18_UART_BYTE_VAL &= ~(BIT4 | BIT5); - auto_pll_divisor(DEV_UART1, CLK_ENABLE, 0, 0); - printk("wmt_uart1_pre_init\n"); -} - -wmt_uart1_post_deinit(void) -{ - GPIO_CTRL_GP18_UART_BYTE_VAL |= (BIT4 | BIT5); - auto_pll_divisor(DEV_UART1, CLK_DISABLE, 0, 0); - printk("wmt_uart1_post_deinit\n"); -} - -static int wmt_startup(struct uart_port *port) -{ - struct wmt_port *sport = (struct wmt_port *)port; - struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport); - char *uartname = NULL; - int retval; - int i; - unsigned long flags; - - switch (sport->port.irq) { - - case IRQ_UART0: - uartname = wmt_uartname[0]; -/*#ifdef CONFIG_SERIAL_WMT_DMA - sport->port.dma_rx_dev = UART_0_RX_DMA_REQ; - sport->port.dma_tx_dev = UART_0_TX_DMA_REQ; - sport->id = "uart0"; - sport->port.dma_rx_cfg = dma_device_cfg_table[UART_0_RX_DMA_REQ]; - sport->port.dma_tx_cfg = dma_device_cfg_table[UART_0_TX_DMA_REQ]; -#endif*/ - break; - - case IRQ_UART1: - wmt_uart1_pre_init();//added by rubbitxiao - uartname = wmt_uartname[1]; -#ifdef CONFIG_SERIAL_WMT_DMA - sport->dma_rx_dev = UART_1_RX_DMA_REQ; - sport->dma_tx_dev = UART_1_TX_DMA_REQ; - sport->id = "uart1"; - sport->dma_rx_cfg = dma_device_cfg_table[UART_1_RX_DMA_REQ]; - sport->dma_tx_cfg = dma_device_cfg_table[UART_1_TX_DMA_REQ]; -#endif - break; - -#ifdef CONFIG_UART_2_3_ENABLE - case IRQ_UART2: - uartname = wmt_uartname[2]; -#ifdef CONFIG_SERIAL_WMT_DMA - sport->dma_rx_dev = UART_2_RX_DMA_REQ; - sport->dma_tx_dev = UART_2_TX_DMA_REQ; - sport->id = "uart2"; - sport->dma_rx_cfg = dma_device_cfg_table[UART_2_RX_DMA_REQ]; - sport->dma_tx_cfg = dma_device_cfg_table[UART_2_TX_DMA_REQ]; -#endif - break; - case IRQ_UART3: - uartname = wmt_uartname[3]; -#ifdef CONFIG_SERIAL_WMT_DMA - sport->dma_rx_dev = UART_3_RX_DMA_REQ; - sport->dma_tx_dev = UART_3_TX_DMA_REQ; - sport->id = "uart3"; - sport->dma_rx_cfg = dma_device_cfg_table[UART_3_RX_DMA_REQ]; - sport->dma_tx_cfg = dma_device_cfg_table[UART_3_TX_DMA_REQ]; -#endif - break; -#endif - - } -#ifdef CONFIG_SERIAL_WMT_DMA - if ((unsigned int)(sport->port.membase) != UART0_BASE_ADDR) { - memset(sport->uart_rx_dma_buf0_org, 0x0, UART_BUFFER_SIZE); - memset(sport->uart_rx_dma_buf1_org, 0x0, UART_BUFFER_SIZE); - memset(sport->uart_rx_dma_buf2_org, 0x0, UART_BUFFER_SIZE); - memset(sport->uart_tx_dma_buf0_org, 0x0, UART_BUFFER_SIZE); - sport->uart_dma_tmp_buf0 = sport->uart_rx_dma_buf0_org; - sport->uart_dma_tmp_phy0 = sport->uart_rx_dma_phy0_org; - sport->uart_dma_tmp_buf1 = sport->uart_rx_dma_buf1_org; - sport->uart_dma_tmp_buf2 = sport->uart_rx_dma_buf2_org; - sport->uart_dma_tmp_phy1 = sport->uart_rx_dma_phy1_org; - sport->uart_dma_tmp_phy2 = sport->uart_rx_dma_phy2_org; - sport->buffer_used = 0; /*to record which buf DMA hardware used*/ - sport->buffer_selected = 0; /* to record which buf software is used to put data to kernel*/ - sport->buffer_rx_count_selected = 0; /* to record which buf rx_count is used*/ - sport->rx_dmach = NULL_DMA; - sport->tx_dmach = NULL_DMA; - sport->last_pos = 0; - sport->uart_tx_dma_flag = DMA_TX_END; - sport->uart_tx_count = 0; - sport->dma_tx_cnt = 0x00; - init_timer(&sport->rx_timer); - sport->rx_timer.function = wmt_rx_timeout; - sport->rx_timer.data = (unsigned long)sport; - DMA_RX_REQUEST(sport, uart_dma_callback_rx); - DMA_TX_REQUEST(sport, uart_dma_callback_tx); - wmt_setup_dma(sport->rx_dmach, sport->dma_rx_cfg); - wmt_setup_dma(sport->tx_dmach, sport->dma_tx_cfg); - DMA_RX_START(sport, sport->uart_rx_dma_phy0_org, UART_BUFFER_SIZE); - DMA_RX_START(sport, sport->uart_rx_dma_phy1_org, UART_BUFFER_SIZE); - DMA_RX_START(sport, sport->uart_rx_dma_phy2_org, UART_BUFFER_SIZE); -#ifdef UART_DEBUG - DMA_pbuf = kmalloc(UART_BUFFER_SIZE*sizeof(unsigned int*), GFP_KERNEL); - COUNT_pbuf = kmalloc(UART_BUFFER_SIZE*sizeof(unsigned int*), GFP_KERNEL); - CPU_pbuf = kmalloc(UART_BUFFER_SIZE*sizeof(unsigned int*), GFP_KERNEL); - if(!DMA_pbuf || !COUNT_pbuf || !CPU_pbuf){ - printk("kmalloc buf for debug buf failed\n"); - return; - }else{ - memset(DMA_pbuf,0x5a,UART_BUFFER_SIZE*sizeof(unsigned int*)); - memset(COUNT_pbuf,0x00,UART_BUFFER_SIZE*sizeof(unsigned int*)); - memset(CPU_pbuf,0x00,UART_BUFFER_SIZE*sizeof(unsigned int*)); - } - dma_write_index =0x00; -#endif - { - char uboot_buf[256]; - int varlen = sizeof(uboot_buf); - if(wmt_getsyspara("wmt.bt.tty",uboot_buf,&varlen) == 0) - { - sscanf(uboot_buf,"%d",&mtk6622_tty); - printk("mtk6622_tty:%d\n",mtk6622_tty); - if(1<=mtk6622_tty && mtk6622_tty <=3){ - printk("wmt.bt.tty is correct\n"); - }else{ - printk("wmt.bt.tty is illegal\n"); - mtk6622_tty = -1; - } - }else{ - printk("have not set uboot variant:wmt.bt.tty\n"); - } - } - } -#endif - /* - * Allocate the IRQ - */ - retval = request_irq(sport->port.irq, wmt_int, 0, uartname, sport); - if (retval) - return retval; - - /* - * Setup the UART clock divisor - */ - for (i = 0; i < BAUD_TABLE_SIZE; i++) { - if (baud_table[i].baud == 115200) - break; - } - spin_lock_irqsave(&sport->port.lock, flags); - - uart->urdiv = baud_table[i].brd; - - /* Disable TX,RX*/ - uart->urlcr = 0; - /* Disable all interrupt*/ - uart->urier = 0; - - /*Reset TX,RX Fifo*/ - uart->urfcr = URFCR_TXFRST | URFCR_RXFRST; - - while (uart->urfcr) - ; - - /* Disable Fifo*/ - uart->urfcr &= ~(URFCR_FIFOEN); - - uart->urlcr |= (URLCR_DLEN & ~URLCR_STBLEN & ~URLCR_PTYEN); -#ifdef CONFIG_SERIAL_WMT_DMA - if ((unsigned int)(sport->port.membase) != UART0_BASE_ADDR) { - uart->urfcr = URFCR_FIFOEN | URFCR_TXFLV(8) | URFCR_RXFLV(1) | URFCR_TRAIL; - uart->urtod = 0x0a; - } else - uart->urfcr = URFCR_FIFOEN | URFCR_TXFLV(8) | URFCR_RXFLV(4); -#else - /* Enable Fifo, Tx 16 , Rx 16*/ - uart->urfcr = URFCR_FIFOEN | URFCR_TXFLV(8) | URFCR_RXFLV(4); -#endif - /* Enable Fifo, Tx 8 , Rx 8*/ -#ifdef CONFIG_SERIAL_WMT_DMA - if ((unsigned int)(sport->port.membase) != UART0_BASE_ADDR) { - uart->urlcr |= URLCR_RXEN | URLCR_TXEN | URLCR_DMAEN | URLCR_RCTSSW; - uart->urier = URIER_ERXFAF | URIER_ERXFF | URIER_ERXTOUT | - URIER_EPER | URIER_EFER | URIER_ERXDOVR; - } else { - uart->urlcr |= URLCR_RXEN | URLCR_TXEN | URLCR_RCTSSW; - uart->urier = URIER_ERXFAF | URIER_ERXFF | URIER_ERXTOUT | - URIER_EPER | URIER_EFER | URIER_ERXDOVR; - } -#else - uart->urlcr |= URLCR_RXEN | URLCR_TXEN | URLCR_RCTSSW; - uart->urier = URIER_ERXFAF | URIER_ERXFF | URIER_ERXTOUT | URIER_EPER | - URIER_EFER | URIER_ERXDOVR; - -#endif - /* - * Enable RX FIFO almost full, timeout, and overrun interrupts. - */ - - /* - * Enable modem status interrupts - */ - - wmt_enable_ms(&sport->port); - spin_unlock_irqrestore(&sport->port.lock, flags); - - return 0; -} - -static void wmt_shutdown(struct uart_port *port) -{ - struct wmt_port *sport = (struct wmt_port *)port; - struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport); - unsigned long flags; - //added begin by rubbitxiao - spin_lock_irqsave(&sport->port.lock, flags); - /* Disable TX,RX*/ - uart->urlcr = 0; - /* Disable all interrupt*/ - uart->urier = 0; - /*Reset TX,RX Fifo*/ - uart->urfcr = URFCR_TXFRST | URFCR_RXFRST; - while (uart->urfcr) - ; - /* Disable Fifo*/ - uart->urfcr &= ~(URFCR_FIFOEN); - uart->urlcr |= (URLCR_DLEN & ~URLCR_STBLEN & ~URLCR_PTYEN); - spin_unlock_irqrestore(&sport->port.lock, flags); - //added end by rubbitxiao - /* - * Stop our timer. - */ - del_timer_sync(&sport->timer); - - /* - * Free the allocated interrupt - */ - free_irq(sport->port.irq, sport); - - /* - * Disable all interrupts, port and break condition. - */ - //spin_lock_irqsave(&sport->port.lock, flags); - //uart->urier &= ~(URIER_ETXFE | URIER_ETXFAE | URIER_ERXFF | URIER_ERXFAF); - //spin_unlock_irqrestore(&sport->port.lock, flags); - -#ifdef CONFIG_SERIAL_WMT_DMA - if ((unsigned int)(sport->port.membase) != UART0_BASE_ADDR) { - del_timer_sync(&sport->rx_timer); - DMA_RX_STOP(sport); - DMA_RX_CLEAR(sport); - DMA_RX_FREE(sport); - while (sport->uart_tx_dma_flag != DMA_TX_END) - msleep(1); - - DMA_TX_STOP(sport); - DMA_TX_CLEAR(sport); - DMA_TX_FREE(sport); - } -#endif - if ((unsigned int)(sport->port.membase) == UART1_BASE_ADDR) - wmt_uart1_post_deinit(); -} - -/* wmt_uart_pm() - * - * Switch on/off uart in powersave mode. - * - * Hint: Identify port by irq number. - */ -static void wmt_uart_pm(struct uart_port *port, u_int state, u_int oldstate) -{ - return; -} - -static void -wmt_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) -{ - struct wmt_port *sport = (struct wmt_port *)port; - struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport); - unsigned long flags; - unsigned int new_urlcr, old_urlcr, old_urier, tmp_urisr, baud; - unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; - int i; - - /* - * If we don't support modem control lines, don't allow - * these to be set. - */ - if (0) { - termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR); - termios->c_cflag |= CLOCAL; - } - /* - * Only support CS7 and CS8. - */ - while ((termios->c_cflag & CSIZE) != CS7 && (termios->c_cflag & CSIZE) != CS8) { - termios->c_cflag &= ~CSIZE; - termios->c_cflag |= old_csize; - old_csize = CS8; - } - - if ((termios->c_cflag & CSIZE) == CS8) - new_urlcr = URLCR_DLEN; - else - new_urlcr = 0; - - if (termios->c_cflag & CRTSCTS) - new_urlcr &= ~URLCR_RCTSSW; - else - new_urlcr |= URLCR_RCTSSW; - - if (termios->c_cflag & CSTOPB) - new_urlcr |= URLCR_STBLEN; - - if (termios->c_cflag & PARENB) { - /* - * Enable parity. - */ - new_urlcr |= URLCR_PTYEN; - - /* - * Parity mode select. - */ - if (termios->c_cflag & PARODD) - new_urlcr |= URLCR_PTYMODE; - } - - /* - * Ask the core to get baud rate, but we need to - * calculate quot by ourself. - */ - baud = uart_get_baud_rate(port, termios, old, 9600, 921600); - - /* - * We need to calculate quot by ourself. - * - * FIXME: Be careful, following result is not an - * interger quotient, fix it if need. - */ - /*quot = port->uartclk / (13 * baud);*/ - - spin_lock_irqsave(&sport->port.lock, flags); - - /* - * Mask out other interesting to listen expect TX FIFO almost empty event. - */ - sport->port.read_status_mask &= URISR_TO_SM(URISR_TXFAE | URISR_TXFE); - - /* - * We're also interested in receiving RX FIFO events. - */ - sport->port.read_status_mask |= URISR_TO_SM(URISR_RXDOVR | URISR_RXFAF | URISR_RXFF); - - /* - * Check if we need to enable frame and parity error events - * to be passed to the TTY layer. - */ - if (termios->c_iflag & INPCK) - sport->port.read_status_mask |= URISR_TO_SM(URISR_FER | URISR_PER); - -#ifdef CONFIG_SERIAL_WMT_BKSIG - /* - * check if we need to enable break events to be passed to the TTY layer. - */ - if (termios->c_iflag & (BRKINT | PARMRK)) - /* - * WMT UART doesn't support break signal detection interrupt. - * - * I try to implement this using URISR_FER. - */ - sport->port.read_status_mask |= SW_BKSIG; -#endif - /* - * Characters to ignore - */ - sport->port.ignore_status_mask = 0; - - if (termios->c_iflag & IGNPAR) - sport->port.ignore_status_mask |= URISR_TO_SM(URISR_FER | URISR_PER); - - if (termios->c_iflag & IGNBRK) { -#ifdef CONFIG_SERIAL_WMT_BKSIG - /* - * WMT UART doesn't support break signal detection interrupt. - * - * I try to implement this using URISR_FER. - */ - sport->port.ignore_status_mask |= BIT31;/*FIXME*/ -#endif - - /* - * If we're ignoring parity and break indicators, - * ignore overruns too (for real raw support). - */ - if (termios->c_iflag & IGNPAR) - sport->port.ignore_status_mask |= URISR_TO_SM(URISR_RXDOVR); - } - - del_timer_sync(&sport->timer); - - /* - * Update the per-port timeout. - */ - uart_update_timeout(port, termios->c_cflag, baud); - - /* - * Disable FIFO request interrupts and drain transmitter - */ - old_urlcr = uart->urlcr; - old_urier = uart->urier; - uart->urier = old_urier & ~(URIER_ETXFAE | URIER_ERXFAF); - - /* - * Two step polling, first step polling the remaining - * entries in TX FIFO. This step make it safe to drain - * out all of remaining data in FIFO. - */ - while (URFIDX_TXFIDX(uart->urfidx)) - barrier(); - - /* - * Second step to make sure the last one data has been sent. - */ - while (uart->urusr & URUSR_TXDBSY) - barrier(); - - /* - * Disable this UART port. - */ - uart->urier = 0; - - /* - * Set the parity, stop bits and data size - */ - uart->urlcr = new_urlcr; - - /* - * Set baud rate - */ - - for (i = 0; i < BAUD_TABLE_SIZE; i++) { - if (baud_table[i].baud == baud) - break; - } - uart->urdiv = baud_table[i].brd; - - /* - * Read to clean any pending pulse interrupts. - */ - tmp_urisr = uart->urisr; - - /* - * Restore FIFO interrupt, TXEN bit, RXEN bit settings. - */ - uart->urier = old_urier; -#ifdef CONFIG_SERIAL_WMT_DMA - uart->urlcr |= old_urlcr & (URLCR_TXEN | URLCR_RXEN | URLCR_DMAEN); -#else - uart->urlcr |= old_urlcr & (URLCR_TXEN | URLCR_RXEN); -#endif - - if (UART_ENABLE_MS(&sport->port, termios->c_cflag)) - wmt_enable_ms(&sport->port); - - spin_unlock_irqrestore(&sport->port.lock, flags); -} - -static const char *wmt_type(struct uart_port *port) -{ - struct wmt_port *sport = (struct wmt_port *)port; - - return (sport->port.type == PORT_WMT) ? "wmt serial" : NULL; -} - -/* - * Release the memory region(s) being used by 'port'. - */ -static void wmt_release_port(struct uart_port *port) -{ - struct wmt_port *sport = (struct wmt_port *)port; - - release_mem_region(sport->port.mapbase, UART_PORT_SIZE); -} - -/* - * Request the memory region(s) being used by 'port'. - */ -static int wmt_request_port(struct uart_port *port) -{ - struct wmt_port *sport = (struct wmt_port *)port; - - return request_mem_region(sport->port.mapbase, - UART_PORT_SIZE, - "uart") != NULL ? 0 : -EBUSY; -} - -/* - * Configure/autoconfigure the port. - */ -static void wmt_config_port(struct uart_port *port, int flags) -{ - struct wmt_port *sport = (struct wmt_port *)port; - - if (flags & UART_CONFIG_TYPE && wmt_request_port(&sport->port) == 0) - sport->port.type = PORT_WMT; -} - -/* - * Verify the new serial_struct (for TIOCSSERIAL). - * The only change we allow are to the flags and type, and - * even then only between PORT_WMT and PORT_UNKNOWN - */ -static int wmt_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - struct wmt_port *sport = (struct wmt_port *)port; - int ret = 0; - - if (ser->type != PORT_UNKNOWN && ser->type != PORT_WMT) - ret = -EINVAL; - if (sport->port.irq != ser->irq) - ret = -EINVAL; - if (ser->io_type != SERIAL_IO_MEM) - ret = -EINVAL; - if (sport->port.uartclk / 16 != ser->baud_base) - ret = -EINVAL; - - if ((void *)sport->port.mapbase != ser->iomem_base) - ret = -EINVAL; - if (sport->port.iobase != ser->port) - ret = -EINVAL; - if (ser->hub6 != 0) - ret = -EINVAL; - return ret; -} - -static struct uart_ops wmt_pops = { - .tx_empty = wmt_tx_empty, - .set_mctrl = wmt_set_mctrl, - .get_mctrl = wmt_get_mctrl, - .stop_tx = wmt_stop_tx, - .start_tx = wmt_start_tx, - .stop_rx = wmt_stop_rx, - .enable_ms = wmt_enable_ms, - .break_ctl = wmt_break_ctl, - .startup = wmt_startup, - .shutdown = wmt_shutdown, - .pm = wmt_uart_pm, - .set_termios = wmt_set_termios, - .type = wmt_type, - .release_port = wmt_release_port, - .request_port = wmt_request_port, - .config_port = wmt_config_port, - .verify_port = wmt_verify_port, -}; - -static int parse_spi1_param(void) -{ - char buf[64]; - size_t l = sizeof(buf); - int uart_spi_sel = 0; - - if (wmt_getsyspara("wmt.spi1.param", buf, &l) == 0) { - sscanf(buf, "%d", &uart_spi_sel); - } - return uart_spi_sel; -} - -/* Setup the WMT serial ports. Note that we don't include the IrDA - * port here since we have our own SIR/FIR driver (see drivers/net/irda) - * - * Note also that we support "console=ttyVTx" where "x" is either 0 to 2. - * Which serial port this ends up being depends on the machine you're - * running this kernel on. - */ -static void wmt_init_ports(void) -{ - static int first = 1; - int i; - - if (!first) - return; - - first = 0; - - wmt_uart_spi_sel = parse_spi1_param(); - - for (i = 0; i < NR_PORTS; i++) { - wmt_ports[i].port.uartclk = 24000000; - wmt_ports[i].port.ops = &wmt_pops; - wmt_ports[i].port.fifosize = 16; - wmt_ports[i].port.line = i; - wmt_ports[i].port.iotype = SERIAL_IO_MEM; - init_timer(&wmt_ports[i].timer); - wmt_ports[i].timer.function = wmt_timeout; - wmt_ports[i].timer.data = (unsigned long)&wmt_ports[i]; - } - - /* - * Make sure all UARTs are not configured as GPIO function. - * - * This step may be redundant due to bootloader has already - * done this for us. - */ - - - /* Switch the Uart's pin from default GPIO into uart function pins for UART0 ~ UART3 */ - GPIO_CTRL_GP18_UART_BYTE_VAL &= ~(BIT0 | BIT1 | BIT2 | BIT3 | - BIT4 | BIT5 | BIT6 | BIT7); /*UART0 UART1*/ -#ifdef CONFIG_UART_2_3_ENABLE - GPIO_CTRL_GP18_UART_BYTE_VAL &= ~(BIT2 | BIT3 | BIT6 | BIT7); /*UART2 UART3*/ -#endif - - /*Set Uart0 and Uart1, Uart2 and Uart3 pin share*/ - PIN_SHARING_SEL_4BYTE_VAL &= ~(BIT9 | BIT8); - if (wmt_uart_spi_sel == SHARE_PIN_UART) - PIN_SHARING_SEL_4BYTE_VAL &= ~(BIT10); - -#ifdef CONFIG_UART_2_3_ENABLE - //kevin modify uart0,uart1(hw flow control),uart2 - PIN_SHARING_SEL_4BYTE_VAL |= (BIT8); -#endif - - auto_pll_divisor(DEV_UART0, CLK_ENABLE, 0, 0); - auto_pll_divisor(DEV_UART1, CLK_ENABLE, 0, 0); -#ifdef CONFIG_UART_2_3_ENABLE - auto_pll_divisor(DEV_UART2, CLK_ENABLE, 0, 0); - auto_pll_divisor(DEV_UART3, CLK_ENABLE, 0, 0); -#endif -} - -void __init wmt_register_uart_fns(struct wmt_port_fns *fns) -{ - if (fns->get_mctrl) - wmt_pops.get_mctrl = fns->get_mctrl; - if (fns->set_mctrl) - wmt_pops.set_mctrl = fns->set_mctrl; - - wmt_pops.pm = fns->pm; - wmt_pops.set_wake = fns->set_wake; -} - -void __init wmt_register_uart(int idx, int port) -{ - if (idx >= NR_PORTS) { - printk(KERN_ERR "%s: bad index number %d\n", __func__, idx); - return; - } - - switch (port) { - case 0: - wmt_ports[idx].port.membase = (void *)(REG32_PTR(UART0_BASE_ADDR)); - wmt_ports[idx].port.mapbase = UART0_BASE_ADDR; - wmt_ports[idx].port.irq = IRQ_UART0; - wmt_ports[idx].port.flags = ASYNC_BOOT_AUTOCONF; - break; - case 1: - wmt_ports[idx].port.membase = (void *)(REG32_PTR(UART1_BASE_ADDR)); - wmt_ports[idx].port.mapbase = UART1_BASE_ADDR; - wmt_ports[idx].port.irq = IRQ_UART1; - wmt_ports[idx].port.flags = ASYNC_BOOT_AUTOCONF; - break; -#ifdef CONFIG_UART_2_3_ENABLE - case 2: - wmt_ports[idx].port.membase = (void *)(REG32_PTR(UART2_BASE_ADDR)); - wmt_ports[idx].port.mapbase = UART2_BASE_ADDR; - wmt_ports[idx].port.irq = IRQ_UART2; - wmt_ports[idx].port.flags = ASYNC_BOOT_AUTOCONF; - break; - case 3: - wmt_ports[idx].port.membase = (void *)(REG32_PTR(UART3_BASE_ADDR)); - wmt_ports[idx].port.mapbase = UART3_BASE_ADDR; - wmt_ports[idx].port.irq = IRQ_UART3; - wmt_ports[idx].port.flags = ASYNC_BOOT_AUTOCONF; - break; -#endif - - default: - printk(KERN_ERR "%s: bad port number %d\n", __func__, port); - } -} - -#ifdef CONFIG_SERIAL_WMT_CONSOLE - -/* - * Interrupts are disabled on entering - * - * Note: We do console writing with UART register mode. - */ - -static void wmt_console_write(struct console *co, const char *s, u_int count) -{ - struct wmt_port *sport = &wmt_ports[co->index]; - struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport); - unsigned int i, old_urlcr, old_urier; - /*{JHT*/ - unsigned int old_urfcr; - unsigned long flags; - - spin_lock_irqsave(&sport->port.lock, flags); - /*}JHT*/ - /* - * First, save URLCR and URIER. - */ - old_urlcr = uart->urlcr; - old_urier = uart->urier; - /*{JHT*/ - old_urfcr = uart->urfcr; - /*}JHT*/ - - /* - * Second, switch to register mode with follows method: - * - * Disable FIFO threshold interrupts, and enable transmitter. - */ - uart->urier &= ~(URIER_ETXFAE | URIER_ERXFAF); - uart->urlcr |= URLCR_TXEN; - /*{JHT*/ - uart->urfcr &= ~URFCR_FIFOEN; - /*}JHT*/ - /* - * Now, do each character - */ - for (i = 0; i < count; i++) { - /* - * Polling until free for transmitting. - */ - while (uart->urusr & URUSR_TXDBSY) - ; - - uart->urtdr = (unsigned int)s[i]; - - /* - * Do CR if there comes a LF. - */ - if (s[i] == '\n') { - /* - * Polling until free for transmitting. - */ - while (uart->urusr & URUSR_TXDBSY) - ; - - uart->urtdr = (unsigned int)'\r'; - } - } - - /* - * Finally, wait for transmitting done and restore URLCR and URIER. - */ - while (uart->urusr & URUSR_TXDBSY) - ; - - uart->urlcr = old_urlcr; - uart->urier = old_urier; - /*{JHT*/ - uart->urfcr = old_urfcr; - /*}JHT*/ - spin_unlock_irqrestore(&sport->port.lock, flags); -} - -/* - * If the port was already initialised (eg, by a boot loader), try to determine - * the current setup. - */ -static void __init wmt_console_get_options(struct wmt_port *sport, int *baud, int *parity, int *bits) -{ - int i; - struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport); - - if ((uart->urlcr & (URLCR_RXEN | URLCR_TXEN)) == (URLCR_RXEN | URLCR_TXEN)) { - /* - * Port was enabled. - */ - unsigned quot; - - *parity = 'n'; - /* - * Check parity mode, 0:evev 1:odd - */ - if (uart->urlcr & URLCR_PTYEN) { - if (uart->urlcr & URLCR_PTYMODE) - *parity = 'o'; - else - *parity = 'e'; - } - - /* - * Check data length, 0:7-bit 1:8-bit - */ - if (uart->urlcr & URLCR_DLEN) - *bits = 8; - else - *bits = 7; - - /* - * Get baud rate divisor. - */ - quot = (uart->urdiv & URBRD_BRDMASK); - /* - * FIXME: I didn't trace the console driver want me - * report baud rate whether actual baud rate or ideal - * target baud rate, current I report baud as actual - * one, if it need value as target baud rate, just - * creat an array to fix it, Dec.23 by Harry. - */ - - for (i = 0; i < BAUD_TABLE_SIZE; i++) { - if ((baud_table[i].brd & URBRD_BRDMASK) == quot) { - *baud = baud_table[i].baud; - break; - } - } - - /* - * If this condition is true, something might be wrong. - * I reprot the actual baud rate temporary. - * Check the printk information then fix it. - */ - if (i >= BAUD_TABLE_SIZE) - *baud = sport->port.uartclk / (13 * (quot + 1)); - } -} - -#ifndef CONFIG_WMT_DEFAULT_BAUDRATE -#define CONFIG_WMT_DEFAULT_BAUDRATE 115200 -#endif - -static int __init -wmt_console_setup(struct console *co, char *options) -{ - struct wmt_port *sport; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - int baud = CONFIG_WMT_DEFAULT_BAUDRATE; - - /* - * Check whether an invalid uart number has been specified, and - * if so, search for the first available port that does have - * console support. - */ - if (co->index == -1 || co->index >= NR_PORTS) - co->index = 0; - - sport = &wmt_ports[co->index]; - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - else - wmt_console_get_options(sport, &baud, &parity, &bits); - - return uart_set_options(&sport->port, co, baud, parity, bits, flow); -} - -static struct uart_driver wmt_reg; - -static struct console wmt_console = { - -#ifdef CONFIG_SERIAL_WMT_TTYVT - .name = "ttyVT", -#else - .name = "ttyS", -#endif - .write = wmt_console_write, - .device = uart_console_device, - .setup = wmt_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &wmt_reg, -}; - -static int __init wmt_rs_console_init(void) -{ - wmt_init_ports(); - register_console(&wmt_console); - return 0; -} - -console_initcall(wmt_rs_console_init); - -#define WMT_CONSOLE (&wmt_console) - -#else /* CONFIG_SERIAL_WMT_CONSOLE */ - -#define WMT_CONSOLE NULL - -#endif - -static struct uart_driver wmt_reg = { - .owner = THIS_MODULE, - -#ifdef CONFIG_SERIAL_WMT_TTYVT - .driver_name = "ttyVT", - .dev_name = "ttyVT", -#else - .driver_name = "ttyS", - .dev_name = "ttyS", -#endif - .major = SERIAL_WMT_MAJOR, - .minor = MINOR_START, - .nr = NR_PORTS, - .cons = WMT_CONSOLE, -}; - - -void wmt_serial_set_reg(void) -{ - *(volatile unsigned int *) (UART0_BASE_ADDR + 0x00000008) = BRD_115200BPS; - *(volatile unsigned int *) (UART0_BASE_ADDR + 0x0000000c) = URLCR_TXEN | - URLCR_RXEN | - URLCR_DLEN | - URLCR_RCTSSW; - - *(volatile unsigned int *) (UART0_BASE_ADDR + 0x00000014) = URIER_ERXFAF | - URIER_ERXFF | - URIER_ERXTOUT | - URIER_EPER | - URIER_EFER | - URIER_ERXDOVR; - - *(volatile unsigned int *) (UART0_BASE_ADDR + 0x00000020) = URFCR_FIFOEN | - URFCR_TXFLV(8) | - URFCR_RXFLV(8); -} - -static int wmt_serial_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct device *dev = &pdev->dev; - struct wmt_port *sport = dev_get_drvdata(dev); - struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport); - unsigned long flags; - - if (sport) { - if (sport->port.irq != IRQ_UART0) - uart_suspend_port(&wmt_reg, &sport->port); - } - if (!sport) - return 0; - - spin_lock_irqsave(&sport->port.lock, flags); - - /* save host register */ - sport->old_urdiv = uart->urdiv; - sport->old_urlcr = uart->urlcr; - sport->old_urier = uart->urier; - sport->old_urfcr = uart->urfcr; - sport->old_urtod = uart->urtod; - - uart->urier = 0; - spin_unlock_irqrestore(&sport->port.lock, flags); - - switch (sport->port.irq) { - case IRQ_UART0: - /*auto_pll_divisor(DEV_UART0, CLK_DISABLE, 0, 0);*/ - break; - case IRQ_UART1: - auto_pll_divisor(DEV_UART1, CLK_DISABLE, 0, 0); - break; -#ifdef CONFIG_UART_2_3_ENABLE - case IRQ_UART2: - auto_pll_divisor(DEV_UART2, CLK_DISABLE, 0, 0); - break; - - case IRQ_UART3: - auto_pll_divisor(DEV_UART3, CLK_DISABLE, 0, 0); - break; -#endif - default: - break; - - } - return 0; -} - -static int wmt_serial_resume(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct wmt_port *sport = dev_get_drvdata(dev); - struct wmt_uart *uart = (struct wmt_uart *)PORT_TO_BASE(sport); - unsigned long flags; - - if (!sport) - return 0; - - GPIO_CTRL_GP18_UART_BYTE_VAL &= ~(BIT0 | BIT1 | BIT2 | BIT3 | - BIT4 | BIT5 | BIT6 | BIT7); /*UART0 UART1*/ -#ifdef CONFIG_UART_2_3_ENABLE - GPIO_CTRL_GP18_UART_BYTE_VAL &= ~(BIT2 | BIT3 | BIT6 | BIT7); /*UART2 UART3*/ -#endif - - /*Set Uart0 and Uart1, Uart2 and Uart3 pin share*/ - PIN_SHARING_SEL_4BYTE_VAL &= ~(BIT9 | BIT8); - if (wmt_uart_spi_sel == SHARE_PIN_UART) - PIN_SHARING_SEL_4BYTE_VAL &= ~(BIT10); - -#ifdef CONFIG_UART_2_3_ENABLE - //kevin modify, uart0,uart1(hw flow control),uart2 - PIN_SHARING_SEL_4BYTE_VAL |= (BIT8); -#endif - - switch (sport->port.irq) { - case IRQ_UART0: - auto_pll_divisor(DEV_UART0, CLK_ENABLE, 0, 0); - break; - case IRQ_UART1: - auto_pll_divisor(DEV_UART1, CLK_ENABLE, 0, 0); - break; -#ifdef CONFIG_UART_2_3_ENABLE - case IRQ_UART2: - auto_pll_divisor(DEV_UART2, CLK_ENABLE, 0, 0); - break; - case IRQ_UART3: - auto_pll_divisor(DEV_UART3, CLK_ENABLE, 0, 0); - break; -#endif - default: - break; - } - - if (sport->port.irq != IRQ_UART0) { - /* Disable TX,RX */ - uart->urlcr = 0; - /* Disable all interrupt */ - uart->urier = 0; - /* Clear all interrupt */ - uart->urisr = 0xffffffff; - - /* Disable Fifo */ - uart->urfcr &= ~(URFCR_FIFOEN); - - /* Reset TX,RX Fifo */ - uart->urfcr = URFCR_TXFRST | URFCR_RXFRST; - - while (uart->urfcr) - ; - } - - spin_lock_irqsave(&sport->port.lock, flags); - /*store back the interrupt enable status*/ - uart->urdiv = sport->old_urdiv; - uart->urfcr = sport->old_urfcr; - uart->urtod = sport->old_urtod; - uart->urier = sport->old_urier; - uart->urlcr = sport->old_urlcr; - spin_unlock_irqrestore(&sport->port.lock, flags); - - if (sport) { - if (sport->port.irq != IRQ_UART0) - uart_resume_port(&wmt_reg, &sport->port); - - } - - return 0; -} -#if 1 -void print_dma_position(struct wmt_port *sport) -{ - unsigned int *rx_dma = (unsigned int *)(0xfe001904 + (0x20*sport->rx_dmach)); - printk("address 0x%p = 0x%x(value)\n",rx_dma,*rx_dma); -} - -void print_dma_buf_pointer(struct wmt_port *sport) -{ - printk("buf0:0x%p; buf1:0x%p; buf2:0x%p\n",sport->uart_dma_tmp_buf0,sport->uart_dma_tmp_buf1,sport->uart_dma_tmp_buf2); - printk("phy0:0x%x; phy1:0x%x; phy2:0x%x\n",sport->uart_dma_tmp_phy0,sport->uart_dma_tmp_phy1,sport->uart_dma_tmp_phy2); -} -void dump_uart_info(void) -{ - unsigned long flags; - struct wmt_port * p_wmt_port = &wmt_ports[1]; - uart_dump_reg(p_wmt_port); - printk("sport1->port.icount.rx0:0x%x,uart_tx_dma_phy0_org:0x%x\n",p_wmt_port->port.icount.rx,p_wmt_port->uart_tx_dma_phy0_org); - print_dma_position(p_wmt_port); - - //spin_lock_irqsave(&(p_wmt_port->port.lock), flags); - wmt_rx_chars(p_wmt_port,URISR_RXFAF | URISR_RXFF); - //spin_unlock_irqrestore(&(p_wmt_port->port.lock), flags); - - print_dma_position(p_wmt_port); - printk("sport1->port.icount.rx1:0x%x,uart_tx_dma_phy0_org:0x%x\n",p_wmt_port->port.icount.rx,p_wmt_port->uart_tx_dma_phy0_org); - printk("uart rxxx dma channel register:\n"); - wmt_dump_dma_regs(p_wmt_port->rx_dmach); - printk("uart tttx dma channel register:\n"); - wmt_dump_dma_regs(p_wmt_port->tx_dmach); - printk("buf pointer position\n"); - print_dma_buf_pointer(p_wmt_port); - printk("#######################################\n"); - dump_rx_dma_buf(p_wmt_port); -#ifdef UART_DEBUG - printk("##########################################\n"); - print_dma_count_cpu_buf_pos(p_wmt_port); -#endif - printk("#############debug dma tx failed begin#############\n"); - printk("sport->port.icount.tx:0x%x,sport->uart_tx_count:0x%x\n",p_wmt_port->port.icount.tx, - p_wmt_port->uart_tx_count); - printk("dma_tx_cnt:0x%x\n",p_wmt_port->dma_tx_cnt); - printk("uart_tx_dma_flag:0x%x\n",p_wmt_port->uart_tx_dma_flag); - printk("uart_tx_stopped:%d\n",uart_tx_stopped(&p_wmt_port->port)); - if(uart_tx_stopped(&p_wmt_port->port)) - { - printk("stopped:%d\n",(&p_wmt_port->port)->state->port.tty->stopped); - printk("hw_stopped:%d\n",(&p_wmt_port->port)->state->port.tty->hw_stopped); - } - printk("#############debug dma tx failed end#############\n"); - -} -EXPORT_SYMBOL(dump_uart_info); -#endif -static int wmt_serial_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct resource *res = pdev->resource; - int i; - - for (i = 0; i < pdev->num_resources; i++, res++) - if (res->flags & IORESOURCE_MEM) - break; - - if (i < pdev->num_resources) { - for (i = 0; i < NR_PORTS; i++) { - if (wmt_ports[i].port.mapbase != res->start) - continue; - - wmt_ports[i].port.dev = dev; - uart_add_one_port(&wmt_reg, &wmt_ports[i].port); - dev_set_drvdata(dev, &wmt_ports[i]); - if (i >= 1) { - wmt_ports[i].uart_rx_dma_buf0_org = - dma_alloc_coherent(NULL, - UART_BUFFER_SIZE, - &wmt_ports[i].uart_rx_dma_phy0_org, - GFP_KERNEL); - wmt_ports[i].uart_rx_dma_buf1_org = - dma_alloc_coherent(NULL, - UART_BUFFER_SIZE, - &wmt_ports[i].uart_rx_dma_phy1_org, - GFP_KERNEL); - wmt_ports[i].uart_rx_dma_buf2_org = - dma_alloc_coherent(NULL, - UART_BUFFER_SIZE, - &wmt_ports[i].uart_rx_dma_phy2_org, - GFP_KERNEL); - wmt_ports[i].uart_tx_dma_buf0_org = - dma_alloc_coherent(NULL, - UART_BUFFER_SIZE, - &wmt_ports[i].uart_tx_dma_phy0_org, - GFP_KERNEL); - } - break; - } - } - return 0; -} - -static int wmt_serial_remove(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct wmt_port *sport = dev_get_drvdata(dev); - - dev_set_drvdata(dev, NULL); - - if (sport) - uart_remove_one_port(&wmt_reg, &sport->port); - - return 0; -} - -static struct platform_driver wmt_serial_driver = { - .driver.name = "uart", - .probe = wmt_serial_probe, - .remove = wmt_serial_remove, - .suspend = wmt_serial_suspend, - .resume = wmt_serial_resume, -}; - -static int __init wmt_serial_init(void) -{ - int ret; - - wmt_init_ports(); - ret = uart_register_driver(&wmt_reg); - - if (ret == 0) { - ret = platform_driver_register(&wmt_serial_driver); - if (ret) - uart_unregister_driver(&wmt_reg); - } -#ifndef CONFIG_SKIP_DRIVER_MSG - printk(KERN_INFO "WMT Serial driver initialized: %s\n", - (ret == 0) ? "ok" : "failed"); -#endif - return ret; -} - -static void __exit wmt_serial_exit(void) -{ - platform_driver_unregister(&wmt_serial_driver); - uart_unregister_driver(&wmt_reg); -} - -module_init(wmt_serial_init); -module_exit(wmt_serial_exit); - -MODULE_AUTHOR("WonderMedia Technologies, Inc."); -MODULE_DESCRIPTION("WMT [generic serial port] driver"); -MODULE_LICENSE("GPL"); |