[USB] More OHCI Code. ohci_start.
authorBalaji Rao <balajirrao@gmail.com>
Wed, 30 Jul 2008 12:47:16 +0000 (18:17 +0530)
committerroot <root@localhost.localdomain>
Wed, 30 Jul 2008 12:47:16 +0000 (18:17 +0530)
src/drivers/bus/usb/ohci.h
src/drivers/bus/usb/ohci_hcd.c

index e7dbe90..0b0c13c 100644 (file)
@@ -172,6 +172,8 @@ struct ohci_hcd {
 
        uint32_t                hc_control;
        uint16_t                num_ports;
+
+       uint32_t                fminterval;
 };
 
 static inline struct ohci_hcd *hcd_to_ohci (struct usb_hcd *hcd)
@@ -179,6 +181,11 @@ static inline struct ohci_hcd *hcd_to_ohci (struct usb_hcd *hcd)
        return (struct ohci_hcd *) (hcd->hcpriv);
 }
 
+#define        FI                      0x2edf          /* 12000 bits per frame (-1) */
+#define        FSMP(fi)                (0x7fff & ((6 * ((fi) - 210)) / 7))
+#define        FIT                     (1 << 31)
+#define LSTHRESH               0x628           /* lowspeed bit threshold */
+
 #define read_roothub(hc, register, mask) (readl (&hc->regs->roothub.register))
 
 
@@ -190,3 +197,4 @@ static inline u32 roothub_status (struct ohci_hcd *hc)
        { return readl (&hc->regs->roothub.status); }
 static inline u32 roothub_portstatus (struct ohci_hcd *hc, int i)
        { return read_roothub (hc, portstatus [i], 0xffe0fce0); }
+
index 58ed3bf..112730a 100644 (file)
@@ -68,6 +68,7 @@ static int reset_port (struct ohci_hcd *ohci, int port)
        int             timeout = 500;
        
        temp = readl (portstat);
+       DBG("%d\n",port );
        if (!(temp & RH_PS_CCS))
                return -1;
        if (temp & RH_PS_PRSC)
@@ -80,10 +81,9 @@ static int reset_port (struct ohci_hcd *ohci, int port)
                timeout -= 10;
        }
        udelay(10);
-       
        /* Now enable the port */
        writel(RH_PS_PES, portstat);
-       mdelay(10);
+       udelay(10);
 
        return 0;
 
@@ -102,6 +102,72 @@ static struct hc_driver ohci_driver = {
        .reset_port = ohci_reset_port,
 };
 
+static int ohci_start(struct ohci_hcd *ohci)
+{
+       uint32_t temp;
+
+       temp = readl(ohci->regs->fminterval);
+       ohci->fminterval = temp & 0x3fff;
+
+       if (ohci->fminterval != FI)
+               DBG("fminterval delta %lx\n",ohci->fminterval - FI);
+       ohci->fminterval |= FSMP (ohci->fminterval) << 16;
+
+       switch (ohci->hc_control & OHCI_CTRL_HCFS) {
+       case OHCI_USB_OPER:
+               temp = 0;
+               break;
+       case OHCI_USB_SUSPEND:
+       case OHCI_USB_RESUME:
+               ohci->hc_control &= OHCI_CTRL_RWC;
+               ohci->hc_control |= OHCI_USB_RESUME;
+               temp = 10 /* msec wait */;
+               break;
+       // case OHCI_USB_RESET:
+       default:
+               ohci->hc_control &= OHCI_CTRL_RWC;
+               ohci->hc_control |= OHCI_USB_RESET;
+               temp = 50 /* msec wait */;
+               break;
+       }
+
+       writel(ohci->hc_control, &ohci->regs->control);
+       // flush the writes
+       (void) readl(&ohci->regs->control);
+       mdelay(temp);
+       
+       /* HC Reset requires max 10 us delay */
+       writel (OHCI_HCR,  &ohci->regs->cmdstatus);
+       temp = 30;      /* ... allow extra time */
+       while ((readl(&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
+               if (--temp == 0) {
+                       DBG("USB HC reset timed out!\n");
+                       return -1;
+               }
+               udelay (1);
+       }
+       /* now we're in the SUSPEND state ... must go OPERATIONAL
+        * within 2msec else HC enters RESUME
+        * Tell the controller where the control and bulk lists are
+        * The lists are empty now. 
+        */
+
+       writel(0, &ohci->regs->ed_controlhead);
+       writel(0, &ohci->regs->ed_bulkhead);
+
+       ohci->hc_control &= OHCI_CTRL_RWC;
+       ohci->hc_control |= OHCI_CTRL_CBSR | OHCI_USB_OPER;
+       writel(ohci->hc_control, &ohci->regs->control);
+
+       temp = roothub_a (ohci);
+       writel(RH_HS_LPSC, &ohci->regs->roothub.status);
+       writel((temp & RH_A_NPS) ? 0 : RH_B_PPCM, &ohci->regs->roothub.b);
+
+       // flush those writes
+       (void) readl(&ohci->regs->control);
+
+       return 0;
+}
 static int ohci_hcd_pci_probe(struct pci_device *pci,
                                        const struct pci_device_id *id __unused)
 {
@@ -144,25 +210,23 @@ static int ohci_hcd_pci_probe(struct pci_device *pci,
 
        ohci_init(ohci);
 
+       ohci_start(ohci);
        /* Look for devices at ports */
        
        for (port = 0; port < ohci->num_ports; port++) {
                uint32_t status = roothub_portstatus (ohci, port);
-
                if (!(status & RH_PS_CCS)) {
                        DBG("No device on port %d\n", port + 1);
                        continue;
                }
+               udev = usb_alloc_dev();
+               if(!udev)
+                       goto err_usb_alloc_dev;
+               udev->hcd = hcd;
+               /* Tell the usb core about the new device */
+               usb_dev_init(udev, port);
        }
 
-       udev = usb_alloc_dev();
-       if(!udev)
-               goto err_usb_alloc_dev;
-       
-       udev->hcd = hcd;
-       /* Tell the usb core about the new device */
-       usb_dev_init(udev, port);
-
        return 0;
 
        usb_free_dev(udev);