FW: [PATCH] mmc-utils: modified FFU to use multiple write command

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Until now the FW was written in a Single Write Command (CMD24) mode.
In order to write the firmware, the host sends hundreds of CMD24.
By using new mode (closed ended multiple write: CMD23,CMD25), the number of write commands is reduced to few commands.
In case the host doesn't support closed ended writing, flash the ffu by single sector writing.
By set [sector] to 1 or omit this parameter.

Signed-off-by: Arthur Simchaev <Arthur.Simchaev@xxxxxxxxxxx>
---
 mmc.c      |   10 +++-
 mmc.h      |    1 +
 mmc_cmds.c |  184 ++++++++++++++++++++++++++++++++++++++++++++----------------
 3 files changed, 146 insertions(+), 49 deletions(-)

diff --git a/mmc.c b/mmc.c
index 50c9c9e..069ce9f 100644
--- a/mmc.c
+++ b/mmc.c
@@ -211,8 +211,14 @@ static struct Command commands[] = {
 	  NULL
 	},
 	{ do_ffu, -2,
-	  "ffu", "<image name> <device>\n"
-		"Run Field Firmware Update with <image name> on <device>.\n",
+	  "ffu", "<image name> <device> [sectors]\n"
+		  "Run Field Firmware Update with <image name> on <device>\n"
+		  "Write FFU file into device with number of blocks = <sectors>\n"
+		  "[sectors] is optional ,default value of the <sector> is 1 sector.\n"
+		  "In case the platform has [sectors] limitation\n"
+		  "(e.g. limited by hw, unsupported close ended writing),\n"
+		  "use default (one sector) command.\n"
+		  "[sectors] parameter cannot be more then MMC_IOC_MAX_BYTES/device 
+sector size\n",
 	  NULL
 	},
 	{ 0, 0, 0, 0 }
diff --git a/mmc.h b/mmc.h
index a3d732c..89ebb9f 100644
--- a/mmc.h
+++ b/mmc.h
@@ -37,6 +37,7 @@
 #define R1_SWITCH_ERROR   (1 << 7)  /* sx, c */
 #define MMC_SWITCH_MODE_WRITE_BYTE	0x03	/* Set target to value */
 #define MMC_READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data addr   R1  */
+#define MMC_SET_BLOCK_COUNT	23	/* adtc [31:0] data addr   R1  */
 #define MMC_WRITE_BLOCK		24	/* adtc [31:0] data addr	R1  */
 #define MMC_WRITE_MULTIPLE_BLOCK 25   /* adtc                    R1  */
 #define MMC_SET_WRITE_PROT	28    /* ac   [31:0] data addr   R1b */
diff --git a/mmc_cmds.c b/mmc_cmds.c
index 6b86115..c0df757 100644
--- a/mmc_cmds.c
+++ b/mmc_cmds.c
@@ -2357,18 +2357,21 @@ int do_ffu(int nargs, char **argv)
 	exit(1);
 #else
 	int dev_fd, img_fd;
-	int sect_done = 0, retry = 3, ret = -EINVAL;
+	int sect_done = 0, retry = 5, ret = -EINVAL;
+	int num_ioctl_blks  = 0;
 	unsigned int sect_size;
 	__u8 ext_csd[512];
-	__u8 *buf;
-	__u32 arg;
+	__u8 *buf = NULL;
+	__u32 arg = 0;
 	off_t fw_size;
-	ssize_t chunk_size;
+	int remain_fw_size = 0;
+	ssize_t chunk_size = 0;
 	char *device;
-	struct mmc_ioc_multi_cmd *multi_cmd;
-
-	CHECK(nargs != 3, "Usage: ffu <image name> </path/to/mmcblkX> \n",
-			exit(1));
+	struct mmc_ioc_multi_cmd *multi_cmd = NULL;
+	int bl_counter = 1;
+	CHECK(nargs != 3 && nargs != 4,
+		"Usage: ffu <image name> </path/to/mmcblkX> <sectors>\n",
+		exit(1));
 
 	device = argv[2];
 	dev_fd = open(device, O_RDWR);
@@ -2383,10 +2386,23 @@ int do_ffu(int nargs, char **argv)
 		exit(1);
 	}
 
-	buf = malloc(512);
-	multi_cmd = calloc(1, sizeof(struct mmc_ioc_multi_cmd) +
-				3 * sizeof(struct mmc_ioc_cmd));
-	if (!buf || !multi_cmd) {
+	if (nargs == 3)
+		bl_counter = 1;
+	else
+		bl_counter = atoi(argv[3]);
+	if (bl_counter <= 0) {
+		fprintf(stderr, "Wrong <sector> value %d\n", bl_counter);
+		goto out;
+	}
+
+	if (bl_counter == 1)
+		multi_cmd = calloc(1, sizeof(struct mmc_ioc_multi_cmd) +
+			3 * sizeof(struct mmc_ioc_cmd));
+	else/* using multiple write cmd */
+		multi_cmd = calloc(1, sizeof(struct mmc_ioc_multi_cmd) +
+			4 * sizeof(struct mmc_ioc_cmd));
+
+	if (!multi_cmd) {
 		perror("failed to allocate memory");
 		goto out;
 	}
@@ -2427,55 +2443,119 @@ int do_ffu(int nargs, char **argv)
 		goto out;
 	}
 
