pci: usb: ohci: Test on PCI not DM_PCI
[platform/kernel/u-boot.git] / drivers / usb / host / ohci-hcd.c
index 5364ced..fedf0db 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * URB OHCI HCD (Host Controller Driver) for USB on the AT91RM9200 and PCI bus.
  *
@@ -16,8 +17,6 @@
  *
  * Modified for the MP2USB by (C) Copyright 2005 Eric Benard
  * ebenard@eukrea.com - based on s3c24x0's driver
- *
- * SPDX-License-Identifier:    GPL-2.0+
  */
 /*
  * IMPORTANT NOTES
  */
 
 #include <common.h>
+#include <cpu_func.h>
 #include <asm/byteorder.h>
 #include <dm.h>
 #include <errno.h>
+#include <asm/cache.h>
+#include <linux/delay.h>
 
 #if defined(CONFIG_PCI_OHCI)
 # include <pci.h>
@@ -41,6 +43,7 @@
 #endif
 
 #include <malloc.h>
+#include <memalign.h>
 #include <usb.h>
 
 #include "ohci.h"
 #endif
 
 #if defined(CONFIG_CPU_ARM920T) || \
-    defined(CONFIG_S3C24X0) || \
-    defined(CONFIG_440EP) || \
-    defined(CONFIG_PCI_OHCI) || \
-    defined(CONFIG_MPC5200) || \
-    defined(CONFIG_SYS_OHCI_USE_NPS)
+       defined(CONFIG_PCI_OHCI) || \
+       defined(CONFIG_PCI) || \
+       defined(CONFIG_SYS_OHCI_USE_NPS)
 # define OHCI_USE_NPS          /* force NoPowerSwitching mode */
 #endif
 
