* Date: 2011.06.18\r
*/\r
\r
-#ifndef CONFIG_SERIAL_RK_CONSOLE\r
-#if defined(CONFIG_SERIAL_RK29_CONSOLE)\r
-#define CONFIG_SERIAL_RK_CONSOLE\r
-#endif\r
-#endif\r
-\r
-#if defined(CONFIG_SERIAL_RK_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)\r
+#if defined(CONFIG_SERIAL_ROCKCHIP_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)\r
#define SUPPORT_SYSRQ\r
#endif\r
\r
-//#define DEBUG\r
#include <linux/module.h>\r
#include <linux/ioport.h>\r
#include <linux/init.h>\r
#include <linux/serial_reg.h>\r
#include <linux/serial_core.h>\r
#include <linux/serial.h>\r
-#include <linux/serial_8250.h>\r
#include <linux/nmi.h>\r
#include <linux/mutex.h>\r
#include <linux/slab.h>\r
#include <linux/timer.h>\r
#include <linux/workqueue.h>\r
#include <linux/dma-mapping.h>\r
-\r
#include <asm/io.h>\r
#include <asm/irq.h>\r
\r
+#include <linux/dmaengine.h>\r
+\r
+#ifdef CONFIG_OF\r
+#include <linux/of.h>\r
+#endif\r
+\r
+\r
+/*\r
+* Driver Version Note\r
+*\r
+*v0.0 : this driver is 2.6.32 kernel driver;\r
+*v0.1 : this driver is 3.0.8 kernel driver;\r
+*v1.0 : 2012-08-09\r
+* 1.modify dma dirver;\r
+* 2.enable Programmable THRE Interrupt Mode, so we can just judge ((up->iir & 0x0f) == 0x02) when transmit\r
+* 3.reset uart and set it to loopback state to ensure setting baud rate sucessfully \r
+*v1.1 : 2012-08-23\r
+* 1. dma driver:make "when tx dma is only enable" work functionally \r
+*v1.2 : 2012-08-28\r
+* 1. dma driver:serial rx use new dma interface rk29_dma_enqueue_ring \r
+*v1.3 : 2012-12-14\r
+* 1. When enable Programmable THRE Interrupt Mode, in lsr register, only UART_LSR_TEMT means transmit empty, but\r
+ UART_LSR_THRE doesn't. So, the macro BOTH_EMPTY should be replaced with UART_LSR_TEMT.\r
+*v1.4 : 2013-04-16\r
+* 1.fix bug dma buffer free error\r
+*v1.5 : 2013-10-17\r
+* 1.in some case, set uart rx as gpio interrupt to wake up arm, when arm suspends \r
+*v1.6 : 2013-11-29\r
+ migrate to kernel3.10,and fit device tree\r
+*v1.7 : 2014-03-03\r
+ DMA use new interfaces, and use some interfaces with devm_ prefix \r
+*v1.8 : 2014-03-04\r
+* 1.clear receive time out interrupt request in irq handler \r
+*/\r
+#define VERSION_AND_TIME "rk_serial.c v1.8 2014-03-04"\r
\r
#define PORT_RK 90\r
#define UART_USR 0x1F /* UART Status Register */\r
+#define UART_USR_TX_FIFO_EMPTY 0x04 /* Transmit FIFO empty */\r
+#define UART_USR_TX_FIFO_NOT_FULL 0x02 /* Transmit FIFO not full */\r
#define UART_USR_BUSY (1)\r
#define UART_IER_PTIME 0x80 /* Programmable THRE Interrupt Mode Enable */\r
#define UART_LSR_RFE 0x80 /* receive fifo error */\r
#define UART_SRR 0x22 /* software reset register */\r
+#define UART_SFE 0x26 /* Shadow FIFO Enable */\r
#define UART_RESET 0x01\r
-#define RX_TIMEOUT (3000*10) //uint ms\r
\r
-#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)\r
\r
-#define UART_NR 4 //uart port number\r
-#define POWER_MANEGEMENT 1\r
+//#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)\r
+#define UART_NR 5 //uart port number\r
\r
-/* configurate whether the port transmit-receive by DMA */\r
+\r
+/* configurate whether the port transmit-receive by DMA in menuconfig*/\r
#define OPEN_DMA 1\r
#define CLOSE_DMA 0\r
\r
-#ifdef CONFIG_UART0_DMA_RK29\r
-#define UART0_USE_DMA OPEN_DMA\r
+#define TX_DMA (1)\r
+#define RX_DMA (2)\r
+#define DMA_SERIAL_BUFFER_SIZE (UART_XMIT_SIZE*2)\r
+#define CONFIG_CLOCK_CTRL 1\r
+//serial wake up \r
+#ifdef CONFIG_UART0_WAKEUP_RK29 \r
+#define UART0_USE_WAKEUP CONFIG_UART0_WAKEUP_RK29\r
#else\r
-#define UART0_USE_DMA CLOSE_DMA\r
+#define UART0_USE_WAKEUP 0\r
#endif\r
-\r
-#ifdef CONFIG_UART2_DMA_RK29\r
-#define UART2_USE_DMA OPEN_DMA\r
+#ifdef CONFIG_UART1_WAKEUP_RK29\r
+#define UART1_USE_WAKEUP CONFIG_UART1_WAKEUP_RK29\r
#else\r
-#define UART2_USE_DMA CLOSE_DMA\r
+#define UART1_USE_WAKEUP 0\r
#endif\r
-\r
-#ifdef CONFIG_UART3_DMA_RK29\r
-#define UART3_USE_DMA OPEN_DMA\r
+#ifdef CONFIG_UART2_WAKEUP_RK29\r
+#define UART2_USE_WAKEUP CONFIG_UART2_WAKEUP_RK29\r
#else\r
-#define UART3_USE_DMA CLOSE_DMA\r
+#define UART2_USE_WAKEUP 0\r
#endif\r
-\r
-#define UART1_USE_DMA CLOSE_DMA\r
-\r
-#define USE_DMA (UART0_USE_DMA | UART1_USE_DMA | UART2_USE_DMA | UART3_USE_DMA)\r
-#if USE_DMA\r
-#ifdef CONFIG_ARCH_RK29\r
-#include <mach/dma-pl330.h>\r
+#ifdef CONFIG_UART3_WAKEUP_RK29\r
+#define UART3_USE_WAKEUP CONFIG_UART3_WAKEUP_RK29\r
#else\r
-#include <plat/dma-pl330.h>\r
+#define UART3_USE_WAKEUP 0\r
#endif\r
+\r
+#define USE_TIMER 1 // use timer for dma transport\r
+#define POWER_MANEGEMENT 1\r
+#define RX_TIMEOUT (3000*3) //uint ms\r
+#define DMA_TX_TRRIGE_LEVEL 128\r
+#define SERIAL_CIRC_CNT_TO_END(xmit) CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE)\r
+\r
+#define USE_DMA OPEN_DMA\r
+\r
+#define USE_WAKEUP (UART0_USE_WAKEUP | UART1_USE_WAKEUP | UART2_USE_WAKEUP | UART3_USE_WAKEUP)\r
+\r
+#if USE_WAKEUP\r
+#include <mach/iomux.h>\r
+#include <linux/wakelock.h>\r
#endif\r
\r
-#define DMA_TX_TRRIGE_LEVEL 30\r
\r
-#define USE_TIMER 1 // use timer for dma transport\r
-#define THRE_MODE 0X00 //0yhh\r
\r
static struct uart_driver serial_rk_reg;\r
\r
/*\r
* Debugging.\r
*/\r
+#ifdef CONFIG_ARCH_RK29\r
#define DBG_PORT 1 //DBG_PORT which uart is used to print log message\r
+#else\r
+#ifndef CONFIG_RK_DEBUG_UART //DBG_PORT which uart is used to print log message\r
+#define DBG_PORT 2\r
+#else\r
+#define DBG_PORT CONFIG_RK_DEBUG_UART\r
+#endif\r
+#endif\r
\r
#ifdef CONFIG_SERIAL_CORE_CONSOLE\r
#define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line)\r
#define uart_console(port) (0)\r
#endif\r
\r
-#define DEBUG 0\r
\r
extern void printascii(const char *);\r
static void dbg(const char *fmt, ...)\r
vsprintf(buff, fmt, va);\r
va_end(va);\r
\r
+#if defined(CONFIG_DEBUG_LL) || defined(CONFIG_RK_EARLY_PRINTK)\r
printascii(buff);\r
+#endif\r
}\r
\r
+//enable log output\r
+#define DEBUG 0\r
+static int log_port = -1;\r
+module_param(log_port, int, S_IRUGO|S_IWUSR);\r
+\r
#if DEBUG\r
-#define DEBUG_INTR(fmt...) if (!uart_console(&up->port)) dbg(fmt)\r
+#define DEBUG_INTR(fmt...) if (up->port.line == log_port && !uart_console(&up->port)) dbg(fmt)\r
#else\r
#define DEBUG_INTR(fmt...) do { } while (0)\r
#endif\r
#if USE_DMA\r
/* added by hhb@rock-chips.com for uart dma transfer */\r
\r
-struct rk29_uart_dma_t {\r
+struct rk_uart_dma {\r
u32 use_dma; //1:used\r
- u32 rx_dma_start;\r
- enum dma_ch rx_dmach;\r
- enum dma_ch tx_dmach;\r
- u32 tx_dma_inited;\r
- u32 rx_dma_inited;\r
- spinlock_t tx_lock;\r
- spinlock_t rx_lock;\r
- char * rx_buffer;\r
+ //enum dma_ch rx_dmach;\r
+ //enum dma_ch tx_dmach;\r
+\r
+ //receive and transfer buffer\r
+ char * rx_buffer; //visual memory\r
char * tx_buffer;\r
- dma_addr_t rx_phy_addr;\r
+ dma_addr_t rx_phy_addr; //physical memory\r
dma_addr_t tx_phy_addr;\r
- u32 rx_buffer_size;\r
- u32 tx_buffer_size;\r
+ u32 rb_size; //buffer size\r
+ u32 tb_size;\r
\r
- u32 rb_cur_pos;\r
- u32 rb_pre_pos;\r
+ //regard the rx buffer as a circular buffer\r
+ u32 rb_head;\r
+ u32 rb_tail;\r
u32 rx_size;\r
- char use_timer;\r
- char tx_dma_used;\r
+\r
+ spinlock_t tx_lock;\r
+ spinlock_t rx_lock;\r
+\r
+ char tx_dma_inited; //1:dma tx channel has been init\r
+ char rx_dma_inited; //1:dma rx channel has been init\r
+ char tx_dma_used; //1:dma tx is working\r
+ char rx_dma_used; //1:dma rx is working\r
+\r
/* timer to poll activity on rx dma */\r
- struct timer_list rx_timer;\r
- int rx_timeout;\r
+ char use_timer;\r
+ int rx_timeout;\r
+ struct timer_list rx_timer;\r
+\r
+ struct dma_chan *dma_chan_rx, *dma_chan_tx;\r
+ struct scatterlist rx_sgl, tx_sgl;\r
+ unsigned int rx_bytes, tx_bytes;\r
+};\r
+#endif\r
\r
+#if USE_WAKEUP \r
+struct uart_wake_up {\r
+ unsigned int enable;\r
+ unsigned int rx_mode;\r
+ unsigned int tx_mode;\r
+ unsigned int rx_pin;\r
+ char rx_pin_name[32];\r
+ unsigned int tx_pin;\r
+ unsigned int rx_irq;\r
+ char rx_irq_name[32];\r
+ struct wake_lock wakelock;\r
+ char wakelock_name[32];\r
};\r
#endif\r
\r
+#ifdef CONFIG_OF\r
+struct of_rk_serial {\r
+ unsigned int id;\r
+ unsigned int use_dma; \r
+ unsigned int uartclk;\r
+};\r
+#endif\r
+\r
+\r
struct uart_rk_port {\r
struct uart_port port;\r
struct platform_device *pdev;\r
unsigned char msr_saved_flags;\r
#endif\r
\r
- char name[12];\r
- char fifo[32];\r
+ char name[16];\r
+ char fifo[64];\r
char fifo_size;\r
unsigned long port_activity;\r
struct work_struct uart_work;\r
struct work_struct uart_work_rx;\r
struct workqueue_struct *uart_wq;\r
-#if USE_DMA\r
- struct rk29_uart_dma_t *prk29_uart_dma_t;\r
+ struct rk_uart_dma *dma;\r
+#if USE_WAKEUP\r
+ struct uart_wake_up *wakeup;\r
#endif\r
};\r
\r
#if USE_DMA\r
-static void serial_rk_release_dma_tx(struct uart_port *port);\r
-static int serial_rk_start_tx_dma(struct uart_port *port);\r
-static void serial_rk_rx_timeout(unsigned long uart);\r
-static void serial_rk_release_dma_rx(struct uart_port *port);\r
-static int serial_rk_start_rx_dma(struct uart_port *port);\r
+static void serial_rk_release_dma_tx(struct uart_rk_port *up);\r
+static int serial_rk_start_dma_tx(struct uart_rk_port *up);\r
+//static void serial_rk_rx_timeout(unsigned long uart);\r
+static void serial_rk_release_dma_rx(struct uart_rk_port *up);\r
+static int serial_rk_start_dma_rx(struct uart_rk_port *up);\r
+static void serial_rk_stop_dma_tx(struct uart_rk_port *up);\r
+static void serial_rk_stop_dma_rx(struct uart_rk_port *up);\r
+\r
#else\r
static inline int serial_rk_start_tx_dma(struct uart_port *port) { return 0; }\r
#endif\r
static int serial_rk_startup(struct uart_port *port);\r
+\r
static inline unsigned int serial_in(struct uart_rk_port *up, int offset)\r
{\r
offset = offset << 2;\r
- return __raw_readb(up->port.membase + offset);\r
+\r
+ return __raw_readl(up->port.membase + offset);\r
}\r
\r
/* Save the LCR value so it can be re-written when a Busy Detect IRQ occurs. */\r
static inline void serial_out(struct uart_rk_port *up, int offset, unsigned char value)\r
{\r
dwapb_save_out_value(up, offset, value);\r
- __raw_writeb(value, up->port.membase + (offset << 2));\r
+ __raw_writel(value, up->port.membase + (offset << 2));\r
if (offset != UART_TX)\r
- dsb();\r
+ dsb(sy);\r
dwapb_check_clear_ier(up, offset);\r
}\r
\r
static int serial_dl_write(struct uart_rk_port *up, unsigned int value)\r
{\r
unsigned int tmout = 100;\r
- if(up->port.line != DBG_PORT)\r
- {\r
- while(!(serial_in(up, UART_LCR) & UART_LCR_DLAB)){\r
- if (--tmout == 0){\r
+\r
+ while(!(serial_in(up, UART_LCR) & UART_LCR_DLAB)){\r
+ if (--tmout == 0){\r
+ if(up->port.line != DBG_PORT)\r
dbg("set serial.%d baudrate fail with DLAB not set\n", up->port.line);\r
- return -1;\r
- }\r
+ return -1;\r
}\r
+ }\r
\r
- tmout = 15000;\r
- while(serial_in(up, UART_USR) & UART_USR_BUSY){\r
- if (--tmout == 0){\r
+ tmout = 15000;\r
+ while(serial_in(up, UART_USR) & UART_USR_BUSY){\r
+ if (--tmout == 0){\r
+ if(up->port.line != DBG_PORT)\r
dbg("set serial.%d baudrate timeout\n", up->port.line);\r
- return -1;\r
- }\r
+ return -1;\r
}\r
+ udelay(1);\r
}\r
\r
serial_out(up, UART_DLL, value & 0xff);\r
{\r
unsigned int tmout = 15000;\r
\r
- if(up->port.line != DBG_PORT)\r
- {\r
- while(serial_in(up, UART_USR) & UART_USR_BUSY){\r
-\r
- if (--tmout == 0){\r
+ while(serial_in(up, UART_USR) & UART_USR_BUSY){\r
+ if (--tmout == 0){\r
+ if(up->port.line != DBG_PORT)\r
dbg("set serial.%d lc r = 0x%02x timeout\n", up->port.line, value);\r
- return -1;\r
- }\r
- udelay(1);\r
+ return -1;\r
}\r
+ udelay(1);\r
}\r
\r
serial_out(up, UART_LCR, value);\r
serial_out(up, UART_IER, up->ier);\r
}\r
}\r
-#if 0\r
+\r
static int rk29_uart_dump_register(struct uart_rk_port *up){\r
\r
unsigned int reg_value = 0;\r
return 0;\r
\r
}\r
-#endif\r
\r
/*\r
* FIFO support.\r
struct uart_rk_port *up =\r
container_of(port, struct uart_rk_port, port);\r
#if USE_DMA\r
- struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t;\r
-\r
- if(OPEN_DMA == prk29_uart_dma_t->use_dma){\r
- serial_rk_release_dma_tx(port);\r
+ struct rk_uart_dma *uart_dma = up->dma;\r
+ if(uart_dma->use_dma & TX_DMA){\r
+ serial_rk_stop_dma_tx(up);\r
}\r
#endif\r
__stop_tx(up);\r
struct uart_rk_port *up =\r
container_of(port, struct uart_rk_port, port);\r
\r
-\r
- if(0 == serial_rk_start_tx_dma(port)){\r
+#if USE_DMA\r
+ if(up->dma->use_dma & TX_DMA) {\r
+ if(!up->dma->tx_dma_used)\r
+ serial_rk_enable_ier_thri(up);\r
+ }else {\r
serial_rk_enable_ier_thri(up);\r
}\r
-\r
+#else\r
+ serial_rk_enable_ier_thri(up);\r
+#endif\r
}\r
\r
\r
struct uart_rk_port *up =\r
container_of(port, struct uart_rk_port, port);\r
#if USE_DMA\r
- struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t;\r
-\r
- if(OPEN_DMA == prk29_uart_dma_t->use_dma){\r
- serial_rk_release_dma_rx(port);\r
+ struct rk_uart_dma *uart_dma = up->dma;\r
+ if(uart_dma->use_dma & RX_DMA){\r
+ serial_rk_stop_dma_rx(up);\r
}\r
#endif\r
up->ier &= ~UART_IER_RLSI;\r
#endif\r
}\r
\r
-\r
-#if USE_DMA\r
-/*\r
- * Start transmitting by dma.\r
- */\r
-#define DMA_SERIAL_BUFFER_SIZE UART_XMIT_SIZE\r
-\r
-/* added by hhb@rock-chips.com for uart dma transfer*/\r
-static struct rk29_uart_dma_t rk29_uart_ports_dma_t[] = {\r
- {UART0_USE_DMA, 0, DMACH_UART0_RX, DMACH_UART0_TX},\r
- {UART1_USE_DMA, 0, DMACH_UART1_RX, DMACH_UART1_TX},\r
- {UART2_USE_DMA, 0, DMACH_UART2_RX, DMACH_UART2_TX},\r
- {UART3_USE_DMA, 0, DMACH_UART3_RX, DMACH_UART3_TX},\r
+#if USE_WAKEUP\r
+static struct uart_wake_up rk29_uart_ports_wakeup[] = {\r
+ {UART0_USE_WAKEUP, UART0_SIN, UART0_SOUT},\r
+ {UART1_USE_WAKEUP, UART1_SIN, UART1_SOUT},\r
+ {UART2_USE_WAKEUP, UART2_SIN, UART2_SOUT},\r
+ {UART3_USE_WAKEUP, UART3_SIN, UART3_SOUT},\r
};\r
+#endif\r
\r
-\r
+#if USE_DMA\r
/* DMAC PL330 add by hhb@rock-chips.com */\r
-static struct rk29_dma_client rk29_uart_dma_client = {\r
- .name = "rk29xx-uart-dma",\r
-};\r
-\r
-/*TX*/\r
\r
-static void serial_rk_release_dma_tx(struct uart_port *port)\r
+static void serial_rk_stop_dma_tx(struct uart_rk_port *up)\r
{\r
- struct uart_rk_port *up =\r
- container_of(port, struct uart_rk_port, port);\r
- struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t;\r
- if(!port){\r
- return;\r
+ struct rk_uart_dma *uart_dma = up->dma;\r
+ \r
+ if(uart_dma && uart_dma->tx_dma_used) {\r
+ dmaengine_terminate_all(uart_dma->dma_chan_tx);\r
+ uart_dma->tx_dma_used = 0;\r
}\r
- if(prk29_uart_dma_t && prk29_uart_dma_t->tx_dma_inited) {\r
- rk29_dma_free(prk29_uart_dma_t->tx_dmach, &rk29_uart_dma_client);\r
- prk29_uart_dma_t->tx_dma_inited = 0;\r
+}\r
+\r
+static void serial_rk_release_dma_tx(struct uart_rk_port *up)\r
+{\r
+ struct rk_uart_dma *uart_dma = up->dma;\r
+\r
+ if(uart_dma && uart_dma->tx_dma_inited) {\r
+ serial_rk_stop_dma_tx(up);\r
+ dma_release_channel(uart_dma->dma_chan_tx);\r
+ uart_dma->dma_chan_tx = NULL;\r
+ uart_dma->tx_dma_inited = 0;\r
}\r
}\r
\r
-/*this function will be called every time after rk29_dma_enqueue() be invoked*/\r
-static void serial_rk_dma_txcb(void *buf, int size, enum rk29_dma_buffresult result) {\r
- struct uart_port *port = buf;\r
+static void dma_tx_callback(void *data)\r
+{\r
+ struct uart_port *port = data;\r
struct uart_rk_port *up = container_of(port, struct uart_rk_port, port);\r
struct circ_buf *xmit = &port->state->xmit;\r
+ struct rk_uart_dma *uart_dma = up->dma;\r
+ struct scatterlist *sgl = &uart_dma->tx_sgl;\r
\r
- if(result != RK29_RES_OK){\r
- return;\r
- }\r
-\r
- port->icount.tx += size;\r
- xmit->tail = (xmit->tail + size) & (UART_XMIT_SIZE - 1);\r
+ dma_unmap_sg(up->port.dev, sgl, 1, DMA_TO_DEVICE);\r
\r
+ xmit->tail = (xmit->tail + uart_dma->tx_bytes) & (UART_XMIT_SIZE - 1);\r
+ port->icount.tx += uart_dma->tx_bytes;\r
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)\r
- uart_write_wakeup(&up->port);\r
- spin_lock(&(up->prk29_uart_dma_t->tx_lock));\r
- up->prk29_uart_dma_t->tx_dma_used = 0;\r
- spin_unlock(&(up->prk29_uart_dma_t->tx_lock));\r
- if (!uart_circ_empty(xmit)) {\r
- serial_rk_start_tx_dma(port);\r
- }\r
+ uart_write_wakeup(port);\r
\r
+ //spin_lock(&(up->dma->tx_lock));\r
+ uart_dma->tx_dma_used = 0;\r
+ //spin_unlock(&(up->dma->tx_lock));\r
+ serial_rk_enable_ier_thri(up);\r
up->port_activity = jiffies;\r
// dev_info(up->port.dev, "s:%d\n", size);\r
+\r
}\r
+static int serial_rk_init_dma_tx(struct uart_rk_port *up) {\r
\r
-static int serial_rk_init_dma_tx(struct uart_port *port) {\r
+ struct dma_slave_config slave_config;\r
+ struct uart_port *port = &up->port;\r
+ struct rk_uart_dma *uart_dma = up->dma;\r
+ int ret;\r
\r
- struct uart_rk_port *up =\r
- container_of(port, struct uart_rk_port, port);\r
- struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t;\r
- if(!port || !prk29_uart_dma_t){\r
+ if(!uart_dma){\r
dev_info(up->port.dev, "serial_rk_init_dma_tx fail\n");\r
return -1;\r
}\r
\r
- if(prk29_uart_dma_t->tx_dma_inited) {\r
+ if(uart_dma->tx_dma_inited) {\r
return 0;\r
}\r
\r
- if (rk29_dma_request(prk29_uart_dma_t->tx_dmach, &rk29_uart_dma_client, NULL) == -EBUSY) {\r
- dev_info(up->port.dev, "rk29_dma_request tx fail\n");\r
- return -1;\r
+ uart_dma->dma_chan_tx = dma_request_slave_channel(port->dev, "tx");\r
+ if (!uart_dma->dma_chan_tx) {\r
+ dev_err(port->dev, "cannot get the TX DMA channel!\n");\r
+ ret = -EINVAL;\r
}\r
\r
- if (rk29_dma_set_buffdone_fn(prk29_uart_dma_t->tx_dmach, serial_rk_dma_txcb)) {\r
- dev_info(up->port.dev, "rk29_dma_set_buffdone_fn tx fail\n");\r
- return -1;\r
- }\r
- if (rk29_dma_devconfig(prk29_uart_dma_t->tx_dmach, RK29_DMASRC_MEM, (unsigned long)(port->iobase + UART_TX))) {\r
- dev_info(up->port.dev, "rk29_dma_devconfig tx fail\n");\r
- return -1;\r
- }\r
- if (rk29_dma_config(prk29_uart_dma_t->tx_dmach, 1, 1)) {\r
- dev_info(up->port.dev, "rk29_dma_config tx fail\n");\r
- return -1;\r
+ slave_config.direction = DMA_MEM_TO_DEV; \r
+ slave_config.dst_addr = port->mapbase + UART_TX; \r
+ slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; \r
+ slave_config.dst_maxburst = 16;\r
+ ret = dmaengine_slave_config(uart_dma->dma_chan_tx, &slave_config); \r
+ if (ret) {\r
+ dev_err(port->dev, "error in TX dma configuration."); \r
+ return ret;\r
}\r
\r
- prk29_uart_dma_t->tx_dma_inited = 1;\r
- dev_info(up->port.dev, "serial_rk_init_dma_tx sucess\n");\r
+ uart_dma->tx_dma_inited = 1;\r
+ dev_info(port->dev, "serial_rk_init_dma_tx sucess\n");\r
return 0;\r
-\r
}\r
\r
-static int serial_rk_start_tx_dma(struct uart_port *port)\r
+static int serial_rk_start_dma_tx(struct uart_rk_port *up)\r
{\r
-\r
+ int count = 0;\r
+ struct uart_port *port = &up->port;\r
struct circ_buf *xmit = &port->state->xmit;\r
- struct uart_rk_port *up = container_of(port, struct uart_rk_port, port);\r
- struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t;\r
+ struct rk_uart_dma *uart_dma = up->dma;\r
+ struct scatterlist *sgl = &uart_dma->tx_sgl;\r
+ struct dma_async_tx_descriptor *desc;\r
+ int ret;\r
\r
- if(0 == prk29_uart_dma_t->use_dma){\r
- return CLOSE_DMA;\r
- }\r
+ if(!uart_dma->use_dma)\r
+ goto err_out;\r
\r
- if(-1 == serial_rk_init_dma_tx(port)){\r
+ if(-1 == serial_rk_init_dma_tx(up))\r
goto err_out;\r
- }\r
\r
- if (1 == prk29_uart_dma_t->tx_dma_used){\r
+ if (1 == uart_dma->tx_dma_used)\r
return 1;\r
- }\r
- if(!uart_circ_empty(xmit)){\r
- if (rk29_dma_enqueue(prk29_uart_dma_t->tx_dmach, port,\r
- prk29_uart_dma_t->tx_phy_addr + xmit->tail,\r
- CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE))) {\r
- goto err_out;\r
- }\r
- }\r
- rk29_dma_ctrl(prk29_uart_dma_t->tx_dmach, RK29_DMAOP_START);\r
- spin_lock(&(prk29_uart_dma_t->tx_lock));\r
- up->prk29_uart_dma_t->tx_dma_used = 1;\r
- spin_unlock(&(prk29_uart_dma_t->tx_lock));\r
\r
+// spin_lock(&(uart_dma->tx_lock));\r
+ __stop_tx(up);\r
+\r
+ count = SERIAL_CIRC_CNT_TO_END(xmit);\r
+ count -= count%16;\r
+ if(count >= DMA_TX_TRRIGE_LEVEL) {\r
+ uart_dma->tx_bytes = count;\r
+ sg_init_one(sgl, uart_dma->tx_buffer + xmit->tail, count);\r
+ ret = dma_map_sg(port->dev, sgl, 1, DMA_TO_DEVICE);\r
+ \r
+ if (ret == 0) {\r
+ dev_err(port->dev, "DMA mapping error for TX.\n"); \r
+ return -1;\r
+ } \r
+ desc = dmaengine_prep_slave_sg(uart_dma->dma_chan_tx, sgl, 1,\r
+ DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT); \r
+\r
+ if (!desc) {\r
+ dev_err(port->dev, "We cannot prepare for the TX slave dma!\n"); \r
+ return -1; \r
+ } \r
+ desc->callback = dma_tx_callback; \r
+ desc->callback_param = port; \r
+ dmaengine_submit(desc);\r
+ dma_async_issue_pending(uart_dma->dma_chan_tx);\r
+ uart_dma->tx_dma_used = 1;\r
+ }\r
+// spin_unlock(&(uart_dma->tx_lock));\r
return 1;\r
err_out:\r
- dev_info(up->port.dev, "-serial_rk_start_tx_dma-error-\n");\r
+ dev_info(up->port.dev, "-serial_rk_start_dma_tx-error-\n");\r
return -1;\r
-\r
}\r
\r
\r
\r
/*RX*/\r
+#if 0\r
static void serial_rk_dma_rxcb(void *buf, int size, enum rk29_dma_buffresult result) {\r
\r
-\r
+ //printk(">>%s:%d\n", __func__, result);\r
}\r
+#endif\r
\r
-static void serial_rk_release_dma_rx(struct uart_port *port)\r
+static void serial_rk_stop_dma_rx(struct uart_rk_port *up)\r
{\r
- struct uart_rk_port *up =\r
- container_of(port, struct uart_rk_port, port);\r
- struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t;\r
- if(!port){\r
- return;\r
+ struct rk_uart_dma *uart_dma = up->dma;\r
+ \r
+ if(uart_dma && uart_dma->rx_dma_used) {\r
+ del_timer(&uart_dma->rx_timer);\r
+ dmaengine_terminate_all(uart_dma->dma_chan_rx); \r
+ uart_dma->rb_tail = 0;\r
+ uart_dma->rx_dma_used = 0;\r
}\r
- if(prk29_uart_dma_t && prk29_uart_dma_t->rx_dma_inited) {\r
- del_timer(&prk29_uart_dma_t->rx_timer);\r
- rk29_dma_free(prk29_uart_dma_t->rx_dmach, &rk29_uart_dma_client);\r
- prk29_uart_dma_t->rb_pre_pos = 0;\r
- prk29_uart_dma_t->rx_dma_inited = 0;\r
- prk29_uart_dma_t->rx_dma_start = 0;\r
+}\r
+\r
+\r
+static void serial_rk_release_dma_rx(struct uart_rk_port *up)\r
+{\r
+ struct rk_uart_dma *uart_dma = up->dma;\r
+ \r
+ if(uart_dma && uart_dma->rx_dma_inited) {\r
+ serial_rk_stop_dma_rx(up);\r
+ dma_release_channel(uart_dma->dma_chan_rx);\r
+ uart_dma->dma_chan_rx = NULL; \r
+ uart_dma->rx_dma_inited = 0;\r
}\r
}\r
\r
\r
-static int serial_rk_init_dma_rx(struct uart_port *port) {\r
+static int serial_rk_init_dma_rx(struct uart_rk_port *up) \r
+{\r
+ int ret;\r
+ struct uart_port *port = &up->port;\r
+ struct dma_slave_config slave_config;\r
+ struct rk_uart_dma *uart_dma = up->dma;\r
\r
- struct uart_rk_port *up =\r
- container_of(port, struct uart_rk_port, port);\r
- struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t;\r
- if(!port || !prk29_uart_dma_t){\r
- dev_info(up->port.dev, "serial_rk_init_dma_rx: port fail\n");\r
+ if(!uart_dma) {\r
+ dev_info(port->dev, "serial_rk_init_dma_rx: port fail\n");\r
return -1;\r
}\r
- if(prk29_uart_dma_t->rx_dma_inited) {\r
- return 0;\r
- }\r
\r
- if (rk29_dma_request(prk29_uart_dma_t->rx_dmach, &rk29_uart_dma_client, NULL) == -EBUSY) {\r
- dev_info(up->port.dev, "rk29_dma_request fail rx \n");\r
- return -1;\r
+ if(uart_dma->rx_dma_inited) {\r
+ return 0;\r
}\r
\r
- if (rk29_dma_set_buffdone_fn(prk29_uart_dma_t->rx_dmach, serial_rk_dma_rxcb)) {\r
- dev_info(up->port.dev, "rk29_dma_set_buffdone_fn rx fail\n");\r
- return -1;\r
- }\r
- if (rk29_dma_devconfig(prk29_uart_dma_t->rx_dmach, RK29_DMASRC_HW, (unsigned long)(port->iobase + UART_RX))) {\r
- dev_info(up->port.dev, "rk29_dma_devconfig rx fail\n");\r
+ uart_dma->dma_chan_rx = dma_request_slave_channel(port->dev, "rx");\r
+ if (!uart_dma->dma_chan_rx) {\r
+ dev_err(port->dev, "cannot get the DMA channel.\n");\r
return -1;\r
}\r
\r
- if (rk29_dma_config(prk29_uart_dma_t->rx_dmach, 1, 1)) {\r
- dev_info(up->port.dev, "rk29_dma_config rx fail\n");\r
- return -1;\r
+ slave_config.direction = DMA_DEV_TO_MEM; \r
+ slave_config.src_addr = port->mapbase + UART_RX; \r
+ slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; \r
+ slave_config.src_maxburst = 1;\r
+ ret = dmaengine_slave_config(uart_dma->dma_chan_rx, &slave_config); \r
+ if (ret) {\r
+ dev_err(port->dev, "error in RX dma configuration.\n"); \r
+ return ret; \r
}\r
\r
- rk29_dma_setflags(prk29_uart_dma_t->rx_dmach, RK29_DMAF_CIRCULAR);\r
-\r
- prk29_uart_dma_t->rx_dma_inited = 1;\r
- dev_info(up->port.dev, "serial_rk_init_dma_rx sucess\n");\r
+ uart_dma->rx_dma_inited = 1;\r
+ dev_info(port->dev, "serial_rk_init_dma_rx sucess\n");\r
return 0;\r
-\r
}\r
\r
-static int serial_rk_start_rx_dma(struct uart_port *port)\r
+static int serial_rk_start_dma_rx(struct uart_rk_port *up)\r
{\r
- struct uart_rk_port *up =\r
- container_of(port, struct uart_rk_port, port);\r
- struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t;\r
- if(0 == prk29_uart_dma_t->use_dma){\r
+ struct uart_port *port = &up->port;\r
+ struct rk_uart_dma *uart_dma = up->dma; \r
+ struct dma_async_tx_descriptor *desc; \r
+ \r
+ if(!uart_dma->use_dma)\r
return 0;\r
- }\r
\r
- if(prk29_uart_dma_t->rx_dma_start == 1){\r
+ if(uart_dma->rx_dma_used == 1)\r
return 0;\r
- }\r
\r
- if(-1 == serial_rk_init_dma_rx(port)){\r
+ if(-1 == serial_rk_init_dma_rx(up)){\r
dev_info(up->port.dev, "*******serial_rk_init_dma_rx*******error*******\n");\r
return -1;\r
}\r
+ desc = dmaengine_prep_dma_cyclic(uart_dma->dma_chan_rx, uart_dma->rx_phy_addr, uart_dma->rb_size, uart_dma->rb_size/2,DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); \r
\r
- if (rk29_dma_enqueue(prk29_uart_dma_t->rx_dmach, (void *)up, prk29_uart_dma_t->rx_phy_addr,\r
- prk29_uart_dma_t->rx_buffer_size/2)) {\r
- dev_info(up->port.dev, "*******rk29_dma_enqueue fail*****\n");\r
- return -1;\r
+ if (!desc) {\r
+ dev_err(port->dev, "We cannot prepare for the RX slave dma!\n"); \r
+ return -EINVAL; \r
}\r
\r
- if (rk29_dma_enqueue(prk29_uart_dma_t->rx_dmach, (void *)up,\r
- prk29_uart_dma_t->rx_phy_addr+prk29_uart_dma_t->rx_buffer_size/2,\r
- prk29_uart_dma_t->rx_buffer_size/2)) {\r
- dev_info(up->port.dev, "*******rk29_dma_enqueue fail*****\n");\r
- return -1;\r
- }\r
+ //desc->callback = dma_rx_callback; \r
+ //desc->callback_param = port; \r
+ dev_dbg(port->dev, "RX: prepare for the DMA.\n");\r
+ dmaengine_submit(desc); \r
+ dma_async_issue_pending(uart_dma->dma_chan_rx);\r
\r
- rk29_dma_ctrl(prk29_uart_dma_t->rx_dmach, RK29_DMAOP_START);\r
- prk29_uart_dma_t->rx_dma_start = 1;\r
- if(prk29_uart_dma_t->use_timer == 1){\r
- mod_timer(&prk29_uart_dma_t->rx_timer, jiffies +\r
- msecs_to_jiffies(prk29_uart_dma_t->rx_timeout));\r
+ uart_dma->rx_dma_used = 1;\r
+ if(uart_dma->use_timer == 1){\r
+ mod_timer(&uart_dma->rx_timer, jiffies + msecs_to_jiffies(uart_dma->rx_timeout));\r
}\r
up->port_activity = jiffies;\r
return 1;\r
}\r
\r
-static void serial_rk_update_rb_addr(struct uart_rk_port *up){\r
- dma_addr_t current_pos = 0;\r
- dma_addr_t rx_current_pos = 0;\r
- struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t;\r
- spin_lock(&(up->prk29_uart_dma_t->rx_lock));\r
- rk29_dma_getposition(prk29_uart_dma_t->rx_dmach, ¤t_pos, &rx_current_pos);\r
-\r
- prk29_uart_dma_t->rb_cur_pos = (rx_current_pos - prk29_uart_dma_t->rx_phy_addr);\r
- prk29_uart_dma_t->rx_size = CIRC_CNT(prk29_uart_dma_t->rb_cur_pos,\r
- prk29_uart_dma_t->rb_pre_pos, prk29_uart_dma_t->rx_buffer_size);\r
-\r
- spin_unlock(&(up->prk29_uart_dma_t->rx_lock));\r
+static void serial_rk_update_rb_addr(struct uart_rk_port *up)\r
+{\r
+ struct rk_uart_dma *uart_dma = up->dma;\r
+ struct dma_tx_state state; \r
+ //spin_lock(&(up->dma->rx_lock));\r
+ uart_dma->rx_size = 0;\r
+ if(uart_dma->rx_dma_used == 1) {\r
+ dmaengine_tx_status(uart_dma->dma_chan_rx, (dma_cookie_t)0, &state);\r
+ uart_dma->rb_head = (state.residue - uart_dma->rx_phy_addr);\r
+ uart_dma->rx_size = CIRC_CNT(uart_dma->rb_head, uart_dma->rb_tail, uart_dma->rb_size);\r
+ }\r
+ //spin_unlock(&(up->dma->rx_lock));\r
}\r
\r
static void serial_rk_report_dma_rx(unsigned long uart)\r
{\r
+ int count, flip = 0;\r
struct uart_rk_port *up = (struct uart_rk_port *)uart;\r
- struct rk29_uart_dma_t *prk29_uart_dma_t = up->prk29_uart_dma_t;\r
- if(prk29_uart_dma_t->use_timer == 1){\r
- serial_rk_update_rb_addr(up);\r
- }\r
- if(prk29_uart_dma_t->rx_size > 0) {\r
- spin_lock(&(up->prk29_uart_dma_t->rx_lock));\r
-\r
- if(prk29_uart_dma_t->rb_cur_pos > prk29_uart_dma_t->rb_pre_pos){\r
- tty_insert_flip_string(up->port.state->port.tty, prk29_uart_dma_t->rx_buffer\r
- + prk29_uart_dma_t->rb_pre_pos, prk29_uart_dma_t->rx_size);\r
- tty_flip_buffer_push(up->port.state->port.tty);\r
- }\r
- else if(prk29_uart_dma_t->rb_cur_pos < prk29_uart_dma_t->rb_pre_pos){\r
-\r
- tty_insert_flip_string(up->port.state->port.tty, prk29_uart_dma_t->rx_buffer\r
- + prk29_uart_dma_t->rb_pre_pos, CIRC_CNT_TO_END(prk29_uart_dma_t->rb_cur_pos,\r
- prk29_uart_dma_t->rb_pre_pos, prk29_uart_dma_t->rx_buffer_size));\r
- tty_flip_buffer_push(up->port.state->port.tty);\r
+ struct uart_port *port = &up->port;\r
+ struct rk_uart_dma *uart_dma = up->dma;\r
\r
- if(prk29_uart_dma_t->rb_cur_pos != 0){\r
- tty_insert_flip_string(up->port.state->port.tty, prk29_uart_dma_t->rx_buffer,\r
- prk29_uart_dma_t->rb_cur_pos);\r
- tty_flip_buffer_push(up->port.state->port.tty);\r
- }\r
- }\r
+ if(!uart_dma->rx_dma_used || !port->state->port.tty)\r
+ return;\r
\r
- prk29_uart_dma_t->rb_pre_pos = (prk29_uart_dma_t->rb_pre_pos + prk29_uart_dma_t->rx_size)\r
- & (prk29_uart_dma_t->rx_buffer_size - 1);\r
- up->port.icount.rx += prk29_uart_dma_t->rx_size;\r
- spin_unlock(&(up->prk29_uart_dma_t->rx_lock));\r
- prk29_uart_dma_t->rx_timeout = 7;\r
+ serial_rk_update_rb_addr(up);\r
+ //if (uart_dma->rx_size > 0)\r
+ // printk("rx_size:%d ADDR:%x\n", uart_dma->rx_size, uart_dma->rb_head);\r
+ while(1) {\r
+ count = CIRC_CNT_TO_END(uart_dma->rb_head, uart_dma->rb_tail, uart_dma->rb_size);\r
+ if(count <= 0)\r
+ break;\r
+ port->icount.rx += count;\r
+ flip = tty_insert_flip_string(&port->state->port, uart_dma->rx_buffer\r
+ + uart_dma->rb_tail, count);\r
+ tty_flip_buffer_push(&port->state->port);\r
+ uart_dma->rb_tail = (uart_dma->rb_tail + count) & (uart_dma->rb_size - 1);\r
up->port_activity = jiffies;\r
}\r
\r
-\r
-#if 1\r
- if (jiffies_to_msecs(jiffies - up->port_activity) < RX_TIMEOUT) {\r
- if(prk29_uart_dma_t->use_timer == 1){\r
- mod_timer(&prk29_uart_dma_t->rx_timer, jiffies + msecs_to_jiffies(prk29_uart_dma_t->rx_timeout));\r
- }\r
- } else {\r
-\r
-#if 1\r
-\r
-\r
- prk29_uart_dma_t->rx_timeout = 20;\r
- mod_timer(&prk29_uart_dma_t->rx_timer, jiffies + msecs_to_jiffies(prk29_uart_dma_t->rx_timeout));\r
-#else\r
-// serial_out(up, 0x2a, 0x01);\r
- serial_rk_release_dma_rx(&up->port);\r
- serial_out(up, 0x2a, 0x01);\r
- up->ier |= (UART_IER_RDI | UART_IER_RLSI);\r
- serial_out(up, UART_IER, up->ier);\r
-// serial_out(up, 0x22, 0x01);\r
- dev_info(up->port.dev, "*****enable recv int*****\n");\r
-\r
- //serial_rk_start_rx_dma(&up->port);\r
-#endif\r
- }\r
-\r
-\r
-#else\r
- if(prk29_uart_dma_t->use_timer == 1){\r
- mod_timer(&prk29_uart_dma_t->rx_timer, jiffies + msecs_to_jiffies(prk29_uart_dma_t->rx_timeout));\r
- }\r
-#endif\r
-\r
-}\r
-\r
-static void serial_rk_rx_timeout(unsigned long uart)\r
-{\r
- struct uart_rk_port *up = (struct uart_rk_port *)uart;\r
-\r
- //serial_rk_report_dma_rx(up);\r
- queue_work(up->uart_wq, &up->uart_work);\r
-}\r
-\r
-static void serial_rk_report_revdata_workfunc(struct work_struct *work)\r
-{\r
- struct uart_rk_port *up =\r
- container_of(work, struct uart_rk_port, uart_work);\r
- serial_rk_report_dma_rx((unsigned long)up);\r
- spin_lock(&(up->prk29_uart_dma_t->rx_lock));\r
-\r
- if(up->prk29_uart_dma_t->use_timer == 1){\r
-\r
- }else{\r
- tty_insert_flip_string(up->port.state->port.tty, up->fifo, up->fifo_size);\r
- tty_flip_buffer_push(up->port.state->port.tty);\r
- up->port.icount.rx += up->fifo_size;\r
- }\r
-\r
- spin_unlock(&(up->prk29_uart_dma_t->rx_lock));\r
-\r
-}\r
-\r
-\r
-static void serial_rk_start_dma_rx(struct work_struct *work)\r
-{\r
- struct uart_rk_port *up =\r
- container_of(work, struct uart_rk_port, uart_work_rx);\r
- serial_rk_start_rx_dma(&up->port);\r
+ if(uart_dma->use_timer == 1)\r
+ mod_timer(&uart_dma->rx_timer, jiffies + msecs_to_jiffies(uart_dma->rx_timeout));\r
}\r
#endif /* USE_DMA */\r
\r
\r
-\r
static void\r
receive_chars(struct uart_rk_port *up, unsigned int *status)\r
{\r
lsr = serial_in(up, UART_LSR);\r
} while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0));\r
spin_unlock(&up->port.lock);\r
- tty_flip_buffer_push(tty);\r
+ tty_flip_buffer_push(tty->port);\r
spin_lock(&up->port.lock);\r
*status = lsr;\r
}\r
__stop_tx(up);\r
return;\r
}\r
-\r
- count = up->tx_loadsz;\r
+#if USE_DMA\r
+ //hhb\r
+ if(up->dma->use_dma & TX_DMA){\r
+ if(SERIAL_CIRC_CNT_TO_END(xmit) >= DMA_TX_TRRIGE_LEVEL){\r
+ serial_rk_start_dma_tx(up);\r
+ return;\r
+ }\r
+ }\r
+#endif\r
+ count = up->port.fifosize - serial_in(up , 0x20);\r
do {\r
serial_out(up, UART_TX, xmit->buf[xmit->tail]);\r
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);\r
uart_write_wakeup(&up->port);\r
\r
DEBUG_INTR("THRE...");\r
-\r
+#if USE_DMA\r
+ up->port_activity = jiffies;\r
+#endif\r
if (uart_circ_empty(xmit))\r
__stop_tx(up);\r
}\r
/* reading UART_LSR can automatically clears PE FE OE bits, except receive fifo error bit*/\r
status = serial_in(up, UART_LSR);\r
\r
- DEBUG_INTR("status = %x...", status);\r
+ DEBUG_INTR("status = %x...\n", status);\r
#if USE_DMA\r
/* DMA mode enable */\r
- if(up->prk29_uart_dma_t->use_dma == 1) {\r
+ if(up->dma->use_dma) {\r
\r
- if(up->iir & UART_IIR_RLSI){\r
- if (status & (UART_LSR_DR | UART_LSR_BI)) {\r
- up->port_activity = jiffies;\r
- up->ier &= ~UART_IER_RLSI;\r
- up->ier &= ~UART_IER_RDI;\r
- serial_out(up, UART_IER, up->ier);\r
- //receive_chars(up, &status);\r
- //mod_timer(&up->prk29_uart_dma_t->rx_timer, jiffies +\r
- //msecs_to_jiffies(up->prk29_uart_dma_t->rx_timeout));\r
- if(serial_rk_start_rx_dma(&up->port) == -1){\r
- receive_chars(up, &status);\r
- }\r
+ if (status & UART_LSR_RFE) {\r
+ if(up->port.line != DBG_PORT){\r
+ dev_info(up->port.dev, "error:lsr=0x%x\n", status);\r
+ status = serial_in(up, UART_LSR);\r
+ DEBUG_INTR("error:lsr=0x%x\n", status);\r
}\r
}\r
\r
- } else\r
+ if (status & 0x02) {\r
+ if(up->port.line != DBG_PORT){\r
+ dev_info(up->port.dev, "error:lsr=0x%x\n", status);\r
+ status = serial_in(up, UART_LSR);\r
+ DEBUG_INTR("error:lsr=0x%x\n", status);\r
+ }\r
+ }\r
+\r
+ if(!(up->dma->use_dma & RX_DMA)) {\r
+ if (status & (UART_LSR_DR | UART_LSR_BI)) {\r
+ receive_chars(up, &status);\r
+ } else if ((up->iir & 0x0f) == 0x0c) {\r
+ serial_in(up, UART_RX);\r
+ }\r
+ }\r
+\r
+ if ((up->iir & 0x0f) == 0x02) {\r
+ transmit_chars(up);\r
+ }\r
+ } else \r
#endif\r
- { //dma mode disable\r
+ { //dma mode disable\r
\r
/*\r
* when uart receive a serial of data which doesn't have stop bit and so on, that causes frame error,and\r
*/\r
\r
if (status & UART_LSR_RFE) {\r
- \r
if(up->port.line != DBG_PORT){\r
- status = serial_in(up, UART_LSR);\r
dev_info(up->port.dev, "error:lsr=0x%x\n", status);\r
+ status = serial_in(up, UART_LSR);\r
+ DEBUG_INTR("error:lsr=0x%x\n", status);\r
+ rk29_uart_dump_register(up);\r
}\r
- \r
- \r
- // rk29_uart_dump_register(up);\r
}\r
\r
if (status & (UART_LSR_DR | UART_LSR_BI)) {\r
receive_chars(up, &status);\r
- }\r
+ } else if ((up->iir & 0x0f) == 0x0c) {\r
+ serial_in(up, UART_RX);\r
+ }\r
check_modem_status(up);\r
- if (status & UART_LSR_THRE) {\r
+ //hhb@rock-chips.com when FIFO and THRE mode both are enabled,and FIFO TX empty trigger is set to larger than 1,\r
+ //,we need to add ((up->iir & 0x0f) == 0x02) to transmit_chars,because when entering interrupt,the FIFO and THR\r
+ //might not be 1.\r
+ if ((up->iir & 0x0f) == 0x02) {\r
transmit_chars(up);\r
}\r
}\r
-\r
spin_unlock_irqrestore(&up->port.lock, flags);\r
}\r
\r
iir = serial_in(up, UART_IIR);\r
\r
DEBUG_INTR("%s(%d) iir = 0x%02x\n", __func__, irq, iir);\r
-\r
up->iir = iir;\r
\r
if (!(iir & UART_IIR_NO_INT)) {\r
up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;\r
spin_unlock_irqrestore(&up->port.lock, flags);\r
\r
- return (lsr & BOTH_EMPTY) == BOTH_EMPTY ? TIOCSER_TEMT : 0;\r
+ return (lsr & UART_LSR_TEMT) == UART_LSR_TEMT ? TIOCSER_TEMT : 0;\r
}\r
\r
static unsigned int serial_rk_get_mctrl(struct uart_port *port)\r
dev_dbg(port->dev, "-%s lcr: 0x%02x\n", __func__, up->lcr);\r
}\r
\r
-#if defined(CONFIG_SERIAL_RK_CONSOLE) || defined(CONFIG_CONSOLE_POLL)\r
+#if defined(CONFIG_SERIAL_ROCKCHIP_CONSOLE) || defined(CONFIG_CONSOLE_POLL)\r
/*\r
* Wait for transmitter & holding register to empty\r
*/\r
ier = serial_in(up, UART_IER);\r
serial_out(up, UART_IER, 0);\r
\r
- wait_for_xmitr(up, BOTH_EMPTY);\r
+ wait_for_xmitr(up, UART_LSR_TEMT);\r
/*\r
* Send the character out.\r
* If a LF, also do CR...\r
*/\r
serial_out(up, UART_TX, c);\r
if (c == 10) {\r
- wait_for_xmitr(up, BOTH_EMPTY);\r
+ wait_for_xmitr(up, UART_LSR_TEMT);\r
serial_out(up, UART_TX, 13);\r
}\r
\r
* Finally, wait for transmitter to become empty\r
* and restore the IER\r
*/\r
- wait_for_xmitr(up, BOTH_EMPTY);\r
+ wait_for_xmitr(up, UART_LSR_TEMT);\r
serial_out(up, UART_IER, ier);\r
}\r
\r
struct uart_rk_port *up =\r
container_of(port, struct uart_rk_port, port);\r
unsigned long flags;\r
- int retval;\r
-\r
+ int retval, fifosize = 0;\r
+ \r
\r
dev_dbg(port->dev, "%s\n", __func__);\r
\r
return retval;\r
\r
up->mcr = 0;\r
-\r
- clk_enable(up->pclk);\r
- clk_enable(up->clk); // enable the config uart clock\r
-\r
+#ifdef CONFIG_CLOCK_CTRL\r
+ clk_prepare_enable(up->clk);\r
+ clk_prepare_enable(up->pclk); // enable the config uart clock\r
+#endif\r
/*\r
* Clear the FIFO buffers and disable them.\r
* (they will be reenabled in set_termios())\r
*/\r
serial_rk_clear_fifos(up);\r
\r
+ //read uart fifo size hhb@rock-chips.com\r
+ fifosize = __raw_readl(up->port.membase + 0xf4);\r
+ up->port.fifosize = ((fifosize >> 16) & 0xff) << 4;\r
+ if(up->port.fifosize <= 0)\r
+ up->port.fifosize = 32;\r
+ //printk("fifo size:%d :%08x\n", up->port.fifosize, fifosize);\r
+\r
/*\r
* Clear the interrupt registers.\r
*/\r
#if 0\r
up->msr_saved_flags = 0;\r
#endif\r
-\r
#if USE_DMA\r
- if (1 == up->prk29_uart_dma_t->use_dma) {\r
-\r
- if(up->port.state->xmit.buf != up->prk29_uart_dma_t->tx_buffer){\r
+ if (up->dma->use_dma & TX_DMA) {\r
+ if(up->port.state->xmit.buf != up->dma->tx_buffer){\r
free_page((unsigned long)up->port.state->xmit.buf);\r
- up->port.state->xmit.buf = up->prk29_uart_dma_t->tx_buffer;\r
+ up->port.state->xmit.buf = up->dma->tx_buffer;\r
}\r
-\r
-#if 1\r
- serial_rk_start_rx_dma(&up->port);\r
-#else\r
- up->ier |= UART_IER_RDI;\r
- up->ier |= UART_IER_RLSI;\r
- serial_out(up, UART_IER, up->ier);\r
+ } else \r
#endif\r
- up->port_activity = jiffies;\r
-\r
- } else\r
-#endif /* USE_DMA */\r
{\r
up->ier = 0;\r
serial_out(up, UART_IER, up->ier);\r
* Read data port to reset things, and then free the irq\r
*/\r
(void) serial_in(up, UART_RX);\r
-\r
+#if USE_DMA\r
+ if (up->dma->use_dma & TX_DMA)\r
+ up->port.state->xmit.buf = NULL;\r
+#endif\r
free_irq(up->port.irq, up);\r
- clk_disable(up->clk);\r
- clk_disable(up->pclk);\r
+#ifdef CONFIG_CLOCK_CTRL\r
+ clk_disable_unprepare(up->clk);\r
+ clk_disable_unprepare(up->pclk); \r
+#endif\r
}\r
\r
static void\r
{\r
struct uart_rk_port *up =\r
container_of(port, struct uart_rk_port, port);\r
- unsigned char cval, fcr = 0;\r
+ unsigned char cval = 0, fcr = 0, mcr = 0;\r
unsigned long flags;\r
unsigned int baud, quot;\r
- int timeout = 1000000;\r
+\r
dev_dbg(port->dev, "+%s\n", __func__);\r
\r
+#if USE_DMA\r
+ //stop dma tx, which might make the uart be busy while some registers are set\r
+ if(up->dma->tx_dma_used) {\r
+ serial_rk_stop_dma_tx(up);\r
+ }\r
+#endif\r
+\r
switch (termios->c_cflag & CSIZE) {\r
case CS5:\r
cval = UART_LCR_WLEN5;\r
port->uartclk / 16);\r
\r
quot = uart_get_divisor(port, baud);\r
-\r
- dev_info(up->port.dev, "baud:%d\n", baud);\r
-// dev_info(up->port.dev, "quot:%d\n", quot);\r
-\r
- /*\r
- * To wait long enough to avoid writting lcr when the uart is busy\r
- * because of data communication, so that we can set lcr and baud rate\r
- * successfully. added by hhb@rock-chips.com\r
- */\r
-\r
- while(serial_in(up, UART_USR) & UART_USR_BUSY){\r
- if(--timeout == 0){\r
- if(port->line != DBG_PORT){\r
- serial_out(up, UART_SRR, UART_RESET);\r
- }\r
- dbg("rk_serial_set_termios uart.%d timeout,irq=%d,ret=0x%x AND uart is reseted\n",\r
- port->line, port->irq, serial_in(up, UART_USR));\r
- break;\r
- }\r
- cpu_relax();\r
- }\r
-\r
-\r
- printk("serial.%d timeout:%d\n", up->port.line,timeout);\r
-\r
+ //dev_info(up->port.dev, "uartclk:%d\n", port->uartclk/16);\r
+ //dev_info(up->port.dev, "baud:%d\n", baud);\r
+ //dev_info(up->port.dev, "quot:%d\n", quot);\r
\r
if (baud < 2400){\r
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;\r
}\r
else{\r
+ fcr = UART_FCR_ENABLE_FIFO;\r
+#if USE_DMA\r
+ //added by hhb@rock-chips.com\r
+ if(up->dma->use_dma & TX_DMA){\r
+ fcr |= UART_FCR_T_TRIG_01;\r
+ } else\r
+#endif\r
+ {\r
+ fcr |= UART_FCR_T_TRIG_01;\r
+ }\r
+\r
#if USE_DMA\r
//added by hhb@rock-chips.com\r
- if(up->prk29_uart_dma_t->use_timer == 1){\r
- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00 | UART_FCR_T_TRIG_01;\r
+ if(up->dma->use_dma & RX_DMA){ \r
+ fcr |= UART_FCR_R_TRIG_00;\r
} else\r
#endif\r
{\r
- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 | UART_FCR_T_TRIG_01;\r
+ if (termios->c_cflag & CRTSCTS)\r
+ fcr |= UART_FCR_R_TRIG_11;\r
+ else\r
+ fcr |= UART_FCR_R_TRIG_00;\r
}\r
}\r
\r
up->ier |= UART_IER_MSI;\r
#endif\r
\r
+ //to avoid uart busy when set baud rate hhb@rock-chips.com\r
+ serial_out(up, UART_SRR, UART_RESET);\r
+ mcr = serial_in(up, UART_MCR);\r
+ serial_out(up, UART_MCR, mcr | 0x10); //loopback mode\r
+ \r
up->lcr = cval; /* Save LCR */\r
/* set DLAB */\r
- if(serial_lcr_write(up, cval | UART_LCR_DLAB)){\r
- dbg("serial.%d set DLAB fail\n", up->port.line);\r
+ if(serial_lcr_write(up, cval | UART_LCR_DLAB)) {\r
+ if(up->port.line != DBG_PORT)\r
+ dbg("serial.%d set DLAB fail\n", up->port.line);\r
serial_out(up, UART_SRR, UART_RESET);\r
goto fail;\r
}\r
\r
/* set uart baud rate */\r
- if(serial_dl_write(up, quot)){\r
- dbg("serial.%d set dll fail\n", up->port.line);\r
+ if(serial_dl_write(up, quot)) {\r
+ if(up->port.line != DBG_PORT)\r
+ dbg("serial.%d set dll fail\n", up->port.line);\r
serial_out(up, UART_SRR, UART_RESET);\r
goto fail;\r
}\r
\r
/* reset DLAB */\r
- if(serial_lcr_write(up, cval)){\r
- dbg("serial.%d reset DLAB fail\n", up->port.line);\r
+ if(serial_lcr_write(up, cval)) {\r
+ if(up->port.line != DBG_PORT)\r
+ dbg("serial.%d reset DLAB fail\n", up->port.line);\r
serial_out(up, UART_SRR, UART_RESET);\r
goto fail;\r
}\r
- else{\r
+ else {\r
serial_rk_set_mctrl(&up->port, up->port.mctrl);\r
- serial_out(up, UART_FCR, fcr); /* set fcr */\r
up->fcr = fcr;\r
- /* enable the uart interrupt last */\r
- up->ier |= UART_IER_RDI;\r
- up->ier |= UART_IER_RLSI;\r
+ serial_out(up, UART_FCR, up->fcr); /* set fcr */\r
+ up->ier = 0;\r
+ //start serial receive data\r
+#if USE_DMA\r
+ if (up->dma->use_dma) {\r
+ up->ier |= UART_IER_RLSI;\r
+ up->ier |= UART_IER_PTIME; //Programmable THRE Interrupt Mode Enable\r
+ if (up->dma->use_dma & RX_DMA)\r
+ serial_rk_start_dma_rx(up);\r
+ else\r
+ up->ier |= UART_IER_RDI;\r
+ } else\r
+#endif\r
+ {\r
+ // not use dma receive\r
+ up->ier |= UART_IER_RDI;\r
+ up->ier |= UART_IER_RLSI;\r
+ if(up->port.line != DBG_PORT)\r
+ up->ier |= UART_IER_PTIME; //Programmable THRE Interrupt Mode Enable\r
+\r
+ }\r
serial_out(up, UART_IER, up->ier);\r
}\r
-\r
+ \r
spin_unlock_irqrestore(&up->port.lock, flags);\r
\r
/* Don't rewrite B0 */\r
if (tty_termios_baud_rate(termios))\r
tty_termios_encode_baud_rate(termios, baud, baud);\r
dev_dbg(port->dev, "-%s baud %d\n", __func__, baud);\r
-\r
return;\r
\r
fail:\r
serial_rk_pm(struct uart_port *port, unsigned int state,\r
unsigned int oldstate)\r
{\r
+#ifdef CONFIG_CLOCK_CTRL\r
struct uart_rk_port *up =\r
container_of(port, struct uart_rk_port, port);\r
\r
dev_dbg(port->dev, "%s: %s\n", __func__, state ? "disable" : "enable");\r
if (state) {\r
- clk_disable(up->clk);\r
- clk_disable(up->pclk);\r
+ clk_disable_unprepare(up->clk);\r
+ clk_disable_unprepare(up->pclk); \r
} else {\r
- clk_enable(up->pclk);\r
- clk_enable(up->clk);\r
+ clk_prepare_enable(up->clk);\r
+ clk_prepare_enable(up->pclk); \r
}\r
+#endif\r
}\r
\r
static void serial_rk_release_port(struct uart_port *port)\r
#endif\r
};\r
\r
-#ifdef CONFIG_SERIAL_RK_CONSOLE\r
+#ifdef CONFIG_SERIAL_ROCKCHIP_CONSOLE\r
\r
static struct uart_rk_port *serial_rk_console_ports[UART_NR];\r
\r
* Finally, wait for transmitter to become empty\r
* and restore the IER\r
*/\r
- wait_for_xmitr(up, BOTH_EMPTY);\r
+ wait_for_xmitr(up, UART_LSR_TEMT);\r
serial_out(up, UART_IER, ier);\r
\r
#if 0\r
local_irq_restore(flags);\r
}\r
\r
+#ifdef CONFIG_RK_CONSOLE_THREAD\r
+#include <linux/kfifo.h>\r
+#include <linux/kthread.h>\r
+static struct task_struct *console_task;\r
+#define FIFO_SIZE SZ_512K\r
+static DEFINE_KFIFO(fifo, unsigned char, FIFO_SIZE);\r
+static bool console_thread_stop;\r
+\r
+static void console_putc(struct uart_rk_port *up, unsigned int c)\r
+{\r
+ while (!(serial_in(up, UART_USR) & UART_USR_TX_FIFO_NOT_FULL))\r
+ cpu_relax();\r
+ serial_out(up, UART_TX, c);\r
+}\r
+\r
+static void console_flush(struct uart_rk_port *up)\r
+{\r
+ while (!(serial_in(up, UART_USR) & UART_USR_TX_FIFO_EMPTY))\r
+ cpu_relax();\r
+}\r
+\r
+static int console_thread(void *data)\r
+{\r
+ struct uart_rk_port *up = data;\r
+ unsigned char c;\r
+\r
+ while (1) {\r
+ set_current_state(TASK_INTERRUPTIBLE);\r
+ schedule();\r
+ if (kthread_should_stop())\r
+ break;\r
+ set_current_state(TASK_RUNNING);\r
+ while (!console_thread_stop && serial_in(up, UART_SFE) && kfifo_get(&fifo, &c)) {\r
+ console_putc(up, c);\r
+ }\r
+ if (!console_thread_stop)\r
+ console_flush(up);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+static void console_write(struct console *co, const char *s, unsigned int count)\r
+{\r
+ struct uart_rk_port *up = serial_rk_console_ports[co->index];\r
+ unsigned int fifo_count = FIFO_SIZE;\r
+ unsigned char c, r = '\r';\r
+\r
+ if (console_thread_stop ||\r
+ oops_in_progress ||\r
+ system_state == SYSTEM_HALT ||\r
+ system_state == SYSTEM_POWER_OFF ||\r
+ system_state == SYSTEM_RESTART) {\r
+ if (!console_thread_stop) {\r
+ console_thread_stop = true;\r
+ smp_wmb();\r
+ console_flush(up);\r
+ while (fifo_count-- && kfifo_get(&fifo, &c))\r
+ console_putc(up, c);\r
+ }\r
+ while (count--) {\r
+ if (*s == '\n') {\r
+ console_putc(up, r);\r
+ }\r
+ console_putc(up, *s++);\r
+ }\r
+ console_flush(up);\r
+ } else {\r
+ while (count--) {\r
+ if (*s == '\n') {\r
+ kfifo_put(&fifo, &r);\r
+ }\r
+ kfifo_put(&fifo, s++);\r
+ }\r
+ wake_up_process(console_task);\r
+ }\r
+}\r
+#endif\r
+\r
static int __init serial_rk_console_setup(struct console *co, char *options)\r
{\r
struct uart_rk_port *up;\r
if (options)\r
uart_parse_options(options, &baud, &parity, &bits, &flow);\r
\r
+#ifdef CONFIG_RK_CONSOLE_THREAD\r
+ if (!console_task) {\r
+ console_task = kthread_create(console_thread, up, "kconsole");\r
+ if (!IS_ERR(console_task))\r
+ co->write = console_write;\r
+ }\r
+#endif\r
return uart_set_options(&up->port, co, baud, parity, bits, flow);\r
}\r
\r
\r
static struct uart_driver serial_rk_reg = {\r
.owner = THIS_MODULE,\r
- .driver_name = "rk29_serial",\r
+ .driver_name = "rk_serial",\r
.dev_name = "ttyS",\r
.major = TTY_MAJOR,\r
.minor = 64,\r
.cons = SERIAL_CONSOLE,\r
.nr = UART_NR,\r
};\r
+#if USE_WAKEUP\r
+static irqreturn_t serial_rk_wakeup_handler(int irq, void *dev) {\r
+ struct uart_rk_port *up = dev;\r
+ struct uart_wake_up *wakeup = up->wakeup;\r
+ if(wakeup->enable == 1) {\r
+ iomux_set(wakeup->rx_mode);\r
+ wake_lock_timeout(&wakeup->wakelock, 3 * HZ);\r
+ } \r
+ return 0;\r
+}\r
\r
-static int __devinit serial_rk_probe(struct platform_device *pdev)\r
+static int serial_rk_setup_wakeup_irq(struct uart_rk_port *up)\r
+{\r
+ int ret = 0;\r
+ struct uart_wake_up *wakeup = up->wakeup;\r
+\r
+ if(wakeup->enable == 1) {\r
+ memset(wakeup->wakelock_name, 0, 32);\r
+ sprintf(wakeup->wakelock_name, "serial.%d_wakelock", up->port.line);\r
+ wake_lock_init(&wakeup->wakelock, WAKE_LOCK_SUSPEND, wakeup->wakelock_name);\r
+ memset(wakeup->rx_pin_name, 0, 32); \r
+ sprintf(wakeup->rx_pin_name, "UART%d_SIN", up->port.line);\r
+ wakeup->rx_pin = iomux_mode_to_gpio(wakeup->rx_mode);\r
+ ret = gpio_request(wakeup->rx_pin, wakeup->rx_pin_name);\r
+ if (ret) {\r
+ printk("request %s fail ! \n", wakeup->rx_pin_name);\r
+ return ret;\r
+ }\r
+ gpio_direction_input(wakeup->rx_pin);\r
+ wakeup->rx_irq = gpio_to_irq(wakeup->rx_pin);\r
+ memset(wakeup->rx_irq_name, 0, 32);\r
+ sprintf(wakeup->rx_irq_name, "serial.%d_wake_up_irq", up->port.line);\r
+ ret = request_irq(wakeup->rx_irq, serial_rk_wakeup_handler, IRQF_TRIGGER_FALLING, wakeup->rx_irq_name, up);\r
+ if(ret < 0) {\r
+ printk("%s request fail\n", wakeup->rx_irq_name);\r
+ return ret;\r
+ }\r
+ disable_irq_nosync(wakeup->rx_irq);\r
+ enable_irq_wake(wakeup->rx_irq);\r
+ iomux_set(wakeup->rx_mode);\r
+ }\r
+ return ret;\r
+}\r
+\r
+static int serial_rk_enable_wakeup_irq(struct uart_rk_port *up) {\r
+ struct uart_wake_up *wakeup = up->wakeup;\r
+ if(wakeup->enable == 1) {\r
+ iomux_set(wakeup->rx_mode & 0xfff0);\r
+ enable_irq(wakeup->rx_irq);\r
+ }\r
+ return 0;\r
+}\r
+\r
+static int serial_rk_disable_wakeup_irq(struct uart_rk_port *up) {\r
+ struct uart_wake_up *wakeup = up->wakeup;\r
+ if(wakeup->enable == 1) {\r
+ disable_irq_nosync(wakeup->rx_irq);\r
+ iomux_set(wakeup->rx_mode);\r
+ }\r
+ return 0;\r
+}\r
+\r
+static int serial_rk_remove_wakeup_irq(struct uart_rk_port *up) {\r
+ struct uart_wake_up *wakeup = up->wakeup;\r
+ if(wakeup->enable == 1) {\r
+ //disable_irq_nosync(wakeup->rx_irq);\r
+ free_irq(wakeup->rx_irq, NULL);\r
+ gpio_free(wakeup->rx_pin);\r
+ wake_lock_destroy(&wakeup->wakelock);\r
+ }\r
+ return 0;\r
+}\r
+#endif\r
+\r
+#ifdef CONFIG_OF\r
+static int of_rk_serial_parse_dt(struct device_node *np, struct of_rk_serial *rks) \r
+{\r
+ unsigned int val = 0;\r
+ const char *s = NULL;\r
+ int ret, i = 0;\r
+ rks->id = of_alias_get_id(np, "serial");\r
+ if(!of_property_read_u32(np, "clock-frequency", &val))\r
+ rks->uartclk = val;\r
+\r
+#if USE_DMA\r
+ rks->use_dma = 0;\r
+ for(i = 0; i < 2; i++) {\r
+ ret = of_property_read_string_index(np, "dma-names", i, &s);\r
+ if(!ret) {\r
+ if(!strcmp(s, "tx"))\r
+ rks->use_dma |= TX_DMA;\r
+ else if (!strcmp(s, "rx"))\r
+ rks->use_dma |= RX_DMA;\r
+ }\r
+ }\r
+#endif\r
+ return 0;\r
+}\r
+#endif\r
+\r
+static int serial_rk_probe(struct platform_device *pdev)\r
{\r
struct uart_rk_port *up;\r
struct resource *mem;\r
int irq;\r
int ret = -ENOSPC;\r
+ struct of_rk_serial rks;\r
+\r
+ up = devm_kzalloc(&pdev->dev, sizeof(*up), GFP_KERNEL);\r
+ if (!up)\r
+ return -ENOMEM;\r
+\r
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);\r
- if (!mem) {\r
- dev_err(&pdev->dev, "no mem resource?\n");\r
- return -ENODEV;\r
- }\r
+ up->port.membase = devm_request_and_ioremap(&pdev->dev, mem);\r
+ if (!up->port.membase)\r
+ return -ENOMEM;\r
\r
irq = platform_get_irq(pdev, 0);\r
if (irq < 0) {\r
return irq;\r
}\r
\r
- if (!request_mem_region(mem->start, (mem->end - mem->start) + 1,\r
- pdev->dev.driver->name)) {\r
- dev_err(&pdev->dev, "memory region already claimed\n");\r
- return -EBUSY;\r
- }\r
-\r
- up = kzalloc(sizeof(*up), GFP_KERNEL);\r
- if (up == NULL) {\r
- ret = -ENOMEM;\r
- goto do_release_region;\r
- }\r
+#ifdef CONFIG_OF\r
+ of_rk_serial_parse_dt(pdev->dev.of_node, &rks);\r
+ pdev->id = rks.id;\r
+#endif\r
\r
sprintf(up->name, "rk29_serial.%d", pdev->id);\r
up->pdev = pdev;\r
- up->pclk = clk_get(&pdev->dev, "pclk_uart");\r
- up->clk = clk_get(&pdev->dev, "uart");\r
- if (unlikely(IS_ERR(up->clk))) {\r
- ret = PTR_ERR(up->clk);\r
- goto do_free;\r
+#ifdef CONFIG_CLOCK_CTRL\r
+ up->pclk = devm_clk_get(&pdev->dev, "pclk_uart");\r
+ up->clk = devm_clk_get(&pdev->dev, "sclk_uart");\r
+ if (unlikely(IS_ERR(up->clk)) || unlikely(IS_ERR(up->pclk))) {\r
+ dev_err(&pdev->dev, "get clock fail\n");\r
+ return -EINVAL;\r
}\r
+#endif\r
up->tx_loadsz = 30;\r
#if USE_DMA\r
- up->prk29_uart_dma_t = &rk29_uart_ports_dma_t[pdev->id];\r
+ up->dma = devm_kzalloc(&pdev->dev, sizeof(struct rk_uart_dma), GFP_KERNEL);\r
+ if (!up->dma) {\r
+ dev_err(&pdev->dev, "unable to allocate mem\n");\r
+ return -ENOMEM;\r
+ }\r
+ up->dma->use_dma = rks.use_dma;\r
+#endif\r
+#if USE_WAKEUP\r
+ up->wakeup = &rk29_uart_ports_wakeup[pdev->id];\r
#endif\r
up->port.dev = &pdev->dev;\r
up->port.type = PORT_RK;\r
up->port.irq = irq;\r
- up->port.iotype = UPIO_DWAPB;\r
-\r
+ up->port.iotype = UPIO_MEM;\r
+ \r
up->port.regshift = 2;\r
+ //fifo size default is 32, but it will be updated later when start_up\r
up->port.fifosize = 32;\r
up->port.ops = &serial_rk_pops;\r
up->port.line = pdev->id;\r
up->port.iobase = mem->start;\r
- up->port.membase = ioremap_nocache(mem->start, mem->end - mem->start + 1);\r
- if (!up->port.membase) {\r
- ret = -ENOMEM;\r
- goto do_put_clk;\r
- }\r
up->port.mapbase = mem->start;\r
up->port.irqflags = IRQF_DISABLED;\r
+#if defined(CONFIG_CLOCK_CTRL)\r
up->port.uartclk = clk_get_rate(up->clk);\r
+#elif defined(CONFIG_OF)\r
+ up->port.uartclk = rks.uartclk;\r
+#else\r
+ up->port.uartclk = 24000000;\r
+#endif\r
\r
#if USE_DMA\r
/* set dma config */\r
- if(1 == up->prk29_uart_dma_t->use_dma) {\r
- pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);\r
-\r
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);\r
+ if(up->dma->use_dma & RX_DMA) {\r
//timer\r
- up->prk29_uart_dma_t->use_timer = USE_TIMER;\r
- up->prk29_uart_dma_t->rx_timer.function = serial_rk_rx_timeout;\r
- up->prk29_uart_dma_t->rx_timer.data = (unsigned long)up;\r
- up->prk29_uart_dma_t->rx_timeout = 7;\r
- up->prk29_uart_dma_t->rx_timer.expires = jiffies + msecs_to_jiffies(up->prk29_uart_dma_t->rx_timeout);\r
- init_timer(&up->prk29_uart_dma_t->rx_timer);\r
- //tx buffer\r
- up->prk29_uart_dma_t->tx_buffer_size = UART_XMIT_SIZE;\r
- up->prk29_uart_dma_t->tx_buffer = dmam_alloc_coherent(up->port.dev, up->prk29_uart_dma_t->tx_buffer_size,\r
- &up->prk29_uart_dma_t->tx_phy_addr, DMA_MEMORY_MAP);\r
- if(!up->prk29_uart_dma_t->tx_buffer){\r
- dev_info(up->port.dev, "dmam_alloc_coherent dma_tx_buffer fail\n");\r
- }\r
- else{\r
- dev_info(up->port.dev, "dma_tx_buffer 0x%08x\n", (unsigned) up->prk29_uart_dma_t->tx_buffer);\r
- dev_info(up->port.dev, "dma_tx_phy 0x%08x\n", (unsigned) up->prk29_uart_dma_t->tx_phy_addr);\r
- }\r
+ up->dma->use_timer = USE_TIMER;\r
+ up->dma->rx_timer.function = serial_rk_report_dma_rx;\r
+ up->dma->rx_timer.data = (unsigned long)up;\r
+ up->dma->rx_timeout = 10;\r
+ up->dma->rx_timer.expires = jiffies + msecs_to_jiffies(up->dma->rx_timeout);\r
+ init_timer(&up->dma->rx_timer);\r
+\r
//rx buffer\r
- up->prk29_uart_dma_t->rx_buffer_size = UART_XMIT_SIZE*32;\r
- up->prk29_uart_dma_t->rx_buffer = dmam_alloc_coherent(up->port.dev, up->prk29_uart_dma_t->rx_buffer_size,\r
- &up->prk29_uart_dma_t->rx_phy_addr, DMA_MEMORY_MAP);\r
- up->prk29_uart_dma_t->rb_pre_pos = 0;\r
- if(!up->prk29_uart_dma_t->rx_buffer){\r
+ up->dma->rb_size = DMA_SERIAL_BUFFER_SIZE;\r
+ up->dma->rx_buffer = dmam_alloc_coherent(up->port.dev, up->dma->rb_size,\r
+ &up->dma->rx_phy_addr, DMA_MEMORY_MAP);\r
+ up->dma->rb_tail = 0;\r
+ up->dma->rx_dma_inited = 0;\r
+ up->dma->rx_dma_used = 0;\r
+\r
+ if(!up->dma->rx_buffer){\r
dev_info(up->port.dev, "dmam_alloc_coherent dma_rx_buffer fail\n");\r
}\r
else {\r
- dev_info(up->port.dev, "dma_rx_buffer 0x%08x\n", (unsigned) up->prk29_uart_dma_t->rx_buffer);\r
- dev_info(up->port.dev, "up 0x%08x\n", (unsigned)up->prk29_uart_dma_t);\r
+ dev_info(up->port.dev, "dma_rx_buffer %p\n", up->dma->rx_buffer);\r
+ dev_info(up->port.dev, "dma_rx_phy 0x%08x\n", (unsigned)up->dma->rx_phy_addr);\r
}\r
\r
// work queue\r
- INIT_WORK(&up->uart_work, serial_rk_report_revdata_workfunc);\r
- INIT_WORK(&up->uart_work_rx, serial_rk_start_dma_rx);\r
- up->uart_wq = create_singlethread_workqueue("uart_workqueue");\r
- up->prk29_uart_dma_t->rx_dma_start = 0;\r
- spin_lock_init(&(up->prk29_uart_dma_t->tx_lock));\r
- spin_lock_init(&(up->prk29_uart_dma_t->rx_lock));\r
- serial_rk_init_dma_rx(&up->port);\r
- serial_rk_init_dma_tx(&up->port);\r
- up->ier |= THRE_MODE; // enable THRE interrupt mode\r
- serial_out(up, UART_IER, up->ier);\r
+ //INIT_WORK(&up->uart_work, serial_rk_report_revdata_workfunc);\r
+ //INIT_WORK(&up->uart_work_rx, serial_rk_start_dma_rx);\r
+ //up->uart_wq = create_singlethread_workqueue("uart_workqueue");\r
+ spin_lock_init(&(up->dma->rx_lock));\r
+ serial_rk_init_dma_rx(up);\r
}\r
-#endif\r
\r
+ if(up->dma->use_dma & TX_DMA){\r
+ //tx buffer\r
+ up->dma->tb_size = UART_XMIT_SIZE;\r
+ up->dma->tx_buffer = dmam_alloc_coherent(up->port.dev, up->dma->tb_size,\r
+ &up->dma->tx_phy_addr, DMA_MEMORY_MAP);\r
+ if(!up->dma->tx_buffer){\r
+ dev_info(up->port.dev, "dmam_alloc_coherent dma_tx_buffer fail\n");\r
+ }\r
+ else{\r
+ dev_info(up->port.dev, "dma_tx_buffer %p\n", up->dma->tx_buffer);\r
+ dev_info(up->port.dev, "dma_tx_phy 0x%08x\n", (unsigned) up->dma->tx_phy_addr);\r
+ }\r
+ spin_lock_init(&(up->dma->tx_lock));\r
+ serial_rk_init_dma_tx(up);\r
+ }\r
+\r
+ \r
+#endif\r
serial_rk_add_console_port(up);\r
ret = uart_add_one_port(&serial_rk_reg, &up->port);\r
if (ret != 0)\r
- goto do_iounmap;\r
-\r
+ return ret;\r
platform_set_drvdata(pdev, up);\r
- dev_info(&pdev->dev, "membase 0x%08x\n", (unsigned) up->port.membase);\r
-\r
+ dev_info(&pdev->dev, "membase %p\n", up->port.membase);\r
+#if USE_WAKEUP\r
+ serial_rk_setup_wakeup_irq(up); \r
+#endif\r
return 0;\r
-\r
-do_iounmap:\r
- iounmap(up->port.membase);\r
- up->port.membase = NULL;\r
-do_put_clk:\r
- clk_put(up->clk);\r
- clk_put(up->pclk);\r
-do_free:\r
- kfree(up);\r
-do_release_region:\r
- release_mem_region(mem->start, (mem->end - mem->start) + 1);\r
- return ret;\r
}\r
\r
-static int __devexit serial_rk_remove(struct platform_device *pdev)\r
+static int serial_rk_remove(struct platform_device *pdev)\r
{\r
struct uart_rk_port *up = platform_get_drvdata(pdev);\r
\r
platform_set_drvdata(pdev, NULL);\r
if (up) {\r
- struct resource *mem;\r
- destroy_workqueue(up->uart_wq);\r
+#if USE_DMA\r
+ serial_rk_release_dma_tx(up);\r
+ serial_rk_release_dma_rx(up);\r
+#endif\r
+#if USE_WAKEUP\r
+ serial_rk_remove_wakeup_irq(up);\r
+#endif\r
+ //destroy_workqueue(up->uart_wq);\r
uart_remove_one_port(&serial_rk_reg, &up->port);\r
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);\r
- iounmap(up->port.membase);\r
up->port.membase = NULL;\r
- clk_put(up->clk);\r
- clk_put(up->pclk);\r
- kfree(up);\r
- release_mem_region(mem->start, (mem->end - mem->start) + 1);\r
}\r
\r
return 0;\r
if(up->port.line == DBG_PORT && POWER_MANEGEMENT){\r
serial_rk_pm(&up->port, 1, 0);\r
}\r
-\r
+#if USE_WAKEUP\r
+ serial_rk_enable_wakeup_irq(up);\r
+#endif\r
return 0;\r
}\r
\r
static int serial_rk_resume(struct platform_device *dev)\r
{\r
struct uart_rk_port *up = platform_get_drvdata(dev);\r
-\r
+#if USE_WAKEUP\r
+ serial_rk_disable_wakeup_irq(up);\r
+#endif\r
if (up && up->port.line != DBG_PORT && POWER_MANEGEMENT){\r
uart_resume_port(&serial_rk_reg, &up->port);\r
}\r
}\r
return 0;\r
}\r
-\r
+#ifdef CONFIG_OF\r
+static const struct of_device_id of_rk_serial_match[] = {\r
+ { .compatible = "rockchip,serial" },\r
+ { /* Sentinel */ }\r
+};\r
+#endif\r
static struct platform_driver serial_rk_driver = {\r
.probe = serial_rk_probe,\r
- .remove = __devexit_p(serial_rk_remove),\r
+ .remove = serial_rk_remove,\r
.suspend = serial_rk_suspend,\r
.resume = serial_rk_resume,\r
.driver = {\r
-#if defined(CONFIG_ARCH_RK29)\r
- .name = "rk29_serial",\r
-#elif defined(CONFIG_SERIAL_RK2818)\r
- .name = "rk2818_serial",\r
-#else\r
- .name = "rk_serial",\r
+ .name = "serial",\r
+#ifdef CONFIG_OF\r
+ .of_match_table = of_rk_serial_match,\r
#endif\r
.owner = THIS_MODULE,\r
},\r
static int __init serial_rk_init(void)\r
{\r
int ret;\r
-\r
+ //hhb@rock-chips.com\r
+ printk("%s\n", VERSION_AND_TIME);\r
ret = uart_register_driver(&serial_rk_reg);\r
if (ret)\r
return ret;\r
-\r
ret = platform_driver_register(&serial_rk_driver);\r
if (ret != 0)\r
uart_unregister_driver(&serial_rk_reg);\r
-\r
return ret;\r
}\r
\r
\r
MODULE_LICENSE("GPL");\r
MODULE_DESCRIPTION("RK UART driver");\r
-\r