dm: core: Add a flag to control sequence numbering
authorSimon Glass <sjg@chromium.org>
Sun, 25 Jan 2015 15:27:05 +0000 (08:27 -0700)
committerSimon Glass <sjg@chromium.org>
Fri, 30 Jan 2015 00:09:55 +0000 (17:09 -0700)
At present we try to use the 'reg' property and device tree aliases to give
devices a sequence number. The 'reg' property is often actually a memory
address, so the sequence numbers thus-obtained are not useful. It would be
better if the devices were just sequentially numbered in that case. In fact
neither I2C nor SPI use this feature, so drop it.

Some devices need us to look up an alias to number them within the uclass.
Add a flag to control this, so it is not done unless it is needed.

Adjust the tests to test this new behaviour.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Masahiro Yamada <yamada.m@jp.panasonic.com>
doc/driver-model/README.txt
drivers/core/device.c
drivers/i2c/i2c-uclass.c
drivers/serial/serial-uclass.c
drivers/spi/spi-uclass.c
include/dm/uclass.h
test/dm/bus.c
test/dm/test-fdt.c
test/dm/test.dts

index 40415698cf496b7700c6b2e90ac6e55a88afc5a5..0c1292bf125240c3090f403351ac1a59288fd44f 100644 (file)
@@ -388,12 +388,12 @@ Device Sequence Numbers
 U-Boot numbers devices from 0 in many situations, such as in the command
 line for I2C and SPI buses, and the device names for serial ports (serial0,
 serial1, ...). Driver model supports this numbering and permits devices
-to be locating by their 'sequence'. This numbering unique identifies a
+to be locating by their 'sequence'. This numbering uniquely identifies a
 device in its uclass, so no two devices within a particular uclass can have
 the same sequence number.
 
 Sequence numbers start from 0 but gaps are permitted. For example, a board
-may have I2C buses 0, 1, 4, 5 but no 2 or 3. The choice of how devices are
+may have I2C buses 1, 4, 5 but no 0, 2 or 3. The choice of how devices are
 numbered is up to a particular board, and may be set by the SoC in some
 cases. While it might be tempting to automatically renumber the devices
 where there are gaps in the sequence, this can lead to confusion and is
@@ -403,7 +403,7 @@ Each device can request a sequence number. If none is required then the
 device will be automatically allocated the next available sequence number.
 
 To specify the sequence number in the device tree an alias is typically
