usb: ehci: add missing cache managment
Commit 8f62ca6
"usb: ehci: Support interrupt transfers via periodic list"
didn't include any cache management in the new interrupt transfer path.
It also added an extra write to or_asynclistaddr in usb_lowlevel_init(),
without having flushed out the data there.
Add the missing cache management calls, so that the code works again.
This allows the USB keyboard on Tegra's Seaboard/Springbank boards to
work.
Cc: Patrick Georgi <patrick@georgi-clan.de>
Cc: Vincent Palatin <vpalatin@chromium.org>
Cc: Julius Werner <jwerner@chromium.org>
Cc: Simon Glass <sjg@chromium.org>
Cc: Marek Vasut <marex@denx.de>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
This commit is contained in:
parent
64cfd3f964
commit
d3e0747846
1 changed files with 30 additions and 0 deletions
|
@ -926,6 +926,9 @@ int usb_lowlevel_init(int index, void **controller)
|
||||||
qh_list->qh_overlay.qt_token =
|
qh_list->qh_overlay.qt_token =
|
||||||
cpu_to_hc32(QT_TOKEN_STATUS(QT_TOKEN_STATUS_HALTED));
|
cpu_to_hc32(QT_TOKEN_STATUS(QT_TOKEN_STATUS_HALTED));
|
||||||
|
|
||||||
|
flush_dcache_range((uint32_t)qh_list,
|
||||||
|
ALIGN_END_ADDR(struct QH, qh_list, 1));
|
||||||
|
|
||||||
/* Set async. queue head pointer. */
|
/* Set async. queue head pointer. */
|
||||||
ehci_writel(&ehcic[index].hcor->or_asynclistaddr, (uint32_t)qh_list);
|
ehci_writel(&ehcic[index].hcor->or_asynclistaddr, (uint32_t)qh_list);
|
||||||
|
|
||||||
|
@ -939,6 +942,9 @@ int usb_lowlevel_init(int index, void **controller)
|
||||||
periodic->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
|
periodic->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
|
||||||
periodic->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
|
periodic->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
|
||||||
|
|
||||||
|
flush_dcache_range((uint32_t)periodic,
|
||||||
|
ALIGN_END_ADDR(struct QH, periodic, 1));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Step 2: Setup frame-list: Every microframe, USB tries the same list.
|
* Step 2: Setup frame-list: Every microframe, USB tries the same list.
|
||||||
* In particular, device specifications on polling frequency
|
* In particular, device specifications on polling frequency
|
||||||
|
@ -956,6 +962,10 @@ int usb_lowlevel_init(int index, void **controller)
|
||||||
| QH_LINK_TYPE_QH;
|
| QH_LINK_TYPE_QH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flush_dcache_range((uint32_t)ehcic[index].periodic_list,
|
||||||
|
ALIGN_END_ADDR(uint32_t, ehcic[index].periodic_list,
|
||||||
|
1024));
|
||||||
|
|
||||||
/* Set periodic list base address */
|
/* Set periodic list base address */
|
||||||
ehci_writel(&ehcic[index].hcor->or_periodiclistbase,
|
ehci_writel(&ehcic[index].hcor->or_periodiclistbase,
|
||||||
(uint32_t)ehcic[index].periodic_list);
|
(uint32_t)ehcic[index].periodic_list);
|
||||||
|
@ -1170,6 +1180,16 @@ create_int_queue(struct usb_device *dev, unsigned long pipe, int queuesize,
|
||||||
*buf = buffer + i * elementsize;
|
*buf = buffer + i * elementsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flush_dcache_range((uint32_t)buffer,
|
||||||
|
ALIGN_END_ADDR(char, buffer,
|
||||||
|
queuesize * elementsize));
|
||||||
|
flush_dcache_range((uint32_t)result->first,
|
||||||
|
ALIGN_END_ADDR(struct QH, result->first,
|
||||||
|
queuesize));
|
||||||
|
flush_dcache_range((uint32_t)result->tds,
|
||||||
|
ALIGN_END_ADDR(struct qTD, result->tds,
|
||||||
|
queuesize));
|
||||||
|
|
||||||
if (disable_periodic(ctrl) < 0) {
|
if (disable_periodic(ctrl) < 0) {
|
||||||
debug("FATAL: periodic should never fail, but did");
|
debug("FATAL: periodic should never fail, but did");
|
||||||
goto fail3;
|
goto fail3;
|
||||||
|
@ -1180,6 +1200,11 @@ create_int_queue(struct usb_device *dev, unsigned long pipe, int queuesize,
|
||||||
result->last->qh_link = list->qh_link;
|
result->last->qh_link = list->qh_link;
|
||||||
list->qh_link = (uint32_t)result->first | QH_LINK_TYPE_QH;
|
list->qh_link = (uint32_t)result->first | QH_LINK_TYPE_QH;
|
||||||
|
|
||||||
|
flush_dcache_range((uint32_t)result->last,
|
||||||
|
ALIGN_END_ADDR(struct QH, result->last, 1));
|
||||||
|
flush_dcache_range((uint32_t)list,
|
||||||
|
ALIGN_END_ADDR(struct QH, list, 1));
|
||||||
|
|
||||||
if (enable_periodic(ctrl) < 0) {
|
if (enable_periodic(ctrl) < 0) {
|
||||||
debug("FATAL: periodic should never fail, but did");
|
debug("FATAL: periodic should never fail, but did");
|
||||||
goto fail3;
|
goto fail3;
|
||||||
|
@ -1210,6 +1235,8 @@ void *poll_int_queue(struct usb_device *dev, struct int_queue *queue)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
/* still active */
|
/* still active */
|
||||||
|
invalidate_dcache_range((uint32_t)cur,
|
||||||
|
ALIGN_END_ADDR(struct QH, cur, 1));
|
||||||
if (cur->qh_overlay.qt_token & 0x80) {
|
if (cur->qh_overlay.qt_token & 0x80) {
|
||||||
debug("Exit poll_int_queue with no completed intr transfer. "
|
debug("Exit poll_int_queue with no completed intr transfer. "
|
||||||
"token is %x\n", cur->qh_overlay.qt_token);
|
"token is %x\n", cur->qh_overlay.qt_token);
|
||||||
|
@ -1316,6 +1343,9 @@ submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
invalidate_dcache_range((uint32_t)buffer,
|
||||||
|
ALIGN_END_ADDR(char, buffer, length));
|
||||||
|
|
||||||
ret = destroy_int_queue(dev, queue);
|
ret = destroy_int_queue(dev, queue);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
Loading…
Reference in a new issue