xref: /rk3399_rockchip-uboot/drivers/dfu/dfu_mtd.c (revision 0bcaecc8ee67bca03ac7c620478fcf43788e9a58)
1*0bcaecc8SYifeng Zhao /*
2*0bcaecc8SYifeng Zhao  * (C) Copyright 2021 Rockchip Electronics Co., Ltd
3*0bcaecc8SYifeng Zhao  *
4*0bcaecc8SYifeng Zhao  * SPDX-License-Identifier:     GPL-2.0+
5*0bcaecc8SYifeng Zhao  */
6*0bcaecc8SYifeng Zhao #include <common.h>
7*0bcaecc8SYifeng Zhao #include <boot_rkimg.h>
8*0bcaecc8SYifeng Zhao #include <div64.h>
9*0bcaecc8SYifeng Zhao #include <dfu.h>
10*0bcaecc8SYifeng Zhao #include <errno.h>
11*0bcaecc8SYifeng Zhao #include <linux/mtd/mtd.h>
12*0bcaecc8SYifeng Zhao #include <malloc.h>
13*0bcaecc8SYifeng Zhao #include <part.h>
14*0bcaecc8SYifeng Zhao 
15*0bcaecc8SYifeng Zhao static int dfu_write_medium_mtd(struct dfu_entity *dfu,	u64 offset, void *buf, long *len)
16*0bcaecc8SYifeng Zhao {
17*0bcaecc8SYifeng Zhao 	struct blk_desc *dev_desc;
18*0bcaecc8SYifeng Zhao 	u64 block_start, block_len;
19*0bcaecc8SYifeng Zhao 	int ret = -ENODEV;
20*0bcaecc8SYifeng Zhao 
21*0bcaecc8SYifeng Zhao 	switch (dfu->layout) {
22*0bcaecc8SYifeng Zhao 	case DFU_RAW_ADDR:
23*0bcaecc8SYifeng Zhao 		/* if buf == NULL return total size of the area */
24*0bcaecc8SYifeng Zhao 		if (!buf) {
25*0bcaecc8SYifeng Zhao 			*len = dfu->data.nand.size;
26*0bcaecc8SYifeng Zhao 			return 0;
27*0bcaecc8SYifeng Zhao 		}
28*0bcaecc8SYifeng Zhao 
29*0bcaecc8SYifeng Zhao 		dev_desc = rockchip_get_bootdev();
30*0bcaecc8SYifeng Zhao 		if (!dev_desc) {
31*0bcaecc8SYifeng Zhao 			printf("%s: dev_desc is NULL!\n", __func__);
32*0bcaecc8SYifeng Zhao 			return -ENODEV;
33*0bcaecc8SYifeng Zhao 		}
34*0bcaecc8SYifeng Zhao 
35*0bcaecc8SYifeng Zhao 		/* in case of ubi partition, erase rest of the partition */
36*0bcaecc8SYifeng Zhao 		if (dfu->data.mtd.ubi && !offset) {
37*0bcaecc8SYifeng Zhao 			block_start = dfu->data.mtd.start >> 9;
38*0bcaecc8SYifeng Zhao 			block_len = dfu->data.mtd.size >> 9;
39*0bcaecc8SYifeng Zhao 
40*0bcaecc8SYifeng Zhao 			ret = blk_derase(dev_desc, block_start, block_len);
41*0bcaecc8SYifeng Zhao 			if (ret != 0)
42*0bcaecc8SYifeng Zhao 				printf("Failure erase: %d\n", ret);
43*0bcaecc8SYifeng Zhao 		}
44*0bcaecc8SYifeng Zhao 
45*0bcaecc8SYifeng Zhao 		block_start = (dfu->data.mtd.start + offset) >> 9;
46*0bcaecc8SYifeng Zhao 		block_len = (*len) >> 9;
47*0bcaecc8SYifeng Zhao 
48*0bcaecc8SYifeng Zhao 		ret = blk_dwrite(dev_desc, block_start, block_len, buf);
49*0bcaecc8SYifeng Zhao 		if (ret == block_len)
50*0bcaecc8SYifeng Zhao 			ret = 0;
51*0bcaecc8SYifeng Zhao 		break;
52*0bcaecc8SYifeng Zhao 	default:
53*0bcaecc8SYifeng Zhao 		printf("%s: Layout (%s) not (yet) supported!\n", __func__,
54*0bcaecc8SYifeng Zhao 		       dfu_get_layout(dfu->layout));
55*0bcaecc8SYifeng Zhao 	}
56*0bcaecc8SYifeng Zhao 
57*0bcaecc8SYifeng Zhao 	return ret;
58*0bcaecc8SYifeng Zhao }
59*0bcaecc8SYifeng Zhao 
60*0bcaecc8SYifeng Zhao static int dfu_get_medium_size_mtd(struct dfu_entity *dfu, u64 *size)
61*0bcaecc8SYifeng Zhao {
62*0bcaecc8SYifeng Zhao 	*size = dfu->data.mtd.size;
63*0bcaecc8SYifeng Zhao 
64*0bcaecc8SYifeng Zhao 	return 0;
65*0bcaecc8SYifeng Zhao }
66*0bcaecc8SYifeng Zhao 
67*0bcaecc8SYifeng Zhao static int dfu_read_medium_mtd(struct dfu_entity *dfu, u64 offset, void *buf, long *len)
68*0bcaecc8SYifeng Zhao {
69*0bcaecc8SYifeng Zhao 	struct blk_desc *dev_desc;
70*0bcaecc8SYifeng Zhao 	u64 block_start, block_len;
71*0bcaecc8SYifeng Zhao 	int ret = -ENODEV;
72*0bcaecc8SYifeng Zhao 
73*0bcaecc8SYifeng Zhao 	switch (dfu->layout) {
74*0bcaecc8SYifeng Zhao 	case DFU_RAW_ADDR:
75*0bcaecc8SYifeng Zhao 		/* if buf == NULL return total size of the area */
76*0bcaecc8SYifeng Zhao 		if (!buf) {
77*0bcaecc8SYifeng Zhao 			*len = dfu->data.nand.size;
78*0bcaecc8SYifeng Zhao 			return 0;
79*0bcaecc8SYifeng Zhao 		}
80*0bcaecc8SYifeng Zhao 
81*0bcaecc8SYifeng Zhao 		dev_desc = rockchip_get_bootdev();
82*0bcaecc8SYifeng Zhao 		if (!dev_desc) {
83*0bcaecc8SYifeng Zhao 			printf("%s: dev_desc is NULL!\n", __func__);
84*0bcaecc8SYifeng Zhao 			return -ENODEV;
85*0bcaecc8SYifeng Zhao 		}
86*0bcaecc8SYifeng Zhao 
87*0bcaecc8SYifeng Zhao 		block_start = (dfu->data.mtd.start + offset) >> 9;
88*0bcaecc8SYifeng Zhao 		block_len = (*len) >> 9;
89*0bcaecc8SYifeng Zhao 
90*0bcaecc8SYifeng Zhao 		ret = blk_dread(dev_desc, block_start, block_len, buf);
91*0bcaecc8SYifeng Zhao 		if (ret == block_len)
92*0bcaecc8SYifeng Zhao 			ret = 0;
93*0bcaecc8SYifeng Zhao 		break;
94*0bcaecc8SYifeng Zhao 	default:
95*0bcaecc8SYifeng Zhao 		printf("%s: Layout (%s) not (yet) supported!\n", __func__,
96*0bcaecc8SYifeng Zhao 		       dfu_get_layout(dfu->layout));
97*0bcaecc8SYifeng Zhao 	}
98*0bcaecc8SYifeng Zhao 
99*0bcaecc8SYifeng Zhao 	return ret;
100*0bcaecc8SYifeng Zhao }
101*0bcaecc8SYifeng Zhao 
102*0bcaecc8SYifeng Zhao static int dfu_flush_medium_mtd(struct dfu_entity *dfu)
103*0bcaecc8SYifeng Zhao {
104*0bcaecc8SYifeng Zhao 	return 0;
105*0bcaecc8SYifeng Zhao }
106*0bcaecc8SYifeng Zhao 
107*0bcaecc8SYifeng Zhao unsigned int dfu_polltimeout_mtd(struct dfu_entity *dfu)
108*0bcaecc8SYifeng Zhao {
109*0bcaecc8SYifeng Zhao 	/*
110*0bcaecc8SYifeng Zhao 	 * Currently, Poll Timeout != 0 is only needed on nand
111*0bcaecc8SYifeng Zhao 	 * ubi partition, as the not used sectors need an erase
112*0bcaecc8SYifeng Zhao 	 */
113*0bcaecc8SYifeng Zhao 	if (dfu->data.mtd.ubi)
114*0bcaecc8SYifeng Zhao 		return DFU_MANIFEST_POLL_TIMEOUT;
115*0bcaecc8SYifeng Zhao 
116*0bcaecc8SYifeng Zhao 	return DFU_DEFAULT_POLL_TIMEOUT;
117*0bcaecc8SYifeng Zhao }
118*0bcaecc8SYifeng Zhao 
119*0bcaecc8SYifeng Zhao int dfu_fill_entity_mtd(struct dfu_entity *dfu, char *devstr, char *s)
120*0bcaecc8SYifeng Zhao {
121*0bcaecc8SYifeng Zhao 	struct blk_desc *dev_desc;
122*0bcaecc8SYifeng Zhao 	disk_partition_t dfu_part;
123*0bcaecc8SYifeng Zhao 	char *st;
124*0bcaecc8SYifeng Zhao 
125*0bcaecc8SYifeng Zhao 	dfu->data.mtd.ubi = 0;
126*0bcaecc8SYifeng Zhao 	dfu->dev_type = DFU_DEV_MTD;
127*0bcaecc8SYifeng Zhao 	st = strsep(&s, " ");
128*0bcaecc8SYifeng Zhao 
129*0bcaecc8SYifeng Zhao 	if (!strcmp(st, "raw")) {
130*0bcaecc8SYifeng Zhao 		dfu->layout = DFU_RAW_ADDR;
131*0bcaecc8SYifeng Zhao 		dfu->data.mtd.start = simple_strtoul(s, &s, 16);
132*0bcaecc8SYifeng Zhao 		s++;
133*0bcaecc8SYifeng Zhao 		dfu->data.mtd.size = simple_strtoul(s, &s, 16);
134*0bcaecc8SYifeng Zhao 	} else if ((!strcmp(st, "part")) || (!strcmp(st, "partubi"))) {
135*0bcaecc8SYifeng Zhao 		dev_desc = rockchip_get_bootdev();
136*0bcaecc8SYifeng Zhao 		if (!dev_desc) {
137*0bcaecc8SYifeng Zhao 			printf("%s: dev_desc is NULL!\n", __func__);
138*0bcaecc8SYifeng Zhao 			return -ENODEV;
139*0bcaecc8SYifeng Zhao 		}
140*0bcaecc8SYifeng Zhao 		dfu->layout = DFU_RAW_ADDR;
141*0bcaecc8SYifeng Zhao 		if (part_get_info_by_name(dev_desc, s, &dfu_part) < 0)
142*0bcaecc8SYifeng Zhao 			return -EIO;
143*0bcaecc8SYifeng Zhao 
144*0bcaecc8SYifeng Zhao 		dfu->data.mtd.start = dfu_part.start << 9;
145*0bcaecc8SYifeng Zhao 		dfu->data.mtd.size = dfu_part.size << 9;
146*0bcaecc8SYifeng Zhao 		if (!strcmp(st, "partubi"))
147*0bcaecc8SYifeng Zhao 			dfu->data.mtd.ubi = 1;
148*0bcaecc8SYifeng Zhao 	} else {
149*0bcaecc8SYifeng Zhao 		printf("%s: Memory layout (%s) not supported!\n", __func__, st);
150*0bcaecc8SYifeng Zhao 		return -1;
151*0bcaecc8SYifeng Zhao 	}
152*0bcaecc8SYifeng Zhao 
153*0bcaecc8SYifeng Zhao 	dfu->get_medium_size = dfu_get_medium_size_mtd;
154*0bcaecc8SYifeng Zhao 	dfu->read_medium = dfu_read_medium_mtd;
155*0bcaecc8SYifeng Zhao 	dfu->write_medium = dfu_write_medium_mtd;
156*0bcaecc8SYifeng Zhao 	dfu->flush_medium = dfu_flush_medium_mtd;
157*0bcaecc8SYifeng Zhao 	dfu->poll_timeout = dfu_polltimeout_mtd;
158*0bcaecc8SYifeng Zhao 
159*0bcaecc8SYifeng Zhao 	/* initial state */
160*0bcaecc8SYifeng Zhao 	dfu->inited = 0;
161*0bcaecc8SYifeng Zhao 
162*0bcaecc8SYifeng Zhao 	return 0;
163*0bcaecc8SYifeng Zhao }
164