From: Sherry Sun <sherry....@nxp.com>

Convert the ci_udc driver to driver model by using the uclass
UCLASS_USB_GADGET_GENERIC. The clk and power of USB controller and USB
PHY both are initialized by parsing the device tree nodes.

If CONFIG_DM_USB_GADGET is defined, we use the ci_udc driver in DM way,
if it does not defined, we can use ci_udc driver in its original Non-DM
way.

Signed-off-by: Sherry Sun <sherry....@nxp.com>
Reviewed-by: Ye Li <ye...@nxp.com>
[Peng: need to extract common code from host and gadget driver(TODO)]
Signed-off-by: Peng Fan <peng....@nxp.com>
---
 drivers/usb/gadget/ci_udc.c | 305 +++++++++++++++++++++++++++++++++++-
 drivers/usb/host/ehci-mx6.c |  15 +-
 include/usb/ci_udc.h        |   3 +
 3 files changed, 305 insertions(+), 18 deletions(-)

diff --git a/drivers/usb/gadget/ci_udc.c b/drivers/usb/gadget/ci_udc.c
index 226a9e6d67..6f2e38ffd8 100644
--- a/drivers/usb/gadget/ci_udc.c
+++ b/drivers/usb/gadget/ci_udc.c
@@ -13,16 +13,25 @@
 #include <cpu_func.h>
 #include <net.h>
 #include <malloc.h>
+#include <dm.h>
+#include <clk.h>
+#include <power-domain.h>
 #include <asm/byteorder.h>
 #include <asm/cache.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <asm/io.h>
 #include <asm/unaligned.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/arch/clock.h>
+#include <asm/mach-imx/regs-usbphy.h>
 #include <linux/types.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include <dm/pinctrl.h>
 #include <usb/ci_udc.h>
+#include <usb/ehci-ci.h>
 #include "../host/ehci.h"
 #include "ci_udc.h"
 
@@ -93,9 +102,18 @@ static int ci_ep_dequeue(struct usb_ep *ep, struct 
usb_request *req);
 static struct usb_request *
 ci_ep_alloc_request(struct usb_ep *ep, unsigned int gfp_flags);
 static void ci_ep_free_request(struct usb_ep *ep, struct usb_request *_req);
+#if CONFIG_IS_ENABLED(DM_USB_GADGET)
+static int ci_udc_gadget_start(struct usb_gadget *g,
+                              struct usb_gadget_driver *driver);
+static int ci_udc_gadget_stop(struct usb_gadget *g);
+#endif
 
 static struct usb_gadget_ops ci_udc_ops = {
        .pullup = ci_pullup,
+#if CONFIG_IS_ENABLED(DM_USB_GADGET)
+       .udc_start              = ci_udc_gadget_start,
+       .udc_stop               = ci_udc_gadget_stop,
+#endif
 };
 
 static struct usb_ep_ops ci_ep_ops = {
@@ -866,7 +884,7 @@ void udc_irq(void)
        }
 }
 
-int usb_gadget_handle_interrupts(int index)
+int ci_udc_handle_interrupts(void)
 {
        u32 value;
        struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor;
@@ -1010,6 +1028,19 @@ static int ci_udc_probe(void)
        return 0;
 }
 
+bool dfu_usb_get_reset(void)
+{
+       struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor;
+
+       return !!(readl(&udc->usbsts) & STS_URI);
+}
+
+#if !CONFIG_IS_ENABLED(DM_USB_GADGET)
+int usb_gadget_handle_interrupts(int index)
+{
+       return ci_udc_handle_interrupts();
+}
+
 int usb_gadget_register_driver(struct usb_gadget_driver *driver)
 {
        int ret;
@@ -1063,10 +1094,276 @@ int usb_gadget_unregister_driver(struct 
usb_gadget_driver *driver)
 
        return 0;
 }
+#else /* !CONFIG_IS_ENABLED(DM_USB_GADGET) */
 
