--- zzzz-none-000/linux-4.1.52/drivers/tty/serial/amba-pl011.c 2018-05-28 02:26:45.000000000 +0000 +++ bcm63-7530ax-731/linux-4.1.52/drivers/tty/serial/amba-pl011.c 2022-03-02 11:37:13.000000000 +0000 @@ -71,6 +71,9 @@ #define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE) #define UART_DUMMY_DR_RX (1 << 16) +#if defined(CONFIG_BCM_KF_CONSOLE_BAUD) +extern int kerSysIsIkosBootSet(void); +#endif /* There is by now at least one vendor with differing details, so handle it */ struct vendor_data { unsigned int ifls; @@ -169,8 +172,37 @@ struct pl011_dmatx_data dmatx; bool dma_probed; #endif +#if defined(CONFIG_AVM_ENHANCED) + atomic_t reflink; +#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 + +#if defined(CONFIG_AVM_ENHANCED) +#include "amba-pl011-dectuart.h" + +static int pl011_serial_dectuart_get_char(void); +static void pl011_serial_dectuart_put_char(unsigned char ch); +static void pl011_serial_dectuart_init(unsigned int baud, int mode); +static void pl011_serial_dectuart_exit(void); +static void pl011_serial_console_stop(void); +static void pl011_serial_console_start(void); +#endif + +#if defined(CONFIG_AVM_ENHANCED) +extern unsigned int avm_console_enabled; +#endif + /* * Reads up to 256 characters from the FIFO or until it's empty and * inserts them into the TTY layer. Returns the number of characters @@ -220,6 +252,14 @@ if (uart_handle_sysrq_char(&uap->port, ch & 255)) continue; +#if defined(CONFIG_AVM_ENHANCED) + if (uap->port.cons->flags & (CON_ENABLED | CON_CONSDEV)) { + if (ch == '\r') { + avm_console_enabled = 1; + } + } +#endif/*--- #if defined(CONFIG_AVM_ENHANCED) ---*/ + uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag); } @@ -418,7 +458,7 @@ unsigned long flags; u16 dmacr; - spin_lock_irqsave(&uap->port.lock, flags); + __BUILD_AVM_CONTEXT_FUNC(spin_lock_irqsave)(&uap->port.lock, flags); if (uap->dmatx.queued) dma_unmap_sg(dmatx->chan->device->dev, &dmatx->sg, 1, DMA_TO_DEVICE); @@ -439,7 +479,7 @@ if (!(dmacr & UART011_TXDMAE) || uart_tx_stopped(&uap->port) || uart_circ_empty(&uap->port.state->xmit)) { uap->dmatx.queued = false; - spin_unlock_irqrestore(&uap->port.lock, flags); + __BUILD_AVM_CONTEXT_FUNC(spin_unlock_irqrestore)(&uap->port.lock, flags); return; } @@ -450,7 +490,7 @@ */ pl011_start_tx_pio(uap); - spin_unlock_irqrestore(&uap->port.lock, flags); + __BUILD_AVM_CONTEXT_FUNC(spin_unlock_irqrestore)(&uap->port.lock, flags); } /* @@ -963,11 +1003,11 @@ if (jiffies_to_msecs(jiffies - dmarx->last_jiffies) > uap->dmarx.poll_timeout) { - spin_lock_irqsave(&uap->port.lock, flags); + __BUILD_AVM_CONTEXT_FUNC(spin_lock_irqsave)(&uap->port.lock, flags); pl011_dma_rx_stop(uap); uap->im |= UART011_RXIM; writew(uap->im, uap->port.membase + UART011_IMSC); - spin_unlock_irqrestore(&uap->port.lock, flags); + __BUILD_AVM_CONTEXT_FUNC(spin_unlock_irqrestore)(&uap->port.lock, flags); uap->dmarx.running = false; dmaengine_terminate_all(rxchan); @@ -1384,7 +1424,7 @@ int handled = 0; unsigned int dummy_read; - spin_lock_irqsave(&uap->port.lock, flags); + __BUILD_AVM_CONTEXT_FUNC(spin_lock_irqsave)(&uap->port.lock, flags); status = readw(uap->port.membase + UART011_MIS); if (status) { do { @@ -1427,7 +1467,7 @@ handled = 1; } - spin_unlock_irqrestore(&uap->port.lock, flags); + __BUILD_AVM_CONTEXT_FUNC(spin_unlock_irqrestore)(&uap->port.lock, flags); return IRQ_RETVAL(handled); } @@ -1495,17 +1535,17 @@ unsigned long flags; unsigned int lcr_h; - spin_lock_irqsave(&uap->port.lock, flags); + __BUILD_AVM_CONTEXT_FUNC(spin_lock_irqsave)(&uap->port.lock, flags); lcr_h = readw(uap->port.membase + uap->lcrh_tx); if (break_state == -1) lcr_h |= UART01x_LCRH_BRK; else lcr_h &= ~UART01x_LCRH_BRK; writew(lcr_h, uap->port.membase + uap->lcrh_tx); - spin_unlock_irqrestore(&uap->port.lock, flags); + __BUILD_AVM_CONTEXT_FUNC(spin_unlock_irqrestore)(&uap->port.lock, flags); } -#ifdef CONFIG_CONSOLE_POLL +#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_AVM_ENHANCED) static void pl011_quiesce_irqs(struct uart_port *port) { @@ -1561,7 +1601,7 @@ writew(ch, uap->port.membase + UART01x_DR); } -#endif /* CONFIG_CONSOLE_POLL */ +#endif /*--- #if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_AVM_ENHANCED) ---*/ static int pl011_hwinit(struct uart_port *port) { @@ -1623,6 +1663,15 @@ container_of(port, struct uart_amba_port, port); unsigned int cr; int retval; +#if defined(CONFIG_AVM_ENHANCED) + unsigned int reflink = atomic_inc_return(&uap->reflink); + + if (reflink > 1) { + pr_debug("%s add reflink %d\n", __func__, reflink); + return 0; + } + pr_debug("%s ttyAMA%d %d\n", __func__, port->line, reflink); +#endif/*--- #if defined(CONFIG_AVM_ENHANCED) ---*/ retval = pl011_hwinit(port); if (retval) @@ -1696,7 +1745,15 @@ struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); unsigned int cr; +#if defined(CONFIG_AVM_ENHANCED) + unsigned int reflink = atomic_dec_return(&uap->reflink); + if (reflink != 0) { + pr_debug("%s sub reflink %d\n", __func__, reflink); + return; + } + pr_debug("%s ttyAMA%d %d\n", __func__, port->line, reflink); +#endif/*--- #if defined(CONFIG_AVM_ENHANCED) ---*/ cancel_delayed_work_sync(&uap->tx_softirq_work); /* @@ -1774,8 +1831,16 @@ /* * Ask the core to calculate the divisor for us. */ +#if defined(CONFIG_BCM_KF_CONSOLE_BAUD) + if (kerSysIsIkosBootSet() == 1) + baud = 1562500; + else + baud = uart_get_baud_rate(port, termios, old, 0, + port->uartclk / clkdiv); +#else baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / clkdiv); +#endif #ifdef CONFIG_DMA_ENGINE /* * Adjust RX DMA polling rate with baud rate if not specified. @@ -1813,7 +1878,7 @@ if (uap->fifosize > 1) lcr_h |= UART01x_LCRH_FEN; - spin_lock_irqsave(&port->lock, flags); + __BUILD_AVM_CONTEXT_FUNC(spin_lock_irqsave)(&port->lock, flags); /* * Update the per-port timeout. @@ -1898,7 +1963,7 @@ pl011_write_lcr_h(uap, lcr_h); writew(old_cr, port->membase + UART011_CR); - spin_unlock_irqrestore(&port->lock, flags); + __BUILD_AVM_CONTEXT_FUNC(spin_unlock_irqrestore)(&port->lock, flags); } static const char *pl011_type(struct uart_port *port) @@ -1995,11 +2060,12 @@ { struct uart_amba_port *uap = amba_ports[co->index]; unsigned int status, old_cr, new_cr; +#if !defined(CONFIG_BCM_KF_PRINTK_INT_ENABLED) || !defined(CONFIG_BCM_PRINTK_INT_ENABLED) unsigned long flags; int locked = 1; - +#endif clk_enable(uap->clk); - +#if !defined(CONFIG_BCM_KF_PRINTK_INT_ENABLED) || !defined(CONFIG_BCM_PRINTK_INT_ENABLED) local_irq_save(flags); if (uap->port.sysrq) locked = 0; @@ -2007,7 +2073,7 @@ locked = spin_trylock(&uap->port.lock); else spin_lock(&uap->port.lock); - +#endif /* * First save the CR then disable the interrupts */ @@ -2026,11 +2092,11 @@ status = readw(uap->port.membase + UART01x_FR); } while (status & UART01x_FR_BUSY); writew(old_cr, uap->port.membase + UART011_CR); - +#if !defined(CONFIG_BCM_KF_PRINTK_INT_ENABLED) || !defined(CONFIG_BCM_PRINTK_INT_ENABLED) if (locked) spin_unlock(&uap->port.lock); local_irq_restore(flags); - +#endif clk_disable(uap->clk); } @@ -2245,6 +2311,17 @@ uap->port.ops = &amba_pl011_pops; uap->port.flags = UPF_BOOT_AUTOCONF; uap->port.line = i; + +#if defined(CONFIG_AVM_ENHANCED) + pr_info("%s: set dectuart_port to ttyAMA%d\n", __func__, i); + pl011_dectuart.port = &uap->port; + pl011_dectuart.pl011_dectuart_get_char = pl011_serial_dectuart_get_char; + pl011_dectuart.pl011_dectuart_put_char = pl011_serial_dectuart_put_char; + pl011_dectuart.pl011_dectuart_init = pl011_serial_dectuart_init; + pl011_dectuart.pl011_console_stop = pl011_serial_console_stop; + pl011_dectuart.pl011_console_start = pl011_serial_console_start; + pl011_dectuart.pl011_dectuart_exit = pl011_serial_dectuart_exit; +#endif INIT_DELAYED_WORK(&uap->tx_softirq_work, pl011_tx_softirq); /* Ensure interrupts from this UART are masked and cleared */ @@ -2357,6 +2434,259 @@ amba_driver_unregister(&pl011_driver); } + +#if defined(CONFIG_AVM_ENHANCED) + +// #define AMBA_PL011_DUMP_REGISTER +#if defined(AMBA_PL011_DUMP_REGISTER) +/** + */ +struct _generic_bit_name { + unsigned int value; + const char *name; +}; + +#define FillField(a, b) {.value = a, .name = b} +static const struct _generic_bit_name cr_field[] = { + FillField(UART011_CR_CTSEN, "CTSEN "), /* CTS hardware flow control */ + FillField(UART011_CR_RTSEN, "RTSEN "), /* RTS hardware flow control */ + FillField(UART011_CR_OUT2, "OUT2 "), /* OUT2 */ + FillField(UART011_CR_OUT1, "OUT1 "), /* OUT1 */ + FillField(UART011_CR_RTS, "RTS "), /* RTS */ + FillField(UART011_CR_DTR, "DTR "), /* DTR */ + FillField(UART011_CR_RXE, "RXE "), /* receive enable */ + FillField(UART011_CR_TXE, "TXE "), /* transmit enable */ + FillField(UART011_CR_LBE, "LBE "), /* loopback enable */ + FillField(0, NULL), +}; + +static const struct _generic_bit_name imsc_field[] = { + FillField(UART011_OEIM, "OEIM "), /* overrun error interrupt mask */ + FillField(UART011_BEIM, "BEIM "), /* break error interrupt mask */ + FillField(UART011_PEIM, "PEIM "), /* parity error interrupt mask */ + FillField(UART011_FEIM, "FEIM "), /* framing error interrupt mask */ + FillField(UART011_RTIM, "RTIM "), /* receive timeout interrupt mask */ + FillField(UART011_TXIM, "TXIM "), /* transmit interrupt mask */ + FillField(UART011_RXIM, "RXIM "), /* receive interrupt mask */ + FillField(UART011_DSRMIM, "DSRMIM "), /* DSR interrupt mask */ + FillField(UART011_DCDMIM, "DCDMIM "), /* DCD interrupt mask */ + FillField(UART011_CTSMIM, "CTSMIM "), /* CTS interrupt mask */ + FillField(UART011_RIMIM, "RIMIM "), /* RI interrupt mask */ + FillField(UART01x_CR_IIRLP, "CR_IIRLP "), /* SIR low power mode */ + FillField(UART01x_CR_SIREN, "SIREN "), /* SIR enable */ + FillField(UART01x_CR_UARTEN, "UARTEN "), /* UART enable */ + FillField(0, NULL), +}; + +static const struct _generic_bit_name dmacr_field[] = { + FillField(UART011_DMAONERR, "DMANOERR "), /* disable dma on error */ + FillField(UART011_TXDMAE, "TXDMAE "), /* enable transmit dma */ + FillField(UART011_RXDMAE, "RXDMAE "), /* enable receive dma */ + FillField(0, NULL), +}; + +static const struct _generic_bit_name fr_field[] = { + FillField(UART011_FR_RI, "FR_RI "), + FillField(UART011_FR_TXFE, "FR_TXFE "), + FillField(UART011_FR_RXFF, "FR_RXFF "), + FillField(UART01x_FR_TXFF, "FR_TXFF "), + FillField(UART01x_FR_RXFE, "FR_RXFE "), + FillField(UART01x_FR_BUSY, "FR_BUSY "), + FillField(UART01x_FR_DCD, "FR_DCD "), + FillField(UART01x_FR_DSR, "FR_DSR "), + FillField(UART01x_FR_CTS, "FR_CTS "), + FillField(0, NULL), +}; + +/** + */ +static char *generic_string_from_bits(char *txt, unsigned int value, const struct _generic_bit_name *pgb) +{ + char *p = txt; + + txt[0] = 0; + while (pgb->name) { + if (pgb->value & value) + p += sprintf(p, "%s", pgb->name); + pgb++; + } + return txt; +} + +#endif/*--- #if defined(AMBA_PL011_DUMP_REGISTER) ---*/ + + +/** + */ +static void pl011_dump_register(const char *prefix __maybe_unused, struct uart_port *port __maybe_unused) +{ +#if defined(AMBA_PL011_DUMP_REGISTER) + char txt[256]; + struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); + + unsigned int imsc = readw(uap->port.membase + UART011_IMSC); + unsigned int dmacr = readw(uap->port.membase + UART011_DMACR); + unsigned int fr = readw(uap->port.membase + UART01x_FR); + unsigned int cr = readw(uap->port.membase + UART011_CR); + + pr_info("%s:\n", prefix); + pr_info("IM = %08x %s\n", imsc, generic_string_from_bits(txt, imsc, imsc_field)); + pr_info("DMACR = %08x %s\n", dmacr, generic_string_from_bits(txt, dmacr, dmacr_field)); + pr_info("FR = %08x %s\n", fr, generic_string_from_bits(txt, fr, fr_field)); + pr_info("CR = %08x %s\n", cr, generic_string_from_bits(txt, cr, cr_field)); +#endif/*--- #if defined(AMBA_PL011_DUMP_REGISTER) ---*/ +} + +/** + */ +static int pl011_serial_dectuart_get_char(void) +{ + struct _pl011_dectuart *pdectuart = &pl011_dectuart; + int c; + + if (!pdectuart->port) + return -ENXIO; + + c = pl011_get_poll_char(pdectuart->port); + if (c == NO_POLL_CHAR) + return -EAGAIN; + return c; +} +/** + */ +static void pl011_serial_dectuart_put_char(unsigned char ch) +{ + struct uart_port *port = pl011_dectuart.port; + + if (port == NULL) { + return; + } + if (pl011_dectuart_is_busy(&pl011_dectuart)) + pl011_put_poll_char(port, ch); +} + +/** + */ +static void pl011_polling_mode(struct _pl011_dectuart *pdectuart) +{ + struct uart_port *port = pdectuart->port; + struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); + unsigned long flags; + + if (port->irq && (pdectuart->irq_off == 0)) { + pdectuart->irq_off = 1; + disable_irq(port->irq); + } + pl011_dump_register("before stop", port); + +#ifdef CONFIG_DMA_ENGINE + del_timer(&uap->dmarx.timer); +#endif + cancel_delayed_work_sync(&uap->tx_softirq_work); + __BUILD_AVM_CONTEXT_FUNC(spin_lock_irqsave)(&port->lock, flags); + if (pdectuart->save_im == 0) { + pdectuart->save_im = uap->im; + } + pl011_stop_tx(port); + pl011_stop_rx(port); + __BUILD_AVM_CONTEXT_FUNC(spin_unlock_irqrestore)(&port->lock, flags); + pl011_dump_register("after stop", port); +} + +/** + */ +static void pl011_irqdma_mode(struct _pl011_dectuart *pdectuart) +{ + struct uart_port *port = pdectuart->port; + struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); + unsigned long flags; + + __BUILD_AVM_CONTEXT_FUNC(spin_lock_irqsave) (&port->lock, flags); + pl011_dump_register("before start", port); + + if (pdectuart->save_im) { + /*--- fixup: not all irq-mask register-bits will restored with trigger-function below ---*/ + uap->im = pdectuart->save_im; + writew(uap->im, uap->port.membase + UART011_IMSC); + pdectuart->save_im = 0; + } + pl011_start_tx(port); + pl011_rx_chars(uap); + + if (port->irq && (pdectuart->irq_off)) { + pdectuart->irq_off = 0; + enable_irq(port->irq); + } + pl011_dump_register("after start", port); + __BUILD_AVM_CONTEXT_FUNC(spin_unlock_irqrestore)(&port->lock, flags); +} + +/** + * mode: != 0 Tx/Rx-Irq an + */ +static void pl011_serial_dectuart_init(unsigned int baud, int mode) +{ + struct _pl011_dectuart *pdectuart = &pl011_dectuart; + struct uart_port *port = pdectuart->port; + + if (port == NULL) { + return; + } + + pr_debug("%s: dect_baud=%u %s busy=%d\n", __func__, baud, + !mode ? "pollmode" : "not supported", + atomic_read(&pdectuart->busy)); + if (mode == 0) { + if ((atomic_inc_return(&pdectuart->busy) == 1) && + (pl011_dectuart_is_shared_uart(pdectuart) == 0)) { + pl011_startup(port); + } + pl011_polling_mode(pdectuart); + uart_set_options(port, NULL, baud, 0, 8, 0); + } +} +/** + */ +static void pl011_serial_console_stop(void) +{ + struct _pl011_dectuart *pdectuart = &pl011_dectuart; + struct uart_port *port = pdectuart->port; + + if (port) { + console_stop(port->cons); + } +} + +/** + */ +static void pl011_serial_console_start(void) +{ + struct _pl011_dectuart *pdectuart = &pl011_dectuart; + struct uart_port *port = pdectuart->port; + + if (port) { + atomic_set(&pdectuart->busy, 0); + uart_set_options(port, NULL, 115200, 0, 8, 0); + pl011_irqdma_mode(pdectuart); + console_start(port->cons); + } +} + +/** + */ +static void pl011_serial_dectuart_exit(void) +{ + struct _pl011_dectuart *pdectuart = &pl011_dectuart; + + if (atomic_xchg(&pdectuart->busy, 0)) { + pl011_irqdma_mode(pdectuart); + + pl011_shutdown(pdectuart->port); + } + pr_debug("%s\n", __func__); +} +#endif/*--- #if defined(CONFIG_AVM_ENHANCED) ---*/ + /* * While this can be a module, if builtin it's most likely the console * So let's leave module_exit but move module_init to an earlier place