aboutsummaryrefslogtreecommitdiff
path: root/lib/libusb/usb-ehci.c
diff options
context:
space:
mode:
authorAvik Sil <aviksil@linux.vnet.ibm.com>2013-07-24 14:27:12 +0530
committerNikunj A Dadhania <nikunj@linux.vnet.ibm.com>2013-07-24 14:46:23 +0530
commita12848da7e574c87b908aad6044c5af33e1835cc (patch)
tree1c963611b1ed1d212093a3a4add94720e09c0b74 /lib/libusb/usb-ehci.c
parent6eb646603dd5f874c97f887ad3ffa469cc3e154f (diff)
downloadSLOF-a12848da7e574c87b908aad6044c5af33e1835cc.zip
SLOF-a12848da7e574c87b908aad6044c5af33e1835cc.tar.gz
SLOF-a12848da7e574c87b908aad6044c5af33e1835cc.tar.bz2
usb-ehci: initialize controller
Signed-off-by: Avik Sil <aviksil@linux.vnet.ibm.com> Signed-off-by: Nikunj A Dadhania <nikunj@linux.vnet.ibm.com> Reviewed-by: Thomas Huth <thuth@linux.vnet.ibm.com>
Diffstat (limited to 'lib/libusb/usb-ehci.c')
-rw-r--r--lib/libusb/usb-ehci.c112
1 files changed, 104 insertions, 8 deletions
diff --git a/lib/libusb/usb-ehci.c b/lib/libusb/usb-ehci.c
index cae0589..f075392 100644
--- a/lib/libusb/usb-ehci.c
+++ b/lib/libusb/usb-ehci.c
@@ -10,12 +10,12 @@
* IBM Corporation - initial implementation
*****************************************************************************/
+#include <string.h>
#include "usb.h"
#include "usb-core.h"
#include "usb-ehci.h"
#include "tools.h"
-struct ehci_controller ehci_cntl;
#undef EHCI_DEBUG
//#define EHCI_DEBUG
#ifdef EHCI_DEBUG
@@ -24,13 +24,14 @@ struct ehci_controller ehci_cntl;
#define dprintf(_x ...)
#endif
-static void dump_ehci_regs(void)
+#ifdef EHCI_DEBUG
+static void dump_ehci_regs(struct ehci_hcd *ehcd)
{
struct ehci_cap_regs *cap_regs;
struct ehci_op_regs *op_regs;
- cap_regs = ehci_cntl.cap_regs;
- op_regs = ehci_cntl.op_regs;
+ cap_regs = ehcd->cap_regs;
+ op_regs = ehcd->op_regs;
dprintf("\n - CAPLENGTH %02X", read_reg8(&cap_regs->caplength));
dprintf("\n - HCIVERSION %04X", read_reg16(&cap_regs->hciversion));
@@ -50,15 +51,110 @@ static void dump_ehci_regs(void)
dprintf("\n - PORTSC %08X", read_reg32(&op_regs->portsc[0]));
dprintf("\n");
}
+#endif
+
+static int ehci_hcd_init(struct ehci_hcd *ehcd)
+{
+ uint32_t usbcmd;
+ uint32_t time;
+ struct ehci_framelist *fl;
+ struct ehci_qh *qh_intr, *qh_async;
+ int i;
+ long fl_phys = 0, qh_intr_phys = 0, qh_async_phys;
+
+ /* Reset the host controller */
+ time = SLOF_GetTimer() + 250;
+ usbcmd = read_reg32(&ehcd->op_regs->usbcmd);
+ write_reg32(&ehcd->op_regs->usbcmd, (usbcmd & ~(CMD_PSE | CMD_ASE)) | CMD_HCRESET);
+ while (time > SLOF_GetTimer())
+ cpu_relax();
+ usbcmd = read_reg32(&ehcd->op_regs->usbcmd);
+ if (usbcmd & CMD_HCRESET) {
+ printf("usb-ehci: reset failed\n");
+ return -1;
+ }
+
+ /* Initialize periodic list */
+ fl = SLOF_dma_alloc(sizeof(*fl));
+ if (!fl) {
+ printf("usb-ehci: Unable to allocate frame list\n");
+ goto fail;
+ }
+ fl_phys = SLOF_dma_map_in(fl, sizeof(*fl), true);
+ dprintf("fl %p, fl_phys %lx\n", fl, fl_phys);
+
+ /* TODO: allocate qh pool */
+ qh_intr = SLOF_dma_alloc(sizeof(*qh_intr));
+ if (!qh_intr) {
+ printf("usb-ehci: Unable to allocate interrupt queue head\n");
+ goto fail_qh_intr;
+ }
+ qh_intr_phys = SLOF_dma_map_in(qh_intr, sizeof(*qh_intr), true);
+ dprintf("qh_intr %p, qh_intr_phys %lx\n", qh_intr, qh_intr_phys);
+
+ memset(qh_intr, 0, sizeof(*qh_intr));
+ qh_intr->qh_ptr = QH_PTR_TERM;
+ qh_intr->ep_cap2 = cpu_to_le32(0x01 << QH_SMASK_SHIFT);
+ qh_intr->next_qtd = qh_intr->alt_next_qtd = QH_PTR_TERM;
+ qh_intr->token = cpu_to_le32(QH_STS_HALTED);
+ for (i = 0; i < FL_SIZE; i++)
+ fl->fl_ptr[i] = cpu_to_le32(qh_intr_phys | EHCI_TYP_QH);
+ write_reg32(&ehcd->op_regs->periodiclistbase, fl_phys);
+
+ /* Initialize async list */
+ qh_async = SLOF_dma_alloc(sizeof(*qh_async));
+ if (!qh_async) {
+ printf("usb-ehci: Unable to allocate async queue head\n");
+ goto fail_qh_async;
+ }
+ qh_async_phys = SLOF_dma_map_in(qh_async, sizeof(*qh_async), true);
+ dprintf("qh_async %p, qh_async_phys %lx\n", qh_async, qh_async_phys);
+
+ memset(qh_async, 0, sizeof(*qh_async));
+ qh_async->qh_ptr = cpu_to_le32(qh_async_phys | EHCI_TYP_QH);
+ qh_async->ep_cap1 = cpu_to_le32(QH_CAP_H);
+ qh_async->next_qtd = qh_async->alt_next_qtd = QH_PTR_TERM;
+ qh_async->token = cpu_to_le32(QH_STS_HALTED);
+ write_reg32(&ehcd->op_regs->asynclistaddr, qh_async_phys);
+
+ write_reg32(&ehcd->op_regs->usbcmd, usbcmd | CMD_ASE | CMD_RUN);
+ write_reg32(&ehcd->op_regs->configflag, 1);
+
+ return 0;
+
+fail_qh_async:
+ SLOF_dma_map_out(qh_intr_phys, qh_intr, sizeof(*qh_intr));
+ SLOF_dma_free(qh_intr, sizeof(*qh_intr));
+fail_qh_intr:
+ SLOF_dma_map_out(fl_phys, fl, sizeof(*fl));
+ SLOF_dma_free(fl, sizeof(*fl));
+fail:
+ return -1;
+}
static void ehci_init(struct usb_hcd_dev *hcidev)
{
+ struct ehci_hcd *ehcd;
+
printf(" EHCI: Initializing\n");
dprintf("%s: device base address %p\n", __func__, hcidev->base);
- ehci_cntl.cap_regs = (struct ehci_cap_regs *)(hcidev->base);
- ehci_cntl.op_regs = (struct ehci_op_regs *)(hcidev->base +
- read_reg8(&ehci_cntl.cap_regs->caplength));
- dump_ehci_regs();
+
+ ehcd = SLOF_dma_alloc(sizeof(*ehcd));
+ if (!ehcd) {
+ printf("usb-ehci: Unable to allocate memory\n");
+ return;
+ }
+
+ hcidev->priv = ehcd;
+ ehcd->hcidev = hcidev;
+ ehcd->cap_regs = (struct ehci_cap_regs *)(hcidev->base);
+ ehcd->op_regs = (struct ehci_op_regs *)(hcidev->base +
+ read_reg8(&ehcd->cap_regs->caplength));
+#ifdef EHCI_DEBUG
+ dump_ehci_regs(ehcd);
+#endif
+ ehci_hcd_init(ehcd);
+ //ehci_hub_check_ports(ehcd);
}
static void ehci_detect(void)