xref: /rk3399_rockchip-uboot/drivers/dfu/dfu_mtd.c (revision 42bb6aac60fa789c9daa873d3e572eea186533f8)
10bcaecc8SYifeng Zhao /*
20bcaecc8SYifeng Zhao  * (C) Copyright 2021 Rockchip Electronics Co., Ltd
30bcaecc8SYifeng Zhao  *
40bcaecc8SYifeng Zhao  * SPDX-License-Identifier:     GPL-2.0+
50bcaecc8SYifeng Zhao  */
60bcaecc8SYifeng Zhao #include <common.h>
70bcaecc8SYifeng Zhao #include <boot_rkimg.h>
80bcaecc8SYifeng Zhao #include <div64.h>
90bcaecc8SYifeng Zhao #include <dfu.h>
100bcaecc8SYifeng Zhao #include <errno.h>
110bcaecc8SYifeng Zhao #include <linux/mtd/mtd.h>
120bcaecc8SYifeng Zhao #include <malloc.h>
130bcaecc8SYifeng Zhao #include <part.h>
140bcaecc8SYifeng Zhao 
dfu_write_medium_mtd(struct dfu_entity * dfu,u64 offset,void * buf,long * len)150bcaecc8SYifeng Zhao static int dfu_write_medium_mtd(struct dfu_entity *dfu,	u64 offset, void *buf, long *len)
160bcaecc8SYifeng Zhao {
170bcaecc8SYifeng Zhao 	struct blk_desc *dev_desc;
180bcaecc8SYifeng Zhao 	u64 block_start, block_len;
190bcaecc8SYifeng Zhao 	int ret = -ENODEV;
200bcaecc8SYifeng Zhao 
210bcaecc8SYifeng Zhao 	switch (dfu->layout) {
220bcaecc8SYifeng Zhao 	case DFU_RAW_ADDR:
230bcaecc8SYifeng Zhao 		/* if buf == NULL return total size of the area */
240bcaecc8SYifeng Zhao 		if (!buf) {
250bcaecc8SYifeng Zhao 			*len = dfu->data.nand.size;
260bcaecc8SYifeng Zhao 			return 0;
270bcaecc8SYifeng Zhao 		}
280bcaecc8SYifeng Zhao 
290bcaecc8SYifeng Zhao 		dev_desc = rockchip_get_bootdev();
300bcaecc8SYifeng Zhao 		if (!dev_desc) {
310bcaecc8SYifeng Zhao 			printf("%s: dev_desc is NULL!\n", __func__);
320bcaecc8SYifeng Zhao 			return -ENODEV;
330bcaecc8SYifeng Zhao 		}
340bcaecc8SYifeng Zhao 
350bcaecc8SYifeng Zhao 		/* in case of ubi partition, erase rest of the partition */
360bcaecc8SYifeng Zhao 		if (dfu->data.mtd.ubi && !offset) {
370bcaecc8SYifeng Zhao 			block_start = dfu->data.mtd.start >> 9;
380bcaecc8SYifeng Zhao 			block_len = dfu->data.mtd.size >> 9;
390bcaecc8SYifeng Zhao 
400bcaecc8SYifeng Zhao 			ret = blk_derase(dev_desc, block_start, block_len);
410bcaecc8SYifeng Zhao 			if (ret != 0)
420bcaecc8SYifeng Zhao 				printf("Failure erase: %d\n", ret);
430bcaecc8SYifeng Zhao 		}
440bcaecc8SYifeng Zhao 
450bcaecc8SYifeng Zhao 		block_start = (dfu->data.mtd.start + offset) >> 9;
460bcaecc8SYifeng Zhao 		block_len = (*len) >> 9;
470bcaecc8SYifeng Zhao 
480bcaecc8SYifeng Zhao 		ret = blk_dwrite(dev_desc, block_start, block_len, buf);
490bcaecc8SYifeng Zhao 		if (ret == block_len)
500bcaecc8SYifeng Zhao 			ret = 0;
510bcaecc8SYifeng Zhao 		break;
520bcaecc8SYifeng Zhao 	default:
530bcaecc8SYifeng Zhao 		printf("%s: Layout (%s) not (yet) supported!\n", __func__,
540bcaecc8SYifeng Zhao 		       dfu_get_layout(dfu->layout));
550bcaecc8SYifeng Zhao 	}
560bcaecc8SYifeng Zhao 
570bcaecc8SYifeng Zhao 	return ret;
580bcaecc8SYifeng Zhao }
590bcaecc8SYifeng Zhao 
dfu_get_medium_size_mtd(struct dfu_entity * dfu,u64 * size)600bcaecc8SYifeng Zhao static int dfu_get_medium_size_mtd(struct dfu_entity *dfu, u64 *size)
610bcaecc8SYifeng Zhao {
620bcaecc8SYifeng Zhao 	*size = dfu->data.mtd.size;
630bcaecc8SYifeng Zhao 
640bcaecc8SYifeng Zhao 	return 0;
650bcaecc8SYifeng Zhao }
660bcaecc8SYifeng Zhao 
dfu_read_medium_mtd(struct dfu_entity * dfu,u64 offset,void * buf,long * len)670bcaecc8SYifeng Zhao static int dfu_read_medium_mtd(struct dfu_entity *dfu, u64 offset, void *buf, long *len)
680bcaecc8SYifeng Zhao {
690bcaecc8SYifeng Zhao 	struct blk_desc *dev_desc;
700bcaecc8SYifeng Zhao 	u64 block_start, block_len;
710bcaecc8SYifeng Zhao 	int ret = -ENODEV;
720bcaecc8SYifeng Zhao 
730bcaecc8SYifeng Zhao 	switch (dfu->layout) {
740bcaecc8SYifeng Zhao 	case DFU_RAW_ADDR:
750bcaecc8SYifeng Zhao 		/* if buf == NULL return total size of the area */
760bcaecc8SYifeng Zhao 		if (!buf) {
770bcaecc8SYifeng Zhao 			*len = dfu->data.nand.size;
780bcaecc8SYifeng Zhao 			return 0;
790bcaecc8SYifeng Zhao 		}
800bcaecc8SYifeng Zhao 
810bcaecc8SYifeng Zhao 		dev_desc = rockchip_get_bootdev();
820bcaecc8SYifeng Zhao 		if (!dev_desc) {
830bcaecc8SYifeng Zhao 			printf("%s: dev_desc is NULL!\n", __func__);
840bcaecc8SYifeng Zhao 			return -ENODEV;
850bcaecc8SYifeng Zhao 		}
860bcaecc8SYifeng Zhao 
870bcaecc8SYifeng Zhao 		block_start = (dfu->data.mtd.start + offset) >> 9;
880bcaecc8SYifeng Zhao 		block_len = (*len) >> 9;
890bcaecc8SYifeng Zhao 
900bcaecc8SYifeng Zhao 		ret = blk_dread(dev_desc, block_start, block_len, buf);
910bcaecc8SYifeng Zhao 		if (ret == block_len)
920bcaecc8SYifeng Zhao 			ret = 0;
930bcaecc8SYifeng Zhao 		break;
940bcaecc8SYifeng Zhao 	default:
950bcaecc8SYifeng Zhao 		printf("%s: Layout (%s) not (yet) supported!\n", __func__,
960bcaecc8SYifeng Zhao 		       dfu_get_layout(dfu->layout));
970bcaecc8SYifeng Zhao 	}
980bcaecc8SYifeng Zhao 
990bcaecc8SYifeng Zhao 	return ret;
1000bcaecc8SYifeng Zhao }
1010bcaecc8SYifeng Zhao 
dfu_flush_medium_mtd(struct dfu_entity * dfu)1020bcaecc8SYifeng Zhao static int dfu_flush_medium_mtd(struct dfu_entity *dfu)
1030bcaecc8SYifeng Zhao {
1040bcaecc8SYifeng Zhao 	return 0;
1050bcaecc8SYifeng Zhao }
1060bcaecc8SYifeng Zhao 
dfu_polltimeout_mtd(struct dfu_entity * dfu)1070bcaecc8SYifeng Zhao unsigned int dfu_polltimeout_mtd(struct dfu_entity *dfu)
1080bcaecc8SYifeng Zhao {
1090bcaecc8SYifeng Zhao 	/*
1100bcaecc8SYifeng Zhao 	 * Currently, Poll Timeout != 0 is only needed on nand
1110bcaecc8SYifeng Zhao 	 * ubi partition, as the not used sectors need an erase
1120bcaecc8SYifeng Zhao 	 */
1130bcaecc8SYifeng Zhao 	if (dfu->data.mtd.ubi)
1140bcaecc8SYifeng Zhao 		return DFU_MANIFEST_POLL_TIMEOUT;
1150bcaecc8SYifeng Zhao 
1160bcaecc8SYifeng Zhao 	return DFU_DEFAULT_POLL_TIMEOUT;
1170bcaecc8SYifeng Zhao }
1180bcaecc8SYifeng Zhao 
dfu_fill_entity_mtd(struct dfu_entity * dfu,char * devstr,char * s)1190bcaecc8SYifeng Zhao int dfu_fill_entity_mtd(struct dfu_entity *dfu, char *devstr, char *s)
1200bcaecc8SYifeng Zhao {
1210bcaecc8SYifeng Zhao 	struct blk_desc *dev_desc;
1220bcaecc8SYifeng Zhao 	disk_partition_t dfu_part;
1230bcaecc8SYifeng Zhao 	char *st;
1240bcaecc8SYifeng Zhao 
1250bcaecc8SYifeng Zhao 	dfu->data.mtd.ubi = 0;
1260bcaecc8SYifeng Zhao 	dfu->dev_type = DFU_DEV_MTD;
1270bcaecc8SYifeng Zhao 	st = strsep(&s, " ");
1280bcaecc8SYifeng Zhao 
129*42bb6aacSTony Xu 	if (!strcmp(st, "raw") || !strcmp(st, "rawubi")) {
1300bcaecc8SYifeng Zhao 		dfu->layout = DFU_RAW_ADDR;
1310bcaecc8SYifeng Zhao 		dfu->data.mtd.start = simple_strtoul(s, &s, 16);
1320bcaecc8SYifeng Zhao 		s++;
1330bcaecc8SYifeng Zhao 		dfu->data.mtd.size = simple_strtoul(s, &s, 16);
134*42bb6aacSTony Xu 		if (!strcmp(st, "rawubi"))
135*42bb6aacSTony Xu 			dfu->data.mtd.ubi = 1;
1360bcaecc8SYifeng Zhao 	} else if ((!strcmp(st, "part")) || (!strcmp(st, "partubi"))) {
1370bcaecc8SYifeng Zhao 		dev_desc = rockchip_get_bootdev();
1380bcaecc8SYifeng Zhao 		if (!dev_desc) {
1390bcaecc8SYifeng Zhao 			printf("%s: dev_desc is NULL!\n", __func__);
1400bcaecc8SYifeng Zhao 			return -ENODEV;
1410bcaecc8SYifeng Zhao 		}
1420bcaecc8SYifeng Zhao 		dfu->layout = DFU_RAW_ADDR;
1430bcaecc8SYifeng Zhao 		if (part_get_info_by_name(dev_desc, s, &dfu_part) < 0)
1440bcaecc8SYifeng Zhao 			return -EIO;
1450bcaecc8SYifeng Zhao 
1460bcaecc8SYifeng Zhao 		dfu->data.mtd.start = dfu_part.start << 9;
1470bcaecc8SYifeng Zhao 		dfu->data.mtd.size = dfu_part.size << 9;
1480bcaecc8SYifeng Zhao 		if (!strcmp(st, "partubi"))
1490bcaecc8SYifeng Zhao 			dfu->data.mtd.ubi = 1;
1500bcaecc8SYifeng Zhao 	} else {
1510bcaecc8SYifeng Zhao 		printf("%s: Memory layout (%s) not supported!\n", __func__, st);
1520bcaecc8SYifeng Zhao 		return -1;
1530bcaecc8SYifeng Zhao 	}
1540bcaecc8SYifeng Zhao 
1550bcaecc8SYifeng Zhao 	dfu->get_medium_size = dfu_get_medium_size_mtd;
1560bcaecc8SYifeng Zhao 	dfu->read_medium = dfu_read_medium_mtd;
1570bcaecc8SYifeng Zhao 	dfu->write_medium = dfu_write_medium_mtd;
1580bcaecc8SYifeng Zhao 	dfu->flush_medium = dfu_flush_medium_mtd;
1590bcaecc8SYifeng Zhao 	dfu->poll_timeout = dfu_polltimeout_mtd;
1600bcaecc8SYifeng Zhao 
1610bcaecc8SYifeng Zhao 	/* initial state */
1620bcaecc8SYifeng Zhao 	dfu->inited = 0;
1630bcaecc8SYifeng Zhao 
1640bcaecc8SYifeng Zhao 	return 0;
1650bcaecc8SYifeng Zhao }
166