Merge branch 'master' of git://git.denx.de/u-boot-usb
authorTom Rini <trini@konsulko.com>
Fri, 24 Aug 2018 20:11:01 +0000 (16:11 -0400)
committerTom Rini <trini@konsulko.com>
Fri, 24 Aug 2018 20:11:01 +0000 (16:11 -0400)
19 files changed:
arch/arm/mach-rockchip/rk3188-board-spl.c
arch/arm/mach-rockchip/rk3288-board-spl.c
arch/sandbox/dts/test.dts
cmd/Kconfig
cmd/Makefile
cmd/bind.c [new file with mode: 0644]
cmd/fastboot.c
configs/sandbox_defconfig
drivers/core/device-remove.c
drivers/core/device.c
drivers/core/dump.c
drivers/core/uclass.c
drivers/usb/gadget/gadget_chips.h
drivers/usb/musb-new/omap2430.c
include/dm/device-internal.h
include/dm/device.h
include/dm/uclass-internal.h
net/eth-uclass.c
test/py/tests/test_bind.py [new file with mode: 0644]

index 59c7e4d..98ca971 100644 (file)
@@ -49,7 +49,7 @@ u32 spl_boot_device(void)
                debug("node=%d\n", node);
                goto fallback;
        }
-       ret = device_get_global_by_of_offset(node, &dev);
+       ret = device_get_global_by_ofnode(offset_to_ofnode(node), &dev);
        if (ret) {
                debug("device at node %s/%d not found: %d\n", bootdev, node,
                      ret);
index ea6a14a..abd62e5 100644 (file)
@@ -51,7 +51,7 @@ u32 spl_boot_device(void)
                debug("node=%d\n", node);
                goto fallback;
        }
-       ret = device_get_global_by_of_offset(node, &dev);
+       ret = device_get_global_by_ofnode(offset_to_ofnode(node), &dev);
        if (ret) {
                debug("device at node %s/%d not found: %d\n", bootdev, node,
                      ret);
index 118ff9f..3668263 100644 (file)
                reg = <2 1>;
        };
 
