Merge tag 'v3.10.56' into update
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / usb / host / xhci.c
index 10223f2b18d20d0884b8e4328b86e56ced608666..c33a1f80c1c0a0d292bc152311dc1970610c30b7 100644 (file)
 
 #include "xhci.h"
 
+#ifdef CONFIG_MTK_XHCI
+#include <asm/uaccess.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/xhci/xhci-mtk-scheduler.h>
+#include <linux/xhci/xhci-mtk-power.h>
+#include <linux/xhci/xhci-mtk.h>
+
+#ifdef CONFIG_USBIF_COMPLIANCE
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
+#include <linux/seq_file.h>
+#include <linux/kobject.h>
+#include <linux/miscdevice.h>
+
+static struct miscdevice mu3h_uevent_device = {
+         .minor = MISC_DYNAMIC_MINOR,
+         .name = "usbif_u3h_uevent",
+         .fops = NULL,
+};
+#endif
+#endif
+
 #define DRIVER_AUTHOR "Sarah Sharp"
 #define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver"
 
@@ -38,6 +61,23 @@ static int link_quirk;
 module_param(link_quirk, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(link_quirk, "Don't clear the chain bit on a link TRB");
 
+#ifdef CONFIG_USBIF_COMPLIANCE
+int usbif_u3h_send_event(char* event)
+{
+       char udev_event[128];
+       char *envp[] = {udev_event, NULL };
+       int ret ;
+
+       snprintf(udev_event, 128, "USBIF_EVENT=%s",event);
+       printk("usbif_u3h_send_event - sending event - %s in %s\n", udev_event, kobject_get_path(&mu3h_uevent_device.this_device->kobj, GFP_KERNEL));
+       ret = kobject_uevent_env(&mu3h_uevent_device.this_device->kobj, KOBJ_CHANGE, envp);
+       if (ret < 0)
+               printk("usbif_u3h_send_event sending failed with ret = %d, \n", ret);
+
+       return ret;
+}
+#endif
+
 /* TODO: copied from ehci-hcd.c - can this be refactored? */
 /*
  * xhci_handshake - spin reading hc until handshake completes or fails
@@ -140,6 +180,7 @@ static int xhci_start(struct xhci_hcd *xhci)
                                XHCI_MAX_HALT_USEC);
        if (!ret)
                xhci->xhc_state &= ~XHCI_STATE_HALTED;
+
        return ret;
 }
 
@@ -521,6 +562,7 @@ int xhci_init(struct usb_hcd *hcd)
        } else {
                xhci_dbg(xhci, "xHCI doesn't need link TRB QUIRK\n");
        }
+
        retval = xhci_mem_init(xhci, GFP_KERNEL);
        xhci_dbg(xhci, "Finished xhci_init\n");
 
@@ -593,6 +635,7 @@ static int xhci_run_finished(struct xhci_hcd *xhci)
                xhci_halt(xhci);
                return -ENODEV;
        }
+
        xhci->shared_hcd->state = HC_STATE_RUNNING;
        xhci->cmd_ring_state = CMD_RING_STATE_RUNNING;
 
@@ -600,6 +643,7 @@ static int xhci_run_finished(struct xhci_hcd *xhci)
                xhci_ring_cmd_db(xhci);
 
        xhci_dbg(xhci, "Finished xhci_run for USB3 roothub\n");
+
        return 0;
 }
 
@@ -746,10 +790,10 @@ void xhci_stop(struct usb_hcd *hcd)
                xhci_dbg(xhci, "%s: compliance mode recovery timer deleted\n",
                                __func__);
        }
-
+#ifndef CONFIG_MTK_XHCI
        if (xhci->quirks & XHCI_AMD_PLL_FIX)
                usb_amd_dev_put();
-
+#endif
        xhci_dbg(xhci, "// Disabling event ring interrupts\n");
        temp = xhci_readl(xhci, &xhci->op_regs->status);
        xhci_writel(xhci, temp & ~STS_EINT, &xhci->op_regs->status);
@@ -1590,6 +1634,11 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
        u32 drop_flag;
        u32 new_add_flags, new_drop_flags, new_slot_info;
        int ret;
+#ifdef CONFIG_MTK_XHCI
+       struct sch_ep *sch_ep = NULL;
+       int isTT;
+       int ep_type = 0;
+#endif
 
        ret = xhci_check_args(hcd, udev, ep, 1, true, __func__);
        if (ret <= 0)
@@ -1641,12 +1690,44 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
 
        xhci_endpoint_zero(xhci, xhci->devs[udev->slot_id], ep);
 
+#ifdef CONFIG_MTK_XHCI
+       slot_ctx = xhci_get_slot_ctx(xhci, xhci->devs[udev->slot_id]->out_ctx);
+       if((slot_ctx->tt_info & 0xff) > 0){
+               isTT = 1;
+       }
+       else{
+               isTT = 0;
+       }
+       if(usb_endpoint_xfer_int(&ep->desc)){
+               ep_type = USB_EP_INT;
+       }
+       else if(usb_endpoint_xfer_isoc(&ep->desc)){
+               ep_type = USB_EP_ISOC;
+       }
+       else if(usb_endpoint_xfer_bulk(&ep->desc)){
+               ep_type = USB_EP_BULK;
+       }
+       sch_ep = mtk_xhci_scheduler_remove_ep(udev->speed, usb_endpoint_dir_in(&ep->desc)
+               , isTT, ep_type, (mtk_u32 *)ep);
+       if(sch_ep != NULL){
+               kfree(sch_ep);
+       }
+       else{
+               xhci_warn(xhci, "[MTK]Doesn't find ep_sch instance when removing endpoint\n");
+       }
+#endif
+
        xhci_dbg(xhci, "drop ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x, new slot info = %#x\n",
                        (unsigned int) ep->desc.bEndpointAddress,
                        udev->slot_id,
                        (unsigned int) new_drop_flags,
                        (unsigned int) new_add_flags,
                        (unsigned int) new_slot_info);
+
+       #if defined(CONFIG_MTK_XHCI) && defined(CONFIG_USB_MTK_DUALMODE)
+       mtk_ep_count_dec();
+       #endif
+
        return 0;
 }
 
@@ -1676,6 +1757,16 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
        u32 new_add_flags, new_drop_flags, new_slot_info;
        struct xhci_virt_device *virt_dev;
        int ret = 0;
+#ifdef CONFIG_MTK_XHCI
+       struct xhci_ep_ctx *in_ep_ctx;
+       struct sch_ep *sch_ep;
+       int isTT;
+       int ep_type = 0;
+       int maxp = 0;
+       int burst = 0;
+       int mult = 0;
+       int interval = 0;
+#endif
 
        ret = xhci_check_args(hcd, udev, ep, 1, true, __func__);
        if (ret <= 0) {
@@ -1738,6 +1829,46 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
                return -ENOMEM;
        }
 
+#ifdef CONFIG_MTK_XHCI
+       in_ep_ctx = xhci_get_ep_ctx(xhci, in_ctx, ep_index);
+       slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx);
+
+       if((slot_ctx->tt_info & 0xff) > 0){
+               isTT = 1;
+       }
+       else{
+               isTT = 0;
+       }
+       if(usb_endpoint_xfer_int(&ep->desc)){
+               ep_type = USB_EP_INT;
+       }
+       else if(usb_endpoint_xfer_isoc(&ep->desc)){
+               ep_type = USB_EP_ISOC;
+       }
+       else if(usb_endpoint_xfer_bulk(&ep->desc)){
+               ep_type = USB_EP_BULK;
+       }
+       if(udev->speed == USB_SPEED_FULL || udev->speed == USB_SPEED_HIGH
+               || udev->speed == USB_SPEED_LOW){
+               maxp = ep->desc.wMaxPacketSize & 0x7FF;
+               burst = ep->desc.wMaxPacketSize >> 11;
+               mult = 0;
+       }
+       else if(udev->speed == USB_SPEED_SUPER){
+               maxp = ep->desc.wMaxPacketSize & 0x7FF;
+               burst = ep->ss_ep_comp.bMaxBurst;
+               mult = ep->ss_ep_comp.bmAttributes & 0x3;
+       }
+       interval = (1 << ((in_ep_ctx->ep_info >> 16) & 0xff));
+       sch_ep = kmalloc(sizeof(struct sch_ep), GFP_KERNEL);
+       if(mtk_xhci_scheduler_add_ep(udev->speed, usb_endpoint_dir_in(&ep->desc),
+               isTT, ep_type, maxp, interval, burst, mult, (mtk_u32 *)ep
+               , (mtk_u32 *)in_ep_ctx, sch_ep) != SCH_SUCCESS){
+               xhci_err(xhci, "[MTK] not enough bandwidth\n");
+               return -ENOSPC;
+       }
+#endif
+
        ctrl_ctx->add_flags |= cpu_to_le32(added_ctxs);
        new_add_flags = le32_to_cpu(ctrl_ctx->add_flags);
 
@@ -1767,6 +1898,11 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
                        (unsigned int) new_drop_flags,
                        (unsigned int) new_add_flags,
                        (unsigned int) new_slot_info);
+
+       #if defined(CONFIG_MTK_XHCI) && defined(CONFIG_USB_MTK_DUALMODE)
+       mtk_ep_count_inc();
+       #endif
+
        return 0;
 }
 
@@ -3503,7 +3639,9 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
 {
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
        struct xhci_virt_device *virt_dev;
+#ifndef CONFIG_USB_DEFAULT_PERSIST
        struct device *dev = hcd->self.controller;
+#endif
        unsigned long flags;
        u32 state;
        int i, ret;
@@ -4708,6 +4846,12 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
                return 0;
        }
 
+#ifdef CONFIG_MTK_XHCI
+       retval = mtk_xhci_ip_init(hcd, xhci);
+       if(retval)
+               goto error;
+#endif
+
        xhci->cap_regs = hcd->regs;
        xhci->op_regs = hcd->regs +
                HC_LENGTH(xhci_readl(xhci, &xhci->cap_regs->hc_capbase));
@@ -4757,6 +4901,9 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
        if (retval)
                goto error;
        xhci_dbg(xhci, "Called HCD init\n");
+
+    printk("%s(%d): do mtk_xhci_set\n", __func__, __LINE__);
+
        return 0;
 error:
        kfree(xhci);
@@ -4767,6 +4914,189 @@ MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_LICENSE("GPL");
 
+#ifdef CONFIG_USBIF_COMPLIANCE
+#ifndef CONFIG_USB_MTK_DUALMODE
+static int xhci_hcd_driver_init(void)
+{
+       int retval;
+
+       retval = xhci_register_pci();
+       if (retval < 0) {
+               printk(KERN_DEBUG "Problem registering PCI driver.");
+               return retval;
+       }
+
+    #ifdef CONFIG_MTK_XHCI
+    mtk_xhci_ip_init();
+    #endif
+
+       retval = xhci_register_plat();
+       if (retval < 0) {
+               printk(KERN_DEBUG "Problem registering platform driver.");
+               goto unreg_pci;
+       }
+
+    #ifdef CONFIG_MTK_XHCI
+    retval = xhci_attrs_init();
+    if(retval < 0){
+        printk(KERN_DEBUG "Problem creating xhci attributes.");
+        goto unreg_plat;
+    }
+
+    mtk_xhci_wakelock_init();
+    #endif
+
+       /*
+        * Check the compiler generated sizes of structures that must be laid
+        * out in specific ways for hardware access.
+        */
+       BUILD_BUG_ON(sizeof(struct xhci_doorbell_array) != 256*32/8);
+       BUILD_BUG_ON(sizeof(struct xhci_slot_ctx) != 8*32/8);
+       BUILD_BUG_ON(sizeof(struct xhci_ep_ctx) != 8*32/8);
+       /* xhci_device_control has eight fields, and also
+        * embeds one xhci_slot_ctx and 31 xhci_ep_ctx
+        */
+       BUILD_BUG_ON(sizeof(struct xhci_stream_ctx) != 4*32/8);
+       BUILD_BUG_ON(sizeof(union xhci_trb) != 4*32/8);
+       BUILD_BUG_ON(sizeof(struct xhci_erst_entry) != 4*32/8);
+       BUILD_BUG_ON(sizeof(struct xhci_cap_regs) != 7*32/8);
+       BUILD_BUG_ON(sizeof(struct xhci_intr_reg) != 8*32/8);
+       /* xhci_run_regs has eight fields and embeds 128 xhci_intr_regs */
+       BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*128)*32/8);
+       return 0;
+
+#ifdef CONFIG_MTK_XHCI
+unreg_plat:
+    xhci_unregister_plat();
+#endif
+unreg_pci:
+       xhci_unregister_pci();
+       return retval;
+}
+
+static void xhci_hcd_driver_cleanup(void)
+{
+       xhci_unregister_pci();
+       xhci_unregister_plat();
+    xhci_attrs_exit();
+}
+#else
+static int xhci_hcd_driver_init(void)
+{
+       // init in mt_devs.c
+       mtk_xhci_eint_iddig_init();
+       mtk_xhci_switch_init();
+       //mtk_xhci_wakelock_init();
+       return 0;
+}
+
+static void xhci_hcd_driver_cleanup(void)
+{
+       mtk_xhci_eint_iddig_deinit() ;
+}
+
+#endif
+
+static int mu3h_normal_driver_on = 0 ;
+
+static int xhci_mu3h_proc_show(struct seq_file *seq, void *v)
+{
+        seq_printf(seq, "xhci_mu3h_proc_show, mu3h is %d (on:1, off:0)\n", mu3h_normal_driver_on);
+        return 0;
+}
+
+static int xhci_mu3h_proc_open(struct inode *inode, struct file *file)
+{
+    return single_open(file, xhci_mu3h_proc_show, inode->i_private);
+}
+
+static ssize_t xhci_mu3h_proc_write(struct file *file, const char __user *buf, size_t length, loff_t *ppos)
+{
+       int ret ;
+       char msg[32] ;
+       int result;
+
+       if (length >= sizeof(msg)) {
+               printk( "xhci_mu3h_proc_write length error, the error len is %d\n", (unsigned int)length);
+               return -EINVAL;
+       }
+       if (copy_from_user(msg, buf, length))
+               return -EFAULT;
+
+       msg[length] = 0 ;
+
+       printk("xhci_mu3h_proc_write: %s, current driver on/off: %d\n", msg, mu3h_normal_driver_on);
+
+       if ((msg[0] == '1') && (mu3h_normal_driver_on == 0)){
+               xhci_hcd_driver_init() ;
+               mu3h_normal_driver_on = 1 ;
+               printk("registe mu3h driver : m3h xhci driver\n");
+       }else if ((msg[0] == '0') && (mu3h_normal_driver_on == 1)){
+               xhci_hcd_driver_cleanup();
+               mu3h_normal_driver_on = 0 ;
+               printk("unregiste m3h xhci driver.\n");
+       }else{
+               printk("xhci_mu3h_proc_write write faile !\n");
+       }
+       return length;
+}
+
+static const struct file_operations mu3h_proc_fops = {
+       .owner = THIS_MODULE,
+       .open = xhci_mu3h_proc_open,
+       .write = xhci_mu3h_proc_write,
+       .read = seq_read,
+       .llseek = seq_lseek,
+
+};
+
+static int __init xhci_hcd_init(void)
+{
+       struct proc_dir_entry *prEntry;
+
+       printk(KERN_DEBUG "xhci_hcd_init");
+
+       // set xhci up at boot up
+       xhci_hcd_driver_init() ;
+       mtk_xhci_wakelock_init();
+       mu3h_normal_driver_on = 1;
+
+       // USBIF
+       prEntry = proc_create("mu3h_driver_init", 0666, NULL, &mu3h_proc_fops);
+       if (prEntry)
+       {
+               printk("create the mu3h init proc OK!\n") ;
+       }else{
+               printk("[ERROR] create the mu3h init proc FAIL\n") ;
+       }
+
+#ifdef CONFIG_MTK_XHCI
+
+       if (!misc_register(&mu3h_uevent_device)){
+               printk("create the mu3h_uevent_device uevent device OK!\n") ;
+
+       }else{
+               printk("[ERROR] create the mu3h_uevent_device uevent device fail\n") ;
+       }
+
+#endif
+
+       return 0 ;
+
+}
+module_init(xhci_hcd_init);
+
+static void __exit xhci_hcd_cleanup(void)
+{
+#ifdef CONFIG_MTK_XHCI
+       misc_deregister(&mu3h_uevent_device);
+#endif
+       printk(KERN_DEBUG "xhci_hcd_cleanup");
+}
+module_exit(xhci_hcd_cleanup);
+
+#else
+#ifndef CONFIG_USB_MTK_DUALMODE
 static int __init xhci_hcd_init(void)
 {
        int retval;
@@ -4781,6 +5111,17 @@ static int __init xhci_hcd_init(void)
                printk(KERN_DEBUG "Problem registering platform driver.");
                goto unreg_pci;
        }
