--- zzzz-none-000/linux-3.10.107/drivers/usb/host/xhci.c 2017-06-27 09:49:32.000000000 +0000 +++ vr9-7490-729/linux-3.10.107/drivers/usb/host/xhci.c 2021-11-10 11:53:55.000000000 +0000 @@ -28,11 +28,32 @@ #include #include +#ifdef CONFIG_VR9 +#include +#endif + +#if defined(CONFIG_ARCH_IPQ806X_DT) || defined(CONFIG_VR9) +#include +#include +#include + +static int usb_power_gpio = -1; +static struct delayed_work xhci_vbus_work; +#endif + #include "xhci.h" #define DRIVER_AUTHOR "Sarah Sharp" #define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver" + +#if defined(CONFIG_ARCH_IPQ806X_DT) || defined (CONFIG_VR9) +/* 20150210 AVM/WK 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 + /* 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); @@ -589,6 +610,19 @@ } #endif +#if defined(CONFIG_ARCH_IPQ806X_DT) || defined(CONFIG_VR9) +static void xhci_vbus_work_func(struct work_struct *work) { + if(usb_power_gpio > 0) { +#ifdef CONFIG_VR9 + ifx_gpio_output_set(usb_power_gpio, IFX_GPIO_MODULE_USB); +#else + avm_gpio_out_bit(usb_power_gpio , 1); /*--- VBUS ON ---*/ +#endif + printk(KERN_INFO "xHCI: delayed VBUS POWER on\n"); + } +} +#endif + static int xhci_run_finished(struct xhci_hcd *xhci) { if (xhci_start(xhci)) { @@ -601,6 +635,13 @@ if (xhci->quirks & XHCI_NEC_HOST) xhci_ring_cmd_db(xhci); +#if defined(CONFIG_ARCH_IPQ806X_DT) || defined(CONFIG_VR9) + /* 20180528 AVM/WKR delay VBUS power after host initialization */ + cancel_delayed_work_sync(&xhci_vbus_work); + printk(KERN_INFO "xHCI: delay VBUS POWER on for 100 ms\n"); + schedule_delayed_work(&xhci_vbus_work, msecs_to_jiffies(100)); +#endif + xhci_dbg(xhci, "Finished xhci_run for USB3 roothub\n"); return 0; } @@ -764,6 +805,20 @@ xhci_mem_cleanup(xhci); xhci_dbg(xhci, "xhci_stop completed - status = %x\n", xhci_readl(xhci, &xhci->op_regs->status)); + +#if defined(CONFIG_ARCH_IPQ806X_DT) || defined(CONFIG_VR9) + cancel_delayed_work_sync(&xhci_vbus_work); + + if(usb_power_gpio > 0) { +#ifdef CONFIG_VR9 + ifx_gpio_output_clear(usb_power_gpio, IFX_GPIO_MODULE_USB); +#else + avm_gpio_out_bit(usb_power_gpio , 0); /*--- VBUS OFF ---*/ +#endif + printk(KERN_INFO "xHCI: PORT POWER off"); + } +#endif + } /* @@ -2908,7 +2963,6 @@ xhci_ring_cmd_db(xhci); } virt_ep->stopped_td = NULL; - virt_ep->stopped_trb = NULL; virt_ep->stopped_stream = 0; spin_unlock_irqrestore(&xhci->lock, flags); @@ -3516,12 +3570,13 @@ { struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct xhci_virt_device *virt_dev; - struct device *dev = hcd->self.controller; unsigned long flags; u32 state; int i, ret; #ifndef CONFIG_USB_DEFAULT_PERSIST + struct device *dev = hcd->self.controller; + /* * We called pm_runtime_get_noresume when the device was attached. * Decrement the counter here to allow controller to runtime suspend @@ -3602,7 +3657,6 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); - struct device *dev = hcd->self.controller; unsigned long flags; int timeleft; int ret; @@ -3662,7 +3716,7 @@ * suspend if there is a device attached. */ if (xhci->quirks & XHCI_RESET_ON_RESUME) - pm_runtime_get_noresume(dev); + pm_runtime_get_noresume(hcd->self.controller); #endif /* Is this a LS or FS device under a HS hub? */ @@ -4729,6 +4783,10 @@ return 0; } +#ifdef XHCI_FWDOWNLOAD_72020x + XHCI_FWDOWNLOAD(hcd); +#endif + xhci->cap_regs = hcd->regs; xhci->op_regs = hcd->regs + HC_LENGTH(xhci_readl(xhci, &xhci->cap_regs->hc_capbase)); @@ -4795,9 +4853,43 @@ if (usb_disabled()) return -ENODEV; +#ifdef CONFIG_VR9 + INIT_DELAYED_WORK(&xhci_vbus_work, xhci_vbus_work_func); + retval = ifx_gpio_register(IFX_GPIO_MODULE_USB); + if (retval < 0) { + printk(KERN_ERR "Problem registering GPIO module."); + return retval; + } + retval = avm_get_hw_config(AVM_HW_CONFIG_VERSION, "gpio_usb_power_enable", &usb_power_gpio, NULL); + if (retval < 0) { + printk(KERN_DEBUG "Problem getting GPIO pin."); + ifx_gpio_deregister(IFX_GPIO_MODULE_USB); + return retval; + } + +#endif + +#if defined(CONFIG_ARCH_IPQ806X_DT) + INIT_DELAYED_WORK(&xhci_vbus_work, xhci_vbus_work_func); + retval = avm_get_hw_config(AVM_HW_CONFIG_VERSION, "gpio_avm_usb_power_enable", &usb_power_gpio, NULL); + if (retval < 0) { + printk(KERN_DEBUG "Problem getting GPIO pin."); + return retval; + } + avm_gpio_ctrl(usb_power_gpio, GPIO_PIN, GPIO_OUTPUT_PIN); + avm_gpio_out_bit(usb_power_gpio, 0); /* VBUS off */ + + //WKR/ temporary HACK: USB3 nur aktiv, wenn beide Ports aktiv sind. + if(usb3port_config != 3) usb3port_config=0; + +#endif + retval = xhci_register_pci(); if (retval < 0) { printk(KERN_DEBUG "Problem registering PCI driver."); +#ifdef CONFIG_VR9 + ifx_gpio_deregister(IFX_GPIO_MODULE_USB); +#endif return retval; } retval = xhci_register_plat(); @@ -4826,6 +4918,9 @@ return 0; unreg_pci: xhci_unregister_pci(); +#ifdef CONFIG_VR9 + ifx_gpio_deregister(IFX_GPIO_MODULE_USB); +#endif return retval; } module_init(xhci_hcd_init); @@ -4833,6 +4928,9 @@ static void __exit xhci_hcd_cleanup(void) { xhci_unregister_pci(); +#ifdef CONFIG_VR9 + ifx_gpio_deregister(IFX_GPIO_MODULE_USB); +#endif xhci_unregister_plat(); } module_exit(xhci_hcd_cleanup);