mirror of
https://github.com/Fishwaldo/u-boot.git
synced 2025-06-28 01:22:20 +00:00
doc: driver-model: Convert usb-info.txt to reST
Convert plain text documentation to reStructuredText format and add it to Sphinx TOC tree. No essential content change. Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
This commit is contained in:
parent
7ee49d03ea
commit
a077bae372
2 changed files with 96 additions and 87 deletions
|
@ -18,3 +18,4 @@ Driver Model
|
||||||
remoteproc-framework
|
remoteproc-framework
|
||||||
serial-howto
|
serial-howto
|
||||||
spi-howto
|
spi-howto
|
||||||
|
usb-info
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
.. SPDX-License-Identifier: GPL-2.0+
|
||||||
|
|
||||||
How USB works with driver model
|
How USB works with driver model
|
||||||
===============================
|
===============================
|
||||||
|
|
||||||
|
@ -24,25 +26,27 @@ Support for EHCI and XHCI
|
||||||
So far OHCI is not supported. Both EHCI and XHCI drivers should be declared
|
So far OHCI is not supported. Both EHCI and XHCI drivers should be declared
|
||||||
as drivers in the USB uclass. For example:
|
as drivers in the USB uclass. For example:
|
||||||
|
|
||||||
static const struct udevice_id ehci_usb_ids[] = {
|
.. code-block:: c
|
||||||
{ .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) = {
|
static const struct udevice_id ehci_usb_ids[] = {
|
||||||
.name = "ehci_tegra",
|
{ .compatible = "nvidia,tegra20-ehci", .data = USB_CTLR_T20 },
|
||||||
.id = UCLASS_USB,
|
{ .compatible = "nvidia,tegra30-ehci", .data = USB_CTLR_T30 },
|
||||||
.of_match = ehci_usb_ids,
|
{ .compatible = "nvidia,tegra114-ehci", .data = USB_CTLR_T114 },
|
||||||
.ofdata_to_platdata = ehci_usb_ofdata_to_platdata,
|
{ }
|
||||||
.probe = tegra_ehci_usb_probe,
|
};
|
||||||
.remove = tegra_ehci_usb_remove,
|
|
||||||
.ops = &ehci_usb_ops,
|
U_BOOT_DRIVER(usb_ehci) = {
|
||||||
.platdata_auto_alloc_size = sizeof(struct usb_platdata),
|
.name = "ehci_tegra",
|
||||||
.priv_auto_alloc_size = sizeof(struct fdt_usb),
|
.id = UCLASS_USB,
|
||||||
.flags = DM_FLAG_ALLOC_PRIV_DMA,
|
.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.
|
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.
|
Each has its own data value. Controllers must be in the UCLASS_USB uclass.
|
||||||
|
@ -80,7 +84,7 @@ Data structures
|
||||||
|
|
||||||
The following primary data structures are in use:
|
The following primary data structures are in use:
|
||||||
|
|
||||||
- struct usb_device
|
- struct usb_device:
|
||||||
This holds information about a device on the bus. All devices have
|
This holds information about a device on the bus. All devices have
|
||||||
this structure, even the root hub. The controller itself does not
|
this structure, even the root hub. The controller itself does not
|
||||||
have this structure. You can access it for a device 'dev' with
|
have this structure. You can access it for a device 'dev' with
|
||||||
|
@ -89,19 +93,19 @@ The following primary data structures are in use:
|
||||||
handles that). Once the device is set up, you can find the device
|
handles that). Once the device is set up, you can find the device
|
||||||
descriptor and current configuration descriptor in this structure.
|
descriptor and current configuration descriptor in this structure.
|
||||||
|
|
||||||
- struct usb_platdata
|
- struct usb_platdata:
|
||||||
This holds platform data for a controller. So far this is only used
|
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
|
as a work-around for controllers which can act as USB devices in OTG
|
||||||
mode, since the gadget framework does not use driver model.
|
mode, since the gadget framework does not use driver model.
|
||||||
|
|
||||||
- struct usb_dev_platdata
|
- struct usb_dev_platdata:
|
||||||
This holds platform data for a device. You can access it for a
|
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
|
device 'dev' with dev_get_parent_platdata(dev). It holds the device
|
||||||
address and speed - anything that can be determined before 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
|
driver is actually set up. When probing the bus this structure is
|
||||||
used to provide essential information to the device driver.
|
used to provide essential information to the device driver.
|
||||||
|
|
||||||
- struct usb_bus_priv
|
- struct usb_bus_priv:
|
||||||
This is private information for each controller, maintained by the
|
This is private information for each controller, maintained by the
|
||||||
controller uclass. It is mostly used to keep track of the next
|
controller uclass. It is mostly used to keep track of the next
|
||||||
device address to use.
|
device address to use.
|
||||||
|
@ -197,49 +201,49 @@ Device initialisation happens roughly like this:
|
||||||
- This calls usb_init() which works through each controller in turn
|
- This calls usb_init() which works through each controller in turn
|
||||||
- The controller is probed(). This does no enumeration.
|
- The controller is probed(). This does no enumeration.
|
||||||
- Then usb_scan_bus() is called. This calls usb_scan_device() to scan the
|
- 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
|
(only) device that is attached to the controller - a root hub
|
||||||
- usb_scan_device() sets up a fake struct usb_device and calls
|
- 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(), passing the port number to be scanned, in this case
|
||||||
0
|
port 0
|
||||||
- usb_setup_device() first calls usb_prepare_device() to set the device
|
- usb_setup_device() first calls usb_prepare_device() to set the device
|
||||||
address, then usb_select_config() to select the first configuration
|
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
|
- 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
|
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
|
use this to figure out what driver to use
|
||||||
- back in usb_scan_device(), we call usb_find_child() to try to find an
|
- 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
|
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
|
happen if the device is mentioned in the device tree, or if we previously
|
||||||
scanned the bus and so the device was created before
|
scanned the bus and so the device was created before
|
||||||
- if usb_find_child() does not find an existing device, we call
|
- 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() which tries to bind one
|
||||||
- usb_find_and_bind_driver() searches all available USB drivers (declared
|
- 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
|
with USB_DEVICE()). If it finds a match it binds that driver to create a
|
||||||
device.
|
new device.
|
||||||
- If it does not, it binds a generic driver. A generic driver is good enough
|
- 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
|
to allow access to the device (sending it packets, etc.) but all
|
||||||
functionality will need to be implemented outside the driver model.
|
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
|
- 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
|
done, we have a device with the correct uclass. At this point we want to
|
||||||
probe the device
|
probe the device
|
||||||
- first we store basic information about the new device (address, port,
|
- first we store basic information about the new device (address, port,
|
||||||
speed) in its parent platform data. We cannot store it its private data
|
speed) in its parent platform data. We cannot store it its private data
|
||||||
since that will not exist until the device is probed.
|
since that will not exist until the device is probed.
|
||||||
- then we call device_probe() which probes the device
|
- then we call device_probe() which probes the device
|
||||||
- the first probe step is actually the USB controller's (or USB hubs's)
|
- 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
|
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
|
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
|
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
|
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
|
(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
|
usb_select_config() again to make sure that everything about the device is
|
||||||
set up
|
set up
|
||||||
- note that we have called usb_select_config() twice. This is inefficient
|
- note that we have called usb_select_config() twice. This is inefficient
|
||||||
but the alternative is to store additional information in the platform data.
|
but the alternative is to store additional information in the platform data.
|
||||||
The time taken is minimal and this way is simpler
|
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
|
- at this point the device is set up and ready for use so far as the USB
|
||||||
subsystem is concerned
|
subsystem is concerned
|
||||||
- the device's probe() method is then called. It can send messages and do
|
- the device's probe() method is then called. It can send messages and do
|
||||||
whatever else it wants to make the device work.
|
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
|
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),
|
find any devices. The above steps will have created a hub (UCLASS_USB_HUB),
|
||||||
|
@ -250,25 +254,25 @@ 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() is called, and the following steps take place:
|
||||||
|
|
||||||
- usb_hub_post_probe() calls usb_hub_scan() to scan the hub, which in turn
|
- usb_hub_post_probe() calls usb_hub_scan() to scan the hub, which in turn
|
||||||
calls usb_hub_configure()
|
calls usb_hub_configure()
|
||||||
- hub power is enabled
|
- hub power is enabled
|
||||||
- we loop through each port on the hub, performing the same steps for each
|
- 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
|
- 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
|
usb_hub_port_connect_change(). If so, then usb_scan_device() is called to
|
||||||
scan the device, passing the appropriate port number.
|
scan the device, passing the appropriate port number.
|
||||||
- you will recognise usb_scan_device() from the steps above. It sets up the
|
- 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
|
device ready for use. If it is a hub, it will scan that hub before it
|
||||||
continues here (recursively, depth-first)
|
continues here (recursively, depth-first)
|
||||||
- once all hub ports are scanned in this way, the hub is ready for use and
|
- once all hub ports are scanned in this way, the hub is ready for use and
|
||||||
all of its downstream devices also
|
all of its downstream devices also
|
||||||
- additional controllers are scanned in the same way
|
- additional controllers are scanned in the same way
|
||||||
|
|
||||||
The above method has some nice properties:
|
The above method has some nice properties:
|
||||||
|
|
||||||
- the bus enumeration happens by virtue of driver model's natural device flow
|
- 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
|
- 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
|
drivers do not need to know they are on a USB bus, at least so far as
|
||||||
enumeration goes
|
enumeration goes
|
||||||
- hub scanning happens automatically after a hub is probed
|
- hub scanning happens automatically after a hub is probed
|
||||||
|
|
||||||
|
|
||||||
|
@ -279,9 +283,9 @@ USB hubs are scanned as in the section above. While hubs have their own
|
||||||
uclass, they share some common elements with controllers:
|
uclass, they share some common elements with controllers:
|
||||||
|
|
||||||
- they both attach private data to their children (struct usb_device,
|
- they both attach private data to their children (struct usb_device,
|
||||||
accessible for a child with dev_get_parent_priv(child))
|
accessible for a child with dev_get_parent_priv(child))
|
||||||
- they both use usb_child_pre_probe() to set up their children as proper USB
|
- they both use usb_child_pre_probe() to set up their children as proper USB
|
||||||
devices
|
devices
|
||||||
|
|
||||||
|
|
||||||
Example - Mass Storage
|
Example - Mass Storage
|
||||||
|
@ -290,20 +294,22 @@ Example - Mass Storage
|
||||||
As an example of a USB device driver, see usb_storage.c. It uses its own
|
As an example of a USB device driver, see usb_storage.c. It uses its own
|
||||||
uclass and declares itself as follows:
|
uclass and declares itself as follows:
|
||||||
|
|
||||||
U_BOOT_DRIVER(usb_mass_storage) = {
|
.. code-block:: c
|
||||||
.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[] = {
|
U_BOOT_DRIVER(usb_mass_storage) = {
|
||||||
{ .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
|
.name = "usb_mass_storage",
|
||||||
.bInterfaceClass = USB_CLASS_MASS_STORAGE},
|
.id = UCLASS_MASS_STORAGE,
|
||||||
{ } /* Terminating entry */
|
.of_match = usb_mass_storage_ids,
|
||||||
};
|
.probe = usb_mass_storage_probe,
|
||||||
|
};
|
||||||
|
|
||||||
USB_DEVICE(usb_mass_storage, mass_storage_id_table);
|
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 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
|
the given driver. Note that the driver is declared in U_BOOT_DRIVER() as
|
||||||
|
@ -347,6 +353,8 @@ stack to be tested without real hardware being needed.
|
||||||
|
|
||||||
Here is an example device tree fragment:
|
Here is an example device tree fragment:
|
||||||
|
|
||||||
|
.. code-block:: none
|
||||||
|
|
||||||
usb@1 {
|
usb@1 {
|
||||||
compatible = "sandbox,usb";
|
compatible = "sandbox,usb";
|
||||||
hub {
|
hub {
|
||||||
|
@ -369,13 +377,13 @@ 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
|
The hub is emulated by a hub emulator, and the emulated hub has a single
|
||||||
flash stick to emulate on one of its ports.
|
flash stick to emulate on one of its ports.
|
||||||
|
|
||||||
When 'usb start' is used, the following 'dm tree' output will be available:
|
When 'usb start' is used, the following 'dm tree' output will be available::
|
||||||
|
|
||||||
usb [ + ] `-- usb@1
|
usb [ + ] `-- usb@1
|
||||||
usb_hub [ + ] `-- hub
|
usb_hub [ + ] `-- hub
|
||||||
usb_emul [ + ] |-- hub-emul
|
usb_emul [ + ] |-- hub-emul
|
||||||
usb_emul [ + ] | `-- flash-stick
|
usb_emul [ + ] | `-- flash-stick
|
||||||
usb_mass_st [ + ] `-- usb_mass_storage
|
usb_mass_st [ + ] `-- usb_mass_storage
|
||||||
|
|
||||||
|
|
||||||
This may look confusing. Most of it mirrors the device tree, but the
|
This may look confusing. Most of it mirrors the device tree, but the
|
||||||
|
@ -393,12 +401,12 @@ embedded system. In fact anything other than a root hub is uncommon. Still
|
||||||
it would be possible to speed up enumeration in two ways:
|
it would be possible to speed up enumeration in two ways:
|
||||||
|
|
||||||
- breadth-first search would allow devices to be reset and probed in
|
- breadth-first search would allow devices to be reset and probed in
|
||||||
parallel to some extent
|
parallel to some extent
|
||||||
- enumeration could be lazy, in the sense that we could enumerate just the
|
- 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
|
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
|
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
|
statically declared in the device tree (which is acceptable for production
|
||||||
boards where the same, known, things are on each bus).
|
boards where the same, known, things are on each bus).
|
||||||
|
|
||||||
But in common cases the current algorithm is sufficient.
|
But in common cases the current algorithm is sufficient.
|
||||||
|
|
||||||
|
@ -410,6 +418,6 @@ Other things that need doing:
|
||||||
- Implement USB PHYs in driver model
|
- Implement USB PHYs in driver model
|
||||||
- Work out a clever way to provide lazy init for USB devices
|
- Work out a clever way to provide lazy init for USB devices
|
||||||
|
|
||||||
--
|
|
||||||
Simon Glass <sjg@chromium.org>
|
.. Simon Glass <sjg@chromium.org>
|
||||||
23-Mar-15
|
.. 23-Mar-15
|
Loading…
Add table
Add a link
Reference in a new issue