1 /* 2 * Copyright (c) 2013 Google, Inc 3 * 4 * (C) Copyright 2012 5 * Pavel Herrmann <morpheus.ibis@gmail.com> 6 * 7 * SPDX-License-Identifier: GPL-2.0+ 8 */ 9 10 #include <common.h> 11 #include <errno.h> 12 #include <fdtdec.h> 13 #include <malloc.h> 14 #include <libfdt.h> 15 #include <dm/device.h> 16 #include <dm/device-internal.h> 17 #include <dm/lists.h> 18 #include <dm/platdata.h> 19 #include <dm/root.h> 20 #include <dm/uclass.h> 21 #include <dm/util.h> 22 #include <linux/list.h> 23 24 DECLARE_GLOBAL_DATA_PTR; 25 26 static const struct driver_info root_info = { 27 .name = "root_driver", 28 }; 29 30 struct udevice *dm_root(void) 31 { 32 if (!gd->dm_root) { 33 dm_warn("Virtual root driver does not exist!\n"); 34 return NULL; 35 } 36 37 return gd->dm_root; 38 } 39 40 int dm_init(void) 41 { 42 int ret; 43 44 if (gd->dm_root) { 45 dm_warn("Virtual root driver already exists!\n"); 46 return -EINVAL; 47 } 48 INIT_LIST_HEAD(&DM_UCLASS_ROOT_NON_CONST); 49 50 ret = device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST); 51 if (ret) 52 return ret; 53 #ifdef CONFIG_OF_CONTROL 54 DM_ROOT_NON_CONST->of_offset = 0; 55 #endif 56 ret = device_probe(DM_ROOT_NON_CONST); 57 if (ret) 58 return ret; 59 60 return 0; 61 } 62 63 int dm_uninit(void) 64 { 65 device_remove(dm_root()); 66 device_unbind(dm_root()); 67 68 return 0; 69 } 70 71 int dm_scan_platdata(bool pre_reloc_only) 72 { 73 int ret; 74 75 ret = lists_bind_drivers(DM_ROOT_NON_CONST, pre_reloc_only); 76 if (ret == -ENOENT) { 77 dm_warn("Some drivers were not found\n"); 78 ret = 0; 79 } 80 81 return ret; 82 } 83 84 #ifdef CONFIG_OF_CONTROL 85 int dm_scan_fdt_node(struct udevice *parent, const void *blob, int offset, 86 bool pre_reloc_only) 87 { 88 int ret = 0, err; 89 90 for (offset = fdt_first_subnode(blob, offset); 91 offset > 0; 92 offset = fdt_next_subnode(blob, offset)) { 93 if (pre_reloc_only && 94 !fdt_getprop(blob, offset, "u-boot,dm-pre-reloc", NULL)) 95 continue; 96 if (!fdtdec_get_is_enabled(blob, offset)) { 97 dm_dbg(" - ignoring disabled device\n"); 98 continue; 99 } 100 err = lists_bind_fdt(parent, blob, offset, NULL); 101 if (err && !ret) 102 ret = err; 103 } 104 105 if (ret) 106 dm_warn("Some drivers failed to bind\n"); 107 108 return ret; 109 } 110 111 int dm_scan_fdt(const void *blob, bool pre_reloc_only) 112 { 113 return dm_scan_fdt_node(gd->dm_root, blob, 0, pre_reloc_only); 114 } 115 #endif 116 117 __weak int dm_scan_other(bool pre_reloc_only) 118 { 119 return 0; 120 } 121 122 int dm_init_and_scan(bool pre_reloc_only) 123 { 124 int ret; 125 126 ret = dm_init(); 127 if (ret) { 128 debug("dm_init() failed: %d\n", ret); 129 return ret; 130 } 131 ret = dm_scan_platdata(pre_reloc_only); 132 if (ret) { 133 debug("dm_scan_platdata() failed: %d\n", ret); 134 return ret; 135 } 136 #ifdef CONFIG_OF_CONTROL 137 ret = dm_scan_fdt(gd->fdt_blob, pre_reloc_only); 138 if (ret) { 139 debug("dm_scan_fdt() failed: %d\n", ret); 140 return ret; 141 } 142 #endif 143 ret = dm_scan_other(pre_reloc_only); 144 if (ret) 145 return ret; 146 147 return 0; 148 } 149 150 /* This is the root driver - all drivers are children of this */ 151 U_BOOT_DRIVER(root_driver) = { 152 .name = "root_driver", 153 .id = UCLASS_ROOT, 154 }; 155 156 /* This is the root uclass */ 157 UCLASS_DRIVER(root) = { 158 .name = "root", 159 .id = UCLASS_ROOT, 160 }; 161