(This patch will be split for submission)

Add driver model support to the XHCI framework, and move exynos over to
use it.

Signed-off-by: Simon Glass <s...@chromium.org>
---

 drivers/usb/host/xhci-exynos5.c | 115 +++++++++++++++++++-
 drivers/usb/host/xhci.c         | 229 ++++++++++++++++++++++++++++++++--------
 drivers/usb/host/xhci.h         |  24 +++++
 3 files changed, 324 insertions(+), 44 deletions(-)

diff --git a/drivers/usb/host/xhci-exynos5.c b/drivers/usb/host/xhci-exynos5.c
index a77c8bc..e61f39e 100644
--- a/drivers/usb/host/xhci-exynos5.c
+++ b/drivers/usb/host/xhci-exynos5.c
@@ -14,6 +14,7 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <fdtdec.h>
 #include <libfdt.h>
 #include <malloc.h>
@@ -32,6 +33,12 @@
 /* Declare global data pointer */
 DECLARE_GLOBAL_DATA_PTR;
 
+struct exynos_xhci_platdata {
+       fdt_addr_t hcd_base;
+       fdt_addr_t phy_base;
+       struct gpio_desc vbus_gpio;
+};
+
 /**
  * Contains pointers to register base addresses
  * for the usb controller.
@@ -40,12 +47,56 @@ struct exynos_xhci {
        struct exynos_usb3_phy *usb3_phy;
        struct xhci_hccr *hcd;
        struct dwc3 *dwc3_reg;
+#ifndef CONFIG_DM_USB
        struct gpio_desc vbus_gpio;
+#endif
 };
 
+#ifndef CONFIG_DM_USB
 static struct exynos_xhci exynos;
+#endif
 
-#ifdef CONFIG_OF_CONTROL
+#ifdef CONFIG_DM_USB
+static int xhci_usb_ofdata_to_platdata(struct udevice *dev)
+{
+       struct exynos_xhci_platdata *plat = dev_get_platdata(dev);
+       const void *blob = gd->fdt_blob;
+       unsigned int node;
+       int depth;
+
+       /*
+        * Get the base address for XHCI controller from the device node
+        */
+       plat->hcd_base = fdtdec_get_addr(blob, dev->of_offset, "reg");
+       if (plat->hcd_base == FDT_ADDR_T_NONE) {
+               debug("Can't get the XHCI register base address\n");
+               return -ENXIO;
+       }
+
+       depth = 0;
+       node = fdtdec_next_compatible_subnode(blob, dev->of_offset,
+                               COMPAT_SAMSUNG_EXYNOS5_USB3_PHY, &depth);
+       if (node <= 0) {
+               debug("XHCI: Can't get device node for usb3-phy controller\n");
+               return -ENODEV;
+       }
+
+       /*
+        * Get the base address for usbphy from the device node
+        */
+       plat->phy_base = fdtdec_get_addr(blob, node, "reg");
+       if (plat->phy_base == FDT_ADDR_T_NONE) {
+               debug("Can't get the usbphy register address\n");
+               return -ENXIO;
+       }
+
+       /* Vbus gpio */
+       gpio_request_by_name(dev, "samsung,vbus-gpio", 0,
+                            &plat->vbus_gpio, GPIOD_IS_OUT);
+
+       return 0;
+}
+#else
 static int exynos_usb3_parse_dt(const void *blob, struct exynos_xhci *exynos)
 {
        fdt_addr_t addr;
@@ -182,7 +233,7 @@ static void exynos5_usb3_phy_exit(struct exynos_usb3_phy 
*phy)
        set_usbdrd_phy_ctrl(POWER_USB_DRD_PHY_CTRL_DISABLE);
 }
 
