]> git.ipfire.org Git - people/ms/u-boot.git/blame - drivers/core/lists.c
arm64: zynqmp: Add reference to pmu firmware node
[people/ms/u-boot.git] / drivers / core / lists.c
CommitLineData
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
21struct 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
37struct 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 52int 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
74int device_bind_driver(struct udevice *parent, const char *drv_name,
75 const char *dev_name, struct udevice **devp)
5b9000dd 76{
45a26867
SG
77 return device_bind_driver_to_node(parent, drv_name, dev_name,
78 ofnode_null(), devp);
5b9000dd
SG
79}
80
81int device_bind_driver_to_node(struct udevice *parent, const char *drv_name,
45a26867 82 const char *dev_name, ofnode node,
5b9000dd 83 struct udevice **devp)
e33dc221
SG
84{
85 struct driver *drv;
86 int ret;
87
88 drv = lists_driver_lookup_name(drv_name);
89 if (!drv) {
3039811e 90 debug("Cannot find driver '%s'\n", drv_name);
e33dc221
SG
91 return -ENOENT;
92 }
45a26867
SG
93 ret = device_bind_with_driver_data(parent, drv, dev_name, 0 /* data */,
94 node, devp);
e33dc221 95
45a26867 96 return ret;
e33dc221
SG
97}
98
29629eb8 99#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
6494d708 100/**
ce701721 101 * driver_check_compatible() - Check if a driver matches a compatible string
6494d708 102 *
2ef249b4
SG
103 * @param of_match: List of compatible strings to match
104 * @param of_idp: Returns the match that was found
ce701721
PB
105 * @param compat: The compatible string to search for
106 * @return 0 if there is a match, -ENOENT if no match
6494d708 107 */
ce701721
PB
108static int driver_check_compatible(const struct udevice_id *of_match,
109 const struct udevice_id **of_idp,
110 const char *compat)
6494d708 111{
6494d708
SG
112 if (!of_match)
113 return -ENOENT;
114
115 while (of_match->compatible) {
ce701721 116 if (!strcmp(of_match->compatible, compat)) {
2ef249b4 117 *of_idp = of_match;
6494d708 118 return 0;
2ef249b4 119 }
6494d708
SG
120 of_match++;
121 }
122
123 return -ENOENT;
124}
125
f5b5719c 126int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp)
6494d708
SG
127{
128 struct driver *driver = ll_entry_start(struct driver, driver);
129 const int n_ents = ll_entry_count(struct driver, driver);
2ef249b4 130 const struct udevice_id *id;
6494d708 131 struct driver *entry;
54c5d08a 132 struct udevice *dev;
9b0ba067 133 bool found = false;
ce701721
PB
134 const char *name, *compat_list, *compat;
135 int compat_length, i;
6494d708 136 int result = 0;
9b0ba067 137 int ret = 0;
6494d708 138
1f359e36
SG
139 if (devp)
140 *devp = NULL;
f5b5719c 141 name = ofnode_get_name(node);
ceb91909 142 pr_debug("bind node %s\n", name);
ce701721 143
61e51bab 144 compat_list = ofnode_get_property(node, "compatible", &compat_length);
ce701721
PB
145 if (!compat_list) {
146 if (compat_length == -FDT_ERR_NOTFOUND) {
ceb91909
MY
147 pr_debug("Device '%s' has no compatible string\n",
148 name);
ce701721 149 return 0;
6494d708
SG
150 }
151
f5b5719c 152 dm_warn("Device tree error at node '%s'\n", name);
ce701721
PB
153 return compat_length;
154 }
155
156 /*
157 * Walk through the compatible string list, attempting to match each
158 * compatible string in order such that we match in order of priority
159 * from the first string to the last.
160 */
161 for (i = 0; i < compat_length; i += strlen(compat) + 1) {
162 compat = compat_list + i;
ceb91909
MY
163 pr_debug(" - attempt to match compatible string '%s'\n",
164 compat);
ce701721
PB
165
166 for (entry = driver; entry != driver + n_ents; entry++) {
167 ret = driver_check_compatible(entry->of_match, &id,
168 compat);
169 if (!ret)
170 break;
171 }
172 if (entry == driver + n_ents)
173 continue;
174
ceb91909 175 pr_debug(" - found match at '%s'\n", entry->name);
daac3bfe 176 ret = device_bind_with_driver_data(parent, entry, name,
f5b5719c 177 id->data, node, &dev);
9fdfadf8 178 if (ret == -ENODEV) {
ceb91909 179 pr_debug("Driver '%s' refuses to bind\n", entry->name);
9fdfadf8
SW
180 continue;
181 }
6494d708 182 if (ret) {
d062482b
SG
183 dm_warn("Error binding driver '%s': %d\n", entry->name,
184 ret);
1f359e36 185 return ret;
9b0ba067
SG
186 } else {
187 found = true;
1f359e36
SG
188 if (devp)
189 *devp = dev;
6494d708 190 }
9b0ba067
SG
191 break;
192 }
193
ce701721 194 if (!found && !result && ret != -ENODEV)
ceb91909 195 pr_debug("No match for node '%s'\n", name);
6494d708
SG
196
197 return result;
198}
199#endif