+	if (sect_size * bl_counter > MMC_IOC_MAX_BYTES) {
+		fprintf(stderr, "<sectors> parameter cannot be more when %d\n",
+				(int) MMC_IOC_MAX_BYTES/sect_size);
+		goto out;
+	}
+
+	buf = calloc(1, bl_counter * sect_size);
+	if (!buf) {
+		perror("failed to allocate memory");
+		goto out;
+	}
 	/* set CMD ARG */
 	arg = ext_csd[EXT_CSD_FFU_ARG_0] |
 		ext_csd[EXT_CSD_FFU_ARG_1] << 8 |
 		ext_csd[EXT_CSD_FFU_ARG_2] << 16 |
 		ext_csd[EXT_CSD_FFU_ARG_3] << 24;
+	/* In this case single write cmd will be use
+	 * Needed for the platform which doesn't support
+	 * close ended writing */
+	if (bl_counter == 1) {
+		multi_cmd->num_of_cmds = 3;
+		/* put device into ffu mode */
+		multi_cmd->cmds[0].opcode = MMC_SWITCH;
+		multi_cmd->cmds[0].arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
+				(EXT_CSD_MODE_CONFIG << 16) |
+				(EXT_CSD_FFU_MODE << 8) |
+				EXT_CSD_CMD_SET_NORMAL;
+		multi_cmd->cmds[0].flags = MMC_RSP_SPI_R1B |
+				MMC_RSP_R1B |
+				MMC_CMD_AC;
+		multi_cmd->cmds[0].write_flag = 1;
+
+		/* send image chunk */
+		multi_cmd->cmds[1].opcode = MMC_WRITE_BLOCK;
+		multi_cmd->cmds[1].blksz = sect_size;
+		multi_cmd->cmds[1].blocks = 1;
+		multi_cmd->cmds[1].arg = arg;
+		multi_cmd->cmds[1].flags = MMC_RSP_SPI_R1 |
+				MMC_RSP_R1 |
+				MMC_CMD_ADTC;
+		multi_cmd->cmds[1].write_flag = 1;
+		mmc_ioc_cmd_set_data(multi_cmd->cmds[1], buf);
 
-	/* prepare multi_cmd to be sent */
-	multi_cmd->num_of_cmds = 3;
+		/* return device into normal mode */
+		multi_cmd->cmds[2].opcode = MMC_SWITCH;
+		multi_cmd->cmds[2].arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
+				(EXT_CSD_MODE_CONFIG << 16) |
+				(EXT_CSD_NORMAL_MODE << 8) |
+				EXT_CSD_CMD_SET_NORMAL;
+		multi_cmd->cmds[2].flags = MMC_RSP_SPI_R1B |
+				MMC_RSP_R1B |
+				MMC_CMD_AC;
+		multi_cmd->cmds[2].write_flag = 1;
+	} else {
+		/* prepare multi_cmd to be sent */
+		multi_cmd->num_of_cmds = 4;
+		/* put device into ffu mode */
+		multi_cmd->cmds[0].opcode = MMC_SWITCH;
+		multi_cmd->cmds[0].arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
+				(EXT_CSD_MODE_CONFIG << 16) |
+				(EXT_CSD_FFU_MODE << 8) |
+				EXT_CSD_CMD_SET_NORMAL;
+		multi_cmd->cmds[0].flags = MMC_RSP_SPI_R1B |
+				MMC_RSP_R1B |
+				MMC_CMD_AC;
+		multi_cmd->cmds[0].write_flag = 1;
+
+		multi_cmd->cmds[1].opcode = MMC_SET_BLOCK_COUNT;
+		multi_cmd->cmds[1].arg = bl_counter & 0x0000FFFF;
+		multi_cmd->cmds[1].flags = MMC_RSP_SPI_R1
+				|MMC_RSP_R1 |
+				MMC_CMD_AC;
+		multi_cmd->cmds[1].write_flag = 1;
 
-	/* put device into ffu mode */
-	multi_cmd->cmds[0].opcode = MMC_SWITCH;
-	multi_cmd->cmds[0].arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
-			(EXT_CSD_MODE_CONFIG << 16) |
-			(EXT_CSD_FFU_MODE << 8) |
-			EXT_CSD_CMD_SET_NORMAL;
-	multi_cmd->cmds[0].flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
-	multi_cmd->cmds[0].write_flag = 1;
-
-	/* send image chunk */
-	multi_cmd->cmds[1].opcode = MMC_WRITE_BLOCK;
-	multi_cmd->cmds[1].blksz = sect_size;
-	multi_cmd->cmds[1].blocks = 1;
-	multi_cmd->cmds[1].arg = arg;
-	multi_cmd->cmds[1].flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
-	multi_cmd->cmds[1].write_flag = 1;
-	mmc_ioc_cmd_set_data(multi_cmd->cmds[1], buf);
-
-	/* return device into normal mode */
-	multi_cmd->cmds[2].opcode = MMC_SWITCH;
-	multi_cmd->cmds[2].arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
+		multi_cmd->cmds[2].opcode = MMC_WRITE_MULTIPLE_BLOCK;
+		multi_cmd->cmds[2].blksz = sect_size;
+		multi_cmd->cmds[2].blocks = bl_counter;
+		multi_cmd->cmds[2].arg = arg;
+		multi_cmd->cmds[2].flags = MMC_RSP_SPI_R1 |
+				MMC_RSP_R1 |
+				MMC_CMD_ADTC;
+		multi_cmd->cmds[2].write_flag = 1;
+		mmc_ioc_cmd_set_data(multi_cmd->cmds[2], buf);
+
+		multi_cmd->cmds[3].opcode = MMC_SWITCH;
+		multi_cmd->cmds[3].arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
 			(EXT_CSD_MODE_CONFIG << 16) |
 			(EXT_CSD_NORMAL_MODE << 8) |
 			EXT_CSD_CMD_SET_NORMAL;
-	multi_cmd->cmds[2].flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
-	multi_cmd->cmds[2].write_flag = 1;
+		multi_cmd->cmds[3].flags = MMC_RSP_SPI_R1B |
+				MMC_RSP_R1B |
+				MMC_CMD_AC;
+		multi_cmd->cmds[3].write_flag = 1;
+	}
 
 do_retry:
 	/* read firmware chunk */
 	lseek(img_fd, 0, SEEK_SET);