-void dwc3_set_mode(struct dwc3 *dwc3_reg, u32 mode)
+static void dwc3_set_mode(struct dwc3 *dwc3_reg, u32 mode)
 {
        clrsetbits_le32(&dwc3_reg->g_ctl,
                        DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG),
@@ -283,6 +334,7 @@ static void exynos_xhci_core_exit(struct exynos_xhci 
*exynos)
        exynos5_usb3_phy_exit(exynos->usb3_phy);
 }
 
+#ifndef CONFIG_DM_USB
 int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor)
 {
        struct exynos_xhci *ctx = &exynos;
@@ -326,3 +378,62 @@ void xhci_hcd_stop(int index)
 
        exynos_xhci_core_exit(ctx);
 }
+#endif
+
+#ifdef CONFIG_DM_USB
+static int xhci_usb_probe(struct udevice *dev)
+{
+       struct exynos_xhci_platdata *plat = dev_get_platdata(dev);
+       struct exynos_xhci *ctx = dev_get_priv(dev);
+       struct xhci_hcor *hcor;
+       int ret;
+
+       ctx->hcd = (struct xhci_hccr *)plat->hcd_base;
+       ctx->usb3_phy = (struct exynos_usb3_phy *)plat->phy_base;
+       ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET);
+       hcor = (struct xhci_hcor *)((uint32_t)ctx->hcd +
+                       HC_LENGTH(xhci_readl(&ctx->hcd->cr_capbase)));
+
+       /* setup the Vbus gpio here */
+       if (dm_gpio_is_valid(&plat->vbus_gpio))
+               dm_gpio_set_value(&plat->vbus_gpio, 1);
+
+       ret = exynos_xhci_core_init(ctx);
+       if (ret) {
+               puts("XHCI: failed to initialize controller\n");
+               return -EINVAL;
+       }
+
+       return xhci_register(dev, ctx->hcd, hcor);
+}
+
+static int xhci_usb_remove(struct udevice *dev)
+{
+       struct exynos_xhci *ctx = dev_get_priv(dev);
+       int ret;
+
+       ret = xhci_deregister(dev);
+       if (ret)
+               return ret;
+       exynos_xhci_core_exit(ctx);
+
+       return 0;
+}
+
+static const struct udevice_id xhci_usb_ids[] = {
+       { .compatible = "samsung,exynos5250-xhci" },
+       { }
+};
+
+U_BOOT_DRIVER(usb_xhci) = {
+       .name   = "xhci_exynos",
+       .id     = UCLASS_USB,
+       .of_match = xhci_usb_ids,
+       .ofdata_to_platdata = xhci_usb_ofdata_to_platdata,
+       .probe = xhci_usb_probe,
+       .remove = xhci_usb_remove,
+       .ops    = &xhci_usb_ops,
+       .priv_auto_alloc_size = sizeof(struct exynos_xhci),
+       .platdata_auto_alloc_size = sizeof(struct exynos_xhci_platdata),
+};
+#endif
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 87f2972..fa3a5c5 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -21,6 +21,7 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <asm/byteorder.h>
 #include <usb.h>
 #include <malloc.h>
@@ -108,7 +109,9 @@ static struct descriptor {
        },
 };
 
+#ifndef CONFIG_DM_USB
 static struct xhci_ctrl xhcic[CONFIG_USB_MAX_CONTROLLER_COUNT];
+#endif
 
 /**
  * Waits for as per specified amount of time
@@ -461,10 +464,10 @@ static int xhci_address_device(struct usb_device *udev)
  * @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)
 {
-       union xhci_trb *event;
        struct xhci_ctrl *ctrl = udev->controller;
+       union xhci_trb *event;
        int ret;
 
        /*
@@ -499,6 +502,13 @@ int usb_alloc_device(struct usb_device *udev)
        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
@@ -858,9 +868,8 @@ unknown:
  * @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
@@ -878,9 +887,8 @@ submit_int_msg(struct usb_device *udev, unsigned long pipe, 
void *buffer,
  * @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));
@@ -900,9 +908,9 @@ submit_bulk_msg(struct usb_device *udev, unsigned long 
pipe, void *buffer,
  * @param setup                Request type
  * @return returns 0 if successful else -1 on failure
  */
