--- zzzz-none-000/linux-4.9.276/drivers/usb/host/xhci.c 2021-07-20 14:21:16.000000000 +0000 +++ falcon-5530-750/linux-4.9.276/drivers/usb/host/xhci.c 2023-04-05 08:19:02.000000000 +0000 @@ -29,6 +29,9 @@ #include #include #include +#include +#include +#include #include "xhci.h" #include "xhci-trace.h" @@ -39,6 +42,17 @@ #define PORT_WAKE_BITS (PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E) +#if defined (CONFIG_GRX5_AVM_FRITZ_BOX) +/* 20190827 AVM/WKR USB3 ports switchable */ +int usb3port_config = 0; //default USB2 only +module_param(usb3port_config, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(usb3port_config, "Bitmask of allowed USB3 ports"); +#endif + +static void xhci_vbus_work_func(struct work_struct *work); +static DECLARE_DELAYED_WORK(xhci_vbus_work, xhci_vbus_work_func); +static int usb_power_gpio = -1; + /* Some 0.95 hardware can't handle the chain bit on a Link TRB being cleared */ static int link_quirk; module_param(link_quirk, int, S_IRUGO | S_IWUSR); @@ -564,6 +578,14 @@ /*-------------------------------------------------------------------------*/ +static void xhci_vbus_work_func(struct work_struct *work) +{ + if (usb_power_gpio >= 0) { + avm_gpio_out_bit(usb_power_gpio, 1); + pr_info("xHCI: delayed VBUS POWER on\n"); + } +} + static int xhci_run_finished(struct xhci_hcd *xhci) { if (xhci_start(xhci)) { @@ -576,6 +598,12 @@ if (xhci->quirks & XHCI_NEC_HOST) xhci_ring_cmd_db(xhci); + if (usb_power_gpio >= 0) { + cancel_delayed_work_sync(&xhci_vbus_work); + pr_info("xHCI: delay VBUS POWER on for 100 ms\n"); + schedule_delayed_work(&xhci_vbus_work, msecs_to_jiffies(100)); + } + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Finished xhci_run for USB3 roothub"); return 0; @@ -722,12 +750,32 @@ writel(ER_IRQ_DISABLE(temp), &xhci->ir_set->irq_pending); xhci_print_ir_set(xhci, 0); + /*== AVM/WKR 20220107: deactivate all ports if no power_gpio present ==*/ + if (usb_power_gpio < 0) { + int port_index = xhci->num_usb3_ports; + while (port_index--) { + writel(0, xhci->usb3_ports[port_index]); + pr_info("xHCI: USB3 port%d power off\n", port_index); + } + port_index = xhci->num_usb2_ports; + while (port_index--) { + writel(0, xhci->usb2_ports[port_index]); + pr_info("xHCI: USB2 port%d power off\n", port_index); + } + } + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "cleaning up memory"); xhci_mem_cleanup(xhci); xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xhci_stop completed - status = %x", readl(&xhci->op_regs->status)); mutex_unlock(&xhci->mutex); + + if (usb_power_gpio >= 0) { + cancel_delayed_work_sync(&xhci_vbus_work); + avm_gpio_out_bit(usb_power_gpio, 0); + pr_info("xHCI: delayed VBUS POWER off\n"); + } } /* @@ -5115,6 +5163,8 @@ static int __init xhci_hcd_init(void) { + int ret; + /* * Check the compiler generated sizes of structures that must be laid * out in specific ways for hardware access. @@ -5136,6 +5186,14 @@ if (usb_disabled()) return -ENODEV; + ret = avm_get_hw_config(AVM_HW_CONFIG_VERSION, "gpio_avm_usb_power_enable", &usb_power_gpio, NULL); + pr_info("xHCI: gpio_avm_usb_power_enable=%d\n", usb_power_gpio); + if (ret < 0) + return 0; + + avm_gpio_ctrl(usb_power_gpio, GPIO_PIN, GPIO_OUTPUT_PIN); + avm_gpio_out_bit(usb_power_gpio, 0); + return 0; }