xref: /openbmc/u-boot/cmd/bind.c (revision a376702f)
1*49c752c9SJean-Jacques Hiblot // SPDX-License-Identifier: GPL-2.0+
2*49c752c9SJean-Jacques Hiblot /*
3*49c752c9SJean-Jacques Hiblot  * Copyright (c) 2018 JJ Hiblot <jjhiblot@ti.com>
4*49c752c9SJean-Jacques Hiblot  */
5*49c752c9SJean-Jacques Hiblot 
6*49c752c9SJean-Jacques Hiblot #include <common.h>
7*49c752c9SJean-Jacques Hiblot #include <dm.h>
8*49c752c9SJean-Jacques Hiblot #include <dm/device-internal.h>
9*49c752c9SJean-Jacques Hiblot #include <dm/lists.h>
10*49c752c9SJean-Jacques Hiblot #include <dm/uclass-internal.h>
11*49c752c9SJean-Jacques Hiblot 
bind_by_class_index(const char * uclass,int index,const char * drv_name)12*49c752c9SJean-Jacques Hiblot static int bind_by_class_index(const char *uclass, int index,
13*49c752c9SJean-Jacques Hiblot 			       const char *drv_name)
14*49c752c9SJean-Jacques Hiblot {
15*49c752c9SJean-Jacques Hiblot 	static enum uclass_id uclass_id;
16*49c752c9SJean-Jacques Hiblot 	struct udevice *dev;
17*49c752c9SJean-Jacques Hiblot 	struct udevice *parent;
18*49c752c9SJean-Jacques Hiblot 	int ret;
19*49c752c9SJean-Jacques Hiblot 	struct driver *drv;
20*49c752c9SJean-Jacques Hiblot 
21*49c752c9SJean-Jacques Hiblot 	drv = lists_driver_lookup_name(drv_name);
22*49c752c9SJean-Jacques Hiblot 	if (!drv) {
23*49c752c9SJean-Jacques Hiblot 		printf("Cannot find driver '%s'\n", drv_name);
24*49c752c9SJean-Jacques Hiblot 		return -ENOENT;
25*49c752c9SJean-Jacques Hiblot 	}
26*49c752c9SJean-Jacques Hiblot 
27*49c752c9SJean-Jacques Hiblot 	uclass_id = uclass_get_by_name(uclass);
28*49c752c9SJean-Jacques Hiblot 	if (uclass_id == UCLASS_INVALID) {
29*49c752c9SJean-Jacques Hiblot 		printf("%s is not a valid uclass\n", uclass);
30*49c752c9SJean-Jacques Hiblot 		return -EINVAL;
31*49c752c9SJean-Jacques Hiblot 	}
32*49c752c9SJean-Jacques Hiblot 
33*49c752c9SJean-Jacques Hiblot 	ret = uclass_find_device(uclass_id, index, &parent);
34*49c752c9SJean-Jacques Hiblot 	if (!parent || ret) {
35*49c752c9SJean-Jacques Hiblot 		printf("Cannot find device %d of class %s\n", index, uclass);
36*49c752c9SJean-Jacques Hiblot 		return ret;
37*49c752c9SJean-Jacques Hiblot 	}
38*49c752c9SJean-Jacques Hiblot 
39*49c752c9SJean-Jacques Hiblot 	ret = device_bind_with_driver_data(parent, drv, drv->name, 0,
40*49c752c9SJean-Jacques Hiblot 					   ofnode_null(), &dev);
41*49c752c9SJean-Jacques Hiblot 	if (!dev || ret) {
42*49c752c9SJean-Jacques Hiblot 		printf("Unable to bind. err:%d\n", ret);
43*49c752c9SJean-Jacques Hiblot 		return ret;
44*49c752c9SJean-Jacques Hiblot 	}
45*49c752c9SJean-Jacques Hiblot 
46*49c752c9SJean-Jacques Hiblot 	return 0;
47*49c752c9SJean-Jacques Hiblot }
48*49c752c9SJean-Jacques Hiblot 
find_dev(const char * uclass,int index,struct udevice ** devp)49*49c752c9SJean-Jacques Hiblot static int find_dev(const char *uclass, int index, struct udevice **devp)
50*49c752c9SJean-Jacques Hiblot {
51*49c752c9SJean-Jacques Hiblot 	static enum uclass_id uclass_id;
52*49c752c9SJean-Jacques Hiblot 	int rc;
53*49c752c9SJean-Jacques Hiblot 
54*49c752c9SJean-Jacques Hiblot 	uclass_id = uclass_get_by_name(uclass);
55*49c752c9SJean-Jacques Hiblot 	if (uclass_id == UCLASS_INVALID) {
56*49c752c9SJean-Jacques Hiblot 		printf("%s is not a valid uclass\n", uclass);
57*49c752c9SJean-Jacques Hiblot 		return -EINVAL;
58*49c752c9SJean-Jacques Hiblot 	}
59*49c752c9SJean-Jacques Hiblot 
60*49c752c9SJean-Jacques Hiblot 	rc = uclass_find_device(uclass_id, index, devp);
61*49c752c9SJean-Jacques Hiblot 	if (!*devp || rc) {
62*49c752c9SJean-Jacques Hiblot 		printf("Cannot find device %d of class %s\n", index, uclass);
63*49c752c9SJean-Jacques Hiblot 		return rc;
64*49c752c9SJean-Jacques Hiblot 	}
65*49c752c9SJean-Jacques Hiblot 
66*49c752c9SJean-Jacques Hiblot 	return 0;
67*49c752c9SJean-Jacques Hiblot }
68*49c752c9SJean-Jacques Hiblot 
unbind_by_class_index(const char * uclass,int index)69*49c752c9SJean-Jacques Hiblot static int unbind_by_class_index(const char *uclass, int index)
70*49c752c9SJean-Jacques Hiblot {
71*49c752c9SJean-Jacques Hiblot 	int ret;
72*49c752c9SJean-Jacques Hiblot 	struct udevice *dev;
73*49c752c9SJean-Jacques Hiblot 
74*49c752c9SJean-Jacques Hiblot 	ret = find_dev(uclass, index, &dev);
75*49c752c9SJean-Jacques Hiblot 	if (ret)
76*49c752c9SJean-Jacques Hiblot 		return ret;
77*49c752c9SJean-Jacques Hiblot 
78*49c752c9SJean-Jacques Hiblot 	ret = device_remove(dev, DM_REMOVE_NORMAL);
79*49c752c9SJean-Jacques Hiblot 	if (ret) {
80*49c752c9SJean-Jacques Hiblot 		printf("Unable to remove. err:%d\n", ret);
81*49c752c9SJean-Jacques Hiblot 		return ret;
82*49c752c9SJean-Jacques Hiblot 	}
83*49c752c9SJean-Jacques Hiblot 
84*49c752c9SJean-Jacques Hiblot 	ret = device_unbind(dev);
85*49c752c9SJean-Jacques Hiblot 	if (ret) {
86*49c752c9SJean-Jacques Hiblot 		printf("Unable to unbind. err:%d\n", ret);
87*49c752c9SJean-Jacques Hiblot 		return ret;
88*49c752c9SJean-Jacques Hiblot 	}
89*49c752c9SJean-Jacques Hiblot 
90*49c752c9SJean-Jacques Hiblot 	return 0;
91*49c752c9SJean-Jacques Hiblot }
92*49c752c9SJean-Jacques Hiblot 
unbind_child_by_class_index(const char * uclass,int index,const char * drv_name)93*49c752c9SJean-Jacques Hiblot static int unbind_child_by_class_index(const char *uclass, int index,
94*49c752c9SJean-Jacques Hiblot 				       const char *drv_name)
95*49c752c9SJean-Jacques Hiblot {
96*49c752c9SJean-Jacques Hiblot 	struct udevice *parent;
97*49c752c9SJean-Jacques Hiblot 	int ret;
98*49c752c9SJean-Jacques Hiblot 	struct driver *drv;
99*49c752c9SJean-Jacques Hiblot 
100*49c752c9SJean-Jacques Hiblot 	drv = lists_driver_lookup_name(drv_name);
101*49c752c9SJean-Jacques Hiblot 	if (!drv) {
102*49c752c9SJean-Jacques Hiblot 		printf("Cannot find driver '%s'\n", drv_name);
103*49c752c9SJean-Jacques Hiblot 		return -ENOENT;
104*49c752c9SJean-Jacques Hiblot 	}
105*49c752c9SJean-Jacques Hiblot 
106*49c752c9SJean-Jacques Hiblot 	ret = find_dev(uclass, index, &parent);
107*49c752c9SJean-Jacques Hiblot 	if (ret)
108*49c752c9SJean-Jacques Hiblot 		return ret;
109*49c752c9SJean-Jacques Hiblot 
110*49c752c9SJean-Jacques Hiblot 	ret = device_chld_remove(parent, drv, DM_REMOVE_NORMAL);
111*49c752c9SJean-Jacques Hiblot 	if (ret)
112*49c752c9SJean-Jacques Hiblot 		printf("Unable to remove all. err:%d\n", ret);
113*49c752c9SJean-Jacques Hiblot 
114*49c752c9SJean-Jacques Hiblot 	ret = device_chld_unbind(parent, drv);
115*49c752c9SJean-Jacques Hiblot 	if (ret)
116*49c752c9SJean-Jacques Hiblot 		printf("Unable to unbind all. err:%d\n", ret);
117*49c752c9SJean-Jacques Hiblot 
118*49c752c9SJean-Jacques Hiblot 	return ret;
119*49c752c9SJean-Jacques Hiblot }
120*49c752c9SJean-Jacques Hiblot 
bind_by_node_path(const char * path,const char * drv_name)121*49c752c9SJean-Jacques Hiblot static int bind_by_node_path(const char *path, const char *drv_name)
122*49c752c9SJean-Jacques Hiblot {
123*49c752c9SJean-Jacques Hiblot 	struct udevice *dev;
124*49c752c9SJean-Jacques Hiblot 	struct udevice *parent = NULL;
125*49c752c9SJean-Jacques Hiblot 	int ret;
126*49c752c9SJean-Jacques Hiblot 	ofnode ofnode;
127*49c752c9SJean-Jacques Hiblot 	struct driver *drv;
128*49c752c9SJean-Jacques Hiblot 
129*49c752c9SJean-Jacques Hiblot 	drv = lists_driver_lookup_name(drv_name);
130*49c752c9SJean-Jacques Hiblot 	if (!drv) {
131*49c752c9SJean-Jacques Hiblot 		printf("%s is not a valid driver name\n", drv_name);
132*49c752c9SJean-Jacques Hiblot 		return -ENOENT;
133*49c752c9SJean-Jacques Hiblot 	}
134*49c752c9SJean-Jacques Hiblot 
135*49c752c9SJean-Jacques Hiblot 	ofnode = ofnode_path(path);
136*49c752c9SJean-Jacques Hiblot 	if (!ofnode_valid(ofnode)) {
137*49c752c9SJean-Jacques Hiblot 		printf("%s is not a valid node path\n", path);
138*49c752c9SJean-Jacques Hiblot 		return -EINVAL;
139*49c752c9SJean-Jacques Hiblot 	}
140*49c752c9SJean-Jacques Hiblot 
141*49c752c9SJean-Jacques Hiblot 	while (ofnode_valid(ofnode)) {
142*49c752c9SJean-Jacques Hiblot 		if (!device_find_global_by_ofnode(ofnode, &parent))
143*49c752c9SJean-Jacques Hiblot 			break;
144*49c752c9SJean-Jacques Hiblot 		ofnode = ofnode_get_parent(ofnode);
145*49c752c9SJean-Jacques Hiblot 	}
146*49c752c9SJean-Jacques Hiblot 
147*49c752c9SJean-Jacques Hiblot 	if (!parent) {
148*49c752c9SJean-Jacques Hiblot 		printf("Cannot find a parent device for node path %s\n", path);
149*49c752c9SJean-Jacques Hiblot 		return -ENODEV;
150*49c752c9SJean-Jacques Hiblot 	}
151*49c752c9SJean-Jacques Hiblot 
152*49c752c9SJean-Jacques Hiblot 	ofnode = ofnode_path(path);
153*49c752c9SJean-Jacques Hiblot 	ret = device_bind_with_driver_data(parent, drv, ofnode_get_name(ofnode),
154*49c752c9SJean-Jacques Hiblot 					   0, ofnode, &dev);
155*49c752c9SJean-Jacques Hiblot 	if (!dev || ret) {
156*49c752c9SJean-Jacques Hiblot 		printf("Unable to bind. err:%d\n", ret);
157*49c752c9SJean-Jacques Hiblot 		return ret;
158*49c752c9SJean-Jacques Hiblot 	}
159*49c752c9SJean-Jacques Hiblot 
160*49c752c9SJean-Jacques Hiblot 	return 0;
161*49c752c9SJean-Jacques Hiblot }
162*49c752c9SJean-Jacques Hiblot 
unbind_by_node_path(const char * path)163*49c752c9SJean-Jacques Hiblot static int unbind_by_node_path(const char *path)
164*49c752c9SJean-Jacques Hiblot {
165*49c752c9SJean-Jacques Hiblot 	struct udevice *dev;
166*49c752c9SJean-Jacques Hiblot 	int ret;
167*49c752c9SJean-Jacques Hiblot 	ofnode ofnode;
168*49c752c9SJean-Jacques Hiblot 
169*49c752c9SJean-Jacques Hiblot 	ofnode = ofnode_path(path);
170*49c752c9SJean-Jacques Hiblot 	if (!ofnode_valid(ofnode)) {
171*49c752c9SJean-Jacques Hiblot 		printf("%s is not a valid node path\n", path);
172*49c752c9SJean-Jacques Hiblot 		return -EINVAL;
173*49c752c9SJean-Jacques Hiblot 	}
174*49c752c9SJean-Jacques Hiblot 
175*49c752c9SJean-Jacques Hiblot 	ret = device_find_global_by_ofnode(ofnode, &dev);
176*49c752c9SJean-Jacques Hiblot 
177*49c752c9SJean-Jacques Hiblot 	if (!dev || ret) {
178*49c752c9SJean-Jacques Hiblot 		printf("Cannot find a device with path %s\n", path);
179*49c752c9SJean-Jacques Hiblot 		return -ENODEV;
180*49c752c9SJean-Jacques Hiblot 	}
181*49c752c9SJean-Jacques Hiblot 
182*49c752c9SJean-Jacques Hiblot 	ret = device_remove(dev, DM_REMOVE_NORMAL);
183*49c752c9SJean-Jacques Hiblot 	if (ret) {
184*49c752c9SJean-Jacques Hiblot 		printf("Unable to remove. err:%d\n", ret);
185*49c752c9SJean-Jacques Hiblot 		return ret;
186*49c752c9SJean-Jacques Hiblot 	}
187*49c752c9SJean-Jacques Hiblot 
188*49c752c9SJean-Jacques Hiblot 	ret = device_unbind(dev);
189*49c752c9SJean-Jacques Hiblot 	if (ret) {
190*49c752c9SJean-Jacques Hiblot 		printf("Unable to unbind. err:%d\n", ret);
191*49c752c9SJean-Jacques Hiblot 		return ret;
192*49c752c9SJean-Jacques Hiblot 	}
193*49c752c9SJean-Jacques Hiblot 
194*49c752c9SJean-Jacques Hiblot 	return 0;
195*49c752c9SJean-Jacques Hiblot }
196*49c752c9SJean-Jacques Hiblot 
do_bind_unbind(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])197*49c752c9SJean-Jacques Hiblot static int do_bind_unbind(cmd_tbl_t *cmdtp, int flag, int argc,
198*49c752c9SJean-Jacques Hiblot 			  char * const argv[])
199*49c752c9SJean-Jacques Hiblot {
200*49c752c9SJean-Jacques Hiblot 	int ret = 0;
201*49c752c9SJean-Jacques Hiblot 	bool bind;
202*49c752c9SJean-Jacques Hiblot 	bool by_node;
203*49c752c9SJean-Jacques Hiblot 
204*49c752c9SJean-Jacques Hiblot 	if (argc < 2)
205*49c752c9SJean-Jacques Hiblot 		return CMD_RET_USAGE;
206*49c752c9SJean-Jacques Hiblot 
207*49c752c9SJean-Jacques Hiblot 	bind = (argv[0][0] == 'b');
208*49c752c9SJean-Jacques Hiblot 	by_node = (argv[1][0] == '/');
209*49c752c9SJean-Jacques Hiblot 
210*49c752c9SJean-Jacques Hiblot 	if (by_node && bind) {
211*49c752c9SJean-Jacques Hiblot 		if (argc != 3)
212*49c752c9SJean-Jacques Hiblot 			return CMD_RET_USAGE;
213*49c752c9SJean-Jacques Hiblot 		ret = bind_by_node_path(argv[1], argv[2]);
214*49c752c9SJean-Jacques Hiblot 	} else if (by_node && !bind) {
215*49c752c9SJean-Jacques Hiblot 		if (argc != 2)
216*49c752c9SJean-Jacques Hiblot 			return CMD_RET_USAGE;
217*49c752c9SJean-Jacques Hiblot 		ret = unbind_by_node_path(argv[1]);
218*49c752c9SJean-Jacques Hiblot 	} else if (!by_node && bind) {
219*49c752c9SJean-Jacques Hiblot 		int index = (argc > 2) ? simple_strtoul(argv[2], NULL, 10) : 0;
220*49c752c9SJean-Jacques Hiblot 
221*49c752c9SJean-Jacques Hiblot 		if (argc != 4)
222*49c752c9SJean-Jacques Hiblot 			return CMD_RET_USAGE;
223*49c752c9SJean-Jacques Hiblot 		ret = bind_by_class_index(argv[1], index, argv[3]);
224*49c752c9SJean-Jacques Hiblot 	} else if (!by_node && !bind) {
225*49c752c9SJean-Jacques Hiblot 		int index = (argc > 2) ? simple_strtoul(argv[2], NULL, 10) : 0;
226*49c752c9SJean-Jacques Hiblot 
227*49c752c9SJean-Jacques Hiblot 		if (argc == 3)
228*49c752c9SJean-Jacques Hiblot 			ret = unbind_by_class_index(argv[1], index);
229*49c752c9SJean-Jacques Hiblot 		else if (argc == 4)
230*49c752c9SJean-Jacques Hiblot 			ret = unbind_child_by_class_index(argv[1], index,
231*49c752c9SJean-Jacques Hiblot 							  argv[3]);
232*49c752c9SJean-Jacques Hiblot 		else
233*49c752c9SJean-Jacques Hiblot 			return CMD_RET_USAGE;
234*49c752c9SJean-Jacques Hiblot 	}
235*49c752c9SJean-Jacques Hiblot 
236*49c752c9SJean-Jacques Hiblot 	if (ret)
237*49c752c9SJean-Jacques Hiblot 		return CMD_RET_FAILURE;
238*49c752c9SJean-Jacques Hiblot 	else
239*49c752c9SJean-Jacques Hiblot 		return CMD_RET_SUCCESS;
240*49c752c9SJean-Jacques Hiblot }
241*49c752c9SJean-Jacques Hiblot 
242*49c752c9SJean-Jacques Hiblot U_BOOT_CMD(
243*49c752c9SJean-Jacques Hiblot 	bind,	4,	0,	do_bind_unbind,
244*49c752c9SJean-Jacques Hiblot 	"Bind a device to a driver",
245*49c752c9SJean-Jacques Hiblot 	"<node path> <driver>\n"
246*49c752c9SJean-Jacques Hiblot 	"bind <class> <index> <driver>\n"
247*49c752c9SJean-Jacques Hiblot );
248*49c752c9SJean-Jacques Hiblot 
249*49c752c9SJean-Jacques Hiblot U_BOOT_CMD(
250*49c752c9SJean-Jacques Hiblot 	unbind,	4,	0,	do_bind_unbind,
251*49c752c9SJean-Jacques Hiblot 	"Unbind a device from a driver",
252*49c752c9SJean-Jacques Hiblot 	"<node path>\n"
253*49c752c9SJean-Jacques Hiblot 	"unbind <class> <index>\n"
254*49c752c9SJean-Jacques Hiblot 	"unbind <class> <index> <driver>\n"
255*49c752c9SJean-Jacques Hiblot );
256