]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - test/dm/bus.c
Merge branch 'master' of git://git.denx.de/u-boot-imx
[karo-tx-uboot.git] / test / dm / bus.c
1 /*
2  * Copyright (c) 2014 Google, Inc
3  *
4  * SPDX-License-Identifier:     GPL-2.0+
5  */
6
7 #include <common.h>
8 #include <dm.h>
9 #include <dm/device-internal.h>
10 #include <dm/root.h>
11 #include <dm/test.h>
12 #include <dm/ut.h>
13 #include <dm/util.h>
14
15 DECLARE_GLOBAL_DATA_PTR;
16
17 enum {
18         FLAG_CHILD_PROBED       = 10,
19         FLAG_CHILD_REMOVED      = -7,
20 };
21
22 static struct dm_test_state *test_state;
23
24 static int testbus_drv_probe(struct udevice *dev)
25 {
26         return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
27 }
28
29 static int testbus_child_pre_probe(struct udevice *dev)
30 {
31         struct dm_test_parent_data *parent_data = dev_get_parentdata(dev);
32
33         parent_data->flag += FLAG_CHILD_PROBED;
34
35         return 0;
36 }
37
38 static int testbus_child_post_remove(struct udevice *dev)
39 {
40         struct dm_test_parent_data *parent_data = dev_get_parentdata(dev);
41         struct dm_test_state *dms = test_state;
42
43         parent_data->flag += FLAG_CHILD_REMOVED;
44         if (dms)
45                 dms->removed = dev;
46
47         return 0;
48 }
49
50 static const struct udevice_id testbus_ids[] = {
51         {
52                 .compatible = "denx,u-boot-test-bus",
53                 .data = DM_TEST_TYPE_FIRST },
54         { }
55 };
56
57 U_BOOT_DRIVER(testbus_drv) = {
58         .name   = "testbus_drv",
59         .of_match       = testbus_ids,
60         .id     = UCLASS_TEST_BUS,
61         .probe  = testbus_drv_probe,
62         .priv_auto_alloc_size = sizeof(struct dm_test_priv),
63         .platdata_auto_alloc_size = sizeof(struct dm_test_pdata),
64         .per_child_auto_alloc_size = sizeof(struct dm_test_parent_data),
65         .child_pre_probe = testbus_child_pre_probe,
66         .child_post_remove = testbus_child_post_remove,
67 };
68
69 UCLASS_DRIVER(testbus) = {
70         .name           = "testbus",
71         .id             = UCLASS_TEST_BUS,
72 };
73
74 /* Test that we can probe for children */
75 static int dm_test_bus_children(struct dm_test_state *dms)
76 {
77         int num_devices = 4;
78         struct udevice *bus;
79         struct uclass *uc;
80
81         ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
82         ut_asserteq(num_devices, list_count_items(&uc->dev_head));
83
84         /* Probe the bus, which should yield 3 more devices */
85         ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
86         num_devices += 3;
87
88         ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
89         ut_asserteq(num_devices, list_count_items(&uc->dev_head));
90
91         ut_assert(!dm_check_devices(dms, num_devices));
92
93         return 0;
94 }
95 DM_TEST(dm_test_bus_children, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
96
97 /* Test our functions for accessing children */
98 static int dm_test_bus_children_funcs(struct dm_test_state *dms)
99 {
100         const void *blob = gd->fdt_blob;
101         struct udevice *bus, *dev;
102         int node;
103
104         ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
105
106         /* device_get_child() */
107         ut_assertok(device_get_child(bus, 0, &dev));
108         ut_asserteq(-ENODEV, device_get_child(bus, 4, &dev));
109         ut_assertok(device_get_child_by_seq(bus, 5, &dev));
110         ut_assert(dev->flags & DM_FLAG_ACTIVATED);
111         ut_asserteq_str("c-test@5", dev->name);
112
113         /* Device with sequence number 0 should be accessible */
114         ut_asserteq(-ENODEV, device_find_child_by_seq(bus, -1, true, &dev));
115         ut_assertok(device_find_child_by_seq(bus, 0, true, &dev));
116         ut_assert(!(dev->flags & DM_FLAG_ACTIVATED));
117         ut_asserteq(-ENODEV, device_find_child_by_seq(bus, 0, false, &dev));
118         ut_assertok(device_get_child_by_seq(bus, 0, &dev));
119         ut_assert(dev->flags & DM_FLAG_ACTIVATED);
120
121         /* There is no device with sequence number 2 */
122         ut_asserteq(-ENODEV, device_find_child_by_seq(bus, 2, false, &dev));
123         ut_asserteq(-ENODEV, device_find_child_by_seq(bus, 2, true, &dev));
124         ut_asserteq(-ENODEV, device_get_child_by_seq(bus, 2, &dev));
125
126         /* Looking for something that is not a child */
127         node = fdt_path_offset(blob, "/junk");
128         ut_asserteq(-ENODEV, device_find_child_by_of_offset(bus, node, &dev));
129         node = fdt_path_offset(blob, "/d-test");
130         ut_asserteq(-ENODEV, device_find_child_by_of_offset(bus, node, &dev));
131
132         /* Find a valid child */
133         node = fdt_path_offset(blob, "/some-bus/c-test@1");
134         ut_assertok(device_find_child_by_of_offset(bus, node, &dev));
135         ut_assert(!(dev->flags & DM_FLAG_ACTIVATED));
136         ut_assertok(device_get_child_by_of_offset(bus, node, &dev));
137         ut_assert(dev->flags & DM_FLAG_ACTIVATED);
138
139         return 0;
140 }
141 DM_TEST(dm_test_bus_children_funcs, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
142
143 /* Test that we can iterate through children */
144 static int dm_test_bus_children_iterators(struct dm_test_state *dms)
145 {
146         struct udevice *bus, *dev, *child;
147
148         /* Walk through the children one by one */
149         ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
150         ut_assertok(device_find_first_child(bus, &dev));
151         ut_asserteq_str("c-test@5", dev->name);
152         ut_assertok(device_find_next_child(&dev));
153         ut_asserteq_str("c-test@0", dev->name);
154         ut_assertok(device_find_next_child(&dev));
155         ut_asserteq_str("c-test@1", dev->name);
156         ut_assertok(device_find_next_child(&dev));
157         ut_asserteq_ptr(dev, NULL);
158
159         /* Move to the next child without using device_find_first_child() */
160         ut_assertok(device_find_child_by_seq(bus, 5, true, &dev));
161         ut_asserteq_str("c-test@5", dev->name);
162         ut_assertok(device_find_next_child(&dev));
163         ut_asserteq_str("c-test@0", dev->name);
164
165         /* Try a device with no children */
166         ut_assertok(device_find_first_child(dev, &child));
167         ut_asserteq_ptr(child, NULL);
168
169         return 0;
170 }
171 DM_TEST(dm_test_bus_children_iterators,
172         DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
173
174 /* Test that the bus can store data about each child */
175 static int dm_test_bus_parent_data(struct dm_test_state *dms)
176 {
177         struct dm_test_parent_data *parent_data;
178         struct udevice *bus, *dev;
179         struct uclass *uc;
180         int value;
181
182         ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
183
184         /* Check that parent data is allocated */
185         ut_assertok(device_find_child_by_seq(bus, 0, true, &dev));
186         ut_asserteq_ptr(NULL, dev_get_parentdata(dev));
187         ut_assertok(device_get_child_by_seq(bus, 0, &dev));
188         parent_data = dev_get_parentdata(dev);
189         ut_assert(NULL != parent_data);
190
191         /* Check that it starts at 0 and goes away when device is removed */
192         parent_data->sum += 5;
193         ut_asserteq(5, parent_data->sum);
194         device_remove(dev);
195         ut_asserteq_ptr(NULL, dev_get_parentdata(dev));
196
197         /* Check that we can do this twice */
198         ut_assertok(device_get_child_by_seq(bus, 0, &dev));
199         parent_data = dev_get_parentdata(dev);
200         ut_assert(NULL != parent_data);
201         parent_data->sum += 5;
202         ut_asserteq(5, parent_data->sum);
203
204         /* Add parent data to all children */
205         ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
206         value = 5;
207         uclass_foreach_dev(dev, uc) {
208                 /* Ignore these if they are not on this bus */
209                 if (dev->parent != bus) {
210                         ut_asserteq_ptr(NULL, dev_get_parentdata(dev));
211                         continue;
212                 }
213                 ut_assertok(device_probe(dev));
214                 parent_data = dev_get_parentdata(dev);
215
216                 parent_data->sum = value;
217                 value += 5;
218         }
219
220         /* Check it is still there */
221         value = 5;
222         uclass_foreach_dev(dev, uc) {
223                 /* Ignore these if they are not on this bus */
224                 if (dev->parent != bus)
225                         continue;
226                 parent_data = dev_get_parentdata(dev);
227
228                 ut_asserteq(value, parent_data->sum);
229                 value += 5;
230         }
231
232         return 0;
233 }
234
235 DM_TEST(dm_test_bus_parent_data, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
236
237 /* Test that the bus ops are called when a child is probed/removed */
238 static int dm_test_bus_parent_ops(struct dm_test_state *dms)
239 {
240         struct dm_test_parent_data *parent_data;
241         struct udevice *bus, *dev;
242         struct uclass *uc;
243
244         test_state = dms;
245         ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
246         ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
247
248         uclass_foreach_dev(dev, uc) {
249                 /* Ignore these if they are not on this bus */
250                 if (dev->parent != bus)
251                         continue;
252                 ut_asserteq_ptr(NULL, dev_get_parentdata(dev));
253
254                 ut_assertok(device_probe(dev));
255                 parent_data = dev_get_parentdata(dev);
256                 ut_asserteq(FLAG_CHILD_PROBED, parent_data->flag);
257         }
258
259         uclass_foreach_dev(dev, uc) {
260                 /* Ignore these if they are not on this bus */
261                 if (dev->parent != bus)
262                         continue;
263                 parent_data = dev_get_parentdata(dev);
264                 ut_asserteq(FLAG_CHILD_PROBED, parent_data->flag);
265                 ut_assertok(device_remove(dev));
266                 ut_asserteq_ptr(NULL, dev_get_parentdata(dev));
267                 ut_asserteq_ptr(dms->removed, dev);
268         }
269         test_state = NULL;
270
271         return 0;
272 }
273 DM_TEST(dm_test_bus_parent_ops, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);