]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
c0aebb33 SR |
2 | /* |
3 | * Copyright 2014 Broadcom Corporation. | |
c0aebb33 SR |
4 | */ |
5 | ||
0ff7e585 | 6 | #include <config.h> |
c0aebb33 | 7 | #include <common.h> |
2a981dc2 | 8 | #include <blk.h> |
7b51b576 | 9 | #include <env.h> |
3c8f98f5 | 10 | #include <fastboot.h> |
f73a7df9 | 11 | #include <fastboot-internal.h> |
c0aebb33 | 12 | #include <fb_mmc.h> |
b79fdc76 | 13 | #include <flash.h> |
3d4ef38d | 14 | #include <image-sparse.h> |
4d72caa5 | 15 | #include <image.h> |
f7ae49fc | 16 | #include <log.h> |
c0aebb33 | 17 | #include <part.h> |
89792381 | 18 | #include <mmc.h> |
5e0efc1b | 19 | #include <div64.h> |
efeccfe7 SP |
20 | #include <linux/compat.h> |
21 | #include <android_image.h> | |
c0aebb33 | 22 | |
f73a7df9 AK |
23 | #define FASTBOOT_MAX_BLK_WRITE 16384 |
24 | ||
efeccfe7 SP |
25 | #define BOOT_PARTITION_NAME "boot" |
26 | ||
a5d1e04a | 27 | struct fb_mmc_sparse { |
4101f687 | 28 | struct blk_desc *dev_desc; |
a5d1e04a MR |
29 | }; |
30 | ||
b6dd69a4 | 31 | static int part_get_info_by_name_or_alias(struct blk_desc *dev_desc, |
0528979f | 32 | const char *name, struct disk_partition *info) |
8a41802f MS |
33 | { |
34 | int ret; | |
35 | ||
87b8530f | 36 | ret = part_get_info_by_name(dev_desc, name, info); |
88b6329c | 37 | if (ret < 0) { |
b762aa12 AK |
38 | /* strlen("fastboot_partition_alias_") + PART_NAME_LEN + 1 */ |
39 | char env_alias_name[25 + PART_NAME_LEN + 1]; | |
8a41802f MS |
40 | char *aliased_part_name; |
41 | ||
42 | /* check for alias */ | |
43 | strcpy(env_alias_name, "fastboot_partition_alias_"); | |
b762aa12 | 44 | strncat(env_alias_name, name, PART_NAME_LEN); |
00caae6d | 45 | aliased_part_name = env_get(env_alias_name); |
8a41802f | 46 | if (aliased_part_name != NULL) |
87b8530f | 47 | ret = part_get_info_by_name(dev_desc, |
8a41802f MS |
48 | aliased_part_name, info); |
49 | } | |
50 | return ret; | |
51 | } | |
52 | ||
f73a7df9 AK |
53 | /** |
54 | * fb_mmc_blk_write() - Write/erase MMC in chunks of FASTBOOT_MAX_BLK_WRITE | |
55 | * | |
56 | * @block_dev: Pointer to block device | |
57 | * @start: First block to write/erase | |
58 | * @blkcnt: Count of blocks | |
59 | * @buffer: Pointer to data buffer for write or NULL for erase | |
60 | */ | |
61 | static lbaint_t fb_mmc_blk_write(struct blk_desc *block_dev, lbaint_t start, | |
62 | lbaint_t blkcnt, const void *buffer) | |
63 | { | |
64 | lbaint_t blk = start; | |
65 | lbaint_t blks_written; | |
66 | lbaint_t cur_blkcnt; | |
67 | lbaint_t blks = 0; | |
68 | int i; | |
69 | ||
70 | for (i = 0; i < blkcnt; i += FASTBOOT_MAX_BLK_WRITE) { | |
71 | cur_blkcnt = min((int)blkcnt - i, FASTBOOT_MAX_BLK_WRITE); | |
72 | if (buffer) { | |
73 | if (fastboot_progress_callback) | |
74 | fastboot_progress_callback("writing"); | |
75 | blks_written = blk_dwrite(block_dev, blk, cur_blkcnt, | |
76 | buffer + (i * block_dev->blksz)); | |
77 | } else { | |
78 | if (fastboot_progress_callback) | |
79 | fastboot_progress_callback("erasing"); | |
80 | blks_written = blk_derase(block_dev, blk, cur_blkcnt); | |
81 | } | |
82 | blk += blks_written; | |
83 | blks += blks_written; | |
84 | } | |
85 | return blks; | |
86 | } | |
87 | ||
cc0f08cd SR |
88 | static lbaint_t fb_mmc_sparse_write(struct sparse_storage *info, |
89 | lbaint_t blk, lbaint_t blkcnt, const void *buffer) | |
a5d1e04a | 90 | { |
cc0f08cd | 91 | struct fb_mmc_sparse *sparse = info->priv; |
4101f687 | 92 | struct blk_desc *dev_desc = sparse->dev_desc; |
a5d1e04a | 93 | |
f73a7df9 | 94 | return fb_mmc_blk_write(dev_desc, blk, blkcnt, buffer); |
a5d1e04a MR |
95 | } |
96 | ||
2c724046 SR |
97 | static lbaint_t fb_mmc_sparse_reserve(struct sparse_storage *info, |
98 | lbaint_t blk, lbaint_t blkcnt) | |
99 | { | |
100 | return blkcnt; | |
101 | } | |
102 | ||
0528979f SG |
103 | static void write_raw_image(struct blk_desc *dev_desc, |
104 | struct disk_partition *info, const char *part_name, | |
105 | void *buffer, u32 download_bytes, char *response) | |
c0aebb33 SR |
106 | { |
107 | lbaint_t blkcnt; | |
108 | lbaint_t blks; | |
109 | ||
110 | /* determine number of blocks to write */ | |
111 | blkcnt = ((download_bytes + (info->blksz - 1)) & ~(info->blksz - 1)); | |
5e0efc1b | 112 | blkcnt = lldiv(blkcnt, info->blksz); |
c0aebb33 SR |
113 | |
114 | if (blkcnt > info->size) { | |
9b643e31 | 115 | pr_err("too large for partition: '%s'\n", part_name); |
c4ded03e | 116 | fastboot_fail("too large for partition", response); |
c0aebb33 SR |
117 | return; |
118 | } | |
119 | ||
120 | puts("Flashing Raw Image\n"); | |
121 | ||
f73a7df9 AK |
122 | blks = fb_mmc_blk_write(dev_desc, info->start, blkcnt, buffer); |
123 | ||
c0aebb33 | 124 | if (blks != blkcnt) { |
9b643e31 | 125 | pr_err("failed writing to device %d\n", dev_desc->devnum); |
c4ded03e | 126 | fastboot_fail("failed writing to device", response); |
c0aebb33 SR |
127 | return; |
128 | } | |
129 | ||
130 | printf("........ wrote " LBAFU " bytes to '%s'\n", blkcnt * info->blksz, | |
131 | part_name); | |
c4ded03e | 132 | fastboot_okay(NULL, response); |
c0aebb33 SR |
133 | } |
134 | ||
1fdbad02 | 135 | #ifdef CONFIG_FASTBOOT_MMC_BOOT1_SUPPORT |
136 | static int fb_mmc_erase_mmc_hwpart(struct blk_desc *dev_desc) | |
137 | { | |
138 | lbaint_t blks; | |
139 | ||
140 | debug("Start Erasing mmc hwpart[%u]...\n", dev_desc->hwpart); | |
141 | ||
142 | blks = fb_mmc_blk_write(dev_desc, 0, dev_desc->lba, NULL); | |
143 | ||
144 | if (blks != dev_desc->lba) { | |
145 | pr_err("Failed to erase mmc hwpart[%u]\n", dev_desc->hwpart); | |
146 | return 1; | |
147 | } | |
148 | ||
149 | printf("........ erased %lu bytes from mmc hwpart[%u]\n", | |
150 | dev_desc->lba * dev_desc->blksz, dev_desc->hwpart); | |
151 | ||
152 | return 0; | |
153 | } | |
154 | ||
155 | static void fb_mmc_boot1_ops(struct blk_desc *dev_desc, void *buffer, | |
156 | u32 buff_sz, char *response) | |
157 | { | |
158 | lbaint_t blkcnt; | |
159 | lbaint_t blks; | |
160 | unsigned long blksz; | |
161 | ||
162 | // To operate on EMMC_BOOT1 (mmc0boot0), we first change the hwpart | |
163 | if (blk_dselect_hwpart(dev_desc, 1)) { | |
164 | pr_err("Failed to select hwpart\n"); | |
165 | fastboot_fail("Failed to select hwpart", response); | |
166 | return; | |
167 | } | |
168 | ||
169 | if (buffer) { /* flash */ | |
170 | ||
171 | /* determine number of blocks to write */ | |
172 | blksz = dev_desc->blksz; | |
173 | blkcnt = ((buff_sz + (blksz - 1)) & ~(blksz - 1)); | |
174 | blkcnt = lldiv(blkcnt, blksz); | |
175 | ||
176 | if (blkcnt > dev_desc->lba) { | |
177 | pr_err("Image size too large\n"); | |
178 | fastboot_fail("Image size too large", response); | |
179 | return; | |
180 | } | |
181 | ||
182 | debug("Start Flashing Image to EMMC_BOOT1...\n"); | |
183 | ||
184 | blks = fb_mmc_blk_write(dev_desc, 0, blkcnt, buffer); | |
185 | ||
186 | if (blks != blkcnt) { | |
187 | pr_err("Failed to write EMMC_BOOT1\n"); | |
188 | fastboot_fail("Failed to write EMMC_BOOT1", response); | |
189 | return; | |
190 | } | |
191 | ||
192 | printf("........ wrote %lu bytes to EMMC_BOOT1\n", | |
193 | blkcnt * blksz); | |
194 | } else { /* erase */ | |
195 | if (fb_mmc_erase_mmc_hwpart(dev_desc)) { | |
196 | fastboot_fail("Failed to erase EMMC_BOOT1", response); | |
197 | return; | |
198 | } | |
199 | } | |
200 | ||
201 | fastboot_okay(NULL, response); | |
202 | } | |
203 | #endif | |
204 | ||
efeccfe7 SP |
205 | #ifdef CONFIG_ANDROID_BOOT_IMAGE |
206 | /** | |
207 | * Read Android boot image header from boot partition. | |
208 | * | |
209 | * @param[in] dev_desc MMC device descriptor | |
210 | * @param[in] info Boot partition info | |
211 | * @param[out] hdr Where to store read boot image header | |
212 | * | |
213 | * @return Boot image header sectors count or 0 on error | |
214 | */ | |
215 | static lbaint_t fb_mmc_get_boot_header(struct blk_desc *dev_desc, | |
0528979f | 216 | struct disk_partition *info, |
c4ded03e AK |
217 | struct andr_img_hdr *hdr, |
218 | char *response) | |
efeccfe7 SP |
219 | { |
220 | ulong sector_size; /* boot partition sector size */ | |
221 | lbaint_t hdr_sectors; /* boot image header sectors count */ | |
222 | int res; | |
223 | ||
224 | /* Calculate boot image sectors count */ | |
225 | sector_size = info->blksz; | |
226 | hdr_sectors = DIV_ROUND_UP(sizeof(struct andr_img_hdr), sector_size); | |
227 | if (hdr_sectors == 0) { | |
1ad5facb | 228 | pr_err("invalid number of boot sectors: 0\n"); |
c4ded03e | 229 | fastboot_fail("invalid number of boot sectors: 0", response); |
efeccfe7 SP |
230 | return 0; |
231 | } | |
232 | ||
233 | /* Read the boot image header */ | |
234 | res = blk_dread(dev_desc, info->start, hdr_sectors, (void *)hdr); | |
6bafa5a4 | 235 | if (res != hdr_sectors) { |
1ad5facb | 236 | pr_err("cannot read header from boot partition\n"); |
c4ded03e AK |
237 | fastboot_fail("cannot read header from boot partition", |
238 | response); | |
efeccfe7 SP |
239 | return 0; |
240 | } | |
241 | ||
242 | /* Check boot header magic string */ | |
243 | res = android_image_check_header(hdr); | |
244 | if (res != 0) { | |
1ad5facb | 245 | pr_err("bad boot image magic\n"); |
c4ded03e | 246 | fastboot_fail("boot partition not initialized", response); |
efeccfe7 SP |
247 | return 0; |
248 | } | |
249 | ||
250 | return hdr_sectors; | |
251 | } | |
252 | ||
253 | /** | |
254 | * Write downloaded zImage to boot partition and repack it properly. | |
255 | * | |
256 | * @param dev_desc MMC device descriptor | |
257 | * @param download_buffer Address to fastboot buffer with zImage in it | |
258 | * @param download_bytes Size of fastboot buffer, in bytes | |
259 | * | |
260 | * @return 0 on success or -1 on error | |
261 | */ | |
262 | static int fb_mmc_update_zimage(struct blk_desc *dev_desc, | |
263 | void *download_buffer, | |
f73a7df9 | 264 | u32 download_bytes, |
c4ded03e | 265 | char *response) |
efeccfe7 | 266 | { |
2341c80c | 267 | uintptr_t hdr_addr; /* boot image header address */ |
efeccfe7 SP |
268 | struct andr_img_hdr *hdr; /* boot image header */ |
269 | lbaint_t hdr_sectors; /* boot image header sectors */ | |
270 | u8 *ramdisk_buffer; | |
271 | u32 ramdisk_sector_start; | |
272 | u32 ramdisk_sectors; | |
273 | u32 kernel_sector_start; | |
274 | u32 kernel_sectors; | |
275 | u32 sectors_per_page; | |
0528979f | 276 | struct disk_partition info; |
efeccfe7 SP |
277 | int res; |
278 | ||
279 | puts("Flashing zImage\n"); | |
280 | ||
281 | /* Get boot partition info */ | |
282 | res = part_get_info_by_name(dev_desc, BOOT_PARTITION_NAME, &info); | |
283 | if (res < 0) { | |
1ad5facb | 284 | pr_err("cannot find boot partition\n"); |
c4ded03e | 285 | fastboot_fail("cannot find boot partition", response); |
efeccfe7 SP |
286 | return -1; |
287 | } | |
288 | ||
289 | /* Put boot image header in fastboot buffer after downloaded zImage */ | |
2341c80c | 290 | hdr_addr = (uintptr_t)download_buffer + ALIGN(download_bytes, PAGE_SIZE); |
efeccfe7 SP |
291 | hdr = (struct andr_img_hdr *)hdr_addr; |
292 | ||
293 | /* Read boot image header */ | |
c4ded03e | 294 | hdr_sectors = fb_mmc_get_boot_header(dev_desc, &info, hdr, response); |
efeccfe7 | 295 | if (hdr_sectors == 0) { |
1ad5facb | 296 | pr_err("unable to read boot image header\n"); |
c4ded03e | 297 | fastboot_fail("unable to read boot image header", response); |
efeccfe7 SP |
298 | return -1; |
299 | } | |
300 | ||
301 | /* Check if boot image has second stage in it (we don't support it) */ | |
302 | if (hdr->second_size > 0) { | |
1ad5facb | 303 | pr_err("moving second stage is not supported yet\n"); |
c4ded03e AK |
304 | fastboot_fail("moving second stage is not supported yet", |
305 | response); | |
efeccfe7 SP |
306 | return -1; |
307 | } | |
308 | ||
309 | /* Extract ramdisk location */ | |
310 | sectors_per_page = hdr->page_size / info.blksz; | |
311 | ramdisk_sector_start = info.start + sectors_per_page; | |
312 | ramdisk_sector_start += DIV_ROUND_UP(hdr->kernel_size, hdr->page_size) * | |
313 | sectors_per_page; | |
314 | ramdisk_sectors = DIV_ROUND_UP(hdr->ramdisk_size, hdr->page_size) * | |
315 | sectors_per_page; | |
316 | ||
317 | /* Read ramdisk and put it in fastboot buffer after boot image header */ | |
318 | ramdisk_buffer = (u8 *)hdr + (hdr_sectors * info.blksz); | |
319 | res = blk_dread(dev_desc, ramdisk_sector_start, ramdisk_sectors, | |
320 | ramdisk_buffer); | |
6bafa5a4 | 321 | if (res != ramdisk_sectors) { |
1ad5facb | 322 | pr_err("cannot read ramdisk from boot partition\n"); |
c4ded03e AK |
323 | fastboot_fail("cannot read ramdisk from boot partition", |
324 | response); | |
efeccfe7 SP |
325 | return -1; |
326 | } | |
327 | ||
328 | /* Write new kernel size to boot image header */ | |
329 | hdr->kernel_size = download_bytes; | |
330 | res = blk_dwrite(dev_desc, info.start, hdr_sectors, (void *)hdr); | |
331 | if (res == 0) { | |
1ad5facb | 332 | pr_err("cannot writeback boot image header\n"); |
c4ded03e | 333 | fastboot_fail("cannot write back boot image header", response); |
efeccfe7 SP |
334 | return -1; |
335 | } | |
336 | ||
337 | /* Write the new downloaded kernel */ | |
338 | kernel_sector_start = info.start + sectors_per_page; | |
339 | kernel_sectors = DIV_ROUND_UP(hdr->kernel_size, hdr->page_size) * | |
340 | sectors_per_page; | |
341 | res = blk_dwrite(dev_desc, kernel_sector_start, kernel_sectors, | |
342 | download_buffer); | |
343 | if (res == 0) { | |
1ad5facb | 344 | pr_err("cannot write new kernel\n"); |
c4ded03e | 345 | fastboot_fail("cannot write new kernel", response); |
efeccfe7 SP |
346 | return -1; |
347 | } | |
348 | ||
349 | /* Write the saved ramdisk back */ | |
350 | ramdisk_sector_start = info.start + sectors_per_page; | |
351 | ramdisk_sector_start += DIV_ROUND_UP(hdr->kernel_size, hdr->page_size) * | |
352 | sectors_per_page; | |
353 | res = blk_dwrite(dev_desc, ramdisk_sector_start, ramdisk_sectors, | |
354 | ramdisk_buffer); | |
355 | if (res == 0) { | |
1ad5facb | 356 | pr_err("cannot write back original ramdisk\n"); |
c4ded03e | 357 | fastboot_fail("cannot write back original ramdisk", response); |
efeccfe7 SP |
358 | return -1; |
359 | } | |
360 | ||
361 | puts("........ zImage was updated in boot partition\n"); | |
c4ded03e | 362 | fastboot_okay(NULL, response); |
efeccfe7 SP |
363 | return 0; |
364 | } | |
365 | #endif | |
366 | ||
f73a7df9 AK |
367 | /** |
368 | * fastboot_mmc_get_part_info() - Lookup eMMC partion by name | |
369 | * | |
370 | * @part_name: Named partition to lookup | |
371 | * @dev_desc: Pointer to returned blk_desc pointer | |
0528979f | 372 | * @part_info: Pointer to returned struct disk_partition |
f73a7df9 AK |
373 | * @response: Pointer to fastboot response buffer |
374 | */ | |
cacb03e4 SP |
375 | int fastboot_mmc_get_part_info(const char *part_name, |
376 | struct blk_desc **dev_desc, | |
0528979f | 377 | struct disk_partition *part_info, char *response) |
f73a7df9 AK |
378 | { |
379 | int r; | |
380 | ||
381 | *dev_desc = blk_get_dev("mmc", CONFIG_FASTBOOT_FLASH_MMC_DEV); | |
382 | if (!*dev_desc) { | |
383 | fastboot_fail("block device not found", response); | |
384 | return -ENOENT; | |
385 | } | |
a40297d7 ER |
386 | if (!part_name || !strcmp(part_name, "")) { |
387 | fastboot_fail("partition not given", response); | |
f73a7df9 AK |
388 | return -ENOENT; |
389 | } | |
390 | ||
391 | r = part_get_info_by_name_or_alias(*dev_desc, part_name, part_info); | |
392 | if (r < 0) { | |
393 | fastboot_fail("partition not found", response); | |
394 | return r; | |
395 | } | |
396 | ||
397 | return r; | |
398 | } | |
399 | ||
d1a119d4 AK |
400 | /** |
401 | * fastboot_mmc_flash_write() - Write image to eMMC for fastboot | |
402 | * | |
403 | * @cmd: Named partition to write image to | |
404 | * @download_buffer: Pointer to image data | |
405 | * @download_bytes: Size of image data | |
406 | * @response: Pointer to fastboot response buffer | |
407 | */ | |
408 | void fastboot_mmc_flash_write(const char *cmd, void *download_buffer, | |
f73a7df9 | 409 | u32 download_bytes, char *response) |
c0aebb33 | 410 | { |
4101f687 | 411 | struct blk_desc *dev_desc; |
0528979f | 412 | struct disk_partition info; |
c0aebb33 | 413 | |
db1d9e78 | 414 | dev_desc = blk_get_dev("mmc", CONFIG_FASTBOOT_FLASH_MMC_DEV); |
c0aebb33 | 415 | if (!dev_desc || dev_desc->type == DEV_TYPE_UNKNOWN) { |
9b643e31 | 416 | pr_err("invalid mmc device\n"); |
c4ded03e | 417 | fastboot_fail("invalid mmc device", response); |
c0aebb33 SR |
418 | return; |
419 | } | |
420 | ||
1fdbad02 | 421 | #ifdef CONFIG_FASTBOOT_MMC_BOOT1_SUPPORT |
422 | if (strcmp(cmd, CONFIG_FASTBOOT_MMC_BOOT1_NAME) == 0) { | |
423 | fb_mmc_boot1_ops(dev_desc, download_buffer, | |
424 | download_bytes, response); | |
425 | return; | |
426 | } | |
427 | #endif | |
428 | ||
bd42a942 | 429 | #if CONFIG_IS_ENABLED(EFI_PARTITION) |
1fdbad02 | 430 | #ifndef CONFIG_FASTBOOT_MMC_USER_NAME |
0ff7e585 | 431 | if (strcmp(cmd, CONFIG_FASTBOOT_GPT_NAME) == 0) { |
1fdbad02 | 432 | #else |
433 | if (strcmp(cmd, CONFIG_FASTBOOT_GPT_NAME) == 0 || | |
434 | strcmp(cmd, CONFIG_FASTBOOT_MMC_USER_NAME) == 0) { | |
435 | #endif | |
0ff7e585 SR |
436 | printf("%s: updating MBR, Primary and Backup GPT(s)\n", |
437 | __func__); | |
438 | if (is_valid_gpt_buf(dev_desc, download_buffer)) { | |
439 | printf("%s: invalid GPT - refusing to write to flash\n", | |
440 | __func__); | |
c4ded03e | 441 | fastboot_fail("invalid GPT partition", response); |
0ff7e585 SR |
442 | return; |
443 | } | |
444 | if (write_mbr_and_gpt_partitions(dev_desc, download_buffer)) { | |
445 | printf("%s: writing GPT partitions failed\n", __func__); | |
c4ded03e AK |
446 | fastboot_fail("writing GPT partitions failed", |
447 | response); | |
0ff7e585 SR |
448 | return; |
449 | } | |
450 | printf("........ success\n"); | |
c4ded03e | 451 | fastboot_okay(NULL, response); |
0ff7e585 | 452 | return; |
b6dd69a4 PK |
453 | } |
454 | #endif | |
455 | ||
b0cf7339 | 456 | #if CONFIG_IS_ENABLED(DOS_PARTITION) |
b6dd69a4 PK |
457 | if (strcmp(cmd, CONFIG_FASTBOOT_MBR_NAME) == 0) { |
458 | printf("%s: updating MBR\n", __func__); | |
459 | if (is_valid_dos_buf(download_buffer)) { | |
460 | printf("%s: invalid MBR - refusing to write to flash\n", | |
461 | __func__); | |
c4ded03e | 462 | fastboot_fail("invalid MBR partition", response); |
b6dd69a4 PK |
463 | return; |
464 | } | |
465 | if (write_mbr_partition(dev_desc, download_buffer)) { | |
466 | printf("%s: writing MBR partition failed\n", __func__); | |
c4ded03e AK |
467 | fastboot_fail("writing MBR partition failed", |
468 | response); | |
b6dd69a4 PK |
469 | return; |
470 | } | |
471 | printf("........ success\n"); | |
c4ded03e | 472 | fastboot_okay(NULL, response); |
b6dd69a4 PK |
473 | return; |
474 | } | |
475 | #endif | |
476 | ||
efeccfe7 SP |
477 | #ifdef CONFIG_ANDROID_BOOT_IMAGE |
478 | if (strncasecmp(cmd, "zimage", 6) == 0) { | |
c4ded03e AK |
479 | fb_mmc_update_zimage(dev_desc, download_buffer, |
480 | download_bytes, response); | |
efeccfe7 SP |
481 | return; |
482 | } | |
483 | #endif | |
484 | ||
88b6329c | 485 | if (part_get_info_by_name_or_alias(dev_desc, cmd, &info) < 0) { |
9b643e31 | 486 | pr_err("cannot find partition: '%s'\n", cmd); |
c4ded03e | 487 | fastboot_fail("cannot find partition", response); |
c0aebb33 SR |
488 | return; |
489 | } | |
490 | ||
a5d1e04a MR |
491 | if (is_sparse_image(download_buffer)) { |
492 | struct fb_mmc_sparse sparse_priv; | |
cc0f08cd | 493 | struct sparse_storage sparse; |
2f83f219 | 494 | int err; |
a5d1e04a MR |
495 | |
496 | sparse_priv.dev_desc = dev_desc; | |
497 | ||
cc0f08cd | 498 | sparse.blksz = info.blksz; |
a5d1e04a MR |
499 | sparse.start = info.start; |
500 | sparse.size = info.size; | |
a5d1e04a | 501 | sparse.write = fb_mmc_sparse_write; |
2c724046 | 502 | sparse.reserve = fb_mmc_sparse_reserve; |
2f83f219 | 503 | sparse.mssg = fastboot_fail; |
a5d1e04a MR |
504 | |
505 | printf("Flashing sparse image at offset " LBAFU "\n", | |
cc0f08cd | 506 | sparse.start); |
a5d1e04a | 507 | |
cc0f08cd | 508 | sparse.priv = &sparse_priv; |
c4ded03e AK |
509 | err = write_sparse_image(&sparse, cmd, download_buffer, |
510 | response); | |
2f83f219 | 511 | if (!err) |
c4ded03e | 512 | fastboot_okay(NULL, response); |
a5d1e04a | 513 | } else { |
e5bf9878 | 514 | write_raw_image(dev_desc, &info, cmd, download_buffer, |
c4ded03e | 515 | download_bytes, response); |
a5d1e04a | 516 | } |
c0aebb33 | 517 | } |
89792381 | 518 | |
d1a119d4 AK |
519 | /** |
520 | * fastboot_mmc_flash_erase() - Erase eMMC for fastboot | |
521 | * | |
522 | * @cmd: Named partition to erase | |
523 | * @response: Pointer to fastboot response buffer | |
524 | */ | |
525 | void fastboot_mmc_erase(const char *cmd, char *response) | |
89792381 DK |
526 | { |
527 | int ret; | |
4101f687 | 528 | struct blk_desc *dev_desc; |
0528979f | 529 | struct disk_partition info; |
89792381 DK |
530 | lbaint_t blks, blks_start, blks_size, grp_size; |
531 | struct mmc *mmc = find_mmc_device(CONFIG_FASTBOOT_FLASH_MMC_DEV); | |
532 | ||
533 | if (mmc == NULL) { | |
1ad5facb | 534 | pr_err("invalid mmc device\n"); |
c4ded03e | 535 | fastboot_fail("invalid mmc device", response); |
89792381 DK |
536 | return; |
537 | } | |
538 | ||
db1d9e78 | 539 | dev_desc = blk_get_dev("mmc", CONFIG_FASTBOOT_FLASH_MMC_DEV); |
89792381 | 540 | if (!dev_desc || dev_desc->type == DEV_TYPE_UNKNOWN) { |
1ad5facb | 541 | pr_err("invalid mmc device\n"); |
c4ded03e | 542 | fastboot_fail("invalid mmc device", response); |
89792381 DK |
543 | return; |
544 | } | |
545 | ||
1fdbad02 | 546 | #ifdef CONFIG_FASTBOOT_MMC_BOOT1_SUPPORT |
547 | if (strcmp(cmd, CONFIG_FASTBOOT_MMC_BOOT1_NAME) == 0) { | |
548 | /* erase EMMC boot1 */ | |
549 | fb_mmc_boot1_ops(dev_desc, NULL, 0, response); | |
550 | return; | |
551 | } | |
552 | #endif | |
553 | ||
554 | #ifdef CONFIG_FASTBOOT_MMC_USER_NAME | |
555 | if (strcmp(cmd, CONFIG_FASTBOOT_MMC_USER_NAME) == 0) { | |
556 | /* erase EMMC userdata */ | |
557 | if (fb_mmc_erase_mmc_hwpart(dev_desc)) | |
558 | fastboot_fail("Failed to erase EMMC_USER", response); | |
559 | else | |
560 | fastboot_okay(NULL, response); | |
561 | return; | |
562 | } | |
563 | #endif | |
564 | ||
b6dd69a4 | 565 | ret = part_get_info_by_name_or_alias(dev_desc, cmd, &info); |
88b6329c | 566 | if (ret < 0) { |
1ad5facb | 567 | pr_err("cannot find partition: '%s'\n", cmd); |
c4ded03e | 568 | fastboot_fail("cannot find partition", response); |
89792381 DK |
569 | return; |
570 | } | |
571 | ||
572 | /* Align blocks to erase group size to avoid erasing other partitions */ | |
573 | grp_size = mmc->erase_grp_size; | |
574 | blks_start = (info.start + grp_size - 1) & ~(grp_size - 1); | |
575 | if (info.size >= grp_size) | |
576 | blks_size = (info.size - (blks_start - info.start)) & | |
577 | (~(grp_size - 1)); | |
578 | else | |
579 | blks_size = 0; | |
580 | ||
581 | printf("Erasing blocks " LBAFU " to " LBAFU " due to alignment\n", | |
582 | blks_start, blks_start + blks_size); | |
583 | ||
f73a7df9 AK |
584 | blks = fb_mmc_blk_write(dev_desc, blks_start, blks_size, NULL); |
585 | ||
89792381 | 586 | if (blks != blks_size) { |
1ad5facb | 587 | pr_err("failed erasing from device %d\n", dev_desc->devnum); |
c4ded03e | 588 | fastboot_fail("failed erasing from device", response); |
89792381 DK |
589 | return; |
590 | } | |
591 | ||
592 | printf("........ erased " LBAFU " bytes from '%s'\n", | |
593 | blks_size * info.blksz, cmd); | |
c4ded03e | 594 | fastboot_okay(NULL, response); |
89792381 | 595 | } |