From ca6885456fe2307d8cee850bd1c41e7ebfe74a38 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Fri, 6 Mar 2020 13:12:02 +0100 Subject: [PATCH] ath79: re-add accidentally dropped patch to kernel 5.4 Patch 0061-tty-serial-ar933x-uart-rs485-gpio.patch wasn't included when adding support for kernel 5.4. Re-add it and refresh patches. Fixes: 53ab9865c2 ("ath79: add support for kernel 5.4") Signed-off-by: Daniel Golle --- .../0036-GPIO-add-named-gpio-exports.patch | 8 +- ...61-tty-serial-ar933x-uart-rs485-gpio.patch | 267 ++++++++++++++++++ .../405-mtd-tp-link-partition-parser.patch | 4 +- .../910-unaligned_access_hacks.patch | 16 +- 4 files changed, 281 insertions(+), 14 deletions(-) create mode 100644 target/linux/ath79/patches-5.4/0061-tty-serial-ar933x-uart-rs485-gpio.patch diff --git a/target/linux/ath79/patches-5.4/0036-GPIO-add-named-gpio-exports.patch b/target/linux/ath79/patches-5.4/0036-GPIO-add-named-gpio-exports.patch index c07d3d3fea6..d4ea3791592 100644 --- a/target/linux/ath79/patches-5.4/0036-GPIO-add-named-gpio-exports.patch +++ b/target/linux/ath79/patches-5.4/0036-GPIO-add-named-gpio-exports.patch @@ -22,8 +22,8 @@ Signed-off-by: John Crispin #include "gpiolib.h" #include "gpiolib-of.h" -@@ -895,3 +897,68 @@ void of_gpiochip_remove(struct gpio_chip - gpiochip_remove_pin_ranges(chip); +@@ -915,3 +917,68 @@ void of_gpiochip_remove(struct gpio_chip + { of_node_put(chip->of_node); } + @@ -141,7 +141,7 @@ Signed-off-by: John Crispin { --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h -@@ -661,6 +661,7 @@ static inline void devm_acpi_dev_remove_ +@@ -668,6 +668,7 @@ static inline void devm_acpi_dev_remove_ #if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS) @@ -149,7 +149,7 @@ Signed-off-by: John Crispin int gpiod_export(struct gpio_desc *desc, bool direction_may_change); int gpiod_export_link(struct device *dev, const char *name, struct gpio_desc *desc); -@@ -668,6 +669,13 @@ void gpiod_unexport(struct gpio_desc *de +@@ -675,6 +676,13 @@ void gpiod_unexport(struct gpio_desc *de #else /* CONFIG_GPIOLIB && CONFIG_GPIO_SYSFS */ diff --git a/target/linux/ath79/patches-5.4/0061-tty-serial-ar933x-uart-rs485-gpio.patch b/target/linux/ath79/patches-5.4/0061-tty-serial-ar933x-uart-rs485-gpio.patch new file mode 100644 index 00000000000..54811eb4c1a --- /dev/null +++ b/target/linux/ath79/patches-5.4/0061-tty-serial-ar933x-uart-rs485-gpio.patch @@ -0,0 +1,267 @@ +From patchwork Fri Feb 21 21:23:31 2020 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Daniel Golle +X-Patchwork-Id: 1198835 +Date: Fri, 21 Feb 2020 22:23:31 +0100 +From: Daniel Golle +To: linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org +Cc: Greg Kroah-Hartman , + Jiri Slaby , Petr =?utf-8?q?=C5=A0tetiar?= , + Chuanhong Guo , Piotr Dymacz +Subject: [PATCH v2] serial: ar933x_uart: add RS485 support +Message-ID: <20200221212331.GA21467@makrotopia.org> +MIME-Version: 1.0 +Content-Disposition: inline +Sender: linux-kernel-owner@vger.kernel.org +Precedence: bulk +List-ID: +X-Mailing-List: linux-kernel@vger.kernel.org + +Emulate half-duplex operation and use mctrl_gpio to add support for +RS485 tranceiver with transmit/receive switch hooked to RTS GPIO line. +This is needed to make use of the RS485 port found on Teltonika RUT955. + +Signed-off-by: Daniel Golle +--- +v2: use bool to indicate ongoing half-duplex send, use it afterwards + to decide whether we've just been in a send operation. + + drivers/tty/serial/Kconfig | 1 + + drivers/tty/serial/ar933x_uart.c | 113 +++++++++++++++++++++++++++++-- + 2 files changed, 108 insertions(+), 6 deletions(-) + +--- a/drivers/tty/serial/Kconfig ++++ b/drivers/tty/serial/Kconfig +@@ -1279,6 +1279,7 @@ config SERIAL_AR933X + tristate "AR933X serial port support" + depends on HAVE_CLK && ATH79 + select SERIAL_CORE ++ select SERIAL_MCTRL_GPIO if GPIOLIB + help + If you have an Atheros AR933X SOC based board and want to use the + built-in UART of the SoC, say Y to this option. +--- a/drivers/tty/serial/ar933x_uart.c ++++ b/drivers/tty/serial/ar933x_uart.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -29,6 +30,8 @@ + + #include + ++#include "serial_mctrl_gpio.h" ++ + #define DRIVER_NAME "ar933x-uart" + + #define AR933X_UART_MAX_SCALE 0xff +@@ -47,6 +50,8 @@ struct ar933x_uart_port { + unsigned int min_baud; + unsigned int max_baud; + struct clk *clk; ++ struct mctrl_gpios *gpios; ++ struct gpio_desc *rts_gpiod; + }; + + static inline unsigned int ar933x_uart_read(struct ar933x_uart_port *up, +@@ -100,6 +105,18 @@ static inline void ar933x_uart_stop_tx_i + ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); + } + ++static inline void ar933x_uart_start_rx_interrupt(struct ar933x_uart_port *up) ++{ ++ up->ier |= AR933X_UART_INT_RX_VALID; ++ ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); ++} ++ ++static inline void ar933x_uart_stop_rx_interrupt(struct ar933x_uart_port *up) ++{ ++ up->ier &= ~AR933X_UART_INT_RX_VALID; ++ ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); ++} ++ + static inline void ar933x_uart_putc(struct ar933x_uart_port *up, int ch) + { + unsigned int rdata; +@@ -125,11 +142,21 @@ static unsigned int ar933x_uart_tx_empty + + static unsigned int ar933x_uart_get_mctrl(struct uart_port *port) + { +- return TIOCM_CAR; ++ struct ar933x_uart_port *up = ++ container_of(port, struct ar933x_uart_port, port); ++ int ret = TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; ++ ++ mctrl_gpio_get(up->gpios, &ret); ++ ++ return ret; + } + + static void ar933x_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) + { ++ struct ar933x_uart_port *up = ++ container_of(port, struct ar933x_uart_port, port); ++ ++ mctrl_gpio_set(up->gpios, mctrl); + } + + static void ar933x_uart_start_tx(struct uart_port *port) +@@ -140,6 +167,37 @@ static void ar933x_uart_start_tx(struct + ar933x_uart_start_tx_interrupt(up); + } + ++static void ar933x_uart_wait_tx_complete(struct ar933x_uart_port *up) ++{ ++ unsigned int status; ++ unsigned int timeout = 60000; ++ ++ /* Wait up to 60ms for the character(s) to be sent. */ ++ do { ++ status = ar933x_uart_read(up, AR933X_UART_CS_REG); ++ if (--timeout == 0) ++ break; ++ udelay(1); ++ } while (status & AR933X_UART_CS_TX_BUSY); ++ ++ if (timeout == 0) ++ dev_err(up->port.dev, "waiting for TX timed out\n"); ++} ++ ++static void ar933x_uart_rx_flush(struct ar933x_uart_port *up) ++{ ++ unsigned int status; ++ ++ /* clear RX_VALID interrupt */ ++ ar933x_uart_write(up, AR933X_UART_INT_REG, AR933X_UART_INT_RX_VALID); ++ ++ /* remove characters from the RX FIFO */ ++ do { ++ ar933x_uart_write(up, AR933X_UART_DATA_REG, AR933X_UART_DATA_RX_CSR); ++ status = ar933x_uart_read(up, AR933X_UART_DATA_REG); ++ } while (status & AR933X_UART_DATA_RX_CSR); ++} ++ + static void ar933x_uart_stop_tx(struct uart_port *port) + { + struct ar933x_uart_port *up = +@@ -153,8 +211,7 @@ static void ar933x_uart_stop_rx(struct u + struct ar933x_uart_port *up = + container_of(port, struct ar933x_uart_port, port); + +- up->ier &= ~AR933X_UART_INT_RX_VALID; +- ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); ++ ar933x_uart_stop_rx_interrupt(up); + } + + static void ar933x_uart_break_ctl(struct uart_port *port, int break_state) +@@ -336,11 +393,20 @@ static void ar933x_uart_rx_chars(struct + static void ar933x_uart_tx_chars(struct ar933x_uart_port *up) + { + struct circ_buf *xmit = &up->port.state->xmit; ++ struct serial_rs485 *rs485conf = &up->port.rs485; + int count; ++ bool half_duplex_send = false; + + if (uart_tx_stopped(&up->port)) + return; + ++ if ((rs485conf->flags & SER_RS485_ENABLED) && ++ (up->port.x_char || !uart_circ_empty(xmit))) { ++ ar933x_uart_stop_rx_interrupt(up); ++ gpiod_set_value(up->rts_gpiod, !!(rs485conf->flags & SER_RS485_RTS_ON_SEND)); ++ half_duplex_send = true; ++ } ++ + count = up->port.fifosize; + do { + unsigned int rdata; +@@ -368,8 +434,14 @@ static void ar933x_uart_tx_chars(struct + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&up->port); + +- if (!uart_circ_empty(xmit)) ++ if (!uart_circ_empty(xmit)) { + ar933x_uart_start_tx_interrupt(up); ++ } else if (half_duplex_send) { ++ ar933x_uart_wait_tx_complete(up); ++ ar933x_uart_rx_flush(up); ++ ar933x_uart_start_rx_interrupt(up); ++ gpiod_set_value(up->rts_gpiod, !!(rs485conf->flags & SER_RS485_RTS_AFTER_SEND)); ++ } + } + + static irqreturn_t ar933x_uart_interrupt(int irq, void *dev_id) +@@ -427,8 +499,7 @@ static int ar933x_uart_startup(struct ua + AR933X_UART_CS_TX_READY_ORIDE | AR933X_UART_CS_RX_READY_ORIDE); + + /* Enable RX interrupts */ +- up->ier = AR933X_UART_INT_RX_VALID; +- ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); ++ ar933x_uart_start_rx_interrupt(up); + + spin_unlock_irqrestore(&up->port.lock, flags); + +@@ -511,6 +582,21 @@ static const struct uart_ops ar933x_uart + .verify_port = ar933x_uart_verify_port, + }; + ++static int ar933x_config_rs485(struct uart_port *port, ++ struct serial_rs485 *rs485conf) ++{ ++ struct ar933x_uart_port *up = ++ container_of(port, struct ar933x_uart_port, port); ++ ++ if ((rs485conf->flags & SER_RS485_ENABLED) && ++ !up->rts_gpiod) { ++ dev_err(port->dev, "RS485 needs rts-gpio\n"); ++ return 1; ++ } ++ port->rs485 = *rs485conf; ++ return 0; ++} ++ + #ifdef CONFIG_SERIAL_AR933X_CONSOLE + static struct ar933x_uart_port * + ar933x_console_ports[CONFIG_SERIAL_AR933X_NR_UARTS]; +@@ -680,6 +766,8 @@ static int ar933x_uart_probe(struct plat + goto err_disable_clk; + } + ++ uart_get_rs485_mode(&pdev->dev, &port->rs485); ++ + port->mapbase = mem_res->start; + port->line = id; + port->irq = irq_res->start; +@@ -690,6 +778,7 @@ static int ar933x_uart_probe(struct plat + port->regshift = 2; + port->fifosize = AR933X_UART_FIFO_SIZE; + port->ops = &ar933x_uart_ops; ++ port->rs485_config = ar933x_config_rs485; + + baud = ar933x_uart_get_baud(port->uartclk, AR933X_UART_MAX_SCALE, 1); + up->min_baud = max_t(unsigned int, baud, AR933X_UART_MIN_BAUD); +@@ -697,6 +786,18 @@ static int ar933x_uart_probe(struct plat + baud = ar933x_uart_get_baud(port->uartclk, 0, AR933X_UART_MAX_STEP); + up->max_baud = min_t(unsigned int, baud, AR933X_UART_MAX_BAUD); + ++ up->gpios = mctrl_gpio_init(port, 0); ++ if (IS_ERR(up->gpios) && PTR_ERR(up->gpios) != -ENOSYS) ++ return PTR_ERR(up->gpios); ++ ++ up->rts_gpiod = mctrl_gpio_to_gpiod(up->gpios, UART_GPIO_RTS); ++ ++ if ((port->rs485.flags & SER_RS485_ENABLED) && ++ !up->rts_gpiod) { ++ dev_err(&pdev->dev, "lacking rts-gpio, disabling RS485\n"); ++ port->rs485.flags &= ~SER_RS485_ENABLED; ++ } ++ + #ifdef CONFIG_SERIAL_AR933X_CONSOLE + ar933x_console_ports[up->port.line] = up; + #endif diff --git a/target/linux/ath79/patches-5.4/405-mtd-tp-link-partition-parser.patch b/target/linux/ath79/patches-5.4/405-mtd-tp-link-partition-parser.patch index 7ea07f376c9..11d1869544a 100644 --- a/target/linux/ath79/patches-5.4/405-mtd-tp-link-partition-parser.patch +++ b/target/linux/ath79/patches-5.4/405-mtd-tp-link-partition-parser.patch @@ -21,5 +21,5 @@ obj-y += parsers/ +obj-$(CONFIG_MTD_TPLINK_PARTS) += tplinkpart.o - # 'Users' - code which presents functionality to userspace. - obj-$(CONFIG_MTD_BLKDEVS) += mtd_blkdevs.o + obj-$(CONFIG_MTD_SPLIT) += mtdsplit/ + diff --git a/target/linux/ath79/patches-5.4/910-unaligned_access_hacks.patch b/target/linux/ath79/patches-5.4/910-unaligned_access_hacks.patch index 950430a2a58..3ac89f1e5c8 100644 --- a/target/linux/ath79/patches-5.4/910-unaligned_access_hacks.patch +++ b/target/linux/ath79/patches-5.4/910-unaligned_access_hacks.patch @@ -305,7 +305,7 @@ list_for_each_entry(p, head, list) { --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c -@@ -457,48 +457,53 @@ static void tcp_options_write(__be32 *pt +@@ -460,48 +460,53 @@ static void tcp_options_write(__be32 *pt u16 options = opts->options; /* mungable copy */ if (unlikely(OPTION_MD5 & options)) { @@ -382,7 +382,7 @@ } if (unlikely(opts->num_sack_blocks)) { -@@ -506,16 +511,17 @@ static void tcp_options_write(__be32 *pt +@@ -509,16 +514,17 @@ static void tcp_options_write(__be32 *pt tp->duplicate_sack : tp->selective_acks; int this_sack; @@ -406,7 +406,7 @@ } tp->rx_opt.dsack = 0; -@@ -528,13 +534,14 @@ static void tcp_options_write(__be32 *pt +@@ -531,13 +537,14 @@ static void tcp_options_write(__be32 *pt if (foc->exp) { len = TCPOLEN_EXP_FASTOPEN_BASE + foc->len; @@ -706,7 +706,7 @@ EXPORT_SYMBOL(xfrm_parse_spi); --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -3953,14 +3953,16 @@ static bool tcp_parse_aligned_timestamp( +@@ -3958,14 +3958,16 @@ static bool tcp_parse_aligned_timestamp( { const __be32 *ptr = (const __be32 *)(th + 1); @@ -754,7 +754,7 @@ ptr = ip6hoff + sizeof(struct ipv6hdr); --- a/include/net/neighbour.h +++ b/include/net/neighbour.h -@@ -274,8 +274,10 @@ static inline bool neigh_key_eq128(const +@@ -273,8 +273,10 @@ static inline bool neigh_key_eq128(const const u32 *n32 = (const u32 *)n->primary_key; const u32 *p32 = pkey; @@ -780,7 +780,7 @@ * No flags defined yet. --- a/net/core/utils.c +++ b/net/core/utils.c -@@ -443,8 +443,14 @@ void inet_proto_csum_replace16(__sum16 * +@@ -460,8 +460,14 @@ void inet_proto_csum_replace16(__sum16 * bool pseudohdr) { __be32 diff[] = { @@ -799,7 +799,7 @@ *sum = csum_fold(csum_partial(diff, sizeof(diff), --- a/include/linux/etherdevice.h +++ b/include/linux/etherdevice.h -@@ -496,7 +496,7 @@ static inline bool is_etherdev_addr(cons +@@ -489,7 +489,7 @@ static inline bool is_etherdev_addr(cons * @b: Pointer to Ethernet header * * Compare two Ethernet headers, returns 0 if equal. @@ -808,7 +808,7 @@ * aligned OR the platform can handle unaligned access. This is the * case for all packets coming into netif_receive_skb or similar * entry points. -@@ -519,11 +519,12 @@ static inline unsigned long compare_ethe +@@ -512,11 +512,12 @@ static inline unsigned long compare_ethe fold |= *(unsigned long *)(a + 6) ^ *(unsigned long *)(b + 6); return fold; #else -- 2.30.2