*/
#include <common.h>
+#include <dm.h>
#include <asm/byteorder.h>
#include <usb.h>
#include <malloc.h>
#include <watchdog.h>
#include <asm/cache.h>
#include <asm/unaligned.h>
-#include <asm-generic/errno.h>
+#include <linux/errno.h>
#include "xhci.h"
#ifndef CONFIG_USB_MAX_CONTROLLER_COUNT
},
};
+#ifndef CONFIG_DM_USB
static struct xhci_ctrl xhcic[CONFIG_USB_MAX_CONTROLLER_COUNT];
+#endif
struct xhci_ctrl *xhci_get_ctrl(struct usb_device *udev)
{
+#ifdef CONFIG_DM_USB
+ struct udevice *dev;
+
+ /* Find the USB controller */
+ for (dev = udev->dev;
+ device_get_uclass_id(dev) != UCLASS_USB;
+ dev = dev->parent)
+ ;
+ return dev_get_priv(dev);
+#else
return udev->controller;
+#endif
}
/**
int ret;
/* Halting the Host first */
- debug("// Halt the HC\n");
+ debug("// Halt the HC: %p\n", hcor);
state = xhci_readl(&hcor->or_usbsts) & STS_HALT;
if (!state) {
cmd = xhci_readl(&hcor->or_usbcmd);
* @param udev pointer to the Device Data Structure
* @return Returns 0 on succes else return error code on failure
*/
-int usb_alloc_device(struct usb_device *udev)
+int _xhci_alloc_device(struct usb_device *udev)
{
struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
union xhci_trb *event;
return 0;
}
+#ifndef CONFIG_DM_USB
+int usb_alloc_device(struct usb_device *udev)
+{
+ return _xhci_alloc_device(udev);
+}
+#endif
+
/*
* Full speed devices may have a max packet size greater than 8 bytes, but the
* USB core doesn't know that until it reads the first 8 bytes of the
srclen = 4;
break;
case 1: /* Vendor String */
- srcptr = "\16\3u\0-\0b\0o\0o\0t\0";
+ srcptr = "\16\3U\0-\0B\0o\0o\0t\0";
srclen = 14;
break;
case 2: /* Product Name */
* @param interval interval of the interrupt
* @return 0
*/
-int
-submit_int_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
- int length, int interval)
+static int _xhci_submit_int_msg(struct usb_device *udev, unsigned long pipe,
+ void *buffer, int length, int interval)
{
/*
* TODO: Not addressing any interrupt type transfer requests
* @param length length of the buffer
* @return returns 0 if successful else -1 on failure
*/
-int
-submit_bulk_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
- int length)
+static int _xhci_submit_bulk_msg(struct usb_device *udev, unsigned long pipe,
+ void *buffer, int length)
{
if (usb_pipetype(pipe) != PIPE_BULK) {
printf("non-bulk pipe (type=%lu)", usb_pipetype(pipe));
if (usb_pipedevice(pipe) == ctrl->rootdev)
return xhci_submit_root(udev, pipe, buffer, setup);
- if (setup->request == USB_REQ_SET_ADDRESS)
+ if (setup->request == USB_REQ_SET_ADDRESS &&
+ (setup->requesttype & USB_TYPE_MASK) == USB_TYPE_STANDARD)
return xhci_address_device(udev, root_portnr);
- if (setup->request == USB_REQ_SET_CONFIGURATION) {
+ if (setup->request == USB_REQ_SET_CONFIGURATION &&
+ (setup->requesttype & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
ret = xhci_set_configuration(udev);
if (ret) {
puts("Failed to configure xHCI endpoint\n");
return xhci_ctrl_tx(udev, pipe, setup, length, buffer);
}
-/**
- * Intialises the XHCI host controller
- * and allocates the necessary data structures
- *
- * @param index index to the host controller data structure
- * @return pointer to the intialised controller
- */
-int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
+static int xhci_lowlevel_init(struct xhci_ctrl *ctrl)
{
+ struct xhci_hccr *hccr;
+ struct xhci_hcor *hcor;
uint32_t val;
uint32_t val2;
uint32_t reg;
- struct xhci_hccr *hccr;
- struct xhci_hcor *hcor;
- struct xhci_ctrl *ctrl;
-
- if (xhci_hcd_init(index, &hccr, (struct xhci_hcor **)&hcor) != 0)
- return -ENODEV;
-
- if (xhci_reset(hcor) != 0)
- return -ENODEV;
-
- ctrl = &xhcic[index];
-
- ctrl->hccr = hccr;
- ctrl->hcor = hcor;
+ hccr = ctrl->hccr;
+ hcor = ctrl->hcor;
/*
* Program the Number of Device Slots Enabled field in the CONFIG
* register with the max value of slots the HC can handle.
reg = HC_VERSION(xhci_readl(&hccr->cr_capbase));
printf("USB XHCI %x.%02x\n", reg >> 8, reg & 0xff);
- *controller = &xhcic[index];
+ return 0;
+}
+
+static int xhci_lowlevel_stop(struct xhci_ctrl *ctrl)
+{
+ u32 temp;
+
+ xhci_reset(ctrl->hcor);
+
+ debug("// Disabling event ring interrupts\n");
+ temp = xhci_readl(&ctrl->hcor->or_usbsts);
+ xhci_writel(&ctrl->hcor->or_usbsts, temp & ~STS_EINT);
+ temp = xhci_readl(&ctrl->ir_set->irq_pending);
+ xhci_writel(&ctrl->ir_set->irq_pending, ER_IRQ_DISABLE(temp));
return 0;
}
+#ifndef CONFIG_DM_USB
int submit_control_msg(struct usb_device *udev, unsigned long pipe,
void *buffer, int length, struct devrequest *setup)
{
hop->portnr);
}
+int submit_bulk_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
+ int length)
+{
+ return _xhci_submit_bulk_msg(udev, pipe, buffer, length);
+}
+
+int submit_int_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
+ int length, int interval)
+{
+ return _xhci_submit_int_msg(udev, pipe, buffer, length, interval);
+}
+
+/**
+ * Intialises the XHCI host controller
+ * and allocates the necessary data structures
+ *
+ * @param index index to the host controller data structure
+ * @return pointer to the intialised controller
+ */
+int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
+{
+ struct xhci_hccr *hccr;
+ struct xhci_hcor *hcor;
+ struct xhci_ctrl *ctrl;
+ int ret;
+
+ *controller = NULL;
+
+ if (xhci_hcd_init(index, &hccr, (struct xhci_hcor **)&hcor) != 0)
+ return -ENODEV;
+
+ if (xhci_reset(hcor) != 0)
+ return -ENODEV;
+
+ ctrl = &xhcic[index];
+
+ ctrl->hccr = hccr;
+ ctrl->hcor = hcor;
+
+ ret = xhci_lowlevel_init(ctrl);
+
+ if (ret) {
+ ctrl->hccr = NULL;
+ ctrl->hcor = NULL;
+ } else {
+ *controller = &xhcic[index];
+ }
+
+ return ret;
+}
+
/**
* Stops the XHCI host controller
* and cleans up all the related data structures
int usb_lowlevel_stop(int index)
{
struct xhci_ctrl *ctrl = (xhcic + index);
- u32 temp;
- xhci_reset(ctrl->hcor);
+ if (ctrl->hcor) {
+ xhci_lowlevel_stop(ctrl);
+ xhci_hcd_stop(index);
+ xhci_cleanup(ctrl);
+ }
- debug("// Disabling event ring interrupts\n");
- temp = xhci_readl(&ctrl->hcor->or_usbsts);
- xhci_writel(&ctrl->hcor->or_usbsts, temp & ~STS_EINT);
- temp = xhci_readl(&ctrl->ir_set->irq_pending);
- xhci_writel(&ctrl->ir_set->irq_pending, ER_IRQ_DISABLE(temp));
+ return 0;
+}
+#endif /* CONFIG_DM_USB */
+
+#ifdef CONFIG_DM_USB
+/*
+static struct usb_device *get_usb_device(struct udevice *dev)
+{
+ struct usb_device *udev;
+
+ if (device_get_uclass_id(dev) == UCLASS_USB)
+ udev = dev_get_uclass_priv(dev);
+ else
+ udev = dev_get_parent_priv(dev);
+
+ return udev;
+}
+*/
+static bool is_root_hub(struct udevice *dev)
+{
+ if (device_get_uclass_id(dev->parent) != UCLASS_USB_HUB)
+ return true;
+
+ return false;
+}
+
+static int xhci_submit_control_msg(struct udevice *dev, struct usb_device *udev,
+ unsigned long pipe, void *buffer, int length,
+ struct devrequest *setup)
+{
+ struct usb_device *uhop;
+ struct udevice *hub;
+ int root_portnr = 0;
+
+ debug("%s: dev='%s', udev=%p, udev->dev='%s', portnr=%d\n", __func__,
+ dev->name, udev, udev->dev->name, udev->portnr);
+ hub = udev->dev;
+ if (device_get_uclass_id(hub) == UCLASS_USB_HUB) {
+ /* Figure out our port number on the root hub */
+ if (is_root_hub(hub)) {
+ root_portnr = udev->portnr;
+ } else {
+ while (!is_root_hub(hub->parent))
+ hub = hub->parent;
+ uhop = dev_get_parent_priv(hub);
+ root_portnr = uhop->portnr;
+ }
+ }
+/*
+ struct usb_device *hop = udev;
+
+ if (hop->parent)
+ while (hop->parent->parent)
+ hop = hop->parent;
+*/
+ return _xhci_submit_control_msg(udev, pipe, buffer, length, setup,
+ root_portnr);
+}
- xhci_hcd_stop(index);
+static int xhci_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 _xhci_submit_bulk_msg(udev, pipe, buffer, length);
+}
+
+static int xhci_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 _xhci_submit_int_msg(udev, pipe, buffer, length, interval);
+}
+static int xhci_alloc_device(struct udevice *dev, struct usb_device *udev)
+{
+ debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev);
+ return _xhci_alloc_device(udev);
+}
+
+int xhci_register(struct udevice *dev, struct xhci_hccr *hccr,
+ struct xhci_hcor *hcor)
+{
+ struct xhci_ctrl *ctrl = dev_get_priv(dev);
+ struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
+ int ret;
+
+ debug("%s: dev='%s', ctrl=%p, hccr=%p, hcor=%p\n", __func__, dev->name,
+ ctrl, hccr, hcor);
+
+ ctrl->dev = dev;
+
+ /*
+ * XHCI needs to issue a Address device command to setup
+ * proper device context structures, before it can interact
+ * with the device. So a get_descriptor will fail before any
+ * of that is done for XHCI unlike EHCI.
+ */
+ priv->desc_before_addr = false;
+
+ ret = xhci_reset(hcor);
+ if (ret)
+ goto err;
+
+ ctrl->hccr = hccr;
+ ctrl->hcor = hcor;
+ ret = xhci_lowlevel_init(ctrl);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ free(ctrl);
+ debug("%s: failed, ret=%d\n", __func__, ret);
+ return ret;
+}
+
+int xhci_deregister(struct udevice *dev)
+{
+ struct xhci_ctrl *ctrl = dev_get_priv(dev);
+
+ xhci_lowlevel_stop(ctrl);
xhci_cleanup(ctrl);
return 0;
}
+
+struct dm_usb_ops xhci_usb_ops = {
+ .control = xhci_submit_control_msg,
+ .bulk = xhci_submit_bulk_msg,
+ .interrupt = xhci_submit_int_msg,
+ .alloc_device = xhci_alloc_device,
+};
+
+#endif