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