@@ -67,6 +68,7 @@
 #define OHCI_CONTROL_INIT \
        (OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE
 
+#if !CONFIG_IS_ENABLED(DM_USB)
 #ifdef CONFIG_PCI_OHCI
 static struct pci_device_id ohci_pci_ids[] = {
        {0x10b9, 0x5237},       /* ULI1575 PCI OHCI module ids */
@@ -76,6 +78,7 @@ static struct pci_device_id ohci_pci_ids[] = {
        {0, 0}
 };
 #endif
+#endif
 
 #ifdef CONFIG_PCI_EHCI_DEVNO
 static struct pci_device_id ehci_pci_ids[] = {
@@ -105,21 +108,13 @@ static struct pci_device_id ehci_pci_ids[] = {
 # define m32_swap(x) cpu_to_le32(x)
 #endif /* CONFIG_SYS_OHCI_BE_CONTROLLER */
 
-#ifdef CONFIG_DM_USB
-/*
- * We really should do proper cache flushing everywhere, but for now we only
- * do it for new (driver-model) usb code to avoid regressions.
- */
+/* We really should do proper cache flushing everywhere */
 #define flush_dcache_buffer(addr, size) \
        flush_dcache_range((unsigned long)(addr), \
                ALIGN((unsigned long)(addr) + size, ARCH_DMA_MINALIGN))
 #define invalidate_dcache_buffer(addr, size) \
        invalidate_dcache_range((unsigned long)(addr), \
                ALIGN((unsigned long)(addr) + size, ARCH_DMA_MINALIGN))
-#else
-#define flush_dcache_buffer(addr, size)
-#define invalidate_dcache_buffer(addr, size)
-#endif
 
 /* Do not use sizeof(ed / td) as our ed / td structs contain extra members */
 #define flush_dcache_ed(addr) flush_dcache_buffer(addr, 16)
@@ -131,7 +126,7 @@ static struct pci_device_id ehci_pci_ids[] = {
 #define invalidate_dcache_iso_td(addr) invalidate_dcache_buffer(addr, 32)
 #define invalidate_dcache_hcca(addr) invalidate_dcache_buffer(addr, 256)
 
-#ifdef CONFIG_DM_USB
+#if CONFIG_IS_ENABLED(DM_USB)
 /*
  * The various ohci_mdelay(1) calls in the code seem unnecessary. We keep
  * them around when building for older boards not yet converted to the dm
@@ -142,7 +137,7 @@ static struct pci_device_id ehci_pci_ids[] = {
 #define ohci_mdelay(x) mdelay(x)
 #endif
 
-#ifndef CONFIG_DM_USB
+#if !CONFIG_IS_ENABLED(DM_USB)
 /* global ohci_t */
 static ohci_t gohci;
 /* this must be aligned to a 256 byte boundary */
@@ -689,7 +684,7 @@ static int ep_link(ohci_t *ohci, ed_t *edi)
                ed->hwNextED = 0;
                flush_dcache_ed(ed);
                if (ohci->ed_controltail == NULL)
-                       ohci_writel(ed, &ohci->regs->ed_controlhead);
+                       ohci_writel((uintptr_t)ed, &ohci->regs->ed_controlhead);
                else
                        ohci->ed_controltail->hwNextED =
                                                   m32_swap((unsigned long)ed);
@@ -707,7 +702,7 @@ static int ep_link(ohci_t *ohci, ed_t *edi)
                ed->hwNextED = 0;
                flush_dcache_ed(ed);
                if (ohci->ed_bulktail == NULL)
-                       ohci_writel(ed, &ohci->regs->ed_bulkhead);
+                       ohci_writel((uintptr_t)ed, &ohci->regs->ed_bulkhead);
                else
                        ohci->ed_bulktail->hwNextED =
                                                   m32_swap((unsigned long)ed);
@@ -760,18 +755,16 @@ static void periodic_unlink(struct ohci *ohci, volatile struct ed *ed,
 
                /* ED might have been unlinked through another path */
                while (*ed_p != 0) {
-                       if (((struct ed *)
+                       if (((struct ed *)(uintptr_t)
                                        m32_swap((unsigned long)ed_p)) == ed) {
                                *ed_p = ed->hwNextED;
-#ifdef CONFIG_DM_USB
                                aligned_ed_p = (unsigned long)ed_p;
                                aligned_ed_p &= ~(ARCH_DMA_MINALIGN - 1);
                                flush_dcache_range(aligned_ed_p,
                                        aligned_ed_p + ARCH_DMA_MINALIGN);
-#endif
                                break;
                        }
-                       ed_p = &(((struct ed *)
+                       ed_p = &(((struct ed *)(uintptr_t)
                                     m32_swap((unsigned long)ed_p))->hwNextED);
                }
        }
@@ -807,7 +800,7 @@ static int ep_unlink(ohci_t *ohci, ed_t *edi)
                if (ohci->ed_controltail == ed) {
                        ohci->ed_controltail = ed->ed_prev;
                } else {
-                       ((ed_t *)m32_swap(
+                       ((ed_t *)(uintptr_t)m32_swap(
                            *((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
                }
                break;
@@ -828,7 +821,7 @@ static int ep_unlink(ohci_t *ohci, ed_t *edi)
                if (ohci->ed_bulktail == ed) {
                        ohci->ed_bulktail = ed->ed_prev;
                } else {
-                       ((ed_t *)m32_swap(
+                       ((ed_t *)(uintptr_t)m32_swap(
                             *((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
                }
                break;
@@ -923,12 +916,13 @@ static void td_fill(ohci_t *ohci, unsigned int info,
 
        /* fill the old dummy TD */
        td = urb_priv->td [index] =
-                            (td_t *)(m32_swap(urb_priv->ed->hwTailP) & ~0xf);
+                            (td_t *)(uintptr_t)
+                            (m32_swap(urb_priv->ed->hwTailP) & ~0xf);
 
        td->ed = urb_priv->ed;
        td->next_dl_td = NULL;
        td->index = index;
-       td->data = (__u32)data;
+       td->data = (uintptr_t)data;
 #ifdef OHCI_FILL_TRACE
        if (usb_pipebulk(urb_priv->pipe) && usb_pipeout(urb_priv->pipe)) {
                for (i = 0; i < len; i++)
@@ -972,7 +966,7 @@ static void td_submit_job(ohci_t *ohci, struct usb_device *dev,
        flush_dcache_buffer(buffer, data_len);
 
        /* OHCI handles the DATA-toggles itself, we just use the USB-toggle
-        * bits for reseting */
+        * bits for resetting */
        if (usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) {
                toggle = TD_T_TOGGLE;
        } else {
@@ -1097,10 +1091,6 @@ static void check_status(td_t *td_list)
                                *phwHeadP &= m32_swap(0xfffffff2);
                        flush_dcache_ed(td_list->ed);
                }
-#ifdef CONFIG_MPC5200
-               td_list->hwNextTD = 0;
-               flush_dcache_td(td_list);
-#endif
        }
 }
 
@@ -1108,7 +1098,7 @@ static void check_status(td_t *td_list)
  * we reverse the reversed done-list */
 static td_t *dl_reverse_done_list(ohci_t *ohci)
 {
-       __u32 td_list_hc;
+       uintptr_t td_list_hc;
        td_t *td_rev = NULL;
        td_t *td_list = NULL;
 
@@ -1505,6 +1495,26 @@ static ohci_dev_t *ohci_get_ohci_dev(ohci_t *ohci, int devnum, int intr)
 
 /* common code for handling submit messages - used for all but root hub */
 /* accesses. */
+static urb_priv_t *ohci_alloc_urb(struct usb_device *dev, unsigned long pipe,
+               void *buffer, int transfer_len, int interval)
+{
+       urb_priv_t *urb;
+
+       urb = calloc(1, sizeof(urb_priv_t));
+       if (!urb) {
+               printf("ohci: Error out of memory allocating urb\n");
+               return NULL;
+       }
+
+       urb->dev = dev;
+       urb->pipe = pipe;
+       urb->transfer_buffer = buffer;
+       urb->transfer_buffer_length = transfer_len;
+       urb->interval = interval;
+
+       return urb;
+}
+
 static int submit_common_msg(ohci_t *ohci, struct usb_device *dev,
                unsigned long pipe, void *buffer, int transfer_len,
                struct devrequest *setup, int interval)
@@ -1515,14 +1525,9 @@ static int submit_common_msg(ohci_t *ohci, struct usb_device *dev,
        urb_priv_t *urb;
        ohci_dev_t *ohci_dev;
 
-       urb = malloc(sizeof(urb_priv_t));
-       memset(urb, 0, sizeof(urb_priv_t));
-
-       urb->dev = dev;
-       urb->pipe = pipe;
-       urb->transfer_buffer = buffer;
-       urb->transfer_buffer_length = transfer_len;
-       urb->interval = interval;
+       urb = ohci_alloc_urb(dev, pipe, buffer, transfer_len, interval);
+       if (!urb)
+               return -ENOMEM;
 
 #ifdef DEBUG
        urb->actual_length = 0;
@@ -1546,10 +1551,8 @@ static int submit_common_msg(ohci_t *ohci, struct usb_device *dev,
                return -1;
        }
 
-#if 0
        mdelay(10);
        /* ohci_dump_status(ohci); */
-#endif
 
        timeout = USB_TIMEOUT_MS(pipe);
 
@@ -1607,7 +1610,92 @@ static int submit_common_msg(ohci_t *ohci, struct usb_device *dev,
        return 0;
 }
 
-#ifndef CONFIG_DM_USB
+#define MAX_INT_QUEUESIZE 8
+
+struct int_queue {
+       int queuesize;
+       int curr_urb;
+       urb_priv_t *urb[MAX_INT_QUEUESIZE];
+};
+
+static struct int_queue *_ohci_create_int_queue(ohci_t *ohci,
+               struct usb_device *udev, unsigned long pipe, int queuesize,
+               int elementsize, void *buffer, int interval)
+{
+       struct int_queue *queue;
+       ohci_dev_t *ohci_dev;
+       int i;
+
+       if (queuesize > MAX_INT_QUEUESIZE)
+               return NULL;
+
+       ohci_dev = ohci_get_ohci_dev(ohci, udev->devnum, 1);
+       if (!ohci_dev)
+               return NULL;
+
+       queue = malloc(sizeof(*queue));
+       if (!queue) {
+               printf("ohci: Error out of memory allocating int queue\n");
+               return NULL;
+       }
+
+       for (i = 0; i < queuesize; i++) {
+               queue->urb[i] = ohci_alloc_urb(udev, pipe,
+                                              buffer + i * elementsize,
+                                              elementsize, interval);
+               if (!queue->urb[i])
+                       break;
+
+               if (sohci_submit_job(ohci, ohci_dev, queue->urb[i], NULL)) {
+                       printf("ohci: Error submitting int queue job\n");
+                       urb_free_priv(queue->urb[i]);
+                       break;
+               }
+       }
+       if (i == 0) {
+               /* We did not succeed in submitting even 1 urb */
+               free(queue);
+               return NULL;
+       }
+
+       queue->queuesize = i;
+       queue->curr_urb = 0;
+
+       return queue;
+}
+
+static void *_ohci_poll_int_queue(ohci_t *ohci, struct usb_device *udev,
+                                 struct int_queue *queue)
+{
+       if (queue->curr_urb == queue->queuesize)
+               return NULL; /* Queue depleted */
+
+       if (hc_interrupt(ohci) < 0)
+               return NULL;
+
+       if (queue->urb[queue->curr_urb]->finished) {
+               void *ret = queue->urb[queue->curr_urb]->transfer_buffer;
+               queue->curr_urb++;
+               return ret;
+       }
+
+       return NULL;
+}
+
+static int _ohci_destroy_int_queue(ohci_t *ohci, struct usb_device *dev,
+                                  struct int_queue *queue)
+{
+       int i;
+
+       for (i = 0; i < queue->queuesize; i++)
+               urb_free_priv(queue->urb[i]);
+
+       free(queue);
+
+       return 0;
+}
+
+#if !CONFIG_IS_ENABLED(DM_USB)
 /* submit routines called from usb.c */
 int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
                int transfer_len)
@@ -1618,12 +1706,30 @@ int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
 }
 
 int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
-               int transfer_len, int interval)
+               int transfer_len, int interval, bool nonblock)
 {
        info("submit_int_msg");
        return submit_common_msg(&gohci, dev, pipe, buffer, transfer_len, NULL,
                        interval);
 }
+
+struct int_queue *create_int_queue(struct usb_device *dev,
+               unsigned long pipe, int queuesize, int elementsize,
+               void *buffer, int interval)
+{
+       return _ohci_create_int_queue(&gohci, dev, pipe, queuesize,
+                                     elementsize, buffer, interval);
+}
+
+void *poll_int_queue(struct usb_device *dev, struct int_queue *queue)
+{
+       return _ohci_poll_int_queue(&gohci, dev, queue);
+}
+
+int destroy_int_queue(struct usb_device *dev, struct int_queue *queue)
+{
+       return _ohci_destroy_int_queue(&gohci, dev, queue);
+}
 #endif
 
 static int _ohci_submit_control_msg(ohci_t *ohci, struct usb_device *dev,
@@ -1753,7 +1859,7 @@ static int hc_start(ohci_t *ohci)
        ohci_writel(0, &ohci->regs->ed_controlhead);
        ohci_writel(0, &ohci->regs->ed_bulkhead);
 
-       ohci_writel((__u32)ohci->hcca,
+       ohci_writel((uintptr_t)ohci->hcca,
                    &ohci->regs->hcca); /* reset clears this */
 
        fminterval = 0x2edf;
@@ -1878,7 +1984,7 @@ static int hc_interrupt(ohci_t *ohci)
 
 /*-------------------------------------------------------------------------*/
 
-#ifndef CONFIG_DM_USB
+#if !CONFIG_IS_ENABLED(DM_USB)
 
 /*-------------------------------------------------------------------------*/
 
@@ -1944,8 +2050,11 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
                pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &base);
                printf("OHCI regs address 0x%08x\n", base);
                gohci.regs = (struct ohci_regs *)base;
-       } else
+       } else {
+               printf("%s: OHCI devnr: %d not found\n", __func__,
+                      CONFIG_PCI_OHCI_DEVNO);
                return -1;
+       }
 #else
        gohci.regs = (struct ohci_regs *)CONFIG_SYS_USB_OHCI_REGS_BASE;
 #endif
@@ -2028,7 +2137,7 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe,
 }
 #endif
 
-#ifdef CONFIG_DM_USB
+#if CONFIG_IS_ENABLED(DM_USB)
 static int ohci_submit_control_msg(struct udevice *dev, struct usb_device *udev,
                                   unsigned long pipe, void *buffer, int length,
                                   struct devrequest *setup)
@@ -2049,7 +2158,7 @@ static int ohci_submit_bulk_msg(struct udevice *dev, struct usb_device *udev,
 
 static int ohci_submit_int_msg(struct udevice *dev, struct usb_device *udev,
                               unsigned long pipe, void *buffer, int length,
-                              int interval)
+                              int interval, bool nonblock)
 {
        ohci_t *ohci = dev_get_priv(usb_get_bus(dev));
 
@@ -2057,6 +2166,32 @@ static int ohci_submit_int_msg(struct udevice *dev, struct usb_device *udev,
                                 NULL, interval);
 }
 
+static struct int_queue *ohci_create_int_queue(struct udevice *dev,
+               struct usb_device *udev, unsigned long pipe, int queuesize,
+               int elementsize, void *buffer, int interval)
+{
+       ohci_t *ohci = dev_get_priv(usb_get_bus(dev));
+
+       return _ohci_create_int_queue(ohci, udev, pipe, queuesize, elementsize,
+                                     buffer, interval);
+}
+
+static void *ohci_poll_int_queue(struct udevice *dev, struct usb_device *udev,
+                                struct int_queue *queue)
+{
+       ohci_t *ohci = dev_get_priv(usb_get_bus(dev));
+
+       return _ohci_poll_int_queue(ohci, udev, queue);
+}
+
+static int ohci_destroy_int_queue(struct udevice *dev, struct usb_device *udev,
+                                 struct int_queue *queue)
+{
+       ohci_t *ohci = dev_get_priv(usb_get_bus(dev));
+
+       return _ohci_destroy_int_queue(ohci, udev, queue);
+}
+
 int ohci_register(struct udevice *dev, struct ohci_regs *regs)
 {
        struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
@@ -2070,6 +2205,7 @@ int ohci_register(struct udevice *dev, struct ohci_regs *regs)
        if (!ohci->hcca)
                return -ENOMEM;
        memset(ohci->hcca, 0, sizeof(struct ohci_hcca));
+       flush_dcache_hcca(ohci->hcca);
 
        if (hc_reset(ohci) < 0)
                return -EIO;
@@ -2099,6 +2235,9 @@ struct dm_usb_ops ohci_usb_ops = {
        .control = ohci_submit_control_msg,
        .bulk = ohci_submit_bulk_msg,
        .interrupt = ohci_submit_int_msg,
+       .create_int_queue = ohci_create_int_queue,
+       .poll_int_queue = ohci_poll_int_queue,
+       .destroy_int_queue = ohci_destroy_int_queue,
 };
 
 #endif