--- zzzz-none-000/linux-4.4.60/drivers/tty/serial/msm_serial.c 2017-04-08 07:53:53.000000000 +0000 +++ honeybee-1240e-714/linux-4.4.60/drivers/tty/serial/msm_serial.c 2019-07-03 09:21:34.000000000 +0000 @@ -19,33 +19,159 @@ # define SUPPORT_SYSRQ #endif +#if defined(CONFIG_AVM_FASTIRQ) +#include +#define CLIENT_FIQ_PRIO FIQ_PRIO_MONITOR + +#include +#define __BUILD_AVM_CONTEXT_FUNC(func) firq_##func +#else +#define __BUILD_AVM_CONTEXT_FUNC(func) func +#define is_avm_rte() 0 +#endif + +#include #include #include #include -#include #include #include #include -#include +#include #include #include #include #include #include -#include #include #include #include #include #include #include +#include + +#define UART_MR1 0x0000 -#include "msm_serial.h" +#define UART_MR1_AUTO_RFR_LEVEL0 0x3F +#define UART_MR1_AUTO_RFR_LEVEL1 0x3FF00 +#define UART_DM_MR1_AUTO_RFR_LEVEL1 0xFFFFFF00 +#define UART_MR1_RX_RDY_CTL BIT(7) +#define UART_MR1_CTS_CTL BIT(6) + +#define UART_MR2 0x0004 +#define UART_MR2_ERROR_MODE BIT(6) +#define UART_MR2_BITS_PER_CHAR 0x30 +#define UART_MR2_BITS_PER_CHAR_5 (0x0 << 4) +#define UART_MR2_BITS_PER_CHAR_6 (0x1 << 4) +#define UART_MR2_BITS_PER_CHAR_7 (0x2 << 4) +#define UART_MR2_BITS_PER_CHAR_8 (0x3 << 4) +#define UART_MR2_STOP_BIT_LEN_ONE (0x1 << 2) +#define UART_MR2_STOP_BIT_LEN_TWO (0x3 << 2) +#define UART_MR2_PARITY_MODE_NONE 0x0 +#define UART_MR2_PARITY_MODE_ODD 0x1 +#define UART_MR2_PARITY_MODE_EVEN 0x2 +#define UART_MR2_PARITY_MODE_SPACE 0x3 +#define UART_MR2_PARITY_MODE 0x3 + +#define UART_CSR 0x0008 + +#define UART_TF 0x000C +#define UARTDM_TF 0x0070 + +#define UART_CR 0x0010 +#define UART_CR_CMD_NULL (0 << 4) +#define UART_CR_CMD_RESET_RX (1 << 4) +#define UART_CR_CMD_RESET_TX (2 << 4) +#define UART_CR_CMD_RESET_ERR (3 << 4) +#define UART_CR_CMD_RESET_BREAK_INT (4 << 4) +#define UART_CR_CMD_START_BREAK (5 << 4) +#define UART_CR_CMD_STOP_BREAK (6 << 4) +#define UART_CR_CMD_RESET_CTS (7 << 4) +#define UART_CR_CMD_RESET_STALE_INT (8 << 4) +#define UART_CR_CMD_PACKET_MODE (9 << 4) +#define UART_CR_CMD_MODE_RESET (12 << 4) +#define UART_CR_CMD_SET_RFR (13 << 4) +#define UART_CR_CMD_RESET_RFR (14 << 4) +#define UART_CR_CMD_PROTECTION_EN (16 << 4) +#define UART_CR_CMD_STALE_EVENT_DISABLE (6 << 8) +#define UART_CR_CMD_STALE_EVENT_ENABLE (80 << 4) +#define UART_CR_CMD_FORCE_STALE (4 << 8) +#define UART_CR_CMD_RESET_TX_READY (3 << 8) +#define UART_CR_TX_DISABLE BIT(3) +#define UART_CR_TX_ENABLE BIT(2) +#define UART_CR_RX_DISABLE BIT(1) +#define UART_CR_RX_ENABLE BIT(0) +#define UART_CR_CMD_RESET_RXBREAK_START ((1 << 11) | (2 << 4)) + +#define UART_IMR 0x0014 +#define UART_IMR_TXLEV BIT(0) +#define UART_IMR_RXSTALE BIT(3) +#define UART_IMR_RXLEV BIT(4) +#define UART_IMR_DELTA_CTS BIT(5) +#define UART_IMR_CURRENT_CTS BIT(6) +#define UART_IMR_RXBREAK_START BIT(10) + +#define UART_IPR_RXSTALE_LAST 0x20 +#define UART_IPR_STALE_LSB 0x1F +#define UART_IPR_STALE_TIMEOUT_MSB 0x3FF80 +#define UART_DM_IPR_STALE_TIMEOUT_MSB 0xFFFFFF80 + +#define UART_IPR 0x0018 +#define UART_TFWR 0x001C +#define UART_RFWR 0x0020 +#define UART_HCR 0x0024 + +#define UART_MREG 0x0028 +#define UART_NREG 0x002C +#define UART_DREG 0x0030 +#define UART_MNDREG 0x0034 +#define UART_IRDA 0x0038 +#define UART_MISR_MODE 0x0040 +#define UART_MISR_RESET 0x0044 +#define UART_MISR_EXPORT 0x0048 +#define UART_MISR_VAL 0x004C +#define UART_TEST_CTRL 0x0050 + +#define UART_SR 0x0008 +#define UART_SR_HUNT_CHAR BIT(7) +#define UART_SR_RX_BREAK BIT(6) +#define UART_SR_PAR_FRAME_ERR BIT(5) +#define UART_SR_OVERRUN BIT(4) +#define UART_SR_TX_EMPTY BIT(3) +#define UART_SR_TX_READY BIT(2) +#define UART_SR_RX_FULL BIT(1) +#define UART_SR_RX_READY BIT(0) + +#define UART_RF 0x000C +#define UARTDM_RF 0x0070 +#define UART_MISR 0x0010 +#define UART_ISR 0x0014 +#define UART_ISR_TX_READY BIT(7) + +#define UARTDM_RXFS 0x50 +#define UARTDM_RXFS_BUF_SHIFT 0x7 +#define UARTDM_RXFS_BUF_MASK 0x7 + +#define UARTDM_DMEN 0x3C +#define UARTDM_DMEN_RX_SC_ENABLE BIT(5) +#define UARTDM_DMEN_TX_SC_ENABLE BIT(4) + +#define UARTDM_DMEN_TX_BAM_ENABLE BIT(2) /* UARTDM_1P4 */ +#define UARTDM_DMEN_TX_DM_ENABLE BIT(0) /* < UARTDM_1P4 */ + +#define UARTDM_DMEN_RX_BAM_ENABLE BIT(3) /* UARTDM_1P4 */ +#define UARTDM_DMEN_RX_DM_ENABLE BIT(1) /* < UARTDM_1P4 */ + +#define UARTDM_DMRX 0x34 +#define UARTDM_NCF_TX 0x40 +#define UARTDM_RX_TOTAL_SNAP 0x38 + +#define UARTDM_BURST_SIZE 16 /* in bytes */ +#define UARTDM_TX_AIGN(x) ((x) & ~0x3) /* valid for > 1p3 */ +#define UARTDM_TX_MAX 256 /* in bytes, valid for <= 1p3 */ +#define UARTDM_RX_SIZE (UART_XMIT_SIZE / 4) -#define UARTDM_BURST_SIZE 16 /* in bytes */ -#define UARTDM_TX_AIGN(x) ((x) & ~0x3) /* valid for > 1p3 */ -#define UARTDM_TX_MAX 256 /* in bytes, valid for <= 1p3 */ -#define UARTDM_RX_SIZE (UART_XMIT_SIZE / 4) enum { UARTDM_1P1 = 1, @@ -78,10 +204,76 @@ struct msm_dma rx_dma; }; +#if defined(CONFIG_AVM_ENHANCED) +#include "msm_dectuart.h" + +static int msm_serial_dectuart_get_char(void); +static void msm_serial_dectuart_put_char(unsigned char ch); +static void msm_serial_dectuart_init(unsigned int baud, int mode); +static void msm_serial_dectuart_exit(void); +static void msm_serial_console_stop(void); +static void msm_serial_console_start(void); +#endif/*--- #if defined(CONFIG_AVM_ENHANCED) ---*/ + +#define UART_TO_MSM(uart_port) container_of(uart_port, struct msm_port, uart) + +static +void msm_write(struct uart_port *port, unsigned int val, unsigned int off) +{ + writel_relaxed(val, port->membase + off); +} + +static +unsigned int msm_read(struct uart_port *port, unsigned int off) +{ + return readl_relaxed(port->membase + off); +} + +/* + * Setup the MND registers to use the TCXO clock. + */ +static void msm_serial_set_mnd_regs_tcxo(struct uart_port *port) +{ + msm_write(port, 0x06, UART_MREG); + msm_write(port, 0xF1, UART_NREG); + msm_write(port, 0x0F, UART_DREG); + msm_write(port, 0x1A, UART_MNDREG); + port->uartclk = 1843200; +} + +/* + * Setup the MND registers to use the TCXO clock divided by 4. + */ +static void msm_serial_set_mnd_regs_tcxoby4(struct uart_port *port) +{ + msm_write(port, 0x18, UART_MREG); + msm_write(port, 0xF6, UART_NREG); + msm_write(port, 0x0F, UART_DREG); + msm_write(port, 0x0A, UART_MNDREG); + port->uartclk = 1843200; +} + +static void msm_serial_set_mnd_regs(struct uart_port *port) +{ + struct msm_port *msm_port = UART_TO_MSM(port); + + /* + * These registers don't exist so we change the clk input rate + * on uartdm hardware instead + */ + if (msm_port->is_uartdm) + return; + + if (port->uartclk == 19200000) + msm_serial_set_mnd_regs_tcxo(port); + else if (port->uartclk == 4800000) + msm_serial_set_mnd_regs_tcxoby4(port); +} + static void msm_handle_tx(struct uart_port *port); static void msm_start_rx_dma(struct msm_port *msm_port); -void msm_stop_dma(struct uart_port *port, struct msm_dma *dma) +static void msm_stop_dma(struct uart_port *port, struct msm_dma *dma) { struct device *dev = port->dev; unsigned int mapped; @@ -243,6 +435,11 @@ struct msm_port *msm_port = UART_TO_MSM(port); struct msm_dma *dma = &msm_port->tx_dma; +#if defined(CONFIG_AVM_ENHANCED) + if(msm_dectuart_is_busy(&msm_dectuart)) { + return; + } +#endif/*--- #if defined(CONFIG_AVM_ENHANCED) ---*/ /* Already started in DMA mode */ if (dma->count) return; @@ -270,7 +467,7 @@ unsigned int count; u32 val; - spin_lock_irqsave(&port->lock, flags); + __BUILD_AVM_CONTEXT_FUNC(spin_lock_irqsave)(&port->lock, flags); /* Already stopped */ if (!dma->count) @@ -305,7 +502,7 @@ msm_handle_tx(port); done: - spin_unlock_irqrestore(&port->lock, flags); + __BUILD_AVM_CONTEXT_FUNC(spin_unlock_irqrestore)(&port->lock, flags); } static int msm_handle_tx_dma(struct msm_port *msm_port, unsigned int count) @@ -378,7 +575,7 @@ unsigned long flags; u32 val; - spin_lock_irqsave(&port->lock, flags); + __BUILD_AVM_CONTEXT_FUNC(spin_lock_irqsave)(&port->lock, flags); /* Already stopped */ if (!dma->count) @@ -388,10 +585,6 @@ val &= ~dma->enable_bit; msm_write(port, val, UARTDM_DMEN); - /* Restore interrupts */ - msm_port->imr |= UART_IMR_RXLEV | UART_IMR_RXSTALE; - msm_write(port, msm_port->imr, UART_IMR); - if (msm_read(port, UART_SR) & UART_SR_OVERRUN) { port->icount.overrun++; tty_insert_flip_char(tport, 0, TTY_OVERRUN); @@ -420,16 +613,16 @@ if (!(port->read_status_mask & UART_SR_RX_BREAK)) flag = TTY_NORMAL; - spin_unlock_irqrestore(&port->lock, flags); + __BUILD_AVM_CONTEXT_FUNC(spin_unlock_irqrestore)(&port->lock, flags); sysrq = uart_handle_sysrq_char(port, dma->virt[i]); - spin_lock_irqsave(&port->lock, flags); + __BUILD_AVM_CONTEXT_FUNC(spin_lock_irqsave)(&port->lock, flags); if (!sysrq) tty_insert_flip_char(tport, dma->virt[i], flag); } msm_start_rx_dma(msm_port); done: - spin_unlock_irqrestore(&port->lock, flags); + __BUILD_AVM_CONTEXT_FUNC(spin_unlock_irqrestore)(&port->lock, flags); if (count) tty_flip_buffer_push(tport); @@ -526,8 +719,11 @@ { struct tty_port *tport = &port->state->port; unsigned int sr; + int sysrq, r_count, i; int count = 0; struct msm_port *msm_port = UART_TO_MSM(port); + unsigned int reg_buf; + unsigned char *buf = (unsigned char *)®_buf; if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) { port->icount.overrun++; @@ -549,9 +745,6 @@ port->icount.rx += count; while (count > 0) { - unsigned char buf[4]; - int sysrq, r_count, i; - sr = msm_read(port, UART_SR); if ((sr & UART_SR_RX_READY) == 0) { msm_port->old_snap_state -= count; @@ -559,7 +752,7 @@ } ioread32_rep(port->membase + UARTDM_RF, buf, 1); - r_count = min_t(int, count, sizeof(buf)); + r_count = min_t(int, count, sizeof(reg_buf)); for (i = 0; i < r_count; i++) { char flag = TTY_NORMAL; @@ -575,18 +768,25 @@ if (!(port->read_status_mask & UART_SR_RX_BREAK)) flag = TTY_NORMAL; - spin_unlock(&port->lock); +#if defined(CONFIG_AVM_ENHANCED) + if(msm_dectuart_is_busy(&msm_dectuart)) { + msm_dectuart_pipe_enqueue(&msm_dectuart, buf[i]); + continue; + } +#endif/*--- #if defined(CONFIG_AVM_ENHANCED) ---*/ + + __BUILD_AVM_CONTEXT_FUNC(spin_unlock)(&port->lock); sysrq = uart_handle_sysrq_char(port, buf[i]); - spin_lock(&port->lock); + __BUILD_AVM_CONTEXT_FUNC(spin_lock)(&port->lock); if (!sysrq) tty_insert_flip_char(tport, buf[i], flag); } count -= r_count; } - spin_unlock(&port->lock); + __BUILD_AVM_CONTEXT_FUNC(spin_unlock)(&port->lock); tty_flip_buffer_push(tport); - spin_lock(&port->lock); + __BUILD_AVM_CONTEXT_FUNC(spin_lock)(&port->lock); if (misr & (UART_IMR_RXSTALE)) msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR); @@ -638,16 +838,16 @@ else if (sr & UART_SR_PAR_FRAME_ERR) flag = TTY_FRAME; - spin_unlock(&port->lock); + __BUILD_AVM_CONTEXT_FUNC(spin_unlock)(&port->lock); sysrq = uart_handle_sysrq_char(port, c); - spin_lock(&port->lock); + __BUILD_AVM_CONTEXT_FUNC(spin_lock)(&port->lock); if (!sysrq) tty_insert_flip_char(tport, c, flag); } - spin_unlock(&port->lock); + __BUILD_AVM_CONTEXT_FUNC(spin_unlock)(&port->lock); tty_flip_buffer_push(tport); - spin_lock(&port->lock); + __BUILD_AVM_CONTEXT_FUNC(spin_lock)(&port->lock); } static void msm_handle_tx_pio(struct uart_port *port, unsigned int tx_count) @@ -657,6 +857,9 @@ unsigned int num_chars; unsigned int tf_pointer = 0; void __iomem *tf; + int i; + unsigned int reg_buf; + unsigned char *buf = (unsigned char *)®_buf; if (msm_port->is_uartdm) tf = port->membase + UARTDM_TF; @@ -667,15 +870,14 @@ msm_reset_dm_count(port, tx_count); while (tf_pointer < tx_count) { - int i; - char buf[4] = { 0 }; + reg_buf = 0; 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)); + (unsigned int)sizeof(reg_buf)); else num_chars = 1; @@ -704,8 +906,13 @@ struct msm_dma *dma = &msm_port->tx_dma; unsigned int pio_count, dma_count, dma_min; void __iomem *tf; + unsigned int reg_buf; int err = 0; - +#if defined(CONFIG_AVM_ENHANCED) + if(msm_dectuart_is_busy(&msm_dectuart)) { + return; + } +#endif/*--- #if defined(CONFIG_AVM_ENHANCED) ---*/ if (port->x_char) { if (msm_port->is_uartdm) tf = port->membase + UARTDM_TF; @@ -715,7 +922,8 @@ if (msm_port->is_uartdm) msm_reset_dm_count(port, 1); - iowrite8_rep(tf, &port->x_char, 1); + reg_buf = port->x_char; + iowrite32_rep(tf, ®_buf, 1); port->icount.tx++; port->x_char = 0; return; @@ -766,7 +974,7 @@ unsigned int misr; u32 val; - spin_lock_irqsave(&port->lock, flags); + __BUILD_AVM_CONTEXT_FUNC(spin_lock_irqsave)(&port->lock, flags); misr = msm_read(port, UART_MISR); msm_write(port, 0, UART_IMR); /* disable interrupt */ @@ -785,7 +993,12 @@ * Flush DMA input fifo to memory, this will also * trigger DMA RX completion */ - dmaengine_terminate_all(dma->chan); + if (msm_port->is_uartdm < UARTDM_1P4) { + dmaengine_terminate_all_graceful(dma->chan, + true); + } else { + dmaengine_terminate_all(dma->chan); + } } else if (msm_port->is_uartdm) { msm_handle_rx_dm(port, misr); } else { @@ -798,7 +1011,7 @@ msm_handle_delta_cts(port); msm_write(port, msm_port->imr, UART_IMR); /* restore interrupt */ - spin_unlock_irqrestore(&port->lock, flags); + __BUILD_AVM_CONTEXT_FUNC(spin_unlock_irqrestore)(&port->lock, flags); return IRQ_HANDLED; } @@ -813,13 +1026,16 @@ return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR | TIOCM_RTS; } -static void msm_reset(struct uart_port *port) +static void msm_reset(struct uart_port *port, bool reset_tx) { 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); + + if (reset_tx) + 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); @@ -861,61 +1077,96 @@ }; static const struct msm_baud_map * -msm_find_best_baud(struct uart_port *port, unsigned int baud) +msm_find_best_baud(struct uart_port *port, unsigned int baud, + unsigned long *rate) { - unsigned int i, divisor; - const struct msm_baud_map *entry; + struct msm_port *msm_port = UART_TO_MSM(port); + unsigned int divisor, result; + unsigned long target, old, best_rate = 0, diff, best_diff = ULONG_MAX; + const struct msm_baud_map *entry, *end, *best; 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 }, - { 0, 0xff, 31 }, + { 2, 0xee, 16 }, + { 3, 0xdd, 8 }, + { 4, 0xcc, 6 }, + { 6, 0xbb, 6 }, + { 8, 0xaa, 6 }, + { 12, 0x99, 6 }, + { 16, 0x88, 1 }, + { 24, 0x77, 1 }, + { 32, 0x66, 1 }, + { 48, 0x55, 1 }, + { 96, 0x44, 1 }, + { 192, 0x33, 1 }, + { 384, 0x22, 1 }, + { 768, 0x11, 1 }, + { 1536, 0x00, 1 }, }; - divisor = uart_get_divisor(port, baud); + best = table; /* Default to smallest divider */ + target = clk_round_rate(msm_port->clk, 16 * baud); + divisor = DIV_ROUND_CLOSEST(target, 16 * baud); + + end = table + ARRAY_SIZE(table); + entry = table; + while (entry < end) { + if (entry->divisor <= divisor) { + result = target / entry->divisor / 16; + diff = abs(result - baud); + + /* Keep track of best entry */ + if (diff < best_diff) { + best_diff = diff; + best = entry; + best_rate = target; + } - for (i = 0, entry = table; i < ARRAY_SIZE(table); i++, entry++) - if (entry->divisor <= divisor) - break; + if (result == baud) + break; + } else if (entry->divisor > divisor) { + old = target; + target = clk_round_rate(msm_port->clk, old + 1); + /* + * The rate didn't get any faster so we can't do + * better at dividing it down + */ + if (target == old) + break; + + /* Start the divisor search over at this new rate */ + entry = table; + divisor = DIV_ROUND_CLOSEST(target, 16 * baud); + continue; + } + entry++; + } - return entry; /* Default to smallest divider */ + *rate = best_rate; + return best; } static int msm_set_baud_rate(struct uart_port *port, unsigned int baud, - unsigned long *saved_flags) + unsigned long *saved_flags) { unsigned int rxstale, watermark, mask; struct msm_port *msm_port = UART_TO_MSM(port); const struct msm_baud_map *entry; - unsigned long flags; - - entry = msm_find_best_baud(port, baud); - - msm_write(port, entry->code, UART_CSR); - - if (baud > 460800) - port->uartclk = baud * 16; + unsigned long flags, rate; + struct device *dev = msm_port->uart.dev; + u32 tx_watermark = 10; flags = *saved_flags; - spin_unlock_irqrestore(&port->lock, flags); + __BUILD_AVM_CONTEXT_FUNC(spin_unlock_irqrestore)(&port->lock, flags); - clk_set_rate(msm_port->clk, port->uartclk); + entry = msm_find_best_baud(port, baud, &rate); + clk_set_rate(msm_port->clk, rate); + baud = rate / 16 / entry->divisor; - spin_lock_irqsave(&port->lock, flags); + __BUILD_AVM_CONTEXT_FUNC(spin_lock_irqsave)(&port->lock, flags); *saved_flags = flags; + port->uartclk = rate; + + msm_write(port, entry->code, UART_CSR); /* RX stale watermark */ rxstale = entry->rxstale; @@ -936,10 +1187,17 @@ msm_write(port, watermark, UART_RFWR); /* set TX watermark */ - msm_write(port, 10, UART_TFWR); + of_property_read_u32(dev->of_node, "tx-watermark", &tx_watermark); + msm_write(port, tx_watermark, UART_TFWR); msm_write(port, UART_CR_CMD_PROTECTION_EN, UART_CR); - msm_reset(port); + + /* + * Check for console in this port and don't do TX reset + * if console is enabled in this port. + */ + msm_reset(port, !(uart_console(port) && + (port->cons->flags & CON_ENABLED))); /* Enable RX and TX */ msm_write(port, UART_CR_TX_ENABLE | UART_CR_RX_ENABLE, UART_CR); @@ -1027,14 +1285,14 @@ } static void msm_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + struct ktermios *old) { struct msm_port *msm_port = UART_TO_MSM(port); struct msm_dma *dma = &msm_port->rx_dma; unsigned long flags; unsigned int baud, mr; - spin_lock_irqsave(&port->lock, flags); + __BUILD_AVM_CONTEXT_FUNC(spin_lock_irqsave)(&port->lock, flags); if (dma->chan) /* Terminate if any */ msm_stop_dma(port, dma); @@ -1106,7 +1364,7 @@ /* Try to use DMA */ msm_start_rx_dma(msm_port); - spin_unlock_irqrestore(&port->lock, flags); + __BUILD_AVM_CONTEXT_FUNC(spin_unlock_irqrestore)(&port->lock, flags); } static const char *msm_type(struct uart_port *port) @@ -1181,7 +1439,7 @@ } 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); @@ -1252,7 +1510,7 @@ return c; } -static int msm_poll_get_char(struct uart_port *port) +static int msm_poll_get_char(struct uart_port *port) { u32 imr; int c; @@ -1272,7 +1530,9 @@ return c; } +#endif +#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_AVM_ENHANCED) static void msm_poll_put_char(struct uart_port *port, unsigned char c) { u32 imr; @@ -1299,7 +1559,7 @@ /* Enable interrupts */ msm_write(port, imr, UART_IMR); } -#endif +#endif/*--- #if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_AVM_ENHANCED) ---*/ static struct uart_ops msm_uart_pops = { .tx_empty = msm_tx_empty, @@ -1366,10 +1626,15 @@ static void __msm_console_write(struct uart_port *port, const char *s, unsigned int count, bool is_uartdm) { - int i; + int i, j; int num_newlines = 0; bool replaced = false; void __iomem *tf; + struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_dma *dma = &msm_port->tx_dma; + unsigned int num_chars; + unsigned int reg_buf; + unsigned char *buf = (unsigned char *)®_buf; if (is_uartdm) tf = port->membase + UARTDM_TF; @@ -1382,18 +1647,27 @@ num_newlines++; count += num_newlines; - spin_lock(&port->lock); + __BUILD_AVM_CONTEXT_FUNC(spin_lock)(&port->lock); + + /* + * If any TX DMA operation is ongoing in BAM DMA then console write + * can not be used since it uses the FIFO mode. + */ + if (dma->count) { + __BUILD_AVM_CONTEXT_FUNC(spin_unlock)(&port->lock); + return; + } + if (is_uartdm) msm_reset_dm_count(port, count); i = 0; while (i < count) { - int j; - unsigned int num_chars; - char buf[4] = { 0 }; + reg_buf = 0; if (is_uartdm) - num_chars = min(count - i, (unsigned int)sizeof(buf)); + num_chars = min(count - i, + (unsigned int)sizeof(reg_buf)); else num_chars = 1; @@ -1418,11 +1692,11 @@ iowrite32_rep(tf, buf, 1); i += num_chars; } - spin_unlock(&port->lock); + __BUILD_AVM_CONTEXT_FUNC(spin_unlock)(&port->lock); } static void msm_console_write(struct console *co, const char *s, - unsigned int count) + unsigned int count) { struct uart_port *port; struct msm_port *msm_port; @@ -1478,9 +1752,8 @@ device->con->write = msm_serial_early_write; return 0; } -EARLYCON_DECLARE(msm_serial, msm_serial_early_console_setup); OF_EARLYCON_DECLARE(msm_serial, "qcom,msm-uart", - msm_serial_early_console_setup); + msm_serial_early_console_setup); static void msm_serial_early_write_dm(struct console *con, const char *s, unsigned n) @@ -1500,9 +1773,8 @@ device->con->write = msm_serial_early_write_dm; return 0; } -EARLYCON_DECLARE(msm_serial_dm, msm_serial_early_console_setup_dm); OF_EARLYCON_DECLARE(msm_serial_dm, "qcom,msm-uartdm", - msm_serial_early_console_setup_dm); + msm_serial_early_console_setup_dm); static struct uart_driver msm_uart_driver; @@ -1547,6 +1819,8 @@ struct uart_port *port; const struct of_device_id *id; int irq, line; + u32 serial_clk; + int ret; if (pdev->dev.of_node) line = of_alias_get_id(pdev->dev.of_node, "serial"); @@ -1564,6 +1838,17 @@ port = msm_get_port_from_line(line); port->dev = &pdev->dev; msm_port = UART_TO_MSM(port); +#if defined(CONFIG_AVM_ENHANCED) + pr_info("%s: set dectuart_port to ttyMSM%d\n", __func__, line); + msm_dectuart.port = port; + msm_dectuart.msm_dectuart_get_char = msm_serial_dectuart_get_char; + msm_dectuart.msm_dectuart_put_char = msm_serial_dectuart_put_char; + msm_dectuart.msm_dectuart_init = msm_serial_dectuart_init; + msm_dectuart.msm_console_stop = msm_serial_console_stop; + msm_dectuart.msm_console_start = msm_serial_console_start; + msm_dectuart.msm_dectuart_exit = msm_serial_dectuart_exit; +#endif/*--- #if defined(CONFIG_AVM_ENHANCED) ---*/ + id = of_match_device(msm_uartdm_table, &pdev->dev); if (id) @@ -1579,8 +1864,17 @@ 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); + /* Setting the clock only if defined in the dts */ + if (!of_property_read_u32(pdev->dev.of_node, "serial_clk", + &serial_clk)) { + ret = clk_set_rate(msm_port->clk, serial_clk); + if (ret) { + dev_err(&pdev->dev, "clk set rate failed (%d) for %u\n", + ret, serial_clk); + return ret; + } } port->uartclk = clk_get_rate(msm_port->clk); @@ -1633,7 +1927,7 @@ ret = uart_register_driver(&msm_uart_driver); if (unlikely(ret)) return ret; - + ret = platform_driver_register(&msm_platform_driver); if (unlikely(ret)) uart_unregister_driver(&msm_uart_driver); @@ -1649,6 +1943,180 @@ uart_unregister_driver(&msm_uart_driver); } +#if defined(CONFIG_AVM_ENHANCED) +/**--------------------------------------------------------------------------------**\ +\**--------------------------------------------------------------------------------**/ +static __maybe_unused void dump_msm_regs(const char *prefix, struct uart_port *port) { + unsigned int sr, isr, misr, mr1, mr2, ncf, rxfs, ts; + + sr = msm_read(port, UART_SR); + isr = msm_read(port, UART_ISR); + misr = msm_read(port, UART_MISR); + mr1 = msm_read(port, UART_MR1); + mr2 = msm_read(port, UART_MR2); + ncf = msm_read(port, UARTDM_NCF_TX); + rxfs = msm_read(port, UARTDM_RXFS); + ts = msm_read(port, UARTDM_RX_TOTAL_SNAP); + + pr_info("%s:\n", prefix); + pr_info("SR: %08x\n", sr); + pr_info("ISR: %08x\n", isr); + pr_info("MISR: %08x\n", misr); + pr_info("MR1: %08x\n", mr1); + pr_info("MR2: %08x\n", mr2); + pr_info("NCF: %08x\n", ncf); + pr_info("RXFS: %08x\n", rxfs); + pr_info("TS: %08x\n", ts); +} +/**--------------------------------------------------------------------------------**\ +\**--------------------------------------------------------------------------------**/ +static void msm_dectuart_dm_save(struct _msm_dectuart *pdectuart) { + struct uart_port *port = pdectuart->port; + struct msm_port *msm_port = UART_TO_MSM(port); + +/*--- dump_msm_regs(__func__, port); ---*/ + pdectuart->mr1 = msm_read(port, UART_MR1); + pdectuart->mr2 = msm_read(port, UART_MR2); + pdectuart->imr = msm_port->imr; /*--- save actual imr-Status ---*/ + /* switch of all interrupts */ + msm_port->imr = 0; + msm_write(port, msm_port->imr, UART_IMR); +} +/**--------------------------------------------------------------------------------**\ +\**--------------------------------------------------------------------------------**/ +static void msm_dectuart_dm_restore(struct _msm_dectuart *pdectuart) { + struct uart_port *port = pdectuart->port; + struct msm_port *msm_port = UART_TO_MSM(port); + /*--- pr_info("%s\n", __func__); ---*/ + msm_port->imr = pdectuart->imr; + msm_write(port, pdectuart->mr1, UART_MR1); + msm_write(port, pdectuart->mr2, UART_MR2); + msm_write(port, msm_port->imr, UART_IMR); +} +/**--------------------------------------------------------------------------------**\ + 8-N-1 configuration: 8 data bits - No parity - 1 stop bit + an no hw-flowcontrol +\**--------------------------------------------------------------------------------**/ +static void msm_dectuart_dm_init(struct _msm_dectuart *pdectuart) { + struct uart_port *port = pdectuart->port; + unsigned int mr; + /*--- pr_info("%s\n", __func__); ---*/ + /* no Hardware flow control */ + mr = msm_read(port, UART_MR1); + mr &= ~(UART_MR1_CTS_CTL | UART_MR1_RX_RDY_CTL); + msm_write(port, mr, UART_MR1); + + mr = msm_read(port, UART_MR2); + /* no parity */ + mr &= ~UART_MR2_PARITY_MODE; + /* CS8 */ + mr &= ~UART_MR2_BITS_PER_CHAR; + mr |= UART_MR2_BITS_PER_CHAR_8; + /* 1 stop bits */ + mr &= ~(UART_MR2_STOP_BIT_LEN_ONE | UART_MR2_STOP_BIT_LEN_TWO); + mr |= UART_MR2_STOP_BIT_LEN_ONE; + + /* set parity, bits per char, and stop bit */ + msm_write(port, mr, UART_MR2); +} +/**--------------------------------------------------------------------------------**\ +\**--------------------------------------------------------------------------------**/ +static int msm_serial_dectuart_get_char(void){ + struct _msm_dectuart *pdectuart = &msm_dectuart; + int c; + if (!pdectuart->port){ + return -ENXIO; + } + c = msm_dectuart_pipe_dequeue(pdectuart); + if(c == -1) { + return -EAGAIN; + } + return c; + return -EAGAIN; +} +/**--------------------------------------------------------------------------------**\ +\**--------------------------------------------------------------------------------**/ +static void msm_serial_dectuart_put_char(unsigned char ch){ + struct uart_port *port = msm_dectuart.port; + if (port == NULL){ + return; + } + msm_poll_put_char(port, ch); +} +/**--------------------------------------------------------------------------------**\ + * mode: != 0 und Tx/Rx-Irq an +\**--------------------------------------------------------------------------------**/ +static void msm_serial_dectuart_init(unsigned int baud, int mode){ + struct _msm_dectuart *pdectuart = &msm_dectuart; + struct uart_port *port = pdectuart->port; + unsigned long flags; + if (port == NULL){ + return; + } + /*--- pr_info("%s: dect_baud=%u %s\n", __func__, baud, !mode ? "pollmode" : ""); ---*/ + /*--- dump_msm_regs(__func__, port); ---*/ + if (mode == 0) { + struct msm_dma *dma; + struct msm_port *msm_port = UART_TO_MSM(port); + __BUILD_AVM_CONTEXT_FUNC(spin_lock_irqsave)(&port->lock, flags); + atomic_inc(&pdectuart->busy); + msm_dectuart_dm_init(pdectuart); + msm_set_baud_rate(port, baud, &flags); + msm_dectuart_pipe_flush(pdectuart); + msm_stop_tx(port); + + dma = &msm_port->rx_dma; + if (dma->chan) {/* Terminate if any */ + msm_stop_dma(port, dma); + } + dma = &msm_port->tx_dma; + if (dma->chan) { + msm_stop_dma(port, dma); + } + __BUILD_AVM_CONTEXT_FUNC(spin_unlock_irqrestore)(&port->lock, flags); + } +} +/**--------------------------------------------------------------------------------**\ +\**--------------------------------------------------------------------------------**/ +static void msm_serial_console_stop(void) { + unsigned long flags; + struct _msm_dectuart *pdectuart = &msm_dectuart; + struct uart_port *port = pdectuart->port; + if(port){ + __BUILD_AVM_CONTEXT_FUNC(spin_lock_irqsave)(&port->lock, flags); + atomic_set(&pdectuart->busy, 1); + msm_dectuart_dm_save(pdectuart); + __BUILD_AVM_CONTEXT_FUNC(spin_unlock_irqrestore)(&port->lock, flags); + console_stop(port->cons); + } +} +/**--------------------------------------------------------------------------------**\ +\**--------------------------------------------------------------------------------**/ +static void msm_serial_console_start(void) { + unsigned long flags; + struct _msm_dectuart *pdectuart = &msm_dectuart; + struct uart_port *port = pdectuart->port; + if (port){ + struct msm_port *msm_port = UART_TO_MSM(port); + __BUILD_AVM_CONTEXT_FUNC(spin_lock_irqsave)(&port->lock, flags); + /*--- msm_set_baud_rate(port, 115200, &flags); ---*/ + msm_dectuart_dm_restore(pdectuart); + atomic_set(&pdectuart->busy, 0); + msm_start_rx_dma(msm_port); + msm_start_tx(port); + __BUILD_AVM_CONTEXT_FUNC(spin_unlock_irqrestore)(&port->lock, flags); + console_start(port->cons); + } +} +/**--------------------------------------------------------------------------------**\ +\**--------------------------------------------------------------------------------**/ +static void msm_serial_dectuart_exit(void){ + struct _msm_dectuart *pdectuart = &msm_dectuart; + pr_info("%s\n", __func__); + atomic_dec(&pdectuart->busy); +} +#endif/*--- #if defined(CONFIG_AVM_ENHANCED) ---*/ + module_init(msm_serial_init); module_exit(msm_serial_exit);