-used.
+used. Make sure that the uclass has the DM_UC_FLAG_SEQ_ALIAS flag set.
 
 aliases {
        serial2 = "/serial@22230000";
@@ -413,43 +413,18 @@ This indicates that in the uclass called "serial", the named node
 ("/serial@22230000") will be given sequence number 2. Any command or driver
 which requests serial device 2 will obtain this device.
 
-Some devices represent buses where the devices on the bus are numbered or
-addressed. For example, SPI typically numbers its slaves from 0, and I2C
-uses a 7-bit address. In these cases the 'reg' property of the subnode is
-used, for example:
+More commonly you can use node references, which expand to the full path:
 
-{
-       aliases {
-               spi2 = "/spi@22300000";
-       };
-
-       spi@22300000 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               spi-flash@0 {
-                       reg = <0>;
-                       ...
-               }
-               eeprom@1 {
-                       reg = <1>;
-               };
-       };
-
-In this case we have a SPI bus with two slaves at 0 and 1. The SPI bus
-itself is numbered 2. So we might access the SPI flash with:
-
-       sf probe 2:0
-
-and the eeprom with
-
-       sspi 2:1 32 ef
-
-These commands simply need to look up the 2nd device in the SPI uclass to
-find the right SPI bus. Then, they look at the children of that bus for the
-right sequence number (0 or 1 in this case).
+aliases {
+       serial2 = &serial_2;
+};
+...
+serial_2: serial@22230000 {
+...
+};
 
-Typically the alias method is used for top-level nodes and the 'reg' method
-is used only for buses.
+The alias resolves to the same string in this case, but this version is
+easier to read.
 
 Device sequence numbers are resolved when a device is probed. Before then
 the sequence number is only a request which may or may not be honoured,
index 2606d18717782be09f0116bfe5fb624bde84cd5d..f78b78a299edfdcefb1fe0e2a6f71b2fc9363a60 100644 (file)
@@ -53,24 +53,22 @@ int device_bind(struct udevice *parent, struct driver *drv, const char *name,
        dev->driver = drv;
        dev->uclass = uc;
 
-       /*
-        * For some devices, such as a SPI or I2C bus, the 'reg' property
-        * is a reasonable indicator of the sequence number. But if there is
-        * an alias, we use that in preference. In any case, this is just
-        * a 'requested' sequence, and will be resolved (and ->seq updated)
-        * when the device is probed.
-        */
        dev->seq = -1;
+       dev->req_seq = -1;
 #ifdef CONFIG_OF_CONTROL
-       dev->req_seq = fdtdec_get_int(gd->fdt_blob, of_offset, "reg", -1);
-       if (!IS_ERR_VALUE(dev->req_seq))
-               dev->req_seq &= INT_MAX;
-       if (uc->uc_drv->name && of_offset != -1) {
-               fdtdec_get_alias_seq(gd->fdt_blob, uc->uc_drv->name, of_offset,
-                                    &dev->req_seq);
+       /*
+        * Some devices, such as a SPI bus, I2C bus and serial ports are
+        * numbered using aliases.
+        *
+        * This is just a 'requested' sequence, and will be
+        * resolved (and ->seq updated) when the device is probed.
+        */
+       if (uc->uc_drv->flags & DM_UC_FLAG_SEQ_ALIAS) {
+               if (uc->uc_drv->name && of_offset != -1) {
+                       fdtdec_get_alias_seq(gd->fdt_blob, uc->uc_drv->name,
+                                            of_offset, &dev->req_seq);
+               }
        }
-#else
-       dev->req_seq = -1;
 #endif
        if (!dev->platdata && drv->platdata_auto_alloc_size) {
                dev->flags |= DM_FLAG_ALLOC_PDATA;
index 24e5ec68f2b4207d22ebaeb20a9e7e99d112d838..94b49dfe52beed7b225dcc7d2b5bb505e9326a20 100644 (file)
@@ -453,6 +453,7 @@ int i2c_post_bind(struct udevice *dev)
 UCLASS_DRIVER(i2c) = {
        .id             = UCLASS_I2C,
        .name           = "i2c",
+       .flags          = DM_UC_FLAG_SEQ_ALIAS,
        .per_device_auto_alloc_size = sizeof(struct dm_i2c_bus),
        .post_bind      = i2c_post_bind,
        .post_probe     = i2c_post_probe,
index d1b5777cecda13be6191404cefe6dcf82a92f564..9131a8f93d9a5adff359d2940ddfd6a6a05c445e 100644 (file)
@@ -297,6 +297,7 @@ static int serial_pre_remove(struct udevice *dev)
 UCLASS_DRIVER(serial) = {
        .id             = UCLASS_SERIAL,
        .name           = "serial",
+       .flags          = DM_UC_FLAG_SEQ_ALIAS,
        .post_probe     = serial_post_probe,
        .pre_remove     = serial_pre_remove,
        .per_device_auto_alloc_size = sizeof(struct serial_dev_priv),
index 7a57bceb260f1c3e79fc9ed4d735f1b27c45160b..35756ad784e94d5e01d47b06311622d83d8f2ec7 100644 (file)
@@ -344,6 +344,7 @@ int spi_ofdata_to_platdata(const void *blob, int node,
 UCLASS_DRIVER(spi) = {
        .id             = UCLASS_SPI,
        .name           = "spi",
+       .flags          = DM_UC_FLAG_SEQ_ALIAS,
        .post_bind      = spi_post_bind,
        .post_probe     = spi_post_probe,
        .per_device_auto_alloc_size = sizeof(struct dm_spi_bus),
index 7d92d34bec0cd55c1e612aff45dd9dc935362a26..9000b22c38de9a263646a992932adb61b16e1496 100644 (file)
@@ -40,6 +40,9 @@ struct uclass {
 
 struct udevice;
 
+/* Members of this uclass sequence themselves with aliases */
+#define DM_UC_FLAG_SEQ_ALIAS                   (1 << 0)
+
 /**
  * struct uclass_driver - Driver for the uclass
  *
@@ -66,6 +69,7 @@ struct udevice;
  * a falback if this member is 0 in the driver.
  * @ops: Uclass operations, providing the consistent interface to devices
  * within the uclass.
+ * @flags: Flags for this uclass (DM_UC_...)
  */
 struct uclass_driver {
        const char *name;
@@ -80,6 +84,7 @@ struct uclass_driver {
        int per_device_auto_alloc_size;
        int per_child_platdata_auto_alloc_size;
        const void *ops;
+       uint32_t flags;
 };
 
 /* Declare a new uclass_driver */
index e18a6f724999e8011993b3e4155a76344f5b971e..972c44979084f5e765cc227f1d400f5f8ea2986b 100644 (file)
@@ -88,12 +88,13 @@ U_BOOT_DRIVER(testbus_drv) = {
 UCLASS_DRIVER(testbus) = {
        .name           = "testbus",
        .id             = UCLASS_TEST_BUS,
+       .flags          = DM_UC_FLAG_SEQ_ALIAS,
 };
 
 /* Test that we can probe for children */
 static int dm_test_bus_children(struct dm_test_state *dms)
 {
-       int num_devices = 4;
+       int num_devices = 6;
        struct udevice *bus;
        struct uclass *uc;
 
index dc4ebf9adaf90e4aecc0848c3af9f873d5d8e911..dfcb3af61bbf20e6c966a56f1abd2d1dcc412fa9 100644 (file)
@@ -89,6 +89,7 @@ int testfdt_ping(struct udevice *dev, int pingval, int *pingret)
 UCLASS_DRIVER(testfdt) = {
        .name           = "testfdt",
        .id             = UCLASS_TEST_FDT,
+       .flags          = DM_UC_FLAG_SEQ_ALIAS,
 };
 
 int dm_check_devices(struct dm_test_state *dms, int num_devices)
@@ -128,7 +129,7 @@ int dm_check_devices(struct dm_test_state *dms, int num_devices)
 /* Test that FDT-based binding works correctly */
 static int dm_test_fdt(struct dm_test_state *dms)
 {
-       const int num_devices = 4;
+       const int num_devices = 6;
        struct udevice *dev;
        struct uclass *uc;
        int ret;
@@ -184,7 +185,7 @@ static int dm_test_fdt_uclass_seq(struct dm_test_state *dms)
        ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_FDT, 3, true, &dev));
        ut_asserteq_str("b-test", dev->name);
 
-       ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_FDT, 0, true, &dev));
+       ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_FDT, 8, true, &dev));
        ut_asserteq_str("a-test", dev->name);
 
        ut_asserteq(-ENODEV, uclass_find_device_by_seq(UCLASS_TEST_FDT, 5,
@@ -220,11 +221,11 @@ static int dm_test_fdt_uclass_seq(struct dm_test_state *dms)
        ut_asserteq(-ENODEV, uclass_get_device_by_seq(UCLASS_TEST_FDT, 1,
                                                      &dev));
        ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev));
-       ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 1, &dev));
+       ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 4, &dev));
 
        /* But now that it is probed, we can find it */
        ut_assertok(uclass_get_device_by_seq(UCLASS_TEST_FDT, 1, &dev));
-       ut_asserteq_str("a-test", dev->name);
+       ut_asserteq_str("f-test", dev->name);
 
        return 0;
 }
index 33f2c00747d86fa61b5beefca6a11a8179570bfe..84024a44a3f0368c5cea2e983a02d25465969482 100644 (file)
@@ -8,7 +8,15 @@
 
        aliases {
                console = &uart0;
+               i2c0 = "/i2c@0";
+               spi0 = "/spi@0";
                testfdt6 = "/e-test";
+               testbus3 = "/some-bus";
+               testfdt0 = "/some-bus/c-test@0";
+               testfdt1 = "/some-bus/c-test@1";
+               testfdt3 = "/b-test";
+               testfdt5 = "/some-bus/c-test@5";
+               testfdt8 = "/a-test";
        };
 
        uart0: serial {
                compatible = "google,another-fdt-test";
        };
 
+       f-test {
+               compatible = "denx,u-boot-fdt-test";
+       };
+
+       g-test {
+               compatible = "denx,u-boot-fdt-test";
+       };
+
        gpio_a: base-gpios {
                compatible = "sandbox,gpio";
                gpio-controller;