doc: driver-model: Convert README.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>
Reviewed-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
This commit is contained in:
Bin Meng 2019-07-18 00:33:49 -07:00 committed by Tom Rini
parent d9756c41f9
commit ed205e677b
2 changed files with 305 additions and 278 deletions

View file

@ -1,40 +1,46 @@
Driver Model
============
.. SPDX-License-Identifier: GPL-2.0+
.. sectionauthor:: Simon Glass <sjg@chromium.org>
Design Details
==============
This README contains high-level information about driver model, a unified
way of declaring and accessing drivers in U-Boot. The original work was done
by:
Marek Vasut <marex@denx.de>
Pavel Herrmann <morpheus.ibis@gmail.com>
Viktor Křivák <viktor.krivak@gmail.com>
Tomas Hlavacek <tmshlvck@gmail.com>
* Marek Vasut <marex@denx.de>
* Pavel Herrmann <morpheus.ibis@gmail.com>
* Viktor Křivák <viktor.krivak@gmail.com>
* Tomas Hlavacek <tmshlvck@gmail.com>
This has been both simplified and extended into the current implementation
by:
Simon Glass <sjg@chromium.org>
* Simon Glass <sjg@chromium.org>
Terminology
-----------
Uclass - a group of devices which operate in the same way. A uclass provides
Uclass
a group of devices which operate in the same way. A uclass provides
a way of accessing individual devices within the group, but always
using the same interface. For example a GPIO uclass provides
operations for get/set value. An I2C uclass may have 10 I2C ports,
4 with one driver, and 6 with another.
Driver - some code which talks to a peripheral and presents a higher-level
Driver
some code which talks to a peripheral and presents a higher-level
interface to it.
Device - an instance of a driver, tied to a particular port or peripheral.
Device
an instance of a driver, tied to a particular port or peripheral.
How to try it
-------------
Build U-Boot sandbox and run it:
Build U-Boot sandbox and run it::
make sandbox_defconfig
make
@ -56,7 +62,7 @@ provide good code coverage of them. It does have multiple drivers, it
handles parameter data and platdata (data which tells the driver how
to operate on a particular platform) and it uses private driver data.
To try it, see the example session below:
To try it, see the example session below::
=>demo hello 1
Hello '@' from 07981110: red 4
@ -88,11 +94,11 @@ Running the tests
The intent with driver model is that the core portion has 100% test coverage
in sandbox, and every uclass has its own test. As a move towards this, tests
are provided in test/dm. To run them, try:
are provided in test/dm. To run them, try::
./test/py/test.py --bd sandbox --build -k ut_dm -v
You should see something like this:
You should see something like this::
(venv)$ ./test/py/test.py --bd sandbox --build -k ut_dm -v
+make O=/root/u-boot/build-sandbox -s sandbox_defconfig
@ -228,6 +234,8 @@ What is going on?
Let's start at the top. The demo command is in common/cmd_demo.c. It does
the usual command processing and then:
.. code-block:: c
struct udevice *demo_dev;
ret = uclass_get_device(UCLASS_DEMO, devnum, &demo_dev);
@ -245,6 +253,8 @@ The device is automatically activated ready for use by uclass_get_device().
Now that we have the device we can do things like:
.. code-block:: c
return demo_hello(demo_dev, ch);
This function is in the demo uclass. It takes care of calling the 'hello'
@ -253,6 +263,8 @@ this particular device may use one or other of them.
The code for demo_hello() is in drivers/demo/demo-uclass.c:
.. code-block:: c
int demo_hello(struct udevice *dev, int ch)
{
const struct demo_ops *ops = device_get_ops(dev);
@ -266,6 +278,8 @@ int demo_hello(struct udevice *dev, int ch)
As you can see it just calls the relevant driver method. One of these is
in drivers/demo/demo-simple.c:
.. code-block:: c
static int simple_hello(struct udevice *dev, int ch)
{
const struct dm_demo_pdata *pdata = dev_get_platdata(dev);
@ -287,6 +301,8 @@ Declaring Drivers
A driver declaration looks something like this (see
drivers/demo/demo-shape.c):
.. code-block:: c
static const struct demo_ops shape_ops = {
.hello = shape_hello,
.status = shape_status,
@ -315,11 +331,11 @@ so driver model can find the drivers that are available.
The methods a device can provide are documented in the device.h header.
Briefly, they are:
bind - make the driver model aware of a device (bind it to its driver)
unbind - make the driver model forget the device
ofdata_to_platdata - convert device tree data to platdata - see later
probe - make a device ready for use
remove - remove a device so it cannot be used until probed again
* bind - make the driver model aware of a device (bind it to its driver)
* unbind - make the driver model forget the device
* ofdata_to_platdata - convert device tree data to platdata - see later
* probe - make a device ready for use
* remove - remove a device so it cannot be used until probed again
The sequence to get a device to work is bind, ofdata_to_platdata (if using
device tree) and probe.
@ -328,14 +344,14 @@ device tree) and probe.
Platform Data
-------------
*** Note: platform data is the old way of doing things. It is
*** basically a C structure which is passed to drivers to tell them about
*** platform-specific settings like the address of its registers, bus
*** speed, etc. Device tree is now the preferred way of handling this.
*** Unless you have a good reason not to use device tree (the main one
*** being you need serial support in SPL and don't have enough SRAM for
*** the cut-down device tree and libfdt libraries) you should stay away
*** from platform data.
Note: platform data is the old way of doing things. It is
basically a C structure which is passed to drivers to tell them about
platform-specific settings like the address of its registers, bus
speed, etc. Device tree is now the preferred way of handling this.
Unless you have a good reason not to use device tree (the main one
being you need serial support in SPL and don't have enough SRAM for
the cut-down device tree and libfdt libraries) you should stay away
from platform data.
Platform data is like Linux platform data, if you are familiar with that.
It provides the board-specific information to start up a device.
@ -384,10 +400,13 @@ Drivers can access their data via dev->info->platdata. Here is
the declaration for the platform data, which would normally appear
in the board file.
.. code-block:: c
static const struct dm_demo_cdata red_square = {
.colour = "red",
.sides = 4.
};
static const struct driver_info info[] = {
{
.name = "demo_shape_drv",
@ -409,6 +428,8 @@ necessary.
With device tree we replace the above code with the following device tree
fragment:
.. code-block:: c
red-square {
compatible = "demo-shape";
colour = "red";
@ -425,6 +446,8 @@ the board first!).
The easiest way to make this work it to add a few members to the driver:
.. code-block:: c
.platdata_auto_alloc_size = sizeof(struct dm_test_pdata),
.ofdata_to_platdata = testfdt_ofdata_to_platdata,
@ -464,6 +487,8 @@ Declaring Uclasses
The demo uclass is declared like this:
.. code-block:: c
U_BOOT_CLASS(demo) = {
.id = UCLASS_DEMO,
};
@ -496,6 +521,8 @@ device will be automatically allocated the next available sequence number.
To specify the sequence number in the device tree an alias is typically
used. Make sure that the uclass has the DM_UC_FLAG_SEQ_ALIAS flag set.
.. code-block:: none
aliases {
serial2 = "/serial@22230000";
};
@ -506,6 +533,8 @@ which requests serial device 2 will obtain this device.
More commonly you can use node references, which expand to the full path:
.. code-block:: none
aliases {
serial2 = &serial_2;
};
@ -547,7 +576,7 @@ children are bound and probed.
Here an explanation of how a bus fits with a uclass may be useful. Consider
a USB bus with several devices attached to it, each from a different (made
up) uclass:
up) uclass::
xhci_usb (UCLASS_USB)
eth (UCLASS_ETHERNET)
@ -579,7 +608,7 @@ Note that the information that controls this behaviour is in the bus's
driver, not the child's. In fact it is possible that child has no knowledge
that it is connected to a bus. The same child device may even be used on two
different bus types. As an example. the 'flash' device shown above may also
be connected on a SATA bus or standalone with no bus:
be connected on a SATA bus or standalone with no bus::
xhci_usb (UCLASS_USB)
flash (UCLASS_FLASH_STORAGE) - parent data/methods defined by USB bus
@ -613,7 +642,8 @@ methods mentioned here are optional - e.g. if there is no probe() method for
a device then it will not be called. A simple device may have very few
methods actually defined.
1. Bind stage
Bind stage
^^^^^^^^^^
U-Boot discovers devices using one of these two methods:
@ -653,45 +683,46 @@ probe/remove which is independent of bind/unbind. This is partly because in
U-Boot it may be expensive to probe devices and we don't want to do it until
they are needed, or perhaps until after relocation.
2. Activation/probe
Activation/probe
^^^^^^^^^^^^^^^^
When a device needs to be used, U-Boot activates it, by following these
steps (see device_probe()):
a. If priv_auto_alloc_size is non-zero, then the device-private space
1. If priv_auto_alloc_size is non-zero, then the device-private space
is allocated for the device and zeroed. It will be accessible as
dev->priv. The driver can put anything it likes in there, but should use
it for run-time information, not platform data (which should be static
and known before the device is probed).
b. If platdata_auto_alloc_size is non-zero, then the platform data space
2. If platdata_auto_alloc_size is non-zero, then the platform data space
is allocated. This is only useful for device tree operation, since
otherwise you would have to specific the platform data in the
U_BOOT_DEVICE() declaration. The space is allocated for the device and
zeroed. It will be accessible as dev->platdata.
c. If the device's uclass specifies a non-zero per_device_auto_alloc_size,
3. If the device's uclass specifies a non-zero per_device_auto_alloc_size,
then this space is allocated and zeroed also. It is allocated for and
stored in the device, but it is uclass data. owned by the uclass driver.
It is possible for the device to access it.
d. If the device's immediate parent specifies a per_child_auto_alloc_size
4. If the device's immediate parent specifies a per_child_auto_alloc_size
then this space is allocated. This is intended for use by the parent
device to keep track of things related to the child. For example a USB
flash stick attached to a USB host controller would likely use this
space. The controller can hold information about the USB state of each
of its children.
e. All parent devices are probed. It is not possible to activate a device
5. All parent devices are probed. It is not possible to activate a device
unless its predecessors (all the way up to the root device) are activated.
This means (for example) that an I2C driver will require that its bus
be activated.
f. The device's sequence number is assigned, either the requested one
6. The device's sequence number is assigned, either the requested one
(assuming no conflicts) or the next available one if there is a conflict
or nothing particular is requested.
g. If the driver provides an ofdata_to_platdata() method, then this is
7. If the driver provides an ofdata_to_platdata() method, then this is
called to convert the device tree data into platform data. This should
do various calls like fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), ...)
to access the node and store the resulting information into dev->platdata.
@ -707,7 +738,7 @@ steps (see device_probe()):
data, one day it is possible that U-Boot will cache platform data for
devices which are regularly de/activated).
h. The device's probe() method is called. This should do anything that
8. The device's probe() method is called. This should do anything that
is required by the device to get it going. This could include checking
that the hardware is actually present, setting up clocks for the
hardware and setting up hardware registers to initial values. The code
@ -722,40 +753,42 @@ steps (see device_probe()):
allocate the priv space here yourself. The same applies also to
platdata_auto_alloc_size. Remember to free them in the remove() method.
i. The device is marked 'activated'
9. The device is marked 'activated'
j. The uclass's post_probe() method is called, if one exists. This may
10. The uclass's post_probe() method is called, if one exists. This may
cause the uclass to do some housekeeping to record the device as
activated and 'known' by the uclass.
3. Running stage
Running stage
^^^^^^^^^^^^^
The device is now activated and can be used. From now until it is removed
all of the above structures are accessible. The device appears in the
uclass's list of devices (so if the device is in UCLASS_GPIO it will appear
as a device in the GPIO uclass). This is the 'running' state of the device.
4. Removal stage
Removal stage
^^^^^^^^^^^^^
When the device is no-longer required, you can call device_remove() to
remove it. This performs the probe steps in reverse:
a. The uclass's pre_remove() method is called, if one exists. This may
1. The uclass's pre_remove() method is called, if one exists. This may
cause the uclass to do some housekeeping to record the device as
deactivated and no-longer 'known' by the uclass.
b. All the device's children are removed. It is not permitted to have
2. All the device's children are removed. It is not permitted to have
an active child device with a non-active parent. This means that
device_remove() is called for all the children recursively at this point.
c. The device's remove() method is called. At this stage nothing has been
3. The device's remove() method is called. At this stage nothing has been
deallocated so platform data, private data and the uclass data will all
still be present. This is where the hardware can be shut down. It is
intended that the device be completely inactive at this point, For U-Boot
to be sure that no hardware is running, it should be enough to remove
all devices.
d. The device memory is freed (platform data, private data, uclass data,
4. The device memory is freed (platform data, private data, uclass data,
parent data).
Note: Because the platform data for a U_BOOT_DEVICE() is defined with a
@ -764,25 +797,26 @@ remove it. This performs the probe steps in reverse:
be dynamically allocated, and thus needs to be deallocated during the
remove() method, either:
1. if the platdata_auto_alloc_size is non-zero, the deallocation
- if the platdata_auto_alloc_size is non-zero, the deallocation
happens automatically within the driver model core; or
2. when platdata_auto_alloc_size is 0, both the allocation (in probe()
- when platdata_auto_alloc_size is 0, both the allocation (in probe()
or preferably ofdata_to_platdata()) and the deallocation in remove()
are the responsibility of the driver author.
e. The device sequence number is set to -1, meaning that it no longer
5. The device sequence number is set to -1, meaning that it no longer
has an allocated sequence. If the device is later reactivated and that
sequence number is still free, it may well receive the name sequence
number again. But from this point, the sequence number previously used
by this device will no longer exist (think of SPI bus 2 being removed
and bus 2 is no longer available for use).
f. The device is marked inactive. Note that it is still bound, so the
6. The device is marked inactive. Note that it is still bound, so the
device structure itself is not freed at this point. Should the device be
activated again, then the cycle starts again at step 2 above.
5. Unbind stage
Unbind stage
^^^^^^^^^^^^
The device is unbound. This is the step that actually destroys the device.
If a parent has children these will be destroyed first. After this point
@ -903,12 +937,3 @@ change this to dynamic numbering, but then we would require some sort of
lookup service, perhaps searching by name. This is slightly less efficient
so has been left out for now. One small advantage of dynamic numbering might
be fewer merge conflicts in uclass-id.h.
Simon Glass
sjg@chromium.org
April 2013
Updated 7-May-13
Updated 14-Jun-13
Updated 18-Oct-13
Updated 5-Nov-13

View file

@ -5,3 +5,5 @@ Driver Model
.. toctree::
:maxdepth: 2
design