+       bind-test {
+               bind-test-child1 {
+                       compatible = "sandbox,phy";
+                       #phy-cells = <1>;
+               };
+
+               bind-test-child2 {
+                       compatible = "simple-bus";
+               };
+       };
+
        b-test {
                reg = <3 1>;
                compatible = "denx,u-boot-fdt-test";
index 51db3da..04bdbf0 100644 (file)
@@ -615,6 +615,15 @@ config CMD_ADC
          Shows ADC device info and permit printing one-shot analog converted
          data from a named Analog to Digital Converter.
 
+config CMD_BIND
+       bool "bind/unbind - Bind or unbind a device to/from a driver"
+       depends on DM
+       help
+         Bind or unbind a device to/from a driver from the command line.
+         This is useful in situations where a device may be handled by several
+         drivers. For example, this can be used to bind a UDC to the usb ether
+         gadget driver from the command line.
+
 config CMD_CLK
        bool "clk - Show clock frequencies"
        help
index b1206fc..3487c80 100644 (file)
@@ -19,6 +19,7 @@ obj-$(CONFIG_SOURCE) += source.o
 obj-$(CONFIG_CMD_SOURCE) += source.o
 obj-$(CONFIG_CMD_BDI) += bdinfo.o
 obj-$(CONFIG_CMD_BEDBUG) += bedbug.o
+obj-$(CONFIG_CMD_BIND) += bind.o
 obj-$(CONFIG_CMD_BINOP) += binop.o
 obj-$(CONFIG_CMD_BLOCK_CACHE) += blkcache.o
 obj-$(CONFIG_CMD_BMP) += bmp.o
diff --git a/cmd/bind.c b/cmd/bind.c
new file mode 100644 (file)
index 0000000..44a5f17
--- /dev/null
@@ -0,0 +1,255 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2018 JJ Hiblot <jjhiblot@ti.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/uclass-internal.h>
+
+static int bind_by_class_index(const char *uclass, int index,
+                              const char *drv_name)
+{
+       static enum uclass_id uclass_id;
+       struct udevice *dev;
+       struct udevice *parent;
+       int ret;
+       struct driver *drv;
+
+       drv = lists_driver_lookup_name(drv_name);
+       if (!drv) {
+               printf("Cannot find driver '%s'\n", drv_name);
+               return -ENOENT;
+       }
+
+       uclass_id = uclass_get_by_name(uclass);
+       if (uclass_id == UCLASS_INVALID) {
+               printf("%s is not a valid uclass\n", uclass);
+               return -EINVAL;
+       }
+
+       ret = uclass_find_device(uclass_id, index, &parent);
+       if (!parent || ret) {
+               printf("Cannot find device %d of class %s\n", index, uclass);
+               return ret;
+       }
+
+       ret = device_bind_with_driver_data(parent, drv, drv->name, 0,
+                                          ofnode_null(), &dev);
+       if (!dev || ret) {
+               printf("Unable to bind. err:%d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int find_dev(const char *uclass, int index, struct udevice **devp)
+{
+       static enum uclass_id uclass_id;
+       int rc;
+
+       uclass_id = uclass_get_by_name(uclass);
+       if (uclass_id == UCLASS_INVALID) {
+               printf("%s is not a valid uclass\n", uclass);
+               return -EINVAL;
+       }
+
+       rc = uclass_find_device(uclass_id, index, devp);
+       if (!*devp || rc) {
+               printf("Cannot find device %d of class %s\n", index, uclass);
+               return rc;
+       }
+
+       return 0;
+}
+
+static int unbind_by_class_index(const char *uclass, int index)
+{
+       int ret;
+       struct udevice *dev;
+
+       ret = find_dev(uclass, index, &dev);
+       if (ret)
+               return ret;
+
+       ret = device_remove(dev, DM_REMOVE_NORMAL);
+       if (ret) {
+               printf("Unable to remove. err:%d\n", ret);
+               return ret;
+       }
+
+       ret = device_unbind(dev);
+       if (ret) {
+               printf("Unable to unbind. err:%d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int unbind_child_by_class_index(const char *uclass, int index,
+                                      const char *drv_name)
+{
+       struct udevice *parent;
+       int ret;
+       struct driver *drv;
+
+       drv = lists_driver_lookup_name(drv_name);
+       if (!drv) {
+               printf("Cannot find driver '%s'\n", drv_name);
+               return -ENOENT;
+       }
+
+       ret = find_dev(uclass, index, &parent);
+       if (ret)
+               return ret;
+
+       ret = device_chld_remove(parent, drv, DM_REMOVE_NORMAL);
+       if (ret)
+               printf("Unable to remove all. err:%d\n", ret);
+
+       ret = device_chld_unbind(parent, drv);
+       if (ret)
+               printf("Unable to unbind all. err:%d\n", ret);
+
+       return ret;
+}
+
+static int bind_by_node_path(const char *path, const char *drv_name)
+{
+       struct udevice *dev;
+       struct udevice *parent = NULL;
+       int ret;
+       ofnode ofnode;
+       struct driver *drv;
+
+       drv = lists_driver_lookup_name(drv_name);
+       if (!drv) {
+               printf("%s is not a valid driver name\n", drv_name);
+               return -ENOENT;
+       }
+
+       ofnode = ofnode_path(path);
+       if (!ofnode_valid(ofnode)) {
+               printf("%s is not a valid node path\n", path);
+               return -EINVAL;
+       }
+
+       while (ofnode_valid(ofnode)) {
+               if (!device_find_global_by_ofnode(ofnode, &parent))
+                       break;
+               ofnode = ofnode_get_parent(ofnode);
+       }
+
+       if (!parent) {
+               printf("Cannot find a parent device for node path %s\n", path);
+               return -ENODEV;
+       }
+
+       ofnode = ofnode_path(path);
+       ret = device_bind_with_driver_data(parent, drv, ofnode_get_name(ofnode),
+                                          0, ofnode, &dev);
+       if (!dev || ret) {
+               printf("Unable to bind. err:%d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int unbind_by_node_path(const char *path)
+{
+       struct udevice *dev;
+       int ret;
+       ofnode ofnode;
+
+       ofnode = ofnode_path(path);
+       if (!ofnode_valid(ofnode)) {
+               printf("%s is not a valid node path\n", path);
+               return -EINVAL;
+       }
+
+       ret = device_find_global_by_ofnode(ofnode, &dev);
+
+       if (!dev || ret) {
+               printf("Cannot find a device with path %s\n", path);
+               return -ENODEV;
+       }
+
+       ret = device_remove(dev, DM_REMOVE_NORMAL);
+       if (ret) {
+               printf("Unable to remove. err:%d\n", ret);
+               return ret;
+       }
+
+       ret = device_unbind(dev);
+       if (ret) {
+               printf("Unable to unbind. err:%d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int do_bind_unbind(cmd_tbl_t *cmdtp, int flag, int argc,
+                         char * const argv[])
+{
+       int ret = 0;
+       bool bind;
+       bool by_node;
+
+       if (argc < 2)
+               return CMD_RET_USAGE;
+
+       bind = (argv[0][0] == 'b');
+       by_node = (argv[1][0] == '/');
+
+       if (by_node && bind) {
+               if (argc != 3)
+                       return CMD_RET_USAGE;
+               ret = bind_by_node_path(argv[1], argv[2]);
+       } else if (by_node && !bind) {
+               if (argc != 2)
+                       return CMD_RET_USAGE;
+               ret = unbind_by_node_path(argv[1]);
+       } else if (!by_node && bind) {
+               int index = (argc > 2) ? simple_strtoul(argv[2], NULL, 10) : 0;
+
+               if (argc != 4)
+                       return CMD_RET_USAGE;
+               ret = bind_by_class_index(argv[1], index, argv[3]);
+       } else if (!by_node && !bind) {
+               int index = (argc > 2) ? simple_strtoul(argv[2], NULL, 10) : 0;
+
+               if (argc == 3)
+                       ret = unbind_by_class_index(argv[1], index);
+               else if (argc == 4)
+                       ret = unbind_child_by_class_index(argv[1], index,
+                                                         argv[3]);
+               else
+                       return CMD_RET_USAGE;
+       }
+
+       if (ret)
+               return CMD_RET_FAILURE;
+       else
+               return CMD_RET_SUCCESS;
+}
+
+U_BOOT_CMD(
+       bind,   4,      0,      do_bind_unbind,
+       "Bind a device to a driver",
+       "<node path> <driver>\n"
+       "bind <class> <index> <driver>\n"
+);
+
+U_BOOT_CMD(
+       unbind, 4,      0,      do_bind_unbind,
+       "Unbind a device from a driver",
+       "<node path>\n"
+       "unbind <class> <index>\n"
+       "unbind <class> <index> <driver>\n"
+);
index e6ae057..ae3a5f6 100644 (file)
@@ -38,13 +38,18 @@ static int do_fastboot_usb(int argc, char *const argv[],
 #if CONFIG_IS_ENABLED(USB_FUNCTION_FASTBOOT)
        int controller_index;
        char *usb_controller;
+       char *endp;
        int ret;
 
        if (argc < 2)
                return CMD_RET_USAGE;
 
        usb_controller = argv[1];
-       controller_index = simple_strtoul(usb_controller, NULL, 0);
+       controller_index = simple_strtoul(usb_controller, &endp, 0);
+       if (*endp != '\0') {
+               pr_err("Error: Wrong USB controller index format\n");
+               return CMD_RET_FAILURE;
+       }
 
        ret = board_usb_init(controller_index, USB_INIT_DEVICE);
        if (ret) {
@@ -120,6 +125,12 @@ NXTARG:
                ;
        }
 
+       /* Handle case when USB controller param is just '-' */
+       if (argc == 1) {
+               pr_err("Error: Incorrect USB controller index\n");
+               return CMD_RET_USAGE;
+       }
+
        fastboot_init((void *)buf_addr, buf_size);
 
        if (!strcmp(argv[1], "udp"))
index c72374e..96e9514 100644 (file)
@@ -34,6 +34,7 @@ CONFIG_CMD_MD5SUM=y
 CONFIG_CMD_MEMINFO=y
 CONFIG_CMD_MEMTEST=y
 CONFIG_CMD_MX_CYCLIC=y
+CONFIG_CMD_BIND=y
 CONFIG_CMD_DEMO=y
 CONFIG_CMD_GPIO=y
 CONFIG_CMD_GPT=y
index 1cf2278..586fade 100644 (file)
 #include <dm/uclass-internal.h>
 #include <dm/util.h>
 
-/**
- * device_chld_unbind() - Unbind all device's children from the device
- *
- * On error, the function continues to unbind all children, and reports the
- * first error.
- *
- * @dev:       The device that is to be stripped of its children
- * @return 0 on success, -ve on error
- */
-static int device_chld_unbind(struct udevice *dev)
+int device_chld_unbind(struct udevice *dev, struct driver *drv)
 {
        struct udevice *pos, *n;
        int ret, saved_ret = 0;
@@ -34,6 +25,9 @@ static int device_chld_unbind(struct udevice *dev)
        assert(dev);
 
        list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
+               if (drv && (pos->driver != drv))
+                       continue;
+
                ret = device_unbind(pos);
                if (ret && !saved_ret)
                        saved_ret = ret;
@@ -42,13 +36,8 @@ static int device_chld_unbind(struct udevice *dev)
        return saved_ret;
 }
 
-/**
- * device_chld_remove() - Stop all device's children
- * @dev:       The device whose children are to be removed
- * @pre_os_remove: Flag, if this functions is called in the pre-OS stage
- * @return 0 on success, -ve on error
- */
-static int device_chld_remove(struct udevice *dev, uint flags)
+int device_chld_remove(struct udevice *dev, struct driver *drv,
+                      uint flags)
 {
        struct udevice *pos, *n;
        int ret;
@@ -56,6 +45,9 @@ static int device_chld_remove(struct udevice *dev, uint flags)
        assert(dev);
 
        list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
+               if (drv && (pos->driver != drv))
+                       continue;
+
                ret = device_remove(pos, flags);
                if (ret)
                        return ret;
@@ -87,7 +79,7 @@ int device_unbind(struct udevice *dev)
                        return ret;
        }
 
-       ret = device_chld_unbind(dev);
+       ret = device_chld_unbind(dev, NULL);
        if (ret)
                return ret;
 
@@ -178,7 +170,7 @@ int device_remove(struct udevice *dev, uint flags)
        if (ret)
                return ret;
 
-       ret = device_chld_remove(dev, flags);
+       ret = device_chld_remove(dev, NULL, flags);
        if (ret)
                goto err;
 
index 207d566..fd59fe1 100644 (file)
@@ -594,16 +594,16 @@ int device_get_child_by_of_offset(struct udevice *parent, int node,
        return device_get_device_tail(dev, ret, devp);
 }
 
-static struct udevice *_device_find_global_by_of_offset(struct udevice *parent,
-                                                       int of_offset)
+static struct udevice *_device_find_global_by_ofnode(struct udevice *parent,
+                                                    ofnode ofnode)
 {
        struct udevice *dev, *found;
 
-       if (dev_of_offset(parent) == of_offset)
+       if (ofnode_equal(dev_ofnode(parent), ofnode))
                return parent;
 
        list_for_each_entry(dev, &parent->child_head, sibling_node) {
-               found = _device_find_global_by_of_offset(dev, of_offset);
+               found = _device_find_global_by_ofnode(dev, ofnode);
                if (found)
                        return found;
        }
@@ -611,11 +611,18 @@ static struct udevice *_device_find_global_by_of_offset(struct udevice *parent,
        return NULL;
 }
 
-int device_get_global_by_of_offset(int of_offset, struct udevice **devp)
+int device_find_global_by_ofnode(ofnode ofnode, struct udevice **devp)
+{
+       *devp = _device_find_global_by_ofnode(gd->dm_root, ofnode);
+
+       return *devp ? 0 : -ENOENT;
+}
+
+int device_get_global_by_ofnode(ofnode ofnode, struct udevice **devp)
 {
        struct udevice *dev;
 
-       dev = _device_find_global_by_of_offset(gd->dm_root, of_offset);
+       dev = _device_find_global_by_ofnode(gd->dm_root, ofnode);
        return device_get_device_tail(dev, dev ? 0 : -ENOENT, devp);
 }
 
index 58820cd..d7cdb14 100644 (file)
@@ -8,6 +8,7 @@
 #include <mapmem.h>
 #include <dm/root.h>
 #include <dm/util.h>
+#include <dm/uclass-internal.h>
 
 static void show_devices(struct udevice *dev, int depth, int last_flag)
 {
@@ -15,7 +16,8 @@ static void show_devices(struct udevice *dev, int depth, int last_flag)
        struct udevice *child;
 
        /* print the first 11 characters to not break the tree-format. */
-       printf(" %-10.10s [ %c ]   %-10.10s  ", dev->uclass->uc_drv->name,
+       printf(" %-10.10s  %d  [ %c ]   %-10.10s  ", dev->uclass->uc_drv->name,
+              dev_get_uclass_index(dev, NULL),
               dev->flags & DM_FLAG_ACTIVATED ? '+' : ' ', dev->driver->name);
 
        for (i = depth; i >= 0; i--) {
@@ -47,8 +49,8 @@ void dm_dump_all(void)
 
        root = dm_root();
        if (root) {
-               printf(" Class      Probed  Driver      Name\n");
-               printf("----------------------------------------\n");
+               printf(" Class    index  Probed  Driver      Name\n");
+               printf("-----------------------------------------\n");
                show_devices(root, -1, 0);
        }
 }
@@ -60,9 +62,9 @@ void dm_dump_all(void)
  *
  * @dev:       Device to display
  */
-static void dm_display_line(struct udevice *dev)
+static void dm_display_line(struct udevice *dev, int index)
 {
-       printf("- %c %s @ %08lx",
+       printf("%i %c %s @ %08lx", index,
               dev->flags & DM_FLAG_ACTIVATED ? '*' : ' ',
               dev->name, (ulong)map_to_sysmem(dev));
        if (dev->seq != -1 || dev->req_seq != -1)
@@ -78,6 +80,7 @@ void dm_dump_uclass(void)
 
        for (id = 0; id < UCLASS_COUNT; id++) {
                struct udevice *dev;
+               int i = 0;
 
                ret = uclass_get(id, &uc);
                if (ret)
@@ -87,7 +90,8 @@ void dm_dump_uclass(void)
                if (list_empty(&uc->dev_head))
                        continue;
                list_for_each_entry(dev, &uc->dev_head, uclass_node) {
-                       dm_display_line(dev);
+                       dm_display_line(dev, i);
+                       i++;
                }
                puts("\n");
        }
index d609b17..3113d6a 100644 (file)
@@ -171,6 +171,27 @@ enum uclass_id uclass_get_by_name(const char *name)
        return UCLASS_INVALID;
 }
 
+int dev_get_uclass_index(struct udevice *dev, struct uclass **ucp)
+{
+       struct udevice *iter;
+       struct uclass *uc = dev->uclass;
+       int i = 0;
+
+       if (list_empty(&uc->dev_head))
+               return -ENODEV;
+
+       list_for_each_entry(iter, &uc->dev_head, uclass_node) {
+               if (iter == dev) {
+                       if (ucp)
+                               *ucp = uc;
+                       return i;
+               }
+               i++;
+       }
+
+       return -ENODEV;
+}
+
 int uclass_find_device(enum uclass_id id, int index, struct udevice **devp)
 {
        struct uclass *uc;
index b9b0819..2c8f235 100644 (file)
@@ -206,5 +206,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
                return 0x21;
        else if (gadget_is_fotg210(gadget))
                return 0x22;
+       else if (gadget_is_dwc3(gadget))
+               return 0x23;
        return -ENOENT;
 }
index 4753d79..342d76b 100644 (file)
  *
  * This file is part of the Inventra Controller Driver for Linux.
  */
-#ifndef __UBOOT__
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/list.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/dma-mapping.h>
-#include <linux/pm_runtime.h>
-#include <linux/err.h>
-#include <linux/usb/musb-omap.h>
-#else
 #include <common.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <linux/usb/otg.h>
 #include <asm/omap_common.h>
 #include <asm/omap_musb.h>
 #include <twl4030.h>
 #include <twl6030.h>
 #include "linux-compat.h"
-#endif
-
 #include "musb_core.h"
 #include "omap2430.h"
-
-#ifndef __UBOOT__
-struct omap2430_glue {
-       struct device           *dev;
-       struct platform_device  *musb;
-       enum omap_musb_vbus_id_status status;
-       struct work_struct      omap_musb_mailbox_work;
-};
-#define glue_to_musb(g)                platform_get_drvdata(g->musb)
-
-struct omap2430_glue           *_glue;
-
-static struct timer_list musb_idle_timer;
-
-static void musb_do_idle(unsigned long _musb)
-{
-       struct musb     *musb = (void *)_musb;
-       unsigned long   flags;
-       u8      power;
-       u8      devctl;
-
-       spin_lock_irqsave(&musb->lock, flags);
-
-       switch (musb->xceiv->state) {
-       case OTG_STATE_A_WAIT_BCON:
-
-               devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
-               if (devctl & MUSB_DEVCTL_BDEVICE) {
-                       musb->xceiv->state = OTG_STATE_B_IDLE;
-                       MUSB_DEV_MODE(musb);
-               } else {
-                       musb->xceiv->state = OTG_STATE_A_IDLE;
-                       MUSB_HST_MODE(musb);
-               }
-               break;
-       case OTG_STATE_A_SUSPEND:
-               /* finish RESUME signaling? */
-               if (musb->port1_status & MUSB_PORT_STAT_RESUME) {
-                       power = musb_readb(musb->mregs, MUSB_POWER);
-                       power &= ~MUSB_POWER_RESUME;
-                       dev_dbg(musb->controller, "root port resume stopped, power %02x\n", power);
-                       musb_writeb(musb->mregs, MUSB_POWER, power);
-                       musb->is_active = 1;
-                       musb->port1_status &= ~(USB_PORT_STAT_SUSPEND
-                                               | MUSB_PORT_STAT_RESUME);
-                       musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
-                       usb_hcd_poll_rh_status(musb_to_hcd(musb));
-                       /* NOTE: it might really be A_WAIT_BCON ... */
-                       musb->xceiv->state = OTG_STATE_A_HOST;
-               }
-               break;
-       case OTG_STATE_A_HOST:
-               devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
-               if (devctl &  MUSB_DEVCTL_BDEVICE)
-                       musb->xceiv->state = OTG_STATE_B_IDLE;
-               else
-                       musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
-       default:
-               break;
-       }
-       spin_unlock_irqrestore(&musb->lock, flags);
-}
-
-
-static void omap2430_musb_try_idle(struct musb *musb, unsigned long timeout)
-{
-       unsigned long           default_timeout = jiffies + msecs_to_jiffies(3);
-       static unsigned long    last_timer;
-
-       if (timeout == 0)
-               timeout = default_timeout;
-
-       /* Never idle if active, or when VBUS timeout is not set as host */
-       if (musb->is_active || ((musb->a_wait_bcon == 0)
-                       && (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) {
-               dev_dbg(musb->controller, "%s active, deleting timer\n",
-                       otg_state_string(musb->xceiv->state));
-               del_timer(&musb_idle_timer);
-               last_timer = jiffies;
-               return;
-       }
-
-       if (time_after(last_timer, timeout)) {
-               if (!timer_pending(&musb_idle_timer))
-                       last_timer = timeout;
-               else {
-                       dev_dbg(musb->controller, "Longer idle timer already pending, ignoring\n");
-                       return;
-               }
-       }
-       last_timer = timeout;
-
-       dev_dbg(musb->controller, "%s inactive, for idle timer for %lu ms\n",
-               otg_state_string(musb->xceiv->state),
-               (unsigned long)jiffies_to_msecs(timeout - jiffies));
-       mod_timer(&musb_idle_timer, timeout);
-}
-
-static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
-{
-       struct usb_otg  *otg = musb->xceiv->otg;
-       u8              devctl;
-       unsigned long timeout = jiffies + msecs_to_jiffies(1000);
-       int ret = 1;
-       /* HDRC controls CPEN, but beware current surges during device
-        * connect.  They can trigger transient overcurrent conditions
-        * that must be ignored.
-        */
-
-       devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
-
-       if (is_on) {
-               if (musb->xceiv->state == OTG_STATE_A_IDLE) {
-                       /* start the session */
-                       devctl |= MUSB_DEVCTL_SESSION;
-                       musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
-                       /*
-                        * Wait for the musb to set as A device to enable the
-                        * VBUS
-                        */
-                       while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) {
-
-                               cpu_relax();
-
-                               if (time_after(jiffies, timeout)) {
-                                       dev_err(musb->controller,
-                                       "configured as A device timeout");
-                                       ret = -EINVAL;
-                                       break;
-                               }
-                       }
-
-                       if (ret && otg->set_vbus)
-                               otg_set_vbus(otg, 1);
-               } else {
-                       musb->is_active = 1;
-                       otg->default_a = 1;
-                       musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
-                       devctl |= MUSB_DEVCTL_SESSION;
-                       MUSB_HST_MODE(musb);
-               }
-       } else {
-               musb->is_active = 0;
-
-               /* NOTE:  we're skipping A_WAIT_VFALL -> A_IDLE and
-                * jumping right to B_IDLE...
-                */
-
-               otg->default_a = 0;
-               musb->xceiv->state = OTG_STATE_B_IDLE;
-               devctl &= ~MUSB_DEVCTL_SESSION;
-
-               MUSB_DEV_MODE(musb);
-       }
-       musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
-
-       dev_dbg(musb->controller, "VBUS %s, devctl %02x "
-               /* otg %3x conf %08x prcm %08x */ "\n",
-               otg_state_string(musb->xceiv->state),
-               musb_readb(musb->mregs, MUSB_DEVCTL));
-}
-
-static int omap2430_musb_set_mode(struct musb *musb, u8 musb_mode)
-{
-       u8      devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
-
-       devctl |= MUSB_DEVCTL_SESSION;
-       musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
-
-       return 0;
-}
-#endif
+#include "musb_uboot.h"
 
 static inline void omap2430_low_level_exit(struct musb *musb)
 {
@@ -223,100 +41,15 @@ static inline void omap2430_low_level_init(struct musb *musb)
        musb_writel(musb->mregs, OTG_FORCESTDBY, l);
 }
 
-#ifndef __UBOOT__
-void omap_musb_mailbox(enum omap_musb_vbus_id_status status)
-{
-       struct omap2430_glue    *glue = _glue;
-       struct musb             *musb = glue_to_musb(glue);
-
-       glue->status = status;
-       if (!musb) {
-               dev_err(glue->dev, "musb core is not yet ready\n");
-               return;
-       }
-
-       schedule_work(&glue->omap_musb_mailbox_work);
-}
-EXPORT_SYMBOL_GPL(omap_musb_mailbox);
-
-static void omap_musb_set_mailbox(struct omap2430_glue *glue)
-{
-       struct musb *musb = glue_to_musb(glue);
-       struct device *dev = musb->controller;
-       struct musb_hdrc_platform_data *pdata = dev->platform_data;
-       struct omap_musb_board_data *data = pdata->board_data;
-       struct usb_otg *otg = musb->xceiv->otg;
-
-       switch (glue->status) {
-       case OMAP_MUSB_ID_GROUND:
-               dev_dbg(dev, "ID GND\n");
-
-               otg->default_a = true;
-               musb->xceiv->state = OTG_STATE_A_IDLE;
-               musb->xceiv->last_event = USB_EVENT_ID;
-               if (!is_otg_enabled(musb) || musb->gadget_driver) {
-                       pm_runtime_get_sync(dev);
-                       usb_phy_init(musb->xceiv);
-                       omap2430_musb_set_vbus(musb, 1);
-               }
-               break;
-
-       case OMAP_MUSB_VBUS_VALID:
-               dev_dbg(dev, "VBUS Connect\n");
-
-               otg->default_a = false;
-               musb->xceiv->state = OTG_STATE_B_IDLE;
-               musb->xceiv->last_event = USB_EVENT_VBUS;
-               if (musb->gadget_driver)
-                       pm_runtime_get_sync(dev);
-               usb_phy_init(musb->xceiv);
-               break;
-
-       case OMAP_MUSB_ID_FLOAT:
-       case OMAP_MUSB_VBUS_OFF:
-               dev_dbg(dev, "VBUS Disconnect\n");
-
-               musb->xceiv->last_event = USB_EVENT_NONE;
-               if (is_otg_enabled(musb) || is_peripheral_enabled(musb))
-                       if (musb->gadget_driver) {
-                               pm_runtime_mark_last_busy(dev);
-                               pm_runtime_put_autosuspend(dev);
-                       }
-
-               if (data->interface_type == MUSB_INTERFACE_UTMI) {
-                       if (musb->xceiv->otg->set_vbus)
-                               otg_set_vbus(musb->xceiv->otg, 0);
-               }
-               usb_phy_shutdown(musb->xceiv);
-               break;
-       default:
-               dev_dbg(dev, "ID float\n");
-       }
-}
-
-
-static void omap_musb_mailbox_work(struct work_struct *mailbox_work)
-{
-       struct omap2430_glue *glue = container_of(mailbox_work,
-                               struct omap2430_glue, omap_musb_mailbox_work);
-       omap_musb_set_mailbox(glue);
-}
-#endif
 
 static int omap2430_musb_init(struct musb *musb)
 {
        u32 l;
        int status = 0;
        unsigned long int start;
-#ifndef __UBOOT__
-       struct device *dev = musb->controller;
-       struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
-       struct musb_hdrc_platform_data *plat = dev->platform_data;
-       struct omap_musb_board_data *data = plat->board_data;
-#else
+
        struct omap_musb_board_data *data =
                (struct omap_musb_board_data *)musb->controller;
-#endif
 
        /* Reset the controller */
        musb_writel(musb->mregs, OTG_SYSCONFIG, SOFTRST);
@@ -334,24 +67,6 @@ static int omap2430_musb_init(struct musb *musb)
                }
        }
 
-#ifndef __UBOOT__
-       /* We require some kind of external transceiver, hooked
-        * up through ULPI.  TWL4030-family PMICs include one,
-        * which needs a driver, drivers aren't always needed.
-        */
-       musb->xceiv = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
-       if (IS_ERR_OR_NULL(musb->xceiv)) {
-               pr_err("HS USB OTG: no transceiver configured\n");
-               return -ENODEV;
-       }
-
-       status = pm_runtime_get_sync(dev);
-       if (status < 0) {
-               dev_err(dev, "pm_runtime_get_sync FAILED %d\n", status);
-               goto err1;
-       }
-#endif
-
        l = musb_readl(musb->mregs, OTG_INTERFSEL);
 
        if (data->interface_type == MUSB_INTERFACE_UTMI) {
@@ -371,64 +86,14 @@ static int omap2430_musb_init(struct musb *musb)
                        musb_readl(musb->mregs, OTG_SYSSTATUS),
                        musb_readl(musb->mregs, OTG_INTERFSEL),
                        musb_readl(musb->mregs, OTG_SIMENABLE));
-
-#ifndef __UBOOT__
-       setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
-
-       if (glue->status != OMAP_MUSB_UNKNOWN)
-               omap_musb_set_mailbox(glue);
-
-       pm_runtime_put_noidle(musb->controller);
-#endif
        return 0;
 
 err1:
        return status;
 }
 
-#ifndef __UBOOT__
-static void omap2430_musb_enable(struct musb *musb)
-#else
 static int omap2430_musb_enable(struct musb *musb)
-#endif
 {
-#ifndef __UBOOT__
-       u8              devctl;
-       unsigned long timeout = jiffies + msecs_to_jiffies(1000);
-       struct device *dev = musb->controller;
-       struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
-       struct musb_hdrc_platform_data *pdata = dev->platform_data;
-       struct omap_musb_board_data *data = pdata->board_data;
-
-       switch (glue->status) {
-
-       case OMAP_MUSB_ID_GROUND:
-               usb_phy_init(musb->xceiv);
-               if (data->interface_type != MUSB_INTERFACE_UTMI)
-                       break;
-               devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
-               /* start the session */
-               devctl |= MUSB_DEVCTL_SESSION;
-               musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
-               while (musb_readb(musb->mregs, MUSB_DEVCTL) &
-                               MUSB_DEVCTL_BDEVICE) {
-                       cpu_relax();
-
-                       if (time_after(jiffies, timeout)) {
-                               dev_err(dev, "configured as A device timeout");
-                               break;
-                       }
-               }
-               break;
-
-       case OMAP_MUSB_VBUS_VALID:
-               usb_phy_init(musb->xceiv);
-               break;
-
-       default:
-               break;
-       }
-#else
 #ifdef CONFIG_TWL4030_USB
        if (twl4030_usb_ulpi_init()) {
                serial_printf("ERROR: %s Could not initialize PHY\n",
@@ -447,18 +112,11 @@ static int omap2430_musb_enable(struct musb *musb)
 #endif
 
        return 0;
-#endif
 }
 
 static void omap2430_musb_disable(struct musb *musb)
 {
-#ifndef __UBOOT__
-       struct device *dev = musb->controller;
-       struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
 
-       if (glue->status != OMAP_MUSB_UNKNOWN)
-               usb_phy_shutdown(musb->xceiv);
-#endif
 }
 
 static int omap2430_musb_exit(struct musb *musb)
@@ -470,174 +128,152 @@ static int omap2430_musb_exit(struct musb *musb)
        return 0;
 }
 
-#ifndef __UBOOT__
-static const struct musb_platform_ops omap2430_ops = {
-#else
 const struct musb_platform_ops omap2430_ops = {
-#endif
        .init           = omap2430_musb_init,
        .exit           = omap2430_musb_exit,
-
-#ifndef __UBOOT__
-       .set_mode       = omap2430_musb_set_mode,
-       .try_idle       = omap2430_musb_try_idle,
-
-       .set_vbus       = omap2430_musb_set_vbus,
-#endif
-
        .enable         = omap2430_musb_enable,
        .disable        = omap2430_musb_disable,
 };
 
-#ifndef __UBOOT__
-static u64 omap2430_dmamask = DMA_BIT_MASK(32);
+#if defined(CONFIG_DM_USB)
+
+struct omap2430_musb_platdata {
+       void *base;
+       void *ctrl_mod_base;
+       struct musb_hdrc_platform_data plat;
+       struct musb_hdrc_config musb_config;
+       struct omap_musb_board_data otg_board_data;
+};
 
-static int __devinit omap2430_probe(struct platform_device *pdev)
+static int omap2430_musb_ofdata_to_platdata(struct udevice *dev)
 {
-       struct musb_hdrc_platform_data  *pdata = pdev->dev.platform_data;
-       struct platform_device          *musb;
-       struct omap2430_glue            *glue;
-       int                             ret = -ENOMEM;
-
-       glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
-       if (!glue) {
-               dev_err(&pdev->dev, "failed to allocate glue context\n");
-               goto err0;
+       struct omap2430_musb_platdata *platdata = dev_get_platdata(dev);
+       const void *fdt = gd->fdt_blob;
+       int node = dev_of_offset(dev);
+
+       platdata->base = (void *)dev_read_addr_ptr(dev);
+
+       platdata->musb_config.multipoint = fdtdec_get_int(fdt, node,
+                                                         "multipoint",
+                                                         -1);
+       if (platdata->musb_config.multipoint < 0) {
+               pr_err("MUSB multipoint DT entry missing\n");
+               return -ENOENT;
        }
 
-       musb = platform_device_alloc("musb-hdrc", -1);
-       if (!musb) {
-               dev_err(&pdev->dev, "failed to allocate musb device\n");
-               goto err0;
+       platdata->musb_config.dyn_fifo = 1;
+       platdata->musb_config.num_eps = fdtdec_get_int(fdt, node,
+                                                      "num-eps", -1);
+       if (platdata->musb_config.num_eps < 0) {
+               pr_err("MUSB num-eps DT entry missing\n");
+               return -ENOENT;
        }
 
-       musb->dev.parent                = &pdev->dev;
-       musb->dev.dma_mask              = &omap2430_dmamask;
-       musb->dev.coherent_dma_mask     = omap2430_dmamask;
-
-       glue->dev                       = &pdev->dev;
-       glue->musb                      = musb;
-       glue->status                    = OMAP_MUSB_UNKNOWN;
-
-       pdata->platform_ops             = &omap2430_ops;
-
-       platform_set_drvdata(pdev, glue);
-
-       /*
-        * REVISIT if we ever have two instances of the wrapper, we will be
-        * in big trouble
-        */
-       _glue   = glue;
-
-       INIT_WORK(&glue->omap_musb_mailbox_work, omap_musb_mailbox_work);
-
-       ret = platform_device_add_resources(musb, pdev->resource,
-                       pdev->num_resources);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to add resources\n");
-               goto err1;
+       platdata->musb_config.ram_bits = fdtdec_get_int(fdt, node,
+                                                       "ram-bits", -1);
+       if (platdata->musb_config.ram_bits < 0) {
+               pr_err("MUSB ram-bits DT entry missing\n");
+               return -ENOENT;
        }
 
-       ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
-       if (ret) {
-               dev_err(&pdev->dev, "failed to add platform_data\n");
-               goto err1;
+       platdata->plat.power = fdtdec_get_int(fdt, node,
+                                                               "power", -1);
+       if (platdata->plat.power < 0) {
+               pr_err("MUSB power DT entry missing\n");
+               return -ENOENT;
        }
 
-       pm_runtime_enable(&pdev->dev);
-
-       ret = platform_device_add(musb);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to register musb device\n");
-               goto err1;
+       platdata->otg_board_data.interface_type = fdtdec_get_int(fdt, node,
+                                                                       "interface-type", -1);
+       if (platdata->otg_board_data.interface_type < 0) {
+               pr_err("MUSB interface-type DT entry missing\n");
+               return -ENOENT;
        }
 
-       return 0;
-
-err1:
-       platform_device_put(musb);
-
-err0:
-       return ret;
-}
-
-static int __devexit omap2430_remove(struct platform_device *pdev)
-{
-       struct omap2430_glue            *glue = platform_get_drvdata(pdev);
-
-       cancel_work_sync(&glue->omap_musb_mailbox_work);
-       platform_device_del(glue->musb);
-       platform_device_put(glue->musb);
-
+#if 0 /* In a perfect world, mode would be set to OTG, mode 3 from DT */
+       platdata->plat.mode = fdtdec_get_int(fdt, node,
+                                                                               "mode", -1);
+       if (platdata->plat.mode < 0) {
+               pr_err("MUSB mode DT entry missing\n");
+               return -ENOENT;
+       }
+#else /* MUSB_OTG, it doesn't work */
+#ifdef CONFIG_USB_MUSB_HOST /* Host seems to be the only option that works */
+       platdata->plat.mode = MUSB_HOST;
+#else /* For that matter, MUSB_PERIPHERAL doesn't either */
+       platdata->plat.mode = MUSB_PERIPHERAL;
+#endif
+#endif
+       platdata->otg_board_data.dev = dev;
+       platdata->plat.config = &platdata->musb_config;
+       platdata->plat.platform_ops = &omap2430_ops;
+       platdata->plat.board_data = &platdata->otg_board_data;
        return 0;
 }
 
-#ifdef CONFIG_PM
-
-static int omap2430_runtime_suspend(struct device *dev)
+static int omap2430_musb_probe(struct udevice *dev)
 {
-       struct omap2430_glue            *glue = dev_get_drvdata(dev);
-       struct musb                     *musb = glue_to_musb(glue);
-
-       if (musb) {
-               musb->context.otg_interfsel = musb_readl(musb->mregs,
-                               OTG_INTERFSEL);
-
-               omap2430_low_level_exit(musb);
-               usb_phy_set_suspend(musb->xceiv, 1);
+#ifdef CONFIG_USB_MUSB_HOST
+       struct musb_host_data *host = dev_get_priv(dev);
+#endif
+       struct omap2430_musb_platdata *platdata = dev_get_platdata(dev);
+       struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
+       struct omap_musb_board_data *otg_board_data;
+       int ret;
+       void *base = dev_read_addr_ptr(dev);
+
+       priv->desc_before_addr = true;
+
+       otg_board_data = &platdata->otg_board_data;
+
+#ifdef CONFIG_USB_MUSB_HOST
+       host->host = musb_init_controller(&platdata->plat,
+                                         (struct device *)otg_board_data,
+                                         platdata->base);
+       if (!host->host) {
+               return -EIO;
        }
 
-       return 0;
+       ret = musb_lowlevel_init(host);
+#else
+       ret = musb_register(&platdata->plat,
+                         (struct device *)otg_board_data,
+                         platdata->base);
+#endif
+       return ret;
 }
 
-static int omap2430_runtime_resume(struct device *dev)
+static int omap2430_musb_remove(struct udevice *dev)
 {
-       struct omap2430_glue            *glue = dev_get_drvdata(dev);
-       struct musb                     *musb = glue_to_musb(glue);
+       struct musb_host_data *host = dev_get_priv(dev);
 
-       if (musb) {
-               omap2430_low_level_init(musb);
-               musb_writel(musb->mregs, OTG_INTERFSEL,
-                               musb->context.otg_interfsel);
-
-               usb_phy_set_suspend(musb->xceiv, 0);
-       }
+       musb_stop(host->host);
 
        return 0;
 }
 
-static struct dev_pm_ops omap2430_pm_ops = {
-       .runtime_suspend = omap2430_runtime_suspend,
-       .runtime_resume = omap2430_runtime_resume,
+static const struct udevice_id omap2430_musb_ids[] = {
+       { .compatible = "ti,omap3-musb" },
+       { .compatible = "ti,omap4-musb" },
+       { }
 };
 
-#define DEV_PM_OPS     (&omap2430_pm_ops)
+U_BOOT_DRIVER(omap2430_musb) = {
+       .name   = "omap2430-musb",
+#ifdef CONFIG_USB_MUSB_HOST
+       .id             = UCLASS_USB,
 #else
-#define DEV_PM_OPS     NULL
+       .id             = UCLASS_USB_DEV_GENERIC,
 #endif
-
-static struct platform_driver omap2430_driver = {
-       .probe          = omap2430_probe,
-       .remove         = __devexit_p(omap2430_remove),
-       .driver         = {
-               .name   = "musb-omap2430",
-               .pm     = DEV_PM_OPS,
-       },
+       .of_match = omap2430_musb_ids,
+       .ofdata_to_platdata = omap2430_musb_ofdata_to_platdata,
+       .probe = omap2430_musb_probe,
+       .remove = omap2430_musb_remove,
+#ifdef CONFIG_USB_MUSB_HOST
+       .ops = &musb_usb_ops,
+#endif
+       .platdata_auto_alloc_size = sizeof(struct omap2430_musb_platdata),
+       .priv_auto_alloc_size = sizeof(struct musb_host_data),
 };
 
-MODULE_DESCRIPTION("OMAP2PLUS MUSB Glue Layer");
-MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
-MODULE_LICENSE("GPL v2");
-
-static int __init omap2430_init(void)
-{
-       return platform_driver_register(&omap2430_driver);
-}
-subsys_initcall(omap2430_init);
-
-static void __exit omap2430_exit(void)
-{
-       platform_driver_unregister(&omap2430_driver);
-}
-module_exit(omap2430_exit);
-#endif
+#endif /* CONFIG_DM_USB */
index f4af154..02ac4c7 100644 (file)
@@ -131,6 +131,44 @@ static inline void device_free(struct udevice *dev) {}
 #endif
 
 /**
+ * device_chld_unbind() - Unbind all device's children from the device if bound
+ *                       to drv
+ *
+ * On error, the function continues to unbind all children, and reports the
+ * first error.
+ *
+ * @dev:       The device that is to be stripped of its children
+ * @drv:       The targeted driver
+ * @return 0 on success, -ve on error
+ */
+#if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)
+int device_chld_unbind(struct udevice *dev, struct driver *drv);
+#else
+static inline int device_chld_unbind(struct udevice *dev, struct driver *drv)
+{
+       return 0;
+}
+#endif
+
+/**
+ * device_chld_remove() - Stop all device's children
+ * @dev:       The device whose children are to be removed
+ * @drv:       The targeted driver
+ * @flags:     Flag, if this functions is called in the pre-OS stage
+ * @return 0 on success, -ve on error
+ */
+#if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)
+int device_chld_remove(struct udevice *dev, struct driver *drv,
+                      uint flags);
+#else
+static inline int device_chld_remove(struct udevice *dev, struct driver *drv,
+                                    uint flags)
+{
+       return 0;
+}
+#endif
+
+/**
  * simple_bus_translate() - translate a bus address to a system address
  *
  * This handles the 'ranges' property in a simple bus. It translates the
index 49078bc..3120b68 100644 (file)
@@ -473,18 +473,33 @@ int device_get_child_by_of_offset(struct udevice *parent, int of_offset,
                                  struct udevice **devp);
 
 /**
- * device_get_global_by_of_offset() - Get a device based on FDT offset
+ * device_find_global_by_ofnode() - Get a device based on ofnode
  *
- * Locates a device by its device tree offset, searching globally throughout
+ * Locates a device by its device tree ofnode, searching globally throughout
+ * the all driver model devices.
+ *
+ * The device is NOT probed
+ *
+ * @node: Device tree ofnode to find
+ * @devp: Returns pointer to device if found, otherwise this is set to NULL
+ * @return 0 if OK, -ve on error
+ */
+
+int device_find_global_by_ofnode(ofnode node, struct udevice **devp);
+
+/**
+ * device_get_global_by_ofnode() - Get a device based on ofnode
+ *
+ * Locates a device by its device tree ofnode, searching globally throughout
  * the all driver model devices.
  *
  * The device is probed to activate it ready for use.
  *
- * @of_offset: Device tree offset to find
+ * @node: Device tree ofnode to find
  * @devp: Returns pointer to device if found, otherwise this is set to NULL
  * @return 0 if OK, -ve on error
  */
-int device_get_global_by_of_offset(int of_offset, struct udevice **devp);
+int device_get_global_by_ofnode(ofnode node, struct udevice **devp);
 
 /**
  * device_find_first_child() - Find the first child of a device
index 7ba064b..30d5a4f 100644 (file)
 int uclass_get_device_tail(struct udevice *dev, int ret, struct udevice **devp);
 
 /**
+ * dev_get_uclass_index() - Get uclass and index of device
+ * @dev:       - in - Device that we want the uclass/index of
+ * @ucp:       - out - A pointer to the uclass the device belongs to
+ *
+ * The device is not prepared for use - this is an internal function.
+ *
+ * @return the index of the device in the uclass list or -ENODEV if not found.
+ */
+int dev_get_uclass_index(struct udevice *dev, struct uclass **ucp);
+
+/**
  * uclass_find_device() - Return n-th child of uclass
  * @id:                Id number of the uclass
  * @index:     Position of the child in uclass's list
index fa3f549..91d861b 100644 (file)
@@ -312,7 +312,8 @@ void eth_halt(void)
 
        eth_get_ops(current)->stop(current);
        priv = current->uclass_priv;
-       priv->state = ETH_STATE_PASSIVE;
+       if (priv)
+               priv->state = ETH_STATE_PASSIVE;
 }
 
 int eth_is_active(struct udevice *dev)
diff --git a/test/py/tests/test_bind.py b/test/py/tests/test_bind.py
new file mode 100644 (file)
index 0000000..f21b705
--- /dev/null
@@ -0,0 +1,178 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
+
+import os.path
+import pytest
+import re
+
+def in_tree(response, name, uclass, drv, depth, last_child):
+       lines = [x.strip() for x in response.splitlines()]
+       leaf = ' ' * 4 * depth;
+       if not last_child:
+               leaf = leaf + '\|'
+       else:
+               leaf = leaf + '`'
+       leaf = leaf + '-- ' + name
+       line = ' *{:10.10}  [0-9]*  \[ [ +] \]   {:10.10}  {}$'.format(uclass, drv,leaf)
+       prog = re.compile(line)
+       for l in lines:
+               if prog.match(l):
+                       return True
+       return False
+
+
+@pytest.mark.buildconfigspec('cmd_bind')
+def test_bind_unbind_with_node(u_boot_console):
+
+       #bind /bind-test. Device should come up as well as its children
+       response = u_boot_console.run_command("bind  /bind-test generic_simple_bus")
+       assert response == ''
+       tree = u_boot_console.run_command("dm tree")
+       assert in_tree(tree, "bind-test", "simple_bus", "generic_simple", 0, True)
+       assert in_tree(tree, "bind-test-child1", "phy", "phy_sandbox", 1, False)
+       assert in_tree(tree, "bind-test-child2", "simple_bus", "generic_simple", 1, True)
+
+       #Unbind child #1. No error expected and all devices should be there except for bind-test-child1
+       response = u_boot_console.run_command("unbind  /bind-test/bind-test-child1")
+       assert response == ''
+       tree = u_boot_console.run_command("dm tree")
+       assert in_tree(tree, "bind-test", "simple_bus", "generic_simple", 0, True)
+       assert "bind-test-child1" not in tree
+       assert in_tree(tree, "bind-test-child2", "simple_bus", "generic_simple", 1, True)
+
+       #bind child #1. No error expected and all devices should be there
+       response = u_boot_console.run_command("bind  /bind-test/bind-test-child1 phy_sandbox")
+       assert response == ''
+       tree = u_boot_console.run_command("dm tree")
+       assert in_tree(tree, "bind-test", "simple_bus", "generic_simple", 0, True)
+       assert in_tree(tree, "bind-test-child1", "phy", "phy_sandbox", 1, True)
+       assert in_tree(tree, "bind-test-child2", "simple_bus", "generic_simple", 1, False)
+
+       #Unbind child #2. No error expected and all devices should be there except for bind-test-child2
+       response = u_boot_console.run_command("unbind  /bind-test/bind-test-child2")
+       assert response == ''
+       tree = u_boot_console.run_command("dm tree")
+       assert in_tree(tree, "bind-test", "simple_bus", "generic_simple", 0, True)
+       assert in_tree(tree, "bind-test-child1", "phy", "phy_sandbox", 1, True)
+       assert "bind-test-child2" not in tree
+
+
+       #Bind child #2. No error expected and all devices should be there
+       response = u_boot_console.run_command("bind /bind-test/bind-test-child2 generic_simple_bus")
+       assert response == ''
+       tree = u_boot_console.run_command("dm tree")
+       assert in_tree(tree, "bind-test", "simple_bus", "generic_simple", 0, True)
+       assert in_tree(tree, "bind-test-child1", "phy", "phy_sandbox", 1, False)
+       assert in_tree(tree, "bind-test-child2", "simple_bus", "generic_simple", 1, True)
+
+       #Unbind parent. No error expected. All devices should be removed and unbound
+       response = u_boot_console.run_command("unbind  /bind-test")
+       assert response == ''
+       tree = u_boot_console.run_command("dm tree")
+       assert "bind-test" not in tree
+       assert "bind-test-child1" not in tree
+       assert "bind-test-child2" not in tree
+
+       #try binding invalid node with valid driver
+       response = u_boot_console.run_command("bind  /not-a-valid-node generic_simple_bus")
+       assert response != ''
+       tree = u_boot_console.run_command("dm tree")
+       assert "not-a-valid-node" not in tree
+
+       #try binding valid node with invalid driver
+       response = u_boot_console.run_command("bind  /bind-test not_a_driver")
+       assert response != ''
+       tree = u_boot_console.run_command("dm tree")
+       assert "bind-test" not in tree
+
+       #bind /bind-test. Device should come up as well as its children
+       response = u_boot_console.run_command("bind  /bind-test generic_simple_bus")
+       assert response == ''
+       tree = u_boot_console.run_command("dm tree")
+       assert in_tree(tree, "bind-test", "simple_bus", "generic_simple", 0, True)
+       assert in_tree(tree, "bind-test-child1", "phy", "phy_sandbox", 1, False)
+       assert in_tree(tree, "bind-test-child2", "simple_bus", "generic_simple", 1, True)
+
+       response = u_boot_console.run_command("unbind  /bind-test")
+       assert response == ''
+
+def get_next_line(tree, name):
+       treelines = [x.strip() for x in tree.splitlines() if x.strip()]
+       child_line = ""
+       for idx, line in enumerate(treelines):
+               if ("-- " + name) in line:
+                       try:
+                               child_line = treelines[idx+1]
+                       except:
+                               pass
+                       break
+       return child_line
+
+@pytest.mark.buildconfigspec('cmd_bind')
+def test_bind_unbind_with_uclass(u_boot_console):
+       #bind /bind-test
+       response = u_boot_console.run_command("bind  /bind-test generic_simple_bus")
+       assert response == ''
+
+       #make sure bind-test-child2 is there and get its uclass/index pair
+       tree = u_boot_console.run_command("dm tree")
+       child2_line = [x.strip() for x in tree.splitlines() if "-- bind-test-child2" in x]
+       assert len(child2_line) == 1
+
+       child2_uclass = child2_line[0].split()[0]
+       child2_index = int(child2_line[0].split()[1])
+
+       #bind generic_simple_bus as a child of bind-test-child2
+       response = u_boot_console.run_command("bind  {} {} generic_simple_bus".format(child2_uclass, child2_index, "generic_simple_bus"))
+
+       #check that the child is there and its uclass/index pair is right
+       tree = u_boot_console.run_command("dm tree")
+
+       child_of_child2_line = get_next_line(tree, "bind-test-child2")
+       assert child_of_child2_line
+       child_of_child2_index = int(child_of_child2_line.split()[1])
+       assert in_tree(tree, "generic_simple_bus", "simple_bus", "generic_simple_bus", 2, True)
+       assert child_of_child2_index == child2_index + 1
+
+       #unbind the child and check it has been removed
+       response = u_boot_console.run_command("unbind  simple_bus {}".format(child_of_child2_index))
+       assert response == ''
+       tree = u_boot_console.run_command("dm tree")
+       assert in_tree(tree, "bind-test-child2", "simple_bus", "generic_simple", 1, True)
+       assert not in_tree(tree, "generic_simple_bus", "simple_bus", "generic_simple_bus", 2, True)
+       child_of_child2_line = get_next_line(tree, "bind-test-child2")
+       assert child_of_child2_line == ""
+
+       #bind generic_simple_bus as a child of bind-test-child2
+       response = u_boot_console.run_command("bind  {} {} generic_simple_bus".format(child2_uclass, child2_index, "generic_simple_bus"))
+
+       #check that the child is there and its uclass/index pair is right
+       tree = u_boot_console.run_command("dm tree")
+       treelines = [x.strip() for x in tree.splitlines() if x.strip()]
+
+       child_of_child2_line = get_next_line(tree, "bind-test-child2")
+       assert child_of_child2_line
+       child_of_child2_index = int(child_of_child2_line.split()[1])
+       assert in_tree(tree, "generic_simple_bus", "simple_bus", "generic_simple_bus", 2, True)
+       assert child_of_child2_index == child2_index + 1
+
+       #unbind the child and check it has been removed
+       response = u_boot_console.run_command("unbind  {} {} generic_simple_bus".format(child2_uclass, child2_index, "generic_simple_bus"))
+       assert response == ''
+
+       tree = u_boot_console.run_command("dm tree")
+       assert in_tree(tree, "bind-test-child2", "simple_bus", "generic_simple", 1, True)
+
+       child_of_child2_line = get_next_line(tree, "bind-test-child2")
+       assert child_of_child2_line == ""
+
+       #unbind the child again and check it doesn't change the tree
+       tree_old = u_boot_console.run_command("dm tree")
+       response = u_boot_console.run_command("unbind  {} {} generic_simple_bus".format(child2_uclass, child2_index, "generic_simple_bus"))
+       tree_new = u_boot_console.run_command("dm tree")
+
+       assert response == ''
+       assert tree_old == tree_new
+
+       response = u_boot_console.run_command("unbind  /bind-test")
+       assert response == ''