Skip to contentSkip to conversation

dm: Add USB support

PATCH Superseded Simon Glass 4 participants 178 messages Mar 25, 2015 – Jun 11, 2015

Subsystems (11)
lore
Share & tools
lore
#0 lore raw

v2 cover dm: Add USB support

This series adds driver model support to USB. The intent is to permit the various subsystems (OHCI, EHCI, XHCI) to co-exist and allow any number of USB ports of different types.

With the RFC series, only USB controllers had a real driver model device. USB devices (including the hub in the controller) were not modelled as driver model devices.

While this was expedient, and produced much fewer patches, it is not a long-term solution. Also, since then, driver model Ethernet support (which USB can use) has been merged to u-boot-dm/next. It seems better to bite the bullet and do a full conversion.

Unfortunately this results in a very large series. It includes:

- USB uclass
- USB hub uclass
- Adjustments to make USB keyboard, Ethernet and storage continue to work
- Sandbox USB emulation support
- Sandbox USB emulations for flash and hub devices
- A reasonable set of tests
- EHCI and XHCI support (not OHCI)
- Conversion of Tegra and Exynos drivers to driver model
- Adjustments to make the 'usb' command operate as expected
- README describing how USB works with driver model

Both EHCI and XHCI needed a little bit of refactoring before they are converted to driver model - e.g. removal of weak fuctions and splitting up the init code.

This series includes patches to remove the non-driver-model code for Exynos and Tegra, to be applied once everything is stable. For now it is convenient to be able to compare the two options.

This series does not change how USB is started up. The 'usb start' command scans the buses as before, and takes just as long. Once it has started you can use 'dm tree' to see the tree structure of the USB bus, although 'usb tree' provides a better view. It is unclear how we could implement lazy init for USB given the long time it takes to probe the bus.

A README is provided to describe how USB works under driver model.

This series is available at u-boot-dm/usb-working.

Changes in v2:
- Rewrite and expand series to support driver model fully

Simon Glass (80):
linker_lists: Add a function to access a linker list entry
sandbox: Fix comment for os_open()
dm: test: bus: Use a local variable to simplify code
dm: exynos: snow: Move the keyboard to I2C
dm: core: Support allocating driver-private data for DMA
dm: core: Convert driver_bind() to use const
dm: core: Rename driver data function to dev_get_driver_data()
dm: core: Mark device as active before calling uclass probe() methods
dm: core: Add device children and sibling functions
dm: gpio: Add an implementation for gpio_get_number()
dm: usb: Add a uclass for USB controllers
dm: usb: Adjust usb command to prepare for driver model
dm: usb: Adjust usb_alloc_new_device() to return an error
dm: usb: Convert 'usb' command to support driver model
dm: usb: Drop the legacy USB init sequence
dm: usb: Refactor port resets
dm: usb: Move descriptor setup code into its own function
dm: usb: Split out more code from usb_new_device()
dm: usb: Complete the splitting up of usb_new_device()
dm: usb: Convert core usb.c file to support driver model
dm: usb: Split hub detection into its own function
dm: usb: Add driver model support for hubs
dm: usb: Move USB storage definitions to usb_defs.h
dm: usb: Fix type problems in usb_stor_get_info()
dm: usb: Simply device finding code in usb_storage
dm: usb: Adjust usb_storage to work with sandbox
dm: usb: Move storage device scanning into its own function
dm: usb: Convert usb_storage to driver model
dm: usb: Move all the EHCI weak functions together and declare them
dm: usb: Pass EHCI controller pointer to ehci_get_port_speed()
dm: usb: Allow ECHI to hold private data for the controller
dm: usb: tegra: Store the controller type explicitly
dm: usb: Pass EHCI controller pointer to ehci_powerup_fixup()
dm: usb: tegra: Drop use of global controller variable
dm: usb: Pass EHCI controller pointer to ehci_set_usbmode()
dm: usb: Pass EHCI controller pointer to ehci_get_portsc_register()
dm: usb: ehci: Use a function to find the controller from struct
udevice
dm: usb: Refactor EHCI init
dm: usb: Drop the EHCI weak functions
dm: usb: Change ehci_reset() to use a pointer
dm: usb: Add driver model support to EHCI
dm: usb: Allow USB drivers to be declared and auto-probed
dm: usb: Bind generic USB devices when there is no driver
dm: usb: Allow setting up a USB controller as a device/gadget
dm: usb: Split out the keyboard probe into its own function
dm: usb: Support driver model with USB keyboards
dm: usb: tegra: Add vbus GPIOs for nyan
dm: usb: Move struct usb_string to a common place
dm: usb: sandbox: Add a uclass for USB device emulation
dm: usb: sandbox: Reset emulation devices in usb stop()
dm: usb: sandbox: Add an emulator for USB flash devices
dm: usb: sandbox: Add an emulator for USB hub emulation
dm: usb: sandbox: Add a driver for sandbox
dm: usb: dts: sandbox: Add some sample USB devices to sandbox
dm: usb: Add support for USB ethernet devices with driver model
dm: usb: exynos: Add driver model support to exynos EHCI
dm: usb: tegra: Remove the port_addr_clear_csc variable
dm: usb: tegra: Tidy up error handling and a static function
dm: usb: tegra: Move most of init/uninit into a function
dm: usb: tegra: Add driver model support to tegra EHCI
dm: usb: xhci: Use a function to get xhci_ctrl
dm: usb: xhci: Use explicit parameters for xhci_alloc_virt_device()
dm: usb: xhci: Use explicit parameters for
xhci_setup_addressable_virt_dev()
dm: usb: xhci: Factor out common init/uninit
dm: usb: Support driver model in XHCI
dm: usb: Rename the XHCI HCD to U-Boot
dm: usb: exynos: Adjust XHCI driver to support driver model
dm: usb: exynos: Use driver model for USB
dm: usb: exynos: Enable both USB ports on snow
dm: usb: exynos: Enable both EHCI and XHCI on snow
dm: usb: tegra: Move to driver model for USB
dm: usb: Add a generic descriptor struct
dm: usb: Tidy up pipe value decoding
dm: usb: sandbox: Enable USB
dm: test: Correct printf() output nit in 'dm uclass'
dm: test: Allow 'dm test' to select a particular test to run
dm: usb: Add tests for the USB uclass
dm: usb: tegra: Drop legacy USB code
dm: usb: exynos: Drop legacy USB code
dm: usb: Add a README for driver model

 Makefile                                |   1 +
 arch/arm/cpu/armv7/exynos/Kconfig       |   3 +
 arch/arm/dts/exynos5250-snow.dts        |   5 +-
 arch/arm/dts/tegra124-nyan-big.dts      |   2 +
 arch/arm/mach-tegra/Kconfig             |   3 +
 arch/sandbox/dts/sandbox.dts            |  40 ++
 board/genesi/mx51_efikamx/efikamx-usb.c |   4 +-
 board/nvidia/common/board.c             |   1 -
 common/cmd_usb.c                        | 198 ++++++++--
 common/usb.c                            | 277 ++++++++------
 common/usb_hub.c                        | 194 ++++++++--
 common/usb_kbd.c                        | 119 ++++--
 common/usb_storage.c                    | 249 ++++++------
 configs/sandbox_defconfig               |   4 +
 doc/driver-model/usb-info.txt           | 415 ++++++++++++++++++++
 drivers/core/device-remove.c            |   4 +-
 drivers/core/device.c                   |  66 +++-
 drivers/core/lists.c                    |   2 +-
 drivers/gpio/gpio-uclass.c              |  12 +
 drivers/i2c/s3c24x0_i2c.c               |   2 +-
 drivers/i2c/tegra_i2c.c                 |   6 +-
 drivers/usb/Kconfig                     |  16 +
 drivers/usb/emul/Kconfig                |   8 +
 drivers/usb/emul/Makefile               |  10 +
 drivers/usb/emul/sandbox_flash.c        | 423 +++++++++++++++++++++
 drivers/usb/emul/sandbox_hub.c          | 303 +++++++++++++++
 drivers/usb/emul/usb-emul-uclass.c      | 263 +++++++++++++
 drivers/usb/eth/usb_ether.c             |  52 ++-
 drivers/usb/gadget/ci_udc.c             |   4 +
 drivers/usb/host/Makefile               |   5 +
 drivers/usb/host/ehci-exynos.c          | 127 +++----
 drivers/usb/host/ehci-faraday.c         | 112 +++---
 drivers/usb/host/ehci-hcd.c             | 379 ++++++++++++++-----
 drivers/usb/host/ehci-mx5.c             |  12 +
 drivers/usb/host/ehci-tegra.c           | 288 +++++++-------
 drivers/usb/host/ehci.h                 |  47 +++
 drivers/usb/host/usb-sandbox.c          | 117 ++++++
 drivers/usb/host/usb-uclass.c           | 645 ++++++++++++++++++++++++++++++++
 drivers/usb/host/xhci-exynos5.c         | 106 +++---
 drivers/usb/host/xhci-mem.c             |  24 +-
 drivers/usb/host/xhci-ring.c            |   8 +-
 drivers/usb/host/xhci.c                 | 312 ++++++++++++---
 drivers/usb/host/xhci.h                 |  31 +-
 drivers/usb/musb-new/musb_uboot.c       |   4 +-
 include/configs/sandbox.h               |   2 +
 include/configs/snow.h                  |   2 +
 include/dm/device-internal.h            |   2 +-
 include/dm/device.h                     |  51 ++-
 include/dm/test.h                       |   7 +-
 include/dm/uclass-id.h                  |   5 +
 include/fdtdec.h                        |   5 -
 include/linker_lists.h                  |  10 +
 include/linux/usb/ch9.h                 |  18 +
 include/linux/usb/gadget.h              |  13 -
 include/os.h                            |   2 +-
 include/usb.h                           | 494 +++++++++++++++++++++++-
 include/usb_defs.h                      |  68 +++-
 lib/fdtdec.c                            |   5 -
 test/dm/Makefile                        |   1 +
 test/dm/bus.c                           |  16 +-
 test/dm/cmd_dm.c                        |  13 +-
 test/dm/test-dm.sh                      |   3 +
 test/dm/test-main.c                     |   7 +-
 test/dm/test-uclass.c                   |   3 +-
 test/dm/test.dts                        |  41 ++
 test/dm/usb.c                           |  50 +++
 66 files changed, 4807 insertions(+), 914 deletions(-)
 create mode 100644 doc/driver-model/usb-info.txt
 create mode 100644 drivers/usb/emul/Kconfig
 create mode 100644 drivers/usb/emul/Makefile
 create mode 100644 drivers/usb/emul/sandbox_flash.c
 create mode 100644 drivers/usb/emul/sandbox_hub.c
 create mode 100644 drivers/usb/emul/usb-emul-uclass.c
 create mode 100644 drivers/usb/host/usb-sandbox.c
 create mode 100644 drivers/usb/host/usb-uclass.c
 create mode 100644 test/dm/usb.c
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#1 lore raw

PATCH v2 1/80 linker_lists: Add a function to access a linker list entry

Once declared, you cannot access a linker_list entry since you do not have a symbol name for it. Add llsym() macro to provide this. This avoids searching for the symbol at run-time based on name.

An example usage is to declare a driver with U_BOOT_DRIVER(), then obtain a pointer to that driver later.

---

Changes in v2: None

 include/linker_lists.h | 10 ++++++++++
 1 file changed, 10 insertions(+)
include/linker_lists.h +10 -0
index 940c871..b22d169 100644
@@ -103,6 +103,16 @@
  */
 
 /**
+ * ll_sym() - Access a linker-generated array entry
+ * @_type:	Data type of the entry
+ * @_name:	Name of the entry
+ * @_list:	name of the list. Should contain only characters allowed
+ *		in a C variable name!
+ */
+#define llsym(_type, _name, _list) \
+		((_type *)&_u_boot_list_2_##_list##_2_##_name)
+
+/**
  * ll_entry_declare() - Declare linker-generated array entry
  * @_type:	Data type of the entry
  * @_name:	Name of the entry
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#2 lore raw

PATCH v2 1/80 linker_lists: Add a function to access a linker list entry

Quoted 7 lines · Simon Glass

Once declared, you cannot access a linker_list entry since you do not have a symbol name for it. Add llsym() macro to provide this. This avoids searching for the symbol at run-time based on name.

An example usage is to declare a driver with U_BOOT_DRIVER(), then obtain a pointer to that driver later.

Quoted 7 lines

---

Changes in v2: None

 include/linker_lists.h | 10 ++++++++++
 1 file changed, 10 insertions(+)

Applied to u-boot-dm/next.

#3 lore raw

PATCH v2 2/80 sandbox: Fix comment for os_open()

In reply to Simon Glass

This has the wrong #define in the function comment. Fix it.

---

Changes in v2: None

 include/os.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
include/os.h +1 -1
index e3645e0..a758f09 100644
@@ -64,7 +64,7 @@ off_t os_lseek(int fd, off_t offset, int whence);
  * Access to the OS open() system call
  *
  * \param pathname	Pathname of file to open
- * \param flags		Flags, like O_RDONLY, O_RDWR
+ * \param flags		Flags, like OS_O_RDONLY, OS_O_RDWR
  * \return file descriptor, or -1 on error
  */
 int os_open(const char *pathname, int flags);
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#4 lore raw

PATCH v2 2/80 sandbox: Fix comment for os_open()

Quoted 9 lines · Simon Glass

This has the wrong #define in the function comment. Fix it.

---

Changes in v2: None

 include/os.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Applied to u-boot-dm/next.

#5 lore raw

PATCH v2 3/80 dm: test: bus: Use a local variable to simplify code

In reply to Simon Glass

Adjust this test to avoid repeating the same code too often.

---

Changes in v2: None

 test/dm/bus.c | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)
test/dm/bus.c +10 -6
index faffe6a..116a52d 100644
@@ -273,20 +273,22 @@ DM_TEST(dm_test_bus_parent_data, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 /* As above but the size is controlled by the uclass */
 static int dm_test_bus_parent_data_uclass(struct dm_test_state *dms)
 {
+	struct driver *drv;
 	struct udevice *bus;
 	int size;
 	int ret;
 
 	/* Set the driver size to 0 so that the uclass size is used */
 	ut_assertok(uclass_find_device(UCLASS_TEST_BUS, 0, &bus));
-	size = bus->driver->per_child_auto_alloc_size;
+	drv = (struct driver *)bus->driver;
+	size = drv->per_child_auto_alloc_size;
 	bus->uclass->uc_drv->per_child_auto_alloc_size = size;
-	bus->driver->per_child_auto_alloc_size = 0;
+	drv->per_child_auto_alloc_size = 0;
 	ret = test_bus_parent_data(dms);
 	if (ret)
 		return ret;
 	bus->uclass->uc_drv->per_child_auto_alloc_size = 0;
-	bus->driver->per_child_auto_alloc_size = size;
+	drv->per_child_auto_alloc_size = size;
 
 	return 0;
 }
@@ -414,19 +416,21 @@ DM_TEST(dm_test_bus_parent_platdata, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 static int dm_test_bus_parent_platdata_uclass(struct dm_test_state *dms)
 {
 	struct udevice *bus;
+	struct driver *drv;
 	int size;
 	int ret;
 
 	/* Set the driver size to 0 so that the uclass size is used */
 	ut_assertok(uclass_find_device(UCLASS_TEST_BUS, 0, &bus));
-	size = bus->driver->per_child_platdata_auto_alloc_size;
+	drv = (struct driver *)bus->driver;
+	size = drv->per_child_platdata_auto_alloc_size;
 	bus->uclass->uc_drv->per_child_platdata_auto_alloc_size = size;
-	bus->driver->per_child_platdata_auto_alloc_size = 0;
+	drv->per_child_platdata_auto_alloc_size = 0;
 	ret = test_bus_parent_platdata(dms);
 	if (ret)
 		return ret;
 	bus->uclass->uc_drv->per_child_platdata_auto_alloc_size = 0;
-	bus->driver->per_child_platdata_auto_alloc_size = size;
+	drv->per_child_platdata_auto_alloc_size = size;
 
 	return 0;
 }
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#6 lore raw

PATCH v2 3/80 dm: test: bus: Use a local variable to simplify code

Quoted 9 lines · Simon Glass

Adjust this test to avoid repeating the same code too often.

---

Changes in v2: None

 test/dm/bus.c | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

Applied to u-boot-dm/next.

#7 lore raw

PATCH v2 4/80 dm: exynos: snow: Move the keyboard to I2C

In reply to Simon Glass

The snow keyboard on shipping devices is actually on I2C not SPI. Move the label to indicate this.

---

Changes in v2: None

 arch/arm/dts/exynos5250-snow.dts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
arch/arm/dts/exynos5250-snow.dts +2 -2
index 7d8be69..d6777ee 100644
@@ -40,7 +40,7 @@
 	};
 
 	i2c4: i2c at 12ca0000 {
-		cros-ec at 1e {
+		cros_ec: cros-ec at 1e {
 			reg = <0x1e>;
 			compatible = "google,cros-ec";
 			i2c-max-frequency = <100000>;
@@ -65,7 +65,7 @@
 	spi at 131b0000 {
 		spi-max-frequency = <1000000>;
 		spi-deactivate-delay = <100>;
-		cros_ec: cros-ec at 0 {
+		cros-ec at 0 {
 			reg = <0>;
 			compatible = "google,cros-ec";
 			spi-max-frequency = <5000000>;
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#8 lore raw

PATCH v2 4/80 dm: exynos: snow: Move the keyboard to I2C

Hi,

Quoted 10 lines · Simon Glass

The snow keyboard on shipping devices is actually on I2C not SPI. Move the label to indicate this.

---

Changes in v2: None

 arch/arm/dts/exynos5250-snow.dts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

This patch is not needed now, so I'm dropping it. Commit c9b53f8d solved this problem.

Regards,
Simon

#9 lore raw

PATCH v2 5/80 dm: core: Support allocating driver-private data for DMA

In reply to Simon Glass

Some driver want to put DMA buffers in their private data. Add a flag to tell driver model to align driver-private data to a cache boundary so that DMA will work correctly in this case.

---

Changes in v2: None

 drivers/core/device.c | 19 +++++++++++++++++--
 include/dm/device.h   |  3 +++
 2 files changed, 20 insertions(+), 2 deletions(-)
drivers/core/device.c +17 -2
index 7483405..1ca5d1c 100644
@@ -164,6 +164,21 @@ int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
 			   -1, devp);
 }
 
+static void *alloc_priv(int size, uint flags)
+{
+	void *priv;
+
+	if (flags & DM_FLAG_ALLOC_PRIV_DMA) {
+		priv = memalign(ARCH_DMA_MINALIGN, size);
+		if (priv)
+			memset(priv, '\0', size);
+	} else {
+		priv = calloc(1, size);
+	}
+
+	return priv;
+}
+
 int device_probe_child(struct udevice *dev, void *parent_priv)
 {
 	struct driver *drv;
@@ -182,7 +197,7 @@ int device_probe_child(struct udevice *dev, void *parent_priv)
 
 	/* Allocate private data if requested */
 	if (drv->priv_auto_alloc_size) {
-		dev->priv = calloc(1, drv->priv_auto_alloc_size);
+		dev->priv = alloc_priv(drv->priv_auto_alloc_size, drv->flags);
 		if (!dev->priv) {
 			ret = -ENOMEM;
 			goto fail;
@@ -206,7 +221,7 @@ int device_probe_child(struct udevice *dev, void *parent_priv)
 					per_child_auto_alloc_size;
 		}
 		if (size) {
-			dev->parent_priv = calloc(1, size);
+			dev->parent_priv = alloc_priv(size, drv->flags);
 			if (!dev->parent_priv) {
 				ret = -ENOMEM;
 				goto fail;
include/dm/device.h +3 -0
index 6980954..f27b34b 100644
@@ -30,6 +30,9 @@ struct driver_info;
 /* DM is responsible for allocating and freeing parent_platdata */
 #define DM_FLAG_ALLOC_PARENT_PDATA	(1 << 3)
 
+/* Allocate driver private data on a DMA boundary */
+#define DM_FLAG_ALLOC_PRIV_DMA	(1 << 4)
+
 /**
  * struct udevice - An instance of a driver
  *
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#10 lore raw

PATCH v2 5/80 dm: core: Support allocating driver-private data for DMA

Quoted 4 lines · Simon Glass

Some driver want to put DMA buffers in their private data. Add a flag to tell driver model to align driver-private data to a cache boundary so that DMA will work correctly in this case.

Quoted 8 lines

---

Changes in v2: None

 drivers/core/device.c | 19 +++++++++++++++++--
 include/dm/device.h   |  3 +++
 2 files changed, 20 insertions(+), 2 deletions(-)

Applied to u-boot-dm/next.

#11 lore raw

PATCH v2 6/80 dm: core: Convert driver_bind() to use const

In reply to Simon Glass

The driver is not modified by driver model, so update driver_bind() to recognise that.

---

Changes in v2: None

 drivers/core/device-remove.c | 4 ++--
 drivers/core/device.c        | 7 ++++---
 include/dm/device-internal.h | 2 +-
 include/dm/device.h          | 2 +-
 4 files changed, 8 insertions(+), 7 deletions(-)
drivers/core/device-remove.c +2 -2
index 3a5f48d..7fee1c0 100644
@@ -66,7 +66,7 @@ static int device_chld_remove(struct udevice *dev)
 
 int device_unbind(struct udevice *dev)
 {
-	struct driver *drv;
+	const struct driver *drv;
 	int ret;
 
 	if (!dev)
@@ -139,7 +139,7 @@ void device_free(struct udevice *dev)
 
 int device_remove(struct udevice *dev)
 {
-	struct driver *drv;
+	const struct driver *drv;
 	int ret;
 
 	if (!dev)
drivers/core/device.c +4 -3
index 1ca5d1c..f1a03d9 100644
@@ -24,8 +24,9 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
-int device_bind(struct udevice *parent, struct driver *drv, const char *name,
-		void *platdata, int of_offset, struct udevice **devp)
+int device_bind(struct udevice *parent, const struct driver *drv,
+		const char *name, void *platdata, int of_offset,
+		struct udevice **devp)
 {
 	struct udevice *dev;
 	struct uclass *uc;
@@ -181,7 +182,7 @@ static void *alloc_priv(int size, uint flags)
 
 int device_probe_child(struct udevice *dev, void *parent_priv)
 {
-	struct driver *drv;
+	const struct driver *drv;
 	int size = 0;
 	int ret;
 	int seq;
include/dm/device-internal.h +1 -1
index e2418fe..687462b 100644
@@ -34,7 +34,7 @@ struct udevice;
  * @devp: Returns a pointer to the bound device
  * @return 0 if OK, -ve on error
  */
-int device_bind(struct udevice *parent, struct driver *drv,
+int device_bind(struct udevice *parent, const struct driver *drv,
 		const char *name, void *platdata, int of_offset,
 		struct udevice **devp);
 
include/dm/device.h +1 -1
index f27b34b..fafecce 100644
@@ -70,7 +70,7 @@ struct driver_info;
  * when the device is probed and will be unique within the device's uclass.
  */
 struct udevice {
-	struct driver *driver;
+	const struct driver *driver;
 	const char *name;
 	void *platdata;
 	void *parent_platdata;
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#12 lore raw

PATCH v2 6/80 dm: core: Convert driver_bind() to use const

Quoted 6 lines · Simon Glass

The driver is not modified by driver model, so update driver_bind() to recognise that.

---

Quoted 7 lines

Changes in v2: None

 drivers/core/device-remove.c | 4 ++--
 drivers/core/device.c        | 7 ++++---
 include/dm/device-internal.h | 2 +-
 include/dm/device.h          | 2 +-
 4 files changed, 8 insertions(+), 7 deletions(-)

Applied to u-boot-dm/next.

#13 lore raw

PATCH v2 7/80 dm: core: Rename driver data function to dev_get_driver_data()

In reply to Simon Glass

The existing get_get_of_data() function provides access to both the driver's compatible string and its driver data. However only the latter is actually useful. Update the interface to reflect this and fix up existing users.

---

Changes in v2: None

 drivers/core/device.c     |  4 ++--
 drivers/core/lists.c      |  2 +-
 drivers/i2c/s3c24x0_i2c.c |  2 +-
 drivers/i2c/tegra_i2c.c   |  6 +++---
 include/dm/device.h       | 16 +++++++++++-----
 5 files changed, 18 insertions(+), 12 deletions(-)
drivers/core/device.c +2 -2
index f1a03d9..4fba118 100644
@@ -467,9 +467,9 @@ struct udevice *dev_get_parent(struct udevice *child)
 	return child->parent;
 }
 
-ulong dev_get_of_data(struct udevice *dev)
+ulong dev_get_driver_data(struct udevice *dev)
 {
-	return dev->of_id->data;
+	return dev->driver_data;
 }
 
 enum uclass_id device_get_uclass_id(struct udevice *dev)
drivers/core/lists.c +1 -1
index ff115c4..647e390 100644
@@ -168,7 +168,7 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset,
 			dm_warn("Error binding driver '%s'\n", entry->name);
 			return ret;
 		} else {
-			dev->of_id = id;
+			dev->driver_data = id->data;
 			found = true;
 			if (devp)
 				*devp = dev;
drivers/i2c/s3c24x0_i2c.c +1 -1
index b4ee33f..27ff587 100644
@@ -1348,7 +1348,7 @@ static int s3c_i2c_ofdata_to_platdata(struct udevice *dev)
 	struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
 	int node, flags;
 
-	i2c_bus->is_highspeed = dev->of_id->data;
+	i2c_bus->is_highspeed = dev_get_driver_data(dev);
 	node = dev->of_offset;
 
 	if (i2c_bus->is_highspeed) {
drivers/i2c/tegra_i2c.c +3 -3
index f414287..fc95646 100644
@@ -338,7 +338,7 @@ static int tegra_i2c_probe(struct udevice *dev)
 	bool is_dvc;
 
 	i2c_bus->id = dev->seq;
-	i2c_bus->type = dev_get_of_data(dev);
+	i2c_bus->type = dev_get_driver_data(dev);
 	i2c_bus->regs = (struct i2c_ctlr *)fdtdec_get_addr(blob, node, "reg");
 
 	/*
@@ -360,7 +360,7 @@ static int tegra_i2c_probe(struct udevice *dev)
 	if (i2c_bus->periph_id == -1)
 		return -EINVAL;
 
-	is_dvc = dev_get_of_data(dev) == TYPE_DVC;
+	is_dvc = dev_get_driver_data(dev) == TYPE_DVC;
 	if (is_dvc) {
 		i2c_bus->control =
 			&((struct dvc_ctlr *)i2c_bus->regs)->control;
@@ -469,7 +469,7 @@ int tegra_i2c_get_dvc_bus(struct udevice **busp)
 	for (uclass_first_device(UCLASS_I2C, &bus);
 	     bus;
 	     uclass_next_device(&bus)) {
-		if (dev_get_of_data(bus) == TYPE_DVC) {
+		if (dev_get_driver_data(bus) == TYPE_DVC) {
 			*busp = bus;
 			return 0;
 		}
include/dm/device.h +11 -5
index fafecce..ec22885 100644
@@ -55,7 +55,8 @@ struct driver_info;
  * @platdata: Configuration data for this device
  * @parent_platdata: The parent bus's configuration data for this device
  * @of_offset: Device tree node offset for this device (- for none)
- * @of_id: Pointer to the udevice_id structure which created the device
+ * @driver_data: Driver data word for the entry that matched this device with
+ *		its driver
  * @parent: Parent of this device, or NULL for the top level device
  * @priv: Private data for this device
  * @uclass: Pointer to uclass for this device
@@ -75,7 +76,7 @@ struct udevice {
 	void *platdata;
 	void *parent_platdata;
 	int of_offset;
-	const struct udevice_id *of_id;
+	ulong driver_data;
 	struct udevice *parent;
 	void *priv;
 	struct uclass *uclass;
@@ -251,13 +252,18 @@ struct udevice *dev_get_parent(struct udevice *child);
 void *dev_get_uclass_priv(struct udevice *dev);
 
 /**
- * dev_get_of_data() - get the device tree data used to bind a device
+ * dev_get_driver_data() - get the driver data used to bind a device
  *
  * When a device is bound using a device tree node, it matches a
  * particular compatible string as in struct udevice_id. This function
- * returns the associated data value for that compatible string
+ * returns the associated data value for that compatible string. This is
+ * the 'data' field in struct udevice_id.
+ *
+ * For USB devices, this is the driver_info field in struct usb_device_id.
+ *
+ * @dev:	Device to check
  */
-ulong dev_get_of_data(struct udevice *dev);
+ulong dev_get_driver_data(struct udevice *dev);
 
 /*
  * device_get_uclass_id() - return the uclass ID of a device
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#14 lore raw

PATCH v2 7/80 dm: core: Rename driver data function to dev_get_driver_data()

Quoted 7 lines · Simon Glass

The existing get_get_of_data() function provides access to both the driver's compatible string and its driver data. However only the latter is actually useful. Update the interface to reflect this and fix up existing users.

---

Quoted 8 lines

Changes in v2: None

 drivers/core/device.c     |  4 ++--
 drivers/core/lists.c      |  2 +-
 drivers/i2c/s3c24x0_i2c.c |  2 +-
 drivers/i2c/tegra_i2c.c   |  6 +++---
 include/dm/device.h       | 16 +++++++++++-----
 5 files changed, 18 insertions(+), 12 deletions(-)

Applied to u-boot-dm/next.

#15 lore raw

PATCH v2 8/80 dm: core: Mark device as active before calling uclass probe() methods

In reply to Simon Glass

The uclass pre-probe functions may end up calling back into the device in some circumstances. This can fail if recursion takes place. Adjust the ordering so that we mark the device as active early, then retract this later if needed.

---

Changes in v2: None

 drivers/core/device.c | 8 +++++---
 test/dm/test-uclass.c | 3 ++-
 2 files changed, 7 insertions(+), 4 deletions(-)
drivers/core/device.c +5 -3
index 4fba118..b7ed21c 100644
@@ -243,6 +243,8 @@ int device_probe_child(struct udevice *dev, void *parent_priv)
 	}
 	dev->seq = seq;
 
+	dev->flags |= DM_FLAG_ACTIVATED;
+
 	ret = uclass_pre_probe_device(dev);
 	if (ret)
 		goto fail;
@@ -269,10 +271,8 @@ int device_probe_child(struct udevice *dev, void *parent_priv)
 	}
 
 	ret = uclass_post_probe_device(dev);
-	if (ret) {
-		dev->flags &= ~DM_FLAG_ACTIVATED;
+	if (ret)
 		goto fail_uclass;
-	}
 
 	return 0;
 fail_uclass:
@@ -281,6 +281,8 @@ fail_uclass:
 			__func__, dev->name);
 	}
 fail:
+	dev->flags &= ~DM_FLAG_ACTIVATED;
+
 	dev->seq = -1;
 	device_free(dev);
 
test/dm/test-uclass.c +2 -1
index be91657..7cb37f7 100644
@@ -31,6 +31,7 @@ int test_ping(struct udevice *dev, int pingval, int *pingret)
 static int test_post_bind(struct udevice *dev)
 {
 	dm_testdrv_op_count[DM_TEST_OP_POST_BIND]++;
+	ut_assert(!device_active(dev));
 
 	return 0;
 }
@@ -48,7 +49,7 @@ static int test_pre_probe(struct udevice *dev)
 
 	dm_testdrv_op_count[DM_TEST_OP_PRE_PROBE]++;
 	ut_assert(priv);
-	ut_assert(!device_active(dev));
+	ut_assert(device_active(dev));
 
 	return 0;
 }
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#16 lore raw

PATCH v2 8/80 dm: core: Mark device as active before calling uclass probe() methods

Quoted 5 lines · Simon Glass

The uclass pre-probe functions may end up calling back into the device in some circumstances. This can fail if recursion takes place. Adjust the ordering so that we mark the device as active early, then retract this later if needed.

Quoted 8 lines

---

Changes in v2: None

 drivers/core/device.c | 8 +++++---
 test/dm/test-uclass.c | 3 ++-
 2 files changed, 7 insertions(+), 4 deletions(-)

Applied to u-boot-dm/next.

#17 lore raw

PATCH v2 9/80 dm: core: Add device children and sibling functions

In reply to Simon Glass

Add some utility functions to check for children and for the last sibling in a device's parent.

---

Changes in v2: None

 drivers/core/device.c | 28 ++++++++++++++++++++++++++++
 include/dm/device.h   | 30 ++++++++++++++++++++++++++++++
 2 files changed, 58 insertions(+)
drivers/core/device.c +28 -0
index b7ed21c..ccaa99c 100644
@@ -490,3 +490,31 @@ fdt_addr_t dev_get_addr(struct udevice *dev)
 	return FDT_ADDR_T_NONE;
 }
 #endif
+
+bool device_has_children(struct udevice *dev)
+{
+	return !list_empty(&dev->child_head);
+}
+
+bool device_has_active_children(struct udevice *dev)
+{
+	struct udevice *child;
+
+	for (device_find_first_child(dev, &child);
+	     child;
+	     device_find_next_child(&child)) {
+		if (device_active(child))
+			return true;
+	}
+
+	return false;
+}
+
+bool device_is_last_sibling(struct udevice *dev)
+{
+	struct udevice *parent = dev->parent;
+
+	if (!parent)
+		return false;
+	return list_is_last(&dev->sibling_node, &parent->child_head);
+}
include/dm/device.h +30 -0
index ec22885..c11342c 100644
@@ -380,4 +380,34 @@ int device_find_next_child(struct udevice **devp);
  */
 fdt_addr_t dev_get_addr(struct udevice *dev);
 
+/**
+ * device_has_children() - check if a device has any children
+ *
+ * @dev:	Device to check
+ * @return true if the device has one or more children
+ */
+bool device_has_children(struct udevice *dev);
+
+/**
+ * device_has_active_children() - check if a device has any active children
+ *
+ * @dev:	Device to check
+ * @return true if the device has one or more children and at least one of
+ * them is active (probed).
+ */
+bool device_has_active_children(struct udevice *dev);
+
+/**
+ * device_is_last_sibling() - check if a device is the last sibling
+ *
+ * This function can be useful for display purposes, when special action needs
+ * to be taken when displaying the last sibling. This can happen when a tree
+ * view of devices is being displayed.
+ *
+ * @dev:	Device to check
+ * @return true if there are no more siblings after this one - i.e. is it
+ * last in the list.
+ */
+bool device_is_last_sibling(struct udevice *dev);
+
 #endif
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#18 lore raw

PATCH v2 9/80 dm: core: Add device children and sibling functions

Quoted 11 lines · Simon Glass

Add some utility functions to check for children and for the last sibling in a device's parent.

---

Changes in v2: None

 drivers/core/device.c | 28 ++++++++++++++++++++++++++++
 include/dm/device.h   | 30 ++++++++++++++++++++++++++++++
 2 files changed, 58 insertions(+)

Applied to u-boot-dm/next.

#19 lore raw

PATCH v2 10/80 dm: gpio: Add an implementation for gpio_get_number()

In reply to Simon Glass

This has a prototype but no implementation. It returns the global GPIO number given a gpio_desc. It is useful for debugging in some cases.

---

Changes in v2: None

 drivers/gpio/gpio-uclass.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)
drivers/gpio/gpio-uclass.c +12 -0
index b6e1058..380366f 100644
@@ -689,6 +689,18 @@ static int gpio_renumber(struct udevice *removed_dev)
 	return 0;
 }
 
+int gpio_get_number(struct gpio_desc *desc)
+{
+	struct udevice *dev = desc->dev;
+	struct gpio_dev_priv *uc_priv;
+
+	if (!dev)
+		return -1;
+	uc_priv = dev->uclass_priv;
+
+	return uc_priv->gpio_base + desc->offset;
+}
+
 static int gpio_post_probe(struct udevice *dev)
 {
 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#20 lore raw

PATCH v2 10/80 dm: gpio: Add an implementation for gpio_get_number()

Quoted 10 lines · Simon Glass

This has a prototype but no implementation. It returns the global GPIO number given a gpio_desc. It is useful for debugging in some cases.

---

Changes in v2: None

 drivers/gpio/gpio-uclass.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

Applied to u-boot-dm/next.

#21 lore raw

PATCH v2 11/80 dm: usb: Add a uclass for USB controllers

In reply to Simon Glass

Add a uclass that can represent a USB controller. For now we do not create devices for things attached to the controller. This will be added later.

---

Changes in v2: None

 drivers/usb/Kconfig               |  14 ++
 drivers/usb/host/Makefile         |   4 +
 drivers/usb/host/usb-uclass.c     | 392 ++++++++++++++++++++++++++++++++++++++
 drivers/usb/musb-new/musb_uboot.c |   4 +-
 include/dm/uclass-id.h            |   1 +
 include/usb.h                     | 285 ++++++++++++++++++++++++++-
 6 files changed, 694 insertions(+), 6 deletions(-)
 create mode 100644 drivers/usb/host/usb-uclass.c
drivers/usb/Kconfig +14 -0
index b4a9442..a4414ef 100644
@@ -35,6 +35,20 @@ config USB
 
 if USB
 
+config DM_USB
+	bool "Enable driver model for USB"
+	depends on USB && DM
+	help
+	  Enable driver model for USB. The USB interface is then implemented
+	  by the USB uclass. Multiple USB controllers of different types
+	  (XHCI, EHCI) can be attached and used. The 'usb' command works as
+	  normal. OCHI is not supported at present.
+
+	  Much of the code is shared but with this option enabled the USB
+	  uclass takes care of device enumeration. USB devices can be
+	  declared with the USB_DEVICE() macro and will be automatically
+	  probed when found on the bus.
+
 source "drivers/usb/host/Kconfig"
 
 config USB_STORAGE
drivers/usb/host/Makefile +4 -0
index eb6f34b..9419295 100644
@@ -5,6 +5,10 @@
 # SPDX-License-Identifier:	GPL-2.0+
 #
 
+ifdef CONFIG_DM_USB
+obj-$(CONFIG_CMD_USB) += usb-uclass.o
+endif
+
 # ohci
 obj-$(CONFIG_USB_OHCI_NEW) += ohci-hcd.o
 obj-$(CONFIG_USB_ATMEL) += ohci-at91.o
drivers/usb/host/usb-uclass.c new file +392 -0

392 lines not on this page · raw message

drivers/usb/musb-new/musb_uboot.c +3 -1
index 6e58ddf..f42db59 100644
@@ -177,7 +177,7 @@ void *poll_int_queue(struct usb_device *dev, struct int_queue *queue)
 	return NULL; /* URB still pending */
 }
 
-void usb_reset_root_port(void)
+int usb_reset_root_port(void)
 {
 	void *mbase = host->mregs;
 	u8 power;
@@ -194,6 +194,8 @@ void usb_reset_root_port(void)
 			(musb_readb(mbase, MUSB_DEVCTL) & MUSB_DEVCTL_FSDEV) ?
 			USB_SPEED_FULL : USB_SPEED_LOW;
 	mdelay((host_speed == USB_SPEED_LOW) ? 200 : 50);
+
+	return 0;
 }
 
 int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
include/dm/uclass-id.h +1 -0
index 84a6955..cb6d2e5 100644
@@ -39,6 +39,7 @@ enum uclass_id {
 	UCLASS_PCI_GENERIC,	/* Generic PCI bus device */
 	UCLASS_PCH,		/* x86 platform controller hub */
 	UCLASS_ETH,		/* Ethernet device */
+	UCLASS_USB,		/* USB bus */
 
 	UCLASS_COUNT,
 	UCLASS_INVALID = -1,
include/usb.h +280 -5

332 lines not on this page · raw message

Signature · 1 line
2.2.0.rc0.207.ga3a616c
#22 lore raw

PATCH v2 11/80 dm: usb: Add a uclass for USB controllers

Quoted 8 lines · Simon Glass

Add a uclass that can represent a USB controller. For now we do not create devices for things attached to the controller. This will be added later.

---

Changes in v2: None

Quoted 8 lines
 drivers/usb/Kconfig               |  14 ++
 drivers/usb/host/Makefile         |   4 +
 drivers/usb/host/usb-uclass.c     | 392 ++++++++++++++++++++++++++++++++++++++
 drivers/usb/musb-new/musb_uboot.c |   4 +-
 include/dm/uclass-id.h            |   1 +
 include/usb.h                     | 285 ++++++++++++++++++++++++++-
 6 files changed, 694 insertions(+), 6 deletions(-)
 create mode 100644 drivers/usb/host/usb-uclass.c

Applied to u-boot-dm/next.

#23 lore raw

PATCH v2 12/80 dm: usb: Adjust usb command to prepare for driver model

In reply to Simon Glass

Use 'udev' instead of 'dev' in a few places, reserving 'dev' for driver model's struct udevice. Also adjust the code in a few minor ways to make it easier to plumb in driver model.

---

Changes in v2: None

 common/cmd_usb.c | 51 +++++++++++++++++++++++++--------------------------
 1 file changed, 25 insertions(+), 26 deletions(-)
common/cmd_usb.c +25 -26
index 27813f0..085802b 100644
@@ -254,15 +254,15 @@ static void usb_display_config(struct usb_device *dev)
 
 static struct usb_device *usb_find_device(int devnum)
 {
-	struct usb_device *dev;
+	struct usb_device *udev;
 	int d;
 
 	for (d = 0; d < USB_MAX_DEVICE; d++) {
-		dev = usb_get_dev_index(d);
-		if (dev == NULL)
+		udev = usb_get_dev_index(d);
+		if (udev == NULL)
 			return NULL;
-		if (dev->devnum == devnum)
-			return dev;
+		if (udev->devnum == devnum)
+			return udev;
 	}
 
 	return NULL;
@@ -305,8 +305,8 @@ static void usb_show_tree_graph(struct usb_device *dev, char *pre)
 			has_child = 1;
 	}
 	/* check if we are the last one */
-	last_child = 1;
-	if (dev->parent != NULL) {
+	last_child = (dev->parent != NULL);
+	if (last_child) {
 		for (i = 0; i < dev->parent->maxchild; i++) {
 			/* search for children */
 			if (dev->parent->children[i] == dev) {
@@ -324,7 +324,7 @@ static void usb_show_tree_graph(struct usb_device *dev, char *pre)
 		} /* for all children of the parent */
 		printf("\b+-");
 		/* correct last child */
-		if (last_child)
+		if (last_child && index)
 			pre[index-1] = ' ';
 	} /* if not root hub */
 	else
@@ -355,7 +355,7 @@ static void usb_show_tree(struct usb_device *dev)
 {
 	char preamble[32];
 
-	memset(preamble, 0, 32);
+	memset(preamble, '\0', sizeof(preamble));
 	usb_show_tree_graph(dev, &preamble[0]);
 }
 
@@ -466,9 +466,8 @@ static void do_usb_start(void)
  */
 static int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
-
+	struct usb_device *udev = NULL;
 	int i;
-	struct usb_device *dev = NULL;
 	extern char usb_started;
 #ifdef CONFIG_USB_STORAGE
 	block_dev_desc_t *stor_dev;
@@ -509,11 +508,11 @@ static int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	if (strncmp(argv[1], "tree", 4) == 0) {
 		puts("USB device tree:\n");
 		for (i = 0; i < USB_MAX_DEVICE; i++) {
-			dev = usb_get_dev_index(i);
-			if (dev == NULL)
+			udev = usb_get_dev_index(i);
+			if (udev == NULL)
 				break;
-			if (dev->parent == NULL)
-				usb_show_tree(dev);
+			if (udev->parent == NULL)
+				usb_show_tree(udev);
 		}
 		return 0;
 	}
@@ -521,23 +520,23 @@ static int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		int d;
 		if (argc == 2) {
 			for (d = 0; d < USB_MAX_DEVICE; d++) {
-				dev = usb_get_dev_index(d);
-				if (dev == NULL)
+				udev = usb_get_dev_index(d);
+				if (udev == NULL)
 					break;
-				usb_display_desc(dev);
-				usb_display_config(dev);
+				usb_display_desc(udev);
+				usb_display_config(udev);
 			}
 			return 0;
 		} else {
 			i = simple_strtoul(argv[2], NULL, 10);
 			printf("config for device %d\n", i);
-			dev = usb_find_device(i);
-			if (dev == NULL) {
+			udev = usb_find_device(i);
+			if (udev == NULL) {
 				printf("*** No device available ***\n");
 				return 0;
 			} else {
-				usb_display_desc(dev);
-				usb_display_config(dev);
+				usb_display_desc(udev);
+				usb_display_config(udev);
 			}
 		}
 		return 0;
@@ -546,13 +545,13 @@ static int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		if (argc < 5)
 			return CMD_RET_USAGE;
 		i = simple_strtoul(argv[2], NULL, 10);
-		dev = usb_find_device(i);
-		if (dev == NULL) {
+		udev = usb_find_device(i);
+		if (udev == NULL) {
 			printf("Device %d does not exist.\n", i);
 			return 1;
 		}
 		i = simple_strtoul(argv[3], NULL, 10);
-		return usb_test(dev, i, argv[4]);
+		return usb_test(udev, i, argv[4]);
 	}
 #ifdef CONFIG_USB_STORAGE
 	if (strncmp(argv[1], "stor", 4) == 0)
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#24 lore raw

PATCH v2 12/80 dm: usb: Adjust usb command to prepare for driver model

Quoted 11 lines · Simon Glass

Use 'udev' instead of 'dev' in a few places, reserving 'dev' for driver model's struct udevice. Also adjust the code in a few minor ways to make it easier to plumb in driver model.

---

Changes in v2: None

 common/cmd_usb.c | 51 +++++++++++++++++++++++++--------------------------
 1 file changed, 25 insertions(+), 26 deletions(-)

Applied to u-boot-dm/next.

#25 lore raw

PATCH v2 13/80 dm: usb: Adjust usb_alloc_new_device() to return an error

In reply to Simon Glass

This function returns NULL on error at present. Adjust it so that we can return a real error, as is needed with driver model. Also improve the error handling in its caller, usb_hub_port_connect_change(), and adjust the code order to prepare for driver model.

---

Changes in v2: None

 common/usb.c     | 17 ++++++++---------
 common/usb_hub.c | 41 ++++++++++++++++++++++++++---------------
 include/usb.h    | 20 ++++++++++++++++++--
 3 files changed, 52 insertions(+), 26 deletions(-)
common/usb.c +8 -9
index 32e15cd..f87c6a5 100644
@@ -94,12 +94,12 @@ int usb_init(void)
 		controllers_initialized++;
 		start_index = dev_index;
 		printf("scanning bus %d for devices... ", i);
-		dev = usb_alloc_new_device(ctrl);
+		ret = usb_alloc_new_device(ctrl, &dev);
 		/*
 		 * device 0 is always present
 		 * (root hub, so let it analyze)
 		 */
-		if (dev)
+		if (!ret)
 			usb_new_device(dev);
 
 		if (start_index == dev_index)
@@ -827,16 +827,13 @@ struct usb_device *usb_get_dev_index(int index)
 		return &usb_dev[index];
 }
 
-/* returns a pointer of a new device structure or NULL, if
- * no device struct is available
- */
-struct usb_device *usb_alloc_new_device(void *controller)
+int usb_alloc_new_device(struct udevice *controller, struct usb_device **devp)
 {
 	int i;
 	debug("New Device %d\n", dev_index);
 	if (dev_index == USB_MAX_DEVICE) {
 		printf("ERROR, too many USB Devices, max=%d\n", USB_MAX_DEVICE);
-		return NULL;
+		return -ENOSPC;
 	}
 	/* default Address is 0, real addresses start with 1 */
 	usb_dev[dev_index].devnum = dev_index + 1;
@@ -846,7 +843,9 @@ struct usb_device *usb_alloc_new_device(void *controller)
 	usb_dev[dev_index].parent = NULL;
 	usb_dev[dev_index].controller = controller;
 	dev_index++;
-	return &usb_dev[dev_index - 1];
+	*devp = &usb_dev[dev_index - 1];
+
+	return 0;
 }
 
 /*
@@ -854,7 +853,7 @@ struct usb_device *usb_alloc_new_device(void *controller)
  * Called in error cases where configuring a newly attached
  * device fails for some reason.
  */
-void usb_free_device(void)
+void usb_free_device(struct udevice *controller)
 {
 	dev_index--;
 	debug("Freeing device node: %d\n", dev_index);
common/usb_hub.c +26 -15

95 lines not on this page · raw message

include/usb.h +18 -2
index 0e1c16a..11ff5ab 100644
@@ -703,10 +703,26 @@ void usb_hub_reset(void);
 int hub_port_reset(struct usb_device *dev, int port,
 			  unsigned short *portstat);
 
-struct usb_device *usb_alloc_new_device(void *controller);
+/**
+ * usb_alloc_new_device() - Allocate a new device
+ *
+ * @devp: returns a pointer of a new device structure. With driver model this
+ *		is a device pointer, but with legacy USB this pointer is
+ *		driver-specific.
+ * @return 0 if OK, -ENOSPC if we have found out of room for new devices
+ */
+int usb_alloc_new_device(struct udevice *controller, struct usb_device **devp);
+
+/**
+ * usb_free_device() - Free a partially-inited device
+ *
+ * This is an internal function. It is used to reverse the action of
+ * usb_alloc_new_device() when we hit a problem during init.
+ */
+void usb_free_device(struct udevice *controller);
 
 int usb_new_device(struct usb_device *dev);
-void usb_free_device(void);
+
 int usb_alloc_device(struct usb_device *dev);
 
 #endif /*_USB_H_ */
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#26 lore raw

PATCH v2 13/80 dm: usb: Adjust usb_alloc_new_device() to return an error

Quoted 6 lines · Simon Glass

This function returns NULL on error at present. Adjust it so that we can return a real error, as is needed with driver model. Also improve the error handling in its caller, usb_hub_port_connect_change(), and adjust the code order to prepare for driver model.

Quoted 8 lines

---

Changes in v2: None

 common/usb.c     | 17 ++++++++---------
 common/usb_hub.c | 41 ++++++++++++++++++++++++++---------------
 include/usb.h    | 20 ++++++++++++++++++--
 3 files changed, 52 insertions(+), 26 deletions(-)

Applied to u-boot-dm/next.

#27 lore raw

PATCH v2 14/80 dm: usb: Convert 'usb' command to support driver model

In reply to Simon Glass

Adjust this command to work with the new driver model uclass. It needs to iterate through multiple independent controllers to find hubs, and work through their children recursively in a different way. Otherwise the functionality is much the same.

---

Changes in v2: None

 common/cmd_usb.c | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 145 insertions(+), 2 deletions(-)
common/cmd_usb.c +145 -2
index 085802b..eab55cd 100644
@@ -2,6 +2,9 @@
  * (C) Copyright 2001
  * Denis Peter, MPL AG Switzerland
  *
+ * Adapted for U-Boot driver model
+ * (C) Copyright 2015 Google, Inc
+ *
  * Most of this source has been derived from the Linux USB
  * project.
  *
@@ -10,6 +13,7 @@
 
 #include <common.h>
 #include <command.h>
+#include <dm.h>
 #include <asm/byteorder.h>
 #include <asm/unaligned.h>
 #include <part.h>
@@ -252,8 +256,46 @@ static void usb_display_config(struct usb_device *dev)
 	printf("\n");
 }
 
+/*
+ * With driver model this isn't right since we can have multiple controllers
+ * and the device numbering starts at 1 on each bus.
+ * TODO(sjg at chromium.org): Add a way to specify the controller/bus.
+ */
 static struct usb_device *usb_find_device(int devnum)
 {
+#ifdef CONFIG_DM_USB
+	struct usb_device *udev;
+	struct udevice *hub;
+	struct uclass *uc;
+	int ret;
+
+	/* Device addresses start at 1 */
+	devnum++;
+	ret = uclass_get(UCLASS_USB_HUB, &uc);
+	if (ret)
+		return NULL;
+
+	uclass_foreach_dev(hub, uc) {
+		struct udevice *dev;
+
+		if (!device_active(hub))
+			continue;
+		udev = dev_get_parentdata(hub);
+		if (udev->devnum == devnum)
+			return udev;
+
+		for (device_find_first_child(hub, &dev);
+		     dev;
+		     device_find_next_child(&dev)) {
+			if (!device_active(hub))
+				continue;
+
+			udev = dev_get_parentdata(dev);
+			if (udev->devnum == devnum)
+				return udev;
+		}
+	}
+#else
 	struct usb_device *udev;
 	int d;
 
@@ -264,6 +306,7 @@ static struct usb_device *usb_find_device(int devnum)
 		if (udev->devnum == devnum)
 			return udev;
 	}
+#endif
 
 	return NULL;
 }
@@ -293,20 +336,31 @@ static inline char *portspeed(int speed)
 /* shows the device tree recursively */
 static void usb_show_tree_graph(struct usb_device *dev, char *pre)
 {
-	int i, index;
+	int index;
 	int has_child, last_child;
 
 	index = strlen(pre);
 	printf(" %s", pre);
+#ifdef CONFIG_DM_USB
+	has_child = device_has_active_children(dev->dev);
+#else
 	/* check if the device has connected children */
+	int i;
+
 	has_child = 0;
 	for (i = 0; i < dev->maxchild; i++) {
 		if (dev->children[i] != NULL)
 			has_child = 1;
 	}
+#endif
 	/* check if we are the last one */
+#ifdef CONFIG_DM_USB
+	last_child = device_is_last_sibling(dev->dev);
+#else
 	last_child = (dev->parent != NULL);
+#endif
 	if (last_child) {
+#ifndef CONFIG_DM_USB
 		for (i = 0; i < dev->parent->maxchild; i++) {
 			/* search for children */
 			if (dev->parent->children[i] == dev) {
@@ -322,6 +376,7 @@ static void usb_show_tree_graph(struct usb_device *dev, char *pre)
 				} /* while */
 			} /* device found */
 		} /* for all children of the parent */
+#endif
 		printf("\b+-");
 		/* correct last child */
 		if (last_child && index)
@@ -340,6 +395,26 @@ static void usb_show_tree_graph(struct usb_device *dev, char *pre)
 	if (strlen(dev->mf) || strlen(dev->prod) || strlen(dev->serial))
 		printf(" %s  %s %s %s\n", pre, dev->mf, dev->prod, dev->serial);
 	printf(" %s\n", pre);
+#ifdef CONFIG_DM_USB
+	struct udevice *child;
+
+	for (device_find_first_child(dev->dev, &child);
+	     child;
+	     device_find_next_child(&child)) {
+		struct usb_device *udev;
+
+		if (!device_active(child))
+			continue;
+
+		udev = dev_get_parentdata(child);
+
+		/* Ignore emulators, we only want real devices */
+		if (device_get_uclass_id(child) != UCLASS_USB_EMUL) {
+			usb_show_tree_graph(udev, pre);
+			pre[index] = 0;
+		}
+	}
+#else
 	if (dev->maxchild > 0) {
 		for (i = 0; i < dev->maxchild; i++) {
 			if (dev->children[i] != NULL) {
@@ -348,6 +423,7 @@ static void usb_show_tree_graph(struct usb_device *dev, char *pre)
 			}
 		}
 	}
+#endif
 }
 
 /* main routine for the tree command */
@@ -448,10 +524,13 @@ static void do_usb_start(void)
 	if (usb_init() < 0)
 		return;
 
+	/* Driver model will probe the devices as they are found */
+#ifndef CONFIG_DM_USB
 #ifdef CONFIG_USB_STORAGE
 	/* try to recognize storage devices immediately */
 	usb_stor_curr_dev = usb_stor_scan(1);
 #endif
+#endif
 #ifdef CONFIG_USB_HOST_ETHER
 	/* try to recognize ethernet devices immediately */
 	usb_ether_curr_dev = usb_host_eth_scan(1);
@@ -461,6 +540,43 @@ static void do_usb_start(void)
 #endif
 }
 
+#ifdef CONFIG_DM_USB
+static void show_info(struct udevice *dev)
+{
+	struct udevice *child;
+	struct usb_device *udev;
+
+	udev = dev_get_parentdata(dev);
+	usb_display_desc(udev);
+	usb_display_config(udev);
+	for (device_find_first_child(dev, &child);
+	     child;
+	     device_find_next_child(&child)) {
+		if (device_active(child))
+			show_info(child);
+	}
+}
+
+static int usb_device_info(void)
+{
+	struct udevice *bus;
+
+	for (uclass_first_device(UCLASS_USB, &bus);
+	     bus;
+	     uclass_next_device(&bus)) {
+		struct udevice *hub;
+
+		device_find_first_child(bus, &hub);
+		if (device_get_uclass_id(hub) == UCLASS_USB_HUB &&
+		    device_active(hub)) {
+			show_info(hub);
+		}
+	}
+
+	return 0;
+}
+#endif
+
 /******************************************************************************
  * usb command intepreter
  */
@@ -507,6 +623,23 @@ static int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	}
 	if (strncmp(argv[1], "tree", 4) == 0) {
 		puts("USB device tree:\n");
+#ifdef CONFIG_DM_USB
+		struct udevice *bus;
+
+		for (uclass_first_device(UCLASS_USB, &bus);
+		     bus;
+		     uclass_next_device(&bus)) {
+			struct usb_device *udev;
+			struct udevice *hub;
+
+			device_find_first_child(bus, &hub);
+			if (device_get_uclass_id(hub) == UCLASS_USB_HUB &&
+			    device_active(hub)) {
+				udev = dev_get_parentdata(hub);
+				usb_show_tree(udev);
+			}
+		}
+#else
 		for (i = 0; i < USB_MAX_DEVICE; i++) {
 			udev = usb_get_dev_index(i);
 			if (udev == NULL)
@@ -514,11 +647,15 @@ static int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 			if (udev->parent == NULL)
 				usb_show_tree(udev);
 		}
+#endif
 		return 0;
 	}
 	if (strncmp(argv[1], "inf", 3) == 0) {
-		int d;
 		if (argc == 2) {
+#ifdef CONFIG_DM_USB
+			usb_device_info();
+#else
+			int d;
 			for (d = 0; d < USB_MAX_DEVICE; d++) {
 				udev = usb_get_dev_index(d);
 				if (udev == NULL)
@@ -526,8 +663,14 @@ static int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 				usb_display_desc(udev);
 				usb_display_config(udev);
 			}
+#endif
 			return 0;
 		} else {
+			/*
+			 * With driver model this isn't right since we can
+			 * have multiple controllers and the device numbering
+			 * starts@1 on each bus.
+			 */
 			i = simple_strtoul(argv[2], NULL, 10);
 			printf("config for device %d\n", i);
 			udev = usb_find_device(i);
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#28 lore raw

PATCH v2 14/80 dm: usb: Convert 'usb' command to support driver model

Quoted 5 lines · Simon Glass

Adjust this command to work with the new driver model uclass. It needs to iterate through multiple independent controllers to find hubs, and work through their children recursively in a different way. Otherwise the functionality is much the same.

Quoted 7 lines

---

Changes in v2: None

 common/cmd_usb.c | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 145 insertions(+), 2 deletions(-)

Applied to u-boot-dm/next.

#29 lore raw

PATCH v2 15/80 dm: usb: Drop the legacy USB init sequence

In reply to Simon Glass

This CONFIG is not used anywhere in U-Boot, so drop it.

---

Changes in v2: None

 common/usb.c | 26 ++++----------------------
 1 file changed, 4 insertions(+), 22 deletions(-)
common/usb.c +4 -22
index f87c6a5..330e6a2 100644
@@ -899,26 +899,8 @@ int usb_new_device(struct usb_device *dev)
 	addr = dev->devnum;
 	dev->devnum = 0;
 
-#ifdef CONFIG_LEGACY_USB_INIT_SEQ
-	/* this is the old and known way of initializing devices, it is
-	 * different than what Windows and Linux are doing. Windows and Linux
-	 * both retrieve 64 bytes while reading the device descriptor
-	 * Several USB stick devices report ERR: CTL_TIMEOUT, caused by an
-	 * invalid header while reading 8 bytes as device descriptor. */
-	dev->descriptor.bMaxPacketSize0 = 8;	    /* Start off at 8 bytes  */
-	dev->maxpacketsize = PACKET_SIZE_8;
-	dev->epmaxpacketin[0] = 8;
-	dev->epmaxpacketout[0] = 8;
-
-	err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, tmpbuf, 8);
-	if (err < 8) {
-		printf("\n      USB device not responding, " \
-		       "giving up (status=%lX)\n", dev->status);
-		return 1;
-	}
-	memcpy(&dev->descriptor, tmpbuf, 8);
-#else
-	/* This is a Windows scheme of initialization sequence, with double
+	/*
+	 * This is a Windows scheme of initialization sequence, with double
 	 * reset of the device (Linux uses the same sequence)
 	 * Some equipment is said to work only with such init sequence; this
 	 * patch is based on the work by Alan Stern:
@@ -929,7 +911,8 @@ int usb_new_device(struct usb_device *dev)
 	struct usb_device *parent = dev->parent;
 	unsigned short portstatus;
 
-	/* send 64-byte GET-DEVICE-DESCRIPTOR request.  Since the descriptor is
+	/*
+	 * send 64-byte GET-DEVICE-DESCRIPTOR request.  Since the descriptor is
 	 * only 18 bytes long, this will terminate with a short packet.  But if
 	 * the maxpacket size is 8 or 16 the device may be waiting to transmit
 	 * some more, or keeps on retransmitting the 8 byte header. */
@@ -972,7 +955,6 @@ int usb_new_device(struct usb_device *dev)
 	} else {
 		usb_reset_root_port();
 	}
-#endif
 
 	dev->epmaxpacketin[0] = dev->descriptor.bMaxPacketSize0;
 	dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#32 lore raw

PATCH v2 16/80 dm: usb: Refactor port resets

In reply to Simon Glass

Move the port reset code into its own function. Rename usb_hub_reset() to indicate that is is now a legacy function.

---

Changes in v2: None

 common/usb.c     | 40 ++++++++++++++++++++++++++--------------
 common/usb_hub.c |  4 ++--
 include/usb.h    | 18 +++++++++++++++++-
 3 files changed, 45 insertions(+), 17 deletions(-)
common/usb.c +26 -14
index 330e6a2..4ab2213 100644
@@ -871,6 +871,26 @@ __weak int usb_alloc_device(struct usb_device *udev)
 {
 	return 0;
 }
+
+int usb_legacy_port_reset(struct usb_device *hub, int portnr)
+{
+	if (hub) {
+		unsigned short portstatus;
+		int err;
+
+		/* reset the port for the second time */
+		err = legacy_hub_port_reset(hub, portnr - 1, &portstatus);
+		if (err < 0) {
+			printf("\n     Couldn't reset port %i\n", portnr);
+			return err;
+		}
+	} else {
+		usb_reset_root_port();
+	}
+
+	return 0;
+}
+
 /*
  * By the time we get here, the device has gotten a new device ID
  * and is in the default state. We need to identify the thing and
@@ -907,9 +927,6 @@ int usb_new_device(struct usb_device *dev)
 	 * http://sourceforge.net/mailarchive/forum.php?
 	 * thread_id=5729457&forum_id=5398
 	 */
-	__maybe_unused struct usb_device_descriptor *desc;
-	struct usb_device *parent = dev->parent;
-	unsigned short portstatus;
 
 	/*
 	 * send 64-byte GET-DEVICE-DESCRIPTOR request.  Since the descriptor is
@@ -917,7 +934,6 @@ int usb_new_device(struct usb_device *dev)
 	 * the maxpacket size is 8 or 16 the device may be waiting to transmit
 	 * some more, or keeps on retransmitting the 8 byte header. */
 
-	desc = (struct usb_device_descriptor *)tmpbuf;
 	dev->descriptor.bMaxPacketSize0 = 64;	    /* Start off at 64 bytes  */
 	/* Default to 64 byte max packet size */
 	dev->maxpacketsize = PACKET_SIZE_64;
@@ -931,6 +947,9 @@ int usb_new_device(struct usb_device *dev)
 	 * of that is done for XHCI unlike EHCI.
 	 */
 #ifndef CONFIG_USB_XHCI
+	struct usb_device_descriptor *desc;
+
+	desc = (struct usb_device_descriptor *)tmpbuf;
 	err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, 64);
 	if (err < 0) {
 		debug("usb_new_device: usb_get_descriptor() failed\n");
@@ -945,16 +964,9 @@ int usb_new_device(struct usb_device *dev)
 	dev->descriptor.bDeviceClass = desc->bDeviceClass;
 #endif
 
-	if (parent) {
-		/* reset the port for the second time */
-		err = hub_port_reset(dev->parent, dev->portnr - 1, &portstatus);
-		if (err < 0) {
-			printf("\n     Couldn't reset port %i\n", dev->portnr);
-			return 1;
-		}
-	} else {
-		usb_reset_root_port();
-	}
+	err = usb_legacy_port_reset(dev->parent, dev->portnr);
+	if (err)
+		return err;
 
 	dev->epmaxpacketin[0] = dev->descriptor.bMaxPacketSize0;
 	dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
common/usb_hub.c +2 -2
index 7199e25..49fa5a6 100644
@@ -141,7 +141,7 @@ static inline char *portspeed(int portstatus)
 	return speed_str;
 }
 
-int hub_port_reset(struct usb_device *dev, int port,
+int legacy_hub_port_reset(struct usb_device *dev, int port,
 			unsigned short *portstat)
 {
 	int tries;
@@ -241,7 +241,7 @@ int usb_hub_port_connect_change(struct usb_device *dev, int port)
 	mdelay(200);
 
 	/* Reset the port */
-	ret = hub_port_reset(dev, port, &portstatus);
+	ret = legacy_hub_port_reset(dev, port, &portstatus);
 	if (ret < 0) {
 		printf("cannot reset port %i!?\n", port + 1);
 		return ret;
include/usb.h +17 -1
index 11ff5ab..badb287 100644
@@ -700,9 +700,25 @@ bool usb_device_has_child_on_port(struct usb_device *parent, int port);
 
 int usb_hub_probe(struct usb_device *dev, int ifnum);
 void usb_hub_reset(void);
-int hub_port_reset(struct usb_device *dev, int port,
+
+/**
+ * legacy_hub_port_reset() - reset a port given its usb_device pointer
+ *
+ * Reset a hub port and see if a device is present on that port, providing
+ * sufficient time for it to show itself. The port status is returned.
+ *
+ * With driver model this moves to hub_port_reset() and is passed a struct
+ * udevice.
+ *
+ * @dev:	USB device to reset
+ * @port:	Port number to reset (note ports are numbered from 0 here)
+ * @portstat:	Returns port status
+ */
+int legacy_hub_port_reset(struct usb_device *dev, int port,
 			  unsigned short *portstat);
 
+int hub_port_reset(struct udevice *dev, int port, unsigned short *portstat);
+
 /**
  * usb_alloc_new_device() - Allocate a new device
  *
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#33 lore raw

PATCH v2 16/80 dm: usb: Refactor port resets

Quoted 4 lines · Simon Glass

Move the port reset code into its own function. Rename usb_hub_reset() to indicate that is is now a legacy function.

Quoted 8 lines

---

Changes in v2: None

 common/usb.c     | 40 ++++++++++++++++++++++++++--------------
 common/usb_hub.c |  4 ++--
 include/usb.h    | 18 +++++++++++++++++-
 3 files changed, 45 insertions(+), 17 deletions(-)

Applied to u-boot-dm/next.

#34 lore raw

PATCH v2 17/80 dm: usb: Move descriptor setup code into its own function

In reply to Simon Glass

usb_new_device() is far too long and does far too much. As a first step, move the code that does initial setup and reads a descriptor into its own function called usb_setup_descriptor().

For XHCI the init order is different - we set up the device but don't actually read the descriptor until after we set an address. Support this option as a parameter to usb_setup_descriptor().

Avoid changing this torturous code more than necessary to make it easy to review.

---

Changes in v2: None

 common/usb.c | 117 ++++++++++++++++++++++++++++++++++-------------------------
 1 file changed, 67 insertions(+), 50 deletions(-)
common/usb.c +67 -50
index 4ab2213..d0debbc 100644
@@ -891,35 +891,12 @@ int usb_legacy_port_reset(struct usb_device *hub, int portnr)
 	return 0;
 }
 
-/*
- * By the time we get here, the device has gotten a new device ID
- * and is in the default state. We need to identify the thing and
- * get the ball rolling..
- *
- * Returns 0 for success, != 0 for error.
- */
-int usb_new_device(struct usb_device *dev)
+static int usb_setup_descriptor(struct usb_device *dev, bool do_read)
 {
-	int addr, err;
-	int tmp;
+	__maybe_unused struct usb_device_descriptor *desc;
 	ALLOC_CACHE_ALIGN_BUFFER(unsigned char, tmpbuf, USB_BUFSIZ);
 
 	/*
-	 * Allocate usb 3.0 device context.
-	 * USB 3.0 (xHCI) protocol tries to allocate device slot
-	 * and related data structures first. This call does that.
-	 * Refer to sec 4.3.2 in xHCI spec rev1.0
-	 */
-	if (usb_alloc_device(dev)) {
-		printf("Cannot allocate device context to get SLOT_ID\n");
-		return -1;
-	}
-
-	/* We still haven't set the Address yet */
-	addr = dev->devnum;
-	dev->devnum = 0;
-
-	/*
 	 * This is a Windows scheme of initialization sequence, with double
 	 * reset of the device (Linux uses the same sequence)
 	 * Some equipment is said to work only with such init sequence; this
@@ -934,40 +911,31 @@ int usb_new_device(struct usb_device *dev)
 	 * the maxpacket size is 8 or 16 the device may be waiting to transmit
 	 * some more, or keeps on retransmitting the 8 byte header. */
 
+	desc = (struct usb_device_descriptor *)tmpbuf;
 	dev->descriptor.bMaxPacketSize0 = 64;	    /* Start off at 64 bytes  */
 	/* Default to 64 byte max packet size */
 	dev->maxpacketsize = PACKET_SIZE_64;
 	dev->epmaxpacketin[0] = 64;
 	dev->epmaxpacketout[0] = 64;
 
-	/*
-	 * 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.
-	 */
-#ifndef CONFIG_USB_XHCI
-	struct usb_device_descriptor *desc;
+	if (do_read) {
+		int err;
 
-	desc = (struct usb_device_descriptor *)tmpbuf;
-	err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, 64);
-	if (err < 0) {
-		debug("usb_new_device: usb_get_descriptor() failed\n");
-		return 1;
+		err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, 64);
+		if (err < sizeof(dev->descriptor)) {
+			if (err < 0) {
+				printf("unable to get device descriptor (error=%d)\n",
+				       err);
+				return err;
+			} else {
+				printf("USB device descriptor short read (expected %i, got %i)\n",
+				       (int)sizeof(dev->descriptor), err);
+				return -EIO;
+			}
+		}
+		memcpy(&dev->descriptor, tmpbuf, sizeof(dev->descriptor));
 	}
 
-	dev->descriptor.bMaxPacketSize0 = desc->bMaxPacketSize0;
-	/*
-	 * Fetch the device class, driver can use this info
-	 * to differentiate between HUB and DEVICE.
-	 */
-	dev->descriptor.bDeviceClass = desc->bDeviceClass;
-#endif
-
-	err = usb_legacy_port_reset(dev->parent, dev->portnr);
-	if (err)
-		return err;
-
 	dev->epmaxpacketin[0] = dev->descriptor.bMaxPacketSize0;
 	dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
 	switch (dev->descriptor.bMaxPacketSize0) {
@@ -984,6 +952,55 @@ int usb_new_device(struct usb_device *dev)
 		dev->maxpacketsize = PACKET_SIZE_64;
 		break;
 	}
+
+	return 0;
+}
+
+/*
+ * By the time we get here, the device has gotten a new device ID
+ * and is in the default state. We need to identify the thing and
+ * get the ball rolling..
+ *
+ * Returns 0 for success, != 0 for error.
+ */
+int usb_new_device(struct usb_device *dev)
+{
+	bool do_read = true;
+	int addr, err;
+	int tmp;
+	ALLOC_CACHE_ALIGN_BUFFER(unsigned char, tmpbuf, USB_BUFSIZ);
+
+	/*
+	 * Allocate usb 3.0 device context.
+	 * USB 3.0 (xHCI) protocol tries to allocate device slot
+	 * and related data structures first. This call does that.
+	 * Refer to sec 4.3.2 in xHCI spec rev1.0
+	 */
+	if (usb_alloc_device(dev)) {
+		printf("Cannot allocate device context to get SLOT_ID\n");
+		return -1;
+	}
+
+	/* We still haven't set the Address yet */
+	addr = dev->devnum;
+	dev->devnum = 0;
+
+	/*
+	 * 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.
+	 */
+#ifndef CONFIG_USB_XHCI
+	do_read = false;
+#endif
+	err = usb_setup_descriptor(dev, do_read);
+	if (err)
+		return err;
+	err = usb_legacy_port_reset(dev->parent, dev->portnr);
+	if (err)
+		return err;
+
 	dev->devnum = addr;
 
 	err = usb_set_address(dev); /* set address */
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#35 lore raw

PATCH v2 17/80 dm: usb: Move descriptor setup code into its own function

Quoted 11 lines · Simon Glass

usb_new_device() is far too long and does far too much. As a first step, move the code that does initial setup and reads a descriptor into its own function called usb_setup_descriptor().

For XHCI the init order is different - we set up the device but don't actually read the descriptor until after we set an address. Support this option as a parameter to usb_setup_descriptor().

Avoid changing this torturous code more than necessary to make it easy to review.

Quoted 7 lines

---

Changes in v2: None

 common/usb.c | 117 ++++++++++++++++++++++++++++++++++-------------------------
 1 file changed, 67 insertions(+), 50 deletions(-)

Applied to u-boot-dm/next.

#36 lore raw

PATCH v2 18/80 dm: usb: Split out more code from usb_new_device()

In reply to Simon Glass

Move the code that sets up the device with a new address into its own function, usb_prepare_device().

---

Changes in v2: None

 common/usb.c | 72 +++++++++++++++++++++++++++++++++++-------------------------
 1 file changed, 42 insertions(+), 30 deletions(-)
common/usb.c +42 -30
index d0debbc..c3f805d 100644
@@ -956,19 +956,10 @@ static int usb_setup_descriptor(struct usb_device *dev, bool do_read)
 	return 0;
 }
 
-/*
- * By the time we get here, the device has gotten a new device ID
- * and is in the default state. We need to identify the thing and
- * get the ball rolling..
- *
- * Returns 0 for success, != 0 for error.
- */
-int usb_new_device(struct usb_device *dev)
+static int usb_prepare_device(struct usb_device *dev, int addr, bool do_read,
+			      struct usb_device *parent, int portnr)
 {
-	bool do_read = true;
-	int addr, err;
-	int tmp;
-	ALLOC_CACHE_ALIGN_BUFFER(unsigned char, tmpbuf, USB_BUFSIZ);
+	int err;
 
 	/*
 	 * Allocate usb 3.0 device context.
@@ -976,28 +967,15 @@ int usb_new_device(struct usb_device *dev)
 	 * and related data structures first. This call does that.
 	 * Refer to sec 4.3.2 in xHCI spec rev1.0
 	 */
-	if (usb_alloc_device(dev)) {
+	err = usb_alloc_device(dev);
+	if (err) {
 		printf("Cannot allocate device context to get SLOT_ID\n");
-		return -1;
+		return err;
 	}
-
-	/* We still haven't set the Address yet */
-	addr = dev->devnum;
-	dev->devnum = 0;
-
-	/*
-	 * 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.
-	 */
-#ifndef CONFIG_USB_XHCI
-	do_read = false;
-#endif
 	err = usb_setup_descriptor(dev, do_read);
 	if (err)
 		return err;
-	err = usb_legacy_port_reset(dev->parent, dev->portnr);
+	err = usb_legacy_port_reset(parent, portnr);
 	if (err)
 		return err;
 
@@ -1008,11 +986,45 @@ int usb_new_device(struct usb_device *dev)
 	if (err < 0) {
 		printf("\n      USB device not accepting new address " \
 			"(error=%lX)\n", dev->status);
-		return 1;
+		return err;
 	}
 
 	mdelay(10);	/* Let the SET_ADDRESS settle */
 
+	return 0;
+}
+
+/*
+ * By the time we get here, the device has gotten a new device ID
+ * and is in the default state. We need to identify the thing and
+ * get the ball rolling..
+ *
+ * Returns 0 for success, != 0 for error.
+ */
+int usb_new_device(struct usb_device *dev)
+{
+	bool do_read = true;
+	int addr, err;
+	int tmp, ret;
+	ALLOC_CACHE_ALIGN_BUFFER(unsigned char, tmpbuf, USB_BUFSIZ);
+
+	/* We still haven't set the Address yet */
+	addr = dev->devnum;
+	dev->devnum = 0;
+
+	/*
+	 * 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.
+	 */
+#ifndef CONFIG_USB_XHCI
+	do_read = false;
+#endif
+	ret = usb_prepare_device(dev, addr, do_read, dev->parent, dev->portnr);
+	if (ret)
+		return ret;
+
 	tmp = sizeof(dev->descriptor);
 
 	err = usb_get_descriptor(dev, USB_DT_DEVICE, 0,
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#37 lore raw

PATCH v2 18/80 dm: usb: Split out more code from usb_new_device()

Quoted 10 lines · Simon Glass

Move the code that sets up the device with a new address into its own function, usb_prepare_device().

---

Changes in v2: None

 common/usb.c | 72 +++++++++++++++++++++++++++++++++++-------------------------
 1 file changed, 42 insertions(+), 30 deletions(-)

Applied to u-boot-dm/next.

#38 lore raw

PATCH v2 19/80 dm: usb: Complete the splitting up of usb_new_device()

In reply to Simon Glass

This function now calls usb_setup_device() to set up the device and usb_hub_probe() to check if it is a hub. The XHCI special case is now a parameter to usb_setup_device(). The latter will be used by the USB uclass when it is added, since it does not rely on any CONFIGs or legacy data structures.

---

Changes in v2: None

 common/usb.c | 114 +++++++++++++++++++++++++++++++++++------------------------
 1 file changed, 68 insertions(+), 46 deletions(-)
common/usb.c +68 -46
index c3f805d..5e14d7c 100644
@@ -994,71 +994,40 @@ static int usb_prepare_device(struct usb_device *dev, int addr, bool do_read,
 	return 0;
 }
 
-/*
- * By the time we get here, the device has gotten a new device ID
- * and is in the default state. We need to identify the thing and
- * get the ball rolling..
- *
- * Returns 0 for success, != 0 for error.
- */
-int usb_new_device(struct usb_device *dev)
+static int usb_select_config(struct usb_device *dev)
 {
-	bool do_read = true;
-	int addr, err;
-	int tmp, ret;
 	ALLOC_CACHE_ALIGN_BUFFER(unsigned char, tmpbuf, USB_BUFSIZ);
+	int err;
 
-	/* We still haven't set the Address yet */
-	addr = dev->devnum;
-	dev->devnum = 0;
-
-	/*
-	 * 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.
-	 */
-#ifndef CONFIG_USB_XHCI
-	do_read = false;
-#endif
-	ret = usb_prepare_device(dev, addr, do_read, dev->parent, dev->portnr);
-	if (ret)
-		return ret;
-
-	tmp = sizeof(dev->descriptor);
+	err = usb_setup_descriptor(dev, true);
+	if (err)
+		return err;
 
-	err = usb_get_descriptor(dev, USB_DT_DEVICE, 0,
-				 tmpbuf, sizeof(dev->descriptor));
-	if (err < tmp) {
-		if (err < 0)
-			printf("unable to get device descriptor (error=%d)\n",
-			       err);
-		else
-			printf("USB device descriptor short read " \
-				"(expected %i, got %i)\n", tmp, err);
-		return 1;
-	}
-	memcpy(&dev->descriptor, tmpbuf, sizeof(dev->descriptor));
 	/* correct le values */
 	le16_to_cpus(&dev->descriptor.bcdUSB);
 	le16_to_cpus(&dev->descriptor.idVendor);
 	le16_to_cpus(&dev->descriptor.idProduct);
 	le16_to_cpus(&dev->descriptor.bcdDevice);
+
 	/* only support for one config for now */
 	err = usb_get_configuration_no(dev, tmpbuf, 0);
 	if (err < 0) {
 		printf("usb_new_device: Cannot read configuration, " \
 		       "skipping device %04x:%04x\n",
 		       dev->descriptor.idVendor, dev->descriptor.idProduct);
-		return -1;
+		return -err;
 	}
 	usb_parse_config(dev, tmpbuf, 0);
 	usb_set_maxpacket(dev);
-	/* we set the default configuration here */
+	/*
+	 * we set the default configuration here
+	 * This seems premature. If the driver wants a different configuration
+	 * it will need to select itself.
+	 */
 	if (usb_set_configuration(dev, dev->config.desc.bConfigurationValue)) {
 		printf("failed to set default configuration " \
 			"len %d, status %lX\n", dev->act_len, dev->status);
-		return -1;
+		return -err;
 	}
 	debug("new device strings: Mfr=%d, Product=%d, SerialNumber=%d\n",
 	      dev->descriptor.iManufacturer, dev->descriptor.iProduct,
@@ -1078,11 +1047,64 @@ int usb_new_device(struct usb_device *dev)
 	debug("Manufacturer %s\n", dev->mf);
 	debug("Product      %s\n", dev->prod);
 	debug("SerialNumber %s\n", dev->serial);
-	/* now prode if the device is a hub */
-	usb_hub_probe(dev, 0);
+
 	return 0;
 }
 
+static int usb_setup_device(struct usb_device *dev, bool do_read,
+			    struct usb_device *parent, int portnr)
+{
+	int addr;
+	int ret;
+
+	/* We still haven't set the Address yet */
+	addr = dev->devnum;
+	dev->devnum = 0;
+
+	ret = usb_prepare_device(dev, addr, do_read, parent, portnr);
+	if (ret)
+		return ret;
+	ret = usb_select_config(dev);
+
+	return ret;
+}
+
+/*
+ * By the time we get here, the device has gotten a new device ID
+ * and is in the default state. We need to identify the thing and
+ * get the ball rolling..
+ *
+ * Returns 0 for success, != 0 for error.
+ */
+int usb_new_device(struct usb_device *dev)
+{
+	bool do_read = true;
+	int count;
+	int err;
+
+	/*
+	 * 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.
+	 */
+#ifndef CONFIG_USB_XHCI
+	do_read = false;
+#endif
+	err = usb_setup_device(dev, do_read, dev->parent, dev->portnr);
+	if (err)
+		return err;
+
+	count = 1;
+	/* now prode if the device is a hub */
+	err = usb_hub_probe(dev, 0);
+	if (err < 0)
+		return err;
+	count += err;
+
+	return count;
+}
+
 __weak
 int board_usb_init(int index, enum usb_init_type init)
 {
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#39 lore raw

PATCH v2 19/80 dm: usb: Complete the splitting up of usb_new_device()

Quoted 6 lines · Simon Glass

This function now calls usb_setup_device() to set up the device and usb_hub_probe() to check if it is a hub. The XHCI special case is now a parameter to usb_setup_device(). The latter will be used by the USB uclass when it is added, since it does not rely on any CONFIGs or legacy data structures.

Quoted 7 lines

---

Changes in v2: None

 common/usb.c | 114 +++++++++++++++++++++++++++++++++++------------------------
 1 file changed, 68 insertions(+), 46 deletions(-)

Applied to u-boot-dm/next.

#40 lore raw

PATCH v2 20/80 dm: usb: Convert core usb.c file to support driver model

In reply to Simon Glass

Add the required #ifdefs and remove unwanted data structures so that the USB uclass will be able to use this file.

---

Changes in v2: None

 common/usb.c | 31 +++++++++++++++++++++++++------
 1 file changed, 25 insertions(+), 6 deletions(-)
common/usb.c +25 -6
index 5e14d7c..06c1c43 100644
@@ -28,6 +28,7 @@
  */
 #include <common.h>
 #include <command.h>
+#include <dm.h>
 #include <asm/processor.h>
 #include <linux/compiler.h>
 #include <linux/ctype.h>
@@ -41,12 +42,13 @@
 
 #define USB_BUFSIZ	512
 
-static struct usb_device usb_dev[USB_MAX_DEVICE];
-static int dev_index;
 static int asynch_allowed;
-
 char usb_started; /* flag for the started/stopped USB status */
 
+#ifndef CONFIG_DM_USB
+static struct usb_device usb_dev[USB_MAX_DEVICE];
+static int dev_index;
+
 #ifndef CONFIG_USB_MAX_CONTROLLER_COUNT
 #define CONFIG_USB_MAX_CONTROLLER_COUNT 1
 #endif
@@ -152,6 +154,7 @@ int usb_disable_asynch(int disable)
 	asynch_allowed = !disable;
 	return old_value;
 }
+#endif /* !CONFIG_DM_USB */
 
 
 /*-------------------------------------------------------------------
@@ -815,6 +818,7 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
  * the USB device are static allocated [USB_MAX_DEVICE].
  */
 
+#ifndef CONFIG_DM_USB
 
 /* returns a pointer to the device with the index [index].
  * if the device is not assigned (dev->devnum==-1) returns NULL
@@ -871,7 +875,9 @@ __weak int usb_alloc_device(struct usb_device *udev)
 {
 	return 0;
 }
+#endif /* !CONFIG_DM_USB */
 
+#ifndef CONFIG_DM_USB
 int usb_legacy_port_reset(struct usb_device *hub, int portnr)
 {
 	if (hub) {
@@ -890,6 +896,7 @@ int usb_legacy_port_reset(struct usb_device *hub, int portnr)
 
 	return 0;
 }
+#endif
 
 static int usb_setup_descriptor(struct usb_device *dev, bool do_read)
 {
@@ -994,7 +1001,7 @@ static int usb_prepare_device(struct usb_device *dev, int addr, bool do_read,
 	return 0;
 }
 
-static int usb_select_config(struct usb_device *dev)
+int usb_select_config(struct usb_device *dev)
 {
 	ALLOC_CACHE_ALIGN_BUFFER(unsigned char, tmpbuf, USB_BUFSIZ);
 	int err;
@@ -1051,8 +1058,8 @@ static int usb_select_config(struct usb_device *dev)
 	return 0;
 }
 
-static int usb_setup_device(struct usb_device *dev, bool do_read,
-			    struct usb_device *parent, int portnr)
+int usb_setup_device(struct usb_device *dev, bool do_read,
+		     struct usb_device *parent, int portnr)
 {
 	int addr;
 	int ret;
@@ -1069,6 +1076,7 @@ static int usb_setup_device(struct usb_device *dev, bool do_read,
 	return ret;
 }
 
+#ifndef CONFIG_DM_USB
 /*
  * By the time we get here, the device has gotten a new device ID
  * and is in the default state. We need to identify the thing and
@@ -1104,10 +1112,21 @@ int usb_new_device(struct usb_device *dev)
 
 	return count;
 }
+#endif
 
 __weak
 int board_usb_init(int index, enum usb_init_type init)
 {
 	return 0;
 }
+
+bool usb_device_has_child_on_port(struct usb_device *parent, int port)
+{
+#ifdef CONFIG_DM_USB
+	return false;
+#else
+	return parent->children[port] != NULL;
+#endif
+}
+
 /* EOF */
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#41 lore raw

PATCH v2 20/80 dm: usb: Convert core usb.c file to support driver model

Quoted 10 lines · Simon Glass

Add the required #ifdefs and remove unwanted data structures so that the USB uclass will be able to use this file.

---

Changes in v2: None

 common/usb.c | 31 +++++++++++++++++++++++++------
 1 file changed, 25 insertions(+), 6 deletions(-)

Applied to u-boot-dm/next.

#42 lore raw

PATCH v2 21/80 dm: usb: Split hub detection into its own function

In reply to Simon Glass

Split out the hub detection logic so it can be used by driver model. Also adjust the code to return errors correctly.

---

Changes in v2: None

 common/usb_hub.c | 57 ++++++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 41 insertions(+), 16 deletions(-)
common/usb_hub.c +41 -16
index 49fa5a6..cc22f4b 100644
@@ -297,27 +297,30 @@ static int usb_hub_configure(struct usb_device *dev)
 	struct usb_hub_descriptor *descriptor;
 	struct usb_hub_device *hub;
 	__maybe_unused struct usb_hub_status *hubsts;
+	int ret;
 
 	/* "allocate" Hub device */
 	hub = usb_hub_allocate();
 	if (hub == NULL)
-		return -1;
+		return -ENOMEM;
 	hub->pusb_dev = dev;
 	/* Get the the hub descriptor */
-	if (usb_get_hub_descriptor(dev, buffer, 4) < 0) {
+	ret = usb_get_hub_descriptor(dev, buffer, 4);
+	if (ret < 0) {
 		debug("usb_hub_configure: failed to get hub " \
 		      "descriptor, giving up %lX\n", dev->status);
-		return -1;
+		return ret;
 	}
 	descriptor = (struct usb_hub_descriptor *)buffer;
 
 	length = min_t(int, descriptor->bLength,
 		       sizeof(struct usb_hub_descriptor));
 
-	if (usb_get_hub_descriptor(dev, buffer, length) < 0) {
+	ret = usb_get_hub_descriptor(dev, buffer, length);
+	if (ret < 0) {
 		debug("usb_hub_configure: failed to get hub " \
 		      "descriptor 2nd giving up %lX\n", dev->status);
-		return -1;
+		return ret;
 	}
 	memcpy((unsigned char *)&hub->desc, buffer, length);
 	/* adjust 16bit values */
@@ -385,13 +388,14 @@ static int usb_hub_configure(struct usb_device *dev)
 	if (sizeof(struct usb_hub_status) > USB_BUFSIZ) {
 		debug("usb_hub_configure: failed to get Status - " \
 		      "too long: %d\n", descriptor->bLength);
-		return -1;
+		return -EFBIG;
 	}
 
-	if (usb_get_hub_status(dev, buffer) < 0) {
+	ret = usb_get_hub_status(dev, buffer);
+	if (ret < 0) {
 		debug("usb_hub_configure: failed to get Status %lX\n",
 		      dev->status);
-		return -1;
+		return ret;
 	}
 
 #ifdef DEBUG
@@ -423,6 +427,7 @@ static int usb_hub_configure(struct usb_device *dev)
 		int ret;
 		ulong start = get_timer(0);
 
+		debug("\n\nScanning port %d\n", i + 1);
 		/*
 		 * Wait for (whichever finishes first)
 		 *  - A maximum of 10 seconds
@@ -503,33 +508,53 @@ static int usb_hub_configure(struct usb_device *dev)
 	return 0;
 }
 
-int usb_hub_probe(struct usb_device *dev, int ifnum)
+static int usb_hub_check(struct usb_device *dev, int ifnum)
 {
 	struct usb_interface *iface;
-	struct usb_endpoint_descriptor *ep;
-	int ret;
+	struct usb_endpoint_descriptor *ep = NULL;
 
 	iface = &dev->config.if_desc[ifnum];
 	/* Is it a hub? */
 	if (iface->desc.bInterfaceClass != USB_CLASS_HUB)
-		return 0;
+		goto err;
 	/* Some hubs have a subclass of 1, which AFAICT according to the */
 	/*  specs is not defined, but it works */
 	if ((iface->desc.bInterfaceSubClass != 0) &&
 	    (iface->desc.bInterfaceSubClass != 1))
-		return 0;
+		goto err;
 	/* Multiple endpoints? What kind of mutant ninja-hub is this? */
 	if (iface->desc.bNumEndpoints != 1)
-		return 0;
+		goto err;
 	ep = &iface->ep_desc[0];
 	/* Output endpoint? Curiousier and curiousier.. */
 	if (!(ep->bEndpointAddress & USB_DIR_IN))
-		return 0;
+		goto err;
 	/* If it's not an interrupt endpoint, we'd better punt! */
 	if ((ep->bmAttributes & 3) != 3)
-		return 0;
+		goto err;
 	/* We found a hub */
 	debug("USB hub found\n");
+	return 0;
+
+err:
+	debug("USB hub not found: bInterfaceClass=%d, bInterfaceSubClass=%d, bNumEndpoints=%d\n",
+	      iface->desc.bInterfaceClass, iface->desc.bInterfaceSubClass,
+	      iface->desc.bNumEndpoints);
+	if (ep) {
+		debug("   bEndpointAddress=%#x, bmAttributes=%d",
+		      ep->bEndpointAddress, ep->bmAttributes);
+	}
+
+	return -ENOENT;
+}
+
+int usb_hub_probe(struct usb_device *dev, int ifnum)
+{
+	int ret;
+
+	ret = usb_hub_check(dev, ifnum);
+	if (ret)
+		return 0;
 	ret = usb_hub_configure(dev);
 	return ret;
 }
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#43 lore raw

PATCH v2 21/80 dm: usb: Split hub detection into its own function

Quoted 10 lines · Simon Glass

Split out the hub detection logic so it can be used by driver model. Also adjust the code to return errors correctly.

---

Changes in v2: None

 common/usb_hub.c | 57 ++++++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 41 insertions(+), 16 deletions(-)

Applied to u-boot-dm/next.

#44 lore raw

PATCH v2 22/80 dm: usb: Add driver model support for hubs

In reply to Simon Glass

Adjust the existing hub code to support driver model, and add a USB driver for hubs.

---

Changes in v2: None

 common/usb_hub.c       | 94 +++++++++++++++++++++++++++++++++++++++++++++++---
 include/dm/uclass-id.h |  1 +
 2 files changed, 91 insertions(+), 4 deletions(-)
common/usb_hub.c +90 -4
index cc22f4b..6933015 100644
@@ -24,12 +24,16 @@
 
 #include <common.h>
 #include <command.h>
+#include <dm.h>
 #include <errno.h>
 #include <asm/processor.h>
 #include <asm/unaligned.h>
 #include <linux/ctype.h>
 #include <asm/byteorder.h>
 #include <asm/unaligned.h>
+#include <dm/root.h>
+
+DECLARE_GLOBAL_DATA_PTR;
 
 #include <usb.h>
 #ifdef CONFIG_4xx
@@ -38,6 +42,7 @@
 
 #define USB_BUFSIZ	512
 
+/* TODO(sjg at chromium.org): Remove this when CONFIG_DM_USB is defined */
 static struct usb_hub_device hub_dev[USB_MAX_HUB];
 static int usb_hub_index;
 
@@ -148,7 +153,12 @@ int legacy_hub_port_reset(struct usb_device *dev, int port,
 	ALLOC_CACHE_ALIGN_BUFFER(struct usb_port_status, portsts, 1);
 	unsigned short portstatus, portchange;
 
-	debug("hub_port_reset: resetting port %d...\n", port);
+#ifdef CONFIG_DM_USB
+	debug("%s: resetting '%s' port %d...\n", __func__, dev->dev->name,
+	      port + 1);
+#else
+	debug("%s: resetting port %d...\n", __func__, port + 1);
+#endif
 	for (tries = 0; tries < MAX_TRIES; tries++) {
 
 		usb_set_port_feature(dev, port + 1, USB_PORT_FEAT_RESET);
@@ -206,10 +216,17 @@ int legacy_hub_port_reset(struct usb_device *dev, int port,
 	return 0;
 }
 
+#ifdef CONFIG_DM_USB
+int hub_port_reset(struct udevice *dev, int port, unsigned short *portstat)
+{
+	struct usb_device *udev = dev_get_parentdata(dev);
+
+	return legacy_hub_port_reset(udev, port, portstat);
+}
+#endif
 
 int usb_hub_port_connect_change(struct usb_device *dev, int port)
 {
-	struct usb_device *usb;
 	ALLOC_CACHE_ALIGN_BUFFER(struct usb_port_status, portsts, 1);
 	unsigned short portstatus;
 	int ret, speed;
@@ -232,7 +249,8 @@ int usb_hub_port_connect_change(struct usb_device *dev, int port)
 
 	/* Disconnect any existing devices under this port */
 	if (((!(portstatus & USB_PORT_STAT_CONNECTION)) &&
-	     (!(portstatus & USB_PORT_STAT_ENABLE))) || (dev->children[port])) {
+	     (!(portstatus & USB_PORT_STAT_ENABLE))) ||
+	    usb_device_has_child_on_port(dev, port)) {
 		debug("usb_disconnect(&hub->children[port]);\n");
 		/* Return now if nothing is connected */
 		if (!(portstatus & USB_PORT_STAT_CONNECTION))
@@ -264,6 +282,13 @@ int usb_hub_port_connect_change(struct usb_device *dev, int port)
 		break;
 	}
 
+#ifdef CONFIG_DM_USB
+	struct udevice *child;
+
+	ret = usb_scan_device(dev->dev, port + 1, speed, &child);
+#else
+	struct usb_device *usb;
+
 	ret = usb_alloc_new_device(dev->controller, &usb);
 	if (ret) {
 		printf("cannot create new device: ret=%d", ret);
@@ -280,6 +305,9 @@ int usb_hub_port_connect_change(struct usb_device *dev, int port)
 		/* Woops, disable the port */
 		usb_free_device(dev->controller);
 		dev->children[port] = NULL;
+	}
+#endif
+	if (ret < 0) {
 		debug("hub: disabling port %d\n", port + 1);
 		usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_ENABLE);
 	}
@@ -427,7 +455,11 @@ static int usb_hub_configure(struct usb_device *dev)
 		int ret;
 		ulong start = get_timer(0);
 
+#ifdef CONFIG_DM_USB
+		debug("\n\nScanning '%s' port %d\n", dev->dev->name, i + 1);
+#else
 		debug("\n\nScanning port %d\n", i + 1);
+#endif
 		/*
 		 * Wait for (whichever finishes first)
 		 *  - A maximum of 10 seconds
@@ -477,7 +509,7 @@ static int usb_hub_configure(struct usb_device *dev)
 			 * them again. Works at least with mouse driver */
 			if (!(portstatus & USB_PORT_STAT_ENABLE) &&
 			     (portstatus & USB_PORT_STAT_CONNECTION) &&
-			     ((dev->children[i]))) {
+			     usb_device_has_child_on_port(dev, i)) {
 				debug("already running port %i "  \
 				      "disabled by hub (EMI?), " \
 				      "re-enabling...\n", i + 1);
@@ -558,3 +590,57 @@ int usb_hub_probe(struct usb_device *dev, int ifnum)
 	ret = usb_hub_configure(dev);
 	return ret;
 }
+
+#ifdef CONFIG_DM_USB
+int usb_hub_scan(struct udevice *hub)
+{
+	struct usb_device *udev = dev_get_parentdata(hub);
+
+	return usb_hub_configure(udev);
+}
+
+static int usb_hub_post_bind(struct udevice *dev)
+{
+	/* Scan the bus for devices */
+	return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
+}
+
+static int usb_hub_post_probe(struct udevice *dev)
+{
+	debug("%s\n", __func__);
+	return usb_hub_scan(dev);
+}
+
+static const struct udevice_id usb_hub_ids[] = {
+	{ .compatible = "usb-hub" },
+	{ }
+};
+
+U_BOOT_DRIVER(usb_generic_hub) = {
+	.name	= "usb_hub",
+	.id	= UCLASS_USB_HUB,
+	.of_match = usb_hub_ids,
+	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
+};
+
+UCLASS_DRIVER(usb_hub) = {
+	.id		= UCLASS_USB_HUB,
+	.name		= "usb_hub",
+	.post_bind	= usb_hub_post_bind,
+	.post_probe	= usb_hub_post_probe,
+	.child_pre_probe	= usb_child_pre_probe,
+	.per_child_auto_alloc_size = sizeof(struct usb_device),
+	.per_child_platdata_auto_alloc_size = sizeof(struct usb_dev_platdata),
+};
+
+static const struct usb_device_id hub_id_table[] = {
+	{
+		.match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS,
+		.bDeviceClass = USB_CLASS_HUB
+	},
+	{ }	/* Terminating entry */
+};
+
+USB_DEVICE(usb_generic_hub, hub_id_table);
+
+#endif
include/dm/uclass-id.h +1 -0
index cb6d2e5..acec938 100644
@@ -40,6 +40,7 @@ enum uclass_id {
 	UCLASS_PCH,		/* x86 platform controller hub */
 	UCLASS_ETH,		/* Ethernet device */
 	UCLASS_USB,		/* USB bus */
+	UCLASS_USB_HUB,		/* USB hub */
 
 	UCLASS_COUNT,
 	UCLASS_INVALID = -1,
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#45 lore raw

PATCH v2 22/80 dm: usb: Add driver model support for hubs

Quoted 11 lines · Simon Glass

Adjust the existing hub code to support driver model, and add a USB driver for hubs.

---

Changes in v2: None

 common/usb_hub.c       | 94 +++++++++++++++++++++++++++++++++++++++++++++++---
 include/dm/uclass-id.h |  1 +
 2 files changed, 91 insertions(+), 4 deletions(-)

Applied to u-boot-dm/next.

#46 lore raw

PATCH v2 23/80 dm: usb: Move USB storage definitions to usb_defs.h

In reply to Simon Glass

These are better off in a header file so they can be used by other code (e.g. the sandbox USB storage emulator).

---

Changes in v2: None

 common/usb_storage.c | 45 ++-------------------------------------------
 include/usb_defs.h   | 42 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 44 insertions(+), 43 deletions(-)
common/usb_storage.c +2 -43
index 1411737..590408a 100644
@@ -56,49 +56,8 @@ static const unsigned char us_direction[256/8] = {
 #define US_DIRECTION(x) ((us_direction[x>>3] >> (x & 7)) & 1)
 
 static ccb usb_ccb __attribute__((aligned(ARCH_DMA_MINALIGN)));
-
-/*
- * CBI style
- */
-
-#define US_CBI_ADSC		0
-
-/*
- * BULK only
- */
-#define US_BBB_RESET		0xff
-#define US_BBB_GET_MAX_LUN	0xfe
-
-/* Command Block Wrapper */
-typedef struct {
-	__u32		dCBWSignature;
-#	define CBWSIGNATURE	0x43425355
-	__u32		dCBWTag;
-	__u32		dCBWDataTransferLength;
-	__u8		bCBWFlags;
-#	define CBWFLAGS_OUT	0x00
-#	define CBWFLAGS_IN	0x80
-	__u8		bCBWLUN;
-	__u8		bCDBLength;
-#	define CBWCDBLENGTH	16
-	__u8		CBWCDB[CBWCDBLENGTH];
-} umass_bbb_cbw_t;
-#define UMASS_BBB_CBW_SIZE	31
 static __u32 CBWTag;
 
-/* Command Status Wrapper */
-typedef struct {
-	__u32		dCSWSignature;
-#	define CSWSIGNATURE	0x53425355
-	__u32		dCSWTag;
-	__u32		dCSWDataResidue;
-	__u8		bCSWStatus;
-#	define CSWSTATUS_GOOD	0x0
-#	define CSWSTATUS_FAILED 0x1
-#	define CSWSTATUS_PHASE	0x2
-} umass_bbb_csw_t;
-#define UMASS_BBB_CSW_SIZE	13
-
 #define USB_MAX_STOR_DEV 5
 static int usb_max_devs; /* number of highest available usb device */
 
@@ -483,7 +442,7 @@ static int usb_stor_BBB_comdat(ccb *srb, struct us_data *us)
 	int actlen;
 	int dir_in;
 	unsigned int pipe;
-	ALLOC_CACHE_ALIGN_BUFFER(umass_bbb_cbw_t, cbw, 1);
+	ALLOC_CACHE_ALIGN_BUFFER(struct umass_bbb_cbw, cbw, 1);
 
 	dir_in = US_DIRECTION(srb->cmd[0]);
 
@@ -658,7 +617,7 @@ static int usb_stor_BBB_transport(ccb *srb, struct us_data *us)
 	int dir_in;
 	int actlen, data_actlen;
 	unsigned int pipe, pipein, pipeout;
-	ALLOC_CACHE_ALIGN_BUFFER(umass_bbb_csw_t, csw, 1);
+	ALLOC_CACHE_ALIGN_BUFFER(struct umass_bbb_csw, csw, 1);
 #ifdef BBB_XPORT_TRACE
 	unsigned char *ptr;
 	int index;
include/usb_defs.h +42 -0

46 lines not on this page · raw message

Signature · 1 line
2.2.0.rc0.207.ga3a616c
#47 lore raw

PATCH v2 23/80 dm: usb: Move USB storage definitions to usb_defs.h

Quoted 11 lines · Simon Glass

These are better off in a header file so they can be used by other code (e.g. the sandbox USB storage emulator).

---

Changes in v2: None

 common/usb_storage.c | 45 ++-------------------------------------------
 include/usb_defs.h   | 42 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 44 insertions(+), 43 deletions(-)

Applied to u-boot-dm/next.

#48 lore raw

PATCH v2 24/80 dm: usb: Fix type problems in usb_stor_get_info()

In reply to Simon Glass

This function assumes that unsigned long is 32-bits wide, but it is not on 64-bit machines. Use the correct type, and add a few debug() lines also.

---

Changes in v2: None

 common/usb_storage.c | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)
common/usb_storage.c +11 -7
index 590408a..80ed14a 100644
@@ -1178,6 +1178,7 @@ int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,
 			iface->desc.bInterfaceClass != USB_CLASS_MASS_STORAGE ||
 			iface->desc.bInterfaceSubClass < US_SC_MIN ||
 			iface->desc.bInterfaceSubClass > US_SC_MAX) {
+		debug("Not mass storage\n");
 		/* if it's not a mass storage, we go no further */
 		return 0;
 	}
@@ -1293,9 +1294,9 @@ int usb_stor_get_info(struct usb_device *dev, struct us_data *ss,
 		      block_dev_desc_t *dev_desc)
 {
 	unsigned char perq, modi;
-	ALLOC_CACHE_ALIGN_BUFFER(unsigned long, cap, 2);
+	ALLOC_CACHE_ALIGN_BUFFER(uint32_t, cap, 2);
 	ALLOC_CACHE_ALIGN_BUFFER(unsigned char, usb_stor_buf, 36);
-	unsigned long *capacity, *blksz;
+	uint32_t *capacity, *blksz;
 	ccb *pccb = &usb_ccb;
 
 	pccb->pdata = usb_stor_buf;
@@ -1304,8 +1305,10 @@ int usb_stor_get_info(struct usb_device *dev, struct us_data *ss,
 	pccb->lun = dev_desc->lun;
 	debug(" address %d\n", dev_desc->target);
 
-	if (usb_inquiry(pccb, ss))
+	if (usb_inquiry(pccb, ss)) {
+		debug("%s: usb_inquiry() failed\n", __func__);
 		return -1;
+	}
 
 	perq = usb_stor_buf[0];
 	modi = usb_stor_buf[1];
@@ -1315,6 +1318,7 @@ int usb_stor_get_info(struct usb_device *dev, struct us_data *ss,
 	 * they would not respond to test_unit_ready .
 	 */
 	if (((perq & 0x1f) == 0x1f) || ((perq & 0x1f) == 0x0d)) {
+		debug("%s: unknown/unsupported device\n", __func__);
 		return 0;
 	}
 	if ((modi&0x80) == 0x80) {
@@ -1352,19 +1356,19 @@ int usb_stor_get_info(struct usb_device *dev, struct us_data *ss,
 		cap[1] = 0x200;
 	}
 	ss->flags &= ~USB_READY;
-	debug("Read Capacity returns: 0x%lx, 0x%lx\n", cap[0], cap[1]);
+	debug("Read Capacity returns: 0x%x, 0x%x\n", cap[0], cap[1]);
 #if 0
 	if (cap[0] > (0x200000 * 10)) /* greater than 10 GByte */
 		cap[0] >>= 16;
 #endif
-	cap[0] = cpu_to_be32(cap[0]);
-	cap[1] = cpu_to_be32(cap[1]);
+	cap[0] = be32_to_cpu(cap[0]);
+	cap[1] = be32_to_cpu(cap[1]);
 
 	/* this assumes bigendian! */
 	cap[0] += 1;
 	capacity = &cap[0];
 	blksz = &cap[1];
-	debug("Capacity = 0x%lx, blocksz = 0x%lx\n", *capacity, *blksz);
+	debug("Capacity = 0x%x, blocksz = 0x%x\n", *capacity, *blksz);
 	dev_desc->lba = *capacity;
 	dev_desc->blksz = *blksz;
 	dev_desc->log2blksz = LOG2(dev_desc->blksz);
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#49 lore raw

PATCH v2 24/80 dm: usb: Fix type problems in usb_stor_get_info()

Quoted 10 lines · Simon Glass

This function assumes that unsigned long is 32-bits wide, but it is not on 64-bit machines. Use the correct type, and add a few debug() lines also.

---

Changes in v2: None

 common/usb_storage.c | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

Applied to u-boot-dm/next.

#50 lore raw

PATCH v2 25/80 dm: usb: Simply device finding code in usb_storage

In reply to Simon Glass

The for() loop is not needed since the value is immediately accessible. Use this instead to simplify the code.

---

Changes in v2: None

 common/usb_storage.c | 30 +++++++++++-------------------
 1 file changed, 11 insertions(+), 19 deletions(-)
common/usb_storage.c +11 -19
index 80ed14a..64d01ea 100644
@@ -1005,7 +1005,7 @@ unsigned long usb_stor_read(int device, lbaint_t blknr,
 	unsigned short smallblks;
 	struct usb_device *dev;
 	struct us_data *ss;
-	int retry, i;
+	int retry;
 	ccb *srb = &usb_ccb;
 
 	if (blkcnt == 0)
@@ -1013,14 +1013,11 @@ unsigned long usb_stor_read(int device, lbaint_t blknr,
 
 	device &= 0xff;
 	/* Setup  device */
-	debug("\nusb_read: dev %d \n", device);
-	dev = NULL;
-	for (i = 0; i < USB_MAX_DEVICE; i++) {
-		dev = usb_get_dev_index(i);
-		if (dev == NULL)
-			return 0;
-		if (dev->devnum == usb_dev_desc[device].target)
-			break;
+	debug("\nusb_read: dev %d\n", device);
+	dev = usb_dev_desc[device].priv;
+	if (!dev) {
+		debug("%s: No device\n", __func__);
+		return 0;
 	}
 	ss = (struct us_data *)dev->privptr;
 
@@ -1078,7 +1075,7 @@ unsigned long usb_stor_write(int device, lbaint_t blknr,
 	unsigned short smallblks;
 	struct usb_device *dev;
 	struct us_data *ss;
-	int retry, i;
+	int retry;
 	ccb *srb = &usb_ccb;
 
 	if (blkcnt == 0)
@@ -1086,15 +1083,10 @@ unsigned long usb_stor_write(int device, lbaint_t blknr,
 
 	device &= 0xff;
 	/* Setup  device */
-	debug("\nusb_write: dev %d \n", device);
-	dev = NULL;
-	for (i = 0; i < USB_MAX_DEVICE; i++) {
-		dev = usb_get_dev_index(i);
-		if (dev == NULL)
-			return 0;
-		if (dev->devnum == usb_dev_desc[device].target)
-			break;
-	}
+	debug("\nusb_write: dev %d\n", device);
+	dev = usb_dev_desc[device].priv;
+	if (!dev)
+		return 0;
 	ss = (struct us_data *)dev->privptr;
 
 	usb_disable_asynch(1); /* asynch transfer not allowed */
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#51 lore raw

PATCH v2 25/80 dm: usb: Simply device finding code in usb_storage

Quoted 10 lines · Simon Glass

The for() loop is not needed since the value is immediately accessible. Use this instead to simplify the code.

---

Changes in v2: None

 common/usb_storage.c | 30 +++++++++++-------------------
 1 file changed, 11 insertions(+), 19 deletions(-)

Applied to u-boot-dm/next.

#52 lore raw

PATCH v2 26/80 dm: usb: Adjust usb_storage to work with sandbox

In reply to Simon Glass

With a few tweaks we can compile this code with sandbox and enable testing of the USB storage layer.

---

Changes in v2: None

 common/usb_storage.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
common/usb_storage.c +5 -3
index 64d01ea..acea5ae 100644
@@ -34,6 +34,7 @@
 #include <common.h>
 #include <command.h>
 #include <inttypes.h>
+#include <mapmem.h>
 #include <asm/byteorder.h>
 #include <asm/processor.h>
 
@@ -295,8 +296,9 @@ static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length)
 		/* set up the transfer loop */
 		do {
 			/* transfer the data */
-			debug("Bulk xfer 0x%x(%d) try #%d\n",
-			      (unsigned int)buf, this_xfer, 11 - maxtry);
+			debug("Bulk xfer 0x%lx(%d) try #%d\n",
+			      (ulong)map_to_sysmem(buf), this_xfer,
+			      11 - maxtry);
 			result = usb_bulk_msg(us->pusb_dev, pipe, buf,
 					      this_xfer, &partial,
 					      USB_CNTL_TIMEOUT * 5);
@@ -562,7 +564,7 @@ static int usb_stor_CBI_get_status(ccb *srb, struct us_data *us)
 			(void *) &us->ip_data, us->irqmaxp, us->irqinterval);
 	timeout = 1000;
 	while (timeout--) {
-		if ((volatile int *) us->ip_wanted == NULL)
+		if (*(volatile int *)&us->ip_wanted == 0)
 			break;
 		mdelay(10);
 	}
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#53 lore raw

PATCH v2 26/80 dm: usb: Adjust usb_storage to work with sandbox

Quoted 10 lines · Simon Glass

With a few tweaks we can compile this code with sandbox and enable testing of the USB storage layer.

---

Changes in v2: None

 common/usb_storage.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

Applied to u-boot-dm/next.

#54 lore raw

PATCH v2 27/80 dm: usb: Move storage device scanning into its own function

In reply to Simon Glass

The usb_stor_scan() function is quite long, so split out the code that scans each device into its own function. Also, rather than setting up the block device list once at the start, set it up as each device is scanned. This makes it possible to use this code from driver model.

---

Changes in v2: None

 common/usb_storage.c | 97 ++++++++++++++++++++++++++++++++--------------------
 1 file changed, 59 insertions(+), 38 deletions(-)
common/usb_storage.c +59 -38
index acea5ae..67494b7 100644
@@ -33,6 +33,7 @@
 
 #include <common.h>
 #include <command.h>
+#include <errno.h>
 #include <inttypes.h>
 #include <mapmem.h>
 #include <asm/byteorder.h>
@@ -168,6 +169,60 @@ static unsigned int usb_get_max_lun(struct us_data *us)
 	return (len > 0) ? *result : 0;
 }
 
+static int usb_stor_probe_device(struct usb_device *dev)
+{
+	if (dev == NULL)
+		return -ENOENT; /* no more devices available */
+
+	debug("\n\nProbing for storage\n");
+	if (usb_storage_probe(dev, 0, &usb_stor[usb_max_devs])) {
+		/* OK, it's a storage device.  Iterate over its LUNs
+			* and populate `usb_dev_desc'.
+			*/
+		int lun, max_lun, start = usb_max_devs;
+
+		max_lun = usb_get_max_lun(&usb_stor[usb_max_devs]);
+		for (lun = 0;
+			lun <= max_lun && usb_max_devs < USB_MAX_STOR_DEV;
+			lun++) {
+			struct block_dev_desc *blkdev;
+
+			blkdev = &usb_dev_desc[usb_max_devs];
+			memset(blkdev, '\0', sizeof(block_dev_desc_t));
+			blkdev->if_type = IF_TYPE_USB;
+			blkdev->dev = usb_max_devs;
+			blkdev->part_type = PART_TYPE_UNKNOWN;
+			blkdev->target = 0xff;
+			blkdev->type = DEV_TYPE_UNKNOWN;
+			blkdev->block_read = usb_stor_read;
+			blkdev->block_write = usb_stor_write;
+			blkdev->lun = lun;
+			blkdev->priv = dev;
+
+			if (usb_stor_get_info(dev, &usb_stor[start],
+					      &usb_dev_desc[usb_max_devs]) ==
+					      1) {
+				usb_max_devs++;
+				debug("%s: Found device %p\n", __func__, dev);
+			}
+		}
+	}
+
+	/* if storage device */
+	if (usb_max_devs == USB_MAX_STOR_DEV) {
+		printf("max USB Storage Device reached: %d stopping\n",
+		       usb_max_devs);
+		return -ENOSPC;
+	}
+
+	return 0;
+}
+
+void usb_stor_reset(void)
+{
+	usb_max_devs = 0;
+}
+
 /*******************************************************************************
  * scan the usb and reports device info
  * to the user if mode = 1
@@ -176,54 +231,20 @@ static unsigned int usb_get_max_lun(struct us_data *us)
 int usb_stor_scan(int mode)
 {
 	unsigned char i;
-	struct usb_device *dev;
 
 	if (mode == 1)
 		printf("       scanning usb for storage devices... ");
 
 	usb_disable_asynch(1); /* asynch transfer not allowed */
 
-	for (i = 0; i < USB_MAX_STOR_DEV; i++) {
-		memset(&usb_dev_desc[i], 0, sizeof(block_dev_desc_t));
-		usb_dev_desc[i].if_type = IF_TYPE_USB;
-		usb_dev_desc[i].dev = i;
-		usb_dev_desc[i].part_type = PART_TYPE_UNKNOWN;
-		usb_dev_desc[i].target = 0xff;
-		usb_dev_desc[i].type = DEV_TYPE_UNKNOWN;
-		usb_dev_desc[i].block_read = usb_stor_read;
-		usb_dev_desc[i].block_write = usb_stor_write;
-	}
-
-	usb_max_devs = 0;
+	usb_stor_reset();
 	for (i = 0; i < USB_MAX_DEVICE; i++) {
+		struct usb_device *dev;
+
 		dev = usb_get_dev_index(i); /* get device */
 		debug("i=%d\n", i);
-		if (dev == NULL)
-			break; /* no more devices available */
-
-		if (usb_storage_probe(dev, 0, &usb_stor[usb_max_devs])) {
-			/* OK, it's a storage device.  Iterate over its LUNs
-			 * and populate `usb_dev_desc'.
-			 */
-			int lun, max_lun, start = usb_max_devs;
-
-			max_lun = usb_get_max_lun(&usb_stor[usb_max_devs]);
-			for (lun = 0;
-			     lun <= max_lun && usb_max_devs < USB_MAX_STOR_DEV;
-			     lun++) {
-				usb_dev_desc[usb_max_devs].lun = lun;
-				if (usb_stor_get_info(dev, &usb_stor[start],
-				    &usb_dev_desc[usb_max_devs]) == 1) {
-					usb_max_devs++;
-				}
-			}
-		}
-		/* if storage device */
-		if (usb_max_devs == USB_MAX_STOR_DEV) {
-			printf("max USB Storage Device reached: %d stopping\n",
-				usb_max_devs);
+		if (usb_stor_probe_device(dev))
 			break;
-		}
 	} /* for */
 
 	usb_disable_asynch(0); /* asynch transfer allowed */
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#55 lore raw

PATCH v2 27/80 dm: usb: Move storage device scanning into its own function

Quoted 5 lines · Simon Glass

The usb_stor_scan() function is quite long, so split out the code that scans each device into its own function. Also, rather than setting up the block device list once at the start, set it up as each device is scanned. This makes it possible to use this code from driver model.

Quoted 7 lines

---

Changes in v2: None

 common/usb_storage.c | 97 ++++++++++++++++++++++++++++++++--------------------
 1 file changed, 59 insertions(+), 38 deletions(-)

Applied to u-boot-dm/next.

#56 lore raw

PATCH v2 28/80 dm: usb: Convert usb_storage to driver model

In reply to Simon Glass

Add support for scanning USB storage devices with driver model. This mostly involves adding a USB device ID for storage devices.

---

Changes in v2: None

 common/usb_storage.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 49 insertions(+), 2 deletions(-)
common/usb_storage.c +49 -2
index 67494b7..8b8962e 100644
@@ -9,6 +9,8 @@
  *
  * Adapted for U-Boot:
  *   (C) Copyright 2001 Denis Peter, MPL AG Switzerland
+ * Driver model conversion:
+ *   (C) Copyright 2015 Google, Inc
  *
  * For BBB support (C) Copyright 2003
  * Gary Jennejohn, DENX Software Engineering <[email protected]>
@@ -33,11 +35,13 @@
 
 #include <common.h>
 #include <command.h>
+#include <dm.h>
 #include <errno.h>
 #include <inttypes.h>
 #include <mapmem.h>
 #include <asm/byteorder.h>
 #include <asm/processor.h>
+#include <dm/device-internal.h>
 
 #include <part.h>
 #include <usb.h>
@@ -106,7 +110,6 @@ struct us_data {
 
 static struct us_data usb_stor[USB_MAX_STOR_DEV];
 
-
 #define USB_STOR_TRANSPORT_GOOD	   0
 #define USB_STOR_TRANSPORT_FAILED -1
 #define USB_STOR_TRANSPORT_ERROR  -2
@@ -119,7 +122,6 @@ unsigned long usb_stor_read(int device, lbaint_t blknr,
 			    lbaint_t blkcnt, void *buffer);
 unsigned long usb_stor_write(int device, lbaint_t blknr,
 			     lbaint_t blkcnt, const void *buffer);
-struct usb_device * usb_get_dev_index(int index);
 void uhci_show_temp_int_td(void);
 
 #ifdef CONFIG_PARTITIONS
@@ -223,6 +225,7 @@ void usb_stor_reset(void)
 	usb_max_devs = 0;
 }
 
+#ifndef CONFIG_DM_USB
 /*******************************************************************************
  * scan the usb and reports device info
  * to the user if mode = 1
@@ -253,6 +256,7 @@ int usb_stor_scan(int mode)
 		return 0;
 	return -1;
 }
+#endif
 
 static int usb_stor_irq(struct usb_device *dev)
 {
@@ -1396,3 +1400,46 @@ int usb_stor_get_info(struct usb_device *dev, struct us_data *ss,
 	debug("partype: %d\n", dev_desc->part_type);
 	return 1;
 }
+
+#ifdef CONFIG_DM_USB
+
+static int usb_mass_storage_probe(struct udevice *dev)
+{
+	struct usb_device *udev = dev_get_parentdata(dev);
+	int ret;
+
+	usb_disable_asynch(1); /* asynch transfer not allowed */
+	ret = usb_stor_probe_device(udev);
+	usb_disable_asynch(0); /* asynch transfer allowed */
+
+	return ret;
+}
+
+static const struct udevice_id usb_mass_storage_ids[] = {
+	{ .compatible = "usb-mass-storage" },
+	{ }
+};
+
+U_BOOT_DRIVER(usb_mass_storage) = {
+	.name	= "usb_mass_storage",
+	.id	= UCLASS_MASS_STORAGE,
+	.of_match = usb_mass_storage_ids,
+	.probe = usb_mass_storage_probe,
+};
+
+UCLASS_DRIVER(usb_mass_storage) = {
+	.id		= UCLASS_MASS_STORAGE,
+	.name		= "usb_mass_storage",
+};
+
+static const struct usb_device_id mass_storage_id_table[] = {
+	{
+		.match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
+		.bInterfaceClass = USB_CLASS_MASS_STORAGE
+	},
+	{ }		/* Terminating entry */
+};
+
+USB_DEVICE(usb_mass_storage, mass_storage_id_table);
+
+#endif
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#57 lore raw

PATCH v2 28/80 dm: usb: Convert usb_storage to driver model

Quoted 10 lines · Simon Glass

Add support for scanning USB storage devices with driver model. This mostly involves adding a USB device ID for storage devices.

---

Changes in v2: None

 common/usb_storage.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 49 insertions(+), 2 deletions(-)

Applied to u-boot-dm/next.

#58 lore raw

PATCH v2 29/80 dm: usb: Move all the EHCI weak functions together and declare them

In reply to Simon Glass

Put these at the top of the file so they are in one place. Also add function prototypes to the header file to avoid call site mismatches.

---

Changes in v2: None

 drivers/usb/host/ehci-hcd.c | 22 +++++++++++-----------
 drivers/usb/host/ehci.h     |  6 ++++++
 2 files changed, 17 insertions(+), 11 deletions(-)
drivers/usb/host/ehci-hcd.c +11 -11
index f1fb190..10a0671 100644
@@ -143,6 +143,17 @@ __weak void ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg)
 	mdelay(50);
 }
 
+__weak uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
+{
+	if (port < 0 || port >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
+		/* Printing the message would cause a scan failure! */
+		debug("The request port(%u) is not configured\n", port);
+		return NULL;
+	}
+
+	return (uint32_t *)&hcor->or_portsc[port];
+}
+
 static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec)
 {
 	uint32_t result;
@@ -649,17 +660,6 @@ fail:
 	return -1;
 }
 
-__weak uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
-{
-	if (port < 0 || port >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
-		/* Printing the message would cause a scan failure! */
-		debug("The request port(%u) is not configured\n", port);
-		return NULL;
-	}
-
-	return (uint32_t *)&hcor->or_portsc[port];
-}
-
 int
 ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 		 int length, struct devrequest *req)
drivers/usb/host/ehci.h +6 -0
index 79aecd4..3e5427a 100644
@@ -250,6 +250,12 @@ struct ehci_ctrl {
 	int ntds;
 };
 
+/* Weak functions that drivers can override */
+int ehci_get_port_speed(struct ehci_hcor *hcor, uint32_t reg);
+void ehci_set_usbmode(int index);
+void ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg);
+uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port);
+
 /* Low level init functions */
 int ehci_hcd_init(int index, enum usb_init_type init,
 		struct ehci_hccr **hccr, struct ehci_hcor **hcor);
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#59 lore raw

PATCH v2 29/80 dm: usb: Move all the EHCI weak functions together and declare them

Quoted 11 lines · Simon Glass

Put these at the top of the file so they are in one place. Also add function prototypes to the header file to avoid call site mismatches.

---

Changes in v2: None

 drivers/usb/host/ehci-hcd.c | 22 +++++++++++-----------
 drivers/usb/host/ehci.h     |  6 ++++++
 2 files changed, 17 insertions(+), 11 deletions(-)

Applied to u-boot-dm/next.

#60 lore raw

PATCH v2 30/80 dm: usb: Pass EHCI controller pointer to ehci_get_port_speed()

In reply to Simon Glass

Adjust this function so that it is passed an EHCI controller pointer so that implementations can look up their controller.

---

Changes in v2: None

 drivers/usb/host/ehci-faraday.c | 5 +++--
 drivers/usb/host/ehci-hcd.c     | 4 ++--
 drivers/usb/host/ehci-tegra.c   | 5 +++--
 drivers/usb/host/ehci.h         | 2 +-
 4 files changed, 9 insertions(+), 7 deletions(-)
drivers/usb/host/ehci-faraday.c +3 -2
index 3b761bc..e386813 100644
@@ -101,11 +101,12 @@ void ehci_set_usbmode(int index)
  * This ehci_get_port_speed() overrides the weak function
  * in "ehci-hcd.c".
  */
-int ehci_get_port_speed(struct ehci_hcor *hcor, uint32_t reg)
+int ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg)
 {
 	int spd, ret = PORTSC_PSPD_HS;
-	union ehci_faraday_regs *regs = (void __iomem *)((ulong)hcor - 0x10);
+	union ehci_faraday_regs *regs;
 
+	ret = (void __iomem *)((ulong)ctrl->hcor - 0x10);
 	if (ehci_is_fotg2xx(regs))
 		spd = OTGCSR_SPD(readl(&regs->otg.otgcsr));
 	else
drivers/usb/host/ehci-hcd.c +2 -2
index 10a0671..fed3942 100644
@@ -119,7 +119,7 @@ static struct descriptor {
 #define ehci_is_TDI()	(0)
 #endif
 
-__weak int ehci_get_port_speed(struct ehci_hcor *hcor, uint32_t reg)
+__weak int ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg)
 {
 	return PORTSC_PSPD(reg);
 }
@@ -781,7 +781,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 			tmpbuf[1] |= USB_PORT_STAT_POWER >> 8;
 
 		if (ehci_is_TDI()) {
-			switch (ehci_get_port_speed(ctrl->hcor, reg)) {
+			switch (ehci_get_port_speed(ctrl, reg)) {
 			case PORTSC_PSPD_FS:
 				break;
 			case PORTSC_PSPD_LS:
drivers/usb/host/ehci-tegra.c +3 -2
index b5ad1e3..0831fe9 100644
@@ -225,13 +225,14 @@ void ehci_set_usbmode(int index)
  * This ehci_get_port_speed overrides the weak function ehci_get_port_speed
  * in "ehci-hcd.c".
  */
-int ehci_get_port_speed(struct ehci_hcor *hcor, uint32_t reg)
+int ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg)
 {
 	uint32_t tmp;
 	uint32_t *reg_ptr;
 
 	if (controller->has_hostpc) {
-		reg_ptr = (uint32_t *)((u8 *)&hcor->or_usbcmd + HOSTPC1_DEVLC);
+		reg_ptr = (uint32_t *)((u8 *)&ctrl->hcor->or_usbcmd +
+				HOSTPC1_DEVLC);
 		tmp = ehci_readl(reg_ptr);
 		return HOSTPC1_PSPD(tmp);
 	} else
drivers/usb/host/ehci.h +1 -1
index 3e5427a..ec4d6b0 100644
@@ -251,7 +251,7 @@ struct ehci_ctrl {
 };
 
 /* Weak functions that drivers can override */
-int ehci_get_port_speed(struct ehci_hcor *hcor, uint32_t reg);
+int ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg);
 void ehci_set_usbmode(int index);
 void ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg);
 uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port);
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#61 lore raw

PATCH v2 30/80 dm: usb: Pass EHCI controller pointer to ehci_get_port_speed()

Quoted 6 lines · Simon Glass

Adjust this function so that it is passed an EHCI controller pointer so that implementations can look up their controller.

---

Quoted 7 lines

Changes in v2: None

 drivers/usb/host/ehci-faraday.c | 5 +++--
 drivers/usb/host/ehci-hcd.c     | 4 ++--
 drivers/usb/host/ehci-tegra.c   | 5 +++--
 drivers/usb/host/ehci.h         | 2 +-
 4 files changed, 9 insertions(+), 7 deletions(-)

Applied to u-boot-dm/next.

#62 lore raw

PATCH v2 31/80 dm: usb: Allow ECHI to hold private data for the controller

In reply to Simon Glass

Add a private data pointer that clients of EHCI can use to access their private information. This establishes a link between struct ehci_ctrl and its associated controller data structure.

---

Changes in v2: None

 drivers/usb/host/ehci-hcd.c | 10 ++++++++++
 drivers/usb/host/ehci.h     | 21 +++++++++++++++++++++
 2 files changed, 31 insertions(+)
drivers/usb/host/ehci-hcd.c +10 -0
index fed3942..d85308f 100644
@@ -930,6 +930,16 @@ unknown:
 	return -1;
 }
 
+void ehci_set_controller_priv(int index, void *priv)
+{
+	ehcic[index].priv = priv;
+}
+
+void *ehci_get_controller_priv(int index)
+{
+	return ehcic[index].priv;
+}
+
 int usb_lowlevel_stop(int index)
 {
 	ehci_shutdown(&ehcic[index]);
drivers/usb/host/ehci.h +21 -0
index ec4d6b0..d538bb6 100644
@@ -248,6 +248,7 @@ struct ehci_ctrl {
 	uint32_t *periodic_list;
 	int periodic_schedules;
 	int ntds;
+	void *priv;	/* client's private data */
 };
 
 /* Weak functions that drivers can override */
@@ -256,6 +257,26 @@ void ehci_set_usbmode(int index);
 void ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg);
 uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port);
 
+/**
+ * ehci_set_controller_priv() - Set up private data for the controller
+ *
+ * This function can be called in ehci_hcd_init() to tell the EHCI layer
+ * about the controller's private data pointer. Then in the above functions
+ * this can be accessed given the struct ehci_ctrl pointer.
+ *
+ * @index:	Controller number to set
+ * @priv:	Controller pointer
+ */
+void ehci_set_controller_priv(int index, void *priv);
+
+/**
+ * ehci_get_controller_priv() - Get controller private data
+ *
+ * @index	Controller number to get
+ * @return controller pointer for this index
+ */
+void *ehci_get_controller_priv(int index);
+
 /* Low level init functions */
 int ehci_hcd_init(int index, enum usb_init_type init,
 		struct ehci_hccr **hccr, struct ehci_hcor **hcor);
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#63 lore raw

PATCH v2 31/80 dm: usb: Allow ECHI to hold private data for the controller

Quoted 4 lines · Simon Glass

Add a private data pointer that clients of EHCI can use to access their private information. This establishes a link between struct ehci_ctrl and its associated controller data structure.

Quoted 8 lines

---

Changes in v2: None

 drivers/usb/host/ehci-hcd.c | 10 ++++++++++
 drivers/usb/host/ehci.h     | 21 +++++++++++++++++++++
 2 files changed, 31 insertions(+)

Applied to u-boot-dm/next.

#64 lore raw

PATCH v2 32/80 dm: usb: tegra: Store the controller type explicitly

In reply to Simon Glass

At present the tegra driver uses a separate pointer to know which controller type is in use. This works because only one controller type is used at a time.

With driver model we want to make the controller state hermetic in the sense that it is not necessary to look elsewhere to know the controller type. This will permit a controller to implement the EHCI weak functions without reference to global data structures.

To achieve this, define an enum for the controller type and store it with the information on each EHCI controller.

---

Changes in v2: None

 drivers/usb/host/ehci-tegra.c | 30 ++++++++++++++++++++++++------
 1 file changed, 24 insertions(+), 6 deletions(-)
drivers/usb/host/ehci-tegra.c +24 -6
index 0831fe9..9a73e60 100644
@@ -61,6 +61,14 @@ enum dr_mode {
 	DR_MODE_OTG,		/* supports both */
 };
 
+enum usb_ctlr_type {
+	USB_CTLR_T20,
+	USB_CTLR_T30,
+	USB_CTLR_T114,
+
+	USB_CTRL_COUNT,
+};
+
 /* Information about a USB port */
 struct fdt_usb {
 	struct usb_ctlr *reg;	/* address of registers in physical memory */
@@ -69,6 +77,7 @@ struct fdt_usb {
 	unsigned enabled:1;	/* 1 to enable, 0 to disable */
 	unsigned has_legacy_mode:1; /* 1 if this port has legacy mode */
 	unsigned initialized:1; /* has this port already been initialized? */
+	enum usb_ctlr_type type;
 	enum usb_init_type init_type;
 	enum dr_mode dr_mode;	/* dual role mode */
 	enum periph_id periph_id;/* peripheral id */
@@ -162,7 +171,7 @@ struct fdt_usb_controller {
 	const unsigned *pll_parameter;
 };
 
-static struct fdt_usb_controller fdt_usb_controllers[] = {
+static struct fdt_usb_controller fdt_usb_controllers[USB_CTRL_COUNT] = {
 	{
 		.compat		= COMPAT_NVIDIA_TEGRA20_USB,
 		.has_hostpc	= 0,
@@ -284,7 +293,7 @@ void usbf_reset_controller(struct fdt_usb *config, struct usb_ctlr *usbctlr)
 		setbits_le32(&usbctlr->susp_ctrl, UTMIP_PHY_ENB);
 }
 
-static const unsigned *get_pll_timing(void)
+static const unsigned *get_pll_timing(struct fdt_usb_controller *controller)
 {
 	const unsigned *timing;
 
@@ -331,6 +340,7 @@ static void init_phy_mux(struct fdt_usb *config, uint pts,
 static int init_utmi_usb_controller(struct fdt_usb *config,
 				    enum usb_init_type init)
 {
+	struct fdt_usb_controller *controller;
 	u32 b_sess_valid_mask, val;
 	int loop_count;
 	const unsigned *timing;
@@ -363,11 +373,14 @@ static int init_utmi_usb_controller(struct fdt_usb *config,
 			VBUS_SENSE_CTL_MASK,
 			VBUS_SENSE_CTL_A_SESS_VLD << VBUS_SENSE_CTL_SHIFT);
 
+	controller = &fdt_usb_controllers[config->type];
+	debug("controller=%p, type=%d\n", controller, config->type);
+
 	/*
 	 * PLL Delay CONFIGURATION settings. The following parameters control
 	 * the bring up of the plls.
 	 */
-	timing = get_pll_timing();
+	timing = get_pll_timing(controller);
 
 	if (!controller->has_hostpc) {
 		val = readl(&usbctlr->utmip_misc_cfg1);
@@ -702,10 +715,12 @@ static int fdt_decode_usb(const void *blob, int node, struct fdt_usb *config)
  * @blob:	fdt blob
  * @node_list:	list of nodes to process (any <=0 are ignored)
  * @count:	number of nodes to process
+ * @id:		controller type (enum usb_ctlr_type)
  *
  * Return:	0 - ok, -1 - error
  */
-static int process_usb_nodes(const void *blob, int node_list[], int count)
+static int process_usb_nodes(const void *blob, int node_list[], int count,
+			     enum usb_ctlr_type id)
 {
 	struct fdt_usb config;
 	int node, i;
@@ -729,9 +744,11 @@ static int process_usb_nodes(const void *blob, int node_list[], int count)
 			return -1;
 		}
 		if (!clk_done) {
-			config_clock(get_pll_timing());
+			config_clock(get_pll_timing(
+					&fdt_usb_controllers[id]));
 			clk_done = 1;
 		}
+		config.type = id;
 		config.initialized = 0;
 
 		/* add new USB port to the list of available ports */
@@ -753,7 +770,7 @@ int usb_process_devicetree(const void *blob)
 		count = fdtdec_find_aliases_for_id(blob, "usb",
 			controller->compat, node_list, USB_PORTS_MAX);
 		if (count) {
-			err = process_usb_nodes(blob, node_list, count);
+			err = process_usb_nodes(blob, node_list, count, i);
 			if (err)
 				printf("%s: Error processing USB node!\n",
 				       __func__);
@@ -786,6 +803,7 @@ int ehci_hcd_init(int index, enum usb_init_type init,
 		return -1;
 
 	config = &port[index];
+	ehci_set_controller_priv(index, config);
 
 	switch (init) {
 	case USB_INIT_HOST:
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#65 lore raw

PATCH v2 32/80 dm: usb: tegra: Store the controller type explicitly

Quoted 12 lines · Simon Glass

At present the tegra driver uses a separate pointer to know which controller type is in use. This works because only one controller type is used at a time.

With driver model we want to make the controller state hermetic in the sense that it is not necessary to look elsewhere to know the controller type. This will permit a controller to implement the EHCI weak functions without reference to global data structures.

To achieve this, define an enum for the controller type and store it with the information on each EHCI controller.

Quoted 7 lines

---

Changes in v2: None

 drivers/usb/host/ehci-tegra.c | 30 ++++++++++++++++++++++++------
 1 file changed, 24 insertions(+), 6 deletions(-)

Applied to u-boot-dm/next.

#66 lore raw

PATCH v2 33/80 dm: usb: Pass EHCI controller pointer to ehci_powerup_fixup()

In reply to Simon Glass

Adjust this function so that it is passed an EHCI controller pointer so that implementations can look up their controller.

---

Changes in v2: None

 board/genesi/mx51_efikamx/efikamx-usb.c | 3 ++-
 drivers/usb/host/ehci-hcd.c             | 5 +++--
 drivers/usb/host/ehci-tegra.c           | 3 ++-
 drivers/usb/host/ehci.h                 | 3 ++-
 4 files changed, 9 insertions(+), 5 deletions(-)
board/genesi/mx51_efikamx/efikamx-usb.c +2 -1
index 0b43101..0c0b8d3 100644
@@ -173,7 +173,8 @@ int board_ehci_hcd_init(int port)
 	return 0;
 }
 
-void ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg)
+void ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
+			uint32_t *reg)
 {
 	uint32_t port = OTG_BASE_ADDR + (0x200 * CONFIG_MXC_USB_PORT);
 	struct usb_ehci *ehci = (struct usb_ehci *)port;
drivers/usb/host/ehci-hcd.c +3 -2
index d85308f..e9f58e3 100644
@@ -138,7 +138,8 @@ __weak void ehci_set_usbmode(int index)
 	ehci_writel(reg_ptr, tmp);
 }
 
-__weak void ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg)
+__weak void ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
+			       uint32_t *reg)
 {
 	mdelay(50);
 }
@@ -843,7 +844,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 				 * usb 2.0 specification say 50 ms resets on
 				 * root
 				 */
-				ehci_powerup_fixup(status_reg, &reg);
+				ehci_powerup_fixup(ctrl, status_reg, &reg);
 
 				ehci_writel(status_reg, reg & ~EHCI_PS_PR);
 				/*
drivers/usb/host/ehci-tegra.c +2 -1
index 9a73e60..5d746f2 100644
@@ -198,7 +198,8 @@ static struct fdt_usb_controller *controller;
  * This ehci_powerup_fixup overrides the weak function ehci_powerup_fixup
  * in "ehci-hcd.c".
  */
-void ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg)
+void ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
+			uint32_t *reg)
 {
 	mdelay(50);
 	/* This is to avoid PORT_ENABLE bit to be cleared in "ehci-hcd.c". */
drivers/usb/host/ehci.h +2 -1
index d538bb6..a00c7e7 100644
@@ -254,7 +254,8 @@ struct ehci_ctrl {
 /* Weak functions that drivers can override */
 int ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg);
 void ehci_set_usbmode(int index);
-void ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg);
+void ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
+			uint32_t *reg);
 uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port);
 
 /**
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#67 lore raw

PATCH v2 33/80 dm: usb: Pass EHCI controller pointer to ehci_powerup_fixup()

Quoted 6 lines · Simon Glass

Adjust this function so that it is passed an EHCI controller pointer so that implementations can look up their controller.

---

Quoted 7 lines

Changes in v2: None

 board/genesi/mx51_efikamx/efikamx-usb.c | 3 ++-
 drivers/usb/host/ehci-hcd.c             | 5 +++--
 drivers/usb/host/ehci-tegra.c           | 3 ++-
 drivers/usb/host/ehci.h                 | 3 ++-
 4 files changed, 9 insertions(+), 5 deletions(-)

Applied to u-boot-dm/next.

#68 lore raw

PATCH v2 34/80 dm: usb: tegra: Drop use of global controller variable

In reply to Simon Glass

We don't need this anymore, so adjust the code to avoid using it.

---

Changes in v2: None

 drivers/usb/host/ehci-tegra.c | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)
drivers/usb/host/ehci-tegra.c +9 -7
index 5d746f2..5060dd1 100644
@@ -189,8 +189,6 @@ static struct fdt_usb_controller fdt_usb_controllers[USB_CTRL_COUNT] = {
 	},
 };
 
-static struct fdt_usb_controller *controller;
-
 /*
  * A known hardware issue where Connect Status Change bit of PORTSC register
  * of USB1 controller will be set after Port Reset.
@@ -201,6 +199,10 @@ static struct fdt_usb_controller *controller;
 void ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
 			uint32_t *reg)
 {
+	struct fdt_usb *config = ctrl->priv;
+	struct fdt_usb_controller *controller;
+
+	controller = &fdt_usb_controllers[config->type];
 	mdelay(50);
 	/* This is to avoid PORT_ENABLE bit to be cleared in "ehci-hcd.c". */
 	if (controller->has_hostpc)
@@ -237,9 +239,12 @@ void ehci_set_usbmode(int index)
  */
 int ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg)
 {
+	struct fdt_usb *config = ctrl->priv;
+	struct fdt_usb_controller *controller;
 	uint32_t tmp;
 	uint32_t *reg_ptr;
 
+	controller = &fdt_usb_controllers[config->type];
 	if (controller->has_hostpc) {
 		reg_ptr = (uint32_t *)((u8 *)&ctrl->hcor->or_usbcmd +
 				HOSTPC1_DEVLC);
@@ -766,10 +771,9 @@ int usb_process_devicetree(const void *blob)
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(fdt_usb_controllers); i++) {
-		controller = &fdt_usb_controllers[i];
-
 		count = fdtdec_find_aliases_for_id(blob, "usb",
-			controller->compat, node_list, USB_PORTS_MAX);
+			fdt_usb_controllers[i].compat, node_list,
+			USB_PORTS_MAX);
 		if (count) {
 			err = process_usb_nodes(blob, node_list, count, i);
 			if (err)
@@ -778,8 +782,6 @@ int usb_process_devicetree(const void *blob)
 			return err;
 		}
 	}
-	if (i == ARRAY_SIZE(fdt_usb_controllers))
-		controller = NULL;
 
 	return err;
 }
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#69 lore raw

PATCH v2 34/80 dm: usb: tegra: Drop use of global controller variable

Quoted 9 lines · Simon Glass

We don't need this anymore, so adjust the code to avoid using it.

---

Changes in v2: None

 drivers/usb/host/ehci-tegra.c | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

Applied to u-boot-dm/next.

#70 lore raw

PATCH v2 35/80 dm: usb: Pass EHCI controller pointer to ehci_set_usbmode()

In reply to Simon Glass

Adjust this function so that it is passed an EHCI controller pointer so that implementations can look up their controller. This makes the weak functions use a consistent API.

---

Changes in v2: None

 drivers/usb/host/ehci-faraday.c | 2 +-
 drivers/usb/host/ehci-hcd.c     | 6 +++---
 drivers/usb/host/ehci-tegra.c   | 5 ++---
 drivers/usb/host/ehci.h         | 2 +-
 4 files changed, 7 insertions(+), 8 deletions(-)
drivers/usb/host/ehci-faraday.c +1 -1
index e386813..c64672b 100644
@@ -92,7 +92,7 @@ int ehci_hcd_stop(int index)
  * This ehci_set_usbmode() overrides the weak function
  * in "ehci-hcd.c".
  */
-void ehci_set_usbmode(int index)
+void ehci_set_usbmode(struct ehci_ctrl *ctrl)
 {
 	/* nothing needs to be done */
 }
drivers/usb/host/ehci-hcd.c +3 -3
index e9f58e3..196e23a 100644
@@ -124,12 +124,12 @@ __weak int ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg)
 	return PORTSC_PSPD(reg);
 }
 
-__weak void ehci_set_usbmode(int index)
+__weak void ehci_set_usbmode(struct ehci_ctrl *ctrl)
 {
 	uint32_t tmp;
 	uint32_t *reg_ptr;
 
-	reg_ptr = (uint32_t *)((u8 *)&ehcic[index].hcor->or_usbcmd + USBMODE);
+	reg_ptr = (uint32_t *)((u8 *)&ctrl->hcor->or_usbcmd + USBMODE);
 	tmp = ehci_readl(reg_ptr);
 	tmp |= USBMODE_CM_HC;
 #if defined(CONFIG_EHCI_MMIO_BIG_ENDIAN)
@@ -187,7 +187,7 @@ static int ehci_reset(int index)
 	}
 
 	if (ehci_is_TDI())
-		ehci_set_usbmode(index);
+		ehci_set_usbmode(&ehcic[index]);
 
 #ifdef CONFIG_USB_EHCI_TXFIFO_THRESH
 	cmd = ehci_readl(&ehcic[index].hcor->or_txfilltuning);
drivers/usb/host/ehci-tegra.c +2 -3
index 5060dd1..6054b2b 100644
@@ -219,13 +219,12 @@ void ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
  * This ehci_set_usbmode overrides the weak function ehci_set_usbmode
  * in "ehci-hcd.c".
  */
-void ehci_set_usbmode(int index)
+void ehci_set_usbmode(struct ehci_ctrl *ctrl)
 {
-	struct fdt_usb *config;
+	struct fdt_usb *config = ctrl->priv;
 	struct usb_ctlr *usbctlr;
 	uint32_t tmp;
 
-	config = &port[index];
 	usbctlr = config->reg;
 
 	tmp = ehci_readl(&usbctlr->usb_mode);
drivers/usb/host/ehci.h +1 -1
index a00c7e7..164b3cb 100644
@@ -253,7 +253,7 @@ struct ehci_ctrl {
 
 /* Weak functions that drivers can override */
 int ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg);
-void ehci_set_usbmode(int index);
+void ehci_set_usbmode(struct ehci_ctrl *ctrl);
 void ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
 			uint32_t *reg);
 uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port);
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#71 lore raw

PATCH v2 35/80 dm: usb: Pass EHCI controller pointer to ehci_set_usbmode()

Quoted 7 lines · Simon Glass

Adjust this function so that it is passed an EHCI controller pointer so that implementations can look up their controller. This makes the weak functions use a consistent API.

---

Quoted 7 lines

Changes in v2: None

 drivers/usb/host/ehci-faraday.c | 2 +-
 drivers/usb/host/ehci-hcd.c     | 6 +++---
 drivers/usb/host/ehci-tegra.c   | 5 ++---
 drivers/usb/host/ehci.h         | 2 +-
 4 files changed, 7 insertions(+), 8 deletions(-)

Applied to u-boot-dm/next.

#72 lore raw

PATCH v2 36/80 dm: usb: Pass EHCI controller pointer to ehci_get_portsc_register()

In reply to Simon Glass

Adjust this function so that it is passed an EHCI controller pointer so that implementations can look up their controller. This makes the weak functions use a consistent API.

---

Changes in v2: None

 drivers/usb/host/ehci-faraday.c | 4 ++--
 drivers/usb/host/ehci-hcd.c     | 6 +++---
 drivers/usb/host/ehci.h         | 2 +-
 3 files changed, 6 insertions(+), 6 deletions(-)
drivers/usb/host/ehci-faraday.c +2 -2
index c64672b..b865fea 100644
@@ -134,7 +134,7 @@ int ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg)
  * This ehci_get_portsc_register() overrides the weak function
  * in "ehci-hcd.c".
  */
-uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
+uint32_t *ehci_get_portsc_register(struct ehci_ctrl *ctrl, int port)
 {
 	/* Faraday EHCI has one and only one portsc register */
 	if (port) {
@@ -144,5 +144,5 @@ uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
 	}
 
 	/* Faraday EHCI PORTSC register offset is 0x20 from hcor */
-	return (uint32_t *)((uint8_t *)hcor + 0x20);
+	return (uint32_t *)((uint8_t *)ctrl->hcor + 0x20);
 }
drivers/usb/host/ehci-hcd.c +3 -3
index 196e23a..4b0074e 100644
@@ -144,7 +144,7 @@ __weak void ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
 	mdelay(50);
 }
 
-__weak uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
+__weak uint32_t *ehci_get_portsc_register(struct ehci_ctrl *ctrl, int port)
 {
 	if (port < 0 || port >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
 		/* Printing the message would cause a scan failure! */
@@ -152,7 +152,7 @@ __weak uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
 		return NULL;
 	}
 
-	return (uint32_t *)&hcor->or_portsc[port];
+	return (uint32_t *)&ctrl->hcor->or_portsc[port];
 }
 
 static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec)
@@ -687,7 +687,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 	case USB_REQ_GET_STATUS | ((USB_RT_PORT | USB_DIR_IN) << 8):
 	case USB_REQ_SET_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
 	case USB_REQ_CLEAR_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
-		status_reg = ehci_get_portsc_register(ctrl->hcor, port - 1);
+		status_reg = ehci_get_portsc_register(ctrl, port - 1);
 		if (!status_reg)
 			return -1;
 		break;
drivers/usb/host/ehci.h +1 -1
index 164b3cb..0fd59bc 100644
@@ -256,7 +256,7 @@ int ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg);
 void ehci_set_usbmode(struct ehci_ctrl *ctrl);
 void ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
 			uint32_t *reg);
-uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port);
+uint32_t *ehci_get_portsc_register(struct ehci_ctrl *ctrl, int port);
 
 /**
  * ehci_set_controller_priv() - Set up private data for the controller
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#73 lore raw

PATCH v2 36/80 dm: usb: Pass EHCI controller pointer to ehci_get_portsc_register()

Quoted 5 lines · Simon Glass

Adjust this function so that it is passed an EHCI controller pointer so that implementations can look up their controller. This makes the weak functions use a consistent API.

Quoted 8 lines

---

Changes in v2: None

 drivers/usb/host/ehci-faraday.c | 4 ++--
 drivers/usb/host/ehci-hcd.c     | 6 +++---
 drivers/usb/host/ehci.h         | 2 +-
 3 files changed, 6 insertions(+), 6 deletions(-)

Applied to u-boot-dm/next.

#74 lore raw

PATCH v2 37/80 dm: usb: ehci: Use a function to find the controller from struct udevice

In reply to Simon Glass

With driver model we want to remove the controller pointer in struct udevice and use driver model data structures instead. To prepare for this, move access to this field to a function which can provide a different implementation for driver model.

---

Changes in v2: None

 drivers/usb/host/ehci-hcd.c | 54 +++++++++++++++++++++++++++++++--------------
 1 file changed, 37 insertions(+), 17 deletions(-)
drivers/usb/host/ehci-hcd.c +37 -17
index 4b0074e..d01e17e 100644
@@ -119,6 +119,11 @@ static struct descriptor {
 #define ehci_is_TDI()	(0)
 #endif
 
+static struct ehci_ctrl *ehci_get_ctrl(struct usb_device *udev)
+{
+	return udev->controller;
+}
+
 __weak int ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg)
 {
 	return PORTSC_PSPD(reg);
@@ -315,7 +320,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 	uint32_t cmd;
 	int timeout;
 	int ret = 0;
-	struct ehci_ctrl *ctrl = dev->controller;
+	struct ehci_ctrl *ctrl = ehci_get_ctrl(dev);
 
 	debug("dev=%p, pipe=%lx, buffer=%p, length=%d, req=%p\n", dev, pipe,
 	      buffer, length, req);
@@ -661,9 +666,8 @@ fail:
 	return -1;
 }
 
-int
-ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
-		 int length, struct devrequest *req)
+static int ehci_submit_root(struct usb_device *dev, unsigned long pipe,
+			    void *buffer, int length, struct devrequest *req)
 {
 	uint8_t tmpbuf[4];
 	u16 typeReq;
@@ -672,7 +676,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 	uint32_t reg;
 	uint32_t *status_reg;
 	int port = le16_to_cpu(req->index) & 0xff;
-	struct ehci_ctrl *ctrl = dev->controller;
+	struct ehci_ctrl *ctrl = ehci_get_ctrl(dev);
 
 	srclen = 0;
 
@@ -1075,9 +1079,8 @@ done:
 	return 0;
 }
 
-int
-submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
-		int length)
+static int _ehci_submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
+				 void *buffer, int length)
 {
 
 	if (usb_pipetype(pipe) != PIPE_BULK) {
@@ -1087,11 +1090,11 @@ submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
 	return ehci_submit_async(dev, pipe, buffer, length, NULL);
 }
 
-int
-submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
-		   int length, struct devrequest *setup)
+static int _ehci_submit_control_msg(struct usb_device *dev, unsigned long pipe,
+				    void *buffer, int length,
+				    struct devrequest *setup)
 {
-	struct ehci_ctrl *ctrl = dev->controller;
+	struct ehci_ctrl *ctrl = ehci_get_ctrl(dev);
 
 	if (usb_pipetype(pipe) != PIPE_CONTROL) {
 		debug("non-control pipe (type=%lu)", usb_pipetype(pipe));
@@ -1161,7 +1164,7 @@ struct int_queue *
 create_int_queue(struct usb_device *dev, unsigned long pipe, int queuesize,
 		 int elementsize, void *buffer, int interval)
 {
-	struct ehci_ctrl *ctrl = dev->controller;
+	struct ehci_ctrl *ctrl = ehci_get_ctrl(dev);
 	struct int_queue *result = NULL;
 	int i;
 
@@ -1353,7 +1356,7 @@ void *poll_int_queue(struct usb_device *dev, struct int_queue *queue)
 int
 destroy_int_queue(struct usb_device *dev, struct int_queue *queue)
 {
-	struct ehci_ctrl *ctrl = dev->controller;
+	struct ehci_ctrl *ctrl = ehci_get_ctrl(dev);
 	int result = -1;
 	unsigned long timeout;
 
@@ -1397,9 +1400,8 @@ out:
 	return result;
 }
 
-int
-submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
-	       int length, int interval)
+static int _ehci_submit_int_msg(struct usb_device *dev, unsigned long pipe,
+				void *buffer, int length, int interval)
 {
 	void *backbuffer;
 	struct int_queue *queue;
@@ -1434,3 +1436,21 @@ submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
 	/* everything worked out fine */
 	return result;
 }
+
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
+			    void *buffer, int length)
+{
+	return _ehci_submit_bulk_msg(dev, pipe, buffer, length);
+}
+
+int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+		   int length, struct devrequest *setup)
+{
+	return _ehci_submit_control_msg(dev, pipe, buffer, length, setup);
+}
+
+int submit_int_msg(struct usb_device *dev, unsigned long pipe,
+		   void *buffer, int length, int interval)
+{
+	return _ehci_submit_int_msg(dev, pipe, buffer, length, interval);
+}
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#75 lore raw

PATCH v2 37/80 dm: usb: ehci: Use a function to find the controller from struct udevice

Quoted 5 lines · Simon Glass

With driver model we want to remove the controller pointer in struct udevice and use driver model data structures instead. To prepare for this, move access to this field to a function which can provide a different implementation for driver model.

Quoted 7 lines

---

Changes in v2: None

 drivers/usb/host/ehci-hcd.c | 54 +++++++++++++++++++++++++++++++--------------
 1 file changed, 37 insertions(+), 17 deletions(-)

Applied to u-boot-dm/next.

#76 lore raw

PATCH v2 38/80 dm: usb: Refactor EHCI init

In reply to Simon Glass

Move the bulk of the code in usb_lowlevel_init() into a separate function which will also be used by driver model. Keep the CONFIG options out of this function by providing a tweak flag for Faraday. We need to avoid using CONFIG options in driver model code where possible, since it makes it impossible to use multiple controllers in that code where they have different options.

The CONFIG_EHCI_HCD_INIT_AFTER_RESET option is also kept out of the common init function. With driver model the controller will be able to perform this extra init itself after registering with the EHCI layer.

---

Changes in v2: None

 drivers/usb/host/ehci-hcd.c | 117 +++++++++++++++++++++++++-------------------
 drivers/usb/host/ehci.h     |   6 +++
 2 files changed, 72 insertions(+), 51 deletions(-)
drivers/usb/host/ehci-hcd.c +66 -51
index d01e17e..3fa6fe2 100644
@@ -945,41 +945,19 @@ void *ehci_get_controller_priv(int index)
 	return ehcic[index].priv;
 }
 
-int usb_lowlevel_stop(int index)
-{
-	ehci_shutdown(&ehcic[index]);
-	return ehci_hcd_stop(index);
-}
-
-int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
+static int ehci_common_init(struct ehci_ctrl *ctrl, uint tweaks)
 {
-	uint32_t reg;
-	uint32_t cmd;
 	struct QH *qh_list;
 	struct QH *periodic;
+	uint32_t reg;
+	uint32_t cmd;
 	int i;
-	int rc;
-
-	rc = ehci_hcd_init(index, init, &ehcic[index].hccr, &ehcic[index].hcor);
-	if (rc)
-		return rc;
-	if (init == USB_INIT_DEVICE)
-		goto done;
-
-	/* EHCI spec section 4.1 */
-	if (ehci_reset(index))
-		return -1;
 
-#if defined(CONFIG_EHCI_HCD_INIT_AFTER_RESET)
-	rc = ehci_hcd_init(index, init, &ehcic[index].hccr, &ehcic[index].hcor);
-	if (rc)
-		return rc;
-#endif
 	/* Set the high address word (aka segment) for 64-bit controller */
-	if (ehci_readl(&ehcic[index].hccr->cr_hccparams) & 1)
-		ehci_writel(&ehcic[index].hcor->or_ctrldssegment, 0);
+	if (ehci_readl(&ctrl->hccr->cr_hccparams) & 1)
+		ehci_writel(&ctrl->hcor->or_ctrldssegment, 0);
 
-	qh_list = &ehcic[index].qh_list;
+	qh_list = &ctrl->qh_list;
 
 	/* Set head of reclaim list */
 	memset(qh_list, 0, sizeof(*qh_list));
@@ -995,14 +973,14 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
 			   ALIGN_END_ADDR(struct QH, qh_list, 1));
 
 	/* Set async. queue head pointer. */
-	ehci_writel(&ehcic[index].hcor->or_asynclistaddr, (uint32_t)qh_list);
+	ehci_writel(&ctrl->hcor->or_asynclistaddr, (uint32_t)qh_list);
 
 	/*
 	 * Set up periodic list
 	 * Step 1: Parent QH for all periodic transfers.
 	 */
-	ehcic[index].periodic_schedules = 0;
-	periodic = &ehcic[index].periodic_queue;
+	ctrl->periodic_schedules = 0;
+	periodic = &ctrl->periodic_queue;
 	memset(periodic, 0, sizeof(*periodic));
 	periodic->qh_link = cpu_to_hc32(QH_LINK_TERMINATE);
 	periodic->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
@@ -1020,25 +998,25 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
 	 *         Split Transactions will be spread across microframes using
 	 *         S-mask and C-mask.
 	 */
-	if (ehcic[index].periodic_list == NULL)
-		ehcic[index].periodic_list = memalign(4096, 1024 * 4);
+	if (ctrl->periodic_list == NULL)
+		ctrl->periodic_list = memalign(4096, 1024 * 4);
 
-	if (!ehcic[index].periodic_list)
+	if (!ctrl->periodic_list)
 		return -ENOMEM;
 	for (i = 0; i < 1024; i++) {
-		ehcic[index].periodic_list[i] = cpu_to_hc32((uint32_t)periodic
+		ctrl->periodic_list[i] = cpu_to_hc32((uint32_t)periodic
 						| QH_LINK_TYPE_QH);
 	}
 
-	flush_dcache_range((uint32_t)ehcic[index].periodic_list,
-			   ALIGN_END_ADDR(uint32_t, ehcic[index].periodic_list,
+	flush_dcache_range((uint32_t)ctrl->periodic_list,
+			   ALIGN_END_ADDR(uint32_t, ctrl->periodic_list,
 					  1024));
 
 	/* Set periodic list base address */
-	ehci_writel(&ehcic[index].hcor->or_periodiclistbase,
-		(uint32_t)ehcic[index].periodic_list);
+	ehci_writel(&ctrl->hcor->or_periodiclistbase,
+		    (uint32_t)ctrl->periodic_list);
 
-	reg = ehci_readl(&ehcic[index].hccr->cr_hcsparams);
+	reg = ehci_readl(&ctrl->hccr->cr_hcsparams);
 	descriptor.hub.bNbrPorts = HCS_N_PORTS(reg);
 	debug("Register %x NbrPorts %d\n", reg, descriptor.hub.bNbrPorts);
 	/* Port Indicators */
@@ -1051,29 +1029,66 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
 				| 0x01, &descriptor.hub.wHubCharacteristics);
 
 	/* Start the host controller. */
-	cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
+	cmd = ehci_readl(&ctrl->hcor->or_usbcmd);
 	/*
 	 * Philips, Intel, and maybe others need CMD_RUN before the
 	 * root hub will detect new devices (why?); NEC doesn't
 	 */
 	cmd &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
 	cmd |= CMD_RUN;
-	ehci_writel(&ehcic[index].hcor->or_usbcmd, cmd);
+	ehci_writel(&ctrl->hcor->or_usbcmd, cmd);
 
-#ifndef CONFIG_USB_EHCI_FARADAY
-	/* take control over the ports */
-	cmd = ehci_readl(&ehcic[index].hcor->or_configflag);
-	cmd |= FLAG_CF;
-	ehci_writel(&ehcic[index].hcor->or_configflag, cmd);
-#endif
+	if (!(tweaks & EHCI_TWEAK_NO_INIT_CF)) {
+		/* take control over the ports */
+		cmd = ehci_readl(&ctrl->hcor->or_configflag);
+		cmd |= FLAG_CF;
+		ehci_writel(&ctrl->hcor->or_configflag, cmd);
+	}
 
 	/* unblock posted write */
-	cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
+	cmd = ehci_readl(&ctrl->hcor->or_usbcmd);
 	mdelay(5);
-	reg = HC_VERSION(ehci_readl(&ehcic[index].hccr->cr_capbase));
+	reg = HC_VERSION(ehci_readl(&ctrl->hccr->cr_capbase));
 	printf("USB EHCI %x.%02x\n", reg >> 8, reg & 0xff);
 
-	ehcic[index].rootdev = 0;
+	return 0;
+}
+
+int usb_lowlevel_stop(int index)
+{
+	ehci_shutdown(&ehcic[index]);
+	return ehci_hcd_stop(index);
+}
+
+int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
+{
+	struct ehci_ctrl *ctrl = &ehcic[index];
+	uint tweaks = 0;
+	int rc;
+
+	rc = ehci_hcd_init(index, init, &ctrl->hccr, &ctrl->hcor);
+	if (rc)
+		return rc;
+	if (init == USB_INIT_DEVICE)
+		goto done;
+
+	/* EHCI spec section 4.1 */
+	if (ehci_reset(index))
+		return -1;
+
+#if defined(CONFIG_EHCI_HCD_INIT_AFTER_RESET)
+	rc = ehci_hcd_init(index, init, &ctrl->hccr, &ctrl->hcor);
+	if (rc)
+		return rc;
+#endif
+#ifdef CONFIG_USB_EHCI_FARADAY
+	tweaks |= EHCI_TWEAK_NO_INIT_CF;
+#endif
+	rc = ehci_common_init(ctrl, tweaks);
+	if (rc)
+		return rc;
+
+	ctrl->rootdev = 0;
 done:
 	*controller = &ehcic[index];
 	return 0;
drivers/usb/host/ehci.h +6 -0
index 0fd59bc..2ca111a 100644
@@ -238,6 +238,12 @@ struct QH {
 	};
 };
 
+/* Tweak flags for EHCI, used to control operation */
+enum {
+	/* don't use or_configflag in init */
+	EHCI_TWEAK_NO_INIT_CF		= 1 << 0,
+};
+
 struct ehci_ctrl {
 	struct ehci_hccr *hccr;	/* R/O registers, not need for volatile */
 	struct ehci_hcor *hcor;
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#77 lore raw

PATCH v2 38/80 dm: usb: Refactor EHCI init

Quoted 11 lines · Simon Glass

Move the bulk of the code in usb_lowlevel_init() into a separate function which will also be used by driver model. Keep the CONFIG options out of this function by providing a tweak flag for Faraday. We need to avoid using CONFIG options in driver model code where possible, since it makes it impossible to use multiple controllers in that code where they have different options.

The CONFIG_EHCI_HCD_INIT_AFTER_RESET option is also kept out of the common init function. With driver model the controller will be able to perform this extra init itself after registering with the EHCI layer.

Quoted 8 lines

---

Changes in v2: None

 drivers/usb/host/ehci-hcd.c | 117 +++++++++++++++++++++++++-------------------
 drivers/usb/host/ehci.h     |   6 +++
 2 files changed, 72 insertions(+), 51 deletions(-)

Applied to u-boot-dm/next.

#78 lore raw

PATCH v2 39/80 dm: usb: Drop the EHCI weak functions

In reply to Simon Glass

These are a pain with driver model because we might have different EHCI drivers which want to implement them differently. Now that they use consistent function signatures, we can in good conscience move them to a struct.

---

Changes in v2: None

 board/genesi/mx51_efikamx/efikamx-usb.c |   5 +-
 drivers/usb/host/ehci-faraday.c         | 113 +++++++++++++++-----------------
 drivers/usb/host/ehci-hcd.c             |  49 +++++++++++---
 drivers/usb/host/ehci-mx5.c             |  12 ++++
 drivers/usb/host/ehci-tegra.c           |  26 ++++----
 drivers/usb/host/ehci.h                 |  27 +++++---
 6 files changed, 136 insertions(+), 96 deletions(-)
board/genesi/mx51_efikamx/efikamx-usb.c +3 -2
index 0c0b8d3..9dfd249 100644
@@ -173,8 +173,9 @@ int board_ehci_hcd_init(int port)
 	return 0;
 }
 
-void ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
-			uint32_t *reg)
+/* This overrides a weak function */
+void mx5_ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
+			   uint32_t *reg)
 {
 	uint32_t port = OTG_BASE_ADDR + (0x200 * CONFIG_MXC_USB_PORT);
 	struct usb_ehci *ehci = (struct usb_ehci *)port;
drivers/usb/host/ehci-faraday.c +54 -59

128 lines not on this page · raw message

drivers/usb/host/ehci-hcd.c +39 -10

107 lines not on this page · raw message

drivers/usb/host/ehci-mx5.c +12 -0
index 7566c61..d319962 100644
@@ -218,11 +218,23 @@ void __weak board_ehci_hcd_postinit(struct usb_ehci *ehci, int port)
 {
 }
 
+__weak void mx5_ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
+				   uint32_t *reg)
+{
+	mdelay(50);
+}
+
+static const struct ehci_ops mx5_ehci_ops = {
+	.powerup_fixup		= mx5_ehci_powerup_fixup,
+};
+
 int ehci_hcd_init(int index, enum usb_init_type init,
 		struct ehci_hccr **hccr, struct ehci_hcor **hcor)
 {
 	struct usb_ehci *ehci;
 
+	/* The only user for this is efikamx-usb */
+	ehci_set_controller_priv(index, NULL, &mx5_ehci_ops);
 	set_usboh3_clk();
 	enable_usboh3_clk(true);
 	set_usb_phy_clk();
drivers/usb/host/ehci-tegra.c +11 -15
index 6054b2b..38333c7 100644
@@ -193,11 +193,9 @@ static struct fdt_usb_controller fdt_usb_controllers[USB_CTRL_COUNT] = {
  * A known hardware issue where Connect Status Change bit of PORTSC register
  * of USB1 controller will be set after Port Reset.
  * We have to clear it in order for later device enumeration to proceed.
- * This ehci_powerup_fixup overrides the weak function ehci_powerup_fixup
- * in "ehci-hcd.c".
  */
-void ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
-			uint32_t *reg)
+static void tegra_ehci_powerup_fixup(struct ehci_ctrl *ctrl,
+				     uint32_t *status_reg, uint32_t *reg)
 {
 	struct fdt_usb *config = ctrl->priv;
 	struct fdt_usb_controller *controller;
@@ -215,11 +213,7 @@ void ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
 		*reg |= EHCI_PS_CSC;
 }
 
-/*
- * This ehci_set_usbmode overrides the weak function ehci_set_usbmode
- * in "ehci-hcd.c".
- */
-void ehci_set_usbmode(struct ehci_ctrl *ctrl)
+static void tegra_ehci_set_usbmode(struct ehci_ctrl *ctrl)
 {
 	struct fdt_usb *config = ctrl->priv;
 	struct usb_ctlr *usbctlr;
@@ -232,11 +226,7 @@ void ehci_set_usbmode(struct ehci_ctrl *ctrl)
 	ehci_writel(&usbctlr->usb_mode, tmp);
 }
 
-/*
- * This ehci_get_port_speed overrides the weak function ehci_get_port_speed
- * in "ehci-hcd.c".
- */
-int ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg)
+static int tegra_ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg)
 {
 	struct fdt_usb *config = ctrl->priv;
 	struct fdt_usb_controller *controller;
@@ -714,6 +704,12 @@ static int fdt_decode_usb(const void *blob, int node, struct fdt_usb *config)
 	return 0;
 }
 
+static const struct ehci_ops tegra_ehci_ops = {
+	.set_usb_mode		= tegra_ehci_set_usbmode,
+	.get_port_speed		= tegra_ehci_get_port_speed,
+	.powerup_fixup		= tegra_ehci_powerup_fixup,
+};
+
 /*
  * process_usb_nodes() - Process a list of USB nodes, adding them to our list
  *			of USB ports.
@@ -805,7 +801,7 @@ int ehci_hcd_init(int index, enum usb_init_type init,
 		return -1;
 
 	config = &port[index];
-	ehci_set_controller_priv(index, config);
+	ehci_set_controller_priv(index, config, &tegra_ehci_ops);
 
 	switch (init) {
 	case USB_INIT_HOST:
drivers/usb/host/ehci.h +17 -10
index 2ca111a..cc23e1f 100644
@@ -244,6 +244,16 @@ enum {
 	EHCI_TWEAK_NO_INIT_CF		= 1 << 0,
 };
 
+struct ehci_ctrl;
+
+struct ehci_ops {
+	void (*set_usb_mode)(struct ehci_ctrl *ctrl);
+	int (*get_port_speed)(struct ehci_ctrl *ctrl, uint32_t reg);
+	void (*powerup_fixup)(struct ehci_ctrl *ctrl, uint32_t *status_reg,
+			      uint32_t *reg);
+	uint32_t *(*get_portsc_register)(struct ehci_ctrl *ctrl, int port);
+};
+
 struct ehci_ctrl {
 	struct ehci_hccr *hccr;	/* R/O registers, not need for volatile */
 	struct ehci_hcor *hcor;
@@ -254,27 +264,24 @@ struct ehci_ctrl {
 	uint32_t *periodic_list;
 	int periodic_schedules;
 	int ntds;
+	struct ehci_ops ops;
 	void *priv;	/* client's private data */
 };
 
-/* Weak functions that drivers can override */
-int ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg);
-void ehci_set_usbmode(struct ehci_ctrl *ctrl);
-void ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
-			uint32_t *reg);
-uint32_t *ehci_get_portsc_register(struct ehci_ctrl *ctrl, int port);
-
 /**
- * ehci_set_controller_priv() - Set up private data for the controller
+ * ehci_set_controller_info() - Set up private data for the controller
  *
  * This function can be called in ehci_hcd_init() to tell the EHCI layer
  * about the controller's private data pointer. Then in the above functions
- * this can be accessed given the struct ehci_ctrl pointer.
+ * this can be accessed given the struct ehci_ctrl pointer. Also special
+ * EHCI operation methods can be provided if required
  *
  * @index:	Controller number to set
  * @priv:	Controller pointer
+ * @ops:	Controller operations, or NULL to use default
  */
-void ehci_set_controller_priv(int index, void *priv);
+void ehci_set_controller_priv(int index, void *priv,
+			      const struct ehci_ops *ops);
 
 /**
  * ehci_get_controller_priv() - Get controller private data
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#79 lore raw

PATCH v2 39/80 dm: usb: Drop the EHCI weak functions

Quoted 10 lines · Simon Glass

These are a pain with driver model because we might have different EHCI drivers which want to implement them differently. Now that they use consistent function signatures, we can in good conscience move them to a struct.

---

Changes in v2: None

Quoted 7 lines
 board/genesi/mx51_efikamx/efikamx-usb.c |   5 +-
 drivers/usb/host/ehci-faraday.c         | 113 +++++++++++++++-----------------
 drivers/usb/host/ehci-hcd.c             |  49 +++++++++++---
 drivers/usb/host/ehci-mx5.c             |  12 ++++
 drivers/usb/host/ehci-tegra.c           |  26 ++++----
 drivers/usb/host/ehci.h                 |  27 +++++---
 6 files changed, 136 insertions(+), 96 deletions(-)

Applied to u-boot-dm/next.

#80 lore raw

PATCH v2 40/80 dm: usb: Change ehci_reset() to use a pointer

In reply to Simon Glass

The index cannot be used with driver model, and isn't needed anyway. Change the parameter to a pointer.

---

Changes in v2: None

 drivers/usb/host/ehci-hcd.c | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)
drivers/usb/host/ehci-hcd.c +8 -9
index 82f7318..86082a9 100644
@@ -176,16 +176,15 @@ static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec)
 	return -1;
 }
 
-static int ehci_reset(int index)
+static int ehci_reset(struct ehci_ctrl *ctrl)
 {
-	struct ehci_ctrl *ctrl = &ehcic[index];
 	uint32_t cmd;
 	int ret = 0;
 
-	cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
+	cmd = ehci_readl(&ctrl->hcor->or_usbcmd);
 	cmd = (cmd & ~CMD_RUN) | CMD_RESET;
-	ehci_writel(&ehcic[index].hcor->or_usbcmd, cmd);
-	ret = handshake((uint32_t *)&ehcic[index].hcor->or_usbcmd,
+	ehci_writel(&ctrl->hcor->or_usbcmd, cmd);
+	ret = handshake((uint32_t *)&ctrl->hcor->or_usbcmd,
 			CMD_RESET, 0, 250 * 1000);
 	if (ret < 0) {
 		printf("EHCI fail to reset\n");
@@ -193,13 +192,13 @@ static int ehci_reset(int index)
 	}
 
 	if (ehci_is_TDI())
-		ctrl->ops.set_usb_mode(&ehcic[index]);
+		ctrl->ops.set_usb_mode(ctrl);
 
 #ifdef CONFIG_USB_EHCI_TXFIFO_THRESH
-	cmd = ehci_readl(&ehcic[index].hcor->or_txfilltuning);
+	cmd = ehci_readl(&ctrl->hcor->or_txfilltuning);
 	cmd &= ~TXFIFO_THRESH_MASK;
 	cmd |= TXFIFO_THRESH(CONFIG_USB_EHCI_TXFIFO_THRESH);
-	ehci_writel(&ehcic[index].hcor->or_txfilltuning, cmd);
+	ehci_writel(&ctrl->hcor->or_txfilltuning, cmd);
 #endif
 out:
 	return ret;
@@ -1102,7 +1101,7 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
 		goto done;
 
 	/* EHCI spec section 4.1 */
-	if (ehci_reset(index))
+	if (ehci_reset(ctrl))
 		return -1;
 
 #if defined(CONFIG_EHCI_HCD_INIT_AFTER_RESET)
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#81 lore raw

PATCH v2 40/80 dm: usb: Change ehci_reset() to use a pointer

Quoted 10 lines · Simon Glass

The index cannot be used with driver model, and isn't needed anyway. Change the parameter to a pointer.

---

Changes in v2: None

 drivers/usb/host/ehci-hcd.c | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

Applied to u-boot-dm/next.

#82 lore raw

PATCH v2 41/80 dm: usb: Add driver model support to EHCI

In reply to Simon Glass

Add a way for EHCI controller drivers to support driver model. Drivers can call ehci_register() to register themselves in their probe() methods.

---

Changes in v2: None

 drivers/usb/host/ehci-hcd.c | 125 ++++++++++++++++++++++++++++++++++++++++++--
 drivers/usb/host/ehci.h     |   6 +++
 2 files changed, 127 insertions(+), 4 deletions(-)
drivers/usb/host/ehci-hcd.c +121 -4
index 86082a9..227aa83 100644
@@ -21,6 +21,7 @@
  * MA 02111-1307 USA
  */
 #include <common.h>
+#include <dm.h>
 #include <errno.h>
 #include <asm/byteorder.h>
 #include <asm/unaligned.h>
@@ -42,7 +43,9 @@
  */
 #define HCHALT_TIMEOUT (8 * 1000)
 
+#ifndef CONFIG_DM_USB
 static struct ehci_ctrl ehcic[CONFIG_USB_MAX_CONTROLLER_COUNT];
+#endif
 
 #define ALIGN_END_ADDR(type, ptr, size)			\
 	((uint32_t)(ptr) + roundup((size) * sizeof(type), USB_DMA_MINALIGN))
@@ -121,7 +124,18 @@ static struct descriptor {
 
 static struct ehci_ctrl *ehci_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
 }
 
 static int ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg)
@@ -281,12 +295,13 @@ static inline u8 ehci_encode_speed(enum usb_device_speed speed)
 	return QH_FULL_SPEED;
 }
 
-static void ehci_update_endpt2_dev_n_port(struct usb_device *dev,
+static void ehci_update_endpt2_dev_n_port(struct usb_device *udev,
 					  struct QH *qh)
 {
 	struct usb_device *ttdev;
+	int parent_devnum;
 
-	if (dev->speed != USB_SPEED_LOW && dev->speed != USB_SPEED_FULL)
+	if (udev->speed != USB_SPEED_LOW && udev->speed != USB_SPEED_FULL)
 		return;
 
 	/*
@@ -294,14 +309,35 @@ static void ehci_update_endpt2_dev_n_port(struct usb_device *dev,
 	 * the tt, so of the first upstream usb-2 hub, there may be usb-1 hubs
 	 * in the tree before that one!
 	 */
-	ttdev = dev;
+#ifdef CONFIG_DM_USB
+	struct udevice *parent;
+
+	for (ttdev = udev; ; ) {
+		struct udevice *dev = ttdev->dev;
+
+		if (dev->parent &&
+		    device_get_uclass_id(dev->parent) == UCLASS_USB_HUB)
+			parent = dev->parent;
+		else
+			parent = NULL;
+		if (!parent)
+			return;
+		ttdev = dev_get_parentdata(parent);
+		if (!ttdev->speed != USB_SPEED_HIGH)
+			break;
+	}
+	parent_devnum = ttdev->devnum;
+#else
+	ttdev = udev;
 	while (ttdev->parent && ttdev->parent->speed != USB_SPEED_HIGH)
 		ttdev = ttdev->parent;
 	if (!ttdev->parent)
 		return;
+	parent_devnum = ttdev->parent->devnum;
+#endif
 
 	qh->qh_endpt2 |= cpu_to_hc32(QH_ENDPT2_PORTNUM(ttdev->portnr) |
-				     QH_ENDPT2_HUBADDR(ttdev->parent->devnum));
+				     QH_ENDPT2_HUBADDR(parent_devnum));
 }
 
 static int
@@ -960,6 +996,7 @@ static void ehci_setup_ops(struct ehci_ctrl *ctrl, const struct ehci_ops *ops)
 	}
 }
 
+#ifndef CONFIG_DM_USB
 void ehci_set_controller_priv(int index, void *priv, const struct ehci_ops *ops)
 {
 	struct ehci_ctrl *ctrl = &ehcic[index];
@@ -972,6 +1009,7 @@ void *ehci_get_controller_priv(int index)
 {
 	return ehcic[index].priv;
 }
+#endif
 
 static int ehci_common_init(struct ehci_ctrl *ctrl, uint tweaks)
 {
@@ -1082,6 +1120,7 @@ static int ehci_common_init(struct ehci_ctrl *ctrl, uint tweaks)
 	return 0;
 }
 
+#ifndef CONFIG_DM_USB
 int usb_lowlevel_stop(int index)
 {
 	ehci_shutdown(&ehcic[index]);
@@ -1121,6 +1160,7 @@ done:
 	*controller = &ehcic[index];
 	return 0;
 }
+#endif
 
 static int _ehci_submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
 				 void *buffer, int length)
@@ -1480,6 +1520,7 @@ static int _ehci_submit_int_msg(struct usb_device *dev, unsigned long pipe,
 	return result;
 }
 
+#ifndef CONFIG_DM_USB
 int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
 			    void *buffer, int length)
 {
@@ -1497,3 +1538,79 @@ int submit_int_msg(struct usb_device *dev, unsigned long pipe,
 {
 	return _ehci_submit_int_msg(dev, pipe, buffer, length, interval);
 }
+#endif
+
+#ifdef CONFIG_DM_USB
+static int ehci_submit_control_msg(struct udevice *dev, struct usb_device *udev,
+				   unsigned long pipe, void *buffer, int length,
+				   struct devrequest *setup)
+{
+	debug("%s: dev='%s', udev=%p, udev->dev='%s', portnr=%d\n", __func__,
+	      dev->name, udev, udev->dev->name, udev->portnr);
+
+	return _ehci_submit_control_msg(udev, pipe, buffer, length, setup);
+}
+
+static int ehci_submit_bulk_msg(struct udevice *dev, struct usb_device *udev,
+				unsigned long pipe, void *buffer, int length)
+{
+	debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev);
+	return _ehci_submit_bulk_msg(udev, pipe, buffer, length);
+}
+
+static int ehci_submit_int_msg(struct udevice *dev, struct usb_device *udev,
+			       unsigned long pipe, void *buffer, int length,
+			       int interval)
+{
+	debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev);
+	return _ehci_submit_int_msg(udev, pipe, buffer, length, interval);
+}
+
+int ehci_register(struct udevice *dev, struct ehci_hccr *hccr,
+		  struct ehci_hcor *hcor, const struct ehci_ops *ops,
+		  uint tweaks, enum usb_init_type init)
+{
+	struct ehci_ctrl *ctrl = dev_get_priv(dev);
+	int ret;
+
+	debug("%s: dev='%s', ctrl=%p, hccr=%p, hcor=%p, init=%d\n", __func__,
+	      dev->name, ctrl, hccr, hcor, init);
+
+	ehci_setup_ops(ctrl, ops);
+	ctrl->hccr = hccr;
+	ctrl->hcor = hcor;
+	ctrl->priv = ctrl;
+
+	if (init == USB_INIT_DEVICE)
+		goto done;
+	ret = ehci_reset(ctrl);
+	if (ret)
+		goto err;
+
+	ret = ehci_common_init(ctrl, tweaks);
+	if (ret)
+		goto err;
+done:
+	return 0;
+err:
+	free(ctrl);
+	debug("%s: failed, ret=%d\n", __func__, ret);
+	return ret;
+}
+
+int ehci_deregister(struct udevice *dev)
+{
+	struct ehci_ctrl *ctrl = dev_get_priv(dev);
+
+	ehci_shutdown(ctrl);
+
+	return 0;
+}
+
+struct dm_usb_ops ehci_usb_ops = {
+	.control = ehci_submit_control_msg,
+	.bulk = ehci_submit_bulk_msg,
+	.interrupt = ehci_submit_int_msg,
+};
+
+#endif
drivers/usb/host/ehci.h +6 -0
index cc23e1f..774282d 100644
@@ -296,4 +296,10 @@ int ehci_hcd_init(int index, enum usb_init_type init,
 		struct ehci_hccr **hccr, struct ehci_hcor **hcor);
 int ehci_hcd_stop(int index);
 
+int ehci_register(struct udevice *dev, struct ehci_hccr *hccr,
+		  struct ehci_hcor *hcor, const struct ehci_ops *ops,
+		  uint tweaks, enum usb_init_type init);
+int ehci_deregister(struct udevice *dev);
+extern struct dm_usb_ops ehci_usb_ops;
+
 #endif /* USB_EHCI_H */
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#83 lore raw

PATCH v2 41/80 dm: usb: Add driver model support to EHCI

Quoted 11 lines · Simon Glass

Add a way for EHCI controller drivers to support driver model. Drivers can call ehci_register() to register themselves in their probe() methods.

---

Changes in v2: None

 drivers/usb/host/ehci-hcd.c | 125 ++++++++++++++++++++++++++++++++++++++++++--
 drivers/usb/host/ehci.h     |   6 +++
 2 files changed, 127 insertions(+), 4 deletions(-)

Applied to u-boot-dm/next.

#84 lore raw

PATCH v2 42/80 dm: usb: Allow USB drivers to be declared and auto-probed

In reply to Simon Glass

USB devices in U-Boot are currently probed only after all devices have been enumerated. Each type of device is probed by custom code, e.g.:

- USB storage
- Keyboard
- Ethernet

With driver model this approach doesn't work very well. We could build a picture of the bus and then go back and add the devices later, but this means that the data structures are incomplete for quite a while. It also does not follow the model of being able to bind a device when we discover it.

We would prefer to have devices automatically be bound as the device is enumerated. This allows us to attach drivers to particular USB classes or product/vendor IDs. This is the method used by Linux.

Add the required #defines from Linux, a way of declaring a USB driver and the logic to locate the correct driver given the USB device's descriptors.

---

Changes in v2: None

 drivers/usb/host/usb-uclass.c | 206 +++++++++++++++++++++++++++++++++++++++++-
 include/usb.h                 | 107 ++++++++++++++++++++++
 2 files changed, 311 insertions(+), 2 deletions(-)
drivers/usb/host/usb-uclass.c +204 -2
index 22dcd14..a86e905 100644
@@ -2,6 +2,8 @@
  * (C) Copyright 2015 Google, Inc
  * Written by Simon Glass <[email protected]>
  *
+ * usb_match_device() modified from Linux kernel v4.0.
+ *
  * SPDX-License-Identifier:	GPL-2.0+
  */
 
@@ -247,6 +249,179 @@ int usb_legacy_port_reset(struct usb_device *parent, int portnr)
 	return usb_port_reset(parent, portnr);
 }
 
+/* returns 0 if no match, 1 if match */
+int usb_match_device(const struct usb_device_descriptor *desc,
+		     const struct usb_device_id *id)
+{
+	if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
+	    id->idVendor != le16_to_cpu(desc->idVendor))
+		return 0;
+
+	if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
+	    id->idProduct != le16_to_cpu(desc->idProduct))
+		return 0;
+
+	/* No need to test id->bcdDevice_lo != 0, since 0 is never
+	   greater than any unsigned number. */
+	if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
+	    (id->bcdDevice_lo > le16_to_cpu(desc->bcdDevice)))
+		return 0;
+
+	if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
+	    (id->bcdDevice_hi < le16_to_cpu(desc->bcdDevice)))
+		return 0;
+
+	if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
+	    (id->bDeviceClass != desc->bDeviceClass))
+		return 0;
+
+	if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
+	    (id->bDeviceSubClass != desc->bDeviceSubClass))
+		return 0;
+
+	if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
+	    (id->bDeviceProtocol != desc->bDeviceProtocol))
+		return 0;
+
+	return 1;
+}
+
+/* returns 0 if no match, 1 if match */
+int usb_match_one_id_intf(const struct usb_device_descriptor *desc,
+			  const struct usb_interface_descriptor *int_desc,
+			  const struct usb_device_id *id)
+{
+	/* The interface class, subclass, protocol and number should never be
+	 * checked for a match if the device class is Vendor Specific,
+	 * unless the match record specifies the Vendor ID. */
+	if (desc->bDeviceClass == USB_CLASS_VENDOR_SPEC &&
+	    !(id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
+	    (id->match_flags & (USB_DEVICE_ID_MATCH_INT_CLASS |
+				USB_DEVICE_ID_MATCH_INT_SUBCLASS |
+				USB_DEVICE_ID_MATCH_INT_PROTOCOL |
+				USB_DEVICE_ID_MATCH_INT_NUMBER)))
+		return 0;
+
+	if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&
+	    (id->bInterfaceClass != int_desc->bInterfaceClass))
+		return 0;
+
+	if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) &&
+	    (id->bInterfaceSubClass != int_desc->bInterfaceSubClass))
+		return 0;
+
+	if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) &&
+	    (id->bInterfaceProtocol != int_desc->bInterfaceProtocol))
+		return 0;
+
+	if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_NUMBER) &&
+	    (id->bInterfaceNumber != int_desc->bInterfaceNumber))
+		return 0;
+
+	return 1;
+}
+
+/* returns 0 if no match, 1 if match */
+int usb_match_one_id(struct usb_device_descriptor *desc,
+		     struct usb_interface_descriptor *int_desc,
+		     const struct usb_device_id *id)
+{
+	if (!usb_match_device(desc, id))
+		return 0;
+
+	return usb_match_one_id_intf(desc, int_desc, id);
+}
+
+/**
+ * usb_find_and_bind_driver() - Find and bind the right USB driver
+ *
+ * This only looks at certain fields in the descriptor.
+ */
+static int usb_find_and_bind_driver(struct udevice *parent,
+				    struct usb_device_descriptor *desc,
+				    struct usb_interface_descriptor *iface,
+				    int bus_seq, int devnum,
+				    struct udevice **devp)
+{
+	struct usb_driver_entry *start, *entry;
+	int n_ents;
+	int ret;
+	char name[30], *str;
+
+	*devp = NULL;
+	debug("%s: Searching for driver\n", __func__);
+	start = ll_entry_start(struct usb_driver_entry, usb_driver_entry);
+	n_ents = ll_entry_count(struct usb_driver_entry, usb_driver_entry);
+	for (entry = start; entry != start + n_ents; entry++) {
+		const struct usb_device_id *id;
+		struct udevice *dev;
+		const struct driver *drv;
+		struct usb_dev_platdata *plat;
+
+		for (id = entry->match; id->match_flags; id++) {
+			if (!usb_match_one_id(desc, iface, id))
+				continue;
+
+			drv = entry->driver;
+			/*
+			 * We could pass the descriptor to the driver as
+			 * platdata (instead of NULL) and allow its bind()
+			 * method to return -ENOENT if it doesn't support this
+			 * device. That way we could continue the search to
+			 * find another driver. For now this doesn't seem
+			 * necesssary, so just bind the first match.
+			 */
+			ret = device_bind(parent, drv, drv->name, NULL, -1,
+					  &dev);
+			if (ret)
+				goto error;
+			debug("%s: Match found: %s\n", __func__, drv->name);
+			dev->driver_data = id->driver_info;
+			plat = dev_get_parent_platdata(dev);
+			plat->id = *id;
+			*devp = dev;
+			return 0;
+		}
+	}
+
+	ret = -ENOENT;
+error:
+	debug("%s: No match found: %d\n", __func__, ret);
+	return ret;
+}
+
+/**
+ * usb_find_child() - Find an existing device which matches our needs
+ *
+ *
+ */
+static int usb_find_child(struct udevice *parent,
+			  struct usb_device_descriptor *desc,
+			  struct usb_interface_descriptor *iface,
+			  struct udevice **devp)
+{
+	struct udevice *dev;
+
+	*devp = NULL;
+	for (device_find_first_child(parent, &dev);
+	     dev;
+	     device_find_next_child(&dev)) {
+		struct usb_dev_platdata *plat = dev_get_parent_platdata(dev);
+
+		/* If this device is already in use, skip it */
+		if (device_active(dev))
+			continue;
+		debug("   %s: name='%s', plat=%d, desc=%d\n", __func__,
+		      dev->name, plat->id.bDeviceClass, desc->bDeviceClass);
+		if (usb_match_one_id(desc, iface, &plat->id)) {
+			*devp = dev;
+			return 0;
+		}
+	}
+
+	return -ENOENT;
+}
+
 int usb_scan_device(struct udevice *parent, int port,
 		    enum usb_device_speed speed, struct udevice **devp)
 {
@@ -307,9 +482,36 @@ int usb_scan_device(struct udevice *parent, int port,
 		return ret;
 	ret = usb_find_child(parent, &udev->descriptor, iface, &dev);
 	debug("** usb_find_child returns %d\n", ret);
+	if (ret) {
+		if (ret != -ENOENT)
+			return ret;
+		ret = usb_find_and_bind_driver(parent, &udev->descriptor, iface,
+					       udev->controller_dev->seq,
+					       udev->devnum, &dev);
+		if (ret)
+			return ret;
+		created = true;
+	}
+	plat = dev_get_parent_platdata(dev);
+	debug("%s: Probing '%s', plat=%p\n", __func__, dev->name, plat);
+	plat->devnum = udev->devnum;
+	plat->speed = udev->speed;
+	plat->slot_id = udev->slot_id;
+	plat->portnr = port;
+	debug("** device '%s': stashing slot_id=%d\n", dev->name,
+	      plat->slot_id);
+	priv->next_addr++;
+	ret = device_probe(dev);
+	if (ret) {
+		debug("%s: Device '%s' probe failed\n", __func__, dev->name);
+		priv->next_addr--;
+		if (created)
+			device_unbind(dev);
+		return ret;
+	}
+	*devp = dev;
 
-	/* TODO: Find a suitable driver and create the device */
-	return -ENOENT;
+	return 0;
 }
 
 int usb_child_post_bind(struct udevice *dev)
include/usb.h +107 -0

113 lines not on this page · raw message

Signature · 1 line
2.2.0.rc0.207.ga3a616c
#85 lore raw

PATCH v2 42/80 dm: usb: Allow USB drivers to be declared and auto-probed

Quoted 20 lines · Simon Glass

USB devices in U-Boot are currently probed only after all devices have been enumerated. Each type of device is probed by custom code, e.g.:

- USB storage
- Keyboard
- Ethernet

With driver model this approach doesn't work very well. We could build a picture of the bus and then go back and add the devices later, but this means that the data structures are incomplete for quite a while. It also does not follow the model of being able to bind a device when we discover it.

We would prefer to have devices automatically be bound as the device is enumerated. This allows us to attach drivers to particular USB classes or product/vendor IDs. This is the method used by Linux.

Add the required #defines from Linux, a way of declaring a USB driver and the logic to locate the correct driver given the USB device's descriptors.

Quoted 8 lines

---

Changes in v2: None

 drivers/usb/host/usb-uclass.c | 206 +++++++++++++++++++++++++++++++++++++++++-
 include/usb.h                 | 107 ++++++++++++++++++++++
 2 files changed, 311 insertions(+), 2 deletions(-)

Applied to u-boot-dm/next.

#86 lore raw

PATCH v2 43/80 dm: usb: Bind generic USB devices when there is no driver

In reply to Simon Glass

At present USB devices with no driver model driver cannot be seen in the device list, and we fail to set them up correctly. This means they cannot be used.

While having real drivers that support driver model for all USB devices is the eventual goal, we are not there yet.

As a stop-gap, add a generic USB driver which is bound when we do not have a real driver. This allows the device to be set up and shown on the bus. It also allows ad-hoc code (such as usb_ether) to find these devices and set them up.

---

Changes in v2: None

 drivers/usb/host/usb-uclass.c | 18 +++++++++++++++++-
 include/dm/uclass-id.h        |  1 +
 2 files changed, 18 insertions(+), 1 deletion(-)
drivers/usb/host/usb-uclass.c +17 -1
index a86e905..fa5f14e 100644
@@ -384,7 +384,13 @@ static int usb_find_and_bind_driver(struct udevice *parent,
 		}
 	}
 
-	ret = -ENOENT;
+	/* Bind a generic driver so that the device can be used */
+	snprintf(name, sizeof(name), "generic_bus_%x_dev_%x", bus_seq, devnum);
+	str = strdup(name);
+	if (!str)
+		return -ENOMEM;
+	ret = device_bind_driver(parent, "usb_dev_generic_drv", str, devp);
+
 error:
 	debug("%s: No match found: %d\n", __func__, ret);
 	return ret;
@@ -592,3 +598,13 @@ UCLASS_DRIVER(usb) = {
 	.child_pre_probe = usb_child_pre_probe,
 	.per_child_platdata_auto_alloc_size = sizeof(struct usb_dev_platdata),
 };
+
+UCLASS_DRIVER(usb_dev_generic) = {
+	.id		= UCLASS_USB_DEV_GENERIC,
+	.name		= "usb_dev_generic",
+};
+
+U_BOOT_DRIVER(usb_dev_generic_drv) = {
+	.id		= UCLASS_USB_DEV_GENERIC,
+	.name		= "usb_dev_generic_drv",
+};
include/dm/uclass-id.h +1 -0
index acec938..42a6f1f 100644
@@ -41,6 +41,7 @@ enum uclass_id {
 	UCLASS_ETH,		/* Ethernet device */
 	UCLASS_USB,		/* USB bus */
 	UCLASS_USB_HUB,		/* USB hub */
+	UCLASS_USB_DEV_GENERIC,	/* USB generic device */
 
 	UCLASS_COUNT,
 	UCLASS_INVALID = -1,
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#87 lore raw

PATCH v2 43/80 dm: usb: Bind generic USB devices when there is no driver

Quoted 12 lines · Simon Glass

At present USB devices with no driver model driver cannot be seen in the device list, and we fail to set them up correctly. This means they cannot be used.

While having real drivers that support driver model for all USB devices is the eventual goal, we are not there yet.

As a stop-gap, add a generic USB driver which is bound when we do not have a real driver. This allows the device to be set up and shown on the bus. It also allows ad-hoc code (such as usb_ether) to find these devices and set them up.

Quoted 8 lines

---

Changes in v2: None

 drivers/usb/host/usb-uclass.c | 18 +++++++++++++++++-
 include/dm/uclass-id.h        |  1 +
 2 files changed, 18 insertions(+), 1 deletion(-)

Applied to u-boot-dm/next.

#88 lore raw

PATCH v2 44/80 dm: usb: Allow setting up a USB controller as a device/gadget

In reply to Simon Glass

Some controllers support OTG (on-the-go) where they can operate as either host or device. The gadget layer in U-Boot supports this.

While this layer does not interact with driver model, we can provide a function which sets up the controller in the correct way. This way the code at least builds (although it likely will not work).

---

Changes in v2: None

 drivers/usb/gadget/ci_udc.c   |  4 ++++
 drivers/usb/host/usb-uclass.c | 24 ++++++++++++++++++++++++
 2 files changed, 28 insertions(+)
drivers/usb/gadget/ci_udc.c +4 -0
index b0ef35e..0afc987 100644
@@ -883,7 +883,11 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
 	if (driver->speed != USB_SPEED_FULL && driver->speed != USB_SPEED_HIGH)
 		return -EINVAL;
 
+#ifdef CONFIG_DM_USB
+	ret = usb_setup_ehci_gadget(&controller.ctrl);
+#else
 	ret = usb_lowlevel_init(0, USB_INIT_DEVICE, (void **)&controller.ctrl);
+#endif
 	if (ret)
 		return ret;
 
drivers/usb/host/usb-uclass.c +24 -0
index fa5f14e..29ef5d9 100644
@@ -249,6 +249,30 @@ int usb_legacy_port_reset(struct usb_device *parent, int portnr)
 	return usb_port_reset(parent, portnr);
 }
 
+int usb_setup_ehci_gadget(struct ehci_ctrl **ctlrp)
+{
+	struct usb_platdata *plat;
+	struct udevice *dev;
+	int ret;
+
+	/* Find the old device and remove it */
+	ret = uclass_find_device_by_seq(UCLASS_USB, 0, true, &dev);
+	if (ret)
+		return ret;
+	ret = device_remove(dev);
+	if (ret)
+		return ret;
+
+	plat = dev_get_platdata(dev);
+	plat->init_type = USB_INIT_DEVICE;
+	ret = device_probe(dev);
+	if (ret)
+		return ret;
+	*ctlrp = dev_get_priv(dev);
+
+	return 0;
+}
+
 /* returns 0 if no match, 1 if match */
 int usb_match_device(const struct usb_device_descriptor *desc,
 		     const struct usb_device_id *id)
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#89 lore raw

PATCH v2 44/80 dm: usb: Allow setting up a USB controller as a device/gadget

Quoted 7 lines · Simon Glass

Some controllers support OTG (on-the-go) where they can operate as either host or device. The gadget layer in U-Boot supports this.

While this layer does not interact with driver model, we can provide a function which sets up the controller in the correct way. This way the code at least builds (although it likely will not work).

Quoted 8 lines

---

Changes in v2: None

 drivers/usb/gadget/ci_udc.c   |  4 ++++
 drivers/usb/host/usb-uclass.c | 24 ++++++++++++++++++++++++
 2 files changed, 28 insertions(+)

Applied to u-boot-dm/next.

#90 lore raw

PATCH v2 45/80 dm: usb: Split out the keyboard probe into its own function

In reply to Simon Glass

Before adding driver model support, split out code from this over-long function.

---

Changes in v2: None

 common/usb_kbd.c | 89 ++++++++++++++++++++++++++++++++------------------------
 1 file changed, 51 insertions(+), 38 deletions(-)
common/usb_kbd.c +51 -38
index ecc3085..e02529f 100644
@@ -471,59 +471,72 @@ static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum)
 	return 1;
 }
 
+static int probe_usb_keyboard(struct usb_device *dev)
+{
+	char *stdinname;
+	struct stdio_dev usb_kbd_dev;
+	int error;
+
+	/* Try probing the keyboard */
+	if (usb_kbd_probe(dev, 0) != 1)
+		return -ENOENT;
+
+	/* Register the keyboard */
+	debug("USB KBD: register.\n");
+	memset(&usb_kbd_dev, 0, sizeof(struct stdio_dev));
+	strcpy(usb_kbd_dev.name, DEVNAME);
+	usb_kbd_dev.flags =  DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
+	usb_kbd_dev.getc = usb_kbd_getc;
+	usb_kbd_dev.tstc = usb_kbd_testc;
+	usb_kbd_dev.priv = (void *)dev;
+	error = stdio_register(&usb_kbd_dev);
+	if (error)
+		return error;
+
+	stdinname = getenv("stdin");
+#ifdef CONFIG_CONSOLE_MUX
+	error = iomux_doenv(stdin, stdinname);
+	if (error)
+		return error;
+#else
+	/* Check if this is the standard input device. */
+	if (strcmp(stdinname, DEVNAME))
+		return 1;
+
+	/* Reassign the console */
+	if (overwrite_console())
+		return 1;
+
+	error = console_assign(stdin, DEVNAME);
+	if (error)
+		return error;
+#endif
+
+	return 0;
+}
+
 /* Search for keyboard and register it if found. */
 int drv_usb_kbd_init(void)
 {
-	struct stdio_dev usb_kbd_dev;
-	struct usb_device *dev;
-	char *stdinname = getenv("stdin");
 	int error, i;
 
-	/* Scan all USB Devices */
+	debug("%s: Probing for keyboard\n", __func__);/* Scan all USB Devices */
 	for (i = 0; i < USB_MAX_DEVICE; i++) {
+		struct usb_device *dev;
+
 		/* Get USB device. */
 		dev = usb_get_dev_index(i);
 		if (!dev)
-			return -1;
+			break;
 
 		if (dev->devnum == -1)
 			continue;
 
-		/* Try probing the keyboard */
-		if (usb_kbd_probe(dev, 0) != 1)
-			continue;
-
-		/* Register the keyboard */
-		debug("USB KBD: register.\n");
-		memset(&usb_kbd_dev, 0, sizeof(struct stdio_dev));
-		strcpy(usb_kbd_dev.name, DEVNAME);
-		usb_kbd_dev.flags =  DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
-		usb_kbd_dev.getc = usb_kbd_getc;
-		usb_kbd_dev.tstc = usb_kbd_testc;
-		usb_kbd_dev.priv = (void *)dev;
-		error = stdio_register(&usb_kbd_dev);
-		if (error)
-			return error;
-
-#ifdef CONFIG_CONSOLE_MUX
-		error = iomux_doenv(stdin, stdinname);
-		if (error)
-			return error;
-#else
-		/* Check if this is the standard input device. */
-		if (strcmp(stdinname, DEVNAME))
-			return 1;
-
-		/* Reassign the console */
-		if (overwrite_console())
+		error = probe_usb_keyboard(dev);
+		if (!error)
 			return 1;
-
-		error = console_assign(stdin, DEVNAME);
-		if (error)
+		if (error && error != -ENOENT)
 			return error;
-#endif
-
-		return 1;
 	}
 
 	/* No USB Keyboard found */
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#91 lore raw

PATCH v2 45/80 dm: usb: Split out the keyboard probe into its own function

Quoted 10 lines · Simon Glass

Before adding driver model support, split out code from this over-long function.

---

Changes in v2: None

 common/usb_kbd.c | 89 ++++++++++++++++++++++++++++++++------------------------
 1 file changed, 51 insertions(+), 38 deletions(-)

Applied to u-boot-dm/next.

#92 lore raw

PATCH v2 46/80 dm: usb: Support driver model with USB keyboards

In reply to Simon Glass

Allow USB keyboards to work with driver model. The main difference is that we can have multiple buses (each with its own device numbering) and each bus must be scanned.

---

Changes in v2: None

 common/usb_kbd.c | 34 +++++++++++++++++++++++++++++++++-
 1 file changed, 33 insertions(+), 1 deletion(-)
common/usb_kbd.c +33 -1
index e02529f..24a1a56 100644
@@ -8,6 +8,7 @@
  * SPDX-License-Identifier:	GPL-2.0+
  */
 #include <common.h>
+#include <dm.h>
 #include <errno.h>
 #include <malloc.h>
 #include <stdio_dev.h>
@@ -520,7 +521,37 @@ int drv_usb_kbd_init(void)
 {
 	int error, i;
 
-	debug("%s: Probing for keyboard\n", __func__);/* Scan all USB Devices */
+	debug("%s: Probing for keyboard\n", __func__);
+#ifdef CONFIG_DM_USB
+	/*
+	 * TODO: We should add USB_DEVICE() declarations to each USB ethernet
+	 * driver and then most of this file can be removed.
+	 */
+	struct udevice *bus;
+	struct uclass *uc;
+	int ret;
+
+	ret = uclass_get(UCLASS_USB, &uc);
+	if (ret)
+		return ret;
+	uclass_foreach_dev(bus, uc) {
+		for (i = 0; i < USB_MAX_DEVICE; i++) {
+			struct usb_device *dev;
+
+			dev = usb_get_dev_index(bus, i); /* get device */
+			debug("i=%d, %p\n", i, dev);
+			if (!dev)
+				break; /* no more devices available */
+
+			error = probe_usb_keyboard(dev);
+			if (!error)
+				return 1;
+			if (error && error != -ENOENT)
+				return error;
+		} /* for */
+	}
+#else
+	/* Scan all USB Devices */
 	for (i = 0; i < USB_MAX_DEVICE; i++) {
 		struct usb_device *dev;
 
@@ -538,6 +569,7 @@ int drv_usb_kbd_init(void)
 		if (error && error != -ENOENT)
 			return error;
 	}
+#endif
 
 	/* No USB Keyboard found */
 	return -1;
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#93 lore raw

PATCH v2 46/80 dm: usb: Support driver model with USB keyboards

Quoted 11 lines · Simon Glass

Allow USB keyboards to work with driver model. The main difference is that we can have multiple buses (each with its own device numbering) and each bus must be scanned.

---

Changes in v2: None

 common/usb_kbd.c | 34 +++++++++++++++++++++++++++++++++-
 1 file changed, 33 insertions(+), 1 deletion(-)

Applied to u-boot-dm/next.

#94 lore raw

PATCH v2 47/80 dm: usb: tegra: Add vbus GPIOs for nyan

In reply to Simon Glass

These are needed to enable the USB bus (although not sufficient since it still does not work).

---

Changes in v2: None

 arch/arm/dts/tegra124-nyan-big.dts | 2 ++
 1 file changed, 2 insertions(+)
arch/arm/dts/tegra124-nyan-big.dts +2 -0
index c1f35a0..9367193 100644
@@ -230,6 +230,7 @@
 
 	usb at 7d000000 { /* Rear external USB port. */
 		status = "okay";
+		nvidia,vbus-gpio = <&gpio TEGRA_GPIO(N, 4) GPIO_ACTIVE_HIGH>;
 	};
 
 	usb-phy at 7d000000 {
@@ -246,6 +247,7 @@
 
 	usb at 7d008000 { /* Left external USB port. */
 		status = "okay";
+		nvidia,vbus-gpio = <&gpio TEGRA_GPIO(N, 5) GPIO_ACTIVE_HIGH>;
 	};
 
 	usb-phy at 7d008000 {
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#95 lore raw

PATCH v2 47/80 dm: usb: tegra: Add vbus GPIOs for nyan

Quoted 10 lines · Simon Glass

These are needed to enable the USB bus (although not sufficient since it still does not work).

---

Changes in v2: None

 arch/arm/dts/tegra124-nyan-big.dts | 2 ++
 1 file changed, 2 insertions(+)

Applied to u-boot-dm/next.

#96 lore raw

PATCH v2 48/80 dm: usb: Move struct usb_string to a common place

In reply to Simon Glass

This is needed for sandbox USB device emulation, so move it to a place where it can be found by things other than gadgets.

---

Changes in v2: None

 include/linux/usb/ch9.h    | 13 +++++++++++++
 include/linux/usb/gadget.h | 13 -------------
 2 files changed, 13 insertions(+), 13 deletions(-)
include/linux/usb/ch9.h +13 -0
index bd48704..10675b4 100644
@@ -1002,4 +1002,17 @@ struct usb_set_sel_req {
  */
 #define USB_SELF_POWER_VBUS_MAX_DRAW		100
 
+/**
+ * struct usb_string - wraps a C string and its USB id
+ * @id:the (nonzero) ID for this string
+ * @s:the string, in UTF-8 encoding
+ *
+ * If you're using usb_gadget_get_string(), use this to wrap a string
+ * together with its ID.
+ */
+struct usb_string {
+	u8 id;
+	const char *s;
+};
+
 #endif /* __LINUX_USB_CH9_H */
include/linux/usb/gadget.h +0 -13
index 9bccd45..bd409bc 100644
@@ -806,19 +806,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver);
 /* utility to simplify dealing with string descriptors */
 
 /**
- * struct usb_string - wraps a C string and its USB id
- * @id:the (nonzero) ID for this string
- * @s:the string, in UTF-8 encoding
- *
- * If you're using usb_gadget_get_string(), use this to wrap a string
- * together with its ID.
- */
-struct usb_string {
-	u8			id;
-	const char		*s;
-};
-
-/**
  * struct usb_gadget_strings - a set of USB strings in a given language
  * @language:identifies the strings' language (0x0409 for en-us)
  * @strings:array of strings with their ids
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#97 lore raw

PATCH v2 48/80 dm: usb: Move struct usb_string to a common place

Quoted 11 lines · Simon Glass

This is needed for sandbox USB device emulation, so move it to a place where it can be found by things other than gadgets.

---

Changes in v2: None

 include/linux/usb/ch9.h    | 13 +++++++++++++
 include/linux/usb/gadget.h | 13 -------------
 2 files changed, 13 insertions(+), 13 deletions(-)

Applied to u-boot-dm/next.

#98 lore raw

PATCH v2 49/80 dm: usb: sandbox: Add a uclass for USB device emulation

In reply to Simon Glass

With sandbox we want to be able to emulate USB devices so that we can test the USB stack. Add a uclass to support this. It implements the same operations as a normal USB device driver, but in this case passes them on to an emulation driver.

---

Changes in v2: None

 Makefile                           |   1 +
 drivers/usb/Kconfig                |   2 +
 drivers/usb/emul/Kconfig           |   8 ++
 drivers/usb/emul/Makefile          |   8 ++
 drivers/usb/emul/usb-emul-uclass.c | 263 +++++++++++++++++++++++++++++++++++++
 include/dm/uclass-id.h             |   1 +
 include/usb.h                      |  64 ++++++++-
 7 files changed, 346 insertions(+), 1 deletion(-)
 create mode 100644 drivers/usb/emul/Kconfig
 create mode 100644 drivers/usb/emul/Makefile
 create mode 100644 drivers/usb/emul/usb-emul-uclass.c
Makefile +1 -0
index 1b3ebe7..c389869 100644
@@ -637,6 +637,7 @@ libs-y += drivers/spi/
 libs-$(CONFIG_FMAN_ENET) += drivers/net/fm/
 libs-$(CONFIG_SYS_FSL_DDR) += drivers/ddr/fsl/
 libs-y += drivers/serial/
+libs-y += drivers/usb/emul/
 libs-y += drivers/usb/eth/
 libs-y += drivers/usb/gadget/
 libs-y += drivers/usb/host/
drivers/usb/Kconfig +2 -0
index a4414ef..637ef3d 100644
@@ -51,6 +51,8 @@ config DM_USB
 
 source "drivers/usb/host/Kconfig"
 
+source "drivers/usb/emul/Kconfig"
+
 config USB_STORAGE
 	bool "USB Mass Storage support"
 	---help---
drivers/usb/emul/Kconfig new file +8 -0
new file mode 100644
index 0000000..ae1ab23
@@ -0,0 +1,8 @@
+config USB_EMUL
+	bool "Support for USB device emulation"
+	depends on DM_USB && SANDBOX
+	help
+	  Since sandbox does not have access to a real USB bus, it is possible
+	  to use device emulators instead. This allows testing of the USB
+	  stack on sandbox without needing a real device, or any host machine
+	  USB resources.
drivers/usb/emul/Makefile new file +8 -0
new file mode 100644
index 0000000..f75bbd8
@@ -0,0 +1,8 @@
+#
+# (C) Copyright 2015 Google, Inc
+# Written by Simon Glass <[email protected]>
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-$(CONFIG_USB_EMUL) += usb-emul-uclass.o
drivers/usb/emul/usb-emul-uclass.c new file +263 -0

263 lines not on this page · raw message

include/dm/uclass-id.h +1 -0
index 42a6f1f..2d0a145 100644
@@ -21,6 +21,7 @@ enum uclass_id {
 	UCLASS_SPI_EMUL,	/* sandbox SPI device emulator */
 	UCLASS_I2C_EMUL,	/* sandbox I2C device emulator */
 	UCLASS_PCI_EMUL,	/* sandbox PCI device emulator */
+	UCLASS_USB_EMUL,	/* sandbox USB bus device emulator */
 	UCLASS_SIMPLE_BUS,
 
 	/* U-Boot uclasses start here */
include/usb.h +63 -1

74 lines not on this page · raw message

Signature · 1 line
2.2.0.rc0.207.ga3a616c
#99 lore raw

PATCH v2 49/80 dm: usb: sandbox: Add a uclass for USB device emulation

Quoted 10 lines · Simon Glass

With sandbox we want to be able to emulate USB devices so that we can test the USB stack. Add a uclass to support this. It implements the same operations as a normal USB device driver, but in this case passes them on to an emulation driver.

---

Changes in v2: None

Quoted 11 lines
 Makefile                           |   1 +
 drivers/usb/Kconfig                |   2 +
 drivers/usb/emul/Kconfig           |   8 ++
 drivers/usb/emul/Makefile          |   8 ++
 drivers/usb/emul/usb-emul-uclass.c | 263 +++++++++++++++++++++++++++++++++++++
 include/dm/uclass-id.h             |   1 +
 include/usb.h                      |  64 ++++++++-
 7 files changed, 346 insertions(+), 1 deletion(-)
 create mode 100644 drivers/usb/emul/Kconfig
 create mode 100644 drivers/usb/emul/Makefile
 create mode 100644 drivers/usb/emul/usb-emul-uclass.c

Applied to u-boot-dm/next.

#100 lore raw

PATCH v2 50/80 dm: usb: sandbox: Reset emulation devices in usb stop()

In reply to Simon Glass

These devices must have their addresses removed ready for the next USB bus enumeration. Add this logic to usb_stop().

---

Changes in v2: None

 drivers/usb/host/usb-uclass.c | 11 +++++++++++
 1 file changed, 11 insertions(+)
drivers/usb/host/usb-uclass.c +11 -0
index 29ef5d9..714bc0e 100644
@@ -93,6 +93,17 @@ int usb_stop(void)
 			err = ret;
 	}
 
+#ifdef CONFIG_SANDBOX
+	struct udevice *dev;
+
+	/* Reset all enulation devices */
+	ret = uclass_get(UCLASS_USB_EMUL, &uc);
+	if (ret)
+		return ret;
+
+	uclass_foreach_dev(dev, uc)
+		usb_emul_reset(dev);
+#endif
 	usb_stor_reset();
 	usb_hub_reset();
 	usb_started = 0;
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#101 lore raw

PATCH v2 50/80 dm: usb: sandbox: Reset emulation devices in usb stop()

Quoted 10 lines · Simon Glass

These devices must have their addresses removed ready for the next USB bus enumeration. Add this logic to usb_stop().

---

Changes in v2: None

 drivers/usb/host/usb-uclass.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

Applied to u-boot-dm/next.

#102 lore raw

PATCH v2 51/80 dm: usb: sandbox: Add an emulator for USB flash devices

In reply to Simon Glass

This emulator supports USB enumeration and allows a local file to be provided as the contents of the emulated flash stick. U-Boot can then use the file as it would a normal device, with all access passing through the usb_stor layer and the USB stack.

---

Changes in v2: None

 drivers/usb/emul/Makefile        |   1 +
 drivers/usb/emul/sandbox_flash.c | 423 +++++++++++++++++++++++++++++++++++++++
 include/dm/uclass-id.h           |   1 +
 3 files changed, 425 insertions(+)
 create mode 100644 drivers/usb/emul/sandbox_flash.c
drivers/usb/emul/Makefile +1 -0
index f75bbd8..1d5acce 100644
@@ -5,4 +5,5 @@
 # SPDX-License-Identifier:	GPL-2.0+
 #
 
+obj-$(CONFIG_USB_EMUL) += sandbox_flash.o
 obj-$(CONFIG_USB_EMUL) += usb-emul-uclass.o
drivers/usb/emul/sandbox_flash.c new file +423 -0

423 lines not on this page · raw message

include/dm/uclass-id.h +1 -0
index 2d0a145..8ebe9fa 100644
@@ -43,6 +43,7 @@ enum uclass_id {
 	UCLASS_USB,		/* USB bus */
 	UCLASS_USB_HUB,		/* USB hub */
 	UCLASS_USB_DEV_GENERIC,	/* USB generic device */
+	UCLASS_MASS_STORAGE,	/* Mass storage device */
 
 	UCLASS_COUNT,
 	UCLASS_INVALID = -1,
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#103 lore raw

PATCH v2 51/80 dm: usb: sandbox: Add an emulator for USB flash devices

Quoted 8 lines · Simon Glass

This emulator supports USB enumeration and allows a local file to be provided as the contents of the emulated flash stick. U-Boot can then use the file as it would a normal device, with all access passing through the usb_stor layer and the USB stack.

---

Quoted 7 lines

Changes in v2: None

 drivers/usb/emul/Makefile        |   1 +
 drivers/usb/emul/sandbox_flash.c | 423 +++++++++++++++++++++++++++++++++++++++
 include/dm/uclass-id.h           |   1 +
 3 files changed, 425 insertions(+)
 create mode 100644 drivers/usb/emul/sandbox_flash.c

Applied to u-boot-dm/next.

#104 lore raw

PATCH v2 52/80 dm: usb: sandbox: Add an emulator for USB hub emulation

In reply to Simon Glass

All USB controllers need a root hub. Add a sandbox emulation for this so that we can add USB devices to sandbox.

---

Changes in v2: None

 drivers/usb/emul/Makefile      |   1 +
 drivers/usb/emul/sandbox_hub.c | 303 +++++++++++++++++++++++++++++++++++++++++
 include/usb_defs.h             |   3 +
 3 files changed, 307 insertions(+)
 create mode 100644 drivers/usb/emul/sandbox_hub.c
drivers/usb/emul/Makefile +1 -0
index 1d5acce..8fd83d5 100644
@@ -6,4 +6,5 @@
 #
 
 obj-$(CONFIG_USB_EMUL) += sandbox_flash.o
+obj-$(CONFIG_USB_EMUL) += sandbox_hub.o
 obj-$(CONFIG_USB_EMUL) += usb-emul-uclass.o
drivers/usb/emul/sandbox_hub.c new file +303 -0

303 lines not on this page · raw message

include/usb_defs.h +3 -0
index d7f7465..27ddc47 100644
@@ -286,6 +286,9 @@
 #define HUB_CHANGE_LOCAL_POWER	0x0001
 #define HUB_CHANGE_OVERCURRENT	0x0002
 
+/* Mask for wIndex in get/set port feature */
+#define USB_HUB_PORT_MASK	0xf
+
 /*
  * CBI style
  */
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#105 lore raw

PATCH v2 52/80 dm: usb: sandbox: Add an emulator for USB hub emulation

Quoted 6 lines · Simon Glass

All USB controllers need a root hub. Add a sandbox emulation for this so that we can add USB devices to sandbox.

---

Quoted 7 lines

Changes in v2: None

 drivers/usb/emul/Makefile      |   1 +
 drivers/usb/emul/sandbox_hub.c | 303 +++++++++++++++++++++++++++++++++++++++++
 include/usb_defs.h             |   3 +
 3 files changed, 307 insertions(+)
 create mode 100644 drivers/usb/emul/sandbox_hub.c

Applied to u-boot-dm/next.

#106 lore raw

PATCH v2 53/80 dm: usb: sandbox: Add a driver for sandbox

In reply to Simon Glass

This driver supports using emulation devices to provide a USB bus within sandbox.

---

Changes in v2: None

 drivers/usb/host/Makefile      |   1 +
 drivers/usb/host/usb-sandbox.c | 117 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 118 insertions(+)
 create mode 100644 drivers/usb/host/usb-sandbox.c
drivers/usb/host/Makefile +1 -0
index 9419295..7658f87 100644
@@ -7,6 +7,7 @@
 
 ifdef CONFIG_DM_USB
 obj-$(CONFIG_CMD_USB) += usb-uclass.o
+obj-$(CONFIG_SANDBOX) += usb-sandbox.o
 endif
 
 # ohci
drivers/usb/host/usb-sandbox.c new file +117 -0

117 lines not on this page · raw message

Signature · 1 line
2.2.0.rc0.207.ga3a616c
#107 lore raw

PATCH v2 53/80 dm: usb: sandbox: Add a driver for sandbox

Quoted 4 lines · Simon Glass

This driver supports using emulation devices to provide a USB bus within sandbox.

Quoted 8 lines

---

Changes in v2: None

 drivers/usb/host/Makefile      |   1 +
 drivers/usb/host/usb-sandbox.c | 117 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 118 insertions(+)
 create mode 100644 drivers/usb/host/usb-sandbox.c

Applied to u-boot-dm/next.

#108 lore raw

PATCH v2 54/80 dm: usb: dts: sandbox: Add some sample USB devices to sandbox

In reply to Simon Glass

These allow basic testing of the USB functionality within sandbox.

---

Changes in v2: None

 arch/sandbox/dts/sandbox.dts | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)
arch/sandbox/dts/sandbox.dts +40 -0
index 7d050d9..03b540c 100644
@@ -1,5 +1,7 @@
 /dts-v1/;
 
+#define USB_CLASS_HUB			9
+
 / {
 	#address-cells = <1>;
 	#size-cells = <1>;
@@ -219,4 +221,42 @@
 		reg = <0x90000000 0x1000>;
 		host-raw-interface = "lo";
 	};
+
+	usb at 0 {
+		compatible = "sandbox,usb";
+		status = "disabled";
+		hub {
+			compatible = "sandbox,usb-hub";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			flash-stick {
+				reg = <0>;
+				compatible = "sandbox,usb-flash";
+			};
+		};
+	};
+
+	usb at 1 {
+		compatible = "sandbox,usb";
+		hub {
+			compatible = "usb-hub";
+			usb,device-class = <USB_CLASS_HUB>;
+			hub-emul {
+				compatible = "sandbox,usb-hub";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				flash-stick {
+					reg = <0>;
+					compatible = "sandbox,usb-flash";
+					sandbox,filepath = "flash.bin";
+				};
+			};
+		};
+	};
+
+	usb at 2 {
+		compatible = "sandbox,usb";
+		status = "disabled";
+	};
+
 };
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#109 lore raw

PATCH v2 54/80 dm: usb: dts: sandbox: Add some sample USB devices to sandbox

Quoted 9 lines · Simon Glass

These allow basic testing of the USB functionality within sandbox.

---

Changes in v2: None

 arch/sandbox/dts/sandbox.dts | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

Applied to u-boot-dm/next.

#110 lore raw

PATCH v2 55/80 dm: usb: Add support for USB ethernet devices with driver model

In reply to Simon Glass

Add support for scanning USB etghernet devices with driver model. This mostly involves scanning all buses since device numbering is not unique across buses.

---

Changes in v2: None

 drivers/usb/eth/usb_ether.c | 52 ++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 44 insertions(+), 8 deletions(-)
drivers/usb/eth/usb_ether.c +44 -8
index 7cb96e3..c72b7e4 100644
@@ -5,7 +5,9 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <usb.h>
+#include <dm/device-internal.h>
 
 #include "usb_ether.h"
 
@@ -118,8 +120,6 @@ static void probe_valid_drivers(struct usb_device *dev)
 int usb_host_eth_scan(int mode)
 {
 	int i, old_async;
-	struct usb_device *dev;
-
 
 	if (mode == 1)
 		printf("       scanning usb for ethernet devices... ");
@@ -138,23 +138,59 @@ int usb_host_eth_scan(int mode)
 	}
 
 	usb_max_eth_dev = 0;
+#ifdef CONFIG_DM_USB
+	/*
+	 * TODO: We should add USB_DEVICE() declarations to each USB ethernet
+	 * driver and then most of this file can be removed.
+	 */
+	struct udevice *bus;
+	struct uclass *uc;
+	int ret;
+
+	ret = uclass_get(UCLASS_USB, &uc);
+	if (ret)
+		return ret;
+	uclass_foreach_dev(bus, uc) {
+		for (i = 0; i < USB_MAX_DEVICE; i++) {
+			struct usb_device *dev;
+
+			dev = usb_get_dev_index(bus, i); /* get device */
+			debug("i=%d, %s\n", i, dev ? dev->dev->name : "(done)");
+			if (!dev)
+				break; /* no more devices available */
+
+			/*
+			 * find valid usb_ether driver for this device,
+			 * if any
+			 */
+			probe_valid_drivers(dev);
+
+			/* check limit */
+			if (usb_max_eth_dev == USB_MAX_ETH_DEV)
+				break;
+		} /* for */
+	}
+#else
 	for (i = 0; i < USB_MAX_DEVICE; i++) {
+		struct usb_device *dev;
+
 		dev = usb_get_dev_index(i); /* get device */
 		debug("i=%d\n", i);
-		if (dev == NULL)
+		if (!dev)
 			break; /* no more devices available */
 
 		/* find valid usb_ether driver for this device, if any */
 		probe_valid_drivers(dev);
 
 		/* check limit */
-		if (usb_max_eth_dev == USB_MAX_ETH_DEV) {
-			printf("max USB Ethernet Device reached: %d stopping\n",
-				usb_max_eth_dev);
+		if (usb_max_eth_dev == USB_MAX_ETH_DEV)
 			break;
-		}
 	} /* for */
-
+#endif
+	if (usb_max_eth_dev == USB_MAX_ETH_DEV) {
+		printf("max USB Ethernet Device reached: %d stopping\n",
+		       usb_max_eth_dev);
+	}
 	usb_disable_asynch(old_async); /* restore asynch value */
 	printf("%d Ethernet Device(s) found\n", usb_max_eth_dev);
 	if (usb_max_eth_dev > 0)
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#111 lore raw

PATCH v2 55/80 dm: usb: Add support for USB ethernet devices with driver model

Quoted 11 lines · Simon Glass

Add support for scanning USB etghernet devices with driver model. This mostly involves scanning all buses since device numbering is not unique across buses.

---

Changes in v2: None

 drivers/usb/eth/usb_ether.c | 52 ++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 44 insertions(+), 8 deletions(-)

Applied to u-boot-dm/next.

#112 lore raw

PATCH v2 56/80 dm: usb: exynos: Add driver model support to exynos EHCI

In reply to Simon Glass

Update this driver with driver model support for USB.

---

Changes in v2: None

 drivers/usb/host/ehci-exynos.c | 112 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 111 insertions(+), 1 deletion(-)
drivers/usb/host/ehci-exynos.c +111 -1
index f3c077d..86cf631 100644
@@ -8,6 +8,7 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <fdtdec.h>
 #include <libfdt.h>
 #include <malloc.h>
@@ -24,19 +25,73 @@
 /* Declare global data pointer */
 DECLARE_GLOBAL_DATA_PTR;
 
+#ifdef CONFIG_DM_USB
+struct exynos_ehci_platdata {
+	struct usb_platdata usb_plat;
+	fdt_addr_t hcd_base;
+	fdt_addr_t phy_base;
+	struct gpio_desc vbus_gpio;
+};
+#endif
+
 /**
  * Contains pointers to register base addresses
  * for the usb controller.
  */
 struct exynos_ehci {
+	struct ehci_ctrl ctrl;
 	struct exynos_usb_phy *usb;
 	struct ehci_hccr *hcd;
+#ifndef CONFIG_DM_USB
 	struct gpio_desc vbus_gpio;
+#endif
 };
 
+#ifndef CONFIG_DM_USB
 static struct exynos_ehci exynos;
+#endif
 
-#ifdef CONFIG_OF_CONTROL
+#ifdef CONFIG_DM_USB
+static int ehci_usb_ofdata_to_platdata(struct udevice *dev)
+{
+	struct exynos_ehci_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 = dev_get_addr(dev);
+	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_EXYNOS_USB_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_usb_parse_dt(const void *blob, struct exynos_ehci *exynos)
 {
 	fdt_addr_t addr;
@@ -215,6 +270,7 @@ static void reset_usb_phy(struct exynos_usb_phy *usb)
 	set_usbhost_phy_ctrl(POWER_USB_HOST_PHY_CTRL_DISABLE);
 }
 
+#ifndef CONFIG_DM_USB
 /*
  * EHCI-initialization
  * Create the appropriate control structures to manage
@@ -268,3 +324,57 @@ int ehci_hcd_stop(int index)
 
 	return 0;
 }
+#endif
+
+#ifdef CONFIG_DM_USB
+static int ehci_usb_probe(struct udevice *dev)
+{
+	struct exynos_ehci_platdata *plat = dev_get_platdata(dev);
+	struct exynos_ehci *ctx = dev_get_priv(dev);
+	struct ehci_hcor *hcor;
+
+	ctx->hcd = (struct ehci_hccr *)plat->hcd_base;
+	ctx->usb = (struct exynos_usb_phy *)plat->phy_base;
+	hcor = (struct ehci_hcor *)((uint32_t)ctx->hcd +
+			HC_LENGTH(ehci_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);
+
+	setup_usb_phy(ctx->usb);
+
+	return ehci_register(dev, ctx->hcd, hcor, NULL, 0, USB_INIT_HOST);
+}
+
+static int ehci_usb_remove(struct udevice *dev)
+{
+	struct exynos_ehci *ctx = dev_get_priv(dev);
+	int ret;
+
+	ret = ehci_deregister(dev);
+	if (ret)
+		return ret;
+	reset_usb_phy(ctx->usb);
+
+	return 0;
+}
+
+static const struct udevice_id ehci_usb_ids[] = {
+	{ .compatible = "samsung,exynos-ehci" },
+	{ }
+};
+
+U_BOOT_DRIVER(usb_ehci) = {
+	.name	= "ehci_exynos",
+	.id	= UCLASS_USB,
+	.of_match = ehci_usb_ids,
+	.ofdata_to_platdata = ehci_usb_ofdata_to_platdata,
+	.probe = ehci_usb_probe,
+	.remove = ehci_usb_remove,
+	.ops	= &ehci_usb_ops,
+	.priv_auto_alloc_size = sizeof(struct exynos_ehci),
+	.platdata_auto_alloc_size = sizeof(struct exynos_ehci_platdata),
+	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
+};
+#endif
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#113 lore raw

PATCH v2 56/80 dm: usb: exynos: Add driver model support to exynos EHCI

Quoted 9 lines · Simon Glass

Update this driver with driver model support for USB.

---

Changes in v2: None

 drivers/usb/host/ehci-exynos.c | 112 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 111 insertions(+), 1 deletion(-)

Applied to u-boot-dm/next.

#114 lore raw

PATCH v2 57/80 dm: usb: tegra: Remove the port_addr_clear_csc variable

In reply to Simon Glass

This variable is a bit of a hack. We can obtain the same information from the normal device config. This will fit better with driver model, where global variables are best avoided.

---

Changes in v2: None

 drivers/usb/host/ehci-tegra.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)
drivers/usb/host/ehci-tegra.c +1 -5
index 38333c7..464f55d 100644
@@ -87,8 +87,6 @@ struct fdt_usb {
 
 static struct fdt_usb port[USB_PORTS_MAX];	/* List of valid USB ports */
 static unsigned port_count;			/* Number of available ports */
-/* Port that needs to clear CSC after Port Reset */
-static u32 port_addr_clear_csc;
 
 /*
  * This table has USB timing parameters for each Oscillator frequency we
@@ -206,7 +204,7 @@ static void tegra_ehci_powerup_fixup(struct ehci_ctrl *ctrl,
 	if (controller->has_hostpc)
 		*reg |= EHCI_PS_PE;
 
-	if (((u32)status_reg & TEGRA_USB_ADDR_MASK) != port_addr_clear_csc)
+	if (!config->has_legacy_mode)
 		return;
 	/* For EHCI_PS_CSC to be cleared in ehci_hcd.c */
 	if (ehci_readl(status_reg) & EHCI_PS_CSC)
@@ -683,8 +681,6 @@ static int fdt_decode_usb(const void *blob, int node, struct fdt_usb *config)
 	config->enabled = fdtdec_get_is_enabled(blob, node);
 	config->has_legacy_mode = fdtdec_get_bool(blob, node,
 						  "nvidia,has-legacy-mode");
-	if (config->has_legacy_mode)
-		port_addr_clear_csc = (u32) config->reg;
 	config->periph_id = clock_decode_periph_id(blob, node);
 	if (config->periph_id == PERIPH_ID_NONE) {
 		debug("%s: Missing/invalid peripheral ID\n", __func__);
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#115 lore raw

PATCH v2 57/80 dm: usb: tegra: Remove the port_addr_clear_csc variable

Quoted 22 lines

-----Original Message-----
From: U-Boot [mailto:u-boot-bounces at lists.denx.de] On Behalf Of Simon Glass
Sent: Thursday, March 26, 2015 2:23 AM
To: U-Boot Mailing List
Cc: Marek Vasut; Stephen Warren; Vivek Gautam; Tom Warren
Subject: [U-Boot] [PATCH v2 57/80] dm: usb: tegra: Remove the port_addr_clear_csc variable

This variable is a bit of a hack. We can obtain the same information from the normal device config. This will fit better with driver model, where global variables > are best avoided.

---

Changes in v2: None

 drivers/usb/host/ehci-tegra.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

drivers/usb/host/ehci-tegra.c struct fdt_usb { · line 92

Quoted 7 lines
drivers/usb/host/ehci-tegra.c +0 -1
@@ -87,8 +87,6 @@ struct fdt_usb {
 
 static struct fdt_usb port[USB_PORTS_MAX];	/* List of valid USB ports */
 static unsigned port_count;			/* Number of available ports */
-/* Port that needs to clear CSC after Port Reset */ -static u32 port_addr_clear_csc;
 
 /*
  * This table has USB timing parameters for each Oscillator frequency we @@ -206,7 +204,7 @@ static void tegra_ehci_powerup_fixup(struct ehci_ctrl *ctrl,

if (controller->has_hostpc)

drivers/usb/host/ehci-tegra.c static void tegra_ehci_powerup_fixup(struct ehci_ctrl *ctrl, · line 208

Quoted 5 lines
drivers/usb/host/ehci-tegra.c +1 -1
 		*reg |= EHCI_PS_PE;
 
-	if (((u32)status_reg & TEGRA_USB_ADDR_MASK) != port_addr_clear_csc)
+	if (!config->has_legacy_mode)
 		return;

How do we get config (config->has_legacy_mode) for in this function? If you read ehci_set_usbmode, "config" comes from
"config = &port[index];".
Or "config" is an input argument like set_up_vbus(struct fdt_usb *config, ...) But for ehci_powerup_fixup, I don't see a way for us to get "config".

Quoted 1 line

/* For EHCI_PS_CSC to be cleared in ehci_hcd.c */

--nvpublic

#116 lore raw

PATCH v2 57/80 dm: usb: tegra: Remove the port_addr_clear_csc variable

Please ignore my question because it is answered by [PATCH v2 34/80].

Quoted 46 lines · Jim Lin
Quoted 21 lines

-----Original Message-----
From: U-Boot [mailto:u-boot-bounces at lists.denx.de] On Behalf Of Simon Glass
Sent: Thursday, March 26, 2015 2:23 AM
To: U-Boot Mailing List
Cc: Marek Vasut; Stephen Warren; Vivek Gautam; Tom Warren
Subject: [U-Boot] [PATCH v2 57/80] dm: usb: tegra: Remove the port_addr_clear_csc variable

This variable is a bit of a hack. We can obtain the same information from the normal device config. This will fit better with driver model, where global variables > are best avoided.

---

Changes in v2: None

  drivers/usb/host/ehci-tegra.c | 6 +-----
  1 file changed, 1 insertion(+), 5 deletions(-)

drivers/usb/host/ehci-tegra.c struct fdt_usb { · line 92

Quoted 7 lines
drivers/usb/host/ehci-tegra.c +0 -1
@@ -87,8 +87,6 @@ struct fdt_usb {
 
  static struct fdt_usb port[USB_PORTS_MAX];	/* List of valid USB ports */
  static unsigned port_count;			/* Number of available ports */
-/* Port that needs to clear CSC after Port Reset */ -static u32 port_addr_clear_csc;
 
  /*
   * This table has USB timing parameters for each Oscillator frequency we @@ -206,7 +204,7 @@ static void tegra_ehci_powerup_fixup(struct ehci_ctrl *ctrl,

if (controller->has_hostpc)

drivers/usb/host/ehci-tegra.c static void tegra_ehci_powerup_fixup(struct ehci_ctrl *ctrl, · line 208

Quoted 5 lines
drivers/usb/host/ehci-tegra.c +1 -1
  		*reg |= EHCI_PS_PE;
 
-	if (((u32)status_reg & TEGRA_USB_ADDR_MASK) != port_addr_clear_csc)
+	if (!config->has_legacy_mode)
  		return;

How do we get config (config->has_legacy_mode) for in this function? If you read ehci_set_usbmode, "config" comes from
"config = &port[index];".
Or "config" is an input argument like set_up_vbus(struct fdt_usb *config, ...) But for ehci_powerup_fixup, I don't see a way for us to get "config".

Quoted 1 line

/* For EHCI_PS_CSC to be cleared in ehci_hcd.c */

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

#117 lore raw

PATCH v2 57/80 dm: usb: tegra: Remove the port_addr_clear_csc variable

Quoted 66 lines · Jim Lin

Please ignore my question because it is answered by [PATCH v2 34/80].

Quoted 60 lines · Jim Lin
Quoted 32 lines

-----Original Message-----
From: U-Boot [mailto:u-boot-bounces at lists.denx.de] On Behalf Of Simon Glass
Sent: Thursday, March 26, 2015 2:23 AM
To: U-Boot Mailing List
Cc: Marek Vasut; Stephen Warren; Vivek Gautam; Tom Warren
Subject: [U-Boot] [PATCH v2 57/80] dm: usb: tegra: Remove the port_addr_clear_csc variable

This variable is a bit of a hack. We can obtain the same information from the normal device config. This will fit better with driver model, where global variables > are best avoided.

---

Changes in v2: None

  drivers/usb/host/ehci-tegra.c | 6 +-----
  1 file changed, 1 insertion(+), 5 deletions(-)
(quoted diff) +0 -0

b/drivers/usb/host/ehci-tegra.c index 38333c7..464f55d 100644

drivers/usb/host/ehci-tegra.c +0 -0
@@ -87,8 +87,6 @@ struct fdt_usb {
    static struct fdt_usb port[USB_PORTS_MAX];  /* List of valid USB

ports */
static unsigned port_count; /* Number of available
ports */
-/* Port that needs to clear CSC after Port Reset */ -static u32

Quoted 5 lines
port_addr_clear_csc;
    /*

* This table has USB timing parameters for each Oscillator frequency
we @@ -206,7 +204,7 @@ static void tegra_ehci_powerup_fixup(struct ehci_ctrl *ctrl,

        if (controller->has_hostpc)
Quoted 6 lines
                *reg |= EHCI_PS_PE;
  -     if (((u32)status_reg & TEGRA_USB_ADDR_MASK) !=
port_addr_clear_csc)
+       if (!config->has_legacy_mode)
                return;

How do we get config (config->has_legacy_mode) for in this function? If you read ehci_set_usbmode, "config" comes from
"config = &port[index];".
Or "config" is an input argument like set_up_vbus(struct fdt_usb *config, ...)
But for ehci_powerup_fixup, I don't see a way for us to get "config".

Quoted 1 line
        /* For EHCI_PS_CSC to be cleared in ehci_hcd.c */

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

Applied to u-boot-dm/next.

#118 lore raw

PATCH v2 58/80 dm: usb: tegra: Tidy up error handling and a static function

In reply to Simon Glass

Try to return useful error numbers where possible. Also avoid swallowing an error number when it is returned by a called function.

---

Changes in v2: None

 drivers/usb/host/ehci-tegra.c | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)
drivers/usb/host/ehci-tegra.c +11 -8
index 464f55d..04653e4 100644
@@ -266,7 +266,8 @@ static void set_up_vbus(struct fdt_usb *config, enum usb_init_type init)
 	}
 }
 
-void usbf_reset_controller(struct fdt_usb *config, struct usb_ctlr *usbctlr)
+static void usbf_reset_controller(struct fdt_usb *config,
+				  struct usb_ctlr *usbctlr)
 {
 	/* Reset the USB controller with 2us delay */
 	reset_periph(config->periph_id, 2);
@@ -524,7 +525,7 @@ static int init_utmi_usb_controller(struct fdt_usb *config,
 		udelay(1);
 	}
 	if (!loop_count)
-		return -1;
+		return -ETIMEDOUT;
 
 	/* Disable ICUSB FS/LS transceiver */
 	clrbits_le32(&usbctlr->icusb_ctrl, IC_ENB1);
@@ -567,6 +568,7 @@ static int init_ulpi_usb_controller(struct fdt_usb *config,
 	int loop_count;
 	struct ulpi_viewport ulpi_vp;
 	struct usb_ctlr *usbctlr = config->reg;
+	int ret;
 
 	/* set up ULPI reference clock on pllp_out4 */
 	clock_enable(PERIPH_ID_DEV2_OUT);
@@ -612,9 +614,10 @@ static int init_ulpi_usb_controller(struct fdt_usb *config,
 	ulpi_vp.port_num = 0;
 	ulpi_vp.viewport_addr = (u32)&usbctlr->ulpi_viewport;
 
-	if (ulpi_init(&ulpi_vp)) {
+	ret = ulpi_init(&ulpi_vp);
+	if (ret) {
 		printf("Tegra ULPI viewport init failed\n");
-		return -1;
+		return ret;
 	}
 
 	ulpi_set_vbus(&ulpi_vp, 1, 1);
@@ -631,7 +634,7 @@ static int init_ulpi_usb_controller(struct fdt_usb *config,
 		udelay(1);
 	}
 	if (!loop_count)
-		return -1;
+		return -ETIMEDOUT;
 	clrbits_le32(&usbctlr->susp_ctrl, USB_SUSP_CLR);
 
 	return 0;
@@ -642,7 +645,7 @@ static int init_ulpi_usb_controller(struct fdt_usb *config,
 {
 	printf("No code to set up ULPI controller, please enable"
 			"CONFIG_USB_ULPI and CONFIG_USB_ULPI_VIEWPORT");
-	return -1;
+	return -ENOSYS;
 }
 #endif
 
@@ -669,7 +672,7 @@ static int fdt_decode_usb(const void *blob, int node, struct fdt_usb *config)
 		else {
 			debug("%s: Cannot decode dr_mode '%s'\n", __func__,
 			      mode);
-			return -FDT_ERR_NOTFOUND;
+			return -EINVAL;
 		}
 	} else {
 		config->dr_mode = DR_MODE_HOST;
@@ -684,7 +687,7 @@ static int fdt_decode_usb(const void *blob, int node, struct fdt_usb *config)
 	config->periph_id = clock_decode_periph_id(blob, node);
 	if (config->periph_id == PERIPH_ID_NONE) {
 		debug("%s: Missing/invalid peripheral ID\n", __func__);
-		return -FDT_ERR_NOTFOUND;
+		return -EINVAL;
 	}
 	gpio_request_by_name_nodev(blob, node, "nvidia,vbus-gpio", 0,
 				   &config->vbus_gpio, GPIOD_IS_OUT);
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#119 lore raw

PATCH v2 58/80 dm: usb: tegra: Tidy up error handling and a static function

Quoted 10 lines · Simon Glass

Try to return useful error numbers where possible. Also avoid swallowing an error number when it is returned by a called function.

---

Changes in v2: None

 drivers/usb/host/ehci-tegra.c | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

Applied to u-boot-dm/next.

#120 lore raw

PATCH v2 59/80 dm: usb: tegra: Move most of init/uninit into a function

In reply to Simon Glass

We want to use mostly the same init and uninit code for driver model, so move the common part into two functions.

---

Changes in v2: None

 drivers/usb/host/ehci-tegra.c | 143 ++++++++++++++++++++++++------------------
 1 file changed, 81 insertions(+), 62 deletions(-)
drivers/usb/host/ehci-tegra.c +81 -62
index 04653e4..940a583 100644
@@ -703,6 +703,82 @@ static int fdt_decode_usb(const void *blob, int node, struct fdt_usb *config)
 	return 0;
 }
 
+int usb_common_init(struct fdt_usb *config, enum usb_init_type init)
+{
+	int ret = 0;
+
+	switch (init) {
+	case USB_INIT_HOST:
+		switch (config->dr_mode) {
+		case DR_MODE_HOST:
+		case DR_MODE_OTG:
+			break;
+		default:
+			printf("tegrausb: Invalid dr_mode %d for host mode\n",
+			       config->dr_mode);
+			return -1;
+		}
+		break;
+	case USB_INIT_DEVICE:
+		if (config->periph_id != PERIPH_ID_USBD) {
+			printf("tegrausb: Device mode only supported on first USB controller\n");
+			return -1;
+		}
+		if (!config->utmi) {
+			printf("tegrausb: Device mode only supported with UTMI PHY\n");
+			return -1;
+		}
+		switch (config->dr_mode) {
+		case DR_MODE_DEVICE:
+		case DR_MODE_OTG:
+			break;
+		default:
+			printf("tegrausb: Invalid dr_mode %d for device mode\n",
+			       config->dr_mode);
+			return -1;
+		}
+		break;
+	default:
+		printf("tegrausb: Unknown USB_INIT_* %d\n", init);
+		return -1;
+	}
+
+#ifndef CONFIG_DM_USB
+	/* skip init, if the port is already initialized */
+	if (config->initialized && config->init_type == init)
+		return 0;
+#endif
+
+	debug("%d, %d\n", config->utmi, config->ulpi);
+	if (config->utmi)
+		ret = init_utmi_usb_controller(config, init);
+	else if (config->ulpi)
+		ret = init_ulpi_usb_controller(config, init);
+	if (ret)
+		return ret;
+
+	set_up_vbus(config, init);
+
+	config->init_type = init;
+
+	return 0;
+}
+
+void usb_common_uninit(struct fdt_usb *priv)
+{
+	struct usb_ctlr *usbctlr;
+
+	usbctlr = priv->reg;
+
+	/* Stop controller */
+	writel(0, &usbctlr->usb_cmd);
+	udelay(1000);
+
+	/* Initiate controller reset */
+	writel(2, &usbctlr->usb_cmd);
+	udelay(1000);
+}
+
 static const struct ehci_ops tegra_ehci_ops = {
 	.set_usb_mode		= tegra_ehci_set_usbmode,
 	.get_port_speed		= tegra_ehci_get_port_speed,
@@ -795,6 +871,7 @@ int ehci_hcd_init(int index, enum usb_init_type init,
 {
 	struct fdt_usb *config;
 	struct usb_ctlr *usbctlr;
+	int ret;
 
 	if (index >= port_count)
 		return -1;
@@ -802,62 +879,14 @@ int ehci_hcd_init(int index, enum usb_init_type init,
 	config = &port[index];
 	ehci_set_controller_priv(index, config, &tegra_ehci_ops);
 
-	switch (init) {
-	case USB_INIT_HOST:
-		switch (config->dr_mode) {
-		case DR_MODE_HOST:
-		case DR_MODE_OTG:
-			break;
-		default:
-			printf("tegrausb: Invalid dr_mode %d for host mode\n",
-			       config->dr_mode);
-			return -1;
-		}
-		break;
-	case USB_INIT_DEVICE:
-		if (config->periph_id != PERIPH_ID_USBD) {
-			printf("tegrausb: Device mode only supported on first USB controller\n");
-			return -1;
-		}
-		if (!config->utmi) {
-			printf("tegrausb: Device mode only supported with UTMI PHY\n");
-			return -1;
-		}
-		switch (config->dr_mode) {
-		case DR_MODE_DEVICE:
-		case DR_MODE_OTG:
-			break;
-		default:
-			printf("tegrausb: Invalid dr_mode %d for device mode\n",
-			       config->dr_mode);
-			return -1;
-		}
-		break;
-	default:
-		printf("tegrausb: Unknown USB_INIT_* %d\n", init);
-		return -1;
-	}
-
-	/* skip init, if the port is already initialized */
-	if (config->initialized && config->init_type == init)
-		goto success;
-
-	if (config->utmi && init_utmi_usb_controller(config, init)) {
-		printf("tegrausb: Cannot init port %d\n", index);
-		return -1;
-	}
-
-	if (config->ulpi && init_ulpi_usb_controller(config, init)) {
+	ret = usb_common_init(config, init);
+	if (ret) {
 		printf("tegrausb: Cannot init port %d\n", index);
-		return -1;
+		return ret;
 	}
 
-	set_up_vbus(config, init);
-
 	config->initialized = 1;
-	config->init_type = init;
 
-success:
 	usbctlr = config->reg;
 	*hccr = (struct ehci_hccr *)&usbctlr->cap_length;
 	*hcor = (struct ehci_hcor *)&usbctlr->usb_cmd;
@@ -870,17 +899,7 @@ success:
  */
 int ehci_hcd_stop(int index)
 {
-	struct usb_ctlr *usbctlr;
-
-	usbctlr = port[index].reg;
-
-	/* Stop controller */
-	writel(0, &usbctlr->usb_cmd);
-	udelay(1000);
-
-	/* Initiate controller reset */
-	writel(2, &usbctlr->usb_cmd);
-	udelay(1000);
+	usb_common_uninit(&port[index]);
 
 	port[index].initialized = 0;
 
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#121 lore raw

PATCH v2 59/80 dm: usb: tegra: Move most of init/uninit into a function

Quoted 10 lines · Simon Glass

We want to use mostly the same init and uninit code for driver model, so move the common part into two functions.

---

Changes in v2: None

 drivers/usb/host/ehci-tegra.c | 143 ++++++++++++++++++++++++------------------
 1 file changed, 81 insertions(+), 62 deletions(-)

Applied to u-boot-dm/next.

#122 lore raw

PATCH v2 60/80 dm: usb: tegra: Add driver model support to tegra EHCI

In reply to Simon Glass

Update this driver with driver model support for USB.

---

Changes in v2: None

 drivers/usb/host/ehci-tegra.c | 83 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 83 insertions(+)
drivers/usb/host/ehci-tegra.c +83 -0
index 940a583..66e5649 100644
@@ -7,6 +7,7 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <asm/errno.h>
 #include <asm/io.h>
 #include <asm-generic/gpio.h>
@@ -20,6 +21,8 @@
 
 #include "ehci.h"
 
+DECLARE_GLOBAL_DATA_PTR;
+
 #define USB1_ADDR_MASK	0xFFFF0000
 
 #define HOSTPC1_DEVLC	0x84
@@ -32,9 +35,11 @@
 	#endif
 #endif
 
+#ifndef CONFIG_DM_USB
 enum {
 	USB_PORTS_MAX	= 3,		/* Maximum ports we allow */
 };
+#endif
 
 /* Parameters we need for USB */
 enum {
@@ -71,12 +76,15 @@ enum usb_ctlr_type {
 
 /* Information about a USB port */
 struct fdt_usb {
+	struct ehci_ctrl ehci;
 	struct usb_ctlr *reg;	/* address of registers in physical memory */
 	unsigned utmi:1;	/* 1 if port has external tranceiver, else 0 */
 	unsigned ulpi:1;	/* 1 if port has external ULPI transceiver */
 	unsigned enabled:1;	/* 1 to enable, 0 to disable */
 	unsigned has_legacy_mode:1; /* 1 if this port has legacy mode */
+#ifndef CONFIG_DM_USB
 	unsigned initialized:1; /* has this port already been initialized? */
+#endif
 	enum usb_ctlr_type type;
 	enum usb_init_type init_type;
 	enum dr_mode dr_mode;	/* dual role mode */
@@ -85,8 +93,10 @@ struct fdt_usb {
 	struct gpio_desc phy_reset_gpio; /* GPIO to reset ULPI phy */
 };
 
+#ifndef CONFIG_DM_USB
 static struct fdt_usb port[USB_PORTS_MAX];	/* List of valid USB ports */
 static unsigned port_count;			/* Number of available ports */
+#endif
 
 /*
  * This table has USB timing parameters for each Oscillator frequency we
@@ -163,6 +173,7 @@ static const u8 utmip_elastic_limit = 16;
 static const u8 utmip_hs_sync_start_delay = 9;
 
 struct fdt_usb_controller {
+	/* TODO(sjg at chromium.org): Remove when we only use driver model */
 	int compat;
 	/* flag to determine whether controller supports hostpc register */
 	u32 has_hostpc:1;
@@ -785,6 +796,7 @@ static const struct ehci_ops tegra_ehci_ops = {
 	.powerup_fixup		= tegra_ehci_powerup_fixup,
 };
 
+#ifndef CONFIG_DM_USB
 /*
  * process_usb_nodes() - Process a list of USB nodes, adding them to our list
  *			of USB ports.
@@ -905,3 +917,74 @@ int ehci_hcd_stop(int index)
 
 	return 0;
 }
+#endif /* !CONFIG_DM_USB */
+
+#ifdef CONFIG_DM_USB
+static int ehci_usb_ofdata_to_platdata(struct udevice *dev)
+{
+	struct fdt_usb *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = fdt_decode_usb(gd->fdt_blob, dev->of_offset, priv);
+	if (ret)
+		return ret;
+
+	priv->type = dev_get_driver_data(dev);
+
+	return 0;
+}
+
+static int ehci_usb_probe(struct udevice *dev)
+{
+	struct usb_platdata *plat = dev_get_platdata(dev);
+	struct fdt_usb *priv = dev_get_priv(dev);
+	struct ehci_hccr *hccr;
+	struct ehci_hcor *hcor;
+	static bool clk_done;
+	int ret;
+
+	ret = usb_common_init(priv, plat->init_type);
+	if (ret)
+		return ret;
+	hccr = (struct ehci_hccr *)&priv->reg->cap_length;
+	hcor = (struct ehci_hcor *)&priv->reg->usb_cmd;
+	if (!clk_done) {
+		config_clock(get_pll_timing(&fdt_usb_controllers[priv->type]));
+		clk_done = true;
+	}
+
+	return ehci_register(dev, hccr, hcor, &tegra_ehci_ops, 0,
+			     plat->init_type);
+}
+
+static int ehci_usb_remove(struct udevice *dev)
+{
+	int ret;
+
+	ret = ehci_deregister(dev);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static const struct udevice_id ehci_usb_ids[] = {
+	{ .compatible = "nvidia,tegra20-ehci", .data = USB_CTLR_T20 },
+	{ .compatible = "nvidia,tegra30-ehci", .data = USB_CTLR_T30 },
+	{ .compatible = "nvidia,tegra114-ehci", .data = USB_CTLR_T114 },
+	{ }
+};
+
+U_BOOT_DRIVER(usb_ehci) = {
+	.name	= "ehci_tegra",
+	.id	= UCLASS_USB,
+	.of_match = ehci_usb_ids,
+	.ofdata_to_platdata = ehci_usb_ofdata_to_platdata,
+	.probe = ehci_usb_probe,
+	.remove = ehci_usb_remove,
+	.ops	= &ehci_usb_ops,
+	.platdata_auto_alloc_size = sizeof(struct usb_platdata),
+	.priv_auto_alloc_size = sizeof(struct fdt_usb),
+	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
+};
+#endif
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#123 lore raw

PATCH v2 60/80 dm: usb: tegra: Add driver model support to tegra EHCI

Quoted 9 lines · Simon Glass

Update this driver with driver model support for USB.

---

Changes in v2: None

 drivers/usb/host/ehci-tegra.c | 83 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 83 insertions(+)

Applied to u-boot-dm/next.

#124 lore raw

PATCH v2 61/80 dm: usb: xhci: Use a function to get xhci_ctrl

In reply to Simon Glass

Rather than getting this directly from struct usb_device, call a function to obtain it. This will make it possible for driver model to provide it another way.

---

Changes in v2: None

 drivers/usb/host/xhci-ring.c |  8 ++++----
 drivers/usb/host/xhci.c      | 19 ++++++++++++-------
 drivers/usb/host/xhci.h      |  2 ++
 3 files changed, 18 insertions(+), 11 deletions(-)
drivers/usb/host/xhci-ring.c +4 -4
index b5aade9..246b697 100644
@@ -353,7 +353,7 @@ static void giveback_first_trb(struct usb_device *udev, int ep_index,
 				int start_cycle,
 				struct xhci_generic_trb *start_trb)
 {
-	struct xhci_ctrl *ctrl = udev->controller;
+	struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
 
 	/*
 	 * Pass all the TRBs to the hardware at once and make sure this write
@@ -477,7 +477,7 @@ union xhci_trb *xhci_wait_for_event(struct xhci_ctrl *ctrl, trb_type expected)
  */
 static void abort_td(struct usb_device *udev, int ep_index)
 {
-	struct xhci_ctrl *ctrl = udev->controller;
+	struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
 	struct xhci_ring *ring =  ctrl->devs[udev->slot_id]->eps[ep_index].ring;
 	union xhci_trb *event;
 	u32 field;
@@ -554,7 +554,7 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
 	int start_cycle;
 	u32 field = 0;
 	u32 length_field = 0;
-	struct xhci_ctrl *ctrl = udev->controller;
+	struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
 	int slot_id = udev->slot_id;
 	int ep_index;
 	struct xhci_virt_device *virt_dev;
@@ -748,7 +748,7 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe,
 	u32 length_field;
 	u64 buf_64 = 0;
 	struct xhci_generic_trb *start_trb;
-	struct xhci_ctrl *ctrl = udev->controller;
+	struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
 	int slot_id = udev->slot_id;
 	int ep_index;
 	u32 trb_fields[4];
drivers/usb/host/xhci.c +12 -7
index 87f2972..ab39878 100644
@@ -110,6 +110,11 @@ static struct descriptor {
 
 static struct xhci_ctrl xhcic[CONFIG_USB_MAX_CONTROLLER_COUNT];
 
+struct xhci_ctrl *xhci_get_ctrl(struct usb_device *udev)
+{
+	return udev->controller;
+}
+
 /**
  * Waits for as per specified amount of time
  * for the "result" to match with "done"
@@ -250,7 +255,7 @@ static int xhci_configure_endpoints(struct usb_device *udev, bool ctx_change)
 {
 	struct xhci_container_ctx *in_ctx;
 	struct xhci_virt_device *virt_dev;
-	struct xhci_ctrl *ctrl = udev->controller;
+	struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
 	union xhci_trb *event;
 
 	virt_dev = ctrl->devs[udev->slot_id];
@@ -298,7 +303,7 @@ static int xhci_set_configuration(struct usb_device *udev)
 	int ep_index;
 	unsigned int dir;
 	unsigned int ep_type;
-	struct xhci_ctrl *ctrl = udev->controller;
+	struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
 	int num_of_ep;
 	int ep_flag = 0;
 	u64 trb_64 = 0;
@@ -382,7 +387,7 @@ static int xhci_set_configuration(struct usb_device *udev)
 static int xhci_address_device(struct usb_device *udev)
 {
 	int ret = 0;
-	struct xhci_ctrl *ctrl = udev->controller;
+	struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
 	struct xhci_slot_ctx *slot_ctx;
 	struct xhci_input_control_ctx *ctrl_ctx;
 	struct xhci_virt_device *virt_dev;
@@ -463,8 +468,8 @@ static int xhci_address_device(struct usb_device *udev)
  */
 int usb_alloc_device(struct usb_device *udev)
 {
+	struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
 	union xhci_trb *event;
-	struct xhci_ctrl *ctrl = udev->controller;
 	int ret;
 
 	/*
@@ -510,7 +515,7 @@ int usb_alloc_device(struct usb_device *udev)
  */
 int xhci_check_maxpacket(struct usb_device *udev)
 {
-	struct xhci_ctrl *ctrl = udev->controller;
+	struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
 	unsigned int slot_id = udev->slot_id;
 	int ep_index = 0;	/* control endpoint */
 	struct xhci_container_ctx *in_ctx;
@@ -640,7 +645,7 @@ static int xhci_submit_root(struct usb_device *udev, unsigned long pipe,
 	int len, srclen;
 	uint32_t reg;
 	volatile uint32_t *status_reg;
-	struct xhci_ctrl *ctrl = udev->controller;
+	struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
 	struct xhci_hcor *hcor = ctrl->hcor;
 
 	if ((req->requesttype & USB_RT_PORT) &&
@@ -904,7 +909,7 @@ int
 submit_control_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
 					int length, struct devrequest *setup)
 {
-	struct xhci_ctrl *ctrl = udev->controller;
+	struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
 	int ret = 0;
 
 	if (usb_pipetype(pipe) != PIPE_CONTROL) {
drivers/usb/host/xhci.h +2 -0
index 6685ed2..6e76872 100644
@@ -1250,4 +1250,6 @@ 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);
 
+struct xhci_ctrl *xhci_get_ctrl(struct usb_device *udev);
+
 #endif /* HOST_XHCI_H_ */
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#125 lore raw

PATCH v2 61/80 dm: usb: xhci: Use a function to get xhci_ctrl

Quoted 5 lines · Simon Glass

Rather than getting this directly from struct usb_device, call a function to obtain it. This will make it possible for driver model to provide it another way.

Quoted 8 lines

---

Changes in v2: None

 drivers/usb/host/xhci-ring.c |  8 ++++----
 drivers/usb/host/xhci.c      | 19 ++++++++++++-------
 drivers/usb/host/xhci.h      |  2 ++
 3 files changed, 18 insertions(+), 11 deletions(-)

Applied to u-boot-dm/next.

#126 lore raw

PATCH v2 62/80 dm: usb: xhci: Use explicit parameters for xhci_alloc_virt_device()

In reply to Simon Glass

This function should not be delving into struct usb_device. Pass in the parameters it needs directly.

---

Changes in v2: None

 drivers/usb/host/xhci-mem.c | 4 +---
 drivers/usb/host/xhci.c     | 2 +-
 drivers/usb/host/xhci.h     | 2 +-
 3 files changed, 3 insertions(+), 5 deletions(-)
drivers/usb/host/xhci-mem.c +1 -3
index 89908e8..4644ffa 100644
@@ -352,12 +352,10 @@ static struct xhci_container_ctx
  * @param udev	pointer to USB deivce structure
  * @return 0 on success else -1 on failure
  */
-int xhci_alloc_virt_device(struct usb_device *udev)
+int xhci_alloc_virt_device(struct xhci_ctrl *ctrl, unsigned int slot_id)
 {
 	u64 byte_64 = 0;
-	unsigned int slot_id = udev->slot_id;
 	struct xhci_virt_device *virt_dev;
-	struct xhci_ctrl *ctrl = udev->controller;
 
 	/* Slot ID 0 is reserved */
 	if (ctrl->devs[slot_id]) {
drivers/usb/host/xhci.c +1 -1
index ab39878..de006f7 100644
@@ -491,7 +491,7 @@ int usb_alloc_device(struct usb_device *udev)
 
 	xhci_acknowledge_event(ctrl);
 
-	ret = xhci_alloc_virt_device(udev);
+	ret = xhci_alloc_virt_device(ctrl, udev->slot_id);
 	if (ret < 0) {
 		/*
 		 * TODO: Unsuccessful Address Device command shall leave
drivers/usb/host/xhci.h +1 -1
index 6e76872..00faa81 100644
@@ -1246,7 +1246,7 @@ void xhci_flush_cache(uint32_t addr, u32 type_len);
 void xhci_inval_cache(uint32_t addr, u32 type_len);
 void xhci_cleanup(struct xhci_ctrl *ctrl);
 struct xhci_ring *xhci_ring_alloc(unsigned int num_segs, bool link_trbs);
-int xhci_alloc_virt_device(struct usb_device *udev);
+int xhci_alloc_virt_device(struct xhci_ctrl *ctrl, unsigned int slot_id);
 int xhci_mem_init(struct xhci_ctrl *ctrl, struct xhci_hccr *hccr,
 		  struct xhci_hcor *hcor);
 
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#127 lore raw

PATCH v2 62/80 dm: usb: xhci: Use explicit parameters for xhci_alloc_virt_device()

Quoted 4 lines · Simon Glass

This function should not be delving into struct usb_device. Pass in the parameters it needs directly.

Quoted 8 lines

---

Changes in v2: None

 drivers/usb/host/xhci-mem.c | 4 +---
 drivers/usb/host/xhci.c     | 2 +-
 drivers/usb/host/xhci.h     | 2 +-
 3 files changed, 3 insertions(+), 5 deletions(-)

Applied to u-boot-dm/next.

#128 lore raw

PATCH v2 63/80 dm: usb: xhci: Use explicit parameters for xhci_setup_addressable_virt_dev()

In reply to Simon Glass

This function should not be delving into struct usb_device. Pass in the parameters it needs directly.

---

Changes in v2: None

 drivers/usb/host/xhci-mem.c | 19 +++++++------------
 drivers/usb/host/xhci.c     | 29 ++++++++++++++++++++++-------
 drivers/usb/host/xhci.h     |  3 ++-
 3 files changed, 31 insertions(+), 20 deletions(-)
drivers/usb/host/xhci-mem.c +7 -12
index 4644ffa..1b55534 100644
@@ -625,17 +625,16 @@ void xhci_slot_copy(struct xhci_ctrl *ctrl, struct xhci_container_ctx *in_ctx,
  * @param udev pointer to the Device Data Structure
  * @return returns negative value on failure else 0 on success
  */
-void xhci_setup_addressable_virt_dev(struct usb_device *udev)
+void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl, int slot_id,
+				     int speed, int hop_portnr)
 {
-	struct usb_device *hop = udev;
 	struct xhci_virt_device *virt_dev;
 	struct xhci_ep_ctx *ep0_ctx;
 	struct xhci_slot_ctx *slot_ctx;
 	u32 port_num = 0;
 	u64 trb_64 = 0;
-	struct xhci_ctrl *ctrl = udev->controller;
 
-	virt_dev = ctrl->devs[udev->slot_id];
+	virt_dev = ctrl->devs[slot_id];
 
 	BUG_ON(!virt_dev);
 
@@ -646,7 +645,7 @@ void xhci_setup_addressable_virt_dev(struct usb_device *udev)
 	/* Only the control endpoint is valid - one endpoint context */
 	slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1) | 0);
 
-	switch (udev->speed) {
+	switch (speed) {
 	case USB_SPEED_SUPER:
 		slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_SS);
 		break;
@@ -664,11 +663,7 @@ void xhci_setup_addressable_virt_dev(struct usb_device *udev)
 		BUG();
 	}
 
-	/* Extract the root hub port number */
-	if (hop->parent)
-		while (hop->parent->parent)
-			hop = hop->parent;
-	port_num = hop->portnr;
+	port_num = hop_portnr;
 	debug("port_num = %d\n", port_num);
 
 	slot_ctx->dev_info2 |=
@@ -678,9 +673,9 @@ void xhci_setup_addressable_virt_dev(struct usb_device *udev)
 	/* Step 4 - ring already allocated */
 	/* Step 5 */
 	ep0_ctx->ep_info2 = cpu_to_le32(CTRL_EP << EP_TYPE_SHIFT);
-	debug("SPEED = %d\n", udev->speed);
+	debug("SPEED = %d\n", speed);
 
-	switch (udev->speed) {
+	switch (speed) {
 	case USB_SPEED_SUPER:
 		ep0_ctx->ep_info2 |= cpu_to_le32(((512 & MAX_PACKET_MASK) <<
 					MAX_PACKET_SHIFT));
drivers/usb/host/xhci.c +22 -7
index de006f7..774c3e6 100644
@@ -384,7 +384,7 @@ static int xhci_set_configuration(struct usb_device *udev)
  * @param udev pointer to the Device Data Structure
  * @return 0 if successful else error code on failure
  */
-static int xhci_address_device(struct usb_device *udev)
+static int xhci_address_device(struct usb_device *udev, int root_portnr)
 {
 	int ret = 0;
 	struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
@@ -400,8 +400,9 @@ static int xhci_address_device(struct usb_device *udev)
 	 * This is the first Set Address since device plug-in
 	 * so setting up the slot context.
 	 */
-	debug("Setting up addressable devices\n");
-	xhci_setup_addressable_virt_dev(udev);
+	debug("Setting up addressable devices %p\n", ctrl->dcbaa);
+	xhci_setup_addressable_virt_dev(ctrl, udev->slot_id, udev->speed,
+					root_portnr);
 
 	ctrl_ctx = xhci_get_input_control_ctx(virt_dev->in_ctx);
 	ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG | EP0_FLAG);
@@ -903,11 +904,12 @@ submit_bulk_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
  * @param buffer	buffer to be read/written based on the request
  * @param length	length of the buffer
  * @param setup		Request type
+ * @param root_portnr	Root port number that this device is on
  * @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, int root_portnr)
 {
 	struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
 	int ret = 0;
@@ -921,7 +923,7 @@ submit_control_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
 		return xhci_submit_root(udev, pipe, buffer, setup);
 
 	if (setup->request == USB_REQ_SET_ADDRESS)
-		return xhci_address_device(udev);
+		return xhci_address_device(udev, root_portnr);
 
 	if (setup->request == USB_REQ_SET_CONFIGURATION) {
 		ret = xhci_set_configuration(udev);
@@ -1007,6 +1009,19 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
 	return 0;
 }
 
+int submit_control_msg(struct usb_device *udev, unsigned long pipe,
+		       void *buffer, int length, struct devrequest *setup)
+{
+	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,
+					hop->portnr);
+}
+
 /**
  * Stops the XHCI host controller
  * and cleans up all the related data structures
drivers/usb/host/xhci.h +2 -1
index 00faa81..916a5a4 100644
@@ -1232,7 +1232,8 @@ void xhci_endpoint_copy(struct xhci_ctrl *ctrl,
 void xhci_slot_copy(struct xhci_ctrl *ctrl,
 		    struct xhci_container_ctx *in_ctx,
 		    struct xhci_container_ctx *out_ctx);
-void xhci_setup_addressable_virt_dev(struct usb_device *udev);
+void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl, int slot_id,
+				     int speed, int hop_portnr);
 void xhci_queue_command(struct xhci_ctrl *ctrl, u8 *ptr,
 			u32 slot_id, u32 ep_index, trb_type cmd);
 void xhci_acknowledge_event(struct xhci_ctrl *ctrl);
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#129 lore raw

PATCH v2 63/80 dm: usb: xhci: Use explicit parameters for xhci_setup_addressable_virt_dev()

Quoted 4 lines · Simon Glass

This function should not be delving into struct usb_device. Pass in the parameters it needs directly.

Quoted 8 lines

---

Changes in v2: None

 drivers/usb/host/xhci-mem.c | 19 +++++++------------
 drivers/usb/host/xhci.c     | 29 ++++++++++++++++++++++-------
 drivers/usb/host/xhci.h     |  3 ++-
 3 files changed, 31 insertions(+), 20 deletions(-)

Applied to u-boot-dm/next.

#130 lore raw

PATCH v2 64/80 dm: usb: xhci: Factor out common init/uninit

In reply to Simon Glass

Since driver model will want to use most of the same code for XHCI init and uninit, put it in a separate function.

---

Changes in v2: None

 drivers/usb/host/xhci.c | 85 ++++++++++++++++++++++++++++++-------------------
 1 file changed, 52 insertions(+), 33 deletions(-)
drivers/usb/host/xhci.c +52 -33
index 774c3e6..4d94618 100644
@@ -936,33 +936,16 @@ static int _xhci_submit_control_msg(struct usb_device *udev, unsigned long pipe,
 	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.
@@ -1004,7 +987,20 @@ 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;
 }
@@ -1023,6 +1019,38 @@ int submit_control_msg(struct usb_device *udev, unsigned long pipe,
 }
 
 /**
+ * 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
  *
@@ -1032,18 +1060,9 @@ int submit_control_msg(struct usb_device *udev, unsigned long pipe,
 int usb_lowlevel_stop(int index)
 {
 	struct xhci_ctrl *ctrl = (xhcic + index);
-	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));
 
+	xhci_lowlevel_stop(ctrl);
 	xhci_hcd_stop(index);
-
 	xhci_cleanup(ctrl);
 
 	return 0;
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#131 lore raw

PATCH v2 64/80 dm: usb: xhci: Factor out common init/uninit

Quoted 10 lines · Simon Glass

Since driver model will want to use most of the same code for XHCI init and uninit, put it in a separate function.

---

Changes in v2: None

 drivers/usb/host/xhci.c | 85 ++++++++++++++++++++++++++++++-------------------
 1 file changed, 52 insertions(+), 33 deletions(-)

Applied to u-boot-dm/next.

#132 lore raw

PATCH v2 65/80 dm: usb: Support driver model in XHCI

In reply to Simon Glass

Add driver model support in the XHCI support code so that it can be used by XHCI USB drivers.

---

Changes in v2: None

 drivers/usb/host/xhci-mem.c |   1 +
 drivers/usb/host/xhci.c     | 179 ++++++++++++++++++++++++++++++++++++++++++--
 drivers/usb/host/xhci.h     |  24 ++++++
 3 files changed, 197 insertions(+), 7 deletions(-)
drivers/usb/host/xhci-mem.c +1 -0
index 1b55534..79cb17e 100644
@@ -15,6 +15,7 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <asm/byteorder.h>
 #include <usb.h>
 #include <malloc.h>
drivers/usb/host/xhci.c +172 -7

235 lines not on this page · raw message

drivers/usb/host/xhci.h +24 -0
index 916a5a4..7f7cb75 100644
@@ -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;
@@ -1251,6 +1254,27 @@ int xhci_alloc_virt_device(struct xhci_ctrl *ctrl, unsigned int slot_id);
 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;
+
 struct xhci_ctrl *xhci_get_ctrl(struct usb_device *udev);
 
 #endif /* HOST_XHCI_H_ */
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#133 lore raw

PATCH v2 65/80 dm: usb: Support driver model in XHCI

Quoted 4 lines · Simon Glass

Add driver model support in the XHCI support code so that it can be used by XHCI USB drivers.

Quoted 8 lines

---

Changes in v2: None

 drivers/usb/host/xhci-mem.c |   1 +
 drivers/usb/host/xhci.c     | 179 ++++++++++++++++++++++++++++++++++++++++++--
 drivers/usb/host/xhci.h     |  24 ++++++
 3 files changed, 197 insertions(+), 7 deletions(-)

Applied to u-boot-dm/next.

#134 lore raw

PATCH v2 66/80 dm: usb: Rename the XHCI HCD to U-Boot

In reply to Simon Glass

This should be "U-Boot", not "u-boot".

---

Changes in v2: None

 drivers/usb/host/xhci.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/host/xhci.c +1 -1
index 6d9d4a6..7396c2d 100644
@@ -704,7 +704,7 @@ static int xhci_submit_root(struct usb_device *udev, unsigned long pipe,
 				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 */
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#135 lore raw

PATCH v2 66/80 dm: usb: Rename the XHCI HCD to U-Boot

Quoted 9 lines · Simon Glass

This should be "U-Boot", not "u-boot".

---

Changes in v2: None

 drivers/usb/host/xhci.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Applied to u-boot-dm/next.

#136 lore raw

PATCH v2 67/80 dm: usb: exynos: Adjust XHCI driver to support driver model

In reply to Simon Glass

Support driver model in the exynos XHCI driver.

---

Changes in v2: None

 drivers/usb/host/xhci-exynos5.c | 120 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 119 insertions(+), 1 deletion(-)
drivers/usb/host/xhci-exynos5.c +119 -1
index 3f86fdc..23c7ecc 100644
@@ -14,6 +14,7 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <fdtdec.h>
 #include <libfdt.h>
 #include <malloc.h>
@@ -32,20 +33,76 @@
 /* Declare global data pointer */
 DECLARE_GLOBAL_DATA_PTR;
 
+#ifdef CONFIG_DM_USB
+struct exynos_xhci_platdata {
+	fdt_addr_t hcd_base;
+	fdt_addr_t phy_base;
+	struct gpio_desc vbus_gpio;
+};
+#endif
+
 /**
  * Contains pointers to register base addresses
  * for the usb controller.
  */
 struct exynos_xhci {
+#ifdef CONFIG_DM_USB
+	struct usb_platdata usb_plat;
+#endif
+	struct xhci_ctrl ctrl;
 	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;
@@ -283,6 +340,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 +384,63 @@ 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,
+	.platdata_auto_alloc_size = sizeof(struct exynos_xhci_platdata),
+	.priv_auto_alloc_size = sizeof(struct exynos_xhci),
+	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
+};
+#endif
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#137 lore raw

PATCH v2 67/80 dm: usb: exynos: Adjust XHCI driver to support driver model

Quoted 9 lines · Simon Glass

Support driver model in the exynos XHCI driver.

---

Changes in v2: None

 drivers/usb/host/xhci-exynos5.c | 120 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 119 insertions(+), 1 deletion(-)

Applied to u-boot-dm/next.

#138 lore raw

PATCH v2 68/80 dm: usb: exynos: Use driver model for USB

In reply to Simon Glass

Convert Exynos boards over to use driver model for USB. This does not remove any unnecessary code so far.

---

Changes in v2: None

 arch/arm/cpu/armv7/exynos/Kconfig | 3 +++
 1 file changed, 3 insertions(+)
arch/arm/cpu/armv7/exynos/Kconfig +3 -0
index eb86a7f..b042fba 100644
@@ -86,6 +86,9 @@ config SYS_MALLOC_F
 config SYS_MALLOC_F_LEN
 	default 0x400
 
+config DM_USB
+	default y
+
 source "board/samsung/smdkv310/Kconfig"
 source "board/samsung/trats/Kconfig"
 source "board/samsung/universal_c210/Kconfig"
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#139 lore raw

PATCH v2 68/80 dm: usb: exynos: Use driver model for USB

Quoted 10 lines · Simon Glass

Convert Exynos boards over to use driver model for USB. This does not remove any unnecessary code so far.

---

Changes in v2: None

 arch/arm/cpu/armv7/exynos/Kconfig | 3 +++
 1 file changed, 3 insertions(+)

Applied to u-boot-dm/next.

#140 lore raw

PATCH v2 69/80 dm: usb: exynos: Enable both USB ports on snow

In reply to Simon Glass

Switch snow over to use both EHCI and XHCI at the same time.

---

Changes in v2: None

 include/configs/snow.h | 2 ++
 1 file changed, 2 insertions(+)
include/configs/snow.h +2 -0
index fe802f2..e024955 100644
@@ -26,7 +26,9 @@
 #define CONFIG_ARCH_EARLY_INIT_R
 
 #define CONFIG_USB_XHCI
+#define CONFIG_USB_EHCI
 #define CONFIG_USB_XHCI_EXYNOS
+#define CONFIG_USB_EHCI_EXYNOS
 
 #define CONFIG_SYS_PROMPT		"snow # "
 #define CONFIG_IDENT_STRING		" for snow"
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#141 lore raw

PATCH v2 69/80 dm: usb: exynos: Enable both USB ports on snow

Quoted 9 lines · Simon Glass

Switch snow over to use both EHCI and XHCI at the same time.

---

Changes in v2: None

 include/configs/snow.h | 2 ++
 1 file changed, 2 insertions(+)

Applied to u-boot-dm/next.

#142 lore raw

PATCH v2 70/80 dm: usb: exynos: Enable both EHCI and XHCI on snow

In reply to Simon Glass

Since we can support both controllers now, enable this in the device tree.

---

Changes in v2: None

 arch/arm/dts/exynos5250-snow.dts | 1 +
 1 file changed, 1 insertion(+)
arch/arm/dts/exynos5250-snow.dts +1 -0
index d6777ee..668961a 100644
@@ -133,6 +133,7 @@
 
 	ehci at 12110000 {
 		samsung,vbus-gpio = <&gpx1 1 GPIO_ACTIVE_HIGH>;
+		status = "okay";
 	};
 
 	xhci at 12000000 {
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#143 lore raw

PATCH v2 70/80 dm: usb: exynos: Enable both EHCI and XHCI on snow

Quoted 9 lines · Simon Glass

Since we can support both controllers now, enable this in the device tree.

---

Changes in v2: None

 arch/arm/dts/exynos5250-snow.dts | 1 +
 1 file changed, 1 insertion(+)

Applied to u-boot-dm/next.

#144 lore raw

PATCH v2 71/80 dm: usb: tegra: Move to driver model for USB

In reply to Simon Glass

Move Tegra boards over to driver model for USB EHCI. There are a few things that are no-longer needed (e.g. in fdtdec.h) but these will be cleaned up in a later patch to be applied one we are confident this change is fully tested.

---

Changes in v2: None

 arch/arm/mach-tegra/Kconfig | 3 +++
 board/nvidia/common/board.c | 2 ++
 2 files changed, 5 insertions(+)
arch/arm/mach-tegra/Kconfig +3 -0
index fccfd79..3625035 100644
@@ -47,6 +47,9 @@ config DM_I2C
 config DM_GPIO
 	default y
 
+config DM_USB
+	default y
+
 source "arch/arm/mach-tegra/tegra20/Kconfig"
 source "arch/arm/mach-tegra/tegra30/Kconfig"
 source "arch/arm/mach-tegra/tegra114/Kconfig"
board/nvidia/common/board.c +2 -0
index 018dddb..a97035c 100644
@@ -128,8 +128,10 @@ int board_init(void)
 
 #ifdef CONFIG_USB_EHCI_TEGRA
 	pin_mux_usb();
+#ifndef CONFIG_DM_USB
 	usb_process_devicetree(gd->fdt_blob);
 #endif
+#endif
 
 #ifdef CONFIG_LCD
 	tegra_lcd_check_next_stage(gd->fdt_blob, 0);
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#145 lore raw

PATCH v2 71/80 dm: usb: tegra: Move to driver model for USB

Quoted 5 lines · Simon Glass

Move Tegra boards over to driver model for USB EHCI. There are a few things that are no-longer needed (e.g. in fdtdec.h) but these will be cleaned up in a later patch to be applied one we are confident this change is fully tested.

Quoted 8 lines

---

Changes in v2: None

 arch/arm/mach-tegra/Kconfig | 3 +++
 board/nvidia/common/board.c | 2 ++
 2 files changed, 5 insertions(+)

Applied to u-boot-dm/next.

#146 lore raw

PATCH v2 72/80 dm: usb: Add a generic descriptor struct

In reply to Simon Glass

This is useful for creating lists of descriptors, and is better than using void * for this purpose.

---

Changes in v2: None

 include/linux/usb/ch9.h | 5 +++++
 1 file changed, 5 insertions(+)
include/linux/usb/ch9.h +5 -0
index 10675b4..822fca0 100644
@@ -379,6 +379,11 @@ struct usb_endpoint_descriptor {
 #define USB_DT_ENDPOINT_SIZE		7
 #define USB_DT_ENDPOINT_AUDIO_SIZE	9	/* Audio extension */
 
+/* Used to access common fields */
+struct usb_generic_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+};
 
 /*
  * Endpoints
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#147 lore raw

PATCH v2 72/80 dm: usb: Add a generic descriptor struct

Quoted 10 lines · Simon Glass

This is useful for creating lists of descriptors, and is better than using void * for this purpose.

---

Changes in v2: None

 include/linux/usb/ch9.h | 5 +++++
 1 file changed, 5 insertions(+)

Applied to u-boot-dm/next.

#148 lore raw

PATCH v2 73/80 dm: usb: Tidy up pipe value decoding

In reply to Simon Glass

Add a few more shifts/masks to make it easier to decode a pipe value (rather than just building it). We need this for USB device emulation.

---

Changes in v2: None

 include/usb_defs.h | 23 +++++++++++++++++------
 1 file changed, 17 insertions(+), 6 deletions(-)
include/usb_defs.h +17 -6
index 27ddc47..8214ba9 100644
@@ -165,12 +165,14 @@
 #define USB_TEST_MODE_FORCE_ENABLE  0x05
 
 
-/* "pipe" definitions */
-
-#define PIPE_ISOCHRONOUS    0
-#define PIPE_INTERRUPT      1
-#define PIPE_CONTROL        2
-#define PIPE_BULK           3
+/*
+ * "pipe" definitions, use unsigned so we can compare reliably, since this
+ * value is shifted up to bits 30/31.
+ */
+#define PIPE_ISOCHRONOUS    0U
+#define PIPE_INTERRUPT      1U
+#define PIPE_CONTROL        2U
+#define PIPE_BULK           3U
 #define PIPE_DEVEP_MASK     0x0007ff00
 
 #define USB_ISOCHRONOUS    0
@@ -178,6 +180,15 @@
 #define USB_CONTROL        2
 #define USB_BULK           3
 
+#define USB_PIPE_TYPE_SHIFT	30
+#define USB_PIPE_TYPE_MASK	(3 << USB_PIPE_TYPE_SHIFT)
+
+#define USB_PIPE_DEV_SHIFT	8
+#define USB_PIPE_DEV_MASK	(0x7f << USB_PIPE_DEV_SHIFT)
+
+#define USB_PIPE_EP_SHIFT	15
+#define USB_PIPE_EP_MASK	(0xf << USB_PIPE_EP_SHIFT)
+
 /* USB-status codes: */
 #define USB_ST_ACTIVE           0x1		/* TD is active */
 #define USB_ST_STALLED          0x2		/* TD is stalled */
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#149 lore raw

PATCH v2 73/80 dm: usb: Tidy up pipe value decoding

Quoted 10 lines · Simon Glass

Add a few more shifts/masks to make it easier to decode a pipe value (rather than just building it). We need this for USB device emulation.

---

Changes in v2: None

 include/usb_defs.h | 23 +++++++++++++++++------
 1 file changed, 17 insertions(+), 6 deletions(-)

Applied to u-boot-dm/next.

#150 lore raw

PATCH v2 74/80 dm: usb: sandbox: Enable USB

In reply to Simon Glass

Enable USB emulation and associated features so that USB can be used in sandbox.

---

Changes in v2: None

 configs/sandbox_defconfig | 4 ++++
 include/configs/sandbox.h | 2 ++
 2 files changed, 6 insertions(+)
configs/sandbox_defconfig +4 -0
index e23b959..3f4812c 100644
@@ -15,3 +15,7 @@ CONFIG_CMD_CROS_EC=y
 CONFIG_PCI=y
 CONFIG_DM_PCI=y
 CONFIG_PCI_SANDBOX=y
+CONFIG_USB=y
+CONFIG_DM_USB=y
+CONFIG_USB_EMUL=y
+CONFIG_USB_STORAGE=y
include/configs/sandbox.h +2 -0
index 558ea2c..95cfce6 100644
@@ -60,6 +60,7 @@
 #define CONFIG_CMD_GPT
 #define CONFIG_PARTITION_UUIDS
 #define CONFIG_EFI_PARTITION
+#define CONFIG_DOS_PARTITION
 
 /*
  * Size of malloc() pool, before and after relocation
@@ -200,5 +201,6 @@
 #define CONFIG_TPM_TIS_SANDBOX
 
 #define CONFIG_CMD_LZMADEC
+#define CONFIG_CMD_USB
 
 #endif
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#151 lore raw

PATCH v2 74/80 dm: usb: sandbox: Enable USB

Quoted 11 lines · Simon Glass

Enable USB emulation and associated features so that USB can be used in sandbox.

---

Changes in v2: None

 configs/sandbox_defconfig | 4 ++++
 include/configs/sandbox.h | 2 ++
 2 files changed, 6 insertions(+)

Applied to u-boot-dm/next.

#152 lore raw

PATCH v2 75/80 dm: test: Correct printf() output nit in 'dm uclass'

In reply to Simon Glass

Neither the hyphen nor the equals sign is needed.

---

Changes in v2: None

 test/dm/cmd_dm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
test/dm/cmd_dm.c +1 -1
index 8d531fd..62e065c 100644
@@ -79,7 +79,7 @@ static void dm_display_line(struct udevice *dev)
 	       dev->flags & DM_FLAG_ACTIVATED ? '*' : ' ',
 	       dev->name, (ulong)map_to_sysmem(dev));
 	if (dev->seq != -1 || dev->req_seq != -1)
-		printf(", seq-%d, (req=%d)", dev->seq, dev->req_seq);
+		printf(", seq %d, (req %d)", dev->seq, dev->req_seq);
 	puts("\n");
 }
 
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#153 lore raw

PATCH v2 75/80 dm: test: Correct printf() output nit in 'dm uclass'

Quoted 9 lines · Simon Glass

Neither the hyphen nor the equals sign is needed.

---

Changes in v2: None

 test/dm/cmd_dm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Applied to u-boot-dm/next.

#154 lore raw

PATCH v2 76/80 dm: test: Allow 'dm test' to select a particular test to run

In reply to Simon Glass

As well as running all tests, it is useful to be able to run a selected test.

---

Changes in v2: None

 include/dm/test.h   |  7 ++++---
 test/dm/cmd_dm.c    | 11 ++++++++---
 test/dm/test-main.c |  7 +++++--
 3 files changed, 17 insertions(+), 8 deletions(-)
include/dm/test.h +4 -3
index b310e5f..9c4b8d3 100644
@@ -205,12 +205,13 @@ void dm_leak_check_start(struct dm_test_state *dms);
 
 
 /**
- * dm_test_main() - Run all the tests
+ * dm_test_main() - Run all or one of the tests
  *
- * This runs all available driver model tests
+ * This runs all available driver model tests, or a selected one
  *
+ * @test_name:	Name of test to run, or NULL for all
  * @return 0 if OK, -ve on error
  */
-int dm_test_main(void);
+int dm_test_main(const char *test_name);
 
 #endif
test/dm/cmd_dm.c +8 -3
index 62e065c..2f527e9 100644
@@ -113,7 +113,12 @@ static int do_dm_dump_uclass(cmd_tbl_t *cmdtp, int flag, int argc,
 static int do_dm_test(cmd_tbl_t *cmdtp, int flag, int argc,
 			  char * const argv[])
 {
-	return dm_test_main();
+	const char *test_name = NULL;
+
+	if (argc > 0)
+		test_name = argv[0];
+
+	return dm_test_main(test_name);
 }
 #define TEST_HELP "\ndm test         Run tests"
 #else
@@ -133,7 +138,7 @@ static int do_dm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	cmd_tbl_t *test_cmd;
 	int ret;
 
-	if (argc != 2)
+	if (argc < 2)
 		return CMD_RET_USAGE;
 	test_cmd = find_cmd_tbl(argv[1], test_commands,
 				ARRAY_SIZE(test_commands));
@@ -148,7 +153,7 @@ static int do_dm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 }
 
 U_BOOT_CMD(
-	dm,	2,	1,	do_dm,
+	dm,	3,	1,	do_dm,
 	"Driver model low level access",
 	"tree         Dump driver model tree ('*' = activated)\n"
 	"dm uclass        Dump list of instances for each uclass"
test/dm/test-main.c +5 -2
index 90ca810..a47bb37 100644
@@ -65,7 +65,7 @@ static int dm_test_destroy(struct dm_test_state *dms)
 	return 0;
 }
 
-int dm_test_main(void)
+int dm_test_main(const char *test_name)
 {
 	struct dm_test *tests = ll_entry_start(struct dm_test, dm_test);
 	const int n_ents = ll_entry_count(struct dm_test, dm_test);
@@ -83,9 +83,12 @@ int dm_test_main(void)
 		ut_assert(gd->fdt_blob);
 	}
 
-	printf("Running %d driver model tests\n", n_ents);
+	if (!test_name)
+		printf("Running %d driver model tests\n", n_ents);
 
 	for (test = tests; test < tests + n_ents; test++) {
+		if (test_name && strcmp(test_name, test->name))
+			continue;
 		printf("Test: %s\n", test->name);
 		ut_assertok(dm_test_init(dms));
 
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#155 lore raw

PATCH v2 76/80 dm: test: Allow 'dm test' to select a particular test to run

Quoted 11 lines · Simon Glass

As well as running all tests, it is useful to be able to run a selected test.

---

Changes in v2: None

 include/dm/test.h   |  7 ++++---
 test/dm/cmd_dm.c    | 11 ++++++++---
 test/dm/test-main.c |  7 +++++--
 3 files changed, 17 insertions(+), 8 deletions(-)

Applied to u-boot-dm/next.

#156 lore raw

PATCH v2 77/80 dm: usb: Add tests for the USB uclass

In reply to Simon Glass

This adds a simple test for probing and a functional test using the flash stick emulator, which tests a large chunk of the USB stack.

---

Changes in v2: None

 test/dm/Makefile   |  1 +
 test/dm/test-dm.sh |  3 +++
 test/dm/test.dts   | 41 +++++++++++++++++++++++++++++++++++++++++
 test/dm/usb.c      | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 95 insertions(+)
 create mode 100644 test/dm/usb.c
test/dm/Makefile +1 -0
index a2e2d23..fd9e29f 100644
@@ -23,4 +23,5 @@ obj-$(CONFIG_DM_I2C) += i2c.o
 obj-$(CONFIG_DM_PCI) += pci.o
 obj-$(CONFIG_DM_SPI_FLASH) += sf.o
 obj-$(CONFIG_DM_SPI) += spi.o
+obj-$(CONFIG_DM_USB) += usb.o
 endif
test/dm/test-dm.sh +3 -0
index 8ebc392..6158f68 100755
@@ -10,5 +10,8 @@ dtc -I dts -O dtb test/dm/test.dts -o test/dm/test.dtb
 make O=sandbox sandbox_config || die "Cannot configure U-Boot"
 make O=sandbox -s -j${NUM_CPUS} || die "Cannot build U-Boot"
 dd if=/dev/zero of=spi.bin bs=1M count=2
+echo -n "this is a test" > testflash.bin
+dd if=/dev/zero bs=1M count=4 >>testflash.bin
 ./sandbox/u-boot -d test/dm/test.dtb -c "dm test"
 rm spi.bin
+rm testflash.bin
test/dm/test.dts +41 -0

51 lines not on this page · raw message

test/dm/usb.c new file +50 -0

50 lines not on this page · raw message

Signature · 1 line
2.2.0.rc0.207.ga3a616c
#157 lore raw

PATCH v2 77/80 dm: usb: Add tests for the USB uclass

Quoted 6 lines · Simon Glass

This adds a simple test for probing and a functional test using the flash stick emulator, which tests a large chunk of the USB stack.

---

Quoted 8 lines

Changes in v2: None

 test/dm/Makefile   |  1 +
 test/dm/test-dm.sh |  3 +++
 test/dm/test.dts   | 41 +++++++++++++++++++++++++++++++++++++++++
 test/dm/usb.c      | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 95 insertions(+)
 create mode 100644 test/dm/usb.c

Applied to u-boot-dm/next.

#158 lore raw

PATCH v2 77/80 dm: usb: Add tests for the USB uclass

In reply to Simon Glass

Hi Simon,

Quoted 4 lines · Simon Glass

This adds a simple test for probing and a functional test using the flash stick emulator, which tests a large chunk of the USB stack.

I'm seeing a seg fault when running the dm tests and bisected it to this patch.

I'm not sure why it's related, but it appears to seg fault on a GPIO test...

U-Boot 2015.04-00280-ge00cb22-dirty (Apr 21 2015 - 00:02:01)

DRAM: 128 MiB
Using default environment

In:    serial
Out:   lcd
Err:   lcd
Net:   eth0: eth at 10002000, eth5: eth at 10003000, eth1: eth at 10004000

Running 53 driver model tests
Test: dm_test_autobind
Test: dm_test_autoprobe
Test: dm_test_bus_child_post_bind
Test: dm_test_bus_child_post_bind_uclass
Test: dm_test_bus_child_pre_probe_uclass
Test: dm_test_bus_children
Device 'c-test at 0': seq 0 is in use by 'd-test'
Device 'c-test at 1': seq 1 is in use by 'f-test'
Test: dm_test_bus_children_funcs
Test: dm_test_bus_children_iterators
Test: dm_test_bus_parent_data
Test: dm_test_bus_parent_data_uclass
Test: dm_test_bus_parent_ops
Test: dm_test_bus_parent_platdata
Test: dm_test_bus_parent_platdata_uclass
Test: dm_test_children
Test: dm_test_device_get_uclass_id
Test: dm_test_eth
Using eth at 10002000 device
Using eth at 10003000 device
Using eth at 10004000 device
Test: dm_test_eth_alias
Using eth at 10002000 device
Using eth at 10004000 device
Using eth at 10002000 device
Using eth at 10003000 device
Test: dm_test_eth_prime
Using eth at 10003000 device
Using eth at 10002000 device
Test: dm_test_eth_rotate

Error: eth at 10004000 address not set.

Error: eth at 10004000 address not set.
Using eth at 10002000 device

Error: eth at 10004000 address not set.

Error: eth at 10004000 address not set. Using eth at 10004000 device
Test: dm_test_fdt
Test: dm_test_fdt_offset
Test: dm_test_fdt_pre_reloc
Test: dm_test_fdt_uclass_seq
Test: dm_test_gpio
extra-gpios: get_value: error: gpio b5 not reserved
Test: dm_test_gpio_anon
Test: dm_test_gpio_copy
Test: dm_test_gpio_leak
extra-gpios: get_value: error: gpio b5 not reserved

Program received signal SIGSEGV, Segmentation fault.
0x000009ec in ?? ()
(gdb) bt
#0 0x000009ec in ?? ()
#1 0x0806a0aa in uclass_destroy (uc=0xb5abd228) at /home/joe/u-boot/drivers/core/uclass.c:109
#2 0x080a29e1 in dm_leak_check_end (dms=0x8106870) at /home/joe/u-boot/test/dm/core.c:89
#3 0x080a46a6 in dm_test_gpio_leak (dms=0x8106870) at /home/joe/u-boot/test/dm/gpio.c:173
#4 0x080a0ed2 in dm_test_main (test_name=0x0) at /home/joe/u-boot/test/dm/test-main.c:103
#5 0x0809e9fb in do_dm (cmdtp=0x80c0250, flag=0, argc=135022648, argv=0xb5abbd40) at /home/joe/u-boot/test/dm/cmd_dm.c:150
#6 0x08065d6b in cmd_process (flag=0, argc=2, argv=0xb5abbd40, repeatable=0x80c5fc4, ticks=0x0) at /home/joe/u-boot/common/command.c:493
#7 0x0804d6fb in run_list_real (pi=0xb5abbc88) at /home/joe/u-boot/common/cli_hush.c:1656
#8 0x0804dce4 in parse_stream_outer (inp=0xbffff0e8, flag=2) at /home/joe/u-boot/common/cli_hush.c:2003
#9 0x0804df1d in parse_string_outer (s=0xbffff513 "dm test", flag=2) at /home/joe/u-boot/common/cli_hush.c:3248
#10 0x0804a855 in sandbox_main_loop_init () at /home/joe/u-boot/arch/sandbox/cpu/start.c:85
#11 0x0804e65b in run_main_loop () at /home/joe/u-boot/common/board_r.c:682 #12 0x0808f082 in initcall_run_list (init_sequence=0x80c1f68) at /home/joe/u-boot/lib/initcall.c:27
#13 0x0804e798 in board_init_r (new_gd=0xb5ab9f14, dest_addr=0) at /home/joe/u-boot/common/board_r.c:916
#14 0x0804a810 in main (argc=Cannot access memory at address 0x0 ) at /home/joe/u-boot/arch/sandbox/cpu/start.c:276
(gdb) f 1
#1 0x0806a0aa in uclass_destroy (uc=0xb5abd228) at /home/joe/u-boot/drivers/core/uclass.c:109
109 ret = device_unbind(dev);
(gdb) l -
99 int uclass_destroy(struct uclass *uc)
100 {

101             struct uclass_driver *uc_drv;
102             struct udevice *dev, *tmp;
103             int ret;

104
105 list_for_each_entry_safe(dev, tmp, &uc->dev_head, uclass_node) {
106 ret = device_remove(dev);
107 if (ret)
108 return ret;
(gdb) l
109 ret = device_unbind(dev);
110 if (ret)
111 return ret;
112 }
113
114 uc_drv = uc->uc_drv;
115 if (uc_drv->destroy)
116 uc_drv->destroy(uc);
117 list_del(&uc->sibling_node);
118 if (uc_drv->priv_auto_alloc_size)
(gdb)

Thoughts?
-Joe

#159 lore raw

PATCH v2 77/80 dm: usb: Add tests for the USB uclass

Hi Joe,

Quoted 135 lines · Joe Hershberger

Hi Simon,

Quoted 4 lines · Simon Glass

This adds a simple test for probing and a functional test using the flash stick emulator, which tests a large chunk of the USB stack.

I'm seeing a seg fault when running the dm tests and bisected it to this patch.

I'm not sure why it's related, but it appears to seg fault on a GPIO test...

U-Boot 2015.04-00280-ge00cb22-dirty (Apr 21 2015 - 00:02:01)

DRAM: 128 MiB
Using default environment

In:    serial
Out:   lcd
Err:   lcd
Net:   eth0: eth at 10002000, eth5: eth at 10003000, eth1: eth at 10004000

Running 53 driver model tests
Test: dm_test_autobind
Test: dm_test_autoprobe
Test: dm_test_bus_child_post_bind
Test: dm_test_bus_child_post_bind_uclass
Test: dm_test_bus_child_pre_probe_uclass
Test: dm_test_bus_children
Device 'c-test at 0': seq 0 is in use by 'd-test'
Device 'c-test at 1': seq 1 is in use by 'f-test'
Test: dm_test_bus_children_funcs
Test: dm_test_bus_children_iterators
Test: dm_test_bus_parent_data
Test: dm_test_bus_parent_data_uclass
Test: dm_test_bus_parent_ops
Test: dm_test_bus_parent_platdata
Test: dm_test_bus_parent_platdata_uclass
Test: dm_test_children
Test: dm_test_device_get_uclass_id
Test: dm_test_eth
Using eth at 10002000 device
Using eth at 10003000 device
Using eth at 10004000 device
Test: dm_test_eth_alias
Using eth at 10002000 device
Using eth at 10004000 device
Using eth at 10002000 device
Using eth at 10003000 device
Test: dm_test_eth_prime
Using eth at 10003000 device
Using eth at 10002000 device
Test: dm_test_eth_rotate

Error: eth at 10004000 address not set.

Error: eth at 10004000 address not set.
Using eth at 10002000 device

Error: eth at 10004000 address not set.

Error: eth at 10004000 address not set. Using eth at 10004000 device
Test: dm_test_fdt
Test: dm_test_fdt_offset
Test: dm_test_fdt_pre_reloc
Test: dm_test_fdt_uclass_seq
Test: dm_test_gpio
extra-gpios: get_value: error: gpio b5 not reserved
Test: dm_test_gpio_anon
Test: dm_test_gpio_copy
Test: dm_test_gpio_leak
extra-gpios: get_value: error: gpio b5 not reserved

Program received signal SIGSEGV, Segmentation fault.
0x000009ec in ?? ()
(gdb) bt
#0 0x000009ec in ?? ()
#1 0x0806a0aa in uclass_destroy (uc=0xb5abd228) at /home/joe/u-boot/drivers/core/uclass.c:109
#2 0x080a29e1 in dm_leak_check_end (dms=0x8106870) at /home/joe/u-boot/test/dm/core.c:89
#3 0x080a46a6 in dm_test_gpio_leak (dms=0x8106870) at /home/joe/u-boot/test/dm/gpio.c:173
#4 0x080a0ed2 in dm_test_main (test_name=0x0) at /home/joe/u-boot/test/dm/test-main.c:103
#5 0x0809e9fb in do_dm (cmdtp=0x80c0250, flag=0, argc=135022648, argv=0xb5abbd40) at /home/joe/u-boot/test/dm/cmd_dm.c:150
#6 0x08065d6b in cmd_process (flag=0, argc=2, argv=0xb5abbd40, repeatable=0x80c5fc4, ticks=0x0) at /home/joe/u-boot/common/command.c:493
#7 0x0804d6fb in run_list_real (pi=0xb5abbc88) at /home/joe/u-boot/common/cli_hush.c:1656
#8 0x0804dce4 in parse_stream_outer (inp=0xbffff0e8, flag=2) at /home/joe/u-boot/common/cli_hush.c:2003
#9 0x0804df1d in parse_string_outer (s=0xbffff513 "dm test", flag=2) at /home/joe/u-boot/common/cli_hush.c:3248
#10 0x0804a855 in sandbox_main_loop_init () at /home/joe/u-boot/arch/sandbox/cpu/start.c:85
#11 0x0804e65b in run_main_loop () at /home/joe/u-boot/common/board_r.c:682 #12 0x0808f082 in initcall_run_list (init_sequence=0x80c1f68) at /home/joe/u-boot/lib/initcall.c:27
#13 0x0804e798 in board_init_r (new_gd=0xb5ab9f14, dest_addr=0) at /home/joe/u-boot/common/board_r.c:916
#14 0x0804a810 in main (argc=Cannot access memory at address 0x0 ) at /home/joe/u-boot/arch/sandbox/cpu/start.c:276
(gdb) f 1
#1 0x0806a0aa in uclass_destroy (uc=0xb5abd228) at /home/joe/u-boot/drivers/core/uclass.c:109
109 ret = device_unbind(dev);
(gdb) l -
99 int uclass_destroy(struct uclass *uc)
100 {

101             struct uclass_driver *uc_drv;
102             struct udevice *dev, *tmp;
103             int ret;

104
105 list_for_each_entry_safe(dev, tmp, &uc->dev_head, uclass_node) {
106 ret = device_remove(dev);
107 if (ret)
108 return ret;
(gdb) l
109 ret = device_unbind(dev);
110 if (ret)
111 return ret;
112 }
113
114 uc_drv = uc->uc_drv;
115 if (uc_drv->destroy)
116 uc_drv->destroy(uc);
117 list_del(&uc->sibling_node);
118 if (uc_drv->priv_auto_alloc_size)
(gdb)

Quoted 1 line

Thoughts?

Yes it is broken. I sent a series to fix this recent ('dm: core: Fix up test failures') starting with this patch:

http://patchwork.ozlabs.org/patch/462556/

If you are able to test it that would be good.

Regards,
Simon

#160 lore raw

PATCH v2 77/80 dm: usb: Add tests for the USB uclass

Hi Simon,

Quoted 14 lines · Simon Glass

Hi Joe,

Quoted 11 lines · Joe Hershberger

Hi Simon,

Quoted 4 lines · Simon Glass

This adds a simple test for probing and a functional test using the flash stick emulator, which tests a large chunk of the USB stack.

I'm seeing a seg fault when running the dm tests and bisected it to this patch.

I'm not sure why it's related, but it appears to seg fault on a GPIO test...

<--snip-->

Quoted 8 lines
Quoted 1 line

Thoughts?

Yes it is broken. I sent a series to fix this recent ('dm: core: Fix up test failures') starting with this patch:

http://patchwork.ozlabs.org/patch/462556/

If you are able to test it that would be good.

I tested the series, but I still have a USB test failure...

"""
Test: dm_test_usb_flash
USB-1: scanning bus 1 for devices... 2 USB Device(s) found
/home/joe/u-boot/test/dm/usb.c:45, dm_test_usb_flash(): 2 == dev_desc->block_read(dev_desc->dev, 0, 2, cmp): Expected 2, got 0 """

Have you seen that one?

Thanks,
-Joe

#161 lore raw

PATCH v2 77/80 dm: usb: Add tests for the USB uclass

Hi Joe,

Quoted 32 lines · Joe Hershberger

Hi Simon,

Quoted 14 lines · Simon Glass

Hi Joe,

Quoted 11 lines · Joe Hershberger

Hi Simon,

Quoted 4 lines · Simon Glass

This adds a simple test for probing and a functional test using the flash stick emulator, which tests a large chunk of the USB stack.

I'm seeing a seg fault when running the dm tests and bisected it to this patch.

I'm not sure why it's related, but it appears to seg fault on a GPIO test...

<--snip-->

Quoted 8 lines
Quoted 1 line

Thoughts?

Yes it is broken. I sent a series to fix this recent ('dm: core: Fix up test failures') starting with this patch:

http://patchwork.ozlabs.org/patch/462556/

If you are able to test it that would be good.

I tested the series, but I still have a USB test failure...

Quoted 8 lines

"""
Test: dm_test_usb_flash
USB-1: scanning bus 1 for devices... 2 USB Device(s) found
/home/joe/u-boot/test/dm/usb.c:45, dm_test_usb_flash(): 2 == dev_desc->block_read(dev_desc->dev, 0, 2, cmp): Expected 2, got 0 """

Have you seen that one?

No I don't see that. It is saying that it was not able to read 2 512-byte blocks from the testflash.bin file. It should be created by the test script. I just tried it again.

BTW I'd like to get a sandbox network device that works in a purely emulated way (i.e. without any reference to real hardware). Then we could use it for ping tests, etc. and they would run instantly. At present the network tests are quite slow. What do you think?

Regards,
Simon

#162 lore raw

PATCH v2 77/80 dm: usb: Add tests for the USB uclass

Hi Simon,

Quoted 42 lines · Simon Glass

Hi Joe,

Quoted 39 lines · Joe Hershberger

Hi Simon,

Quoted 14 lines · Simon Glass

Hi Joe,

Quoted 11 lines · Joe Hershberger

Hi Simon,

Quoted 4 lines · Simon Glass

This adds a simple test for probing and a functional test using the flash stick emulator, which tests a large chunk of the USB stack.

I'm seeing a seg fault when running the dm tests and bisected it to this patch.

I'm not sure why it's related, but it appears to seg fault on a GPIO test...

<--snip-->

Quoted 8 lines
Quoted 1 line

Thoughts?

Yes it is broken. I sent a series to fix this recent ('dm: core: Fix up test failures') starting with this patch:

http://patchwork.ozlabs.org/patch/462556/

If you are able to test it that would be good.

I tested the series, but I still have a USB test failure...

"""
Test: dm_test_usb_flash
USB-1: scanning bus 1 for devices... 2 USB Device(s) found
/home/joe/u-boot/test/dm/usb.c:45, dm_test_usb_flash(): 2 == dev_desc->block_read(dev_desc->dev, 0, 2, cmp): Expected 2, got 0 """

Quoted 5 lines
Quoted 1 line

Have you seen that one?

No I don't see that. It is saying that it was not able to read 2 512-byte blocks from the testflash.bin file. It should be created by the test script. I just tried it again.

That makes sense... I wasn't creating that file. D'oh! Working for me now too.

Quoted 4 lines

BTW I'd like to get a sandbox network device that works in a purely emulated way (i.e. without any reference to real hardware). Then we could use it for ping tests, etc. and they would run instantly. At present the network tests are quite slow. What do you think?

The tests are all using fully emulated Ethernet... the issue is that the ping test ensures that on timeout an error is returned. Even though it is an emulated MAC, the timeout in the network stack is still there.

I'll work on a patch that adds a way to change the ping timeout to make this faster.

Cheers,
-Joe

#163 lore raw

PATCH v2 77/80 dm: usb: Add tests for the USB uclass

Hi Joe,

Quoted 58 lines · Joe Hershberger

Hi Simon,

Quoted 42 lines · Simon Glass

Hi Joe,

Quoted 39 lines · Joe Hershberger

Hi Simon,

Quoted 14 lines · Simon Glass

Hi Joe,

Quoted 11 lines · Joe Hershberger

Hi Simon,

Quoted 4 lines · Simon Glass

This adds a simple test for probing and a functional test using the flash stick emulator, which tests a large chunk of the USB stack.

I'm seeing a seg fault when running the dm tests and bisected it to this patch.

I'm not sure why it's related, but it appears to seg fault on a GPIO test...

<--snip-->

Quoted 8 lines
Quoted 1 line

Thoughts?

Yes it is broken. I sent a series to fix this recent ('dm: core: Fix up test failures') starting with this patch:

http://patchwork.ozlabs.org/patch/462556/

If you are able to test it that would be good.

I tested the series, but I still have a USB test failure...

"""
Test: dm_test_usb_flash
USB-1: scanning bus 1 for devices... 2 USB Device(s) found
/home/joe/u-boot/test/dm/usb.c:45, dm_test_usb_flash(): 2 == dev_desc->block_read(dev_desc->dev, 0, 2, cmp): Expected 2, got 0 """

Quoted 5 lines
Quoted 1 line

Have you seen that one?

No I don't see that. It is saying that it was not able to read 2 512-byte blocks from the testflash.bin file. It should be created by the test script. I just tried it again.

That makes sense... I wasn't creating that file. D'oh! Working for me now too.

Quoted 4 lines

BTW I'd like to get a sandbox network device that works in a purely emulated way (i.e. without any reference to real hardware). Then we could use it for ping tests, etc. and they would run instantly. At present the network tests are quite slow. What do you think?

Quoted 7 lines

The tests are all using fully emulated Ethernet... the issue is that the ping test ensures that on timeout an error is returned. Even though it is an emulated MAC, the timeout in the network stack is still there.

I'll work on a patch that adds a way to change the ping timeout to make this faster.

OK thanks for explaining this. Rather than changing the ping timeout, can you look at changing the time? With sandbox it should be possible to adjust the time so that timeouts appear to happen instantly. The arch/sandbox/include/test.h file has some test functions used by various parts of the stack.

Regards,
Simon

#164 lore raw

PATCH v2 77/80 dm: usb: Add tests for the USB uclass

Hi Simon,

Quoted 66 lines · Simon Glass

Hi Joe,

Quoted 63 lines · Joe Hershberger

Hi Simon,

Quoted 42 lines · Simon Glass

Hi Joe,

Quoted 39 lines · Joe Hershberger

Hi Simon,

Quoted 14 lines · Simon Glass

Hi Joe,

Quoted 11 lines · Joe Hershberger

Hi Simon,

Quoted 4 lines · Simon Glass

This adds a simple test for probing and a functional test using the flash stick emulator, which tests a large chunk of the USB stack.

I'm seeing a seg fault when running the dm tests and bisected it to this patch.

I'm not sure why it's related, but it appears to seg fault on a GPIO test...

<--snip-->

Quoted 8 lines
Quoted 1 line

Thoughts?

Yes it is broken. I sent a series to fix this recent ('dm: core: Fix up test failures') starting with this patch:

http://patchwork.ozlabs.org/patch/462556/

If you are able to test it that would be good.

I tested the series, but I still have a USB test failure...

"""
Test: dm_test_usb_flash
USB-1: scanning bus 1 for devices... 2 USB Device(s) found
/home/joe/u-boot/test/dm/usb.c:45, dm_test_usb_flash(): 2 == dev_desc->block_read(dev_desc->dev, 0, 2, cmp): Expected 2, got 0 """

Quoted 5 lines
Quoted 1 line

Have you seen that one?

No I don't see that. It is saying that it was not able to read 2 512-byte blocks from the testflash.bin file. It should be created by the test script. I just tried it again.

That makes sense... I wasn't creating that file. D'oh! Working for me now too.

Quoted 4 lines

BTW I'd like to get a sandbox network device that works in a purely emulated way (i.e. without any reference to real hardware). Then we could use it for ping tests, etc. and they would run instantly. At present the network tests are quite slow. What do you think?

The tests are all using fully emulated Ethernet... the issue is that the ping test ensures that on timeout an error is returned. Even though it is an emulated MAC, the timeout in the network stack is still there.

Quoted 8 lines
Quoted 2 lines

I'll work on a patch that adds a way to change the ping timeout to make this faster.

OK thanks for explaining this. Rather than changing the ping timeout, can you look at changing the time? With sandbox it should be possible to adjust the time so that timeouts appear to happen instantly. The arch/sandbox/include/test.h file has some test functions used by various parts of the stack.

I posted a series that handles the issue as you recommended and called it "test: Speed up test timeouts by advancing time".

I now notice that the only test that takes any time is the USB Flash test.

"""
Test: dm_test_usb_flash
USB-1: scanning bus 1 for devices... 2 USB Device(s) found
"""

It takes about 3 seconds. Is that a timeout too?

Thanks,
-Joe

#165 lore raw

PATCH v2 77/80 dm: usb: Add tests for the USB uclass

Hi Joe,

Quoted 72 lines · Joe Hershberger

Hi Simon,

Quoted 69 lines · Simon Glass

Hi Joe,

Quoted 65 lines · Joe Hershberger

Hi Simon,

Quoted 42 lines · Simon Glass

Hi Joe,

Quoted 39 lines · Joe Hershberger

Hi Simon,

Quoted 14 lines · Simon Glass

Hi Joe,

Quoted 11 lines · Joe Hershberger

Hi Simon,

Quoted 4 lines · Simon Glass

This adds a simple test for probing and a functional test using the flash stick emulator, which tests a large chunk of the USB stack.

I'm seeing a seg fault when running the dm tests and bisected it to this patch.

I'm not sure why it's related, but it appears to seg fault on a GPIO test...

<--snip-->

Quoted 8 lines
Quoted 1 line

Thoughts?

Yes it is broken. I sent a series to fix this recent ('dm: core: Fix up test failures') starting with this patch:

http://patchwork.ozlabs.org/patch/462556/

If you are able to test it that would be good.

I tested the series, but I still have a USB test failure...

"""
Test: dm_test_usb_flash
USB-1: scanning bus 1 for devices... 2 USB Device(s) found
/home/joe/u-boot/test/dm/usb.c:45, dm_test_usb_flash(): 2 == dev_desc->block_read(dev_desc->dev, 0, 2, cmp): Expected 2, got 0 """

Quoted 5 lines
Quoted 1 line

Have you seen that one?

No I don't see that. It is saying that it was not able to read 2 512-byte blocks from the testflash.bin file. It should be created by the test script. I just tried it again.

That makes sense... I wasn't creating that file. D'oh! Working for me now too.

Quoted 4 lines

BTW I'd like to get a sandbox network device that works in a purely emulated way (i.e. without any reference to real hardware). Then we could use it for ping tests, etc. and they would run instantly. At present the network tests are quite slow. What do you think?

The tests are all using fully emulated Ethernet... the issue is that the ping test ensures that on timeout an error is returned. Even though it is an emulated MAC, the timeout in the network stack is still there.

I'll work on a patch that adds a way to change the ping timeout to make this faster.

Quoted 8 lines
Quoted 5 lines

OK thanks for explaining this. Rather than changing the ping timeout, can you look at changing the time? With sandbox it should be possible to adjust the time so that timeouts appear to happen instantly. The arch/sandbox/include/test.h file has some test functions used by various parts of the stack.

I posted a series that handles the issue as you recommended and called it "test: Speed up test timeouts by advancing time".

I see it. This is great, thank you!

Quoted 9 lines

I now notice that the only test that takes any time is the USB Flash test.

"""
Test: dm_test_usb_flash
USB-1: scanning bus 1 for devices... 2 USB Device(s) found
"""

It takes about 3 seconds. Is that a timeout too?

Yes. I'll take a look at how you have advanced time - we should do this for USB too.

Regards,
Simon

#166 lore raw

PATCH v2 78/80 dm: usb: tegra: Drop legacy USB code

In reply to Simon Glass

Drop the code that doesn't use driver model for USB.

---

Changes in v2: None

 board/nvidia/common/board.c   |   3 -
 drivers/usb/host/ehci-tegra.c | 150 ------------------------------------------
 include/fdtdec.h              |   3 -
 lib/fdtdec.c                  |   3 -
 4 files changed, 159 deletions(-)
board/nvidia/common/board.c +0 -3
index a97035c..91bc03b 100644
@@ -128,9 +128,6 @@ int board_init(void)
 
 #ifdef CONFIG_USB_EHCI_TEGRA
 	pin_mux_usb();
-#ifndef CONFIG_DM_USB
-	usb_process_devicetree(gd->fdt_blob);
-#endif
 #endif
 
 #ifdef CONFIG_LCD
drivers/usb/host/ehci-tegra.c +0 -150

203 lines not on this page · raw message

include/fdtdec.h +0 -3
index 063a980..c24fed2 100644
@@ -112,9 +112,6 @@ static inline fdt_size_t fdt_resource_size(const struct fdt_resource *res)
  */
 enum fdt_compat_id {
 	COMPAT_UNKNOWN,
-	COMPAT_NVIDIA_TEGRA20_USB,	/* Tegra20 USB port */
-	COMPAT_NVIDIA_TEGRA30_USB,	/* Tegra30 USB port */
-	COMPAT_NVIDIA_TEGRA114_USB,	/* Tegra114 USB port */
 	COMPAT_NVIDIA_TEGRA20_EMC,	/* Tegra20 memory controller */
 	COMPAT_NVIDIA_TEGRA20_EMC_TABLE, /* Tegra20 memory timing table */
 	COMPAT_NVIDIA_TEGRA20_KBC,	/* Tegra20 Keyboard */
lib/fdtdec.c +0 -3
index 9fcc1bb..d3e725b 100644
@@ -21,9 +21,6 @@ DECLARE_GLOBAL_DATA_PTR;
 #define COMPAT(id, name) name
 static const char * const compat_names[COMPAT_COUNT] = {
 	COMPAT(UNKNOWN, "<none>"),
-	COMPAT(NVIDIA_TEGRA20_USB, "nvidia,tegra20-ehci"),
-	COMPAT(NVIDIA_TEGRA30_USB, "nvidia,tegra30-ehci"),
-	COMPAT(NVIDIA_TEGRA114_USB, "nvidia,tegra114-ehci"),
 	COMPAT(NVIDIA_TEGRA20_EMC, "nvidia,tegra20-emc"),
 	COMPAT(NVIDIA_TEGRA20_EMC_TABLE, "nvidia,tegra20-emc-table"),
 	COMPAT(NVIDIA_TEGRA20_KBC, "nvidia,tegra20-kbc"),
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#167 lore raw

PATCH v2 78/80 dm: usb: tegra: Drop legacy USB code

Quoted 5 lines · Simon Glass

Drop the code that doesn't use driver model for USB.

---

Quoted 7 lines

Changes in v2: None

 board/nvidia/common/board.c   |   3 -
 drivers/usb/host/ehci-tegra.c | 150 ------------------------------------------
 include/fdtdec.h              |   3 -
 lib/fdtdec.c                  |   3 -
 4 files changed, 159 deletions(-)

Applied to u-boot-dm.

#168 lore raw

PATCH v2 79/80 dm: usb: exynos: Drop legacy USB code

In reply to Simon Glass

Drop the code that doesn't use driver model for USB.

---

Changes in v2: None

 drivers/usb/host/ehci-exynos.c  | 117 ----------------------------------------
 drivers/usb/host/xhci-exynos5.c | 108 -------------------------------------
 include/fdtdec.h                |   2 -
 lib/fdtdec.c                    |   2 -
 4 files changed, 229 deletions(-)
drivers/usb/host/ehci-exynos.c +0 -117
index 86cf631..18e9251 100644
@@ -25,14 +25,12 @@
 /* Declare global data pointer */
 DECLARE_GLOBAL_DATA_PTR;
 
-#ifdef CONFIG_DM_USB
 struct exynos_ehci_platdata {
 	struct usb_platdata usb_plat;
 	fdt_addr_t hcd_base;
 	fdt_addr_t phy_base;
 	struct gpio_desc vbus_gpio;
 };
-#endif
 
 /**
  * Contains pointers to register base addresses
@@ -42,16 +40,8 @@ struct exynos_ehci {
 	struct ehci_ctrl ctrl;
 	struct exynos_usb_phy *usb;
 	struct ehci_hccr *hcd;
-#ifndef CONFIG_DM_USB
-	struct gpio_desc vbus_gpio;
-#endif
 };
 
-#ifndef CONFIG_DM_USB
-static struct exynos_ehci exynos;
-#endif
-
-#ifdef CONFIG_DM_USB
 static int ehci_usb_ofdata_to_platdata(struct udevice *dev)
 {
 	struct exynos_ehci_platdata *plat = dev_get_platdata(dev);
@@ -91,55 +81,6 @@ static int ehci_usb_ofdata_to_platdata(struct udevice *dev)
 
 	return 0;
 }
-#else
-static int exynos_usb_parse_dt(const void *blob, struct exynos_ehci *exynos)
-{
-	fdt_addr_t addr;
-	unsigned int node;
-	int depth;
-
-	node = fdtdec_next_compatible(blob, 0, COMPAT_SAMSUNG_EXYNOS_EHCI);
-	if (node <= 0) {
-		debug("EHCI: Can't get device node for ehci\n");
-		return -ENODEV;
-	}
-
-	/*
-	 * Get the base address for EHCI controller from the device node
-	 */
-	addr = fdtdec_get_addr(blob, node, "reg");
-	if (addr == FDT_ADDR_T_NONE) {
-		debug("Can't get the EHCI register address\n");
-		return -ENXIO;
-	}
-
-	exynos->hcd = (struct ehci_hccr *)addr;
-
-	/* Vbus gpio */
-	gpio_request_by_name_nodev(blob, node, "samsung,vbus-gpio", 0,
-				   &exynos->vbus_gpio, GPIOD_IS_OUT);
-
-	depth = 0;
-	node = fdtdec_next_compatible_subnode(blob, node,
-					COMPAT_SAMSUNG_EXYNOS_USB_PHY, &depth);
-	if (node <= 0) {
-		debug("EHCI: Can't get device node for usb-phy controller\n");
-		return -ENODEV;
-	}
-
-	/*
-	 * Get the base address for usbphy from the device node
-	 */
-	exynos->usb = (struct exynos_usb_phy *)fdtdec_get_addr(blob, node,
-								"reg");
-	if (exynos->usb == NULL) {
-		debug("Can't get the usbphy register address\n");
-		return -ENXIO;
-	}
-
-	return 0;
-}
-#endif
 
 static void exynos5_setup_usb_phy(struct exynos_usb_phy *usb)
 {
@@ -270,63 +211,6 @@ static void reset_usb_phy(struct exynos_usb_phy *usb)
 	set_usbhost_phy_ctrl(POWER_USB_HOST_PHY_CTRL_DISABLE);
 }
 
-#ifndef CONFIG_DM_USB
-/*
- * EHCI-initialization
- * Create the appropriate control structures to manage
- * a new EHCI host controller.
- */
-int ehci_hcd_init(int index, enum usb_init_type init,
-		struct ehci_hccr **hccr, struct ehci_hcor **hcor)
-{
-	struct exynos_ehci *ctx = &exynos;
-
-#ifdef CONFIG_OF_CONTROL
-	if (exynos_usb_parse_dt(gd->fdt_blob, ctx)) {
-		debug("Unable to parse device tree for ehci-exynos\n");
-		return -ENODEV;
-	}
-#else
-	ctx->usb = (struct exynos_usb_phy *)samsung_get_base_usb_phy();
-	ctx->hcd = (struct ehci_hccr *)samsung_get_base_usb_ehci();
-#endif
-
-#ifdef CONFIG_OF_CONTROL
-	/* setup the Vbus gpio here */
-	if (dm_gpio_is_valid(&ctx->vbus_gpio))
-		dm_gpio_set_value(&ctx->vbus_gpio, 1);
-#endif
-
-	setup_usb_phy(ctx->usb);
-
-	board_usb_init(index, init);
-
-	*hccr = ctx->hcd;
-	*hcor = (struct ehci_hcor *)((uint32_t) *hccr
-				+ HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
-
-	debug("Exynos5-ehci: init hccr %x and hcor %x hc_length %d\n",
-		(uint32_t)*hccr, (uint32_t)*hcor,
-		(uint32_t)HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
-
-	return 0;
-}
-
-/*
- * Destroy the appropriate control structures corresponding
- * the EHCI host controller.
- */
-int ehci_hcd_stop(int index)
-{
-	struct exynos_ehci *ctx = &exynos;
-
-	reset_usb_phy(ctx->usb);
-
-	return 0;
-}
-#endif
-
-#ifdef CONFIG_DM_USB
 static int ehci_usb_probe(struct udevice *dev)
 {
 	struct exynos_ehci_platdata *plat = dev_get_platdata(dev);
@@ -377,4 +261,3 @@ U_BOOT_DRIVER(usb_ehci) = {
 	.platdata_auto_alloc_size = sizeof(struct exynos_ehci_platdata),
 	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
 };
-#endif
drivers/usb/host/xhci-exynos5.c +0 -108

147 lines not on this page · raw message

include/fdtdec.h +0 -2
index c24fed2..b9d63ad 100644
@@ -133,8 +133,6 @@ enum fdt_compat_id {
 	COMPAT_WOLFSON_WM8994_CODEC,	/* Wolfson WM8994 Sound Codec */
 	COMPAT_GOOGLE_CROS_EC,		/* Google CROS_EC Protocol */
 	COMPAT_GOOGLE_CROS_EC_KEYB,	/* Google CROS_EC Keyboard */
-	COMPAT_SAMSUNG_EXYNOS_EHCI,	/* Exynos EHCI controller */
-	COMPAT_SAMSUNG_EXYNOS5_XHCI,	/* Exynos5 XHCI controller */
 	COMPAT_SAMSUNG_EXYNOS_USB_PHY,	/* Exynos phy controller for usb2.0 */
 	COMPAT_SAMSUNG_EXYNOS5_USB3_PHY,/* Exynos phy controller for usb3.0 */
 	COMPAT_SAMSUNG_EXYNOS_TMU,	/* Exynos TMU */
lib/fdtdec.c +0 -2
index d3e725b..94460d0 100644
@@ -41,8 +41,6 @@ static const char * const compat_names[COMPAT_COUNT] = {
 	COMPAT(WOLFSON_WM8994_CODEC, "wolfson,wm8994-codec"),
 	COMPAT(GOOGLE_CROS_EC, "google,cros-ec"),
 	COMPAT(GOOGLE_CROS_EC_KEYB, "google,cros-ec-keyb"),
-	COMPAT(SAMSUNG_EXYNOS_EHCI, "samsung,exynos-ehci"),
-	COMPAT(SAMSUNG_EXYNOS5_XHCI, "samsung,exynos5250-xhci"),
 	COMPAT(SAMSUNG_EXYNOS_USB_PHY, "samsung,exynos-usb-phy"),
 	COMPAT(SAMSUNG_EXYNOS5_USB3_PHY, "samsung,exynos5250-usb3-phy"),
 	COMPAT(SAMSUNG_EXYNOS_TMU, "samsung,exynos-tmu"),
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#169 lore raw

PATCH v2 79/80 dm: usb: exynos: Drop legacy USB code

Quoted 5 lines · Simon Glass

Drop the code that doesn't use driver model for USB.

---

Quoted 7 lines

Changes in v2: None

 drivers/usb/host/ehci-exynos.c  | 117 ----------------------------------------
 drivers/usb/host/xhci-exynos5.c | 108 -------------------------------------
 include/fdtdec.h                |   2 -
 lib/fdtdec.c                    |   2 -
 4 files changed, 229 deletions(-)

Applied to u-boot-dm.

#170 lore raw

PATCH v2 80/80 dm: usb: Add a README for driver model

In reply to Simon Glass

Add some documentation describing how USB is implemented with USB. This might make things easier for people to understand.

---

Changes in v2:
- Rewrite and expand series to support driver model fully

 doc/driver-model/usb-info.txt | 415 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 415 insertions(+)
 create mode 100644 doc/driver-model/usb-info.txt
doc/driver-model/usb-info.txt new file +415 -0
new file mode 100644
index 0000000..3762b6c
@@ -0,0 +1,415 @@
+How USB works with driver model
+===============================
+
+Introduction
+------------
+
+Driver model USB support makes use of existing features but changes how
+drivers are found. This document provides some information intended to help
+understand how things work with USB in U-Boot when driver model is enabled.
+
+
+Enabling driver model for USB
+-----------------------------
+
+A new CONFIG_DM_USB option is provided to enable driver model for USB. This
+causes the USB uclass to be included, and drops the equivalent code in
+usb.c. In particular the usb_init() function is then implemented by the
+uclass.
+
+
+Support for ECHI and XCHI
+-------------------------
+
+So far OHCI is not supported. Both EHCI and XHCI drivers should be declared
+as drivers in the USB uclass. For example:
+
+static const struct udevice_id ehci_usb_ids[] = {
+	{ .compatible = "nvidia,tegra20-ehci", .data = USB_CTLR_T20 },
+	{ .compatible = "nvidia,tegra30-ehci", .data = USB_CTLR_T30 },
+	{ .compatible = "nvidia,tegra114-ehci", .data = USB_CTLR_T114 },
+	{ }
+};
+
+U_BOOT_DRIVER(usb_ehci) = {
+	.name	= "ehci_tegra",
+	.id	= UCLASS_USB,
+	.of_match = ehci_usb_ids,
+	.ofdata_to_platdata = ehci_usb_ofdata_to_platdata,
+	.probe = tegra_ehci_usb_probe,
+	.remove = tegra_ehci_usb_remove,
+	.ops	= &ehci_usb_ops,
+	.platdata_auto_alloc_size = sizeof(struct usb_platdata),
+	.priv_auto_alloc_size = sizeof(struct fdt_usb),
+	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
+};
+
+Here ehci_usb_ids is used to list the controllers that the driver supports.
+Each has its own data value. Controllers must be in the UCLASS_USB uclass.
+
+The ofdata_to_platdata() method allows the controller driver to grab any
+necessary settings from the device tree.
+
+The ops here are ehci_usb_ops. All EHCI drivers will use these same ops in
+most cases, since they are all ECHI-compatible. For ECHI there are also some
+special operations that can be overriden when calling ehci_register().
+
+The driver can use priv_auto_alloc_size to set the size of its private data.
+This can hold run-time information needed by the driver for operation. It
+exists when the device is probed (not when it is bound) and is removed when
+the driver is removed.
+
+Note that usb_platdata is currently only used to deal with setting up a bus
+in USB device mode (OTG operation). It can be omitted if that is not
+supported.
+
+The driver's probe() method should do the basic controller init and then
+call ehci_register() to register itself as an EHCI device. It should call
+ehci_deregister() in the remove() method. Registering a new EHCI device
+does not by itself cause the bus to be scanned.
+
+The old ehci_hcd_init() function is no-longer used. Nor is it necessary to
+set up the USB controllers from board init code. When 'usb start' is used,
+each controller will be probed and its bus scanned.
+
+XHCI works in a similar way.
+
+
+Data structures
+---------------
+
+The following primary data structures are in use:
+
+- struct usb_device
+	This holds information about a device on the bus. All devices have
+	this structure, even the root hub. The controller itself does not
+	have this structure. You can access it for a device 'dev' with
+	dev_get_parentdata(dev). It matches the old structure except that the
+	parent and child information is not present (since driver model
+	handles that). Once the device is set up, you can find the device
+	descriptor and current configuration descriptor in this structure.
+
+- struct usb_platdata
+	This holds platform data for a controller. So far this is only used
+	as a work-around for controllers which can act as USB devices in OTG
+	mode, since the gadget framework does not use driver model.
+
+- struct usb_dev_platdata
+	This holds platform data for a device. You can access it for a
+	device 'dev' with dev_get_parent_platdata(dev). It holds the device
+	address and speed - anything that can be determined before the device
+	driver is actually set up. When probing the bus this structure is
+	used to provide essential information to the device driver.
+
+- struct usb_bus_priv
+	This is private information for each controller, maintained by the
+	controller uclass. It is mostly used to keep track of the next
+	device address to use.
+
+Of these, only struct usb_device was used prior to driver model.
+
+
+USB buses
+---------
+
+Given a controller, you know the bus - it is the one attached to the
+controller. Each controller handles exactly one bus. Every controller has a
+root hub attached to it. This hub, which is itself a USB device, can provide
+one or more 'ports' to which additional devices can be attached. It is
+possible to power up a hub and find out which of its ports have devices
+attached.
+
+Devices are given addresses starting at 1. The root hub is always address 1,
+and from there the devices are numbered in sequence. The USB uclass takes
+care of this numbering automatically during enumeration.
+
+USB devices are enumerated by finding a device on a particular hub, and
+setting its address to the next available address. The USB bus stretches out
+in a tree structure, potentially with multiple hubs each with several ports
+and perhaps other hubs. Some hubs will have their own power since otherwise
+the 5V 500mA power supplied by the controller will not be sufficient to run
+very many devices.
+
+Enumeration in U-Boot takes a long time since devices are probed one at a
+time, and each is given sufficient time to wake up and announce itself. The
+timeouts are set for the slowest device.
+
+Up to 127 devices can be on each bus. USB has four bus speeds: low
+(1.5Mbps), full (12Mbps), high (480Mbps) which is only available with USB2
+and newer (EHCI), and super (5Gbps) which is only available with USB3 and
+newer (XHCI). If you connect a super-speed device to a high-speed hub, you
+will only get high-speed.
+
+
+USB operations
+--------------
+
+As before driver model, messages can be sent using submit_bulk_msg() and the
+like. These are now implemented by the USB uclass and route through the
+controller drivers. Note that messages are not sent to the driver of the
+device itself - i.e. they don't pass down the stack to the controller.
+U-Boot simply finds the controller to which the device is attached, and sends
+the message there with an appropriate 'pipe' value so it can be addressed
+properly. Having said that, the USB device which should receive the message
+is passed in to the driver methods, for use by sandbox. This design decision
+is open for review and the code impact of changing it is small since the
+methods are typically implemented by the EHCI and XHCI stacks.
+
+Controller drivers (in UCLASS_USB) themselves provide methods for sending
+each message type. For XHCI an additional alloc_device() method is provided
+since XHCI needs to allocate a device context before it can even read the
+device's descriptor.
+
+These methods use a 'pipe' which is a collection of bit fields used to
+describe the type of message, direction of transfer and the intended
+recipient (device number).
+
+
+USB Devices
+-----------
+
+USB devices are found using a simple algorithm which works through the
+available hubs in a depth-first search. Devices can be in any uclass, but
+are attached to a parent hub (or controller in the case of the root hub) and
+so have parent data attached to them (this is struct usb_device).
+
+By the time the device's probe() method is called, it is enumerated and is
+ready to talk to the host.
+
+The enumeration process needs to work out which driver to attach to each USB
+device. It does this by examining the device class, interface class, vendor
+ID, product ID, etc. See struct usb_driver_entry for how drivers are matched
+with USB devices - you can use the USB_DEVICE() macro to declare a USB
+driver. For example, usb_storage.c defines a USB_DEVICE() to handle storage
+devices, and it will be used for all USB devices which match.
+
+
+
+Technical details on enumeration flow
+-------------------------------------
+
+It is useful to understand precisely how a USB bus is enumerating to avoid
+confusion when dealing with USB devices.
+
+Device initialisation happens roughly like this:
+
+- At some point the 'usb start' command is run
+- This calls usb_init() which works through each controller in turn
+- The controller is probed(). This does no enumeration.
+- Then usb_scan_bus() is called. This calls usb_scan_device() to scan the
+(only) device that is attached to the controller - a root hub
+- usb_scan_device() sets up a fake struct usb_device and calls
+usb_setup_device(), passing the port number to be scanned, in this case port
+0
+- usb_setup_device() first calls usb_prepare_device() to set the device
+address, then usb_select_config() to select the first configuration
+- at this point the device is enumerated but we do not have a real struct
+udevice for it. But we do have the descriptor in struct usb_device so we can
+use this to figure out what driver to use
+- back in usb_scan_device(), we call usb_find_child() to try to find an
+existing device which matches the one we just found on the bus. This can
+happen if the device is mentioned in the device tree, or if we previously
+scanned the bus and so the device was created before
+- if usb_find_child() does not find an existing device, we call
+usb_find_and_bind_driver() which tries to bind one
+- usb_find_and_bind_driver() searches all available USB drivers (declared
+with USB_DEVICE()). If it finds a match it binds that driver to create a new
+device.
+- If it does not, it binds a generic driver. A generic driver is good enough
+to allow access to the device (sending it packets, etc.) but all
+functionality will need to be implemented outside the driver model.
+- in any case, when usb_find_child() and/or usb_find_and_bind_driver() are
+done, we have a device with the correct uclass. At this point we want to
+probe the device
+- first we store basic information about the new device (address, port,
+speed) in its parent platform data. We cannot store it its private data
+since that will not exist until the device is probed.
+- then we call device_probe() which probes the device
+- the first probe step is actually the USB controller's (or USB hubs's)
+child_pre_probe() method. This gets called before anything else and is
+intended to set up a child device ready to be used with its parent bus. For
+USB this calls usb_child_pre_probe() which grabs the information that was
+stored in the parent platform data and stores it in the parent private data
+(which is struct usb_device, a real one this time). It then calls
+usb_select_config() again to make sure that everything about the device is
+set up
+- note that we have called usb_select_config() twice. This is inefficient
+but the alternative is to store additional information in the platform data.
+The time taken is minimal and this way is simpler
+- at this point the device is set up and ready for use so far as the USB
+subsystem is concerned
+- the device's probe() method is then called. It can send messages and do
+whatever else it wants to make the device work.
+
+Note that the first device is always a root hub, and this must be scanned to
+find any devices. The above steps will have created a hub (UCLASS_USB_HUB),
+given it address 1 and set the configuration.
+
+For hubs, the hub uclass has a post_probe() method. This means that after
+any hub is probed, the uclass gets to do some processing. In this case
+usb_hub_post_probe() is called, and the following steps take place:
+
+- usb_hub_post_probe() calls usb_hub_scan() to scan the hub, which in turn
+calls usb_hub_configure()
+- hub power is enabled
+- we loop through each port on the hub, performing the same steps for each
+- first, check if there is a device present. This happens in
+usb_hub_port_connect_change(). If so, then usb_scan_device() is called to
+scan the device, passing the appropriate port number.
+- you will recognise usb_scan_device() from the steps above. It sets up the
+device ready for use. If it is a hub, it will scan that hub before it
+continues here (recursively, depth-first)
+- once all hub ports are scanned in this way, the hub is ready for use and
+all of its downstream devices also
+- additional controllers are scanned in the same way
+
+The above method has some nice properties:
+
+- the bus enumeration happens by virtue of driver model's natural device flow
+- most logic is in the USB controller and hub uclasses; the actual device
+drivers do not need to know they are on a USB bus, at least so far as
+enumeration goes
+- hub scanning happens automatically after a hub is probed
+
+
+Hubs
+----
+
+USB hubs are scanned as in the section above. While hubs have their own
+uclass, they share some common elements with controllers:
+
+- they both attach private data to their children (struct usb_device,
+accessible for a child with dev_get_parentdata(child))
+- they both use usb_child_pre_probe() to set up their children as proper USB
+devices
+
+
+Example - Mass Storage
+----------------------
+
+As an example of a USB device driver, see usb_storage.c. It uses its own
+uclass and declares itself as follows:
+
+U_BOOT_DRIVER(usb_mass_storage) = {
+	.name	= "usb_mass_storage",
+	.id	= UCLASS_MASS_STORAGE,
+	.of_match = usb_mass_storage_ids,
+	.probe = usb_mass_storage_probe,
+};
+
+static const struct usb_device_id mass_storage_id_table[] = {
+    { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
+      .bInterfaceClass = USB_CLASS_MASS_STORAGE},
+    { }						/* Terminating entry */
+};
+
+USB_DEVICE(usb_mass_storage, mass_storage_id_table);
+
+The USB_DEVICE() macro attaches the given table of matching information to
+the given driver. Note that the driver is declared in U_BOOT_DRIVER() as
+'usb_mass_storage' and this must match the first parameter of USB_DEVICE.
+
+When usb_find_and_bind_driver() is called on a USB device with the
+bInterfaceClass value of USB_CLASS_MASS_STORAGE, it will automatically find
+this driver and use it.
+
+
+Counter-example: USB Ethernet
+-----------------------------
+
+As an example of the old way of doing things, see usb_ether.c. When the bus
+is scanned, all Ethernet devices will be created as generic USB devices (in
+uclass UCLASS_USB_DEV_GENERIC). Then, when the scan is completed,
+usb_host_eth_scan() will be called. This looks through all the devices on
+each bus and manually figures out which are Ethernet devices in the ways of
+yore.
+
+In fact, usb_ether should be moved to driver model. Each USB Ethernet driver
+(e.g drivers/usb/eth/asix.c) should include a USB_DEVICE() declaration, so
+that it will be found as part of normal USB enumeration. Then, instead of a
+generic USB driver, a real (driver-model-aware) driver will be used. Since
+Ethernet now supports driver model, this should be fairly easy to achieve,
+and then usb_ether.c and the usb_host_eth_scan() will melt away.
+
+
+Sandbox
+-------
+
+All driver model uclasses must have tests and USB is no exception. To
+achieve this, a sandbox USB controller is provided. This can make use of
+emulation drivers which pretend to be USB devices. Emulations are provided
+for a hub and a flash stick. These are enough to create a pretend USB bus
+(defined by the sandbox device tree sandbox.dts) which can be scanned and
+used.
+
+Tests in test/dm/usb.c make use of this feature. It allows much of the USB
+stack to be tested without real hardware being needed.
+
+Here is an example device tree fragment:
+
+	usb at 1 {
+		compatible = "sandbox,usb";
+		hub {
+			compatible = "usb-hub";
+			usb,device-class = <USB_CLASS_HUB>;
+			hub-emul {
+				compatible = "sandbox,usb-hub";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				flash-stick {
+					reg = <0>;
+					compatible = "sandbox,usb-flash";
+					sandbox,filepath = "flash.bin";
+				};
+			};
+		};
+	};
+
+This defines a single controller, containing a root hub (which is required).
+The hub is emulated by a hub emulator, and the emulated hub has a single
+flash stick to emulate on one of its ports.
+
+When 'usb start' is used, the following 'dm tree' output will be available:
+
+ usb         [ + ]    `-- usb at 1
+ usb_hub     [ + ]        `-- hub
+ usb_emul    [ + ]            |-- hub-emul
+ usb_emul    [ + ]            |   `-- flash-stick
+ usb_mass_st [ + ]            `-- usb_mass_storage
+
+
+This may look a confusing. Most of it mirrors the device tree, but the
+'usb_mass_storage' device is not in the device tree. This is created by
+usb_find_and_bind_driver() based on the USB_DRIVER in usb_storage.c. While
+'flash-stick' is the emulation device, 'usb_mass_storage' is the real U-Boot
+USB device driver that talks to it.
+
+
+Future work
+-----------
+
+It is pretty uncommon to have a large USB bus with lots of hubs on an
+embedded system. In fact anything other than a root hub is uncommon. Still
+it would be possible to speed up enumeration in two ways:
+
+- breadth-first search would allow devices to be reset and probed in
+parallel to some extent
+- enumeration could be lazy, in the sense that we could enumerate just the
+root hub at first, then only progress to the next 'level' when a device is
+used that we cannot find. This could be made easier if the devices were
+statically declared in the device tree (which is acceptable for production
+boards where the same, known, things are on each bus).
+
+But in common cases the current algorithm is sufficient.
+
+Other things that need doing:
+- Convert usb_ether to use driver model as described above
+- Test that keyboards work (and convert to driver model)
+- Move the USB gadget framework to driver model
+- Implement OHCI in driver model
+- Implement USB PHYs in driver model
+- Work out a clever way to provide lazy init for USB devices
+
+--
+Simon Glass <[email protected]>
+23-Mar-15
Signature · 1 line
2.2.0.rc0.207.ga3a616c
#171 lore raw

PATCH v2 80/80 dm: usb: Add a README for driver model

There are some typos. Please correct them, thanks.

Quoted 30 lines · Simon Glass

Add some documentation describing how USB is implemented with USB. This might make things easier for people to understand.

---

Changes in v2:
- Rewrite and expand series to support driver model fully

  doc/driver-model/usb-info.txt | 415 ++++++++++++++++++++++++++++++++++++++++++
  1 file changed, 415 insertions(+)

create mode 100644 doc/driver-model/usb-info.txt

doc/driver-model/usb-info.txt new file +11 -0
new file mode 100644
index 0000000..3762b6c
@@ -0,0 +1,415 @@
+How USB works with driver model
+===============================
+
+Introduction
+------------
+
+Driver model USB support makes use of existing features but changes how
+drivers are found. This document provides some information intended to help
+understand how things work with USB in U-Boot when driver model is enabled.
+
+

doc/driver-model/usb-info.txt line 21

Quoted 10 lines
doc/driver-model/usb-info.txt new file +10 -0
+Enabling driver model for USB
+-----------------------------
+
+A new CONFIG_DM_USB option is provided to enable driver model for USB. This
+causes the USB uclass to be included, and drops the equivalent code in
+usb.c. In particular the usb_init() function is then implemented by the
+uclass.
+
+
+Support for ECHI and XCHI

EHCI
XHCI

Quoted 23 lines
doc/driver-model/usb-info.txt new file +23 -0
+-------------------------
+
+So far OHCI is not supported. Both EHCI and XHCI drivers should be declared
+as drivers in the USB uclass. For example:
+
+static const struct udevice_id ehci_usb_ids[] = {
+	{ .compatible = "nvidia,tegra20-ehci", .data = USB_CTLR_T20 },
+	{ .compatible = "nvidia,tegra30-ehci", .data = USB_CTLR_T30 },
+	{ .compatible = "nvidia,tegra114-ehci", .data = USB_CTLR_T114 },
+	{ }
+};
+
+U_BOOT_DRIVER(usb_ehci) = {
+	.name	= "ehci_tegra",
+	.id	= UCLASS_USB,
+	.of_match = ehci_usb_ids,
+	.ofdata_to_platdata = ehci_usb_ofdata_to_platdata,
+	.probe = tegra_ehci_usb_probe,
+	.remove = tegra_ehci_usb_remove,
+	.ops	= &ehci_usb_ops,
+	.platdata_auto_alloc_size = sizeof(struct usb_platdata),
+	.priv_auto_alloc_size = sizeof(struct fdt_usb),
+	.flags	= DM_FLAG_ALLOC_PRIV_DMA,

doc/driver-model/usb-info.txt line 54

Quoted 10 lines
doc/driver-model/usb-info.txt new file +10 -0
+};
+
+Here ehci_usb_ids is used to list the controllers that the driver supports.
+Each has its own data value. Controllers must be in the UCLASS_USB uclass.
+
+The ofdata_to_platdata() method allows the controller driver to grab any
+necessary settings from the device tree.
+
+The ops here are ehci_usb_ops. All EHCI drivers will use these same ops in
+most cases, since they are all ECHI-compatible. For ECHI there are also some

EHCI-compatible
For EHCI

doc/driver-model/usb-info.txt line 55

Quoted 1 line
doc/driver-model/usb-info.txt new file +1 -0
+special operations that can be overriden when calling ehci_register().

overridden

Quoted 4 lines
doc/driver-model/usb-info.txt new file +4 -0
+This defines a single controller, containing a root hub (which is required).
+The hub is emulated by a hub emulator, and the emulated hub has a single
+flash stick to emulate on one of its ports.
+

doc/driver-model/usb-info.txt line 381

Quoted 10 lines
doc/driver-model/usb-info.txt new file +10 -0
+When 'usb start' is used, the following 'dm tree' output will be available:
+
+ usb         [ + ]    `-- usb at 1
+ usb_hub     [ + ]        `-- hub
+ usb_emul    [ + ]            |-- hub-emul
+ usb_emul    [ + ]            |   `-- flash-stick
+ usb_mass_st [ + ]            `-- usb_mass_storage
+
+
+This may look a confusing. Most of it mirrors the device tree, but the

may look confusing
--nvpublic

#172 lore raw

PATCH v2 80/80 dm: usb: Add a README for driver model

Hi Jim,

Quoted 111 lines · Jim Lin

There are some typos. Please correct them, thanks.

Quoted 39 lines · Simon Glass

Add some documentation describing how USB is implemented with USB. This might make things easier for people to understand.

---

Changes in v2:
- Rewrite and expand series to support driver model fully

  doc/driver-model/usb-info.txt | 415
++++++++++++++++++++++++++++++++++++++++++
  1 file changed, 415 insertions(+)

create mode 100644 doc/driver-model/usb-info.txt

doc/driver-model/usb-info.txt new file +8 -0
new file mode 100644
index 0000000..3762b6c
@@ -0,0 +1,415 @@
+How USB works with driver model
+===============================
+
+Introduction
+------------
+
+Driver model USB support makes use of existing features but changes how
+drivers are found. This document provides some information intended to

help
+understand how things work with USB in U-Boot when driver model is enabled.

doc/driver-model/usb-info.txt new file +6 -0
+
+
+Enabling driver model for USB
+-----------------------------
+
+A new CONFIG_DM_USB option is provided to enable driver model for USB.

This

doc/driver-model/usb-info.txt line 21

Quoted 6 lines
doc/driver-model/usb-info.txt new file +6 -0
+causes the USB uclass to be included, and drops the equivalent code in
+usb.c. In particular the usb_init() function is then implemented by the
+uclass.
+
+
+Support for ECHI and XCHI

EHCI
XHCI

Quoted 35 lines

+-------------------------

doc/driver-model/usb-info.txt new file +2 -0
+
+So far OHCI is not supported. Both EHCI and XHCI drivers should be

declared

doc/driver-model/usb-info.txt new file +23 -0
+as drivers in the USB uclass. For example:
+
+static const struct udevice_id ehci_usb_ids[] = {
+       { .compatible = "nvidia,tegra20-ehci", .data = USB_CTLR_T20 },
+       { .compatible = "nvidia,tegra30-ehci", .data = USB_CTLR_T30 },
+       { .compatible = "nvidia,tegra114-ehci", .data = USB_CTLR_T114 },
+       { }
+};
+
+U_BOOT_DRIVER(usb_ehci) = {
+       .name   = "ehci_tegra",
+       .id     = UCLASS_USB,
+       .of_match = ehci_usb_ids,
+       .ofdata_to_platdata = ehci_usb_ofdata_to_platdata,
+       .probe = tegra_ehci_usb_probe,
+       .remove = tegra_ehci_usb_remove,
+       .ops    = &ehci_usb_ops,
+       .platdata_auto_alloc_size = sizeof(struct usb_platdata),
+       .priv_auto_alloc_size = sizeof(struct fdt_usb),
+       .flags  = DM_FLAG_ALLOC_PRIV_DMA,
+};
+
+Here ehci_usb_ids is used to list the controllers that the driver

supports.
+Each has its own data value. Controllers must be in the UCLASS_USB uclass.

doc/driver-model/usb-info.txt new file +5 -0
+
+The ofdata_to_platdata() method allows the controller driver to grab any
+necessary settings from the device tree.
+
+The ops here are ehci_usb_ops. All EHCI drivers will use these same ops
Quoted 3 lines

in
+most cases, since they are all ECHI-compatible. For ECHI there are also some

EHCI-compatible
For EHCI

Quoted 2 lines

+special operations that can be overriden when calling ehci_register().

overridden

Quoted 11 lines

+This defines a single controller, containing a root hub (which is required).

doc/driver-model/usb-info.txt new file +4 -0
+The hub is emulated by a hub emulator, and the emulated hub has a single
+flash stick to emulate on one of its ports.
+
+When 'usb start' is used, the following 'dm tree' output will be

available:
+

+ usb         [ + ]    `-- usb at 1
+ usb_hub     [ + ]        `-- hub
+ usb_emul    [ + ]            |-- hub-emul
Quoted 8 lines

doc/driver-model/usb-info.txt line 381

Quoted 5 lines

+ usb_emul [ + ] | `-- flash-stick
+ usb_mass_st [ + ] `-- usb_mass_storage

doc/driver-model/usb-info.txt new file +3 -0
+
+
+This may look a confusing. Most of it mirrors the device tree, but the

may look confusing
--nvpublic

Thanks for the corrections, I fixed these.

Applied to u-boot-dm/next.

#173 lore raw

v2 cover dm: Add USB support

In reply to Simon Glass
Quoted 4 lines · Simon Glass

This series adds driver model support to USB. The intent is to permit the various subsystems (OHCI, EHCI, XHCI) to co-exist and allow any number of USB ports of different types.

Quoted 8 lines

With the RFC series, only USB controllers had a real driver model device. USB devices (including the hub in the controller) were not modelled as driver model devices.

While this was expedient, and produced much fewer patches, it is not a long-term solution. Also, since then, driver model Ethernet support (which USB can use) has been merged to u-boot-dm/next. It seems better to bite the bullet and do a full conversion.

Whew.

Best regards,
Marek Vasut

#174 lore raw

v2 cover dm: Add USB support

Hi Marek,

Quoted 9 lines · Marek Vasut
Quoted 8 lines · Simon Glass

This series adds driver model support to USB. The intent is to permit the various subsystems (OHCI, EHCI, XHCI) to co-exist and allow any number of USB ports of different types.

With the RFC series, only USB controllers had a real driver model device. USB devices (including the hub in the controller) were not modelled as driver model devices.

Quoted 8 lines
Quoted 4 lines

While this was expedient, and produced much fewer patches, it is not a long-term solution. Also, since then, driver model Ethernet support (which USB can use) has been merged to u-boot-dm/next. It seems better to bite the bullet and do a full conversion.

Whew.

Thanks very much for working through these!

Unless there are other comments I plan to apply this to u-boot-dm/next in the next few days. I expect it will need some tweaking as boards are moved over too.

Regards,
Simon

#175 lore raw

v2 cover dm: Add USB support

Quoted 1 line · Simon Glass

Hi Marek,

Hi Simon,

Quoted 17 lines · Marek Vasut
Quoted 16 lines · Simon Glass
Quoted 4 lines

This series adds driver model support to USB. The intent is to permit the various subsystems (OHCI, EHCI, XHCI) to co-exist and allow any number of USB ports of different types.

Quoted 8 lines

With the RFC series, only USB controllers had a real driver model device. USB devices (including the hub in the controller) were not modelled as driver model devices.

While this was expedient, and produced much fewer patches, it is not a long-term solution. Also, since then, driver model Ethernet support (which USB can use) has been merged to u-boot-dm/next. It seems better to bite the bullet and do a full conversion.

Whew.

Quoted 7 lines
Quoted 1 line

Thanks very much for working through these!

Unless there are other comments I plan to apply this to u-boot-dm/next in the next few days. I expect it will need some tweaking as boards are moved over too.

Please apply, I'm really looking forward to this.

Thank you very much for putting all the effort into this !

Best regards,
Marek Vasut

#176 lore raw

v2 cover dm: Add USB support

Hi Marek,

Quoted 26 lines · Marek Vasut
Quoted 1 line · Simon Glass

Hi Marek,

Hi Simon,

Quoted 21 lines · Marek Vasut
Quoted 9 lines · Simon Glass
Quoted 8 lines

This series adds driver model support to USB. The intent is to permit the various subsystems (OHCI, EHCI, XHCI) to co-exist and allow any number of USB ports of different types.

With the RFC series, only USB controllers had a real driver model device. USB devices (including the hub in the controller) were not modelled as driver model devices.

Quoted 8 lines
Quoted 4 lines

While this was expedient, and produced much fewer patches, it is not a long-term solution. Also, since then, driver model Ethernet support (which USB can use) has been merged to u-boot-dm/next. It seems better to bite the bullet and do a full conversion.

Whew.

Thanks very much for working through these!

Quoted 7 lines
Quoted 3 lines

Unless there are other comments I plan to apply this to u-boot-dm/next in the next few days. I expect it will need some tweaking as boards are moved over too.

Please apply, I'm really looking forward to this.

Thank you very much for putting all the effort into this !

OK, I'll apply to u-boot-dm/next, do a bit more testing, and apply. It will be great to get this moved over.

Regards,
Simon

#177 lore raw

v2 cover dm: Add USB support

Quoted 1 line · Simon Glass

Hi Marek,

Hi Simon,

Quoted 31 lines · Marek Vasut
Quoted 30 lines · Simon Glass
Quoted 1 line

Hi Marek,

Hi Simon,

Quoted 24 lines · Marek Vasut
Quoted 9 lines · Simon Glass
Quoted 8 lines

This series adds driver model support to USB. The intent is to permit the various subsystems (OHCI, EHCI, XHCI) to co-exist and allow any number of USB ports of different types.

With the RFC series, only USB controllers had a real driver model device. USB devices (including the hub in the controller) were not modelled as driver model devices.

Quoted 8 lines
Quoted 4 lines

While this was expedient, and produced much fewer patches, it is not a long-term solution. Also, since then, driver model Ethernet support (which USB can use) has been merged to u-boot-dm/next. It seems better to bite the bullet and do a full conversion.

Whew.

Thanks very much for working through these!

Unless there are other comments I plan to apply this to u-boot-dm/next in the next few days. I expect it will need some tweaking as boards are moved over too.

Quoted 6 lines
Quoted 3 lines

Please apply, I'm really looking forward to this.

Thank you very much for putting all the effort into this !

OK, I'll apply to u-boot-dm/next, do a bit more testing, and apply. It will be great to get this moved over.

Thank you!

Best regards,
Marek Vasut