xref: /openbmc/u-boot/drivers/core/lists.c (revision 29629eb8)
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>
14fd536d81SJeroen Hofstee #include <dm/lists.h>
156494d708SSimon Glass #include <dm/platdata.h>
166494d708SSimon Glass #include <dm/uclass.h>
176494d708SSimon Glass #include <dm/util.h>
186a6d8fbeSSimon Glass #include <fdtdec.h>
196494d708SSimon Glass #include <linux/compiler.h>
206494d708SSimon Glass 
216494d708SSimon Glass struct driver *lists_driver_lookup_name(const char *name)
226494d708SSimon Glass {
236494d708SSimon Glass 	struct driver *drv =
246494d708SSimon Glass 		ll_entry_start(struct driver, driver);
256494d708SSimon Glass 	const int n_ents = ll_entry_count(struct driver, driver);
266494d708SSimon Glass 	struct driver *entry;
276494d708SSimon Glass 
286494d708SSimon Glass 	for (entry = drv; entry != drv + n_ents; entry++) {
292cede453SMasahiro Yamada 		if (!strcmp(name, entry->name))
306494d708SSimon Glass 			return entry;
316494d708SSimon Glass 	}
326494d708SSimon Glass 
336494d708SSimon Glass 	/* Not found */
346494d708SSimon Glass 	return NULL;
356494d708SSimon Glass }
366494d708SSimon Glass 
376494d708SSimon Glass struct uclass_driver *lists_uclass_lookup(enum uclass_id id)
386494d708SSimon Glass {
396494d708SSimon Glass 	struct uclass_driver *uclass =
406494d708SSimon Glass 		ll_entry_start(struct uclass_driver, uclass);
416494d708SSimon Glass 	const int n_ents = ll_entry_count(struct uclass_driver, uclass);
426494d708SSimon Glass 	struct uclass_driver *entry;
436494d708SSimon Glass 
446494d708SSimon Glass 	for (entry = uclass; entry != uclass + n_ents; entry++) {
456494d708SSimon Glass 		if (entry->id == id)
466494d708SSimon Glass 			return entry;
476494d708SSimon Glass 	}
486494d708SSimon Glass 
496494d708SSimon Glass 	return NULL;
506494d708SSimon Glass }
516494d708SSimon Glass 
5200606d7eSSimon Glass int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only)
536494d708SSimon Glass {
546494d708SSimon Glass 	struct driver_info *info =
556494d708SSimon Glass 		ll_entry_start(struct driver_info, driver_info);
566494d708SSimon Glass 	const int n_ents = ll_entry_count(struct driver_info, driver_info);
576494d708SSimon Glass 	struct driver_info *entry;
5854c5d08aSHeiko Schocher 	struct udevice *dev;
596494d708SSimon Glass 	int result = 0;
606494d708SSimon Glass 	int ret;
616494d708SSimon Glass 
626494d708SSimon Glass 	for (entry = info; entry != info + n_ents; entry++) {
6300606d7eSSimon Glass 		ret = device_bind_by_name(parent, pre_reloc_only, entry, &dev);
6400606d7eSSimon Glass 		if (ret && ret != -EPERM) {
656494d708SSimon Glass 			dm_warn("No match for driver '%s'\n", entry->name);
666494d708SSimon Glass 			if (!result || ret != -ENOENT)
676494d708SSimon Glass 				result = ret;
686494d708SSimon Glass 		}
696494d708SSimon Glass 	}
706494d708SSimon Glass 
716494d708SSimon Glass 	return result;
726494d708SSimon Glass }
736494d708SSimon Glass 
74e33dc221SSimon Glass int device_bind_driver(struct udevice *parent, const char *drv_name,
75e33dc221SSimon Glass 		       const char *dev_name, struct udevice **devp)
76e33dc221SSimon Glass {
775b9000ddSSimon Glass 	return device_bind_driver_to_node(parent, drv_name, dev_name, -1, devp);
785b9000ddSSimon Glass }
795b9000ddSSimon Glass 
805b9000ddSSimon Glass int device_bind_driver_to_node(struct udevice *parent, const char *drv_name,
815b9000ddSSimon Glass 			       const char *dev_name, int node,
825b9000ddSSimon Glass 			       struct udevice **devp)
835b9000ddSSimon Glass {
84e33dc221SSimon Glass 	struct driver *drv;
85e33dc221SSimon Glass 	int ret;
86e33dc221SSimon Glass 
87e33dc221SSimon Glass 	drv = lists_driver_lookup_name(drv_name);
88e33dc221SSimon Glass 	if (!drv) {
893039811eSSimon Glass 		debug("Cannot find driver '%s'\n", drv_name);
90e33dc221SSimon Glass 		return -ENOENT;
91e33dc221SSimon Glass 	}
925b9000ddSSimon Glass 	ret = device_bind(parent, drv, dev_name, NULL, node, devp);
93e33dc221SSimon Glass 	if (ret) {
943039811eSSimon Glass 		debug("Cannot create device named '%s' (err=%d)\n",
95e33dc221SSimon Glass 		      dev_name, ret);
96e33dc221SSimon Glass 		return ret;
97e33dc221SSimon Glass 	}
98e33dc221SSimon Glass 
99e33dc221SSimon Glass 	return 0;
100e33dc221SSimon Glass }
101e33dc221SSimon Glass 
102*29629eb8SSimon Glass #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
1036494d708SSimon Glass /**
1046494d708SSimon Glass  * driver_check_compatible() - Check if a driver is compatible with this node
1056494d708SSimon Glass  *
1066494d708SSimon Glass  * @param blob:		Device tree pointer
1076494d708SSimon Glass  * @param offset:	Offset of node in device tree
1082ef249b4SSimon Glass  * @param of_match:	List of compatible strings to match
1092ef249b4SSimon Glass  * @param of_idp:	Returns the match that was found
1106494d708SSimon Glass  * @return 0 if there is a match, -ENOENT if no match, -ENODEV if the node
1116494d708SSimon Glass  * does not have a compatible string, other error <0 if there is a device
1126494d708SSimon Glass  * tree error
1136494d708SSimon Glass  */
1146494d708SSimon Glass static int driver_check_compatible(const void *blob, int offset,
1152ef249b4SSimon Glass 				   const struct udevice_id *of_match,
1162ef249b4SSimon Glass 				   const struct udevice_id **of_idp)
1176494d708SSimon Glass {
1186494d708SSimon Glass 	int ret;
1196494d708SSimon Glass 
1202ef249b4SSimon Glass 	*of_idp = NULL;
1216494d708SSimon Glass 	if (!of_match)
1226494d708SSimon Glass 		return -ENOENT;
1236494d708SSimon Glass 
1246494d708SSimon Glass 	while (of_match->compatible) {
1256494d708SSimon Glass 		ret = fdt_node_check_compatible(blob, offset,
1266494d708SSimon Glass 						of_match->compatible);
1272ef249b4SSimon Glass 		if (!ret) {
1282ef249b4SSimon Glass 			*of_idp = of_match;
1296494d708SSimon Glass 			return 0;
1302ef249b4SSimon Glass 		} else if (ret == -FDT_ERR_NOTFOUND) {
1316494d708SSimon Glass 			return -ENODEV;
1322ef249b4SSimon Glass 		} else if (ret < 0) {
1336494d708SSimon Glass 			return -EINVAL;
1342ef249b4SSimon Glass 		}
1356494d708SSimon Glass 		of_match++;
1366494d708SSimon Glass 	}
1376494d708SSimon Glass 
1386494d708SSimon Glass 	return -ENOENT;
1396494d708SSimon Glass }
1406494d708SSimon Glass 
1411f359e36SSimon Glass int lists_bind_fdt(struct udevice *parent, const void *blob, int offset,
1421f359e36SSimon Glass 		   struct udevice **devp)
1436494d708SSimon Glass {
1446494d708SSimon Glass 	struct driver *driver = ll_entry_start(struct driver, driver);
1456494d708SSimon Glass 	const int n_ents = ll_entry_count(struct driver, driver);
1462ef249b4SSimon Glass 	const struct udevice_id *id;
1476494d708SSimon Glass 	struct driver *entry;
14854c5d08aSHeiko Schocher 	struct udevice *dev;
1499b0ba067SSimon Glass 	bool found = false;
1506494d708SSimon Glass 	const char *name;
1516494d708SSimon Glass 	int result = 0;
1529b0ba067SSimon Glass 	int ret = 0;
1536494d708SSimon Glass 
1546494d708SSimon Glass 	dm_dbg("bind node %s\n", fdt_get_name(blob, offset, NULL));
1551f359e36SSimon Glass 	if (devp)
1561f359e36SSimon Glass 		*devp = NULL;
1576494d708SSimon Glass 	for (entry = driver; entry != driver + n_ents; entry++) {
1582ef249b4SSimon Glass 		ret = driver_check_compatible(blob, offset, entry->of_match,
1592ef249b4SSimon Glass 					      &id);
1609b0ba067SSimon Glass 		name = fdt_get_name(blob, offset, NULL);
1616494d708SSimon Glass 		if (ret == -ENOENT) {
1626494d708SSimon Glass 			continue;
1636494d708SSimon Glass 		} else if (ret == -ENODEV) {
1649b0ba067SSimon Glass 			dm_dbg("Device '%s' has no compatible string\n", name);
1656494d708SSimon Glass 			break;
1666494d708SSimon Glass 		} else if (ret) {
1676494d708SSimon Glass 			dm_warn("Device tree error at offset %d\n", offset);
1686494d708SSimon Glass 			result = ret;
1696494d708SSimon Glass 			break;
1706494d708SSimon Glass 		}
1716494d708SSimon Glass 
1726494d708SSimon Glass 		dm_dbg("   - found match at '%s'\n", entry->name);
173daac3bfeSStephen Warren 		ret = device_bind_with_driver_data(parent, entry, name,
174daac3bfeSStephen Warren 						   id->data, offset, &dev);
1759fdfadf8SStephen Warren 		if (ret == -ENODEV) {
1769fdfadf8SStephen Warren 			dm_dbg("Driver '%s' refuses to bind\n", entry->name);
1779fdfadf8SStephen Warren 			continue;
1789fdfadf8SStephen Warren 		}
1796494d708SSimon Glass 		if (ret) {
180d062482bSSimon Glass 			dm_warn("Error binding driver '%s': %d\n", entry->name,
181d062482bSSimon Glass 				ret);
1821f359e36SSimon Glass 			return ret;
1839b0ba067SSimon Glass 		} else {
1849b0ba067SSimon Glass 			found = true;
1851f359e36SSimon Glass 			if (devp)
1861f359e36SSimon Glass 				*devp = dev;
1876494d708SSimon Glass 		}
1889b0ba067SSimon Glass 		break;
1899b0ba067SSimon Glass 	}
1909b0ba067SSimon Glass 
1919b0ba067SSimon Glass 	if (!found && !result && ret != -ENODEV) {
1929b0ba067SSimon Glass 		dm_dbg("No match for node '%s'\n",
1939b0ba067SSimon Glass 		       fdt_get_name(blob, offset, NULL));
1946494d708SSimon Glass 	}
1956494d708SSimon Glass 
1966494d708SSimon Glass 	return result;
1976494d708SSimon Glass }
1986494d708SSimon Glass #endif
199