-bool dfu_usb_get_reset(void)
+static int ci_udc_gadget_start(struct usb_gadget *g,
+                              struct usb_gadget_driver *driver)
 {
-       struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor;
+       if (!driver)
+               return -EINVAL;
+       if (!driver->bind || !driver->setup || !driver->disconnect)
+               return -EINVAL;
 
-       return !!(readl(&udc->usbsts) & STS_URI);
+       controller.driver = driver;
+       return 0;
+}
+
+static int ci_udc_gadget_stop(struct usb_gadget *g)
+{
+       controller.driver = NULL;
+
+       ci_ep_free_request(&controller.ep[0].ep, &controller.ep0_req->req);
+       free(controller.items_mem);
+       free(controller.epts);
+       return 0;
+}
+
+struct ci_udc_priv_data {
+       struct ehci_ctrl ctrl;
+       struct udevice otgdev;
+       struct clk_bulk         clks;
+       int phy_off;
+       struct power_domain otg_pd;
+       struct clk phy_clk;
+       struct power_domain phy_pd;
+};
+
+int dm_usb_gadget_handle_interrupts(struct udevice *dev)
+{
+       return ci_udc_handle_interrupts();
+}
+
+static int ci_udc_phy_setup(struct udevice *dev, struct ci_udc_priv_data *priv)
+{
+       struct udevice __maybe_unused phy_dev;
+       priv->phy_off = fdtdec_lookup_phandle(gd->fdt_blob,
+                                             dev_of_offset(dev),
+                                             "fsl,usbphy");
+       if (priv->phy_off < 0)
+               return -EINVAL;
+
+       phy_dev.node = offset_to_ofnode(priv->phy_off);
+
+#if CONFIG_IS_ENABLED(POWER_DOMAIN)
+       /* Need to power on the PHY before access it */
+       if (!power_domain_get(&phy_dev, &priv->phy_pd)) {
+               if (power_domain_on(&priv->phy_pd))
+                       return -EINVAL;
+       }
+#endif
+
+#if CONFIG_IS_ENABLED(CLK)
+       int ret;
+
+       ret = clk_get_by_index(&phy_dev, 0, &priv->phy_clk);
+       if (ret) {
+               printf("Failed to get phy_clk\n");
+               return ret;
+       }
+
+       ret = clk_enable(&priv->phy_clk);
+       if (ret) {
+               printf("Failed to enable phy_clk\n");
+               return ret;
+       }
+#endif
+
+       return 0;
+}
+
+static int ci_udc_phy_shutdown(struct ci_udc_priv_data *priv)
+{
+       int ret = 0;
+
+#if CONFIG_IS_ENABLED(CLK)
+       if (priv->phy_clk.dev) {
+               ret = clk_disable(&priv->phy_clk);
+               if (ret)
+                       return ret;
+
+               ret = clk_free(&priv->phy_clk);
+               if (ret)
+                       return ret;
+       }
+#endif
+
+#if CONFIG_IS_ENABLED(POWER_DOMAIN)
+       ret = power_domain_off(&priv->phy_pd);
+       if (ret)
+               printf("Power down USB PHY failed! (error = %d)\n", ret);
+#endif
+       return ret;
+}
+
+static int ci_udc_otg_clk_init(struct udevice *dev,
+                              struct clk_bulk *clks)
+{
+       int ret;
+
+       ret = clk_get_bulk(dev, clks);
+       if (ret == -ENOSYS)
+               return 0;
+
+       if (ret)
+               return ret;
+
+#if CONFIG_IS_ENABLED(CLK)
+       ret = clk_enable_bulk(clks);
+       if (ret) {
+               clk_release_bulk(clks);
+               return ret;
+       }
+#endif
+
+       return 0;
+}
+
+static int ci_udc_otg_phy_mode(struct udevice *dev)
+{
+       struct ci_udc_priv_data *priv = dev_get_priv(dev);
+
+       void *__iomem phy_ctrl, *__iomem phy_status;
+       void *__iomem phy_base = (void *__iomem)devfdt_get_addr(&priv->otgdev);
+       u32 val;
+
+       if (is_mx6() || is_mx7ulp() || is_imx8()) {
+               phy_base = (void __iomem *)fdtdec_get_addr(gd->fdt_blob,
+                                                          priv->phy_off,
+                                                          "reg");
+               if ((fdt_addr_t)phy_base == FDT_ADDR_T_NONE)
+                       return -EINVAL;
+
+               phy_ctrl = (void __iomem *)(phy_base + USBPHY_CTRL);
+               val = readl(phy_ctrl);
+               if (val & USBPHY_CTRL_OTG_ID)
+                       return USB_INIT_DEVICE;
+               else
+                       return USB_INIT_HOST;
+       } else if (is_mx7() || is_imx8mm() || is_imx8mn()) {
+               phy_status = (void __iomem *)(phy_base +
+                                             USBNC_PHY_STATUS_OFFSET);
+               val = readl(phy_status);
+               if (val & USBNC_PHYSTATUS_ID_DIG)
+                       return USB_INIT_DEVICE;
+               else
+                       return USB_INIT_HOST;
+       } else {
+               return -EINVAL;
+       }
+}
+
+static int ci_udc_otg_ofdata_to_platdata(struct udevice *dev)
+{
+       struct ci_udc_priv_data *priv = dev_get_priv(dev);
+       int node = dev_of_offset(dev);
+       int usbotg_off;
+
+       if (usb_get_dr_mode(dev_ofnode(dev)) != USB_DR_MODE_PERIPHERAL) {
+               dev_dbg(dev, "Invalid mode\n");
+               return -ENODEV;
+       }
+
+       usbotg_off = fdtdec_lookup_phandle(gd->fdt_blob,
+                                          node,
+                                          "chipidea,usb");
+       if (usbotg_off < 0)
+               return -EINVAL;
+       priv->otgdev.node = offset_to_ofnode(usbotg_off);
+       priv->otgdev.parent = dev->parent;
+
+       return 0;
+}
+
+static int ci_udc_otg_probe(struct udevice *dev)
+{
+       struct ci_udc_priv_data *priv = dev_get_priv(dev);
+       struct usb_ehci *ehci;
+       int ret;
+
+       ehci = (struct usb_ehci *)devfdt_get_addr(&priv->otgdev);
+
+       pinctrl_select_state(&priv->otgdev, "default");
+
+#if defined(CONFIG_MX6)
+       if (mx6_usb_fused((u32)ehci)) {
+               printf("USB@0x%x is fused, disable it\n", (u32)ehci);
+               return -ENODEV;
+       }
+#endif
+
+       ret = board_usb_init(dev->seq, USB_INIT_DEVICE);
+       if (ret) {
+               printf("Failed to initialize board for USB\n");
+               return ret;
+       }
+
+#if CONFIG_IS_ENABLED(POWER_DOMAIN)
+       if (!power_domain_get(&priv->otgdev, &priv->otg_pd)) {
+               if (power_domain_on(&priv->otg_pd))
+                       return -EINVAL;
+       }
+#endif
+
+       ret = ci_udc_phy_setup(&priv->otgdev, priv);
+       if (ret)
+               return ret;
+
+       ret = ci_udc_otg_clk_init(&priv->otgdev, &priv->clks);
+       if (ret)
+               return ret;
+
+       if (ci_udc_otg_phy_mode(dev) != USB_INIT_DEVICE)
+               return -ENODEV;
+
+       priv->ctrl.hccr = (struct ehci_hccr *)((ulong)&ehci->caplength);
+       priv->ctrl.hcor = (struct ehci_hcor *)((ulong)priv->ctrl.hccr +
+                       HC_LENGTH(ehci_readl(&(priv->ctrl.hccr)->cr_capbase)));
+       controller.ctrl = &priv->ctrl;
+
+       ret = ci_udc_probe();
+       if (ret) {
+               DBG("udc probe failed, returned %d\n", ret);
+               return ret;
+       }
+
+       ret = usb_add_gadget_udc((struct device *)dev, &controller.gadget);
+
+       return ret;
+}
+
+static int ci_udc_otg_remove(struct udevice *dev)
+{
+       struct ci_udc_priv_data *priv = dev_get_priv(dev);
+
+       usb_del_gadget_udc(&controller.gadget);
+
+       clk_release_bulk(&priv->clks);
+       ci_udc_phy_shutdown(priv);
+#if CONFIG_IS_ENABLED(POWER_DOMAIN)
+       if (power_domain_off(&priv->otg_pd)) {
+               printf("Power down USB controller failed!\n");
+               return -EINVAL;
+       }
+#endif
+       board_usb_cleanup(dev->seq, USB_INIT_DEVICE);
+
+       controller.ctrl = NULL;
+       return 0;
 }
