X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=drivers%2Fusb%2Fhost%2Fehci-hcd.c;h=13aa70d606614a61eb0db6fd04a4651786958671;hb=5cf618ee60a752d058a767372ca1ecb8d9c09b16;hp=9a9ec01d9f6bf4dc52eda7034be3d8ae41aef4ff;hpb=7372b5bd318515c0e756a96e1f730a3ff119bd31;p=u-boot diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 9a9ec01d9f..13aa70d606 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -5,28 +5,17 @@ * * All rights reserved. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2 of - * the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * SPDX-License-Identifier: GPL-2.0 */ #include +#include #include #include #include #include #include #include +#include #include #include @@ -42,7 +31,9 @@ */ #define HCHALT_TIMEOUT (8 * 1000) +#ifndef CONFIG_DM_USB static struct ehci_ctrl ehcic[CONFIG_USB_MAX_CONTROLLER_COUNT]; +#endif #define ALIGN_END_ADDR(type, ptr, size) \ ((unsigned long)(ptr) + roundup((size) * sizeof(type), USB_DMA_MINALIGN)) @@ -121,15 +112,19 @@ static struct descriptor { static struct ehci_ctrl *ehci_get_ctrl(struct usb_device *udev) { +#ifdef CONFIG_DM_USB + return dev_get_priv(usb_get_bus(udev->dev)); +#else return udev->controller; +#endif } -__weak int ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg) +static int ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg) { return PORTSC_PSPD(reg); } -__weak void ehci_set_usbmode(struct ehci_ctrl *ctrl) +static void ehci_set_usbmode(struct ehci_ctrl *ctrl) { uint32_t tmp; uint32_t *reg_ptr; @@ -139,17 +134,19 @@ __weak void ehci_set_usbmode(struct ehci_ctrl *ctrl) tmp |= USBMODE_CM_HC; #if defined(CONFIG_EHCI_MMIO_BIG_ENDIAN) tmp |= USBMODE_BE; +#else + tmp &= ~USBMODE_BE; #endif ehci_writel(reg_ptr, tmp); } -__weak void ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg, +static void ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg, uint32_t *reg) { mdelay(50); } -__weak uint32_t *ehci_get_portsc_register(struct ehci_ctrl *ctrl, int port) +static uint32_t *ehci_get_portsc_register(struct ehci_ctrl *ctrl, int port) { if (port < 0 || port >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) { /* Printing the message would cause a scan failure! */ @@ -176,15 +173,15 @@ static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec) return -1; } -static int ehci_reset(int index) +static int ehci_reset(struct ehci_ctrl *ctrl) { uint32_t cmd; int ret = 0; - cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd); + cmd = ehci_readl(&ctrl->hcor->or_usbcmd); cmd = (cmd & ~CMD_RUN) | CMD_RESET; - ehci_writel(&ehcic[index].hcor->or_usbcmd, cmd); - ret = handshake((uint32_t *)&ehcic[index].hcor->or_usbcmd, + ehci_writel(&ctrl->hcor->or_usbcmd, cmd); + ret = handshake((uint32_t *)&ctrl->hcor->or_usbcmd, CMD_RESET, 0, 250 * 1000); if (ret < 0) { printf("EHCI fail to reset\n"); @@ -192,13 +189,13 @@ static int ehci_reset(int index) } if (ehci_is_TDI()) - ehci_set_usbmode(&ehcic[index]); + ctrl->ops.set_usb_mode(ctrl); #ifdef CONFIG_USB_EHCI_TXFIFO_THRESH - cmd = ehci_readl(&ehcic[index].hcor->or_txfilltuning); + cmd = ehci_readl(&ctrl->hcor->or_txfilltuning); cmd &= ~TXFIFO_THRESH_MASK; cmd |= TXFIFO_THRESH(CONFIG_USB_EHCI_TXFIFO_THRESH); - ehci_writel(&ehcic[index].hcor->or_txfilltuning, cmd); + ehci_writel(&ctrl->hcor->or_txfilltuning, cmd); #endif out: return ret; @@ -213,6 +210,9 @@ static int ehci_shutdown(struct ehci_ctrl *ctrl) return -EINVAL; cmd = ehci_readl(&ctrl->hcor->or_usbcmd); + /* If not run, directly return */ + if (!(cmd & CMD_RUN)) + return 0; cmd &= ~(CMD_PSE | CMD_ASE); ehci_writel(&ctrl->hcor->or_usbcmd, cmd); ret = handshake(&ctrl->hcor->or_usbsts, STS_ASS | STS_PSS, 0, @@ -240,7 +240,7 @@ static int ehci_shutdown(struct ehci_ctrl *ctrl) static int ehci_td_buffer(struct qTD *td, void *buf, size_t sz) { uint32_t delta, next; - uint32_t addr = (unsigned long)buf; + unsigned long addr = (unsigned long)buf; int idx; if (addr != ALIGN(addr, ARCH_DMA_MINALIGN)) @@ -250,7 +250,7 @@ static int ehci_td_buffer(struct qTD *td, void *buf, size_t sz) idx = 0; while (idx < QT_BUFFER_CNT) { - td->qt_buffer[idx] = cpu_to_hc32(addr); + td->qt_buffer[idx] = cpu_to_hc32(virt_to_phys((void *)addr)); td->qt_buffer_hi[idx] = 0; next = (addr + EHCI_PAGE_SIZE) & ~(EHCI_PAGE_SIZE - 1); delta = next - addr; @@ -281,27 +281,19 @@ static inline u8 ehci_encode_speed(enum usb_device_speed speed) return QH_FULL_SPEED; } -static void ehci_update_endpt2_dev_n_port(struct usb_device *dev, +static void ehci_update_endpt2_dev_n_port(struct usb_device *udev, struct QH *qh) { - struct usb_device *ttdev; + uint8_t portnr = 0; + uint8_t hubaddr = 0; - if (dev->speed != USB_SPEED_LOW && dev->speed != USB_SPEED_FULL) + if (udev->speed != USB_SPEED_LOW && udev->speed != USB_SPEED_FULL) return; - /* - * For full / low speed devices we need to get the devnum and portnr of - * the tt, so of the first upstream usb-2 hub, there may be usb-1 hubs - * in the tree before that one! - */ - ttdev = dev; - while (ttdev->parent && ttdev->parent->speed != USB_SPEED_HIGH) - ttdev = ttdev->parent; - if (!ttdev->parent) - return; + usb_find_usb2_hub_address_port(udev, &hubaddr, &portnr); - qh->qh_endpt2 |= cpu_to_hc32(QH_ENDPT2_PORTNUM(ttdev->portnr) | - QH_ENDPT2_HUBADDR(ttdev->parent->devnum)); + qh->qh_endpt2 |= cpu_to_hc32(QH_ENDPT2_PORTNUM(portnr) | + QH_ENDPT2_HUBADDR(hubaddr)); } static int @@ -411,7 +403,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, * qh_overlay.qt_next ...... 13-10 H * - qh_overlay.qt_altnext */ - qh->qh_link = cpu_to_hc32((unsigned long)&ctrl->qh_list | QH_LINK_TYPE_QH); + qh->qh_link = cpu_to_hc32(virt_to_phys(&ctrl->qh_list) | QH_LINK_TYPE_QH); c = (dev->speed != USB_SPEED_HIGH) && !usb_pipeendpoint(pipe); maxpacket = usb_maxpacket(dev, pipe); endpt = QH_ENDPT1_RL(8) | QH_ENDPT1_C(c) | @@ -428,7 +420,6 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, qh->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); tdp = &qh->qh_overlay.qt_next; - if (req != NULL) { /* * Setup request qTD (3.5 in ehci-r10.pdf) @@ -451,7 +442,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, goto fail; } /* Update previous qTD! */ - *tdp = cpu_to_hc32((unsigned long)&qtd[qtd_counter]); + *tdp = cpu_to_hc32(virt_to_phys(&qtd[qtd_counter])); tdp = &qtd[qtd_counter++].qt_next; toggle = 1; } @@ -510,7 +501,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, goto fail; } /* Update previous qTD! */ - *tdp = cpu_to_hc32((unsigned long)&qtd[qtd_counter]); + *tdp = cpu_to_hc32(virt_to_phys(&qtd[qtd_counter])); tdp = &qtd[qtd_counter++].qt_next; /* * Data toggle has to be adjusted since the qTD transfer @@ -541,11 +532,11 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, QT_TOKEN_STATUS(QT_TOKEN_STATUS_ACTIVE); qtd[qtd_counter].qt_token = cpu_to_hc32(token); /* Update previous qTD! */ - *tdp = cpu_to_hc32((unsigned long)&qtd[qtd_counter]); + *tdp = cpu_to_hc32(virt_to_phys(&qtd[qtd_counter])); tdp = &qtd[qtd_counter++].qt_next; } - ctrl->qh_list.qh_link = cpu_to_hc32((unsigned long)qh | QH_LINK_TYPE_QH); + ctrl->qh_list.qh_link = cpu_to_hc32(virt_to_phys(qh) | QH_LINK_TYPE_QH); /* Flush dcache */ flush_dcache_range((unsigned long)&ctrl->qh_list, @@ -555,7 +546,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, ALIGN_END_ADDR(struct qTD, qtd, qtd_count)); /* Set async. queue head pointer. */ - ehci_writel(&ctrl->hcor->or_asynclistaddr, (unsigned long)&ctrl->qh_list); + ehci_writel(&ctrl->hcor->or_asynclistaddr, virt_to_phys(&ctrl->qh_list)); usbsts = ehci_readl(&ctrl->hcor->or_usbsts); ehci_writel(&ctrl->hcor->or_usbsts, (usbsts & 0x3f)); @@ -691,7 +682,7 @@ static int ehci_submit_root(struct usb_device *dev, unsigned long pipe, case USB_REQ_GET_STATUS | ((USB_RT_PORT | USB_DIR_IN) << 8): case USB_REQ_SET_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8): case USB_REQ_CLEAR_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8): - status_reg = ehci_get_portsc_register(ctrl, port - 1); + status_reg = ctrl->ops.get_portsc_register(ctrl, port - 1); if (!status_reg) return -1; break; @@ -786,7 +777,7 @@ static int ehci_submit_root(struct usb_device *dev, unsigned long pipe, tmpbuf[1] |= USB_PORT_STAT_POWER >> 8; if (ehci_is_TDI()) { - switch (ehci_get_port_speed(ctrl, reg)) { + switch (ctrl->ops.get_port_speed(ctrl, reg)) { case PORTSC_PSPD_FS: break; case PORTSC_PSPD_LS: @@ -836,7 +827,7 @@ static int ehci_submit_root(struct usb_device *dev, unsigned long pipe, port - 1); reg |= EHCI_PS_PO; ehci_writel(status_reg, reg); - break; + return -ENXIO; } else { int ret; @@ -848,7 +839,7 @@ static int ehci_submit_root(struct usb_device *dev, unsigned long pipe, * usb 2.0 specification say 50 ms resets on * root */ - ehci_powerup_fixup(ctrl, status_reg, ®); + ctrl->ops.powerup_fixup(ctrl, status_reg, ®); ehci_writel(status_reg, reg & ~EHCI_PS_PR); /* @@ -858,11 +849,22 @@ static int ehci_submit_root(struct usb_device *dev, unsigned long pipe, */ ret = handshake(status_reg, EHCI_PS_PR, 0, 2 * 1000); - if (!ret) - ctrl->portreset |= 1 << port; - else + if (!ret) { + reg = ehci_readl(status_reg); + if ((reg & (EHCI_PS_PE | EHCI_PS_CS)) + == EHCI_PS_CS && !ehci_is_TDI()) { + debug("port %d full speed --> companion\n", port - 1); + reg &= ~EHCI_PS_CLEAR; + reg |= EHCI_PS_PO; + ehci_writel(status_reg, reg); + return -ENXIO; + } else { + ctrl->portreset |= 1 << port; + } + } else { printf("port(%d) reset error\n", port - 1); + } } break; case USB_PORT_FEAT_TEST: @@ -935,15 +937,45 @@ unknown: return -1; } -void ehci_set_controller_priv(int index, void *priv) +const struct ehci_ops default_ehci_ops = { + .set_usb_mode = ehci_set_usbmode, + .get_port_speed = ehci_get_port_speed, + .powerup_fixup = ehci_powerup_fixup, + .get_portsc_register = ehci_get_portsc_register, +}; + +static void ehci_setup_ops(struct ehci_ctrl *ctrl, const struct ehci_ops *ops) { - ehcic[index].priv = priv; + if (!ops) { + ctrl->ops = default_ehci_ops; + } else { + ctrl->ops = *ops; + if (!ctrl->ops.set_usb_mode) + ctrl->ops.set_usb_mode = ehci_set_usbmode; + if (!ctrl->ops.get_port_speed) + ctrl->ops.get_port_speed = ehci_get_port_speed; + if (!ctrl->ops.powerup_fixup) + ctrl->ops.powerup_fixup = ehci_powerup_fixup; + if (!ctrl->ops.get_portsc_register) + ctrl->ops.get_portsc_register = + ehci_get_portsc_register; + } +} + +#ifndef CONFIG_DM_USB +void ehci_set_controller_priv(int index, void *priv, const struct ehci_ops *ops) +{ + struct ehci_ctrl *ctrl = &ehcic[index]; + + ctrl->priv = priv; + ehci_setup_ops(ctrl, ops); } void *ehci_get_controller_priv(int index) { return ehcic[index].priv; } +#endif static int ehci_common_init(struct ehci_ctrl *ctrl, uint tweaks) { @@ -961,7 +993,7 @@ static int ehci_common_init(struct ehci_ctrl *ctrl, uint tweaks) /* Set head of reclaim list */ memset(qh_list, 0, sizeof(*qh_list)); - qh_list->qh_link = cpu_to_hc32((unsigned long)qh_list | QH_LINK_TYPE_QH); + qh_list->qh_link = cpu_to_hc32(virt_to_phys(qh_list) | QH_LINK_TYPE_QH); qh_list->qh_endpt1 = cpu_to_hc32(QH_ENDPT1_H(1) | QH_ENDPT1_EPS(USB_SPEED_HIGH)); qh_list->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); @@ -973,7 +1005,7 @@ static int ehci_common_init(struct ehci_ctrl *ctrl, uint tweaks) ALIGN_END_ADDR(struct QH, qh_list, 1)); /* Set async. queue head pointer. */ - ehci_writel(&ctrl->hcor->or_asynclistaddr, (unsigned long)qh_list); + ehci_writel(&ctrl->hcor->or_asynclistaddr, virt_to_phys(qh_list)); /* * Set up periodic list @@ -1054,6 +1086,7 @@ static int ehci_common_init(struct ehci_ctrl *ctrl, uint tweaks) return 0; } +#ifndef CONFIG_DM_USB int usb_lowlevel_stop(int index) { ehci_shutdown(&ehcic[index]); @@ -1066,6 +1099,12 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller) uint tweaks = 0; int rc; + /** + * Set ops to default_ehci_ops, ehci_hcd_init should call + * ehci_set_controller_priv to change any of these function pointers. + */ + ctrl->ops = default_ehci_ops; + rc = ehci_hcd_init(index, init, &ctrl->hccr, &ctrl->hcor); if (rc) return rc; @@ -1073,7 +1112,7 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller) goto done; /* EHCI spec section 4.1 */ - if (ehci_reset(index)) + if (ehci_reset(ctrl)) return -1; #if defined(CONFIG_EHCI_HCD_INIT_AFTER_RESET) @@ -1093,6 +1132,7 @@ done: *controller = &ehcic[index]; return 0; } +#endif static int _ehci_submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int length) @@ -1126,6 +1166,7 @@ static int _ehci_submit_control_msg(struct usb_device *dev, unsigned long pipe, struct int_queue { int elementsize; + unsigned long pipe; struct QH *first; struct QH *current; struct QH *last; @@ -1175,13 +1216,13 @@ disable_periodic(struct ehci_ctrl *ctrl) return 0; } -struct int_queue * -create_int_queue(struct usb_device *dev, unsigned long pipe, int queuesize, - int elementsize, void *buffer, int interval) +static struct int_queue *_ehci_create_int_queue(struct usb_device *dev, + unsigned long pipe, int queuesize, int elementsize, + void *buffer, int interval) { struct ehci_ctrl *ctrl = ehci_get_ctrl(dev); struct int_queue *result = NULL; - int i; + uint32_t i, toggle; /* * Interrupt transfers requiring several transactions are not supported @@ -1221,6 +1262,7 @@ create_int_queue(struct usb_device *dev, unsigned long pipe, int queuesize, goto fail1; } result->elementsize = elementsize; + result->pipe = pipe; result->first = memalign(USB_DMA_MINALIGN, sizeof(struct QH) * queuesize); if (!result->first) { @@ -1238,6 +1280,8 @@ create_int_queue(struct usb_device *dev, unsigned long pipe, int queuesize, memset(result->first, 0, sizeof(struct QH) * queuesize); memset(result->tds, 0, sizeof(struct qTD) * queuesize); + toggle = usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); + for (i = 0; i < queuesize; i++) { struct QH *qh = result->first + i; struct qTD *td = result->tds + i; @@ -1269,7 +1313,9 @@ create_int_queue(struct usb_device *dev, unsigned long pipe, int queuesize, td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); debug("communication direction is '%s'\n", usb_pipein(pipe) ? "in" : "out"); - td->qt_token = cpu_to_hc32((elementsize << 16) | + td->qt_token = cpu_to_hc32( + QT_TOKEN_DT(toggle) | + (elementsize << 16) | ((usb_pipein(pipe) ? 1 : 0) << 8) | /* IN/OUT token */ 0x80); /* active */ td->qt_buffer[0] = @@ -1284,6 +1330,7 @@ create_int_queue(struct usb_device *dev, unsigned long pipe, int queuesize, cpu_to_hc32((td->qt_buffer[0] + 0x4000) & ~0xfff); *buf = buffer + i * elementsize; + toggle ^= 1; } flush_dcache_range((unsigned long)buffer, @@ -1333,10 +1380,13 @@ fail1: return NULL; } -void *poll_int_queue(struct usb_device *dev, struct int_queue *queue) +static void *_ehci_poll_int_queue(struct usb_device *dev, + struct int_queue *queue) { struct QH *cur = queue->current; struct qTD *cur_td; + uint32_t token, toggle; + unsigned long pipe = queue->pipe; /* depleted queue */ if (cur == NULL) { @@ -1347,12 +1397,15 @@ void *poll_int_queue(struct usb_device *dev, struct int_queue *queue) cur_td = &queue->tds[queue->current - queue->first]; invalidate_dcache_range((unsigned long)cur_td, ALIGN_END_ADDR(struct qTD, cur_td, 1)); - if (QT_TOKEN_GET_STATUS(hc32_to_cpu(cur_td->qt_token)) & - QT_TOKEN_STATUS_ACTIVE) { - debug("Exit poll_int_queue with no completed intr transfer. token is %x\n", - hc32_to_cpu(cur_td->qt_token)); + token = hc32_to_cpu(cur_td->qt_token); + if (QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE) { + debug("Exit poll_int_queue with no completed intr transfer. token is %x\n", token); return NULL; } + + toggle = QT_TOKEN_GET_DT(token); + usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), toggle); + if (!(cur->qh_link & QH_LINK_TERMINATE)) queue->current++; else @@ -1363,13 +1416,13 @@ void *poll_int_queue(struct usb_device *dev, struct int_queue *queue) queue->elementsize)); debug("Exit poll_int_queue with completed intr transfer. token is %x at %p (first at %p)\n", - hc32_to_cpu(cur_td->qt_token), cur, queue->first); + token, cur, queue->first); return cur->buffer; } /* Do not free buffers associated with QHs, they're owned by someone else */ -int -destroy_int_queue(struct usb_device *dev, struct int_queue *queue) +static int _ehci_destroy_int_queue(struct usb_device *dev, + struct int_queue *queue) { struct ehci_ctrl *ctrl = ehci_get_ctrl(dev); int result = -1; @@ -1426,12 +1479,12 @@ static int _ehci_submit_int_msg(struct usb_device *dev, unsigned long pipe, debug("dev=%p, pipe=%lu, buffer=%p, length=%d, interval=%d", dev, pipe, buffer, length, interval); - queue = create_int_queue(dev, pipe, 1, length, buffer, interval); + queue = _ehci_create_int_queue(dev, pipe, 1, length, buffer, interval); if (!queue) return -1; timeout = get_timer(0) + USB_TIMEOUT_MS(pipe); - while ((backbuffer = poll_int_queue(dev, queue)) == NULL) + while ((backbuffer = _ehci_poll_int_queue(dev, queue)) == NULL) if (get_timer(0) > timeout) { printf("Timeout poll on interrupt endpoint\n"); result = -ETIMEDOUT; @@ -1444,7 +1497,7 @@ static int _ehci_submit_int_msg(struct usb_device *dev, unsigned long pipe, return -EINVAL; } - ret = destroy_int_queue(dev, queue); + ret = _ehci_destroy_int_queue(dev, queue); if (ret < 0) return ret; @@ -1452,6 +1505,7 @@ static int _ehci_submit_int_msg(struct usb_device *dev, unsigned long pipe, return result; } +#ifndef CONFIG_DM_USB int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int length) { @@ -1469,3 +1523,137 @@ int submit_int_msg(struct usb_device *dev, unsigned long pipe, { return _ehci_submit_int_msg(dev, pipe, buffer, length, interval); } + +struct int_queue *create_int_queue(struct usb_device *dev, + unsigned long pipe, int queuesize, int elementsize, + void *buffer, int interval) +{ + return _ehci_create_int_queue(dev, pipe, queuesize, elementsize, + buffer, interval); +} + +void *poll_int_queue(struct usb_device *dev, struct int_queue *queue) +{ + return _ehci_poll_int_queue(dev, queue); +} + +int destroy_int_queue(struct usb_device *dev, struct int_queue *queue) +{ + return _ehci_destroy_int_queue(dev, queue); +} +#endif + +#ifdef CONFIG_DM_USB +static int ehci_submit_control_msg(struct udevice *dev, struct usb_device *udev, + unsigned long pipe, void *buffer, int length, + struct devrequest *setup) +{ + debug("%s: dev='%s', udev=%p, udev->dev='%s', portnr=%d\n", __func__, + dev->name, udev, udev->dev->name, udev->portnr); + + return _ehci_submit_control_msg(udev, pipe, buffer, length, setup); +} + +static int ehci_submit_bulk_msg(struct udevice *dev, struct usb_device *udev, + unsigned long pipe, void *buffer, int length) +{ + debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev); + return _ehci_submit_bulk_msg(udev, pipe, buffer, length); +} + +static int ehci_submit_int_msg(struct udevice *dev, struct usb_device *udev, + unsigned long pipe, void *buffer, int length, + int interval) +{ + debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev); + return _ehci_submit_int_msg(udev, pipe, buffer, length, interval); +} + +static struct int_queue *ehci_create_int_queue(struct udevice *dev, + struct usb_device *udev, unsigned long pipe, int queuesize, + int elementsize, void *buffer, int interval) +{ + debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev); + return _ehci_create_int_queue(udev, pipe, queuesize, elementsize, + buffer, interval); +} + +static void *ehci_poll_int_queue(struct udevice *dev, struct usb_device *udev, + struct int_queue *queue) +{ + debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev); + return _ehci_poll_int_queue(udev, queue); +} + +static int ehci_destroy_int_queue(struct udevice *dev, struct usb_device *udev, + struct int_queue *queue) +{ + debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev); + return _ehci_destroy_int_queue(udev, queue); +} + +int ehci_register(struct udevice *dev, struct ehci_hccr *hccr, + struct ehci_hcor *hcor, const struct ehci_ops *ops, + uint tweaks, enum usb_init_type init) +{ + struct usb_bus_priv *priv = dev_get_uclass_priv(dev); + struct ehci_ctrl *ctrl = dev_get_priv(dev); + int ret; + + debug("%s: dev='%s', ctrl=%p, hccr=%p, hcor=%p, init=%d\n", __func__, + dev->name, ctrl, hccr, hcor, init); + + priv->desc_before_addr = true; + + ehci_setup_ops(ctrl, ops); + ctrl->hccr = hccr; + ctrl->hcor = hcor; + ctrl->priv = ctrl; + + ctrl->init = init; + if (ctrl->init == USB_INIT_DEVICE) + goto done; + + ret = ehci_reset(ctrl); + if (ret) + goto err; + + if (ctrl->ops.init_after_reset) { + ret = ctrl->ops.init_after_reset(ctrl); + if (ret) + goto err; + } + + ret = ehci_common_init(ctrl, tweaks); + if (ret) + goto err; +done: + return 0; +err: + free(ctrl); + debug("%s: failed, ret=%d\n", __func__, ret); + return ret; +} + +int ehci_deregister(struct udevice *dev) +{ + struct ehci_ctrl *ctrl = dev_get_priv(dev); + + if (ctrl->init == USB_INIT_DEVICE) + return 0; + + ehci_shutdown(ctrl); + + return 0; +} + +struct dm_usb_ops ehci_usb_ops = { + .control = ehci_submit_control_msg, + .bulk = ehci_submit_bulk_msg, + .interrupt = ehci_submit_int_msg, + .create_int_queue = ehci_create_int_queue, + .poll_int_queue = ehci_poll_int_queue, + .destroy_int_queue = ehci_destroy_int_queue, +}; + +#endif