-int
-submit_control_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
-                                       int length, struct devrequest *setup)
+static int _xhci_submit_control_msg(struct usb_device *udev, unsigned long 
pipe,
+                                   void *buffer, int length,
+                                   struct devrequest *setup)
 {
        struct xhci_ctrl *ctrl = udev->controller;
        int ret = 0;
@@ -929,33 +937,16 @@ submit_control_msg(struct usb_device *udev, unsigned long 
pipe, void *buffer,
        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.
@@ -997,11 +988,75 @@ int usb_lowlevel_init(int index, enum usb_init_type init, 
void **controller)
        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)
+{
+       return _xhci_submit_control_msg(udev, pipe, buffer, length, setup);
+}
+
+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;
+
+       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);
+
+       *controller = &xhcic[index];
+
+       return ret;
+}
+
 /**
  * Stops the XHCI host controller
  * and cleans up all the related data structures
@@ -1012,19 +1067,109 @@ int usb_lowlevel_init(int index, enum usb_init_type 
init, void **controller)
 int usb_lowlevel_stop(int index)
 {
        struct xhci_ctrl *ctrl = (xhcic + index);
-       u32 temp;
 
-       xhci_reset(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 */
 
-       xhci_hcd_stop(index);
+#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_parentdata(dev);
+
+       return udev;
+}
+*/
+static int xhci_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\n", __func__, dev->name, udev);
+       return _xhci_submit_control_msg(udev, pipe, buffer, length, setup);
+}
+
+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 dm_usb_info *usb = dev_get_uclass_priv(dev);
+       struct xhci_ctrl *ctrl;
+       int ret;
+
+       debug("%s: dev='%s', hccr=%p, hcor=%p\n", __func__, dev->name,
+             hccr, hcor);
+       ctrl = calloc(1, sizeof(*ctrl));
+       if (!ctrl)
+               return -ENOMEM;
+
+       ctrl->dev = dev;
+       usb->dev = dev;
+       usb->controller = ctrl;
+
+       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 dm_usb_info *usb = dev_get_uclass_priv(dev);
+       struct xhci_ctrl *ctrl = usb->controller;
+
+       xhci_lowlevel_stop(ctrl);
        xhci_cleanup(ctrl);
+       free(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
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 6685ed2..f9fd99e 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1200,6 +1200,9 @@ void xhci_hcd_stop(int index);
 #define XHCI_STS_CNR           (1 << 11)
 
 struct xhci_ctrl {
+#ifdef CONFIG_DM_USB
+       struct udevice *dev;
+#endif
        struct xhci_hccr *hccr; /* R/O registers, not need for volatile */
        struct xhci_hcor *hcor;
        struct xhci_doorbell_array *dba;
@@ -1250,4 +1253,25 @@ int xhci_alloc_virt_device(struct usb_device *udev);
 int xhci_mem_init(struct xhci_ctrl *ctrl, struct xhci_hccr *hccr,
                  struct xhci_hcor *hcor);
 
+/**
+ * xhci_deregister() - Unregister an XHCI controller
+ *
+ * @dev:       Controller device
+ * @return 0 if registered, -ve on error
+ */
+int xhci_deregister(struct udevice *dev);
+
+/**
+ * xhci_register() - Register a new XHCI controller
+ *
+ * @dev:       Controller device
+ * @hccr:      Host controller control registers
+ * @hcor:      Not sure what this means
+ * @return 0 if registered, -ve on error
+ */
+int xhci_register(struct udevice *dev, struct xhci_hccr *hccr,
+                 struct xhci_hcor *hcor);
+
+extern struct dm_usb_ops xhci_usb_ops;
+
 #endif /* HOST_XHCI_H_ */
-- 
2.2.0.rc0.207.ga3a616c

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to