+
+    #ifdef CONFIG_MTK_XHCI
+    retval = xhci_attrs_init();
+    if(retval < 0){
+        printk(KERN_DEBUG "Problem creating xhci attributes.");
+        goto unreg_plat;
+    }
+
+    mtk_xhci_wakelock_init();
+    #endif
+
        /*
         * Check the compiler generated sizes of structures that must be laid
         * out in specific ways for hardware access.
@@ -4799,6 +5140,11 @@ static int __init xhci_hcd_init(void)
        /* xhci_run_regs has eight fields and embeds 128 xhci_intr_regs */
        BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*128)*32/8);
        return 0;
+
+#ifdef CONFIG_MTK_XHCI
+unreg_plat:
+    xhci_unregister_plat();
+#endif
 unreg_pci:
        xhci_unregister_pci();
        return retval;
@@ -4809,5 +5155,23 @@ static void __exit xhci_hcd_cleanup(void)
 {
        xhci_unregister_pci();
        xhci_unregister_plat();
+    xhci_attrs_exit();
 }
 module_exit(xhci_hcd_cleanup);
+#else
+static int __init xhci_hcd_init(void)
+{
+    mtk_xhci_eint_iddig_init();
+    mtk_xhci_switch_init();
+    mtk_xhci_wakelock_init();
+       return 0;
+}
+module_init(xhci_hcd_init);
+
+static void __exit xhci_hcd_cleanup(void)
+{
+}
+module_exit(xhci_hcd_cleanup);
+
+#endif
+#endif