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>
This commit is contained in:
parent
6eb646603d
commit
a12848da7e
|
@ -10,12 +10,12 @@
|
||||||
* IBM Corporation - initial implementation
|
* IBM Corporation - initial implementation
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
#include "usb.h"
|
#include "usb.h"
|
||||||
#include "usb-core.h"
|
#include "usb-core.h"
|
||||||
#include "usb-ehci.h"
|
#include "usb-ehci.h"
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
|
|
||||||
struct ehci_controller ehci_cntl;
|
|
||||||
#undef EHCI_DEBUG
|
#undef EHCI_DEBUG
|
||||||
//#define EHCI_DEBUG
|
//#define EHCI_DEBUG
|
||||||
#ifdef EHCI_DEBUG
|
#ifdef EHCI_DEBUG
|
||||||
|
@ -24,13 +24,14 @@ struct ehci_controller ehci_cntl;
|
||||||
#define dprintf(_x ...)
|
#define dprintf(_x ...)
|
||||||
#endif
|
#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_cap_regs *cap_regs;
|
||||||
struct ehci_op_regs *op_regs;
|
struct ehci_op_regs *op_regs;
|
||||||
|
|
||||||
cap_regs = ehci_cntl.cap_regs;
|
cap_regs = ehcd->cap_regs;
|
||||||
op_regs = ehci_cntl.op_regs;
|
op_regs = ehcd->op_regs;
|
||||||
|
|
||||||
dprintf("\n - CAPLENGTH %02X", read_reg8(&cap_regs->caplength));
|
dprintf("\n - CAPLENGTH %02X", read_reg8(&cap_regs->caplength));
|
||||||
dprintf("\n - HCIVERSION %04X", read_reg16(&cap_regs->hciversion));
|
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 - PORTSC %08X", read_reg32(&op_regs->portsc[0]));
|
||||||
dprintf("\n");
|
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)
|
static void ehci_init(struct usb_hcd_dev *hcidev)
|
||||||
{
|
{
|
||||||
|
struct ehci_hcd *ehcd;
|
||||||
|
|
||||||
printf(" EHCI: Initializing\n");
|
printf(" EHCI: Initializing\n");
|
||||||
dprintf("%s: device base address %p\n", __func__, hcidev->base);
|
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 +
|
ehcd = SLOF_dma_alloc(sizeof(*ehcd));
|
||||||
read_reg8(&ehci_cntl.cap_regs->caplength));
|
if (!ehcd) {
|
||||||
dump_ehci_regs();
|
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)
|
static void ehci_detect(void)
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define FL_SIZE 1024
|
||||||
|
|
||||||
struct ehci_cap_regs {
|
struct ehci_cap_regs {
|
||||||
uint8_t caplength;
|
uint8_t caplength;
|
||||||
uint8_t reserved;
|
uint8_t reserved;
|
||||||
|
@ -41,9 +43,48 @@ struct ehci_op_regs {
|
||||||
uint32_t portsc[0];
|
uint32_t portsc[0];
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct ehci_controller {
|
struct ehci_hcd {
|
||||||
struct ehci_cap_regs *cap_regs;
|
struct ehci_cap_regs *cap_regs;
|
||||||
struct ehci_op_regs *op_regs;
|
struct ehci_op_regs *op_regs;
|
||||||
|
struct usb_hcd_dev *hcidev;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ehci_framelist {
|
||||||
|
uint32_t fl_ptr[FL_SIZE];
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
struct ehci_qtd {
|
||||||
|
uint32_t next_qtd;
|
||||||
|
uint32_t alt_next_qtd;
|
||||||
|
uint32_t token;
|
||||||
|
uint32_t buffer[5];
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
struct ehci_qh {
|
||||||
|
uint32_t qh_ptr;
|
||||||
|
uint32_t ep_cap1;
|
||||||
|
uint32_t ep_cap2;
|
||||||
|
uint32_t curr_qtd;
|
||||||
|
uint32_t next_qtd;
|
||||||
|
uint32_t alt_next_qtd;
|
||||||
|
uint32_t token;
|
||||||
|
uint32_t buffer[5];
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
#define EHCI_TYP_ITD 0x00
|
||||||
|
#define EHCI_TYP_QH 0x02
|
||||||
|
#define EHCI_TYP_SITD 0x04
|
||||||
|
#define EHCI_TYP_FSTN 0x06
|
||||||
|
|
||||||
|
#define CMD_ASE (1 << 5)
|
||||||
|
#define CMD_PSE (1 << 4)
|
||||||
|
#define CMD_FLS_MASK (3 << 2)
|
||||||
|
#define CMD_HCRESET (1 << 1)
|
||||||
|
#define CMD_RUN (1 << 0)
|
||||||
|
|
||||||
|
#define QH_CAP_H (1 << 15)
|
||||||
|
#define QH_PTR_TERM 0x0001
|
||||||
|
#define QH_SMASK_SHIFT 0
|
||||||
|
#define QH_STS_HALTED (1 << 6)
|
||||||
|
|
||||||
#endif /* USB_EHCI_H */
|
#endif /* USB_EHCI_H */
|
||||||
|
|
Loading…
Reference in New Issue