xref: /rk3399_rockchip-uboot/drivers/block/sandbox.c (revision 433647a7ef9241b963b4636e7f8c3a2159d156f0)
1f4d8de48SHenrik Nordström /*
2f4d8de48SHenrik Nordström  * Copyright (C) 2013 Henrik Nordstrom <henrik@henriknordstrom.net>
3f4d8de48SHenrik Nordström  *
4f4d8de48SHenrik Nordström  * SPDX-License-Identifier:	GPL-2.0+
5f4d8de48SHenrik Nordström  */
6f4d8de48SHenrik Nordström 
7f4d8de48SHenrik Nordström #include <common.h>
840fd0508SSimon Glass #include <blk.h>
940fd0508SSimon Glass #include <dm.h>
1040fd0508SSimon Glass #include <fdtdec.h>
11f4d8de48SHenrik Nordström #include <part.h>
12f4d8de48SHenrik Nordström #include <os.h>
13f4d8de48SHenrik Nordström #include <malloc.h>
14f4d8de48SHenrik Nordström #include <sandboxblockdev.h>
151221ce45SMasahiro Yamada #include <linux/errno.h>
1640fd0508SSimon Glass #include <dm/device-internal.h>
17f4d8de48SHenrik Nordström 
1840fd0508SSimon Glass DECLARE_GLOBAL_DATA_PTR;
1940fd0508SSimon Glass 
20e161356bSSimon Glass #ifndef CONFIG_BLK
21e161356bSSimon Glass static struct host_block_dev host_devices[CONFIG_HOST_MAX_DEVICES];
22e161356bSSimon Glass 
find_host_device(int dev)23e161356bSSimon Glass static struct host_block_dev *find_host_device(int dev)
24e161356bSSimon Glass {
25e161356bSSimon Glass 	if (dev >= 0 && dev < CONFIG_HOST_MAX_DEVICES)
26e161356bSSimon Glass 		return &host_devices[dev];
27e161356bSSimon Glass 
28e161356bSSimon Glass 	return NULL;
29e161356bSSimon Glass }
30e161356bSSimon Glass #endif
31e161356bSSimon Glass 
32e161356bSSimon Glass #ifdef CONFIG_BLK
host_block_read(struct udevice * dev,unsigned long start,lbaint_t blkcnt,void * buffer)3340fd0508SSimon Glass static unsigned long host_block_read(struct udevice *dev,
3440fd0508SSimon Glass 				     unsigned long start, lbaint_t blkcnt,
3540fd0508SSimon Glass 				     void *buffer)
3640fd0508SSimon Glass {
3740fd0508SSimon Glass 	struct host_block_dev *host_dev = dev_get_priv(dev);
3840fd0508SSimon Glass 	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
3940fd0508SSimon Glass 
40e161356bSSimon Glass #else
41e161356bSSimon Glass static unsigned long host_block_read(struct blk_desc *block_dev,
42e161356bSSimon Glass 				     unsigned long start, lbaint_t blkcnt,
43e161356bSSimon Glass 				     void *buffer)
44e161356bSSimon Glass {
45e161356bSSimon Glass 	int dev = block_dev->devnum;
46e161356bSSimon Glass 	struct host_block_dev *host_dev = find_host_device(dev);
47e161356bSSimon Glass 
48e161356bSSimon Glass 	if (!host_dev)
49e161356bSSimon Glass 		return -1;
50e161356bSSimon Glass #endif
51e161356bSSimon Glass 
527ded959eSSimon Glass 	if (os_lseek(host_dev->fd, start * block_dev->blksz, OS_SEEK_SET) ==
537ded959eSSimon Glass 			-1) {
547ded959eSSimon Glass 		printf("ERROR: Invalid block %lx\n", start);
55f4d8de48SHenrik Nordström 		return -1;
56f4d8de48SHenrik Nordström 	}
577ded959eSSimon Glass 	ssize_t len = os_read(host_dev->fd, buffer, blkcnt * block_dev->blksz);
58f4d8de48SHenrik Nordström 	if (len >= 0)
597ded959eSSimon Glass 		return len / block_dev->blksz;
60f4d8de48SHenrik Nordström 	return -1;
61f4d8de48SHenrik Nordström }
62f4d8de48SHenrik Nordström 
63e161356bSSimon Glass #ifdef CONFIG_BLK
6440fd0508SSimon Glass static unsigned long host_block_write(struct udevice *dev,
6540fd0508SSimon Glass 				      unsigned long start, lbaint_t blkcnt,
6640fd0508SSimon Glass 				      const void *buffer)
6740fd0508SSimon Glass {
6840fd0508SSimon Glass 	struct host_block_dev *host_dev = dev_get_priv(dev);
6940fd0508SSimon Glass 	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
70e161356bSSimon Glass #else
71e161356bSSimon Glass static unsigned long host_block_write(struct blk_desc *block_dev,
72e161356bSSimon Glass 				      unsigned long start, lbaint_t blkcnt,
73e161356bSSimon Glass 				      const void *buffer)
74e161356bSSimon Glass {
75e161356bSSimon Glass 	int dev = block_dev->devnum;
76e161356bSSimon Glass 	struct host_block_dev *host_dev = find_host_device(dev);
77e161356bSSimon Glass #endif
787ded959eSSimon Glass 
797ded959eSSimon Glass 	if (os_lseek(host_dev->fd, start * block_dev->blksz, OS_SEEK_SET) ==
807ded959eSSimon Glass 			-1) {
817ded959eSSimon Glass 		printf("ERROR: Invalid block %lx\n", start);
82f4d8de48SHenrik Nordström 		return -1;
83f4d8de48SHenrik Nordström 	}
847ded959eSSimon Glass 	ssize_t len = os_write(host_dev->fd, buffer, blkcnt * block_dev->blksz);
85f4d8de48SHenrik Nordström 	if (len >= 0)
867ded959eSSimon Glass 		return len / block_dev->blksz;
87f4d8de48SHenrik Nordström 	return -1;
88f4d8de48SHenrik Nordström }
89f4d8de48SHenrik Nordström 
90e161356bSSimon Glass #ifdef CONFIG_BLK
9140fd0508SSimon Glass int host_dev_bind(int devnum, char *filename)
9240fd0508SSimon Glass {
9340fd0508SSimon Glass 	struct host_block_dev *host_dev;
9440fd0508SSimon Glass 	struct udevice *dev;
9540fd0508SSimon Glass 	char dev_name[20], *str, *fname;
9640fd0508SSimon Glass 	int ret, fd;
9740fd0508SSimon Glass 
9840fd0508SSimon Glass 	/* Remove and unbind the old device, if any */
9940fd0508SSimon Glass 	ret = blk_get_device(IF_TYPE_HOST, devnum, &dev);
10040fd0508SSimon Glass 	if (ret == 0) {
101*706865afSStefan Roese 		ret = device_remove(dev, DM_REMOVE_NORMAL);
10240fd0508SSimon Glass 		if (ret)
10340fd0508SSimon Glass 			return ret;
10440fd0508SSimon Glass 		ret = device_unbind(dev);
10540fd0508SSimon Glass 		if (ret)
10640fd0508SSimon Glass 			return ret;
10740fd0508SSimon Glass 	} else if (ret != -ENODEV) {
10840fd0508SSimon Glass 		return ret;
10940fd0508SSimon Glass 	}
11040fd0508SSimon Glass 
11140fd0508SSimon Glass 	if (!filename)
11240fd0508SSimon Glass 		return 0;
11340fd0508SSimon Glass 
11440fd0508SSimon Glass 	snprintf(dev_name, sizeof(dev_name), "host%d", devnum);
11540fd0508SSimon Glass 	str = strdup(dev_name);
11640fd0508SSimon Glass 	if (!str)
11740fd0508SSimon Glass 		return -ENOMEM;
11840fd0508SSimon Glass 	fname = strdup(filename);
11940fd0508SSimon Glass 	if (!fname) {
12040fd0508SSimon Glass 		free(str);
12140fd0508SSimon Glass 		return -ENOMEM;
12240fd0508SSimon Glass 	}
12340fd0508SSimon Glass 
12440fd0508SSimon Glass 	fd = os_open(filename, OS_O_RDWR);
12540fd0508SSimon Glass 	if (fd == -1) {
12640fd0508SSimon Glass 		printf("Failed to access host backing file '%s'\n", filename);
12740fd0508SSimon Glass 		ret = -ENOENT;
12840fd0508SSimon Glass 		goto err;
12940fd0508SSimon Glass 	}
13040fd0508SSimon Glass 	ret = blk_create_device(gd->dm_root, "sandbox_host_blk", str,
13140fd0508SSimon Glass 				IF_TYPE_HOST, devnum, 512,
13240fd0508SSimon Glass 				os_lseek(fd, 0, OS_SEEK_END), &dev);
13340fd0508SSimon Glass 	if (ret)
13440fd0508SSimon Glass 		goto err_file;
13540fd0508SSimon Glass 	ret = device_probe(dev);
13640fd0508SSimon Glass 	if (ret) {
13740fd0508SSimon Glass 		device_unbind(dev);
13840fd0508SSimon Glass 		goto err_file;
13940fd0508SSimon Glass 	}
14040fd0508SSimon Glass 
14140fd0508SSimon Glass 	host_dev = dev_get_priv(dev);
14240fd0508SSimon Glass 	host_dev->fd = fd;
14340fd0508SSimon Glass 	host_dev->filename = fname;
14440fd0508SSimon Glass 
14540fd0508SSimon Glass 	return blk_prepare_device(dev);
14640fd0508SSimon Glass err_file:
14740fd0508SSimon Glass 	os_close(fd);
14840fd0508SSimon Glass err:
14940fd0508SSimon Glass 	free(fname);
15040fd0508SSimon Glass 	free(str);
15140fd0508SSimon Glass 	return ret;
15240fd0508SSimon Glass }
153e161356bSSimon Glass #else
154e161356bSSimon Glass int host_dev_bind(int dev, char *filename)
155e161356bSSimon Glass {
156e161356bSSimon Glass 	struct host_block_dev *host_dev = find_host_device(dev);
157e161356bSSimon Glass 
158e161356bSSimon Glass 	if (!host_dev)
159e161356bSSimon Glass 		return -1;
160e161356bSSimon Glass 	if (host_dev->blk_dev.priv) {
161e161356bSSimon Glass 		os_close(host_dev->fd);
162e161356bSSimon Glass 		host_dev->blk_dev.priv = NULL;
163e161356bSSimon Glass 	}
164e161356bSSimon Glass 	if (host_dev->filename)
165e161356bSSimon Glass 		free(host_dev->filename);
166e161356bSSimon Glass 	if (filename && *filename) {
167e161356bSSimon Glass 		host_dev->filename = strdup(filename);
168e161356bSSimon Glass 	} else {
169e161356bSSimon Glass 		host_dev->filename = NULL;
170e161356bSSimon Glass 		return 0;
171e161356bSSimon Glass 	}
172e161356bSSimon Glass 
173e161356bSSimon Glass 	host_dev->fd = os_open(host_dev->filename, OS_O_RDWR);
174e161356bSSimon Glass 	if (host_dev->fd == -1) {
175e161356bSSimon Glass 		printf("Failed to access host backing file '%s'\n",
176e161356bSSimon Glass 		       host_dev->filename);
177e161356bSSimon Glass 		return 1;
178e161356bSSimon Glass 	}
179e161356bSSimon Glass 
180e161356bSSimon Glass 	struct blk_desc *blk_dev = &host_dev->blk_dev;
181e161356bSSimon Glass 	blk_dev->if_type = IF_TYPE_HOST;
182e161356bSSimon Glass 	blk_dev->priv = host_dev;
183e161356bSSimon Glass 	blk_dev->blksz = 512;
184e161356bSSimon Glass 	blk_dev->lba = os_lseek(host_dev->fd, 0, OS_SEEK_END) / blk_dev->blksz;
185e161356bSSimon Glass 	blk_dev->block_read = host_block_read;
186e161356bSSimon Glass 	blk_dev->block_write = host_block_write;
187e161356bSSimon Glass 	blk_dev->devnum = dev;
188e161356bSSimon Glass 	blk_dev->part_type = PART_TYPE_UNKNOWN;
189e161356bSSimon Glass 	part_init(blk_dev);
190e161356bSSimon Glass 
191e161356bSSimon Glass 	return 0;
192e161356bSSimon Glass }
193e161356bSSimon Glass #endif
194f4d8de48SHenrik Nordström 
1957ded959eSSimon Glass int host_get_dev_err(int devnum, struct blk_desc **blk_devp)
196f4d8de48SHenrik Nordström {
197e161356bSSimon Glass #ifdef CONFIG_BLK
19840fd0508SSimon Glass 	struct udevice *dev;
19940fd0508SSimon Glass 	int ret;
20040fd0508SSimon Glass 
20140fd0508SSimon Glass 	ret = blk_get_device(IF_TYPE_HOST, devnum, &dev);
20240fd0508SSimon Glass 	if (ret)
20340fd0508SSimon Glass 		return ret;
20440fd0508SSimon Glass 	*blk_devp = dev_get_uclass_platdata(dev);
205e161356bSSimon Glass #else
206e161356bSSimon Glass 	struct host_block_dev *host_dev = find_host_device(devnum);
207e161356bSSimon Glass 
208e161356bSSimon Glass 	if (!host_dev)
209e161356bSSimon Glass 		return -ENODEV;
210e161356bSSimon Glass 
211e161356bSSimon Glass 	if (!host_dev->blk_dev.priv)
212e161356bSSimon Glass 		return -ENOENT;
213e161356bSSimon Glass 
214e161356bSSimon Glass 	*blk_devp = &host_dev->blk_dev;
215e161356bSSimon Glass #endif
21640fd0508SSimon Glass 
217f4d8de48SHenrik Nordström 	return 0;
218f4d8de48SHenrik Nordström }
219f4d8de48SHenrik Nordström 
220e161356bSSimon Glass #ifdef CONFIG_BLK
22140fd0508SSimon Glass static const struct blk_ops sandbox_host_blk_ops = {
22240fd0508SSimon Glass 	.read	= host_block_read,
22340fd0508SSimon Glass 	.write	= host_block_write,
22440fd0508SSimon Glass };
22540fd0508SSimon Glass 
22640fd0508SSimon Glass U_BOOT_DRIVER(sandbox_host_blk) = {
22740fd0508SSimon Glass 	.name		= "sandbox_host_blk",
22840fd0508SSimon Glass 	.id		= UCLASS_BLK,
22940fd0508SSimon Glass 	.ops		= &sandbox_host_blk_ops,
23040fd0508SSimon Glass 	.priv_auto_alloc_size	= sizeof(struct host_block_dev),
23140fd0508SSimon Glass };
2320cc65a7cSSimon Glass #else
2330cc65a7cSSimon Glass U_BOOT_LEGACY_BLK(sandbox_host) = {
2340cc65a7cSSimon Glass 	.if_typename	= "host",
2350cc65a7cSSimon Glass 	.if_type	= IF_TYPE_HOST,
2360cc65a7cSSimon Glass 	.max_devs	= CONFIG_HOST_MAX_DEVICES,
2370cc65a7cSSimon Glass 	.get_dev	= host_get_dev_err,
2380cc65a7cSSimon Glass };
239e161356bSSimon Glass #endif
240