xref: /rk3399_rockchip-uboot/common/fb_mmc.c (revision 3c8f98f5fed5c6f03bb185b79191477885748b14)
1 /*
2  * Copyright 2014 Broadcom Corporation.
3  *
4  * SPDX-License-Identifier:	GPL-2.0+
5  */
6 
7 #include <config.h>
8 #include <common.h>
9 #include <fastboot.h>
10 #include <fb_mmc.h>
11 #include <part.h>
12 #include <aboot.h>
13 #include <sparse_format.h>
14 #include <mmc.h>
15 
16 #ifndef CONFIG_FASTBOOT_GPT_NAME
17 #define CONFIG_FASTBOOT_GPT_NAME GPT_ENTRY_NAME
18 #endif
19 
20 static char *response_str;
21 
22 static 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 
44 static 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);
57 		fastboot_fail(response_str, "too large for partition");
58 		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);
67 		fastboot_fail(response_str, "failed writing to device");
68 		return;
69 	}
70 
71 	printf("........ wrote " LBAFU " bytes to '%s'\n", blkcnt * info->blksz,
72 	       part_name);
73 	fastboot_okay(response_str, "");
74 }
75 
76 void fb_mmc_flash_write(const char *cmd, void *download_buffer,
77 			unsigned int download_bytes, char *response)
78 {
79 	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");
88 		fastboot_fail(response_str, "invalid mmc device");
89 		return;
90 	}
91 
92 	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__);
98 			fastboot_fail(response_str, "invalid GPT partition");
99 			return;
100 		}
101 		if (write_mbr_and_gpt_partitions(dev_desc, download_buffer)) {
102 			printf("%s: writing GPT partitions failed\n", __func__);
103 			fastboot_fail(response_str,
104 				      "writing GPT partitions failed");
105 			return;
106 		}
107 		printf("........ success\n");
108 		fastboot_okay(response_str, "");
109 		return;
110 	} else if (get_partition_info_efi_by_name_or_alias(dev_desc, cmd, &info)) {
111 		error("cannot find partition: '%s'\n", cmd);
112 		fastboot_fail(response_str, "cannot find partition");
113 		return;
114 	}
115 
116 	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);
122 
123 	fastboot_okay(response_str, "");
124 }
125 
126 void 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");
136 		fastboot_fail(response_str, "invalid mmc device");
137 		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");
146 		fastboot_fail(response_str, "invalid mmc device");
147 		return;
148 	}
149 
150 	ret = get_partition_info_efi_by_name_or_alias(dev_desc, cmd, &info);
151 	if (ret) {
152 		error("cannot find partition: '%s'", cmd);
153 		fastboot_fail(response_str, "cannot find partition");
154 		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);
172 		fastboot_fail(response_str, "failed erasing from device");
173 		return;
174 	}
175 
176 	printf("........ erased " LBAFU " bytes from '%s'\n",
177 	       blks_size * info.blksz, cmd);
178 	fastboot_okay(response_str, "");
179 }
180