+
+static const struct udevice_id ci_udc_otg_ids[] = {
+       { .compatible = "fsl,imx27-usb-gadget" },
+       { }
+};
+
+U_BOOT_DRIVER(ci_udc_otg) = {
+       .name   = "ci-udc-otg",
+       .id     = UCLASS_USB_GADGET_GENERIC,
+       .of_match = ci_udc_otg_ids,
+       .ofdata_to_platdata = ci_udc_otg_ofdata_to_platdata,
+       .probe = ci_udc_otg_probe,
+       .remove = ci_udc_otg_remove,
+       .priv_auto_alloc_size = sizeof(struct ci_udc_priv_data),
+};
+
+#endif /* !CONFIG_IS_ENABLED(DM_USB_GADGET) */
diff --git a/drivers/usb/host/ehci-mx6.c b/drivers/usb/host/ehci-mx6.c
index 20617850f3..2bfae1f661 100644
--- a/drivers/usb/host/ehci-mx6.c
+++ b/drivers/usb/host/ehci-mx6.c
@@ -17,6 +17,7 @@
 #include <asm/arch/imx-regs.h>
 #include <asm/arch/clock.h>
 #include <asm/mach-imx/iomux-v3.h>
+#include <asm/mach-imx/regs-usbphy.h>
 #include <asm/mach-imx/sys_proto.h>
 #include <dm.h>
 #include <asm/mach-types.h>
