]>
Commit | Line | Data |
---|---|---|
6494d708 SG |
1 | /* |
2 | * Copyright (c) 2013 Google, Inc | |
3 | * | |
4 | * (C) Copyright 2012 | |
5 | * Marek Vasut <marex@denx.de> | |
6 | * | |
7 | * SPDX-License-Identifier: GPL-2.0+ | |
8 | */ | |
9 | ||
10 | #include <common.h> | |
11 | #include <errno.h> | |
12 | #include <dm/device.h> | |
13 | #include <dm/device-internal.h> | |
fd536d81 | 14 | #include <dm/lists.h> |
6494d708 SG |
15 | #include <dm/platdata.h> |
16 | #include <dm/uclass.h> | |
17 | #include <dm/util.h> | |
6a6d8fbe | 18 | #include <fdtdec.h> |
6494d708 SG |
19 | #include <linux/compiler.h> |
20 | ||
21 | struct driver *lists_driver_lookup_name(const char *name) | |
22 | { | |
23 | struct driver *drv = | |
24 | ll_entry_start(struct driver, driver); | |
25 | const int n_ents = ll_entry_count(struct driver, driver); | |
26 | struct driver *entry; | |
6494d708 | 27 | |
6494d708 | 28 | for (entry = drv; entry != drv + n_ents; entry++) { |
2cede453 | 29 | if (!strcmp(name, entry->name)) |
6494d708 SG |
30 | return entry; |
31 | } | |
32 | ||
33 | /* Not found */ | |
34 | return NULL; | |
35 | } | |
36 | ||
37 | struct uclass_driver *lists_uclass_lookup(enum uclass_id id) | |
38 | { | |
39 | struct uclass_driver *uclass = | |
40 | ll_entry_start(struct uclass_driver, uclass); | |
41 | const int n_ents = ll_entry_count(struct uclass_driver, uclass); | |
42 | struct uclass_driver *entry; | |
43 | ||
6494d708 SG |
44 | for (entry = uclass; entry != uclass + n_ents; entry++) { |
45 | if (entry->id == id) | |
46 | return entry; | |
47 | } | |
48 | ||
49 | return NULL; | |
50 | } | |
51 | ||
00606d7e | 52 | int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only) |
6494d708 SG |
53 | { |
54 | struct driver_info *info = | |
55 | ll_entry_start(struct driver_info, driver_info); | |
56 | const int n_ents = ll_entry_count(struct driver_info, driver_info); | |
57 | struct driver_info *entry; | |
54c5d08a | 58 | struct udevice *dev; |
6494d708 SG |
59 | int result = 0; |
60 | int ret; | |
61 | ||
62 | for (entry = info; entry != info + n_ents; entry++) { | |
00606d7e SG |
63 | ret = device_bind_by_name(parent, pre_reloc_only, entry, &dev); |
64 | if (ret && ret != -EPERM) { | |
6494d708 SG |
65 | dm_warn("No match for driver '%s'\n", entry->name); |
66 | if (!result || ret != -ENOENT) | |
67 | result = ret; | |
68 | } | |
69 | } | |
70 | ||
71 | return result; | |
72 | } | |
73 | ||
e33dc221 SG |
74 | int device_bind_driver(struct udevice *parent, const char *drv_name, |
75 | const char *dev_name, struct udevice **devp) | |
5b9000dd SG |
76 | { |
77 | return device_bind_driver_to_node(parent, drv_name, dev_name, -1, devp); | |
78 | } | |
79 | ||
80 | int device_bind_driver_to_node(struct udevice *parent, const char *drv_name, | |
81 | const char *dev_name, int node, | |
82 | struct udevice **devp) | |
e33dc221 SG |
83 | { |
84 | struct driver *drv; | |
85 | int ret; | |
86 | ||
87 | drv = lists_driver_lookup_name(drv_name); | |
88 | if (!drv) { | |
3039811e | 89 | debug("Cannot find driver '%s'\n", drv_name); |
e33dc221 SG |
90 | return -ENOENT; |
91 | } | |
5b9000dd | 92 | ret = device_bind(parent, drv, dev_name, NULL, node, devp); |
e33dc221 | 93 | if (ret) { |
3039811e SG |
94 | debug("Cannot create device named '%s' (err=%d)\n", |
95 | dev_name, ret); | |
e33dc221 SG |
96 | return ret; |
97 | } | |
98 | ||
99 | return 0; | |
100 | } | |
101 | ||
0f925822 | 102 | #if CONFIG_IS_ENABLED(OF_CONTROL) |
6494d708 SG |
103 | /** |
104 | * driver_check_compatible() - Check if a driver is compatible with this node | |
105 | * | |
106 | * @param blob: Device tree pointer | |
107 | * @param offset: Offset of node in device tree | |
2ef249b4 SG |
108 | * @param of_match: List of compatible strings to match |
109 | * @param of_idp: Returns the match that was found | |
6494d708 SG |
110 | * @return 0 if there is a match, -ENOENT if no match, -ENODEV if the node |
111 | * does not have a compatible string, other error <0 if there is a device | |
112 | * tree error | |
113 | */ | |
114 | static int driver_check_compatible(const void *blob, int offset, | |
2ef249b4 SG |
115 | const struct udevice_id *of_match, |
116 | const struct udevice_id **of_idp) | |
6494d708 SG |
117 | { |
118 | int ret; | |
119 | ||
2ef249b4 | 120 | *of_idp = NULL; |
6494d708 SG |
121 | if (!of_match) |
122 | return -ENOENT; | |
123 | ||
124 | while (of_match->compatible) { | |
125 | ret = fdt_node_check_compatible(blob, offset, | |
126 | of_match->compatible); | |
2ef249b4 SG |
127 | if (!ret) { |
128 | *of_idp = of_match; | |
6494d708 | 129 | return 0; |
2ef249b4 | 130 | } else if (ret == -FDT_ERR_NOTFOUND) { |
6494d708 | 131 | return -ENODEV; |
2ef249b4 | 132 | } else if (ret < 0) { |
6494d708 | 133 | return -EINVAL; |
2ef249b4 | 134 | } |
6494d708 SG |
135 | of_match++; |
136 | } | |
137 | ||
138 | return -ENOENT; | |
139 | } | |
140 | ||
1f359e36 SG |
141 | int lists_bind_fdt(struct udevice *parent, const void *blob, int offset, |
142 | struct udevice **devp) | |
6494d708 SG |
143 | { |
144 | struct driver *driver = ll_entry_start(struct driver, driver); | |
145 | const int n_ents = ll_entry_count(struct driver, driver); | |
2ef249b4 | 146 | const struct udevice_id *id; |
6494d708 | 147 | struct driver *entry; |
54c5d08a | 148 | struct udevice *dev; |
9b0ba067 | 149 | bool found = false; |
6494d708 SG |
150 | const char *name; |
151 | int result = 0; | |
9b0ba067 | 152 | int ret = 0; |
6494d708 SG |
153 | |
154 | dm_dbg("bind node %s\n", fdt_get_name(blob, offset, NULL)); | |
1f359e36 SG |
155 | if (devp) |
156 | *devp = NULL; | |
6494d708 | 157 | for (entry = driver; entry != driver + n_ents; entry++) { |
2ef249b4 SG |
158 | ret = driver_check_compatible(blob, offset, entry->of_match, |
159 | &id); | |
9b0ba067 | 160 | name = fdt_get_name(blob, offset, NULL); |
6494d708 SG |
161 | if (ret == -ENOENT) { |
162 | continue; | |
163 | } else if (ret == -ENODEV) { | |
9b0ba067 | 164 | dm_dbg("Device '%s' has no compatible string\n", name); |
6494d708 SG |
165 | break; |
166 | } else if (ret) { | |
167 | dm_warn("Device tree error at offset %d\n", offset); | |
84a71537 | 168 | result = ret; |
6494d708 SG |
169 | break; |
170 | } | |
171 | ||
6494d708 SG |
172 | dm_dbg(" - found match at '%s'\n", entry->name); |
173 | ret = device_bind(parent, entry, name, NULL, offset, &dev); | |
174 | if (ret) { | |
d062482b SG |
175 | dm_warn("Error binding driver '%s': %d\n", entry->name, |
176 | ret); | |
1f359e36 | 177 | return ret; |
9b0ba067 | 178 | } else { |
39de8433 | 179 | dev->driver_data = id->data; |
9b0ba067 | 180 | found = true; |
1f359e36 SG |
181 | if (devp) |
182 | *devp = dev; | |
6494d708 | 183 | } |
9b0ba067 SG |
184 | break; |
185 | } | |
186 | ||
187 | if (!found && !result && ret != -ENODEV) { | |
188 | dm_dbg("No match for node '%s'\n", | |
189 | fdt_get_name(blob, offset, NULL)); | |
6494d708 SG |
190 | } |
191 | ||
192 | return result; | |
193 | } | |
194 | #endif |