blob: b31a9fb929c53d40ff354e598d7658caacf42ddb [file] [log] [blame]
Steve Raec0aebb32014-08-26 11:47:27 -07001/*
2 * Copyright 2014 Broadcom Corporation.
3 *
4 * SPDX-License-Identifier: GPL-2.0+
5 */
6
Steve Rae0ff7e582014-12-12 15:51:54 -08007#include <config.h>
Steve Raec0aebb32014-08-26 11:47:27 -07008#include <common.h>
Maxime Ripard3c8f98f2015-10-15 14:34:13 +02009#include <fastboot.h>
Steve Raec0aebb32014-08-26 11:47:27 -070010#include <fb_mmc.h>
11#include <part.h>
Steve Raee5bf9872014-08-26 11:47:30 -070012#include <aboot.h>
13#include <sparse_format.h>
Dileep Katta89792382015-02-17 18:48:23 +053014#include <mmc.h>
Steve Raec0aebb32014-08-26 11:47:27 -070015
Steve Rae0ff7e582014-12-12 15:51:54 -080016#ifndef CONFIG_FASTBOOT_GPT_NAME
17#define CONFIG_FASTBOOT_GPT_NAME GPT_ENTRY_NAME
18#endif
19
Steve Raec0aebb32014-08-26 11:47:27 -070020static char *response_str;
21
Michael Scott8a418022015-03-11 10:02:31 -070022static int get_partition_info_efi_by_name_or_alias(block_dev_desc_t *dev_desc,
23 const char *name, disk_partition_t *info)
24{
25 int ret;
26
27 ret = get_partition_info_efi_by_name(dev_desc, name, info);
28 if (ret) {
29 /* strlen("fastboot_partition_alias_") + 32(part_name) + 1 */
30 char env_alias_name[25 + 32 + 1];
31 char *aliased_part_name;
32
33 /* check for alias */
34 strcpy(env_alias_name, "fastboot_partition_alias_");
35 strncat(env_alias_name, name, 32);
36 aliased_part_name = getenv(env_alias_name);
37 if (aliased_part_name != NULL)
38 ret = get_partition_info_efi_by_name(dev_desc,
39 aliased_part_name, info);
40 }
41 return ret;
42}
43
Steve Raec0aebb32014-08-26 11:47:27 -070044static void write_raw_image(block_dev_desc_t *dev_desc, disk_partition_t *info,
45 const char *part_name, void *buffer,
46 unsigned int download_bytes)
47{
48 lbaint_t blkcnt;
49 lbaint_t blks;
50
51 /* determine number of blocks to write */
52 blkcnt = ((download_bytes + (info->blksz - 1)) & ~(info->blksz - 1));
53 blkcnt = blkcnt / info->blksz;
54
55 if (blkcnt > info->size) {
56 error("too large for partition: '%s'\n", part_name);
Maxime Ripard3c8f98f2015-10-15 14:34:13 +020057 fastboot_fail(response_str, "too large for partition");
Steve Raec0aebb32014-08-26 11:47:27 -070058 return;
59 }
60
61 puts("Flashing Raw Image\n");
62
63 blks = dev_desc->block_write(dev_desc->dev, info->start, blkcnt,
64 buffer);
65 if (blks != blkcnt) {
66 error("failed writing to device %d\n", dev_desc->dev);
Maxime Ripard3c8f98f2015-10-15 14:34:13 +020067 fastboot_fail(response_str, "failed writing to device");
Steve Raec0aebb32014-08-26 11:47:27 -070068 return;
69 }
70
71 printf("........ wrote " LBAFU " bytes to '%s'\n", blkcnt * info->blksz,
72 part_name);
Maxime Ripard3c8f98f2015-10-15 14:34:13 +020073 fastboot_okay(response_str, "");
Steve Raec0aebb32014-08-26 11:47:27 -070074}
75
76void fb_mmc_flash_write(const char *cmd, void *download_buffer,
77 unsigned int download_bytes, char *response)
78{
Steve Raec0aebb32014-08-26 11:47:27 -070079 block_dev_desc_t *dev_desc;
80 disk_partition_t info;
81
82 /* initialize the response buffer */
83 response_str = response;
84
85 dev_desc = get_dev("mmc", CONFIG_FASTBOOT_FLASH_MMC_DEV);
86 if (!dev_desc || dev_desc->type == DEV_TYPE_UNKNOWN) {
87 error("invalid mmc device\n");
Maxime Ripard3c8f98f2015-10-15 14:34:13 +020088 fastboot_fail(response_str, "invalid mmc device");
Steve Raec0aebb32014-08-26 11:47:27 -070089 return;
90 }
91
Steve Rae0ff7e582014-12-12 15:51:54 -080092 if (strcmp(cmd, CONFIG_FASTBOOT_GPT_NAME) == 0) {
93 printf("%s: updating MBR, Primary and Backup GPT(s)\n",
94 __func__);
95 if (is_valid_gpt_buf(dev_desc, download_buffer)) {
96 printf("%s: invalid GPT - refusing to write to flash\n",
97 __func__);
Maxime Ripard3c8f98f2015-10-15 14:34:13 +020098 fastboot_fail(response_str, "invalid GPT partition");
Steve Rae0ff7e582014-12-12 15:51:54 -080099 return;
100 }
101 if (write_mbr_and_gpt_partitions(dev_desc, download_buffer)) {
102 printf("%s: writing GPT partitions failed\n", __func__);
Maxime Ripard3c8f98f2015-10-15 14:34:13 +0200103 fastboot_fail(response_str,
104 "writing GPT partitions failed");
Steve Rae0ff7e582014-12-12 15:51:54 -0800105 return;
106 }
107 printf("........ success\n");
Maxime Ripard3c8f98f2015-10-15 14:34:13 +0200108 fastboot_okay(response_str, "");
Steve Rae0ff7e582014-12-12 15:51:54 -0800109 return;
Michael Scott8a418022015-03-11 10:02:31 -0700110 } else if (get_partition_info_efi_by_name_or_alias(dev_desc, cmd, &info)) {
Steve Raec0aebb32014-08-26 11:47:27 -0700111 error("cannot find partition: '%s'\n", cmd);
Maxime Ripard3c8f98f2015-10-15 14:34:13 +0200112 fastboot_fail(response_str, "cannot find partition");
Steve Raec0aebb32014-08-26 11:47:27 -0700113 return;
114 }
115
Steve Raee5bf9872014-08-26 11:47:30 -0700116 if (is_sparse_image(download_buffer))
117 write_sparse_image(dev_desc, &info, cmd, download_buffer,
118 download_bytes);
119 else
120 write_raw_image(dev_desc, &info, cmd, download_buffer,
121 download_bytes);
Maxime Ripard3c8f98f2015-10-15 14:34:13 +0200122
123 fastboot_okay(response_str, "");
Steve Raec0aebb32014-08-26 11:47:27 -0700124}
Dileep Katta89792382015-02-17 18:48:23 +0530125
126void fb_mmc_erase(const char *cmd, char *response)
127{
128 int ret;
129 block_dev_desc_t *dev_desc;
130 disk_partition_t info;
131 lbaint_t blks, blks_start, blks_size, grp_size;
132 struct mmc *mmc = find_mmc_device(CONFIG_FASTBOOT_FLASH_MMC_DEV);
133
134 if (mmc == NULL) {
135 error("invalid mmc device");
Maxime Ripard3c8f98f2015-10-15 14:34:13 +0200136 fastboot_fail(response_str, "invalid mmc device");
Dileep Katta89792382015-02-17 18:48:23 +0530137 return;
138 }
139
140 /* initialize the response buffer */
141 response_str = response;
142
143 dev_desc = get_dev("mmc", CONFIG_FASTBOOT_FLASH_MMC_DEV);
144 if (!dev_desc || dev_desc->type == DEV_TYPE_UNKNOWN) {
145 error("invalid mmc device");
Maxime Ripard3c8f98f2015-10-15 14:34:13 +0200146 fastboot_fail(response_str, "invalid mmc device");
Dileep Katta89792382015-02-17 18:48:23 +0530147 return;
148 }
149
Michael Scott8a418022015-03-11 10:02:31 -0700150 ret = get_partition_info_efi_by_name_or_alias(dev_desc, cmd, &info);
Dileep Katta89792382015-02-17 18:48:23 +0530151 if (ret) {
152 error("cannot find partition: '%s'", cmd);
Maxime Ripard3c8f98f2015-10-15 14:34:13 +0200153 fastboot_fail(response_str, "cannot find partition");
Dileep Katta89792382015-02-17 18:48:23 +0530154 return;
155 }
156
157 /* Align blocks to erase group size to avoid erasing other partitions */
158 grp_size = mmc->erase_grp_size;
159 blks_start = (info.start + grp_size - 1) & ~(grp_size - 1);
160 if (info.size >= grp_size)
161 blks_size = (info.size - (blks_start - info.start)) &
162 (~(grp_size - 1));
163 else
164 blks_size = 0;
165
166 printf("Erasing blocks " LBAFU " to " LBAFU " due to alignment\n",
167 blks_start, blks_start + blks_size);
168
169 blks = dev_desc->block_erase(dev_desc->dev, blks_start, blks_size);
170 if (blks != blks_size) {
171 error("failed erasing from device %d", dev_desc->dev);
Maxime Ripard3c8f98f2015-10-15 14:34:13 +0200172 fastboot_fail(response_str, "failed erasing from device");
Dileep Katta89792382015-02-17 18:48:23 +0530173 return;
174 }
175
176 printf("........ erased " LBAFU " bytes from '%s'\n",
177 blks_size * info.blksz, cmd);
Maxime Ripard3c8f98f2015-10-15 14:34:13 +0200178 fastboot_okay(response_str, "");
Dileep Katta89792382015-02-17 18:48:23 +0530179}