Blame view

drivers/dfu/dfu_mmc.c 6.41 KB
cb383cd21   Lukasz Majewski   dfu: MMC specific...
1
2
3
4
5
6
  /*
   * dfu.c -- DFU back-end routines
   *
   * Copyright (C) 2012 Samsung Electronics
   * author: Lukasz Majewski <l.majewski@samsung.com>
   *
1a4596601   Wolfgang Denk   Add GPL-2.0+ SPDX...
7
   * SPDX-License-Identifier:	GPL-2.0+
cb383cd21   Lukasz Majewski   dfu: MMC specific...
8
9
10
11
   */
  
  #include <common.h>
  #include <malloc.h>
1b6ca18b4   Pantelis Antoniou   dfu: Add a partit...
12
  #include <errno.h>
ea2453d56   Pantelis Antoniou   dfu: Support larg...
13
  #include <div64.h>
cb383cd21   Lukasz Majewski   dfu: MMC specific...
14
  #include <dfu.h>
7d0b605ab   Łukasz Majewski   dfu: mmc: Replace...
15
  #include <mmc.h>
cb383cd21   Lukasz Majewski   dfu: MMC specific...
16

ea2453d56   Pantelis Antoniou   dfu: Support larg...
17
18
19
  static unsigned char __aligned(CONFIG_SYS_CACHELINE_SIZE)
  				dfu_file_buf[CONFIG_SYS_DFU_MAX_FILE_SIZE];
  static long dfu_file_buf_len;
5a127c843   Afzal Mohammed   dfu: unify mmc/na...
20
  static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu,
ea2453d56   Pantelis Antoniou   dfu: Support larg...
21
  			u64 offset, void *buf, long *len)
