--- zzzz-none-000/linux-3.10.107/drivers/tty/serial/msm_serial.c 2017-06-27 09:49:32.000000000 +0000 +++ vr9-7490-729/linux-3.10.107/drivers/tty/serial/msm_serial.c 2021-11-10 11:53:55.000000000 +0000 @@ -39,932 +39,1195 @@ #include "msm_serial.h" -struct msm_port { - struct uart_port uart; - char name[16]; - struct clk *clk; - struct clk *pclk; - unsigned int imr; - unsigned int *gsbi_base; - int is_uartdm; - unsigned int old_snap_state; +enum +{ + UARTDM_1P1 = 1, + UARTDM_1P2, + UARTDM_1P3, + UARTDM_1P4, }; -static inline void wait_for_xmitr(struct uart_port *port, int bits) +struct msm_port { - if (!(msm_read(port, UART_SR) & UART_SR_TX_EMPTY)) - while ((msm_read(port, UART_ISR) & bits) != bits) - cpu_relax(); + struct uart_port uart; + char name[16]; + struct clk *clk; + struct clk *pclk; + unsigned int imr; + int is_uartdm; + unsigned int old_snap_state; + u32 slop; + int count; + bool break_detected; +}; + +#if defined(CONFIG_AVM_ENHANCED) +static struct uart_port *dectuart_port; +#endif/*--- #if defined(CONFIG_AVM_ENHANCED) ---*/ + +static inline void wait_for_xmitr(struct uart_port *port) +{ + while(!(msm_read(port, UART_SR) & UART_SR_TX_EMPTY)){ + if(msm_read(port, UART_ISR) & UART_ISR_TX_READY) + break; + udelay(1); + } + msm_write(port, UART_CR_CMD_RESET_TX_READY, UART_CR); } static void msm_stop_tx(struct uart_port *port) { - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = UART_TO_MSM(port); - msm_port->imr &= ~UART_IMR_TXLEV; - msm_write(port, msm_port->imr, UART_IMR); + msm_port->imr &= ~UART_IMR_TXLEV; + msm_write(port, msm_port->imr, UART_IMR); } static void msm_start_tx(struct uart_port *port) { - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = UART_TO_MSM(port); - msm_port->imr |= UART_IMR_TXLEV; - msm_write(port, msm_port->imr, UART_IMR); + msm_port->imr |= UART_IMR_TXLEV; + msm_write(port, msm_port->imr, UART_IMR); } static void msm_stop_rx(struct uart_port *port) { - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = UART_TO_MSM(port); - msm_port->imr &= ~(UART_IMR_RXLEV | UART_IMR_RXSTALE); - msm_write(port, msm_port->imr, UART_IMR); + msm_port->imr &= ~(UART_IMR_RXLEV | UART_IMR_RXSTALE); + msm_write(port, msm_port->imr, UART_IMR); } static void msm_enable_ms(struct uart_port *port) { - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = UART_TO_MSM(port); - msm_port->imr |= UART_IMR_DELTA_CTS; - msm_write(port, msm_port->imr, UART_IMR); + msm_port->imr |= UART_IMR_DELTA_CTS; + msm_write(port, msm_port->imr, UART_IMR); } static void handle_rx_dm(struct uart_port *port, unsigned int misr) { - struct tty_port *tport = &port->state->port; - unsigned int sr; - int count = 0; - struct msm_port *msm_port = UART_TO_MSM(port); - - if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) { - port->icount.overrun++; - tty_insert_flip_char(tport, 0, TTY_OVERRUN); - msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR); - } - - if (misr & UART_IMR_RXSTALE) { - count = msm_read(port, UARTDM_RX_TOTAL_SNAP) - - msm_port->old_snap_state; - msm_port->old_snap_state = 0; - } else { - count = 4 * (msm_read(port, UART_RFWR)); - msm_port->old_snap_state += count; - } - - /* TODO: Precise error reporting */ - - port->icount.rx += count; - - while (count > 0) { - unsigned int c; - - sr = msm_read(port, UART_SR); - if ((sr & UART_SR_RX_READY) == 0) { - msm_port->old_snap_state -= count; - break; - } - c = msm_read(port, UARTDM_RF); - if (sr & UART_SR_RX_BREAK) { - port->icount.brk++; - if (uart_handle_break(port)) - continue; - } else if (sr & UART_SR_PAR_FRAME_ERR) - port->icount.frame++; - - /* TODO: handle sysrq */ - tty_insert_flip_string(tport, (char *)&c, - (count > 4) ? 4 : count); - count -= 4; - } - - tty_flip_buffer_push(tport); - if (misr & (UART_IMR_RXSTALE)) - msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR); - msm_write(port, 0xFFFFFF, UARTDM_DMRX); - msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR); + struct tty_port *tport; + struct msm_port *msm_port; + unsigned int sr; + int count, i, r_count, sysrq; + unsigned char buf[4]; + char flag; + + count = 0; + tport = &port->state->port; + msm_port = UART_TO_MSM(port); + + if((msm_read(port, UART_SR) & UART_SR_OVERRUN)){ + port->icount.overrun++; + tty_insert_flip_char(tport, 0, TTY_OVERRUN); + msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR); + } + + if(misr & UART_IMR_RXSTALE){ + count = msm_read(port, UARTDM_RX_TOTAL_SNAP) - + msm_port->old_snap_state; + + msm_port->old_snap_state = 0; + }else{ + count = 4 * (msm_read(port, UART_RFWR)); + msm_port->old_snap_state += count; + } + + /* TODO: Precise error reporting */ + + port->icount.rx += count; + + while(count > 0){ + + sr = msm_read(port, UART_SR); + if((sr & UART_SR_RX_READY) == 0){ + msm_port->old_snap_state -= count; + break; + } + + ioread32_rep(port->membase + UARTDM_RF, buf, 1); + r_count = min_t(int, count, sizeof(buf)); + + flag = TTY_NORMAL; + for(i = 0; i < r_count; ++i){ + if(msm_port->break_detected && buf[i] == 0){ + port->icount.brk++; + flag = TTY_BREAK; + msm_port->break_detected = false; + + if(uart_handle_break(port)){ + continue; + } + } + + if(!(port->read_status_mask & UART_SR_RX_BREAK)){ + flag = TTY_NORMAL; + } + + spin_unlock(&port->lock); + sysrq = uart_handle_sysrq_char(port, buf[i]); + spin_lock(&port->lock); + if(!sysrq){ + tty_insert_flip_char(tport, buf[i], flag); + } + } + + count -= r_count; + } + + spin_unlock(&port->lock); + tty_flip_buffer_push(tport); + spin_lock(&port->lock); + + if(misr & UART_IMR_RXSTALE){ + msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR); + } + msm_write(port, 0xFFFFFF, UARTDM_DMRX); + msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR); } static void handle_rx(struct uart_port *port) { - struct tty_port *tport = &port->state->port; - unsigned int sr; + struct tty_port *tport = &port->state->port; + unsigned int sr, sysrq; - /* - * Handle overrun. My understanding of the hardware is that overrun - * is not tied to the RX buffer, so we handle the case out of band. - */ - if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) { - port->icount.overrun++; - tty_insert_flip_char(tport, 0, TTY_OVERRUN); - msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR); - } - - /* and now the main RX loop */ - while ((sr = msm_read(port, UART_SR)) & UART_SR_RX_READY) { - unsigned int c; - char flag = TTY_NORMAL; - - c = msm_read(port, UART_RF); - - if (sr & UART_SR_RX_BREAK) { - port->icount.brk++; - if (uart_handle_break(port)) - continue; - } else if (sr & UART_SR_PAR_FRAME_ERR) { - port->icount.frame++; - } else { - port->icount.rx++; - } - - /* Mask conditions we're ignorning. */ - sr &= port->read_status_mask; - - if (sr & UART_SR_RX_BREAK) { - flag = TTY_BREAK; - } else if (sr & UART_SR_PAR_FRAME_ERR) { - flag = TTY_FRAME; - } - - if (!uart_handle_sysrq_char(port, c)) - tty_insert_flip_char(tport, c, flag); - } - - tty_flip_buffer_push(tport); -} - -static void reset_dm_count(struct uart_port *port) -{ - wait_for_xmitr(port, UART_ISR_TX_READY); - msm_write(port, 1, UARTDM_NCF_TX); + /* + * Handle overrun. My understanding of the hardware is that overrun + * is not tied to the RX buffer, so we handle the case out of band. + */ + if((msm_read(port, UART_SR) & UART_SR_OVERRUN)){ + port->icount.overrun++; + tty_insert_flip_char(tport, 0, TTY_OVERRUN); + msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR); + } + + /* and now the main RX loop */ + while((sr = msm_read(port, UART_SR)) & UART_SR_RX_READY){ + unsigned int c; + char flag = TTY_NORMAL; + + c = msm_read(port, UART_RF); + + if(sr & UART_SR_RX_BREAK){ + port->icount.brk++; + if(uart_handle_break(port)) + continue; + }else if(sr & UART_SR_PAR_FRAME_ERR){ + port->icount.frame++; + }else{ + port->icount.rx++; + } + + /* Mask conditions we're ignorning. */ + sr &= port->read_status_mask; + + if(sr & UART_SR_RX_BREAK){ + flag = TTY_BREAK; + }else if(sr & UART_SR_PAR_FRAME_ERR){ + flag = TTY_FRAME; + } + + spin_unlock(&port->lock); + sysrq = uart_handle_sysrq_char(port, c); + spin_lock(&port->lock); + + if(!sysrq){ + tty_insert_flip_char(tport, c, flag); + } + } + + spin_unlock(&port->lock); + tty_flip_buffer_push(tport); + spin_lock(&port->lock); +} + +static void reset_dm_count(struct uart_port *port, int count) +{ + wait_for_xmitr(port); + msm_write(port, count, UARTDM_NCF_TX); + msm_read(port, UARTDM_NCF_TX); } static void handle_tx(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; - struct msm_port *msm_port = UART_TO_MSM(port); - int sent_tx; - - if (port->x_char) { - if (msm_port->is_uartdm) - reset_dm_count(port); - - msm_write(port, port->x_char, - msm_port->is_uartdm ? UARTDM_TF : UART_TF); - port->icount.tx++; - port->x_char = 0; - } - - if (msm_port->is_uartdm) - reset_dm_count(port); - - while (msm_read(port, UART_SR) & UART_SR_TX_READY) { - if (uart_circ_empty(xmit)) { - /* disable tx interrupts */ - msm_port->imr &= ~UART_IMR_TXLEV; - msm_write(port, msm_port->imr, UART_IMR); - break; - } - msm_write(port, xmit->buf[xmit->tail], - msm_port->is_uartdm ? UARTDM_TF : UART_TF); - - if (msm_port->is_uartdm) - reset_dm_count(port); - - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - sent_tx = 1; - } + struct circ_buf *xmit = &port->state->xmit; + struct msm_port *msm_port = UART_TO_MSM(port); + unsigned int tx_count, num_chars; + unsigned int tf_pointer = 0; + + tx_count = uart_circ_chars_pending(xmit); + tx_count = min3(tx_count, (unsigned int)UART_XMIT_SIZE - xmit->tail, + port->fifosize); + + if(port->x_char){ + if(msm_port->is_uartdm) + reset_dm_count(port, tx_count + 1); + + msm_write(port, port->x_char, + msm_port->is_uartdm ? UARTDM_TF : UART_TF); + port->icount.tx++; + port->x_char = 0; + }else if(tx_count && msm_port->is_uartdm){ + reset_dm_count(port, tx_count); + } + + while(tf_pointer < tx_count){ + int i; + char buf[4] = { 0 }; + unsigned int *bf = (unsigned int *) &buf; + + if(!(msm_read(port, UART_SR) & UART_SR_TX_READY)) + break; + + if(msm_port->is_uartdm) + num_chars = min(tx_count - tf_pointer, + (unsigned int )sizeof(buf)); + else + num_chars = 1; + + for(i = 0; i < num_chars; i++){ + buf[i] = xmit->buf[xmit->tail + i]; + port->icount.tx++; + } + + msm_write(port, *bf, msm_port->is_uartdm ? UARTDM_TF : UART_TF); + xmit->tail = (xmit->tail + num_chars) & (UART_XMIT_SIZE - 1); + tf_pointer += num_chars; + } + + /* disable tx interrupts if nothing more to send */ + if(uart_circ_empty(xmit)) + msm_stop_tx(port); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); + if(uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); } static void handle_delta_cts(struct uart_port *port) { - msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR); - port->icount.cts++; - wake_up_interruptible(&port->state->port.delta_msr_wait); + msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR); + port->icount.cts++; + wake_up_interruptible(&port->state->port.delta_msr_wait); } static irqreturn_t msm_irq(int irq, void *dev_id) { - struct uart_port *port = dev_id; - struct msm_port *msm_port = UART_TO_MSM(port); - unsigned int misr; - - spin_lock(&port->lock); - misr = msm_read(port, UART_MISR); - msm_write(port, 0, UART_IMR); /* disable interrupt */ - - if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE)) { - if (msm_port->is_uartdm) - handle_rx_dm(port, misr); - else - handle_rx(port); - } - if (misr & UART_IMR_TXLEV) - handle_tx(port); - if (misr & UART_IMR_DELTA_CTS) - handle_delta_cts(port); + struct uart_port *port = dev_id; + struct msm_port *msm_port = UART_TO_MSM(port); + unsigned int misr; + + spin_lock(&port->lock); + misr = msm_read(port, UART_MISR); + msm_write(port, 0, UART_IMR); /* disable interrupt */ + + if(misr & UART_IMR_RXBREAK_START){ + msm_port->break_detected = true; + msm_write(port, UART_CR_CMD_RESET_RXBREAK_START, UART_CR); + } + + if(misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE)){ + if(msm_port->is_uartdm) + handle_rx_dm(port, misr); + else + handle_rx(port); + } + if(misr & UART_IMR_TXLEV) + handle_tx(port); + if(misr & UART_IMR_DELTA_CTS) + handle_delta_cts(port); - msm_write(port, msm_port->imr, UART_IMR); /* restore interrupt */ - spin_unlock(&port->lock); + msm_write(port, msm_port->imr, UART_IMR); /* restore interrupt */ + spin_unlock(&port->lock); - return IRQ_HANDLED; + return IRQ_HANDLED; } static unsigned int msm_tx_empty(struct uart_port *port) { - return (msm_read(port, UART_SR) & UART_SR_TX_EMPTY) ? TIOCSER_TEMT : 0; + return (msm_read(port, UART_SR) & UART_SR_TX_EMPTY) ? TIOCSER_TEMT : 0; } static unsigned int msm_get_mctrl(struct uart_port *port) { - return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR | TIOCM_RTS; + return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR | TIOCM_RTS; } - static void msm_reset(struct uart_port *port) { - /* reset everything */ - msm_write(port, UART_CR_CMD_RESET_RX, UART_CR); - msm_write(port, UART_CR_CMD_RESET_TX, UART_CR); - msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR); - msm_write(port, UART_CR_CMD_RESET_BREAK_INT, UART_CR); - msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR); - msm_write(port, UART_CR_CMD_SET_RFR, UART_CR); -} - -void msm_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - unsigned int mr; - mr = msm_read(port, UART_MR1); - - if (!(mctrl & TIOCM_RTS)) { - mr &= ~UART_MR1_RX_RDY_CTL; - msm_write(port, mr, UART_MR1); - msm_write(port, UART_CR_CMD_RESET_RFR, UART_CR); - } else { - mr |= UART_MR1_RX_RDY_CTL; - msm_write(port, mr, UART_MR1); - } + struct msm_port *msm_port = UART_TO_MSM(port); + + /* reset everything */ + msm_write(port, UART_CR_CMD_RESET_RX, UART_CR); + msm_write(port, UART_CR_CMD_RESET_TX, UART_CR); + msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR); + msm_write(port, UART_CR_CMD_RESET_BREAK_INT, UART_CR); + msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR); + msm_write(port, UART_CR_CMD_SET_RFR, UART_CR); + + /* Disable DM modes */ + if(msm_port->is_uartdm) + msm_write(port, 0, UARTDM_DMEN); +} + +static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + unsigned int mr; + mr = msm_read(port, UART_MR1); + + if(!(mctrl & TIOCM_RTS)){ + mr &= ~UART_MR1_RX_RDY_CTL; + msm_write(port, mr, UART_MR1); + msm_write(port, UART_CR_CMD_RESET_RFR, UART_CR); + }else{ + mr |= UART_MR1_RX_RDY_CTL; + msm_write(port, mr, UART_MR1); + } } static void msm_break_ctl(struct uart_port *port, int break_ctl) { - if (break_ctl) - msm_write(port, UART_CR_CMD_START_BREAK, UART_CR); - else - msm_write(port, UART_CR_CMD_STOP_BREAK, UART_CR); + if(break_ctl) + msm_write(port, UART_CR_CMD_START_BREAK, UART_CR); + else + msm_write(port, UART_CR_CMD_STOP_BREAK, UART_CR); } -static int msm_set_baud_rate(struct uart_port *port, unsigned int baud) +struct msm_baud_map { - unsigned int baud_code, rxstale, watermark; - struct msm_port *msm_port = UART_TO_MSM(port); + u16 divisor; + u8 code; + u8 rxstale; +}; - switch (baud) { - case 300: - baud_code = UART_CSR_300; - rxstale = 1; - break; - case 600: - baud_code = UART_CSR_600; - rxstale = 1; - break; - case 1200: - baud_code = UART_CSR_1200; - rxstale = 1; - break; - case 2400: - baud_code = UART_CSR_2400; - rxstale = 1; - break; - case 4800: - baud_code = UART_CSR_4800; - rxstale = 1; - break; - case 9600: - baud_code = UART_CSR_9600; - rxstale = 2; - break; - case 14400: - baud_code = UART_CSR_14400; - rxstale = 3; - break; - case 19200: - baud_code = UART_CSR_19200; - rxstale = 4; - break; - case 28800: - baud_code = UART_CSR_28800; - rxstale = 6; - break; - case 38400: - baud_code = UART_CSR_38400; - rxstale = 8; - break; - case 57600: - baud_code = UART_CSR_57600; - rxstale = 16; - break; - case 115200: - default: - baud_code = UART_CSR_115200; - baud = 115200; - rxstale = 31; - break; - } - - if (msm_port->is_uartdm) - msm_write(port, UART_CR_CMD_RESET_RX, UART_CR); - - msm_write(port, baud_code, UART_CSR); - - /* RX stale watermark */ - watermark = UART_IPR_STALE_LSB & rxstale; - watermark |= UART_IPR_RXSTALE_LAST; - watermark |= UART_IPR_STALE_TIMEOUT_MSB & (rxstale << 2); - msm_write(port, watermark, UART_IPR); - - /* set RX watermark */ - watermark = (port->fifosize * 3) / 4; - msm_write(port, watermark, UART_RFWR); - - /* set TX watermark */ - msm_write(port, 10, UART_TFWR); - - if (msm_port->is_uartdm) { - msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR); - msm_write(port, 0xFFFFFF, UARTDM_DMRX); - msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR); - } +static const struct msm_baud_map * +msm_find_best_baud(struct uart_port *port, unsigned int baud) +{ + unsigned int i, divisor; + const struct msm_baud_map *entry; + static const struct msm_baud_map table[] = { + { 1536, 0x00, 1 }, + { 768, 0x11, 1 }, + { 384, 0x22, 1 }, + { 192, 0x33, 1 }, + { 96, 0x44, 1 }, + { 48, 0x55, 1 }, + { 32, 0x66, 1 }, + { 24, 0x77, 1 }, + { 16, 0x88, 1 }, + { 12, 0x99, 6 }, + { 8, 0xaa, 6 }, + { 6, 0xbb, 6 }, + { 4, 0xcc, 6 }, + { 3, 0xdd, 8 }, + { 2, 0xee, 16 }, + { 1, 0xff, 31 }, + }; + + divisor = uart_get_divisor(port, baud); + + for(i = 0, entry = table; i < ARRAY_SIZE(table); i++, entry++) + if(entry->divisor <= divisor) + break; - return baud; + return entry; /* Default to smallest divider */ } +static int msm_set_baud_rate(struct uart_port *port, unsigned int baud) +{ + unsigned int rxstale, watermark; + struct msm_port *msm_port = UART_TO_MSM(port); + const struct msm_baud_map *entry; + + entry = msm_find_best_baud(port, baud); + + if(msm_port->is_uartdm) + msm_write(port, UART_CR_CMD_RESET_RX, UART_CR); + + msm_write(port, entry->code, UART_CSR); + + /* RX stale watermark */ + rxstale = entry->rxstale; + watermark = UART_IPR_STALE_LSB & rxstale; + watermark |= UART_IPR_RXSTALE_LAST; + watermark |= UART_IPR_STALE_TIMEOUT_MSB & (rxstale << 2); + msm_write(port, watermark, UART_IPR); + + /* set RX watermark */ + watermark = (port->fifosize * 3) / 4; + msm_write(port, watermark, UART_RFWR); + + /* set TX watermark */ + /*--- important fix (avm): generate tx-irq only when tx-fifo empty because filling barrier with reset_dm_count() -> wait_for_xmitr() makes waste-time in irq !! ---*/ + msm_write(port, 0, UART_TFWR); + + msm_write(port, UART_CR_CMD_PROTECTION_EN, UART_CR); + msm_reset(port); + + /* Enable RX and TX */ + msm_write(port, UART_CR_TX_ENABLE | UART_CR_RX_ENABLE, UART_CR); + + /* turn on RX and CTS interrupts */ + msm_port->imr = UART_IMR_RXLEV | UART_IMR_RXSTALE | + UART_IMR_CURRENT_CTS | UART_IMR_RXBREAK_START; + + msm_write(port, msm_port->imr, UART_IMR); + + if(msm_port->is_uartdm){ + msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR); + msm_write(port, 0xFFFFFF, UARTDM_DMRX); + msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR); + } + + return baud; +} static void msm_init_clock(struct uart_port *port) { - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = UART_TO_MSM(port); - clk_enable(msm_port->clk); - if (!IS_ERR(msm_port->pclk)) - clk_enable(msm_port->pclk); - msm_serial_set_mnd_regs(port); + clk_prepare_enable(msm_port->clk); + clk_prepare_enable(msm_port->pclk); + msm_serial_set_mnd_regs(port); } static int msm_startup(struct uart_port *port) { - struct msm_port *msm_port = UART_TO_MSM(port); - unsigned int data, rfr_level; - int ret; - - snprintf(msm_port->name, sizeof(msm_port->name), - "msm_serial%d", port->line); - - ret = request_irq(port->irq, msm_irq, IRQF_TRIGGER_HIGH, - msm_port->name, port); - if (unlikely(ret)) - return ret; - - msm_init_clock(port); - - if (likely(port->fifosize > 12)) - rfr_level = port->fifosize - 12; - else - rfr_level = port->fifosize; - - /* set automatic RFR level */ - data = msm_read(port, UART_MR1); - data &= ~UART_MR1_AUTO_RFR_LEVEL1; - data &= ~UART_MR1_AUTO_RFR_LEVEL0; - data |= UART_MR1_AUTO_RFR_LEVEL1 & (rfr_level << 2); - data |= UART_MR1_AUTO_RFR_LEVEL0 & rfr_level; - msm_write(port, data, UART_MR1); - - /* make sure that RXSTALE count is non-zero */ - data = msm_read(port, UART_IPR); - if (unlikely(!data)) { - data |= UART_IPR_RXSTALE_LAST; - data |= UART_IPR_STALE_LSB; - msm_write(port, data, UART_IPR); - } - - data = 0; - if (!port->cons || (port->cons && !(port->cons->flags & CON_ENABLED))) { - msm_write(port, UART_CR_CMD_PROTECTION_EN, UART_CR); - msm_reset(port); - data = UART_CR_TX_ENABLE; - } - - data |= UART_CR_RX_ENABLE; - msm_write(port, data, UART_CR); /* enable TX & RX */ - - /* Make sure IPR is not 0 to start with*/ - if (msm_port->is_uartdm) - msm_write(port, UART_IPR_STALE_LSB, UART_IPR); - - /* turn on RX and CTS interrupts */ - msm_port->imr = UART_IMR_RXLEV | UART_IMR_RXSTALE | - UART_IMR_CURRENT_CTS; - - if (msm_port->is_uartdm) { - msm_write(port, 0xFFFFFF, UARTDM_DMRX); - msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR); - msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR); - } + struct msm_port *msm_port = UART_TO_MSM(port); + unsigned int data, rfr_level; + int ret; + + snprintf(msm_port->name, sizeof(msm_port->name), + "msm_serial%d", port->line); + + ret = request_irq(port->irq, msm_irq, IRQF_TRIGGER_HIGH, + msm_port->name, port); + if(unlikely(ret)) + return ret; + + msm_init_clock(port); + + if(likely(port->fifosize > 12)) + rfr_level = port->fifosize - 12; + else + rfr_level = port->fifosize; + + /* set automatic RFR level */ + data = msm_read(port, UART_MR1); + data &= ~UART_MR1_AUTO_RFR_LEVEL1; + data &= ~UART_MR1_AUTO_RFR_LEVEL0; + data |= UART_MR1_AUTO_RFR_LEVEL1 & (rfr_level << 2); + data |= UART_MR1_AUTO_RFR_LEVEL0 & rfr_level; + msm_write(port, data, UART_MR1); + + /* make sure that RXSTALE count is non-zero */ + data = msm_read(port, UART_IPR); + if(unlikely(!data)){ + data |= UART_IPR_RXSTALE_LAST; + data |= UART_IPR_STALE_LSB; + msm_write(port, data, UART_IPR); + } + + data = 0; + if(!port->cons || (port->cons && !(port->cons->flags & CON_ENABLED))){ + msm_write(port, UART_CR_CMD_PROTECTION_EN, UART_CR); + msm_reset(port); + data = UART_CR_TX_ENABLE; + } + + data |= UART_CR_RX_ENABLE; + msm_write(port, data, UART_CR); /* enable TX & RX */ + + /* Make sure IPR is not 0 to start with*/ + if(msm_port->is_uartdm) + msm_write(port, UART_IPR_STALE_LSB, UART_IPR); + + /* turn on RX and CTS interrupts */ + msm_port->imr = UART_IMR_RXLEV | UART_IMR_RXSTALE | + UART_IMR_CURRENT_CTS; + + if(msm_port->is_uartdm){ + msm_write(port, 0xFFFFFF, UARTDM_DMRX); + msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR); + msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR); + } + + msm_write(port, msm_port->imr, UART_IMR); - msm_write(port, msm_port->imr, UART_IMR); - return 0; + return 0; } static void msm_shutdown(struct uart_port *port) { - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = UART_TO_MSM(port); - msm_port->imr = 0; - msm_write(port, 0, UART_IMR); /* disable interrupts */ + msm_port->imr = 0; + msm_write(port, 0, UART_IMR); /* disable interrupts */ - clk_disable(msm_port->clk); + clk_disable_unprepare(msm_port->clk); - free_irq(port->irq, port); + free_irq(port->irq, port); } static void msm_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + struct ktermios *old) { - unsigned long flags; - unsigned int baud, mr; + unsigned long flags; + unsigned int baud, mr; - spin_lock_irqsave(&port->lock, flags); + spin_lock_irqsave(&port->lock, flags); - /* calculate and set baud rate */ - baud = uart_get_baud_rate(port, termios, old, 300, 115200); - baud = msm_set_baud_rate(port, baud); - if (tty_termios_baud_rate(termios)) - tty_termios_encode_baud_rate(termios, baud, baud); - - /* calculate parity */ - mr = msm_read(port, UART_MR2); - mr &= ~UART_MR2_PARITY_MODE; - if (termios->c_cflag & PARENB) { - if (termios->c_cflag & PARODD) - mr |= UART_MR2_PARITY_MODE_ODD; - else if (termios->c_cflag & CMSPAR) - mr |= UART_MR2_PARITY_MODE_SPACE; - else - mr |= UART_MR2_PARITY_MODE_EVEN; - } - - /* calculate bits per char */ - mr &= ~UART_MR2_BITS_PER_CHAR; - switch (termios->c_cflag & CSIZE) { - case CS5: - mr |= UART_MR2_BITS_PER_CHAR_5; - break; - case CS6: - mr |= UART_MR2_BITS_PER_CHAR_6; - break; - case CS7: - mr |= UART_MR2_BITS_PER_CHAR_7; - break; - case CS8: - default: - mr |= UART_MR2_BITS_PER_CHAR_8; - break; - } - - /* calculate stop bits */ - mr &= ~(UART_MR2_STOP_BIT_LEN_ONE | UART_MR2_STOP_BIT_LEN_TWO); - if (termios->c_cflag & CSTOPB) - mr |= UART_MR2_STOP_BIT_LEN_TWO; - else - mr |= UART_MR2_STOP_BIT_LEN_ONE; - - /* set parity, bits per char, and stop bit */ - msm_write(port, mr, UART_MR2); - - /* calculate and set hardware flow control */ - mr = msm_read(port, UART_MR1); - mr &= ~(UART_MR1_CTS_CTL | UART_MR1_RX_RDY_CTL); - if (termios->c_cflag & CRTSCTS) { - mr |= UART_MR1_CTS_CTL; - mr |= UART_MR1_RX_RDY_CTL; - } - msm_write(port, mr, UART_MR1); - - /* Configure status bits to ignore based on termio flags. */ - port->read_status_mask = 0; - if (termios->c_iflag & INPCK) - port->read_status_mask |= UART_SR_PAR_FRAME_ERR; - if (termios->c_iflag & (BRKINT | PARMRK)) - port->read_status_mask |= UART_SR_RX_BREAK; + /* calculate and set baud rate */ + baud = uart_get_baud_rate(port, termios, old, 300, 115200); + baud = msm_set_baud_rate(port, baud); + if(tty_termios_baud_rate(termios)) + tty_termios_encode_baud_rate(termios, baud, baud); + + /* calculate parity */ + mr = msm_read(port, UART_MR2); + mr &= ~UART_MR2_PARITY_MODE; + if(termios->c_cflag & PARENB){ + if(termios->c_cflag & PARODD) + mr |= UART_MR2_PARITY_MODE_ODD; + else if(termios->c_cflag & CMSPAR) + mr |= UART_MR2_PARITY_MODE_SPACE; + else + mr |= UART_MR2_PARITY_MODE_EVEN; + } + + /* calculate bits per char */ + mr &= ~UART_MR2_BITS_PER_CHAR; + switch(termios->c_cflag & CSIZE){ + case CS5: + mr |= UART_MR2_BITS_PER_CHAR_5; + break; + case CS6: + mr |= UART_MR2_BITS_PER_CHAR_6; + break; + case CS7: + mr |= UART_MR2_BITS_PER_CHAR_7; + break; + case CS8: + default: + mr |= UART_MR2_BITS_PER_CHAR_8; + break; + } + + /* calculate stop bits */ + mr &= ~(UART_MR2_STOP_BIT_LEN_ONE | UART_MR2_STOP_BIT_LEN_TWO); + if(termios->c_cflag & CSTOPB) + mr |= UART_MR2_STOP_BIT_LEN_TWO; + else + mr |= UART_MR2_STOP_BIT_LEN_ONE; + + /* set parity, bits per char, and stop bit */ + msm_write(port, mr, UART_MR2); + + /* calculate and set hardware flow control */ + mr = msm_read(port, UART_MR1); + mr &= ~(UART_MR1_CTS_CTL | UART_MR1_RX_RDY_CTL); + if(termios->c_cflag & CRTSCTS){ + mr |= UART_MR1_CTS_CTL; + mr |= UART_MR1_RX_RDY_CTL; + } + msm_write(port, mr, UART_MR1); + + /* Configure status bits to ignore based on termio flags. */ + port->read_status_mask = 0; + if(termios->c_iflag & INPCK) + port->read_status_mask |= UART_SR_PAR_FRAME_ERR; + if(termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) + port->read_status_mask |= UART_SR_RX_BREAK; - uart_update_timeout(port, termios->c_cflag, baud); + uart_update_timeout(port, termios->c_cflag, baud); - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock_irqrestore(&port->lock, flags); } static const char *msm_type(struct uart_port *port) { - return "MSM"; + return "MSM"; } static void msm_release_port(struct uart_port *port) { - struct platform_device *pdev = to_platform_device(port->dev); - struct msm_port *msm_port = UART_TO_MSM(port); - struct resource *uart_resource; - struct resource *gsbi_resource; - resource_size_t size; - - uart_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (unlikely(!uart_resource)) - return; - size = resource_size(uart_resource); - - release_mem_region(port->mapbase, size); - iounmap(port->membase); - port->membase = NULL; - - if (msm_port->gsbi_base) { - iowrite32(GSBI_PROTOCOL_IDLE, msm_port->gsbi_base + - GSBI_CONTROL); - - gsbi_resource = platform_get_resource(pdev, - IORESOURCE_MEM, 1); - - if (unlikely(!gsbi_resource)) - return; - - size = resource_size(gsbi_resource); - release_mem_region(gsbi_resource->start, size); - iounmap(msm_port->gsbi_base); - msm_port->gsbi_base = NULL; - } + struct platform_device *pdev = to_platform_device(port->dev); + struct resource *uart_resource; + resource_size_t size; + + uart_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if(unlikely(!uart_resource)) + return; + size = resource_size(uart_resource); + + release_mem_region(port->mapbase, size); + iounmap(port->membase); + port->membase = NULL; } static int msm_request_port(struct uart_port *port) { - struct msm_port *msm_port = UART_TO_MSM(port); - struct platform_device *pdev = to_platform_device(port->dev); - struct resource *uart_resource; - struct resource *gsbi_resource; - resource_size_t size; - int ret; - - uart_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (unlikely(!uart_resource)) - return -ENXIO; - - size = resource_size(uart_resource); - - if (!request_mem_region(port->mapbase, size, "msm_serial")) - return -EBUSY; - - port->membase = ioremap(port->mapbase, size); - if (!port->membase) { - ret = -EBUSY; - goto fail_release_port; - } - - gsbi_resource = platform_get_resource(pdev, IORESOURCE_MEM, 1); - /* Is this a GSBI-based port? */ - if (gsbi_resource) { - size = resource_size(gsbi_resource); - - if (!request_mem_region(gsbi_resource->start, size, - "msm_serial")) { - ret = -EBUSY; - goto fail_release_port; - } - - msm_port->gsbi_base = ioremap(gsbi_resource->start, size); - if (!msm_port->gsbi_base) { - ret = -EBUSY; - goto fail_release_gsbi; - } - } - - return 0; - -fail_release_gsbi: - release_mem_region(gsbi_resource->start, size); -fail_release_port: - release_mem_region(port->mapbase, size); - return ret; + struct platform_device *pdev = to_platform_device(port->dev); + struct resource *uart_resource; + resource_size_t size; + int ret; + + uart_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if(unlikely(!uart_resource)) + return -ENXIO; + + size = resource_size(uart_resource); + + if(!request_mem_region(port->mapbase, size, "msm_serial")) + return -EBUSY; + + port->membase = ioremap(port->mapbase, size); + if(!port->membase){ + ret = -EBUSY; + goto fail_release_port; + } + + return 0; + + fail_release_port: + release_mem_region(port->mapbase, size); + return ret; } static void msm_config_port(struct uart_port *port, int flags) { - struct msm_port *msm_port = UART_TO_MSM(port); - int ret; - if (flags & UART_CONFIG_TYPE) { - port->type = PORT_MSM; - ret = msm_request_port(port); - if (ret) - return; - } - - if (msm_port->is_uartdm) - iowrite32(GSBI_PROTOCOL_UART, msm_port->gsbi_base + - GSBI_CONTROL); + int ret; + if(flags & UART_CONFIG_TYPE){ + port->type = PORT_MSM; + ret = msm_request_port(port); + if(ret) + return; + } } static int msm_verify_port(struct uart_port *port, struct serial_struct *ser) { - if (unlikely(ser->type != PORT_UNKNOWN && ser->type != PORT_MSM)) - return -EINVAL; - if (unlikely(port->irq != ser->irq)) - return -EINVAL; - return 0; + if(unlikely(ser->type != PORT_UNKNOWN && ser->type != PORT_MSM)) + return -EINVAL; + if(unlikely(port->irq != ser->irq)) + return -EINVAL; + return 0; } static void msm_power(struct uart_port *port, unsigned int state, - unsigned int oldstate) + unsigned int oldstate) { - struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_port *msm_port = UART_TO_MSM(port); - switch (state) { - case 0: - clk_enable(msm_port->clk); - if (!IS_ERR(msm_port->pclk)) - clk_enable(msm_port->pclk); - break; - case 3: - clk_disable(msm_port->clk); - if (!IS_ERR(msm_port->pclk)) - clk_disable(msm_port->pclk); - break; - default: - printk(KERN_ERR "msm_serial: Unknown PM state %d\n", state); - } + switch(state){ + case 0: + clk_prepare_enable(msm_port->clk); + clk_prepare_enable(msm_port->pclk); + break; + case 3: + clk_disable_unprepare(msm_port->clk); + clk_disable_unprepare(msm_port->pclk); + break; + default: + printk(KERN_ERR "msm_serial: Unknown PM state %d\n", state); + } } -static struct uart_ops msm_uart_pops = { - .tx_empty = msm_tx_empty, - .set_mctrl = msm_set_mctrl, - .get_mctrl = msm_get_mctrl, - .stop_tx = msm_stop_tx, - .start_tx = msm_start_tx, - .stop_rx = msm_stop_rx, - .enable_ms = msm_enable_ms, - .break_ctl = msm_break_ctl, - .startup = msm_startup, - .shutdown = msm_shutdown, - .set_termios = msm_set_termios, - .type = msm_type, - .release_port = msm_release_port, - .request_port = msm_request_port, - .config_port = msm_config_port, - .verify_port = msm_verify_port, - .pm = msm_power, -}; +#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_AVM_ENHANCED) +static int msm_poll_init(struct uart_port *port) +{ + struct msm_port *msm_port = UART_TO_MSM(port); -static struct msm_port msm_uart_ports[] = { - { - .uart = { - .iotype = UPIO_MEM, - .ops = &msm_uart_pops, - .flags = UPF_BOOT_AUTOCONF, - .fifosize = 64, - .line = 0, - }, - }, - { - .uart = { - .iotype = UPIO_MEM, - .ops = &msm_uart_pops, - .flags = UPF_BOOT_AUTOCONF, - .fifosize = 64, - .line = 1, - }, - }, - { - .uart = { - .iotype = UPIO_MEM, - .ops = &msm_uart_pops, - .flags = UPF_BOOT_AUTOCONF, - .fifosize = 64, - .line = 2, - }, - }, -}; + /* Enable single character mode on RX FIFO */ + if(msm_port->is_uartdm >= UARTDM_1P4) + msm_write(port, UARTDM_DMEN_RX_SC_ENABLE, UARTDM_DMEN); -#define UART_NR ARRAY_SIZE(msm_uart_ports) + return 0; +} -static inline struct uart_port *get_port_from_line(unsigned int line) +static int msm_poll_get_char_single(struct uart_port *port) { - return &msm_uart_ports[line].uart; -} + struct msm_port *msm_port = UART_TO_MSM(port); + unsigned int rf_reg = msm_port->is_uartdm ? UARTDM_RF : UART_RF; -#ifdef CONFIG_SERIAL_MSM_CONSOLE + if(!(msm_read(port, UART_SR) & UART_SR_RX_READY)) + return NO_POLL_CHAR; + else + return msm_read(port, rf_reg) & 0xff; +} -static void msm_console_putchar(struct uart_port *port, int c) +static int msm_poll_get_char_dm_1p3(struct uart_port *port) { - struct msm_port *msm_port = UART_TO_MSM(port); + int c; + struct msm_port *msm_port = UART_TO_MSM(port); + unsigned char *sp = (unsigned char *) &msm_port->slop; - if (msm_port->is_uartdm) - reset_dm_count(port); + /* Check if a previous read had more than one char */ + if(msm_port->count){ + c = sp[sizeof(msm_port->slop) - msm_port->count]; + msm_port->count--; + /* Or if FIFO is empty */ + }else if(!(msm_read(port, UART_SR) & UART_SR_RX_READY)){ + /* + * If RX packing buffer has less than a word, force stale to + * push contents into RX FIFO + */ + msm_port->count = msm_read(port, UARTDM_RXFS); + msm_port->count = (msm_port->count >> UARTDM_RXFS_BUF_SHIFT) & UARTDM_RXFS_BUF_MASK; + if(msm_port->count){ + msm_write(port, UART_CR_CMD_FORCE_STALE, UART_CR); + msm_port->slop = msm_read(port, UARTDM_RF); + c = sp[0]; + msm_port->count--; + }else{ + c = NO_POLL_CHAR; + } + /* FIFO has a word */ + }else{ + msm_port->slop = msm_read(port, UARTDM_RF); + c = sp[0]; + msm_port->count = sizeof(msm_port->slop) - 1; + } - while (!(msm_read(port, UART_SR) & UART_SR_TX_READY)) - ; - msm_write(port, c, msm_port->is_uartdm ? UARTDM_TF : UART_TF); + return c; } -static void msm_console_write(struct console *co, const char *s, - unsigned int count) +static int msm_poll_get_char(struct uart_port *port) { - struct uart_port *port; - struct msm_port *msm_port; + u32 imr; + int c; + struct msm_port *msm_port = UART_TO_MSM(port); + + /* Disable all interrupts */ + imr = msm_read(port, UART_IMR); + msm_write(port, 0, UART_IMR); - BUG_ON(co->index < 0 || co->index >= UART_NR); + if(msm_port->is_uartdm == UARTDM_1P3) + c = msm_poll_get_char_dm_1p3(port); + else + c = msm_poll_get_char_single(port); - port = get_port_from_line(co->index); - msm_port = UART_TO_MSM(port); + /* Enable interrupts */ + msm_write(port, imr, UART_IMR); - spin_lock(&port->lock); - uart_console_write(port, s, count, msm_console_putchar); - spin_unlock(&port->lock); + return c; } -static int __init msm_console_setup(struct console *co, char *options) +static void msm_poll_put_char(struct uart_port *port, unsigned char c) { - struct uart_port *port; - struct msm_port *msm_port; - int baud, flow, bits, parity; + u32 imr; + struct msm_port *msm_port = UART_TO_MSM(port); - if (unlikely(co->index >= UART_NR || co->index < 0)) - return -ENXIO; + /* Disable all interrupts */ + imr = msm_read(port, UART_IMR); + msm_write(port, 0, UART_IMR); - port = get_port_from_line(co->index); - msm_port = UART_TO_MSM(port); + if(msm_port->is_uartdm) + reset_dm_count(port, 1); - if (unlikely(!port->membase)) - return -ENXIO; + /* Wait until FIFO is empty */ + while(!(msm_read(port, UART_SR) & UART_SR_TX_READY)) + cpu_relax(); - msm_init_clock(port); + /* Write a character */ + msm_write(port, c, msm_port->is_uartdm ? UARTDM_TF : UART_TF); - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); + /* Wait until FIFO is empty */ + while(!(msm_read(port, UART_SR) & UART_SR_TX_READY)) + cpu_relax(); - bits = 8; - parity = 'n'; - flow = 'n'; - msm_write(port, UART_MR2_BITS_PER_CHAR_8 | UART_MR2_STOP_BIT_LEN_ONE, - UART_MR2); /* 8N1 */ + /* Enable interrupts */ + msm_write(port, imr, UART_IMR); - if (baud < 300 || baud > 115200) - baud = 115200; - msm_set_baud_rate(port, baud); + return; +} +#endif +#if defined(CONFIG_AVM_ENHANCED) +/*--------------------------------------------------------------------------------*\ +\*--------------------------------------------------------------------------------*/ +int msm_dectuart_get_char(void) +{ + if(dectuart_port){ + return msm_poll_get_char(dectuart_port); + } + return -ENXIO; +} +EXPORT_SYMBOL(msm_dectuart_get_char); +/*--------------------------------------------------------------------------------*\ +\*--------------------------------------------------------------------------------*/ +void msm_dectuart_put_char(unsigned char c) +{ + if(dectuart_port){ + msm_poll_put_char(dectuart_port, c); + } +} +EXPORT_SYMBOL(msm_dectuart_put_char); + +/*--------------------------------------------------------------------------------*\ +\*--------------------------------------------------------------------------------*/ +void msm_dectuart_init(unsigned int baud) +{ + struct msm_port *msm_port; + struct uart_port *port = dectuart_port; + if(dectuart_port == NULL){ + return; + } + msm_port = UART_TO_MSM(port); + msm_poll_init(port); + + msm_init_clock(port); + msm_write(port, UART_MR2_BITS_PER_CHAR_8 | UART_MR2_STOP_BIT_LEN_ONE, UART_MR2); /* 8N1 */ + + if(baud < 300 || baud > 115200) + baud = 115200; + msm_set_baud_rate(port, baud); + + msm_reset(port); + + if(msm_port->is_uartdm){ + msm_write(port, UART_CR_CMD_PROTECTION_EN, UART_CR); + msm_write(port, UART_CR_TX_ENABLE, UART_CR); + } +#if 0 + printk(KERN_INFO "%s: setup on port #%d\n", __func__, port->line); + printk(KERN_ERR "%s: %p:MR1: %x %x\n MR2: %x %x\nSR : %x %x TFWR: %x %x RFWR: %x %x\nfifo=%d\n", + __func__, + msm_port->is_uartdm, + port->membase, UART_MR1, msm_read(port, UART_MR1), + UART_MR2, msm_read(port, UART_MR2), + UART_SR, msm_read(port, UART_SR), + UART_TFWR, msm_read(port, UART_TFWR), + UART_RFWR, msm_read(port, UART_RFWR), + port->fifosize + ); +#endif +} +EXPORT_SYMBOL(msm_dectuart_init); +/*--------------------------------------------------------------------------------*\ +\*--------------------------------------------------------------------------------*/ +void msm_dectuart_exit(void) +{ +} +EXPORT_SYMBOL(msm_dectuart_exit); +#endif/*--- #if defined(CONFIG_AVM_ENHANCED) ---*/ - msm_reset(port); +static struct uart_ops msm_uart_pops = { + .tx_empty = msm_tx_empty, + .set_mctrl = msm_set_mctrl, + .get_mctrl = msm_get_mctrl, + .stop_tx = msm_stop_tx, + .start_tx = msm_start_tx, + .stop_rx = msm_stop_rx, + .enable_ms = msm_enable_ms, + .break_ctl = msm_break_ctl, + .startup = msm_startup, + .shutdown = msm_shutdown, + .set_termios = msm_set_termios, + .type = msm_type, + .release_port = msm_release_port, + .request_port = msm_request_port, + .config_port = msm_config_port, + .verify_port = msm_verify_port, + .pm = msm_power, +#ifdef CONFIG_CONSOLE_POLL + .poll_init = msm_poll_init, + .poll_get_char = msm_poll_get_char, + .poll_put_char = msm_poll_put_char, +#endif + }; - if (msm_port->is_uartdm) { - msm_write(port, UART_CR_CMD_PROTECTION_EN, UART_CR); - msm_write(port, UART_CR_TX_ENABLE, UART_CR); - } +static struct msm_port msm_uart_ports[] = { + { + .uart = { + .iotype = UPIO_MEM, + .ops = &msm_uart_pops, + .flags = UPF_BOOT_AUTOCONF, + .fifosize = 64, + .line = 0, + }, + }, + { + .uart = { + .iotype = UPIO_MEM, + .ops = &msm_uart_pops, + .flags = UPF_BOOT_AUTOCONF, + .fifosize = 64, + .line = 1, + }, + }, + { + .uart = { + .iotype = UPIO_MEM, + .ops = &msm_uart_pops, + .flags = UPF_BOOT_AUTOCONF, + .fifosize = 64, + .line = 2, + }, + }, +}; - printk(KERN_INFO "msm_serial: console setup on port #%d\n", port->line); +#define UART_NR ARRAY_SIZE(msm_uart_ports) - return uart_set_options(port, co, baud, parity, bits, flow); +static inline struct uart_port *get_port_from_line(unsigned int line) +{ + return &msm_uart_ports[line].uart; } -static struct uart_driver msm_uart_driver; +#ifdef CONFIG_SERIAL_MSM_CONSOLE +static void msm_console_write(struct console *co, const char *s, + unsigned int count) +{ + int i; + struct uart_port *port; + struct msm_port *msm_port; + int num_newlines = 0; + bool replaced = false; + + BUG_ON(co->index < 0 || co->index >= UART_NR); + + port = get_port_from_line(co->index); + msm_port = UART_TO_MSM(port); + + /* Account for newlines that will get a carriage return added */ + for(i = 0; i < count; i++) + if(s[i] == '\n') + num_newlines++; + count += num_newlines; + + spin_lock(&port->lock); + if(msm_port->is_uartdm) + reset_dm_count(port, count); + + i = 0; + while(i < count){ + int j; + unsigned int num_chars; + char buf[4] = { 0 }; + unsigned int *bf = (unsigned int *) &buf; + + if(msm_port->is_uartdm) + num_chars = min(count - i, (unsigned int )sizeof(buf)); + else + num_chars = 1; + + for(j = 0; j < num_chars; j++){ + char c = *s; + + if(c == '\n' && !replaced){ + buf[j] = '\r'; + j++; + replaced = true; + } + if(j < num_chars){ + buf[j] = c; + s++; + replaced = false; + } + } + + while(!(msm_read(port, UART_SR) & UART_SR_TX_READY)) + cpu_relax(); + + msm_write(port, *bf, msm_port->is_uartdm ? UARTDM_TF : UART_TF); + i += num_chars; + } + spin_unlock(&port->lock); +} -static struct console msm_console = { - .name = "ttyMSM", - .write = msm_console_write, - .device = uart_console_device, - .setup = msm_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &msm_uart_driver, -}; +static int __init msm_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + struct msm_port *msm_port; + int baud, flow, bits, parity; -#define MSM_CONSOLE (&msm_console) + if(unlikely(co->index >= UART_NR || co->index < 0)) + return -ENXIO; -#else -#define MSM_CONSOLE NULL -#endif + port = get_port_from_line(co->index); + msm_port = UART_TO_MSM(port); -static struct uart_driver msm_uart_driver = { - .owner = THIS_MODULE, - .driver_name = "msm_serial", - .dev_name = "ttyMSM", - .nr = UART_NR, - .cons = MSM_CONSOLE, -}; + if(unlikely(!port->membase)) + return -ENXIO; -static atomic_t msm_uart_next_id = ATOMIC_INIT(0); + msm_init_clock(port); -static int __init msm_serial_probe(struct platform_device *pdev) -{ - struct msm_port *msm_port; - struct resource *resource; - struct uart_port *port; - int irq; + if(options) + uart_parse_options(options, &baud, &parity, &bits, &flow); - if (pdev->id == -1) - pdev->id = atomic_inc_return(&msm_uart_next_id) - 1; + bits = 8; + parity = 'n'; + flow = 'n'; + msm_write(port, UART_MR2_BITS_PER_CHAR_8 | UART_MR2_STOP_BIT_LEN_ONE, + UART_MR2); /* 8N1 */ - if (unlikely(pdev->id < 0 || pdev->id >= UART_NR)) - return -ENXIO; + if(baud < 300 || baud > 115200) + baud = 115200; + msm_set_baud_rate(port, baud); - printk(KERN_INFO "msm_serial: detected port #%d\n", pdev->id); + msm_reset(port); - port = get_port_from_line(pdev->id); - port->dev = &pdev->dev; - msm_port = UART_TO_MSM(port); + if(msm_port->is_uartdm){ + msm_write(port, UART_CR_CMD_PROTECTION_EN, UART_CR); + msm_write(port, UART_CR_TX_ENABLE, UART_CR); + } - if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) - msm_port->is_uartdm = 1; - else - msm_port->is_uartdm = 0; + printk(KERN_INFO "msm_serial: console setup on port #%d\n", port->line); - if (msm_port->is_uartdm) { - msm_port->clk = clk_get(&pdev->dev, "gsbi_uart_clk"); - msm_port->pclk = clk_get(&pdev->dev, "gsbi_pclk"); - } else { - msm_port->clk = clk_get(&pdev->dev, "uart_clk"); - msm_port->pclk = ERR_PTR(-ENOENT); - } + return uart_set_options(port, co, baud, parity, bits, flow); +} - if (unlikely(IS_ERR(msm_port->clk) || (IS_ERR(msm_port->pclk) && - msm_port->is_uartdm))) - return PTR_ERR(msm_port->clk); +static struct uart_driver msm_uart_driver; - if (msm_port->is_uartdm) - clk_set_rate(msm_port->clk, 1843200); +static struct console msm_console = { + .name = "ttyMSM", + .write = msm_console_write, + .device = uart_console_device, + .setup = msm_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &msm_uart_driver, +}; - port->uartclk = clk_get_rate(msm_port->clk); - printk(KERN_INFO "uartclk = %d\n", port->uartclk); +#define MSM_CONSOLE (&msm_console) +#else +#define MSM_CONSOLE NULL +#endif - resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (unlikely(!resource)) - return -ENXIO; - port->mapbase = resource->start; +static struct uart_driver msm_uart_driver = { + .owner = THIS_MODULE, + .driver_name = "msm_serial", + .dev_name = "ttyMSM", + .nr = UART_NR, + .cons = MSM_CONSOLE, +}; - irq = platform_get_irq(pdev, 0); - if (unlikely(irq < 0)) - return -ENXIO; - port->irq = irq; +static atomic_t msm_uart_next_id = ATOMIC_INIT(0); - platform_set_drvdata(pdev, port); +static const struct of_device_id msm_uartdm_table[] = { + { .compatible = "qcom,msm-uartdm-v1.1", .data = (void *) UARTDM_1P1 }, + { .compatible = "qcom,msm-uartdm-v1.2", .data = (void *) UARTDM_1P2 }, + { .compatible = "qcom,msm-uartdm-v1.3", .data = (void *) UARTDM_1P3 }, + { .compatible = "qcom,msm-uartdm-v1.4", .data = (void *) UARTDM_1P4 }, + { } +}; - return uart_add_one_port(&msm_uart_driver, port); +static int msm_serial_probe(struct platform_device *pdev) +{ + struct msm_port *msm_port; + struct resource *resource; + struct uart_port *port; + const struct of_device_id *id; + int irq; + + if(pdev->id == -1) + pdev->id = atomic_inc_return(&msm_uart_next_id) - 1; + + if(unlikely(pdev->id < 0 || pdev->id >= UART_NR)) + return -ENXIO; + + printk(KERN_INFO "msm_serial: detected port #%d '%s'\n", pdev->id, pdev->name); + + port = get_port_from_line(pdev->id); + port->dev = &pdev->dev; + msm_port = UART_TO_MSM(port); + + id = of_match_device(msm_uartdm_table, &pdev->dev); + if(id) + msm_port->is_uartdm = (unsigned long) id->data; + else + msm_port->is_uartdm = 0; + + msm_port->clk = devm_clk_get(&pdev->dev, "core"); + if(IS_ERR(msm_port->clk)) + return PTR_ERR(msm_port->clk); + + if(msm_port->is_uartdm){ + msm_port->pclk = devm_clk_get(&pdev->dev, "iface"); + if(IS_ERR(msm_port->pclk)) + return PTR_ERR(msm_port->pclk); + + clk_set_rate(msm_port->clk, 1843200); + } + + port->uartclk = clk_get_rate(msm_port->clk); + /*--- printk(KERN_INFO "uartclk = %ld\n", port->uartclk); ---*/ + + resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if(unlikely(!resource)) + return -ENXIO; + port->mapbase = resource->start; + + irq = platform_get_irq(pdev, 0); + if(unlikely(irq < 0)) + return -ENXIO; + port->irq = irq; + + platform_set_drvdata(pdev, port); +#if defined(CONFIG_AVM_ENHANCED) + if(strcmp(pdev->name, "12490000.serial") == 0){ + /*--- mbahr: how we can detect this better ? ---*/ + printk(KERN_INFO "msm_serial: port #%d '%s' reserved for dectuart\n", + pdev->id, pdev->name); + + dectuart_port = port; + } +#endif/*--- #if defined(CONFIG_AVM_ENHANCED) ---*/ + return uart_add_one_port(&msm_uart_driver, port); } static int msm_serial_remove(struct platform_device *pdev) { - struct msm_port *msm_port = platform_get_drvdata(pdev); + struct uart_port *port = platform_get_drvdata(pdev); - clk_put(msm_port->clk); + uart_remove_one_port(&msm_uart_driver, port); - return 0; + return 0; } static struct of_device_id msm_match_table[] = { - { .compatible = "qcom,msm-uart" }, - {} + { .compatible = "qcom,msm-uart" }, + { .compatible = "qcom,msm-uartdm" }, + { } }; MODULE_DEVICE_TABLE(of, msm_match_table); static struct platform_driver msm_platform_driver = { - .remove = msm_serial_remove, - .driver = { - .name = "msm_serial", - .owner = THIS_MODULE, - .of_match_table = msm_match_table, - }, + .remove = msm_serial_remove, + .probe = msm_serial_probe, + .driver = { + .name = "msm_serial", + .owner = THIS_MODULE, + .of_match_table = msm_match_table, + }, }; static int __init msm_serial_init(void) { - int ret; + int ret; - ret = uart_register_driver(&msm_uart_driver); - if (unlikely(ret)) - return ret; + ret = uart_register_driver(&msm_uart_driver); + if(unlikely(ret)) + return ret; - ret = platform_driver_probe(&msm_platform_driver, msm_serial_probe); - if (unlikely(ret)) - uart_unregister_driver(&msm_uart_driver); + ret = platform_driver_register(&msm_platform_driver); + if(unlikely(ret)) + uart_unregister_driver(&msm_uart_driver); - printk(KERN_INFO "msm_serial: driver initialized\n"); + printk(KERN_INFO "msm_serial: driver initialized\n"); - return ret; + return ret; } static void __exit msm_serial_exit(void) { #ifdef CONFIG_SERIAL_MSM_CONSOLE - unregister_console(&msm_console); + unregister_console(&msm_console); #endif - platform_driver_unregister(&msm_platform_driver); - uart_unregister_driver(&msm_uart_driver); + platform_driver_unregister(&msm_platform_driver); + uart_unregister_driver(&msm_uart_driver); } module_init(msm_serial_init);