#define UART_USR 0x1F /* UART Status Register */\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_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
\r
/* configurate whether the port transmit-receive by DMA */\r
#define OPEN_DMA 1\r
/*\r
* Debugging.\r
*/\r
-#define DBG_PORT 1\r
+#define DBG_PORT 1 //DBG_PORT which uart is used to print log message\r
+\r
#ifdef CONFIG_SERIAL_CORE_CONSOLE\r
#define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line)\r
#else\r
#define uart_console(port) (0)\r
#endif\r
\r
-#ifdef DEBUG\r
-extern void printascii(const char *);\r
+#define DEBUG 0\r
\r
+extern void printascii(const char *);\r
static void dbg(const char *fmt, ...)\r
{\r
va_list va;\r
printascii(buff);\r
}\r
\r
+#if DEBUG\r
#define DEBUG_INTR(fmt...) if (!uart_console(&up->port)) dbg(fmt)\r
#else\r
#define DEBUG_INTR(fmt...) do { } while (0)\r
unsigned char lcr;\r
unsigned char mcr;\r
unsigned char iir;\r
-\r
+ unsigned char fcr;\r
/*\r
* Some bits in registers are cleared on a read, so they must\r
* be saved whenever the register is read but the bits will not\r
}\r
\r
/* Uart divisor latch write */\r
-static inline void serial_dl_write(struct uart_rk_port *up, unsigned int value)\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
+ dbg("set serial.%d baudrate fail with DLAB not set\n", up->port.line);\r
+ return -1;\r
+ }\r
+ }\r
+\r
+ tmout = 15000;\r
+ while(serial_in(up, UART_USR) & UART_USR_BUSY){\r
+ if (--tmout == 0){\r
+ dbg("set serial.%d baudrate timeout\n", up->port.line);\r
+ return -1;\r
+ }\r
+ }\r
+ }\r
+\r
serial_out(up, UART_DLL, value & 0xff);\r
serial_out(up, UART_DLM, value >> 8 & 0xff);\r
+\r
+ return 0;\r
+\r
}\r
\r
-static void serial_lcr_write(struct uart_rk_port *up, unsigned char value)\r
+static int serial_lcr_write(struct uart_rk_port *up, unsigned char value)\r
{\r
unsigned int tmout = 15000;\r
\r
- for (;;) {\r
- unsigned char lcr;\r
- serial_out(up, UART_LCR, value);\r
- lcr = serial_in(up, UART_LCR);\r
- if (lcr == value)\r
- break;\r
- /* Read the USR to clear any busy interrupts */\r
- serial_in(up, UART_USR);\r
- serial_in(up, UART_RX);\r
- if (--tmout == 0){\r
- dev_info(up->port.dev, "set lcr timeout\n");\r
- break;\r
- }\r
+ if(up->port.line != DBG_PORT)\r
+ {\r
+ while(serial_in(up, UART_USR) & UART_USR_BUSY){\r
\r
- udelay(1);\r
+ if (--tmout == 0){\r
+ dbg("set serial.%d lc r = 0x%02x timeout\n", up->port.line, value);\r
+ return -1;\r
+ }\r
+ udelay(1);\r
+ }\r
}\r
+\r
+ serial_out(up, UART_LCR, value);\r
+\r
+ return 0;\r
}\r
\r
static inline void serial_rk_enable_ier_thri(struct uart_rk_port *up)\r
serial_out(up, UART_IER, up->ier);\r
}\r
}\r
+#if 0\r
+static int rk29_uart_dump_register(struct uart_rk_port *up){\r
+\r
+ unsigned int reg_value = 0;\r
+\r
+ reg_value = serial_in(up, UART_IER);\r
+ dbg("UART_IER = 0x%0x\n", reg_value);\r
+ reg_value = serial_in(up, UART_IIR);\r
+ dbg("UART_IIR = 0x%0x\n", reg_value);\r
+ reg_value = serial_in(up, UART_LSR);\r
+ dbg("UART_LSR = 0x%0x\n", reg_value);\r
+ reg_value = serial_in(up, UART_MSR);\r
+ dbg("UART_MSR = 0x%0x\n", reg_value);\r
+ reg_value = serial_in(up, UART_MCR);\r
+ dbg("UART_MCR = 0x%0x\n", reg_value);\r
+ reg_value = serial_in(up, 0x21);\r
+ dbg("UART_RFL = 0x%0x\n", reg_value);\r
+ reg_value = serial_in(up, UART_LCR);\r
+ dbg("UART_LCR = 0x%0x\n", reg_value);\r
+ return 0;\r
+\r
+}\r
+#endif\r
\r
/*\r
* FIFO support.\r
{\r
struct uart_rk_port *up =\r
container_of(port, struct uart_rk_port, port);\r
-/*\r
- * struct circ_buf *xmit = &port->state->xmit;\r
- int size = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE);\r
- if(size > 64){\r
- serial_rk_start_tx_dma(port);\r
- }\r
- else{\r
- serial_rk_enable_ier_thri(up);\r
- }\r
-*/\r
+\r
\r
if(0 == serial_rk_start_tx_dma(port)){\r
serial_rk_enable_ier_thri(up);\r
char flag;\r
\r
do {\r
- if (likely(lsr & UART_LSR_DR))\r
+ if (likely(lsr & UART_LSR_DR)){\r
ch = serial_in(up, UART_RX);\r
+ }\r
else\r
/*\r
* Intel 82571 has a Serial Over Lan device that will\r
unsigned long flags;\r
spin_lock_irqsave(&up->port.lock, flags);\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
-\r
+ /* DMA mode enable */\r
if(up->prk29_uart_dma_t->use_dma == 1) {\r
\r
if(up->iir & UART_IIR_RLSI){\r
-\r
if (status & (UART_LSR_DR | UART_LSR_BI)) {\r
up->port_activity = jiffies;\r
up->ier &= ~UART_IER_RLSI;\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
+ //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
}\r
}\r
\r
-/*\r
- if (status & UART_LSR_THRE) {\r
- transmit_chars(up);\r
- }\r
-*/\r
-\r
}else { //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
+ * set UART_LSR_RFE to one,what is worse,we couldn't read the data in the receive fifo. So if\r
+ * wo don't clear this bit and reset the receive fifo, the received data available interrupt would\r
+ * occur continuously. added by hhb@rock-chips.com 2011-08-05\r
+ */\r
+\r
+ if (status & UART_LSR_RFE) {\r
+ status = serial_in(up, UART_LSR);\r
+ dev_info(up->port.dev, "error:lsr=0x%x\n", status);\r
+ // rk29_uart_dump_register(up);\r
+ }\r
+\r
if (status & (UART_LSR_DR | UART_LSR_BI)) {\r
receive_chars(up, &status);\r
}\r
unsigned int iir;\r
\r
iir = serial_in(up, UART_IIR);\r
- DEBUG_INTR("%s(%d) iir = 0x%02x ", __func__, irq, 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
serial_rk_handle_port(up);\r
handled = 1;\r
} else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {\r
+\r
/* The DesignWare APB UART has an Busy Detect (0x07)\r
* interrupt meaning an LCR write attempt occured while the\r
* UART was busy. The interrupt must be cleared by reading\r
* the UART status register (USR) and the LCR re-written. */\r
- \r
+\r
if(!(serial_in(up, UART_USR) & UART_USR_BUSY)){\r
- //serial_out(up, UART_LCR, up->lcr);\r
+ serial_out(up, UART_LCR, up->lcr);\r
}\r
-\r
handled = 1;\r
- dev_info(up->port.dev, "the serial is busy\n");\r
+ dbg("the serial.%d is busy\n", up->port.line);\r
}\r
DEBUG_INTR("end(%d).\n", handled);\r
\r
mcr |= up->mcr;\r
\r
serial_out(up, UART_MCR, mcr);\r
- dev_dbg(port->dev, "-%s mcr: 0x%02x\n", __func__, mcr);\r
+ dev_dbg(port->dev, "-serial.%d %s mcr: 0x%02x\n", port->line, __func__, mcr);\r
}\r
\r
static void serial_rk_break_ctl(struct uart_port *port, int break_state)\r
/*\r
* Now, initialize the UART\r
*/\r
- serial_lcr_write(up, UART_LCR_WLEN8);\r
+ serial_lcr_write(up, UART_LCR_WLEN8 | UART_LCR_EPAR);\r
\r
spin_lock_irqsave(&up->port.lock, flags);\r
\r
/*\r
* Most PC uarts need OUT2 raised to enable interrupts.\r
*/\r
- up->port.mctrl |= TIOCM_OUT2;\r
+// up->port.mctrl |= TIOCM_OUT2;\r
\r
serial_rk_set_mctrl(&up->port, up->port.mctrl);\r
\r
* saved flags to avoid getting false values from polling\r
* routines or the previous session.\r
*/\r
- serial_in(up, UART_LSR);\r
- serial_in(up, UART_RX);\r
- serial_in(up, UART_IIR);\r
- serial_in(up, UART_MSR);\r
- serial_in(up, UART_USR);\r
+ (void) serial_in(up, UART_LSR);\r
+ (void) serial_in(up, UART_RX);\r
+ (void) serial_in(up, UART_IIR);\r
+ (void) serial_in(up, UART_MSR);\r
+ (void) serial_in(up, UART_USR);\r
up->lsr_saved_flags = 0;\r
#if 0\r
up->msr_saved_flags = 0;\r
#endif\r
\r
-\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
serial_out(up, UART_IER, 0);\r
\r
spin_lock_irqsave(&up->port.lock, flags);\r
- up->port.mctrl &= ~TIOCM_OUT2;\r
+// up->port.mctrl &= ~TIOCM_OUT2;\r
serial_rk_set_mctrl(&up->port, up->port.mctrl);\r
spin_unlock_irqrestore(&up->port.lock, flags);\r
\r
{\r
struct uart_rk_port *up =\r
container_of(port, struct uart_rk_port, port);\r
- unsigned char cval=0, fcr = 0;\r
- unsigned long flags, bits;\r
+ unsigned char cval, fcr = 0;\r
+ unsigned long flags;\r
unsigned int baud, quot;\r
-\r
+ int timeout = 1000000;\r
dev_dbg(port->dev, "+%s\n", __func__);\r
\r
- //start bit\r
- bits += 1;\r
switch (termios->c_cflag & CSIZE) {\r
case CS5:\r
cval = UART_LCR_WLEN5;\r
- bits += 5;\r
break;\r
case CS6:\r
cval = UART_LCR_WLEN6;\r
- bits += 6;\r
break;\r
case CS7:\r
cval = UART_LCR_WLEN7;\r
- bits += 7;\r
break;\r
+ case CS8:\r
default:\r
cval = UART_LCR_WLEN8;\r
- bits += 8;\r
break;\r
}\r
\r
if (termios->c_cflag & CSTOPB){\r
cval |= UART_LCR_STOP;\r
- bits += 2;\r
- }\r
- else{\r
- bits += 1;\r
}\r
if (termios->c_cflag & PARENB){\r
cval |= UART_LCR_PARITY;\r
- bits += 1;\r
}\r
if (!(termios->c_cflag & PARODD)){\r
cval |= UART_LCR_EPAR;\r
cval |= UART_LCR_SPAR;\r
#endif\r
\r
+\r
/*\r
* Ask the core to calculate the divisor for us.\r
*/\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
- dev_info(up->port.dev, "*****baud:%d*******\n", baud);\r
-// dev_info(up->port.dev, "*****quot:%d*******\n", quot);\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
- int timeout = 10000000;\r
- while(serial_in(up, UART_USR)&UART_USR_BUSY){\r
- if(timeout-- == 0){\r
- printk("rk29_serial_set_termios uart timeout,uart%d,ret=0x%x\n",up->port.line,serial_in(up, UART_USR));\r
- break;\r
- }\r
- cpu_relax();\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
- printk("%s:timeout=%d\n",__FUNCTION__,timeout);\r
+\r
+\r
+ printk("serial.%d timeout:%d\n", up->port.line,timeout);\r
+\r
\r
if (baud < 2400){\r
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;\r
up->mcr |= UART_MCR_AFE;\r
}\r
\r
-\r
/*\r
* Ok, we're now changing the port state. Do it with\r
* interrupts disabled.\r
up->ier |= UART_IER_MSI;\r
#endif\r
\r
- serial_lcr_write(up, cval | UART_LCR_DLAB);/* set DLAB */\r
-\r
- serial_dl_write(up, quot);\r
-\r
- serial_lcr_write(up, cval); /* reset DLAB */\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
+ serial_out(up, UART_SRR, UART_RESET);\r
+ goto fail;\r
+ }\r
\r
- serial_rk_set_mctrl(&up->port, up->port.mctrl);\r
+ /* set uart baud rate */\r
+ if(serial_dl_write(up, quot)){\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
- serial_out(up, UART_FCR, fcr); /* set fcr */\r
- up->ier |= UART_IER_RDI;\r
- up->ier |= UART_IER_RLSI;\r
- serial_out(up, UART_IER, up->ier);\r
+ /* reset DLAB */\r
+ if(serial_lcr_write(up, cval)){\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
+ 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_IER, up->ier);\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
+ spin_unlock_irqrestore(&up->port.lock, flags);\r
+\r
}\r
\r
#if 0\r
goto do_put_clk;\r
}\r
up->port.mapbase = mem->start;\r
- up->port.irqflags = 0;\r
+ up->port.irqflags = IRQF_DISABLED;\r
up->port.uartclk = clk_get_rate(up->clk);\r
\r
/* set dma config */\r
{\r
struct uart_rk_port *up = platform_get_drvdata(dev);\r
\r
- if (up)\r
+ if (up && up->port.line != DBG_PORT && POWER_MANEGEMENT){\r
uart_suspend_port(&serial_rk_reg, &up->port);\r
+ }\r
+ if(up->port.line == DBG_PORT && POWER_MANEGEMENT){\r
+ serial_rk_pm(&up->port, 1, 0);\r
+ }\r
+\r
return 0;\r
}\r
\r
{\r
struct uart_rk_port *up = platform_get_drvdata(dev);\r
\r
- if (up)\r
+ if (up && up->port.line != DBG_PORT && POWER_MANEGEMENT){\r
uart_resume_port(&serial_rk_reg, &up->port);\r
+ }\r
+ if(up->port.line == DBG_PORT && POWER_MANEGEMENT){\r
+ serial_rk_pm(&up->port, 0, 1);\r
+ }\r
return 0;\r
}\r
\r