cb383cd21   Lukasz Majewski   dfu: MMC specific...
22
  {
7d0b605ab   Łukasz Majewski   dfu: mmc: Replace...
23
24
  	struct mmc *mmc = find_mmc_device(dfu->dev_num);
  	u32 blk_start, blk_count, n = 0;
ea2453d56   Pantelis Antoniou   dfu: Support larg...
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
  
  	/*
  	 * We must ensure that we work in lba_blk_size chunks, so ALIGN
  	 * this value.
  	 */
  	*len = ALIGN(*len, dfu->data.mmc.lba_blk_size);
  
  	blk_start = dfu->data.mmc.lba_start +
  			(u32)lldiv(offset, dfu->data.mmc.lba_blk_size);
  	blk_count = *len / dfu->data.mmc.lba_blk_size;
  	if (blk_start + blk_count >
  			dfu->data.mmc.lba_start + dfu->data.mmc.lba_size) {
  		puts("Request would exceed designated area!
  ");
  		return -EINVAL;
  	}
cb383cd21   Lukasz Majewski   dfu: MMC specific...
41

7d0b605ab   Łukasz Majewski   dfu: mmc: Replace...
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
  	debug("%s: %s dev: %d start: %d cnt: %d buf: 0x%p
  ", __func__,
  	      op == DFU_OP_READ ? "MMC READ" : "MMC WRITE", dfu->dev_num,
  	      blk_start, blk_count, buf);
  	switch (op) {
  	case DFU_OP_READ:
  		n = mmc->block_dev.block_read(dfu->dev_num, blk_start,
  					      blk_count, buf);
  		break;
  	case DFU_OP_WRITE:
  		n = mmc->block_dev.block_write(dfu->dev_num, blk_start,
  					       blk_count, buf);
  		break;
  	default:
  		error("Operation not supported
  ");
  	}
  
  	if (n != blk_count) {
  		error("MMC operation failed");
  		return -EIO;
  	}
cb383cd21   Lukasz Majewski   dfu: MMC specific...
64

7d0b605ab   Łukasz Majewski   dfu: mmc: Replace...
65
  	return 0;
cb383cd21   Lukasz Majewski   dfu: MMC specific...
66
  }
ea2453d56   Pantelis Antoniou   dfu: Support larg...
67
  static int mmc_file_buffer(struct dfu_entity *dfu, void *buf, long *len)
cb383cd21   Lukasz Majewski   dfu: MMC specific...
68
  {
ea2453d56   Pantelis Antoniou   dfu: Support larg...
69
70
71
72
  	if (dfu_file_buf_len + *len > CONFIG_SYS_DFU_MAX_FILE_SIZE) {
  		dfu_file_buf_len = 0;
  		return -EINVAL;
  	}
cb383cd21   Lukasz Majewski   dfu: MMC specific...
73

ea2453d56   Pantelis Antoniou   dfu: Support larg...
74
75
76
77
78
  	/* Add to the current buffer. */
  	memcpy(dfu_file_buf + dfu_file_buf_len, buf, *len);
  	dfu_file_buf_len += *len;
  
  	return 0;
cb383cd21   Lukasz Majewski   dfu: MMC specific...
79
  }
5a127c843   Afzal Mohammed   dfu: unify mmc/na...
80
  static int mmc_file_op(enum dfu_op op, struct dfu_entity *dfu,
cb383cd21   Lukasz Majewski   dfu: MMC specific...
81
82
83
84
85
  			void *buf, long *len)
  {
  	char cmd_buf[DFU_CMD_BUF_SIZE];
  	char *str_env;
  	int ret;
43e662725   Łukasz Majewski   dfu:usb: Support ...
86
87
  	switch (dfu->layout) {
  	case DFU_FS_FAT:
ea2453d56   Pantelis Antoniou   dfu: Support larg...
88
  		sprintf(cmd_buf, "fat%s mmc %d:%d 0x%x %s",
43e662725   Łukasz Majewski   dfu:usb: Support ...
89
90
  			op == DFU_OP_READ ? "load" : "write",
  			dfu->data.mmc.dev, dfu->data.mmc.part,
ea2453d56   Pantelis Antoniou   dfu: Support larg...
91
  			(unsigned int) buf, dfu->name);
43e662725   Łukasz Majewski   dfu:usb: Support ...
92
93
  		break;
  	case DFU_FS_EXT4:
ea2453d56   Pantelis Antoniou   dfu: Support larg...
94
  		sprintf(cmd_buf, "ext4%s mmc %d:%d 0x%x /%s",
43e662725   Łukasz Majewski   dfu:usb: Support ...
95
96
  			op == DFU_OP_READ ? "load" : "write",
  			dfu->data.mmc.dev, dfu->data.mmc.part,
ea2453d56   Pantelis Antoniou   dfu: Support larg...
97
  			(unsigned int) buf, dfu->name);
43e662725   Łukasz Majewski   dfu:usb: Support ...
98
99
100
101
102
  		break;
  	default:
  		printf("%s: Layout (%s) not (yet) supported!
  ", __func__,
  		       dfu_get_layout(dfu->layout));
ea2453d56   Pantelis Antoniou   dfu: Support larg...
103
  		return -1;
43e662725   Łukasz Majewski   dfu:usb: Support ...
104
  	}
cb383cd21   Lukasz Majewski   dfu: MMC specific...
105

17eb1d8f5   Lukasz Majewski   dfu: mmc: fs: Fix...
106
107
  	if (op == DFU_OP_WRITE)
  		sprintf(cmd_buf + strlen(cmd_buf), " %lx", *len);
cb383cd21   Lukasz Majewski   dfu: MMC specific...
108
109
110
111
112
113
114
115
116
  	debug("%s: %s 0x%p
  ", __func__, cmd_buf, cmd_buf);
  
  	ret = run_command(cmd_buf, 0);
  	if (ret) {
  		puts("dfu: Read error!
  ");
  		return ret;
  	}
81c1d7b60   Łukasz Majewski   dfu:usb:fix: Read...
117
  	if (dfu->layout != DFU_RAW_ADDR && op == DFU_OP_READ) {
cb383cd21   Lukasz Majewski   dfu: MMC specific...
118
119
120
121
122
123
124
125
126
127
128
  		str_env = getenv("filesize");
  		if (str_env == NULL) {
  			puts("dfu: Wrong file size!
  ");
  			return -1;
  		}
  		*len = simple_strtoul(str_env, NULL, 16);
  	}
  
  	return ret;
  }
ea2453d56   Pantelis Antoniou   dfu: Support larg...
129
130
  int dfu_write_medium_mmc(struct dfu_entity *dfu,
  		u64 offset, void *buf, long *len)
cb383cd21   Lukasz Majewski   dfu: MMC specific...
131
132
133
134
135
  {
  	int ret = -1;
  
  	switch (dfu->layout) {
  	case DFU_RAW_ADDR:
ea2453d56   Pantelis Antoniou   dfu: Support larg...
136
  		ret = mmc_block_op(DFU_OP_WRITE, dfu, offset, buf, len);
cb383cd21   Lukasz Majewski   dfu: MMC specific...
137
138
  		break;
  	case DFU_FS_FAT:
43e662725   Łukasz Majewski   dfu:usb: Support ...
139
  	case DFU_FS_EXT4:
ea2453d56   Pantelis Antoniou   dfu: Support larg...
140
  		ret = mmc_file_buffer(dfu, buf, len);
cb383cd21   Lukasz Majewski   dfu: MMC specific...
141
142
143
144
145
146
147
148
149
  		break;
  	default:
  		printf("%s: Layout (%s) not (yet) supported!
  ", __func__,
  		       dfu_get_layout(dfu->layout));
  	}
  
  	return ret;
  }
ea2453d56   Pantelis Antoniou   dfu: Support larg...
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
  int dfu_flush_medium_mmc(struct dfu_entity *dfu)
  {
  	int ret = 0;
  
  	if (dfu->layout != DFU_RAW_ADDR) {
  		/* Do stuff here. */
  		ret = mmc_file_op(DFU_OP_WRITE, dfu, &dfu_file_buf,
  				&dfu_file_buf_len);
  
  		/* Now that we're done */
  		dfu_file_buf_len = 0;
  	}
  
  	return ret;
  }
  
  int dfu_read_medium_mmc(struct dfu_entity *dfu, u64 offset, void *buf,
  		long *len)
cb383cd21   Lukasz Majewski   dfu: MMC specific...
168
169
170
171
172
  {
  	int ret = -1;
  
  	switch (dfu->layout) {
  	case DFU_RAW_ADDR:
ea2453d56   Pantelis Antoniou   dfu: Support larg...
173
  		ret = mmc_block_op(DFU_OP_READ, dfu, offset, buf, len);
cb383cd21   Lukasz Majewski   dfu: MMC specific...
174
175
  		break;
  	case DFU_FS_FAT:
43e662725   Łukasz Majewski   dfu:usb: Support ...
176
  	case DFU_FS_EXT4:
ea2453d56   Pantelis Antoniou   dfu: Support larg...
177
  		ret = mmc_file_op(DFU_OP_READ, dfu, buf, len);
cb383cd21   Lukasz Majewski   dfu: MMC specific...
178
179
180
181
182
183
184
185
186
  		break;
  	default:
  		printf("%s: Layout (%s) not (yet) supported!
  ", __func__,
  		       dfu_get_layout(dfu->layout));
  	}
  
  	return ret;
  }
711b931f9   Mateusz Zalega   dfu: mmc: raw dat...
187
188
189
190
191
192
193
194
195
196
197
  /*
   * @param s Parameter string containing space-separated arguments:
   *	1st:
   *		raw	(raw read/write)
   *		fat	(files)
   *		ext4	(^)
   *		part	(partition image)
   *	2nd and 3rd:
   *		lba_start and lba_size, for raw write
   *		mmc_dev and mmc_part, for filesystems and part
   */
cb383cd21   Lukasz Majewski   dfu: MMC specific...
198
199
  int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *s)
  {
711b931f9   Mateusz Zalega   dfu: mmc: raw dat...
200
201
202
  	const char *entity_type;
  	size_t second_arg;
  	size_t third_arg;
cb383cd21   Lukasz Majewski   dfu: MMC specific...
203

711b931f9   Mateusz Zalega   dfu: mmc: raw dat...
204
  	struct mmc *mmc;
1b6ca18b4   Pantelis Antoniou   dfu: Add a partit...
205

711b931f9   Mateusz Zalega   dfu: mmc: raw dat...
206
207
  	const char *argv[3];
  	const char **parg = argv;
1b6ca18b4   Pantelis Antoniou   dfu: Add a partit...
208

711b931f9   Mateusz Zalega   dfu: mmc: raw dat...
209
210
211
212
213
  	for (; parg < argv + sizeof(argv) / sizeof(*argv); ++parg) {
  		*parg = strsep(&s, " ");
  		if (*parg == NULL) {
  			error("Invalid number of arguments.
  ");
1b6ca18b4   Pantelis Antoniou   dfu: Add a partit...
214
215
  			return -ENODEV;
  		}
711b931f9   Mateusz Zalega   dfu: mmc: raw dat...
216
  	}
1b6ca18b4   Pantelis Antoniou   dfu: Add a partit...
217

711b931f9   Mateusz Zalega   dfu: mmc: raw dat...
218
  	entity_type = argv[0];
b7d4259af   Mateusz Zalega   dfu: mmc: change ...
219
220
221
222
223
224
  	/*
  	 * Base 0 means we'll accept (prefixed with 0x or 0) base 16, 8,
  	 * with default 10.
  	 */
  	second_arg = simple_strtoul(argv[1], NULL, 0);
  	third_arg = simple_strtoul(argv[2], NULL, 0);
711b931f9   Mateusz Zalega   dfu: mmc: raw dat...
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
  
  	mmc = find_mmc_device(dfu->dev_num);
  	if (mmc == NULL) {
  		error("Couldn't find MMC device no. %d.
  ", dfu->dev_num);
  		return -ENODEV;
  	}
  
  	if (mmc_init(mmc)) {
  		error("Couldn't init MMC device.
  ");
  		return -ENODEV;
  	}
  
  	if (!strcmp(entity_type, "raw")) {
  		dfu->layout			= DFU_RAW_ADDR;
  		dfu->data.mmc.lba_start		= second_arg;
  		dfu->data.mmc.lba_size		= third_arg;
  		dfu->data.mmc.lba_blk_size	= mmc->read_bl_len;
  	} else if (!strcmp(entity_type, "part")) {
  		disk_partition_t partinfo;
  		block_dev_desc_t *blk_dev = &mmc->block_dev;
  		int mmcdev = second_arg;
  		int mmcpart = third_arg;
  
  		if (get_partition_info(blk_dev, mmcpart, &partinfo) != 0) {
  			error("Couldn't find part #%d on mmc device #%d
  ",
  			      mmcpart, mmcdev);
1b6ca18b4   Pantelis Antoniou   dfu: Add a partit...
254
255
  			return -ENODEV;
  		}
711b931f9   Mateusz Zalega   dfu: mmc: raw dat...
256
257
258
259
260
261
262
263
  		dfu->layout			= DFU_RAW_ADDR;
  		dfu->data.mmc.lba_start		= partinfo.start;
  		dfu->data.mmc.lba_size		= partinfo.size;
  		dfu->data.mmc.lba_blk_size	= partinfo.blksz;
  	} else if (!strcmp(entity_type, "fat")) {
  		dfu->layout = DFU_FS_FAT;
  	} else if (!strcmp(entity_type, "ext4")) {
  		dfu->layout = DFU_FS_EXT4;
cb383cd21   Lukasz Majewski   dfu: MMC specific...
264
  	} else {
711b931f9   Mateusz Zalega   dfu: mmc: raw dat...
265
266
  		error("Memory layout (%s) not supported!
  ", entity_type);
1b6ca18b4   Pantelis Antoniou   dfu: Add a partit...
267
  		return -ENODEV;
cb383cd21   Lukasz Majewski   dfu: MMC specific...
268
  	}
711b931f9   Mateusz Zalega   dfu: mmc: raw dat...
269
270
271
272
  	/* if it's NOT a raw write */
  	if (strcmp(entity_type, "raw")) {
  		dfu->data.mmc.dev = second_arg;
  		dfu->data.mmc.part = third_arg;
43e662725   Łukasz Majewski   dfu:usb: Support ...
273
  	}
711b931f9   Mateusz Zalega   dfu: mmc: raw dat...
274
  	dfu->dev_type = DFU_DEV_MMC;
cb383cd21   Lukasz Majewski   dfu: MMC specific...
275
276
  	dfu->read_medium = dfu_read_medium_mmc;
  	dfu->write_medium = dfu_write_medium_mmc;
ea2453d56   Pantelis Antoniou   dfu: Support larg...
277
  	dfu->flush_medium = dfu_flush_medium_mmc;
ea2453d56   Pantelis Antoniou   dfu: Support larg...
278
  	dfu->inited = 0;
cb383cd21   Lukasz Majewski   dfu: MMC specific...
279
280
281
  
  	return 0;
  }