--- zzzz-none-000/linux-5.15.111/drivers/tty/serial/serial_core.c 2023-05-11 14:00:40.000000000 +0000 +++ puma7-atom-6670-761/linux-5.15.111/drivers/tty/serial/serial_core.c 2024-02-07 10:23:21.000000000 +0000 @@ -25,10 +25,15 @@ #include #include #include +#include #include #include +#ifdef CONFIG_INTEL_UART_ENABLE_CONTROL +#include +#endif + /* * This is used to lock changes in serial line configuration. */ @@ -128,6 +133,9 @@ struct uart_state *state = tty->driver_data; struct uart_port *port = state->uart_port; + if (port->ops->wake_peer) + port->ops->wake_peer(port); + if (port && !uart_tx_stopped(port)) port->ops->start_tx(port); } @@ -2110,7 +2118,8 @@ * which can end up calling uart_set_options() for an already enabled * console via tty_find_polling_driver() and uart_poll_init(). */ - if (!uart_console_enabled(port) && !port->console_reinit) + if (!uart_console_enabled(port) && !(port->flags & UPF_AVM_POLLING) && + !port->console_reinit) uart_port_spin_lock_init(port); memset(&termios, 0, sizeof(struct ktermios)); @@ -2518,7 +2527,7 @@ if (!port) return; - if (ch == '\n') + if (ch == '\n' && !(port->flags & UPF_AVM_POLLING)) port->ops->poll_put_char(port, '\r'); port->ops->poll_put_char(port, ch); uart_port_deref(port); @@ -2568,6 +2577,188 @@ .shutdown = uart_tty_port_shutdown, }; +#ifdef CONFIG_AVM_TTY_POLLING +struct polling_tty_port { + struct tty_driver *driver; + int line; +}; + +struct polling_tty_port *avm_tty_poll_acquire(const char *ttyname) +{ + struct polling_tty_port *pport; + struct tty_driver *ttydrv; + struct uart_driver *drv; + struct uart_state *state; + struct uart_port *uport; + struct tty_port *port; + int line, err; + char name[40]; + + pr_debug("Acquiring polling tty port %s\n", ttyname); + + strlcpy(name, ttyname, sizeof(name)); + ttydrv = tty_find_polling_driver(name, &line); + if (!ttydrv) { + err = -ENODEV; + goto err_out; + } + + drv = ttydrv->driver_state; + state = drv->state + line; + if (!state) + goto noport; + port = &state->port; + + mutex_lock(&port->mutex); + + uport = uart_port_check(state); + if (!uport) { + mutex_unlock(&port->mutex); + goto noport; + } + + pport = kmalloc(sizeof(*pport), GFP_KERNEL); + if (!pport) { + err = -ENOMEM; + mutex_unlock(&port->mutex); + goto put_driver; + } + + if (uport->irq) + disable_irq(uport->irq); + pm_runtime_get_sync(uport->dev); + uport->flags |= UPF_AVM_POLLING; + + mutex_unlock(&port->mutex); + + pport->driver = ttydrv; + pport->line = line; + + return pport; +noport: + pr_err("No port state for %s\n", ttyname); + err = -EL3HLT; +put_driver: + tty_driver_kref_put(ttydrv); +err_out: + pr_err("Error acquiring polling tty port %s: %d\n", ttyname, err); + + return ERR_PTR(err); +} +EXPORT_SYMBOL(avm_tty_poll_acquire); + +int avm_tty_poll_configure(struct polling_tty_port *pport, int baud, + int parity, int bits, int flow) +{ + struct tty_driver *ttydrv = pport->driver; + struct uart_driver *drv; + struct uart_state *state; + struct uart_port *uport; + struct tty_port *port; + + pr_debug("Setting polling tty port %s%d to %u baud\n", + ttydrv->name, pport->line, baud); + + drv = ttydrv->driver_state; + state = drv->state + pport->line; + if (!state) + goto noport; + port = &state->port; + + mutex_lock(&port->mutex); + uport = uart_port_check(state); + if (!uport) { + mutex_unlock(&port->mutex); + goto noport; + } + uart_set_options(uport, NULL, baud, parity, bits, flow); + mutex_unlock(&port->mutex); + + return 0; +noport: + pr_err("Error setting baudrate of polling tty port %s%d: no port state\n", + ttydrv->name, pport->line); + return -EL3HLT; +} +EXPORT_SYMBOL(avm_tty_poll_configure); + +void avm_tty_poll_release(struct polling_tty_port *pport) +{ + struct tty_driver *ttydrv = pport->driver; + struct uart_driver *drv; + struct uart_state *state; + struct uart_port *uport; + struct tty_port *port; + + pr_debug("Releasing polling tty port %s%d\n", + ttydrv->name, pport->line); + + drv = ttydrv->driver_state; + state = drv->state + pport->line; + if (!state) + goto out; + + port = &state->port; + mutex_lock(&port->mutex); + + uport = uart_port_check(state); + if (!uport) { + mutex_unlock(&port->mutex); + goto out; + } + + if (uport->irq) + enable_irq(uport->irq); + + uport->flags &= ~UPF_AVM_POLLING; + + pm_runtime_put(uport->dev); + mutex_unlock(&port->mutex); +out: + tty_driver_kref_put(ttydrv); + kfree(pport); +} +EXPORT_SYMBOL(avm_tty_poll_release); + +int avm_tty_poll_get_char(struct polling_tty_port *pport) +{ + return pport->driver->ops->poll_get_char(pport->driver, pport->line); +} +EXPORT_SYMBOL(avm_tty_poll_get_char); + +void avm_tty_poll_put_char(struct polling_tty_port *pport, unsigned char c) +{ + pport->driver->ops->poll_put_char(pport->driver, pport->line, c); +} +EXPORT_SYMBOL(avm_tty_poll_put_char); +#endif /* CONFIG_AVM_TTY_POLLING */ + +#ifdef CONFIG_INTEL_UART_ENABLE_CONTROL +static ssize_t uart_get_attr_enable_ctrl(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int enable; + + if (intel_ce2700_read_atom_uartctrl(&enable) != IOCNFG_OK) + pr_err(KERN_ERR "Unable to read AtomUartCtrl status\n"); + + return sprintf(buf, "%d\n", enable); +} + +static ssize_t uart_set_attr_enable_ctrl(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int enable; + + enable = (int)(buf[0] - '0'); + if ((enable == 0) || (enable == 1)) + intel_ce2700_config_atom_uartctrl(enable); + else + pr_info(KERN_ERR "uart_enable_ctrl: 0(disable) / 1(enable) UART\n"); + + return count; +} +#endif /** * uart_register_driver - register a driver with the uart core layer * @drv: low level driver structure @@ -2872,6 +3063,9 @@ static DEVICE_ATTR_RO(iomem_base); static DEVICE_ATTR_RO(iomem_reg_shift); static DEVICE_ATTR_RW(console); +#ifdef CONFIG_INTEL_UART_ENABLE_CONTROL +static DEVICE_ATTR(uart_enable_ctrl, S_IRUSR | S_IWUSR, uart_get_attr_enable_ctrl, uart_set_attr_enable_ctrl); +#endif static struct attribute *tty_dev_attrs[] = { &dev_attr_uartclk.attr, @@ -3253,6 +3447,20 @@ EXPORT_SYMBOL_GPL(uart_try_toggle_sysrq); #endif +#ifdef CONFIG_INTEL_UART_ENABLE_CONTROL +int uart_sysfs_create_uart_enable_ctrl(void) +{ + int retval = sysfs_create_file(kernel_kobj, &dev_attr_uart_enable_ctrl.attr); + + if (retval) + return -ENOMEM; + + return retval; +} +EXPORT_SYMBOL_GPL(uart_sysfs_create_uart_enable_ctrl); +#endif + + EXPORT_SYMBOL(uart_write_wakeup); EXPORT_SYMBOL(uart_register_driver); EXPORT_SYMBOL(uart_unregister_driver);