xref: /rk3399_rockchip-uboot/drivers/dfu/dfu_mmc.c (revision 7d0b605abb1f2dbccf4abb502f3b1fc9f97f2552)
1cb383cd2SLukasz Majewski /*
2cb383cd2SLukasz Majewski  * dfu.c -- DFU back-end routines
3cb383cd2SLukasz Majewski  *
4cb383cd2SLukasz Majewski  * Copyright (C) 2012 Samsung Electronics
5cb383cd2SLukasz Majewski  * author: Lukasz Majewski <l.majewski@samsung.com>
6cb383cd2SLukasz Majewski  *
71a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
8cb383cd2SLukasz Majewski  */
9cb383cd2SLukasz Majewski 
10cb383cd2SLukasz Majewski #include <common.h>
11cb383cd2SLukasz Majewski #include <malloc.h>
121b6ca18bSPantelis Antoniou #include <errno.h>
13ea2453d5SPantelis Antoniou #include <div64.h>
14cb383cd2SLukasz Majewski #include <dfu.h>
15*7d0b605aSŁukasz Majewski #include <mmc.h>
16cb383cd2SLukasz Majewski 
17ea2453d5SPantelis Antoniou static unsigned char __aligned(CONFIG_SYS_CACHELINE_SIZE)
18ea2453d5SPantelis Antoniou 				dfu_file_buf[CONFIG_SYS_DFU_MAX_FILE_SIZE];
19ea2453d5SPantelis Antoniou static long dfu_file_buf_len;
20ea2453d5SPantelis Antoniou 
215a127c84SAfzal Mohammed static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu,
22ea2453d5SPantelis Antoniou 			u64 offset, void *buf, long *len)
23cb383cd2SLukasz Majewski {
24*7d0b605aSŁukasz Majewski 	struct mmc *mmc = find_mmc_device(dfu->dev_num);
25*7d0b605aSŁukasz Majewski 	u32 blk_start, blk_count, n = 0;
26cb383cd2SLukasz Majewski 
27ea2453d5SPantelis Antoniou 	/*
28ea2453d5SPantelis Antoniou 	 * We must ensure that we work in lba_blk_size chunks, so ALIGN
29ea2453d5SPantelis Antoniou 	 * this value.
30ea2453d5SPantelis Antoniou 	 */
31ea2453d5SPantelis Antoniou 	*len = ALIGN(*len, dfu->data.mmc.lba_blk_size);
32ea2453d5SPantelis Antoniou 
33ea2453d5SPantelis Antoniou 	blk_start = dfu->data.mmc.lba_start +
34ea2453d5SPantelis Antoniou 			(u32)lldiv(offset, dfu->data.mmc.lba_blk_size);
35ea2453d5SPantelis Antoniou 	blk_count = *len / dfu->data.mmc.lba_blk_size;
36ea2453d5SPantelis Antoniou 	if (blk_start + blk_count >
37ea2453d5SPantelis Antoniou 			dfu->data.mmc.lba_start + dfu->data.mmc.lba_size) {
38ea2453d5SPantelis Antoniou 		puts("Request would exceed designated area!\n");
39ea2453d5SPantelis Antoniou 		return -EINVAL;
40ea2453d5SPantelis Antoniou 	}
41ea2453d5SPantelis Antoniou 
42*7d0b605aSŁukasz Majewski 	debug("%s: %s dev: %d start: %d cnt: %d buf: 0x%p\n", __func__,
43*7d0b605aSŁukasz Majewski 	      op == DFU_OP_READ ? "MMC READ" : "MMC WRITE", dfu->dev_num,
44*7d0b605aSŁukasz Majewski 	      blk_start, blk_count, buf);
45*7d0b605aSŁukasz Majewski 	switch (op) {
46*7d0b605aSŁukasz Majewski 	case DFU_OP_READ:
47*7d0b605aSŁukasz Majewski 		n = mmc->block_dev.block_read(dfu->dev_num, blk_start,
48*7d0b605aSŁukasz Majewski 					      blk_count, buf);
49*7d0b605aSŁukasz Majewski 		break;
50*7d0b605aSŁukasz Majewski 	case DFU_OP_WRITE:
51*7d0b605aSŁukasz Majewski 		n = mmc->block_dev.block_write(dfu->dev_num, blk_start,
52*7d0b605aSŁukasz Majewski 					       blk_count, buf);
53*7d0b605aSŁukasz Majewski 		break;
54*7d0b605aSŁukasz Majewski 	default:
55*7d0b605aSŁukasz Majewski 		error("Operation not supported\n");
56*7d0b605aSŁukasz Majewski 	}
57cb383cd2SLukasz Majewski 
58*7d0b605aSŁukasz Majewski 	if (n != blk_count) {
59*7d0b605aSŁukasz Majewski 		error("MMC operation failed");
60*7d0b605aSŁukasz Majewski 		return -EIO;
61*7d0b605aSŁukasz Majewski 	}
62*7d0b605aSŁukasz Majewski 
63*7d0b605aSŁukasz Majewski 	return 0;
64cb383cd2SLukasz Majewski }
65cb383cd2SLukasz Majewski 
66ea2453d5SPantelis Antoniou static int mmc_file_buffer(struct dfu_entity *dfu, void *buf, long *len)
67cb383cd2SLukasz Majewski {
68ea2453d5SPantelis Antoniou 	if (dfu_file_buf_len + *len > CONFIG_SYS_DFU_MAX_FILE_SIZE) {
69ea2453d5SPantelis Antoniou 		dfu_file_buf_len = 0;
70ea2453d5SPantelis Antoniou 		return -EINVAL;
71cb383cd2SLukasz Majewski 	}
72cb383cd2SLukasz Majewski 
73ea2453d5SPantelis Antoniou 	/* Add to the current buffer. */
74ea2453d5SPantelis Antoniou 	memcpy(dfu_file_buf + dfu_file_buf_len, buf, *len);
75ea2453d5SPantelis Antoniou 	dfu_file_buf_len += *len;
76ea2453d5SPantelis Antoniou 
77ea2453d5SPantelis Antoniou 	return 0;
78cb383cd2SLukasz Majewski }
79cb383cd2SLukasz Majewski 
805a127c84SAfzal Mohammed static int mmc_file_op(enum dfu_op op, struct dfu_entity *dfu,
81cb383cd2SLukasz Majewski 			void *buf, long *len)
82cb383cd2SLukasz Majewski {
83cb383cd2SLukasz Majewski 	char cmd_buf[DFU_CMD_BUF_SIZE];
84cb383cd2SLukasz Majewski 	char *str_env;
85cb383cd2SLukasz Majewski 	int ret;
86cb383cd2SLukasz Majewski 
8743e66272SŁukasz Majewski 	switch (dfu->layout) {
8843e66272SŁukasz Majewski 	case DFU_FS_FAT:
89ea2453d5SPantelis Antoniou 		sprintf(cmd_buf, "fat%s mmc %d:%d 0x%x %s",
90cb383cd2SLukasz Majewski 			op == DFU_OP_READ ? "load" : "write",
91cb383cd2SLukasz Majewski 			dfu->data.mmc.dev, dfu->data.mmc.part,
92ea2453d5SPantelis Antoniou 			(unsigned int) buf, dfu->name);
9343e66272SŁukasz Majewski 		break;
9443e66272SŁukasz Majewski 	case DFU_FS_EXT4:
95ea2453d5SPantelis Antoniou 		sprintf(cmd_buf, "ext4%s mmc %d:%d 0x%x /%s",
9643e66272SŁukasz Majewski 			op == DFU_OP_READ ? "load" : "write",
9743e66272SŁukasz Majewski 			dfu->data.mmc.dev, dfu->data.mmc.part,
98ea2453d5SPantelis Antoniou 			(unsigned int) buf, dfu->name);
9943e66272SŁukasz Majewski 		break;
10043e66272SŁukasz Majewski 	default:
10143e66272SŁukasz Majewski 		printf("%s: Layout (%s) not (yet) supported!\n", __func__,
10243e66272SŁukasz Majewski 		       dfu_get_layout(dfu->layout));
103ea2453d5SPantelis Antoniou 		return -1;
10443e66272SŁukasz Majewski 	}
105cb383cd2SLukasz Majewski 
10617eb1d8fSLukasz Majewski 	if (op == DFU_OP_WRITE)
10717eb1d8fSLukasz Majewski 		sprintf(cmd_buf + strlen(cmd_buf), " %lx", *len);
10817eb1d8fSLukasz Majewski 
109cb383cd2SLukasz Majewski 	debug("%s: %s 0x%p\n", __func__, cmd_buf, cmd_buf);
110cb383cd2SLukasz Majewski 
111cb383cd2SLukasz Majewski 	ret = run_command(cmd_buf, 0);
112cb383cd2SLukasz Majewski 	if (ret) {
113cb383cd2SLukasz Majewski 		puts("dfu: Read error!\n");
114cb383cd2SLukasz Majewski 		return ret;
115cb383cd2SLukasz Majewski 	}
116cb383cd2SLukasz Majewski 
11781c1d7b6SŁukasz Majewski 	if (dfu->layout != DFU_RAW_ADDR && op == DFU_OP_READ) {
118cb383cd2SLukasz Majewski 		str_env = getenv("filesize");
119cb383cd2SLukasz Majewski 		if (str_env == NULL) {
120cb383cd2SLukasz Majewski 			puts("dfu: Wrong file size!\n");
121cb383cd2SLukasz Majewski 			return -1;
122cb383cd2SLukasz Majewski 		}
123cb383cd2SLukasz Majewski 		*len = simple_strtoul(str_env, NULL, 16);
124cb383cd2SLukasz Majewski 	}
125cb383cd2SLukasz Majewski 
126cb383cd2SLukasz Majewski 	return ret;
127cb383cd2SLukasz Majewski }
128cb383cd2SLukasz Majewski 
129ea2453d5SPantelis Antoniou int dfu_write_medium_mmc(struct dfu_entity *dfu,
130ea2453d5SPantelis Antoniou 		u64 offset, void *buf, long *len)
131cb383cd2SLukasz Majewski {
132cb383cd2SLukasz Majewski 	int ret = -1;
133cb383cd2SLukasz Majewski 
134cb383cd2SLukasz Majewski 	switch (dfu->layout) {
135cb383cd2SLukasz Majewski 	case DFU_RAW_ADDR:
136ea2453d5SPantelis Antoniou 		ret = mmc_block_op(DFU_OP_WRITE, dfu, offset, buf, len);
137cb383cd2SLukasz Majewski 		break;
138cb383cd2SLukasz Majewski 	case DFU_FS_FAT:
13943e66272SŁukasz Majewski 	case DFU_FS_EXT4:
140ea2453d5SPantelis Antoniou 		ret = mmc_file_buffer(dfu, buf, len);
141cb383cd2SLukasz Majewski 		break;
142cb383cd2SLukasz Majewski 	default:
143cb383cd2SLukasz Majewski 		printf("%s: Layout (%s) not (yet) supported!\n", __func__,
144cb383cd2SLukasz Majewski 		       dfu_get_layout(dfu->layout));
145cb383cd2SLukasz Majewski 	}
146cb383cd2SLukasz Majewski 
147cb383cd2SLukasz Majewski 	return ret;
148cb383cd2SLukasz Majewski }
149cb383cd2SLukasz Majewski 
150ea2453d5SPantelis Antoniou int dfu_flush_medium_mmc(struct dfu_entity *dfu)
151ea2453d5SPantelis Antoniou {
152ea2453d5SPantelis Antoniou 	int ret = 0;
153ea2453d5SPantelis Antoniou 
154ea2453d5SPantelis Antoniou 	if (dfu->layout != DFU_RAW_ADDR) {
155ea2453d5SPantelis Antoniou 		/* Do stuff here. */
156ea2453d5SPantelis Antoniou 		ret = mmc_file_op(DFU_OP_WRITE, dfu, &dfu_file_buf,
157ea2453d5SPantelis Antoniou 				&dfu_file_buf_len);
158ea2453d5SPantelis Antoniou 
159ea2453d5SPantelis Antoniou 		/* Now that we're done */
160ea2453d5SPantelis Antoniou 		dfu_file_buf_len = 0;
161ea2453d5SPantelis Antoniou 	}
162ea2453d5SPantelis Antoniou 
163ea2453d5SPantelis Antoniou 	return ret;
164ea2453d5SPantelis Antoniou }
165ea2453d5SPantelis Antoniou 
166ea2453d5SPantelis Antoniou int dfu_read_medium_mmc(struct dfu_entity *dfu, u64 offset, void *buf,
167ea2453d5SPantelis Antoniou 		long *len)
168cb383cd2SLukasz Majewski {
169cb383cd2SLukasz Majewski 	int ret = -1;
170cb383cd2SLukasz Majewski 
171cb383cd2SLukasz Majewski 	switch (dfu->layout) {
172cb383cd2SLukasz Majewski 	case DFU_RAW_ADDR:
173ea2453d5SPantelis Antoniou 		ret = mmc_block_op(DFU_OP_READ, dfu, offset, buf, len);
174cb383cd2SLukasz Majewski 		break;
175cb383cd2SLukasz Majewski 	case DFU_FS_FAT:
17643e66272SŁukasz Majewski 	case DFU_FS_EXT4:
177ea2453d5SPantelis Antoniou 		ret = mmc_file_op(DFU_OP_READ, dfu, buf, len);
178cb383cd2SLukasz Majewski 		break;
179cb383cd2SLukasz Majewski 	default:
180cb383cd2SLukasz Majewski 		printf("%s: Layout (%s) not (yet) supported!\n", __func__,
181cb383cd2SLukasz Majewski 		       dfu_get_layout(dfu->layout));
182cb383cd2SLukasz Majewski 	}
183cb383cd2SLukasz Majewski 
184cb383cd2SLukasz Majewski 	return ret;
185cb383cd2SLukasz Majewski }
186cb383cd2SLukasz Majewski 
187cb383cd2SLukasz Majewski int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *s)
188cb383cd2SLukasz Majewski {
1891b6ca18bSPantelis Antoniou 	int dev, part;
1901b6ca18bSPantelis Antoniou 	struct mmc *mmc;
1911b6ca18bSPantelis Antoniou 	block_dev_desc_t *blk_dev;
1921b6ca18bSPantelis Antoniou 	disk_partition_t partinfo;
193cb383cd2SLukasz Majewski 	char *st;
194cb383cd2SLukasz Majewski 
195cb383cd2SLukasz Majewski 	dfu->dev_type = DFU_DEV_MMC;
196cb383cd2SLukasz Majewski 	st = strsep(&s, " ");
197cb383cd2SLukasz Majewski 	if (!strcmp(st, "mmc")) {
198cb383cd2SLukasz Majewski 		dfu->layout = DFU_RAW_ADDR;
199cb383cd2SLukasz Majewski 		dfu->data.mmc.lba_start = simple_strtoul(s, &s, 16);
200cb383cd2SLukasz Majewski 		dfu->data.mmc.lba_size = simple_strtoul(++s, &s, 16);
201cb383cd2SLukasz Majewski 		dfu->data.mmc.lba_blk_size = get_mmc_blk_size(dfu->dev_num);
202cb383cd2SLukasz Majewski 	} else if (!strcmp(st, "fat")) {
203cb383cd2SLukasz Majewski 		dfu->layout = DFU_FS_FAT;
20443e66272SŁukasz Majewski 	} else if (!strcmp(st, "ext4")) {
20543e66272SŁukasz Majewski 		dfu->layout = DFU_FS_EXT4;
2061b6ca18bSPantelis Antoniou 	} else if (!strcmp(st, "part")) {
2071b6ca18bSPantelis Antoniou 
2081b6ca18bSPantelis Antoniou 		dfu->layout = DFU_RAW_ADDR;
2091b6ca18bSPantelis Antoniou 
2101b6ca18bSPantelis Antoniou 		dev = simple_strtoul(s, &s, 10);
2111b6ca18bSPantelis Antoniou 		s++;
2121b6ca18bSPantelis Antoniou 		part = simple_strtoul(s, &s, 10);
2131b6ca18bSPantelis Antoniou 
2141b6ca18bSPantelis Antoniou 		mmc = find_mmc_device(dev);
2151b6ca18bSPantelis Antoniou 		if (mmc == NULL || mmc_init(mmc)) {
216ea2453d5SPantelis Antoniou 			printf("%s: could not find mmc device #%d!\n",
217ea2453d5SPantelis Antoniou 			       __func__, dev);
2181b6ca18bSPantelis Antoniou 			return -ENODEV;
2191b6ca18bSPantelis Antoniou 		}
2201b6ca18bSPantelis Antoniou 
2211b6ca18bSPantelis Antoniou 		blk_dev = &mmc->block_dev;
2221b6ca18bSPantelis Antoniou 		if (get_partition_info(blk_dev, part, &partinfo) != 0) {
2231b6ca18bSPantelis Antoniou 			printf("%s: could not find partition #%d on mmc device #%d!\n",
2241b6ca18bSPantelis Antoniou 			       __func__, part, dev);
2251b6ca18bSPantelis Antoniou 			return -ENODEV;
2261b6ca18bSPantelis Antoniou 		}
2271b6ca18bSPantelis Antoniou 
2281b6ca18bSPantelis Antoniou 		dfu->data.mmc.lba_start = partinfo.start;
2291b6ca18bSPantelis Antoniou 		dfu->data.mmc.lba_size = partinfo.size;
2301b6ca18bSPantelis Antoniou 		dfu->data.mmc.lba_blk_size = partinfo.blksz;
2311b6ca18bSPantelis Antoniou 
232cb383cd2SLukasz Majewski 	} else {
233cb383cd2SLukasz Majewski 		printf("%s: Memory layout (%s) not supported!\n", __func__, st);
2341b6ca18bSPantelis Antoniou 		return -ENODEV;
235cb383cd2SLukasz Majewski 	}
236cb383cd2SLukasz Majewski 
23743e66272SŁukasz Majewski 	if (dfu->layout == DFU_FS_EXT4 || dfu->layout == DFU_FS_FAT) {
23843e66272SŁukasz Majewski 		dfu->data.mmc.dev = simple_strtoul(s, &s, 10);
23943e66272SŁukasz Majewski 		dfu->data.mmc.part = simple_strtoul(++s, &s, 10);
24043e66272SŁukasz Majewski 	}
24143e66272SŁukasz Majewski 
242cb383cd2SLukasz Majewski 	dfu->read_medium = dfu_read_medium_mmc;
243cb383cd2SLukasz Majewski 	dfu->write_medium = dfu_write_medium_mmc;
244ea2453d5SPantelis Antoniou 	dfu->flush_medium = dfu_flush_medium_mmc;
245ea2453d5SPantelis Antoniou 
246ea2453d5SPantelis Antoniou 	/* initial state */
247ea2453d5SPantelis Antoniou 	dfu->inited = 0;
248cb383cd2SLukasz Majewski 
249cb383cd2SLukasz Majewski 	return 0;
250cb383cd2SLukasz Majewski }
251