@@ -110,6 +110,11 @@ static struct Command commands[] = {
"Send Sanitize command to the <device>.\nThis will delete the unmapped memory region of the device.",
NULL
},
+ { do_emmc50_ffu, -2,
+ "ffu", "<image name> <device>\n"
+ "run eMMC 5.0 Field firmware update.\n.",
+ NULL
+ },
{ 0, 0, 0, 0 }
};
@@ -64,6 +64,7 @@
#define EXT_CSD_ENH_START_ADDR_2 138
#define EXT_CSD_ENH_START_ADDR_1 137
#define EXT_CSD_ENH_START_ADDR_0 136
+#define EXT_CSD_REV 192
#define EXT_CSD_NATIVE_SECTOR_SIZE 63 /* R */
#define EXT_CSD_USE_NATIVE_SECTOR 62 /* R/W */
#define EXT_CSD_DATA_SECTOR_SIZE 61 /* R */
@@ -79,6 +80,9 @@
*/
#define BKOPS_ENABLE (1<<0)
+#define MMC_FFU_DOWNLOAD_OP 302
+#define MMC_FFU_INSTALL_OP 303
+
/*
* EXT_CSD field definitions
*/
@@ -1142,7 +1142,7 @@ int do_sanitize(int nargs, char **argv)
char *device;
CHECK(nargs != 2, "Usage: mmc sanitize </path/to/mmcblkX>\n",
- exit(1));
+ exit(1));
device = argv[1];
@@ -1163,3 +1163,94 @@ int do_sanitize(int nargs, char **argv)
}
+static int ffu_download_image(char *fname, int mmc_fd, int blk_size)
+{
+ int ret = 0;
+ struct mmc_ioc_cmd mmc_ioc_cmd;
+ char firmware_name[512];
+
+ memset(firmware_name, 0, sizeof(firmware_name));
+ memcpy(firmware_name, fname, strlen(fname));
+
+ /* prepare and send ioctl */
+ memset(&mmc_ioc_cmd, 0, sizeof(mmc_ioc_cmd));
+ mmc_ioc_cmd.opcode = MMC_FFU_DOWNLOAD_OP;
+ mmc_ioc_cmd.blksz = blk_size;
+ mmc_ioc_cmd.blocks = 1;
+ mmc_ioc_cmd.arg = 0;
+ mmc_ioc_cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+ mmc_ioc_cmd.write_flag = 1;
+ mmc_ioc_cmd_set_data(mmc_ioc_cmd, firmware_name);
+ ret = ioctl(mmc_fd, MMC_IOC_CMD, &mmc_ioc_cmd);
+ if (ret) {
+ fprintf(stderr, "ioctl FW download error%d\n", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int ffu_install(int mmc_fd, int blk_size)
+{
+ int ret;
+ struct mmc_ioc_cmd mmc_ioc_cmd;
+
+ memset(&mmc_ioc_cmd, 0, sizeof(mmc_ioc_cmd));
+ mmc_ioc_cmd.opcode = MMC_FFU_INSTALL_OP;
+ mmc_ioc_cmd.blksz = blk_size;
+ mmc_ioc_cmd.blocks = 0;
+ mmc_ioc_cmd.arg = 0;
+ mmc_ioc_cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+ mmc_ioc_cmd.write_flag = 0;
+ ret = ioctl(mmc_fd, MMC_IOC_CMD, &mmc_ioc_cmd);
+
+ return ret;
+}
+
+int do_emmc50_ffu (int nargs, char **argv)
+{
+ int fd, ret;
+ char *device;
+ char *path;
+ __u8 ext_csd[512];
+ int blk_size;
+
+ CHECK(nargs != 3, "Usage: ffu <image name> </path/to/mmcblkX> \n",
+ exit(1));
+
+ device = argv[2];
+ fd = open(device, O_RDWR);
+ if (fd < 0) {
+ perror("open");
+ exit(1);
+ }
+
+ ret = read_extcsd(fd, ext_csd);
+ if (ret) {
+ fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
+ exit(1);
+ }
+
+ if (ext_csd[EXT_CSD_REV] < 7) {
+ fprintf(stderr, "FFU is not supported on device %s\n", device);
+ exit(1);
+ }
+
+ blk_size = (ext_csd[EXT_CSD_DATA_SECTOR_SIZE] == 0) ? 512 : 4096;
+ path = argv[1];
+ ret = ffu_download_image(path, fd, blk_size);
+ if (ret) {
+ fprintf(stderr, "FFU failed %d\n", ret);
+ exit(1);
+ }
+
+ ret = ffu_install(fd, blk_size);
+ if (ret) {
+ fprintf(stderr, "FFU failed %d\n", ret);
+ exit(1);
+ }
+
+ close(fd);
+ fprintf(stderr, "FFU finished with status %d \n", ret);
+ return ret;
+}
@@ -28,3 +28,4 @@ int do_sanitize(int nargs, char **argv);
int do_status_get(int nargs, char **argv);
int do_enh_area_set(int nargs, char **argv);
int do_write_reliability_set(int nargs, char **argv);
+int do_emmc50_ffu(int nargs, char **argv);