@@ -37,18 +38,6 @@ DECLARE_GLOBAL_DATA_PTR;
 
 #define USB_H1_CTRL_OFFSET     0x04
 
-#define USBPHY_CTRL                            0x00000030
-#define USBPHY_CTRL_SET                                0x00000034
-#define USBPHY_CTRL_CLR                                0x00000038
-#define USBPHY_CTRL_TOG                                0x0000003c
-
-#define USBPHY_PWD                             0x00000000
-#define USBPHY_CTRL_SFTRST                     0x80000000
-#define USBPHY_CTRL_CLKGATE                    0x40000000
-#define USBPHY_CTRL_ENUTMILEVEL3               0x00008000
-#define USBPHY_CTRL_ENUTMILEVEL2               0x00004000
-#define USBPHY_CTRL_OTG_ID                     0x08000000
-
 #define ANADIG_USB2_CHRG_DETECT_EN_B           0x00100000
 #define ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B     0x00080000
 
@@ -58,8 +47,6 @@ DECLARE_GLOBAL_DATA_PTR;
 #define ANADIG_USB2_PLL_480_CTRL_EN_USB_CLKS   0x00000040
 
 #define USBNC_OFFSET           0x200
-#define USBNC_PHY_STATUS_OFFSET        0x23C
-#define USBNC_PHYSTATUS_ID_DIG (1 << 4) /* otg_id status */
 #define USBNC_PHYCFG2_ACAENB   (1 << 4) /* otg_id detection enable */
 #define UCTRL_PWR_POL          (1 << 9) /* OTG Polarity of Power Pin */
 #define UCTRL_OVER_CUR_POL     (1 << 8) /* OTG Polarity of Overcurrent */
diff --git a/include/usb/ci_udc.h b/include/usb/ci_udc.h
index 06adb2bb4d..ddae8e178b 100644
--- a/include/usb/ci_udc.h
+++ b/include/usb/ci_udc.h
@@ -7,7 +7,10 @@
 
 #ifndef __CI_UDC_H__
 #define __CI_UDC_H__
+#include <usb/ehci-ci.h>
 
 #define EP_MAX_PACKET_SIZE     0x200
 #define EP0_MAX_PACKET_SIZE    64
+
+int ehci_mx6_common_init(struct usb_ehci *ehci, int index);
 #endif /* __CI_UDC_H__ */
-- 
2.28.0

Reply via email to