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 { 77*5b9000ddSSimon Glass return device_bind_driver_to_node(parent, drv_name, dev_name, -1, devp); 78*5b9000ddSSimon Glass } 79*5b9000ddSSimon Glass 80*5b9000ddSSimon Glass int device_bind_driver_to_node(struct udevice *parent, const char *drv_name, 81*5b9000ddSSimon Glass const char *dev_name, int node, 82*5b9000ddSSimon Glass struct udevice **devp) 83*5b9000ddSSimon 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) { 89e33dc221SSimon Glass printf("Cannot find driver '%s'\n", drv_name); 90e33dc221SSimon Glass return -ENOENT; 91e33dc221SSimon Glass } 92*5b9000ddSSimon Glass ret = device_bind(parent, drv, dev_name, NULL, node, devp); 93e33dc221SSimon Glass if (ret) { 94e33dc221SSimon Glass printf("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 1026494d708SSimon Glass #ifdef CONFIG_OF_CONTROL 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); 1736494d708SSimon Glass ret = device_bind(parent, entry, name, NULL, offset, &dev); 1746494d708SSimon Glass if (ret) { 1759b0ba067SSimon Glass dm_warn("Error binding driver '%s'\n", entry->name); 1761f359e36SSimon Glass return ret; 1779b0ba067SSimon Glass } else { 17839de8433SSimon Glass dev->driver_data = id->data; 1799b0ba067SSimon Glass found = true; 1801f359e36SSimon Glass if (devp) 1811f359e36SSimon Glass *devp = dev; 1826494d708SSimon Glass } 1839b0ba067SSimon Glass break; 1849b0ba067SSimon Glass } 1859b0ba067SSimon Glass 1869b0ba067SSimon Glass if (!found && !result && ret != -ENODEV) { 1879b0ba067SSimon Glass dm_dbg("No match for node '%s'\n", 1889b0ba067SSimon Glass fdt_get_name(blob, offset, NULL)); 1896494d708SSimon Glass } 1906494d708SSimon Glass 1916494d708SSimon Glass return result; 1926494d708SSimon Glass } 1936494d708SSimon Glass #endif 194