USB: RK3288 USB CTLR initialization
[firefly-linux-kernel-4.4.55.git] / drivers / usb / host / ehci-rk.c
index 9b6fae73c0c192318162ddab17c83c3355a3354d..9bab80435673da9ea9500286f9790f103e0639b6 100755 (executable)
 #endif
 
 static int rkehci_status = 1;
+static struct ehci_hcd *g_ehci;
+#define EHCI_PRINT(x...)   printk( KERN_INFO "EHCI: " x )
+
+static struct rkehci_pdata_id rkehci_pdata[] = {
+       {
+               .name = "rk3188-reserved",
+               .pdata = NULL,
+       },
+       {
+               .name = "rk3288-ehci",
+               .pdata = &rkehci_pdata_rk3288,
+       },
+       { },
+};
+
 static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
 {
+       unsigned port;
+
+       if (!HCS_PPC (ehci->hcs_params))
+               return;
 
+       ehci_dbg (ehci, "...power%s ports...\n", is_on ? "up" : "down");
+       for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; )
+               (void) ehci_hub_control(ehci_to_hcd(ehci),
+                               is_on ? SetPortFeature : ClearPortFeature,
+                               USB_PORT_FEAT_POWER,
+                               port--, NULL, 0);
+       /* Flush those writes */
+       ehci_readl(ehci, &ehci->regs->command);
+       msleep(20);
 }
 
