--- zzzz-none-000/linux-5.4.213/drivers/tty/serial/msm_serial.c 2022-09-15 10:04:56.000000000 +0000 +++ miami-7690-761/linux-5.4.213/drivers/tty/serial/msm_serial.c 2024-05-29 11:20:02.000000000 +0000 @@ -8,7 +8,7 @@ */ #if defined(CONFIG_SERIAL_MSM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -# define SUPPORT_SYSRQ +#define SUPPORT_SYSRQ #endif #include @@ -31,6 +31,7 @@ #include #include #include +#include #define UART_MR1 0x0000 @@ -148,9 +149,9 @@ #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_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 { @@ -161,27 +162,34 @@ }; struct msm_dma { - struct dma_chan *chan; + struct dma_chan *chan; enum dma_data_direction dir; - dma_addr_t phys; - unsigned char *virt; - dma_cookie_t cookie; - u32 enable_bit; - unsigned int count; - struct dma_async_tx_descriptor *desc; + dma_addr_t phys; + unsigned char *virt; + dma_cookie_t cookie; + u32 enable_bit; + unsigned int count; + struct dma_async_tx_descriptor *desc; }; struct msm_port { - struct uart_port uart; - char name[16]; - struct clk *clk; - struct clk *pclk; - unsigned int imr; - int is_uartdm; - unsigned int old_snap_state; - bool break_detected; - struct msm_dma tx_dma; - struct msm_dma rx_dma; + struct uart_port uart; + char name[16]; + struct clk *clk; + struct clk *pclk; + unsigned int imr; + int is_uartdm; + unsigned int old_snap_state; + bool break_detected; + struct msm_dma tx_dma; + struct msm_dma rx_dma; + int pinctrl_rx_only_active; + struct pinctrl *pinctrl; + struct pinctrl_state *pinctrl_default; + struct pinctrl_state *pinctrl_rx_only; +#if defined(CONFIG_AVM_ENHANCED) + atomic_t reflink; +#endif }; #define UART_TO_MSM(uart_port) container_of(uart_port, struct msm_port, uart) @@ -896,7 +904,7 @@ pio_count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); dma_count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); - dma_min = 1; /* Always DMA */ + dma_min = 1; /* Always DMA */ if (msm_port->is_uartdm > UARTDM_1P3) { dma_count = UARTDM_TX_AIGN(dma_count); dma_min = UARTDM_BURST_SIZE; @@ -913,7 +921,7 @@ else err = msm_handle_tx_dma(msm_port, dma_count); - if (err) /* fall back to PIO mode */ + if (err) /* fall back to PIO mode */ msm_handle_tx_pio(port, pio_count); } @@ -935,7 +943,7 @@ spin_lock_irqsave(&port->lock, flags); misr = msm_read(port, UART_MISR); - msm_write(port, 0, UART_IMR); /* disable interrupt */ + msm_write(port, 0, UART_IMR); /* disable interrupt */ if (misr & UART_IMR_RXBREAK_START) { msm_port->break_detected = true; @@ -964,7 +972,7 @@ if (misr & UART_IMR_DELTA_CTS) msm_handle_delta_cts(port); - msm_write(port, msm_port->imr, UART_IMR); /* restore interrupt */ + msm_write(port, msm_port->imr, UART_IMR); /* restore interrupt */ spin_unlock_irqrestore(&port->lock, flags); return IRQ_HANDLED; @@ -980,21 +988,30 @@ 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); + struct device *dev = msm_port->uart.dev; unsigned int mr; /* 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); - msm_write(port, UART_CR_CMD_RESET_RFR, UART_CR); - mr = msm_read(port, UART_MR1); - mr &= ~UART_MR1_RX_RDY_CTL; - msm_write(port, mr, UART_MR1); + + if (of_find_property(dev->of_node, "qca,bt-rfr-fixup", NULL)) { + msm_write(port, UART_CR_CMD_SET_RFR, UART_CR); + } else { + msm_write(port, UART_CR_CMD_RESET_RFR, UART_CR); + mr = msm_read(port, UART_MR1); + mr &= ~UART_MR1_RX_RDY_CTL; + msm_write(port, mr, UART_MR1); + } /* Disable DM modes */ if (msm_port->is_uartdm) @@ -1026,9 +1043,9 @@ } struct msm_baud_map { - u16 divisor; - u8 code; - u8 rxstale; + u16 divisor; + u8 code; + u8 rxstale; }; static const struct msm_baud_map * @@ -1039,26 +1056,27 @@ 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[] = { - { 1, 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 }, + {1, 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}, }; - best = table; /* Default to smallest divider */ + best = table; /* Default to smallest divider */ target = clk_round_rate(msm_port->clk, 16 * baud); divisor = DIV_ROUND_CLOSEST(target, 16 * baud); @@ -1101,12 +1119,14 @@ } 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, rate; + struct device *dev = msm_port->uart.dev; + u32 tx_watermark = 10; flags = *saved_flags; spin_unlock_irqrestore(&port->lock, flags); @@ -1139,11 +1159,24 @@ watermark = (port->fifosize * 3) / 4; msm_write(port, watermark, UART_RFWR); +#if defined(CONFIG_AVM_ENHANCED) + /* JZ-114474: fix: tx_watermark should be zero + * if tx-irq too early we waste much time in msm_wait_for_xmitr() + */ + tx_watermark = 0; +#endif /* 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); @@ -1178,6 +1211,15 @@ unsigned int data, rfr_level, mask; int ret; +#if defined(CONFIG_AVM_ENHANCED) + unsigned int reflink = atomic_inc_return(&msm_port->reflink); + + if (reflink > 1) { + pr_debug("%s add reflink %d\n", __func__, reflink); + return 0; + } + pr_debug("%s ttyMSM%d %d\n", __func__, port->line, reflink); +#endif/*--- #if defined(CONFIG_AVM_ENHANCED) ---*/ snprintf(msm_port->name, sizeof(msm_port->name), "msm_serial%d", port->line); @@ -1228,8 +1270,18 @@ { struct msm_port *msm_port = UART_TO_MSM(port); +#if defined(CONFIG_AVM_ENHANCED) + unsigned int reflink = atomic_dec_return(&msm_port->reflink); + + if (reflink != 0) { + pr_debug("%s sub reflink %d\n", __func__, reflink); + return; + } + pr_debug("%s ttyMSM%d %d\n", __func__, port->line, reflink); +#endif/*--- #if defined(CONFIG_AVM_ENHANCED) ---*/ + msm_port->imr = 0; - msm_write(port, 0, UART_IMR); /* disable interrupts */ + msm_write(port, 0, UART_IMR); /* disable interrupts */ if (msm_port->is_uartdm) msm_release_dma(msm_port); @@ -1240,7 +1292,7 @@ } 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; @@ -1249,7 +1301,7 @@ spin_lock_irqsave(&port->lock, flags); - if (dma->chan) /* Terminate if any */ + if (dma->chan) /* Terminate if any */ msm_stop_dma(port, dma); /* calculate and set baud rate */ @@ -1394,7 +1446,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); @@ -1430,12 +1482,17 @@ static u32 slop; static int count; unsigned char *sp = (unsigned char *)&slop; + /*UARTDM_DMRX: Initializes RX transfer and configures maximal length in bytes + * of the transfer. + * Is needed for polling with irq disabled in order to receive bytes correctly. + */ + msm_write(port, 0xFFFFFF, UARTDM_DMRX); /* Check if a previous read had more than one char */ if (count) { c = sp[sizeof(slop) - count]; count--; - /* Or if FIFO is empty */ + /* 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 @@ -1455,7 +1512,7 @@ } else { c = NO_POLL_CHAR; } - /* FIFO has a word */ + /* FIFO has a word */ } else { slop = msm_read(port, UARTDM_RF); c = sp[0]; @@ -1485,8 +1542,10 @@ return c; } +#endif -static void msm_poll_put_char(struct uart_port *port, unsigned char c) +#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_AVM_ENHANCED) +static __maybe_unused void msm_poll_put_char(struct uart_port *port, unsigned char c) { u32 imr; struct msm_port *msm_port = UART_TO_MSM(port); @@ -1512,9 +1571,9 @@ /* 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 = { +static const struct uart_ops msm_uart_pops = { .tx_empty = msm_tx_empty, .set_mctrl = msm_set_mctrl, .get_mctrl = msm_get_mctrl, @@ -1533,19 +1592,37 @@ .verify_port = msm_verify_port, .pm = msm_power, #ifdef CONFIG_CONSOLE_POLL - .poll_get_char = msm_poll_get_char, - .poll_put_char = msm_poll_put_char, + .poll_get_char = msm_poll_get_char, + .poll_put_char = msm_poll_put_char, #endif }; 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 = 0, + .line = 2, }, }, { @@ -1554,7 +1631,7 @@ .ops = &msm_uart_pops, .flags = UPF_BOOT_AUTOCONF, .fifosize = 64, - .line = 1, + .line = 3, }, }, { @@ -1563,7 +1640,16 @@ .ops = &msm_uart_pops, .flags = UPF_BOOT_AUTOCONF, .fifosize = 64, - .line = 2, + .line = 4, + }, + }, + { + .uart = { + .iotype = UPIO_MEM, + .ops = &msm_uart_pops, + .flags = UPF_BOOT_AUTOCONF, + .fifosize = 64, + .line = 5, }, }, }; @@ -1577,7 +1663,8 @@ #ifdef CONFIG_SERIAL_MSM_CONSOLE static void __msm_console_write(struct uart_port *port, const char *s, - unsigned int count, bool is_uartdm) + unsigned int count, bool is_uartdm, + bool is_early) { unsigned long flags; int i; @@ -1585,6 +1672,13 @@ bool replaced = false; void __iomem *tf; int locked = 1; + struct msm_port *msm_port; + struct msm_dma *dma; + + if (!is_early) { + msm_port = UART_TO_MSM(port); + dma = &msm_port->tx_dma; + } if (is_uartdm) tf = port->membase + UARTDM_TF; @@ -1606,6 +1700,15 @@ else 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 ((!is_early) && (dma->count)) { + spin_unlock(&port->lock); + return; + } + if (is_uartdm) msm_reset_dm_count(port, count); @@ -1649,7 +1752,7 @@ } 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; @@ -1659,7 +1762,7 @@ port = msm_get_port_from_line(co->index); msm_port = UART_TO_MSM(port); - __msm_console_write(port, s, count, msm_port->is_uartdm); + __msm_console_write(port, s, count, msm_port->is_uartdm, false); } static int msm_console_setup(struct console *co, char *options) @@ -1689,11 +1792,11 @@ } static void -msm_serial_early_write(struct console *con, const char *s, unsigned n) +msm_serial_early_write(struct console *con, const char *s, unsigned int n) { struct earlycon_device *dev = con->data; - __msm_console_write(&dev->port, s, n, false); + __msm_console_write(&dev->port, s, n, false, true); } static int __init @@ -1706,14 +1809,14 @@ return 0; } 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) +msm_serial_early_write_dm(struct console *con, const char *s, unsigned int n) { struct earlycon_device *dev = con->data; - __msm_console_write(&dev->port, s, n, true); + __msm_console_write(&dev->port, s, n, true, true); } static int __init @@ -1727,7 +1830,7 @@ return 0; } 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; @@ -1758,20 +1861,111 @@ static atomic_t msm_uart_next_id = ATOMIC_INIT(0); 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 }, - { } + {.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}, + {} }; +static ssize_t avm_rx_only_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct platform_device *pdev = container_of(dev, struct platform_device, dev); + struct uart_port *port = platform_get_drvdata(pdev); + struct msm_port *msm_port = UART_TO_MSM(port); + + return sprintf(buf, "%d [0 1]\n", msm_port->pinctrl_rx_only_active); +} + +static ssize_t avm_rx_only_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct platform_device *pdev = container_of(dev, struct platform_device, dev); + struct uart_port *port = platform_get_drvdata(pdev); + struct msm_port *msm_port = UART_TO_MSM(port); + struct pinctrl_state *tgt; + long value; + int ret; + + ret = kstrtol(buf, 0, &value); + if (ret != 0 || (value != 0 && value != 1)) + return -EINVAL; + + tgt = value ? msm_port->pinctrl_rx_only : msm_port->pinctrl_default; + + ret = pinctrl_select_state(msm_port->pinctrl, tgt); + if (ret) + return ret; + + msm_port->pinctrl_rx_only_active = value; + + return len; +} + +static DEVICE_ATTR_RW(avm_rx_only); + +static int avm_rx_only_setup(struct platform_device *pdev) +{ + struct uart_port *port = platform_get_drvdata(pdev); + struct msm_port *msm_port = UART_TO_MSM(port); + int ret = 0; + + msm_port->pinctrl = devm_pinctrl_get(&pdev->dev); + if (IS_ERR(msm_port->pinctrl)) { + dev_info(&pdev->dev, "no pinctrl configured (%ld)\n", + PTR_ERR(msm_port->pinctrl)); + goto fail_null; + } + + msm_port->pinctrl_default = pinctrl_lookup_state(msm_port->pinctrl, PINCTRL_STATE_DEFAULT); + if (IS_ERR(msm_port->pinctrl_default)) { + dev_info(&pdev->dev, "no default pinctrl configured (%ld)\n", + PTR_ERR(msm_port->pinctrl_default)); + goto fail_put; + } + + msm_port->pinctrl_rx_only = pinctrl_lookup_state(msm_port->pinctrl, "avm,rx-only"); + if (IS_ERR(msm_port->pinctrl_rx_only)) + goto fail_put; + + dev_info(&pdev->dev, "enabling support for the rx only pinctrl setting\n"); + + ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_avm_rx_only.attr); + if (ret) + goto fail_put; + + msm_port->pinctrl_rx_only_active = 0; + + return 0; + +fail_put: + devm_pinctrl_put(msm_port->pinctrl); +fail_null: + msm_port->pinctrl = NULL; + msm_port->pinctrl_default = NULL; + msm_port->pinctrl_rx_only = NULL; + msm_port->pinctrl_rx_only_active = -1; + return ret; +} + +static void avm_rx_only_cleanup(struct platform_device *pdev) +{ + struct uart_port *port = platform_get_drvdata(pdev); + struct msm_port *msm_port = UART_TO_MSM(port); + + if (msm_port->pinctrl_rx_only_active >= 0) + sysfs_remove_file(&pdev->dev.kobj, &dev_attr_avm_rx_only.attr); +} + 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, line; + int irq, line, ret; if (pdev->dev.of_node) line = of_alias_get_id(pdev->dev.of_node, "serial"); @@ -1821,6 +2015,10 @@ platform_set_drvdata(pdev, port); + ret = avm_rx_only_setup(pdev); + if (ret < 0) + return ret; + return uart_add_one_port(&msm_uart_driver, port); } @@ -1828,14 +2026,15 @@ { struct uart_port *port = platform_get_drvdata(pdev); + avm_rx_only_cleanup(pdev); uart_remove_one_port(&msm_uart_driver, port); return 0; } static const struct of_device_id msm_match_table[] = { - { .compatible = "qcom,msm-uart" }, - { .compatible = "qcom,msm-uartdm" }, + {.compatible = "qcom,msm-uart"}, + {.compatible = "qcom,msm-uartdm"}, {} }; MODULE_DEVICE_TABLE(of, msm_match_table); @@ -1895,6 +2094,34 @@ 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); +} +#endif/*--- #if defined(CONFIG_AVM_ENHANCED) ---*/ + module_init(msm_serial_init); module_exit(msm_serial_exit);