xref: /OK3568_Linux_fs/u-boot/drivers/block/blk-uclass.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (C) 2016 Google, Inc
3*4882a593Smuzhiyun  * Written by Simon Glass <sjg@chromium.org>
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <common.h>
9*4882a593Smuzhiyun #include <blk.h>
10*4882a593Smuzhiyun #include <dm.h>
11*4882a593Smuzhiyun #include <dm/device-internal.h>
12*4882a593Smuzhiyun #include <dm/lists.h>
13*4882a593Smuzhiyun #include <dm/uclass-internal.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun static const char *if_typename_str[IF_TYPE_COUNT] = {
16*4882a593Smuzhiyun 	[IF_TYPE_IDE]		= "ide",
17*4882a593Smuzhiyun 	[IF_TYPE_SCSI]		= "scsi",
18*4882a593Smuzhiyun 	[IF_TYPE_ATAPI]		= "atapi",
19*4882a593Smuzhiyun 	[IF_TYPE_USB]		= "usb",
20*4882a593Smuzhiyun 	[IF_TYPE_DOC]		= "doc",
21*4882a593Smuzhiyun 	[IF_TYPE_MMC]		= "mmc",
22*4882a593Smuzhiyun 	[IF_TYPE_SD]		= "sd",
23*4882a593Smuzhiyun 	[IF_TYPE_SATA]		= "sata",
24*4882a593Smuzhiyun 	[IF_TYPE_HOST]		= "host",
25*4882a593Smuzhiyun 	[IF_TYPE_SYSTEMACE]	= "ace",
26*4882a593Smuzhiyun 	[IF_TYPE_NVME]		= "nvme",
27*4882a593Smuzhiyun 	[IF_TYPE_RKNAND]	= "rknand",
28*4882a593Smuzhiyun 	[IF_TYPE_SPINAND]	= "spinand",
29*4882a593Smuzhiyun 	[IF_TYPE_SPINOR]	= "spinor",
30*4882a593Smuzhiyun 	[IF_TYPE_RAMDISK]	= "ramdisk",
31*4882a593Smuzhiyun 	[IF_TYPE_MTD]		= "mtd",
32*4882a593Smuzhiyun };
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = {
35*4882a593Smuzhiyun 	[IF_TYPE_IDE]		= UCLASS_IDE,
36*4882a593Smuzhiyun 	[IF_TYPE_SCSI]		= UCLASS_SCSI,
37*4882a593Smuzhiyun 	[IF_TYPE_ATAPI]		= UCLASS_INVALID,
38*4882a593Smuzhiyun 	[IF_TYPE_USB]		= UCLASS_MASS_STORAGE,
39*4882a593Smuzhiyun 	[IF_TYPE_DOC]		= UCLASS_INVALID,
40*4882a593Smuzhiyun 	[IF_TYPE_MMC]		= UCLASS_MMC,
41*4882a593Smuzhiyun 	[IF_TYPE_SD]		= UCLASS_INVALID,
42*4882a593Smuzhiyun 	[IF_TYPE_SATA]		= UCLASS_AHCI,
43*4882a593Smuzhiyun 	[IF_TYPE_HOST]		= UCLASS_ROOT,
44*4882a593Smuzhiyun 	[IF_TYPE_NVME]		= UCLASS_NVME,
45*4882a593Smuzhiyun 	[IF_TYPE_RKNAND]	= UCLASS_RKNAND,
46*4882a593Smuzhiyun 	[IF_TYPE_SPINAND]	= UCLASS_SPI_FLASH,
47*4882a593Smuzhiyun 	[IF_TYPE_SPINOR]	= UCLASS_SPI_FLASH,
48*4882a593Smuzhiyun 	[IF_TYPE_RAMDISK]	= UCLASS_RAMDISK,
49*4882a593Smuzhiyun 	[IF_TYPE_MTD]		= UCLASS_MTD,
50*4882a593Smuzhiyun 	[IF_TYPE_SYSTEMACE]	= UCLASS_INVALID,
51*4882a593Smuzhiyun };
52*4882a593Smuzhiyun 
if_typename_to_iftype(const char * if_typename)53*4882a593Smuzhiyun enum if_type if_typename_to_iftype(const char *if_typename)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun 	int i;
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 	for (i = 0; i < IF_TYPE_COUNT; i++) {
58*4882a593Smuzhiyun 		if (if_typename_str[i] &&
59*4882a593Smuzhiyun 		    !strcmp(if_typename, if_typename_str[i]))
60*4882a593Smuzhiyun 			return i;
61*4882a593Smuzhiyun 	}
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	return IF_TYPE_UNKNOWN;
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun 
if_type_to_uclass_id(enum if_type if_type)66*4882a593Smuzhiyun static enum uclass_id if_type_to_uclass_id(enum if_type if_type)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun 	return if_type_uclass_id[if_type];
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun 
blk_get_if_type_name(enum if_type if_type)71*4882a593Smuzhiyun const char *blk_get_if_type_name(enum if_type if_type)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun 	return if_typename_str[if_type];
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun 
blk_get_devnum_by_type(enum if_type if_type,int devnum)76*4882a593Smuzhiyun struct blk_desc *blk_get_devnum_by_type(enum if_type if_type, int devnum)
77*4882a593Smuzhiyun {
78*4882a593Smuzhiyun 	struct blk_desc *desc;
79*4882a593Smuzhiyun 	struct udevice *dev;
80*4882a593Smuzhiyun 	int ret;
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun 	ret = blk_get_device(if_type, devnum, &dev);
83*4882a593Smuzhiyun 	if (ret)
84*4882a593Smuzhiyun 		return NULL;
85*4882a593Smuzhiyun 	desc = dev_get_uclass_platdata(dev);
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	return desc;
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun /*
91*4882a593Smuzhiyun  * This function is complicated with driver model. We look up the interface
92*4882a593Smuzhiyun  * name in a local table. This gives us an interface type which we can match
93*4882a593Smuzhiyun  * against the uclass of the block device's parent.
94*4882a593Smuzhiyun  */
blk_get_devnum_by_typename(const char * if_typename,int devnum)95*4882a593Smuzhiyun struct blk_desc *blk_get_devnum_by_typename(const char *if_typename, int devnum)
96*4882a593Smuzhiyun {
97*4882a593Smuzhiyun 	enum uclass_id uclass_id;
98*4882a593Smuzhiyun 	enum if_type if_type;
99*4882a593Smuzhiyun 	struct udevice *dev;
100*4882a593Smuzhiyun 	struct uclass *uc;
101*4882a593Smuzhiyun 	int ret;
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	if_type = if_typename_to_iftype(if_typename);
104*4882a593Smuzhiyun 	if (if_type == IF_TYPE_UNKNOWN) {
105*4882a593Smuzhiyun 		debug("%s: Unknown interface type '%s'\n", __func__,
106*4882a593Smuzhiyun 		      if_typename);
107*4882a593Smuzhiyun 		return NULL;
108*4882a593Smuzhiyun 	}
109*4882a593Smuzhiyun 	uclass_id = if_type_to_uclass_id(if_type);
110*4882a593Smuzhiyun 	if (uclass_id == UCLASS_INVALID) {
111*4882a593Smuzhiyun 		debug("%s: Unknown uclass for interface type'\n",
112*4882a593Smuzhiyun 		      if_typename_str[if_type]);
113*4882a593Smuzhiyun 		return NULL;
114*4882a593Smuzhiyun 	}
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	ret = uclass_get(UCLASS_BLK, &uc);
117*4882a593Smuzhiyun 	if (ret)
118*4882a593Smuzhiyun 		return NULL;
119*4882a593Smuzhiyun 	uclass_foreach_dev(dev, uc) {
120*4882a593Smuzhiyun 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 		debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
123*4882a593Smuzhiyun 		      if_type, devnum, dev->name, desc->if_type, desc->devnum);
124*4882a593Smuzhiyun 		if (desc->devnum != devnum)
125*4882a593Smuzhiyun 			continue;
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 		/* Find out the parent device uclass */
128*4882a593Smuzhiyun 		if (device_get_uclass_id(dev->parent) != uclass_id) {
129*4882a593Smuzhiyun #ifdef CONFIG_MTD_BLK
130*4882a593Smuzhiyun 			/*
131*4882a593Smuzhiyun 			 * The normal mtd block attachment steps are
132*4882a593Smuzhiyun 			 * UCLASS_BLK -> UCLASS_MTD -> UCLASS_(SPI or NAND).
133*4882a593Smuzhiyun 			 * Since the spi flash frame is attached to
134*4882a593Smuzhiyun 			 * UCLASS_SPI_FLASH, this make mistake to find
135*4882a593Smuzhiyun 			 * the UCLASS_MTD when find the mtd block device.
136*4882a593Smuzhiyun 			 * Fix it here when enable CONFIG_MTD_BLK.
137*4882a593Smuzhiyun 			 */
138*4882a593Smuzhiyun 			if (device_get_uclass_id(dev->parent) == UCLASS_SPI_FLASH &&
139*4882a593Smuzhiyun 			    if_type == IF_TYPE_MTD &&
140*4882a593Smuzhiyun 			    devnum == BLK_MTD_SPI_NOR) {
141*4882a593Smuzhiyun 				debug("Fix the spi flash uclass different\n");
142*4882a593Smuzhiyun 			} else {
143*4882a593Smuzhiyun 				debug("%s: parent uclass %d, this dev %d\n",
144*4882a593Smuzhiyun 				      __func__,
145*4882a593Smuzhiyun 				      device_get_uclass_id(dev->parent),
146*4882a593Smuzhiyun 				      uclass_id);
147*4882a593Smuzhiyun 				continue;
148*4882a593Smuzhiyun 			}
149*4882a593Smuzhiyun #else
150*4882a593Smuzhiyun 			debug("%s: parent uclass %d, this dev %d\n", __func__,
151*4882a593Smuzhiyun 			      device_get_uclass_id(dev->parent), uclass_id);
152*4882a593Smuzhiyun 			continue;
153*4882a593Smuzhiyun #endif
154*4882a593Smuzhiyun 		}
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 		if (device_probe(dev))
157*4882a593Smuzhiyun 			return NULL;
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 		debug("%s: Device desc %p\n", __func__, desc);
160*4882a593Smuzhiyun 		return desc;
161*4882a593Smuzhiyun 	}
162*4882a593Smuzhiyun 	debug("%s: No device found\n", __func__);
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	return NULL;
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun /**
168*4882a593Smuzhiyun  * get_desc() - Get the block device descriptor for the given device number
169*4882a593Smuzhiyun  *
170*4882a593Smuzhiyun  * @if_type:	Interface type
171*4882a593Smuzhiyun  * @devnum:	Device number (0 = first)
172*4882a593Smuzhiyun  * @descp:	Returns block device descriptor on success
173*4882a593Smuzhiyun  * @return 0 on success, -ENODEV if there is no such device and no device
174*4882a593Smuzhiyun  * with a higher device number, -ENOENT if there is no such device but there
175*4882a593Smuzhiyun  * is one with a higher number, or other -ve on other error.
176*4882a593Smuzhiyun  */
get_desc(enum if_type if_type,int devnum,struct blk_desc ** descp)177*4882a593Smuzhiyun static int get_desc(enum if_type if_type, int devnum, struct blk_desc **descp)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun 	bool found_more = false;
180*4882a593Smuzhiyun 	struct udevice *dev;
181*4882a593Smuzhiyun 	struct uclass *uc;
182*4882a593Smuzhiyun 	int ret;
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	*descp = NULL;
185*4882a593Smuzhiyun 	ret = uclass_get(UCLASS_BLK, &uc);
186*4882a593Smuzhiyun 	if (ret)
187*4882a593Smuzhiyun 		return ret;
188*4882a593Smuzhiyun 	uclass_foreach_dev(dev, uc) {
189*4882a593Smuzhiyun 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 		debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
192*4882a593Smuzhiyun 		      if_type, devnum, dev->name, desc->if_type, desc->devnum);
193*4882a593Smuzhiyun 		if (desc->if_type == if_type) {
194*4882a593Smuzhiyun 			if (desc->devnum == devnum) {
195*4882a593Smuzhiyun 				ret = device_probe(dev);
196*4882a593Smuzhiyun 				if (ret)
197*4882a593Smuzhiyun 					return ret;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 				*descp = desc;
200*4882a593Smuzhiyun 				return 0;
201*4882a593Smuzhiyun 			} else if (desc->devnum > devnum) {
202*4882a593Smuzhiyun 				found_more = true;
203*4882a593Smuzhiyun 			}
204*4882a593Smuzhiyun 		}
205*4882a593Smuzhiyun 	}
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	return found_more ? -ENOENT : -ENODEV;
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun 
blk_select_hwpart_devnum(enum if_type if_type,int devnum,int hwpart)210*4882a593Smuzhiyun int blk_select_hwpart_devnum(enum if_type if_type, int devnum, int hwpart)
211*4882a593Smuzhiyun {
212*4882a593Smuzhiyun 	struct udevice *dev;
213*4882a593Smuzhiyun 	int ret;
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	ret = blk_get_device(if_type, devnum, &dev);
216*4882a593Smuzhiyun 	if (ret)
217*4882a593Smuzhiyun 		return ret;
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	return blk_select_hwpart(dev, hwpart);
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun 
blk_list_part(enum if_type if_type)222*4882a593Smuzhiyun int blk_list_part(enum if_type if_type)
223*4882a593Smuzhiyun {
224*4882a593Smuzhiyun 	struct blk_desc *desc;
225*4882a593Smuzhiyun 	int devnum, ok;
226*4882a593Smuzhiyun 	int ret;
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	for (ok = 0, devnum = 0;; ++devnum) {
229*4882a593Smuzhiyun 		ret = get_desc(if_type, devnum, &desc);
230*4882a593Smuzhiyun 		if (ret == -ENODEV)
231*4882a593Smuzhiyun 			break;
232*4882a593Smuzhiyun 		else if (ret)
233*4882a593Smuzhiyun 			continue;
234*4882a593Smuzhiyun 		if (desc->part_type != PART_TYPE_UNKNOWN) {
235*4882a593Smuzhiyun 			++ok;
236*4882a593Smuzhiyun 			if (devnum)
237*4882a593Smuzhiyun 				putc('\n');
238*4882a593Smuzhiyun 			part_print(desc);
239*4882a593Smuzhiyun 		}
240*4882a593Smuzhiyun 	}
241*4882a593Smuzhiyun 	if (!ok)
242*4882a593Smuzhiyun 		return -ENODEV;
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 	return 0;
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun 
blk_print_part_devnum(enum if_type if_type,int devnum)247*4882a593Smuzhiyun int blk_print_part_devnum(enum if_type if_type, int devnum)
248*4882a593Smuzhiyun {
249*4882a593Smuzhiyun 	struct blk_desc *desc;
250*4882a593Smuzhiyun 	int ret;
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	ret = get_desc(if_type, devnum, &desc);
253*4882a593Smuzhiyun 	if (ret)
254*4882a593Smuzhiyun 		return ret;
255*4882a593Smuzhiyun 	if (desc->type == DEV_TYPE_UNKNOWN)
256*4882a593Smuzhiyun 		return -ENOENT;
257*4882a593Smuzhiyun 	part_print(desc);
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	return 0;
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun 
blk_list_devices(enum if_type if_type)262*4882a593Smuzhiyun void blk_list_devices(enum if_type if_type)
263*4882a593Smuzhiyun {
264*4882a593Smuzhiyun 	struct blk_desc *desc;
265*4882a593Smuzhiyun 	int ret;
266*4882a593Smuzhiyun 	int i;
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	for (i = 0;; ++i) {
269*4882a593Smuzhiyun 		ret = get_desc(if_type, i, &desc);
270*4882a593Smuzhiyun 		if (ret == -ENODEV)
271*4882a593Smuzhiyun 			break;
272*4882a593Smuzhiyun 		else if (ret)
273*4882a593Smuzhiyun 			continue;
274*4882a593Smuzhiyun 		if (desc->type == DEV_TYPE_UNKNOWN)
275*4882a593Smuzhiyun 			continue;  /* list only known devices */
276*4882a593Smuzhiyun 		printf("Device %d: ", i);
277*4882a593Smuzhiyun 		dev_print(desc);
278*4882a593Smuzhiyun 	}
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun 
blk_print_device_num(enum if_type if_type,int devnum)281*4882a593Smuzhiyun int blk_print_device_num(enum if_type if_type, int devnum)
282*4882a593Smuzhiyun {
283*4882a593Smuzhiyun 	struct blk_desc *desc;
284*4882a593Smuzhiyun 	int ret;
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	ret = get_desc(if_type, devnum, &desc);
287*4882a593Smuzhiyun 	if (ret)
288*4882a593Smuzhiyun 		return ret;
289*4882a593Smuzhiyun 	printf("\nIDE device %d: ", devnum);
290*4882a593Smuzhiyun 	dev_print(desc);
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	return 0;
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun 
blk_show_device(enum if_type if_type,int devnum)295*4882a593Smuzhiyun int blk_show_device(enum if_type if_type, int devnum)
296*4882a593Smuzhiyun {
297*4882a593Smuzhiyun 	struct blk_desc *desc;
298*4882a593Smuzhiyun 	int ret;
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 	printf("\nDevice %d: ", devnum);
301*4882a593Smuzhiyun 	ret = get_desc(if_type, devnum, &desc);
302*4882a593Smuzhiyun 	if (ret == -ENODEV || ret == -ENOENT) {
303*4882a593Smuzhiyun 		printf("unknown device\n");
304*4882a593Smuzhiyun 		return -ENODEV;
305*4882a593Smuzhiyun 	}
306*4882a593Smuzhiyun 	if (ret)
307*4882a593Smuzhiyun 		return ret;
308*4882a593Smuzhiyun 	dev_print(desc);
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	if (desc->type == DEV_TYPE_UNKNOWN)
311*4882a593Smuzhiyun 		return -ENOENT;
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	return 0;
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun 
blk_read_devnum(enum if_type if_type,int devnum,lbaint_t start,lbaint_t blkcnt,void * buffer)316*4882a593Smuzhiyun ulong blk_read_devnum(enum if_type if_type, int devnum, lbaint_t start,
317*4882a593Smuzhiyun 		      lbaint_t blkcnt, void *buffer)
318*4882a593Smuzhiyun {
319*4882a593Smuzhiyun 	struct blk_desc *desc;
320*4882a593Smuzhiyun 	ulong n;
321*4882a593Smuzhiyun 	int ret;
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	ret = get_desc(if_type, devnum, &desc);
324*4882a593Smuzhiyun 	if (ret)
325*4882a593Smuzhiyun 		return ret;
326*4882a593Smuzhiyun 	n = blk_dread(desc, start, blkcnt, buffer);
327*4882a593Smuzhiyun 	if (IS_ERR_VALUE(n))
328*4882a593Smuzhiyun 		return n;
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	return n;
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun 
blk_write_devnum(enum if_type if_type,int devnum,lbaint_t start,lbaint_t blkcnt,const void * buffer)333*4882a593Smuzhiyun ulong blk_write_devnum(enum if_type if_type, int devnum, lbaint_t start,
334*4882a593Smuzhiyun 		       lbaint_t blkcnt, const void *buffer)
335*4882a593Smuzhiyun {
336*4882a593Smuzhiyun 	struct blk_desc *desc;
337*4882a593Smuzhiyun 	int ret;
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	ret = get_desc(if_type, devnum, &desc);
340*4882a593Smuzhiyun 	if (ret)
341*4882a593Smuzhiyun 		return ret;
342*4882a593Smuzhiyun 	return blk_dwrite(desc, start, blkcnt, buffer);
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun 
blk_erase_devnum(enum if_type if_type,int devnum,lbaint_t start,lbaint_t blkcnt)345*4882a593Smuzhiyun ulong blk_erase_devnum(enum if_type if_type, int devnum, lbaint_t start,
346*4882a593Smuzhiyun 		       lbaint_t blkcnt)
347*4882a593Smuzhiyun {
348*4882a593Smuzhiyun 	struct blk_desc *desc;
349*4882a593Smuzhiyun 	int ret;
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	ret = get_desc(if_type, devnum, &desc);
352*4882a593Smuzhiyun 	if (ret)
353*4882a593Smuzhiyun 		return ret;
354*4882a593Smuzhiyun 	return blk_derase(desc, start, blkcnt);
355*4882a593Smuzhiyun }
356*4882a593Smuzhiyun 
blk_select_hwpart(struct udevice * dev,int hwpart)357*4882a593Smuzhiyun int blk_select_hwpart(struct udevice *dev, int hwpart)
358*4882a593Smuzhiyun {
359*4882a593Smuzhiyun 	const struct blk_ops *ops = blk_get_ops(dev);
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	if (!ops)
362*4882a593Smuzhiyun 		return -ENOSYS;
363*4882a593Smuzhiyun 	if (!ops->select_hwpart)
364*4882a593Smuzhiyun 		return 0;
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	return ops->select_hwpart(dev, hwpart);
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun 
blk_dselect_hwpart(struct blk_desc * desc,int hwpart)369*4882a593Smuzhiyun int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
370*4882a593Smuzhiyun {
371*4882a593Smuzhiyun 	return blk_select_hwpart(desc->bdev, hwpart);
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun 
blk_first_device(int if_type,struct udevice ** devp)374*4882a593Smuzhiyun int blk_first_device(int if_type, struct udevice **devp)
375*4882a593Smuzhiyun {
376*4882a593Smuzhiyun 	struct blk_desc *desc;
377*4882a593Smuzhiyun 	int ret;
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	ret = uclass_find_first_device(UCLASS_BLK, devp);
380*4882a593Smuzhiyun 	if (ret)
381*4882a593Smuzhiyun 		return ret;
382*4882a593Smuzhiyun 	if (!*devp)
383*4882a593Smuzhiyun 		return -ENODEV;
384*4882a593Smuzhiyun 	do {
385*4882a593Smuzhiyun 		desc = dev_get_uclass_platdata(*devp);
386*4882a593Smuzhiyun 		if (desc->if_type == if_type)
387*4882a593Smuzhiyun 			return 0;
388*4882a593Smuzhiyun 		ret = uclass_find_next_device(devp);
389*4882a593Smuzhiyun 		if (ret)
390*4882a593Smuzhiyun 			return ret;
391*4882a593Smuzhiyun 	} while (*devp);
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 	return -ENODEV;
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun 
blk_next_device(struct udevice ** devp)396*4882a593Smuzhiyun int blk_next_device(struct udevice **devp)
397*4882a593Smuzhiyun {
398*4882a593Smuzhiyun 	struct blk_desc *desc;
399*4882a593Smuzhiyun 	int ret, if_type;
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	desc = dev_get_uclass_platdata(*devp);
402*4882a593Smuzhiyun 	if_type = desc->if_type;
403*4882a593Smuzhiyun 	do {
404*4882a593Smuzhiyun 		ret = uclass_find_next_device(devp);
405*4882a593Smuzhiyun 		if (ret)
406*4882a593Smuzhiyun 			return ret;
407*4882a593Smuzhiyun 		if (!*devp)
408*4882a593Smuzhiyun 			return -ENODEV;
409*4882a593Smuzhiyun 		desc = dev_get_uclass_platdata(*devp);
410*4882a593Smuzhiyun 		if (desc->if_type == if_type)
411*4882a593Smuzhiyun 			return 0;
412*4882a593Smuzhiyun 	} while (1);
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun 
blk_find_device(int if_type,int devnum,struct udevice ** devp)415*4882a593Smuzhiyun int blk_find_device(int if_type, int devnum, struct udevice **devp)
416*4882a593Smuzhiyun {
417*4882a593Smuzhiyun 	struct uclass *uc;
418*4882a593Smuzhiyun 	struct udevice *dev;
419*4882a593Smuzhiyun 	int ret;
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun 	ret = uclass_get(UCLASS_BLK, &uc);
422*4882a593Smuzhiyun 	if (ret)
423*4882a593Smuzhiyun 		return ret;
424*4882a593Smuzhiyun 	uclass_foreach_dev(dev, uc) {
425*4882a593Smuzhiyun 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 		debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
428*4882a593Smuzhiyun 		      if_type, devnum, dev->name, desc->if_type, desc->devnum);
429*4882a593Smuzhiyun 		if (desc->if_type == if_type && desc->devnum == devnum) {
430*4882a593Smuzhiyun 			*devp = dev;
431*4882a593Smuzhiyun 			return 0;
432*4882a593Smuzhiyun 		}
433*4882a593Smuzhiyun 	}
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 	return -ENODEV;
436*4882a593Smuzhiyun }
437*4882a593Smuzhiyun 
blk_get_device(int if_type,int devnum,struct udevice ** devp)438*4882a593Smuzhiyun int blk_get_device(int if_type, int devnum, struct udevice **devp)
439*4882a593Smuzhiyun {
440*4882a593Smuzhiyun 	int ret;
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	ret = blk_find_device(if_type, devnum, devp);
443*4882a593Smuzhiyun 	if (ret)
444*4882a593Smuzhiyun 		return ret;
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 	return device_probe(*devp);
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun 
blk_dread(struct blk_desc * block_dev,lbaint_t start,lbaint_t blkcnt,void * buffer)449*4882a593Smuzhiyun unsigned long blk_dread(struct blk_desc *block_dev, lbaint_t start,
450*4882a593Smuzhiyun 			lbaint_t blkcnt, void *buffer)
451*4882a593Smuzhiyun {
452*4882a593Smuzhiyun 	struct udevice *dev = block_dev->bdev;
453*4882a593Smuzhiyun 	const struct blk_ops *ops = blk_get_ops(dev);
454*4882a593Smuzhiyun 	ulong blks_read;
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	if (!ops->read)
457*4882a593Smuzhiyun 		return -ENOSYS;
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun 	if (blkcache_read(block_dev->if_type, block_dev->devnum,
460*4882a593Smuzhiyun 			  start, blkcnt, block_dev->blksz, buffer))
461*4882a593Smuzhiyun 		return blkcnt;
462*4882a593Smuzhiyun 	blks_read = ops->read(dev, start, blkcnt, buffer);
463*4882a593Smuzhiyun 	if (blks_read == blkcnt)
464*4882a593Smuzhiyun 		blkcache_fill(block_dev->if_type, block_dev->devnum,
465*4882a593Smuzhiyun 			      start, blkcnt, block_dev->blksz, buffer);
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun 	return blks_read;
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun 
blk_dwrite(struct blk_desc * block_dev,lbaint_t start,lbaint_t blkcnt,const void * buffer)470*4882a593Smuzhiyun unsigned long blk_dwrite(struct blk_desc *block_dev, lbaint_t start,
471*4882a593Smuzhiyun 			 lbaint_t blkcnt, const void *buffer)
472*4882a593Smuzhiyun {
473*4882a593Smuzhiyun 	struct udevice *dev = block_dev->bdev;
474*4882a593Smuzhiyun 	const struct blk_ops *ops = blk_get_ops(dev);
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun 	if (!ops->write)
477*4882a593Smuzhiyun 		return -ENOSYS;
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun 	blkcache_invalidate(block_dev->if_type, block_dev->devnum);
480*4882a593Smuzhiyun 	return ops->write(dev, start, blkcnt, buffer);
481*4882a593Smuzhiyun }
482*4882a593Smuzhiyun 
blk_derase(struct blk_desc * block_dev,lbaint_t start,lbaint_t blkcnt)483*4882a593Smuzhiyun unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start,
484*4882a593Smuzhiyun 			 lbaint_t blkcnt)
485*4882a593Smuzhiyun {
486*4882a593Smuzhiyun 	struct udevice *dev = block_dev->bdev;
487*4882a593Smuzhiyun 	const struct blk_ops *ops = blk_get_ops(dev);
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	if (!ops->erase)
490*4882a593Smuzhiyun 		return -ENOSYS;
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 	blkcache_invalidate(block_dev->if_type, block_dev->devnum);
493*4882a593Smuzhiyun 	return ops->erase(dev, start, blkcnt);
494*4882a593Smuzhiyun }
495*4882a593Smuzhiyun 
blk_prepare_device(struct udevice * dev)496*4882a593Smuzhiyun int blk_prepare_device(struct udevice *dev)
497*4882a593Smuzhiyun {
498*4882a593Smuzhiyun 	struct blk_desc *desc = dev_get_uclass_platdata(dev);
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 	part_init(desc);
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun 	return 0;
503*4882a593Smuzhiyun }
504*4882a593Smuzhiyun 
blk_get_from_parent(struct udevice * parent,struct udevice ** devp)505*4882a593Smuzhiyun int blk_get_from_parent(struct udevice *parent, struct udevice **devp)
506*4882a593Smuzhiyun {
507*4882a593Smuzhiyun 	struct udevice *dev;
508*4882a593Smuzhiyun 	enum uclass_id id;
509*4882a593Smuzhiyun 	int ret;
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun 	device_find_first_child(parent, &dev);
512*4882a593Smuzhiyun 	if (!dev) {
513*4882a593Smuzhiyun 		debug("%s: No block device found for parent '%s'\n", __func__,
514*4882a593Smuzhiyun 		      parent->name);
515*4882a593Smuzhiyun 		return -ENODEV;
516*4882a593Smuzhiyun 	}
517*4882a593Smuzhiyun 	id = device_get_uclass_id(dev);
518*4882a593Smuzhiyun 	if (id != UCLASS_BLK) {
519*4882a593Smuzhiyun 		debug("%s: Incorrect uclass %s for block device '%s'\n",
520*4882a593Smuzhiyun 		      __func__, uclass_get_name(id), dev->name);
521*4882a593Smuzhiyun 		return -ENOTBLK;
522*4882a593Smuzhiyun 	}
523*4882a593Smuzhiyun 	ret = device_probe(dev);
524*4882a593Smuzhiyun 	if (ret)
525*4882a593Smuzhiyun 		return ret;
526*4882a593Smuzhiyun 	*devp = dev;
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun 	return 0;
529*4882a593Smuzhiyun }
530*4882a593Smuzhiyun 
blk_find_max_devnum(enum if_type if_type)531*4882a593Smuzhiyun int blk_find_max_devnum(enum if_type if_type)
532*4882a593Smuzhiyun {
533*4882a593Smuzhiyun 	struct udevice *dev;
534*4882a593Smuzhiyun 	int max_devnum = -ENODEV;
535*4882a593Smuzhiyun 	struct uclass *uc;
536*4882a593Smuzhiyun 	int ret;
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun 	ret = uclass_get(UCLASS_BLK, &uc);
539*4882a593Smuzhiyun 	if (ret)
540*4882a593Smuzhiyun 		return ret;
541*4882a593Smuzhiyun 	uclass_foreach_dev(dev, uc) {
542*4882a593Smuzhiyun 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 		if (desc->if_type == if_type && desc->devnum > max_devnum)
545*4882a593Smuzhiyun 			max_devnum = desc->devnum;
546*4882a593Smuzhiyun 	}
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun 	return max_devnum;
549*4882a593Smuzhiyun }
550*4882a593Smuzhiyun 
blk_next_free_devnum(enum if_type if_type)551*4882a593Smuzhiyun static int blk_next_free_devnum(enum if_type if_type)
552*4882a593Smuzhiyun {
553*4882a593Smuzhiyun 	int ret;
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun 	ret = blk_find_max_devnum(if_type);
556*4882a593Smuzhiyun 	if (ret == -ENODEV)
557*4882a593Smuzhiyun 		return 0;
558*4882a593Smuzhiyun 	if (ret < 0)
559*4882a593Smuzhiyun 		return ret;
560*4882a593Smuzhiyun 
561*4882a593Smuzhiyun 	return ret + 1;
562*4882a593Smuzhiyun }
563*4882a593Smuzhiyun 
blk_claim_devnum(enum if_type if_type,int devnum)564*4882a593Smuzhiyun static int blk_claim_devnum(enum if_type if_type, int devnum)
565*4882a593Smuzhiyun {
566*4882a593Smuzhiyun 	struct udevice *dev;
567*4882a593Smuzhiyun 	struct uclass *uc;
568*4882a593Smuzhiyun 	int ret;
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 	ret = uclass_get(UCLASS_BLK, &uc);
571*4882a593Smuzhiyun 	if (ret)
572*4882a593Smuzhiyun 		return ret;
573*4882a593Smuzhiyun 	uclass_foreach_dev(dev, uc) {
574*4882a593Smuzhiyun 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun 		if (desc->if_type == if_type && desc->devnum == devnum) {
577*4882a593Smuzhiyun 			int next = blk_next_free_devnum(if_type);
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 			if (next < 0)
580*4882a593Smuzhiyun 				return next;
581*4882a593Smuzhiyun #ifdef CONFIG_USING_KERNEL_DTB_V2
582*4882a593Smuzhiyun 			/*
583*4882a593Smuzhiyun 			 * Not allow devnum to be forced distributed.
584*4882a593Smuzhiyun 			 * See commit (e48eeb9ea3 dm: blk: Improve block device claiming).
585*4882a593Smuzhiyun 			 *
586*4882a593Smuzhiyun 			 * fix like: "Device 'dwmmc@fe2b0000': seq 0 is in use by 'sdhci@fe310000'"
587*4882a593Smuzhiyun 			 */
588*4882a593Smuzhiyun 			if (!(gd->flags & GD_FLG_KDTB_READY))
589*4882a593Smuzhiyun #endif
590*4882a593Smuzhiyun 			desc->devnum = next;
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun 			return 0;
593*4882a593Smuzhiyun 		}
594*4882a593Smuzhiyun 	}
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun 	return -ENOENT;
597*4882a593Smuzhiyun }
598*4882a593Smuzhiyun 
blk_create_device(struct udevice * parent,const char * drv_name,const char * name,int if_type,int devnum,int blksz,lbaint_t size,struct udevice ** devp)599*4882a593Smuzhiyun int blk_create_device(struct udevice *parent, const char *drv_name,
600*4882a593Smuzhiyun 		      const char *name, int if_type, int devnum, int blksz,
601*4882a593Smuzhiyun 		      lbaint_t size, struct udevice **devp)
602*4882a593Smuzhiyun {
603*4882a593Smuzhiyun 	struct blk_desc *desc;
604*4882a593Smuzhiyun 	struct udevice *dev;
605*4882a593Smuzhiyun 	int ret;
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun 	if (devnum == -1) {
608*4882a593Smuzhiyun 		devnum = blk_next_free_devnum(if_type);
609*4882a593Smuzhiyun 	} else {
610*4882a593Smuzhiyun 		ret = blk_claim_devnum(if_type, devnum);
611*4882a593Smuzhiyun 		if (ret < 0 && ret != -ENOENT)
612*4882a593Smuzhiyun 			return ret;
613*4882a593Smuzhiyun 	}
614*4882a593Smuzhiyun 	if (devnum < 0)
615*4882a593Smuzhiyun 		return devnum;
616*4882a593Smuzhiyun 	ret = device_bind_driver(parent, drv_name, name, &dev);
617*4882a593Smuzhiyun 	if (ret)
618*4882a593Smuzhiyun 		return ret;
619*4882a593Smuzhiyun 	desc = dev_get_uclass_platdata(dev);
620*4882a593Smuzhiyun 	desc->if_type = if_type;
621*4882a593Smuzhiyun 	desc->blksz = blksz;
622*4882a593Smuzhiyun 	desc->lba = size / blksz;
623*4882a593Smuzhiyun 	desc->part_type = PART_TYPE_UNKNOWN;
624*4882a593Smuzhiyun 	desc->bdev = dev;
625*4882a593Smuzhiyun 	desc->devnum = devnum;
626*4882a593Smuzhiyun 	*devp = dev;
627*4882a593Smuzhiyun 
628*4882a593Smuzhiyun 	return 0;
629*4882a593Smuzhiyun }
630*4882a593Smuzhiyun 
blk_create_devicef(struct udevice * parent,const char * drv_name,const char * name,int if_type,int devnum,int blksz,lbaint_t size,struct udevice ** devp)631*4882a593Smuzhiyun int blk_create_devicef(struct udevice *parent, const char *drv_name,
632*4882a593Smuzhiyun 		       const char *name, int if_type, int devnum, int blksz,
633*4882a593Smuzhiyun 		       lbaint_t size, struct udevice **devp)
634*4882a593Smuzhiyun {
635*4882a593Smuzhiyun 	char dev_name[30], *str;
636*4882a593Smuzhiyun 	int ret;
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun 	snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name);
639*4882a593Smuzhiyun 	str = strdup(dev_name);
640*4882a593Smuzhiyun 	if (!str)
641*4882a593Smuzhiyun 		return -ENOMEM;
642*4882a593Smuzhiyun 
643*4882a593Smuzhiyun 	ret = blk_create_device(parent, drv_name, str, if_type, devnum,
644*4882a593Smuzhiyun 				blksz, size, devp);
645*4882a593Smuzhiyun 	if (ret) {
646*4882a593Smuzhiyun 		free(str);
647*4882a593Smuzhiyun 		return ret;
648*4882a593Smuzhiyun 	}
649*4882a593Smuzhiyun 	device_set_name_alloced(*devp);
650*4882a593Smuzhiyun 
651*4882a593Smuzhiyun 	return 0;
652*4882a593Smuzhiyun }
653*4882a593Smuzhiyun 
blk_unbind_all(int if_type)654*4882a593Smuzhiyun int blk_unbind_all(int if_type)
655*4882a593Smuzhiyun {
656*4882a593Smuzhiyun 	struct uclass *uc;
657*4882a593Smuzhiyun 	struct udevice *dev, *next;
658*4882a593Smuzhiyun 	int ret;
659*4882a593Smuzhiyun 
660*4882a593Smuzhiyun 	ret = uclass_get(UCLASS_BLK, &uc);
661*4882a593Smuzhiyun 	if (ret)
662*4882a593Smuzhiyun 		return ret;
663*4882a593Smuzhiyun 	uclass_foreach_dev_safe(dev, next, uc) {
664*4882a593Smuzhiyun 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
665*4882a593Smuzhiyun 
666*4882a593Smuzhiyun 		if (desc->if_type == if_type) {
667*4882a593Smuzhiyun 			ret = device_remove(dev, DM_REMOVE_NORMAL);
668*4882a593Smuzhiyun 			if (ret)
669*4882a593Smuzhiyun 				return ret;
670*4882a593Smuzhiyun 			ret = device_unbind(dev);
671*4882a593Smuzhiyun 			if (ret)
672*4882a593Smuzhiyun 				return ret;
673*4882a593Smuzhiyun 		}
674*4882a593Smuzhiyun 	}
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun 	return 0;
677*4882a593Smuzhiyun }
678*4882a593Smuzhiyun 
679*4882a593Smuzhiyun UCLASS_DRIVER(blk) = {
680*4882a593Smuzhiyun 	.id		= UCLASS_BLK,
681*4882a593Smuzhiyun 	.name		= "blk",
682*4882a593Smuzhiyun 	.per_device_platdata_auto_alloc_size = sizeof(struct blk_desc),
683*4882a593Smuzhiyun };
684