usb-info.txt 17 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415
How USB works with driver model


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

Support for EHCI and XHCI

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),

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 EHCI-compatible. For EHCI there are also some
special operations that can be overridden 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

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

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
- 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
- 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


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

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",
	.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

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.


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

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@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@1
 usb_hub     [ + ]        `-- hub
 usb_emul    [ + ]            |-- hub-emul
 usb_emul    [ + ]            |   `-- flash-stick
 usb_mass_st [ + ]            `-- usb_mass_storage

This may look 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 <>