-static struct hc_driver rk_hc_driver = {
+static struct hc_driver rk_ehci_hc_driver = {
        .description            = hcd_name,
        .product_desc           = "Rockchip On-Chip EHCI Host Controller",
        .hcd_priv_size          = sizeof(struct ehci_hcd),
@@ -91,19 +119,191 @@ static ssize_t ehci_power_store( struct device *_dev,
                                        struct device_attribute *attr,
                                        const char *buf, size_t count )
 {
+       uint32_t val = simple_strtoul(buf, NULL, 16);
+       struct usb_hcd *hcd = dev_get_drvdata(_dev);
+       struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+       struct rkehci_platform_data *pldata = _dev->platform_data;
+
+       printk("%s: %d setting to: %d\n", __func__, rkehci_status, val);
+       if(val == rkehci_status)
+               goto out;
+
+       rkehci_status = val;
+       switch(val){
+               case 0: //power down
+                       ehci_port_power(ehci, 0);
+                       msleep(5);
+                       usb_remove_hcd(hcd);
+                       break;
+               case 1:// power on
+                       pldata->soft_reset();
+                       usb_add_hcd(hcd, hcd->irq, IRQF_DISABLED | IRQF_SHARED);
+                       ehci_port_power(ehci, 1);
+                       writel_relaxed(0x1d4d ,hcd->regs +0x90);
+                       writel_relaxed(0x4 ,hcd->regs +0xa0);
+                       dsb();
+                       break;
+               default:
+                       break;
+       }
+out:
        return count;
 }
 static DEVICE_ATTR(ehci_power, S_IRUGO|S_IWUSR, ehci_power_show, ehci_power_store);
 static ssize_t debug_show( struct device *_dev,
                                struct device_attribute *attr, char *buf)
 {
+       volatile uint32_t *addr;
+
+       EHCI_PRINT("******** EHCI Capability Registers **********\n");
+       addr = &g_ehci->caps->hc_capbase;
+       EHCI_PRINT("HCIVERSION / CAPLENGTH  @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = &g_ehci->caps->hcs_params;
+       EHCI_PRINT("HCSPARAMS               @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = &g_ehci->caps->hcc_params;
+       EHCI_PRINT("HCCPARAMS               @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       EHCI_PRINT("********* EHCI Operational Registers *********\n");
+       addr = &g_ehci->regs->command;
+       EHCI_PRINT("USBCMD                  @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = &g_ehci->regs->status;
+       EHCI_PRINT("USBSTS                  @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = &g_ehci->regs->intr_enable;
+       EHCI_PRINT("USBINTR                 @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = &g_ehci->regs->frame_index;
+       EHCI_PRINT("FRINDEX                 @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = &g_ehci->regs->segment;
+       EHCI_PRINT("CTRLDSSEGMENT           @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = &g_ehci->regs->frame_list;
+       EHCI_PRINT("PERIODICLISTBASE        @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr)); 
+       addr = &g_ehci->regs->async_next;
+       EHCI_PRINT("ASYNCLISTADDR           @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = &g_ehci->regs->configured_flag;
+       EHCI_PRINT("CONFIGFLAG              @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
+       addr = g_ehci->regs->port_status;
+       EHCI_PRINT("PORTSC                  @0x%08x:  0x%08x\n", (uint32_t)addr, readl_relaxed(addr));
        return sprintf(buf, "EHCI Registers Dump\n");
 }
 static DEVICE_ATTR(debug_ehci, S_IRUGO, debug_show, NULL);
+
+static struct of_device_id rk_ehci_of_match[] = {
+       {
+               .compatible = "rockchip,rk3288_rk_ehci_host",
+               .data = &rkehci_pdata[RK3288_USB_CTLR],
+       },
+       { },
+};
+MODULE_DEVICE_TABLE(of, rk_ehci_of_match);
+
 static int ehci_rk_probe(struct platform_device *pdev)
 {
+       struct usb_hcd *hcd;
+       struct ehci_hcd *ehci;
+       struct resource *res;
+       struct device *dev = &pdev->dev;
+       struct rkehci_platform_data *pldata;
+       int ret;
+       int retval = 0;
+       static u64 usb_dmamask = 0xffffffffUL;
+       struct device_node *node = pdev->dev.of_node;
+       struct rkehci_pdata_id *p;
+       const struct of_device_id *match =
+               of_match_device(of_match_ptr( rk_ehci_of_match ), &pdev->dev);
+
        dev_dbg(&pdev->dev, "ehci_rk proble\n");
+       
+       if (match){
+               p = (struct rkehci_pdata_id *)match->data;
+       }else{
+               dev_err(dev, "ehci_rk match failed\n");
+               return -EINVAL;
+       }
+
+       dev->platform_data = p->pdata;
+       pldata = dev->platform_data;
+       pldata->dev = dev;
+
+       if (!node) {
+               dev_err(dev, "device node not found\n");
+               return -EINVAL;
+       }
+
+       dev->dma_mask = &usb_dmamask;
+
+       retval = device_create_file(dev, &dev_attr_ehci_power);
+       retval = device_create_file(dev, &dev_attr_debug_ehci);
+       hcd = usb_create_hcd(&rk_ehci_hc_driver, &pdev->dev, dev_name(&pdev->dev));
+       if (!hcd) {
+               dev_err(&pdev->dev, "Unable to create HCD\n");
+               return  -ENOMEM;
+       }
+
+       if(pldata->hw_init)
+               pldata->hw_init();
+
+       if(pldata->clock_init){
+               pldata->clock_init(pldata);
+               pldata->clock_enable(pldata, 1);
+       }
+
+       if(pldata->soft_reset)
+               pldata->soft_reset();
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "Unable to get memory resource\n");
+               ret = -ENODEV;
+               goto put_hcd;
+       }
+
+       hcd->rsrc_start = res->start;
+       hcd->rsrc_len = resource_size(res);
+       hcd->regs = devm_ioremap_resource(dev, res);
+
+       if (!hcd->regs) {
+               dev_err(&pdev->dev, "ioremap failed\n");
+               ret = -ENOMEM;
+               goto put_hcd;
+       }
+
+       hcd->irq = platform_get_irq(pdev, 0);
+       if (hcd->irq < 0) {
+               dev_err(&pdev->dev, "Unable to get IRQ resource\n");
+               ret = hcd->irq;
+               goto put_hcd;
+       }
+
+       ehci = hcd_to_ehci(hcd);
+       ehci->caps = hcd->regs;
+       ehci->regs = hcd->regs + 0x10;
+       printk("%s %p %p\n", __func__, ehci->caps, ehci->regs);
+
+       dbg_hcs_params(ehci, "reset");
+       dbg_hcc_params(ehci, "reset");
+
+       ehci->hcs_params = readl(&ehci->caps->hcs_params);
+
+       ret = usb_add_hcd(hcd, hcd->irq, IRQF_DISABLED | IRQF_SHARED);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to add USB HCD\n");
+               goto put_hcd;
+       }
+
+       g_ehci = ehci;
+       ehci_port_power(ehci, 1);
+       writel_relaxed(0x1d4d ,hcd->regs +0x90);
+       writel_relaxed(0x4 ,hcd->regs +0xa0);
+       dsb();
+
+       printk("%s ok\n", __func__);
+
        return 0;
+put_hcd:
+       if(pldata->clock_enable)
+               pldata->clock_enable(pldata, 0);
+       usb_put_hcd(hcd);
+
+       return ret;
 }
 static int ehci_rk_remove(struct platform_device *pdev)
 {
@@ -156,13 +356,6 @@ static const struct dev_pm_ops ehci_rk_dev_pm_ops = {
        .resume          = ehci_rk_pm_resume,
 };
 
-static struct of_device_id rk_ehci_of_match[] = {
-       { .compatible = "rockchip,rk_ehci_host", },
-       { },
-};
-
-MODULE_DEVICE_TABLE(of, rk_ehci_of_match);
-
 static struct platform_driver ehci_rk_driver = {
        .probe  = ehci_rk_probe,
        .remove = ehci_rk_remove,