-	chunk_size = read(img_fd, buf, 512);
+	num_ioctl_blks = bl_counter;
+	chunk_size = read(img_fd, buf, num_ioctl_blks * sect_size);
+	remain_fw_size = fw_size - chunk_size;
 
 	while (chunk_size > 0) {
 		/* send ioctl with multi-cmd */
 		ret = ioctl(dev_fd, MMC_IOC_MULTI_CMD, multi_cmd);
 
 		if (ret) {
-			perror("Multi-cmd ioctl");
+			perror("Multi-cmd ioctl failed.");
 			/* In case multi-cmd ioctl failed before exiting from ffu mode */
-			ioctl(dev_fd, MMC_IOC_CMD, &multi_cmd->cmds[2]);
+			if (bl_counter == 1)
+				ioctl(dev_fd, MMC_IOC_CMD, &multi_cmd->cmds[2]);
+			else
+				ioctl(dev_fd, MMC_IOC_CMD, &multi_cmd->cmds[3]);
 			goto out;
 		}
 
@@ -2494,7 +2574,6 @@ do_retry:
 		if (sect_done == 0) {
 			if (retry > 0) {
 				retry--;
-				fprintf(stderr, "Programming failed. Retrying... (%d)\n", retry);
 				goto do_retry;
 			}
 			fprintf(stderr, "Programming failed! Aborting...\n"); @@ -2502,14 +2581,25 @@ do_retry:
 		} else {
 			fprintf(stderr, "Programmed %d/%jd bytes\r", sect_done * sect_size, (intmax_t)fw_size);
 		}
+		memset(buf, 0, num_ioctl_blks);
 
+		if (remain_fw_size >= bl_counter * sect_size)
+			num_ioctl_blks = bl_counter;
+		else
+			num_ioctl_blks = remain_fw_size / sect_size;
 		/* read the next firmware chunk (if any) */
-		chunk_size = read(img_fd, buf, 512);
+		chunk_size = read(img_fd, buf, num_ioctl_blks * sect_size);
+		if (chunk_size > 0)
+			remain_fw_size = remain_fw_size - chunk_size;
+		/* Update the values for Multiple Write CMD */
+		if (bl_counter > 1) {
+			multi_cmd->cmds[1].arg = num_ioctl_blks & 0x0000FFFF;
+			multi_cmd->cmds[2].blocks = num_ioctl_blks;
+		}
 	}
-
 	if ((sect_done * sect_size) == fw_size) {
 		fprintf(stderr, "Programmed %jd/%jd bytes\n", (intmax_t)fw_size, (intmax_t)fw_size);
-		fprintf(stderr, "Programming finished with status %d \n", ret);
+		fprintf(stderr, "Programming finished with status %d\n", ret);
 	}
 	else {
 		fprintf(stderr, "FW size and number of sectors written mismatch. Status return %d\n", ret); @@ -2529,9 +2619,9 @@ do_retry:
 		multi_cmd->cmds[1].blksz = 0;
 		multi_cmd->cmds[1].blocks = 0;
 		multi_cmd->cmds[1].arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
-				(EXT_CSD_MODE_OPERATION_CODES << 16) |
-				(EXT_CSD_FFU_INSTALL << 8) |
-				EXT_CSD_CMD_SET_NORMAL;
+			(EXT_CSD_MODE_OPERATION_CODES << 16) |
+			(EXT_CSD_FFU_INSTALL << 8) |
+			EXT_CSD_CMD_SET_NORMAL;
 		multi_cmd->cmds[1].flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
 		multi_cmd->cmds[1].write_flag = 1;
 
--
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux