@@ -234,7 +234,8 @@ static struct Command commands[] = {
"should be in decimal bytes and sector aligned.\n"
"[-m <ffu_mode>] Optional, provides five firmware bundle download command modes:\n"
" -m 1: Default mode (CMD6+CMD23+CMD25+CMD6 repeated), may exit FFU mode if the firmware size exceeds chunk size.\n"
- " -m 2: FFU mode 2 (enter FFU mode, CMD23+CMD25 repeated, exit FFU mode), stays in FFU mode until firmware download completes.\n",
+ " -m 2: FFU mode 2 (enter FFU mode, CMD23+CMD25 repeated, exit FFU mode), stays in FFU mode until firmware download completes.\n"
+ " -m 3: FFU mode 3 (enter FFU mode, CMD25+CMD12 repeated, exit FFU mode), stays in FFU mode until firmware download completes.\n",
NULL
},
{ do_erase, -4,
@@ -27,6 +27,7 @@
#define MMC_BOOT_INITIATION_ARG 0xFFFFFFFA
#define MMC_SWITCH 6 /* ac [31:0] See below R1b */
#define MMC_SEND_EXT_CSD 8 /* adtc R1 */
+#define MMC_STOP_TRANSMISSION 12 /* ac R1b */
#define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */
#define R1_SWITCH_ERROR (1 << 7) /* sx, c */
#define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */
@@ -48,6 +48,13 @@ static void set_ffu_download_cmd(struct mmc_ioc_multi_cmd *multi_cmd, __u8 *ext_
multi_cmd->cmds[0].flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
set_single_cmd(&multi_cmd->cmds[1], MMC_WRITE_MULTIPLE_BLOCK, 1, bytes / 512, arg);
mmc_ioc_cmd_set_data(multi_cmd->cmds[1], buf + offset);
+ } else if (ffu_mode == 3) {
+ set_single_cmd(&multi_cmd->cmds[0], MMC_WRITE_MULTIPLE_BLOCK, 1, bytes / 512, arg);
+ multi_cmd->cmds[0].flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+ mmc_ioc_cmd_set_data(multi_cmd->cmds[0], buf + offset);
+ set_single_cmd(&multi_cmd->cmds[1], MMC_STOP_TRANSMISSION, 0, 0, 0);
+ multi_cmd->cmds[1].flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+
}
}
@@ -231,7 +238,7 @@ int do_ffu(int nargs, char **argv)
break;
case 'm':
ffu_mode = atoi(optarg);
- if (ffu_mode > 2) {
+ if (ffu_mode > 3) {
fprintf(stderr, "Unsupported ffu mode `%d'.\n", ffu_mode);
abort();
}