xref: /openbmc/u-boot/drivers/core/lists.c (revision 6a6d8fbe)
16494d708SSimon Glass /*
26494d708SSimon Glass  * Copyright (c) 2013 Google, Inc
36494d708SSimon Glass  *
46494d708SSimon Glass  * (C) Copyright 2012
56494d708SSimon Glass  * Marek Vasut <marex@denx.de>
66494d708SSimon Glass  *
76494d708SSimon Glass  * SPDX-License-Identifier:	GPL-2.0+
86494d708SSimon Glass  */
96494d708SSimon Glass 
106494d708SSimon Glass #include <common.h>
116494d708SSimon Glass #include <errno.h>
126494d708SSimon Glass #include <dm/device.h>
136494d708SSimon Glass #include <dm/device-internal.h>
146494d708SSimon Glass #include <dm/platdata.h>
156494d708SSimon Glass #include <dm/uclass.h>
166494d708SSimon Glass #include <dm/util.h>
17*6a6d8fbeSSimon Glass #include <fdtdec.h>
186494d708SSimon Glass #include <linux/compiler.h>
196494d708SSimon Glass 
206494d708SSimon Glass struct driver *lists_driver_lookup_name(const char *name)
216494d708SSimon Glass {
226494d708SSimon Glass 	struct driver *drv =
236494d708SSimon Glass 		ll_entry_start(struct driver, driver);
246494d708SSimon Glass 	const int n_ents = ll_entry_count(struct driver, driver);
256494d708SSimon Glass 	struct driver *entry;
266494d708SSimon Glass 	int len;
276494d708SSimon Glass 
286494d708SSimon Glass 	if (!drv || !n_ents)
296494d708SSimon Glass 		return NULL;
306494d708SSimon Glass 
316494d708SSimon Glass 	len = strlen(name);
326494d708SSimon Glass 
336494d708SSimon Glass 	for (entry = drv; entry != drv + n_ents; entry++) {
346494d708SSimon Glass 		if (strncmp(name, entry->name, len))
356494d708SSimon Glass 			continue;
366494d708SSimon Glass 
376494d708SSimon Glass 		/* Full match */
386494d708SSimon Glass 		if (len == strlen(entry->name))
396494d708SSimon Glass 			return entry;
406494d708SSimon Glass 	}
416494d708SSimon Glass 
426494d708SSimon Glass 	/* Not found */
436494d708SSimon Glass 	return NULL;
446494d708SSimon Glass }
456494d708SSimon Glass 
466494d708SSimon Glass struct uclass_driver *lists_uclass_lookup(enum uclass_id id)
476494d708SSimon Glass {
486494d708SSimon Glass 	struct uclass_driver *uclass =
496494d708SSimon Glass 		ll_entry_start(struct uclass_driver, uclass);
506494d708SSimon Glass 	const int n_ents = ll_entry_count(struct uclass_driver, uclass);
516494d708SSimon Glass 	struct uclass_driver *entry;
526494d708SSimon Glass 
536494d708SSimon Glass 	if ((id == UCLASS_INVALID) || !uclass)
546494d708SSimon Glass 		return NULL;
556494d708SSimon Glass 
566494d708SSimon Glass 	for (entry = uclass; entry != uclass + n_ents; entry++) {
576494d708SSimon Glass 		if (entry->id == id)
586494d708SSimon Glass 			return entry;
596494d708SSimon Glass 	}
606494d708SSimon Glass 
616494d708SSimon Glass 	return NULL;
626494d708SSimon Glass }
636494d708SSimon Glass 
6454c5d08aSHeiko Schocher int lists_bind_drivers(struct udevice *parent)
656494d708SSimon Glass {
666494d708SSimon Glass 	struct driver_info *info =
676494d708SSimon Glass 		ll_entry_start(struct driver_info, driver_info);
686494d708SSimon Glass 	const int n_ents = ll_entry_count(struct driver_info, driver_info);
696494d708SSimon Glass 	struct driver_info *entry;
7054c5d08aSHeiko Schocher 	struct udevice *dev;
716494d708SSimon Glass 	int result = 0;
726494d708SSimon Glass 	int ret;
736494d708SSimon Glass 
746494d708SSimon Glass 	for (entry = info; entry != info + n_ents; entry++) {
756494d708SSimon Glass 		ret = device_bind_by_name(parent, entry, &dev);
766494d708SSimon Glass 		if (ret) {
776494d708SSimon Glass 			dm_warn("No match for driver '%s'\n", entry->name);
786494d708SSimon Glass 			if (!result || ret != -ENOENT)
796494d708SSimon Glass 				result = ret;
806494d708SSimon Glass 		}
816494d708SSimon Glass 	}
826494d708SSimon Glass 
836494d708SSimon Glass 	return result;
846494d708SSimon Glass }
856494d708SSimon Glass 
866494d708SSimon Glass #ifdef CONFIG_OF_CONTROL
876494d708SSimon Glass /**
886494d708SSimon Glass  * driver_check_compatible() - Check if a driver is compatible with this node
896494d708SSimon Glass  *
906494d708SSimon Glass  * @param blob:		Device tree pointer
916494d708SSimon Glass  * @param offset:	Offset of node in device tree
926494d708SSimon Glass  * @param of_matchL	List of compatible strings to match
936494d708SSimon Glass  * @return 0 if there is a match, -ENOENT if no match, -ENODEV if the node
946494d708SSimon Glass  * does not have a compatible string, other error <0 if there is a device
956494d708SSimon Glass  * tree error
966494d708SSimon Glass  */
976494d708SSimon Glass static int driver_check_compatible(const void *blob, int offset,
98ae7f4513SSimon Glass 				   const struct udevice_id *of_match)
996494d708SSimon Glass {
1006494d708SSimon Glass 	int ret;
1016494d708SSimon Glass 
1026494d708SSimon Glass 	if (!of_match)
1036494d708SSimon Glass 		return -ENOENT;
1046494d708SSimon Glass 
1056494d708SSimon Glass 	while (of_match->compatible) {
1066494d708SSimon Glass 		ret = fdt_node_check_compatible(blob, offset,
1076494d708SSimon Glass 						of_match->compatible);
1086494d708SSimon Glass 		if (!ret)
1096494d708SSimon Glass 			return 0;
1106494d708SSimon Glass 		else if (ret == -FDT_ERR_NOTFOUND)
1116494d708SSimon Glass 			return -ENODEV;
1126494d708SSimon Glass 		else if (ret < 0)
1136494d708SSimon Glass 			return -EINVAL;
1146494d708SSimon Glass 		of_match++;
1156494d708SSimon Glass 	}
1166494d708SSimon Glass 
1176494d708SSimon Glass 	return -ENOENT;
1186494d708SSimon Glass }
1196494d708SSimon Glass 
12054c5d08aSHeiko Schocher int lists_bind_fdt(struct udevice *parent, const void *blob, int offset)
1216494d708SSimon Glass {
1226494d708SSimon Glass 	struct driver *driver = ll_entry_start(struct driver, driver);
1236494d708SSimon Glass 	const int n_ents = ll_entry_count(struct driver, driver);
1246494d708SSimon Glass 	struct driver *entry;
12554c5d08aSHeiko Schocher 	struct udevice *dev;
1266494d708SSimon Glass 	const char *name;
1276494d708SSimon Glass 	int result = 0;
1286494d708SSimon Glass 	int ret;
1296494d708SSimon Glass 
1306494d708SSimon Glass 	dm_dbg("bind node %s\n", fdt_get_name(blob, offset, NULL));
1316494d708SSimon Glass 	for (entry = driver; entry != driver + n_ents; entry++) {
1326494d708SSimon Glass 		ret = driver_check_compatible(blob, offset, entry->of_match);
1336494d708SSimon Glass 		if (ret == -ENOENT) {
1346494d708SSimon Glass 			continue;
1356494d708SSimon Glass 		} else if (ret == -ENODEV) {
1366494d708SSimon Glass 			break;
1376494d708SSimon Glass 		} else if (ret) {
1386494d708SSimon Glass 			dm_warn("Device tree error at offset %d\n", offset);
1396494d708SSimon Glass 			if (!result || ret != -ENOENT)
1406494d708SSimon Glass 				result = ret;
1416494d708SSimon Glass 			break;
1426494d708SSimon Glass 		}
1436494d708SSimon Glass 
1446494d708SSimon Glass 		name = fdt_get_name(blob, offset, NULL);
1456494d708SSimon Glass 		dm_dbg("   - found match at '%s'\n", entry->name);
1466494d708SSimon Glass 		ret = device_bind(parent, entry, name, NULL, offset, &dev);
1476494d708SSimon Glass 		if (ret) {
1486494d708SSimon Glass 			dm_warn("No match for driver '%s'\n", entry->name);
1496494d708SSimon Glass 			if (!result || ret != -ENOENT)
1506494d708SSimon Glass 				result = ret;
1516494d708SSimon Glass 		}
1526494d708SSimon Glass 	}
1536494d708SSimon Glass 
1546494d708SSimon Glass 	return result;
1556494d708SSimon Glass }
1566494d708SSimon Glass #endif
157