xref: /rk3399_rockchip-uboot/drivers/dfu/dfu_mmc.c (revision 1b6ca18b4244756d4dbd4240510f4cc448ade0bc)
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  *
7cb383cd2SLukasz Majewski  * This program is free software; you can redistribute it and/or modify
8cb383cd2SLukasz Majewski  * it under the terms of the GNU General Public License as published by
9cb383cd2SLukasz Majewski  * the Free Software Foundation; either version 2 of the License, or
10cb383cd2SLukasz Majewski  * (at your option) any later version.
11cb383cd2SLukasz Majewski  *
12cb383cd2SLukasz Majewski  * This program is distributed in the hope that it will be useful,
13cb383cd2SLukasz Majewski  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14cb383cd2SLukasz Majewski  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15cb383cd2SLukasz Majewski  * GNU General Public License for more details.
16cb383cd2SLukasz Majewski  *
17cb383cd2SLukasz Majewski  * You should have received a copy of the GNU General Public License
18cb383cd2SLukasz Majewski  * along with this program; if not, write to the Free Software
19cb383cd2SLukasz Majewski  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20cb383cd2SLukasz Majewski  */
21cb383cd2SLukasz Majewski 
22cb383cd2SLukasz Majewski #include <common.h>
23cb383cd2SLukasz Majewski #include <malloc.h>
24*1b6ca18bSPantelis Antoniou #include <errno.h>
25cb383cd2SLukasz Majewski #include <dfu.h>
26cb383cd2SLukasz Majewski 
27cb383cd2SLukasz Majewski enum dfu_mmc_op {
28cb383cd2SLukasz Majewski 	DFU_OP_READ = 1,
29cb383cd2SLukasz Majewski 	DFU_OP_WRITE,
30cb383cd2SLukasz Majewski };
31cb383cd2SLukasz Majewski 
32cb383cd2SLukasz Majewski static int mmc_block_op(enum dfu_mmc_op op, struct dfu_entity *dfu,
33cb383cd2SLukasz Majewski 			void *buf, long *len)
34cb383cd2SLukasz Majewski {
35cb383cd2SLukasz Majewski 	char cmd_buf[DFU_CMD_BUF_SIZE];
36cb383cd2SLukasz Majewski 
37cb383cd2SLukasz Majewski 	sprintf(cmd_buf, "mmc %s 0x%x %x %x",
38cb383cd2SLukasz Majewski 		op == DFU_OP_READ ? "read" : "write",
39cb383cd2SLukasz Majewski 		(unsigned int) buf,
40cb383cd2SLukasz Majewski 		dfu->data.mmc.lba_start,
41cb383cd2SLukasz Majewski 		dfu->data.mmc.lba_size);
42cb383cd2SLukasz Majewski 
43cb383cd2SLukasz Majewski 	if (op == DFU_OP_READ)
44cb383cd2SLukasz Majewski 		*len = dfu->data.mmc.lba_blk_size * dfu->data.mmc.lba_size;
45cb383cd2SLukasz Majewski 
46cb383cd2SLukasz Majewski 	debug("%s: %s 0x%p\n", __func__, cmd_buf, cmd_buf);
47cb383cd2SLukasz Majewski 	return run_command(cmd_buf, 0);
48cb383cd2SLukasz Majewski }
49cb383cd2SLukasz Majewski 
50cb383cd2SLukasz Majewski static inline int mmc_block_write(struct dfu_entity *dfu, void *buf, long *len)
51cb383cd2SLukasz Majewski {
52cb383cd2SLukasz Majewski 	return mmc_block_op(DFU_OP_WRITE, dfu, buf, len);
53cb383cd2SLukasz Majewski }
54cb383cd2SLukasz Majewski 
55cb383cd2SLukasz Majewski static inline int mmc_block_read(struct dfu_entity *dfu, void *buf, long *len)
56cb383cd2SLukasz Majewski {
57cb383cd2SLukasz Majewski 	return mmc_block_op(DFU_OP_READ, dfu, buf, len);
58cb383cd2SLukasz Majewski }
59cb383cd2SLukasz Majewski 
60cb383cd2SLukasz Majewski static int mmc_file_op(enum dfu_mmc_op op, struct dfu_entity *dfu,
61cb383cd2SLukasz Majewski 			void *buf, long *len)
62cb383cd2SLukasz Majewski {
63cb383cd2SLukasz Majewski 	char cmd_buf[DFU_CMD_BUF_SIZE];
64cb383cd2SLukasz Majewski 	char *str_env;
65cb383cd2SLukasz Majewski 	int ret;
66cb383cd2SLukasz Majewski 
6743e66272SŁukasz Majewski 	switch (dfu->layout) {
6843e66272SŁukasz Majewski 	case DFU_FS_FAT:
69cb383cd2SLukasz Majewski 		sprintf(cmd_buf, "fat%s mmc %d:%d 0x%x %s %lx",
70cb383cd2SLukasz Majewski 			op == DFU_OP_READ ? "load" : "write",
71cb383cd2SLukasz Majewski 			dfu->data.mmc.dev, dfu->data.mmc.part,
72cb383cd2SLukasz Majewski 			(unsigned int) buf, dfu->name, *len);
7343e66272SŁukasz Majewski 		break;
7443e66272SŁukasz Majewski 	case DFU_FS_EXT4:
7543e66272SŁukasz Majewski 		sprintf(cmd_buf, "ext4%s mmc %d:%d /%s 0x%x %ld",
7643e66272SŁukasz Majewski 			op == DFU_OP_READ ? "load" : "write",
7743e66272SŁukasz Majewski 			dfu->data.mmc.dev, dfu->data.mmc.part,
7843e66272SŁukasz Majewski 			dfu->name, (unsigned int) buf, *len);
7943e66272SŁukasz Majewski 		break;
8043e66272SŁukasz Majewski 	default:
8143e66272SŁukasz Majewski 		printf("%s: Layout (%s) not (yet) supported!\n", __func__,
8243e66272SŁukasz Majewski 		       dfu_get_layout(dfu->layout));
8343e66272SŁukasz Majewski 	}
84cb383cd2SLukasz Majewski 
85cb383cd2SLukasz Majewski 	debug("%s: %s 0x%p\n", __func__, cmd_buf, cmd_buf);
86cb383cd2SLukasz Majewski 
87cb383cd2SLukasz Majewski 	ret = run_command(cmd_buf, 0);
88cb383cd2SLukasz Majewski 	if (ret) {
89cb383cd2SLukasz Majewski 		puts("dfu: Read error!\n");
90cb383cd2SLukasz Majewski 		return ret;
91cb383cd2SLukasz Majewski 	}
92cb383cd2SLukasz Majewski 
9381c1d7b6SŁukasz Majewski 	if (dfu->layout != DFU_RAW_ADDR && op == DFU_OP_READ) {
94cb383cd2SLukasz Majewski 		str_env = getenv("filesize");
95cb383cd2SLukasz Majewski 		if (str_env == NULL) {
96cb383cd2SLukasz Majewski 			puts("dfu: Wrong file size!\n");
97cb383cd2SLukasz Majewski 			return -1;
98cb383cd2SLukasz Majewski 		}
99cb383cd2SLukasz Majewski 		*len = simple_strtoul(str_env, NULL, 16);
100cb383cd2SLukasz Majewski 	}
101cb383cd2SLukasz Majewski 
102cb383cd2SLukasz Majewski 	return ret;
103cb383cd2SLukasz Majewski }
104cb383cd2SLukasz Majewski 
105cb383cd2SLukasz Majewski static inline int mmc_file_write(struct dfu_entity *dfu, void *buf, long *len)
106cb383cd2SLukasz Majewski {
107cb383cd2SLukasz Majewski 	return mmc_file_op(DFU_OP_WRITE, dfu, buf, len);
108cb383cd2SLukasz Majewski }
109cb383cd2SLukasz Majewski 
110cb383cd2SLukasz Majewski static inline int mmc_file_read(struct dfu_entity *dfu, void *buf, long *len)
111cb383cd2SLukasz Majewski {
112cb383cd2SLukasz Majewski 	return mmc_file_op(DFU_OP_READ, dfu, buf, len);
113cb383cd2SLukasz Majewski }
114cb383cd2SLukasz Majewski 
115cb383cd2SLukasz Majewski int dfu_write_medium_mmc(struct dfu_entity *dfu, void *buf, long *len)
116cb383cd2SLukasz Majewski {
117cb383cd2SLukasz Majewski 	int ret = -1;
118cb383cd2SLukasz Majewski 
119cb383cd2SLukasz Majewski 	switch (dfu->layout) {
120cb383cd2SLukasz Majewski 	case DFU_RAW_ADDR:
121cb383cd2SLukasz Majewski 		ret = mmc_block_write(dfu, buf, len);
122cb383cd2SLukasz Majewski 		break;
123cb383cd2SLukasz Majewski 	case DFU_FS_FAT:
12443e66272SŁukasz Majewski 	case DFU_FS_EXT4:
125cb383cd2SLukasz Majewski 		ret = mmc_file_write(dfu, buf, len);
126cb383cd2SLukasz Majewski 		break;
127cb383cd2SLukasz Majewski 	default:
128cb383cd2SLukasz Majewski 		printf("%s: Layout (%s) not (yet) supported!\n", __func__,
129cb383cd2SLukasz Majewski 		       dfu_get_layout(dfu->layout));
130cb383cd2SLukasz Majewski 	}
131cb383cd2SLukasz Majewski 
132cb383cd2SLukasz Majewski 	return ret;
133cb383cd2SLukasz Majewski }
134cb383cd2SLukasz Majewski 
135cb383cd2SLukasz Majewski int dfu_read_medium_mmc(struct dfu_entity *dfu, void *buf, long *len)
136cb383cd2SLukasz Majewski {
137cb383cd2SLukasz Majewski 	int ret = -1;
138cb383cd2SLukasz Majewski 
139cb383cd2SLukasz Majewski 	switch (dfu->layout) {
140cb383cd2SLukasz Majewski 	case DFU_RAW_ADDR:
141cb383cd2SLukasz Majewski 		ret = mmc_block_read(dfu, buf, len);
142cb383cd2SLukasz Majewski 		break;
143cb383cd2SLukasz Majewski 	case DFU_FS_FAT:
14443e66272SŁukasz Majewski 	case DFU_FS_EXT4:
145cb383cd2SLukasz Majewski 		ret = mmc_file_read(dfu, buf, len);
146cb383cd2SLukasz Majewski 		break;
147cb383cd2SLukasz Majewski 	default:
148cb383cd2SLukasz Majewski 		printf("%s: Layout (%s) not (yet) supported!\n", __func__,
149cb383cd2SLukasz Majewski 		       dfu_get_layout(dfu->layout));
150cb383cd2SLukasz Majewski 	}
151cb383cd2SLukasz Majewski 
152cb383cd2SLukasz Majewski 	return ret;
153cb383cd2SLukasz Majewski }
154cb383cd2SLukasz Majewski 
155cb383cd2SLukasz Majewski int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *s)
156cb383cd2SLukasz Majewski {
157*1b6ca18bSPantelis Antoniou 	int dev, part;
158*1b6ca18bSPantelis Antoniou 	struct mmc *mmc;
159*1b6ca18bSPantelis Antoniou 	block_dev_desc_t *blk_dev;
160*1b6ca18bSPantelis Antoniou 	disk_partition_t partinfo;
161cb383cd2SLukasz Majewski 	char *st;
162cb383cd2SLukasz Majewski 
163cb383cd2SLukasz Majewski 	dfu->dev_type = DFU_DEV_MMC;
164cb383cd2SLukasz Majewski 	st = strsep(&s, " ");
165cb383cd2SLukasz Majewski 	if (!strcmp(st, "mmc")) {
166cb383cd2SLukasz Majewski 		dfu->layout = DFU_RAW_ADDR;
167cb383cd2SLukasz Majewski 		dfu->data.mmc.lba_start = simple_strtoul(s, &s, 16);
168cb383cd2SLukasz Majewski 		dfu->data.mmc.lba_size = simple_strtoul(++s, &s, 16);
169cb383cd2SLukasz Majewski 		dfu->data.mmc.lba_blk_size = get_mmc_blk_size(dfu->dev_num);
170cb383cd2SLukasz Majewski 	} else if (!strcmp(st, "fat")) {
171cb383cd2SLukasz Majewski 		dfu->layout = DFU_FS_FAT;
17243e66272SŁukasz Majewski 	} else if (!strcmp(st, "ext4")) {
17343e66272SŁukasz Majewski 		dfu->layout = DFU_FS_EXT4;
174*1b6ca18bSPantelis Antoniou 	} else if (!strcmp(st, "part")) {
175*1b6ca18bSPantelis Antoniou 
176*1b6ca18bSPantelis Antoniou 		dfu->layout = DFU_RAW_ADDR;
177*1b6ca18bSPantelis Antoniou 
178*1b6ca18bSPantelis Antoniou 		dev = simple_strtoul(s, &s, 10);
179*1b6ca18bSPantelis Antoniou 		s++;
180*1b6ca18bSPantelis Antoniou 		part = simple_strtoul(s, &s, 10);
181*1b6ca18bSPantelis Antoniou 
182*1b6ca18bSPantelis Antoniou 		mmc = find_mmc_device(dev);
183*1b6ca18bSPantelis Antoniou 		if (mmc == NULL || mmc_init(mmc)) {
184*1b6ca18bSPantelis Antoniou 			printf("%s: could not find mmc device #%d!\n", __func__, dev);
185*1b6ca18bSPantelis Antoniou 			return -ENODEV;
186*1b6ca18bSPantelis Antoniou 		}
187*1b6ca18bSPantelis Antoniou 
188*1b6ca18bSPantelis Antoniou 		blk_dev = &mmc->block_dev;
189*1b6ca18bSPantelis Antoniou 		if (get_partition_info(blk_dev, part, &partinfo) != 0) {
190*1b6ca18bSPantelis Antoniou 			printf("%s: could not find partition #%d on mmc device #%d!\n",
191*1b6ca18bSPantelis Antoniou 					__func__, part, dev);
192*1b6ca18bSPantelis Antoniou 			return -ENODEV;
193*1b6ca18bSPantelis Antoniou 		}
194*1b6ca18bSPantelis Antoniou 
195*1b6ca18bSPantelis Antoniou 		dfu->data.mmc.lba_start = partinfo.start;
196*1b6ca18bSPantelis Antoniou 		dfu->data.mmc.lba_size = partinfo.size;
197*1b6ca18bSPantelis Antoniou 		dfu->data.mmc.lba_blk_size = partinfo.blksz;
198*1b6ca18bSPantelis Antoniou 
199cb383cd2SLukasz Majewski 	} else {
200cb383cd2SLukasz Majewski 		printf("%s: Memory layout (%s) not supported!\n", __func__, st);
201*1b6ca18bSPantelis Antoniou 		return -ENODEV;
202cb383cd2SLukasz Majewski 	}
203cb383cd2SLukasz Majewski 
20443e66272SŁukasz Majewski 	if (dfu->layout == DFU_FS_EXT4 || dfu->layout == DFU_FS_FAT) {
20543e66272SŁukasz Majewski 		dfu->data.mmc.dev = simple_strtoul(s, &s, 10);
20643e66272SŁukasz Majewski 		dfu->data.mmc.part = simple_strtoul(++s, &s, 10);
20743e66272SŁukasz Majewski 	}
20843e66272SŁukasz Majewski 
209cb383cd2SLukasz Majewski 	dfu->read_medium = dfu_read_medium_mmc;
210cb383cd2SLukasz Majewski 	dfu->write_medium = dfu_write_medium_mmc;
211cb383cd2SLukasz Majewski 
212cb383cd2SLukasz Majewski 	return 0;
213cb383cd2SLukasz Majewski }
214