技术支持

联系我们

CONTACT US

深圳超盈智能科技有限公司

总机电话:0755-89344942

客服电话:19806503197

邮箱:sales@chaoyingzn.com

地址:深圳市龙岗区坂田街道象角塘社区中浩路润昌工业园A栋5楼

您当前所在的位置:首页 > 技术支持 > 资料下载 > eMMC Firmware Upgrade

资料下载

eMMC Firmware Upgrade

阅读次数: 【 461 】 更新时间: 【 2021-10-25 】
问题由来:之前做过的一款Android手机,在系统启动或者运行过程中,会造成死机的问题;经过大量的测试,发现这是eMMC Firmware的一个bug,但是此时,已经有一大批机器出货,所以解决方案也只能通过Offline eMMC firmware更新来解决。

方案选择:Offline eMMC firmware更新,是指eMMC chip已经安装到PCBA板上,这时更新,只有通过SDIO interface来更新;当时考虑在2个地方开始做更新的动作,一是bootloader, 二是Linux Kernel中eMMC初始化的地方。通过比较,最后选择了方案二。

eMMC Firmware更新的主要步骤,

1. 向eMMC controller写入eMMC Firmware更新的密码,默认情况下,eMMC Firmware是不允许更新的。

    1.1, make sure it entered transfer state

    1.2 write the "mmc FW update password" to controller

    1.3, read back and check the FW update response

2. 向eMMC controller写入eMMCFirmware内容。

    2.1, program the Toshiba mmc FW

    2.2, read back the Toshiba mmc FW

3. Assert CMD0, 使eMMC进入idle状态。

4. 重启device。

示例代码路径如下,

/drivers/mmc/core/mmc_ops.c
可以在 mmc_init_card()函数内,开始check eMMC Firmware version, 并决定是否进行Firmware更新。
Firmware更新的函数是“toshiba_mmc_fw_update”。

用到的CMD及其含义,


主要示例代码如下,

+/* funtion description: Toshba mmc FW update
+ * paraters: 
+ * card: the Toshiba card
+ * return value: 0 for OK; others for error number.
+ * author: Guangwei Jiang
+ * date:2014-12-25
+*/
+int toshiba_mmc_fw_update(struct mmc_card *card)
+{
+ int err = -1;
+ void *buf;
+ int status;
+
+ BUG_ON(!card);
+ BUG_ON(!card->host);
+
+ // step1.1, make sure it entered transfer state
+ err = mmc_send_status(card, &status);
+ if (err)
+ {
+ pr_err("Toshiba mmc fw update failed (mmc send status failed)!\n");
+ return err;
+ }
+ if (R1_CURRENT_STATE(status) != R1_STATE_TRAN)
+ {
+ pr_err("MMC not in the transfer state, exit the FW update\n");
+ return -1;
+ }
+
+ // step1.2, write the "mmc FW update password" to controller
+ buf = kmalloc(TOSHIBA_MMC_UNLOCK_KEY_LENGTH, GFP_KERNEL);
+ if (buf == NULL)
+ {
+ pr_err("Toshiba mmc fw update failed (memory allocate failed)!\n");
+ return -ENOMEM;
+ }
+
+ memcpy(buf, toshiba_fw_update_unlock_key, TOSHIBA_MMC_UNLOCK_KEY_LENGTH);
+
+ err = mmc_gen_cmd(card, buf, 1); // write the FW update command by CMD56
+ if (err)
+ {
+ pr_err("Toshiba mmc fw update failed (mmc unlock key write failed)!\n");
+ return err;
+ }
+
+ // step1.3, read back and check the FW update response
+ memset(buf, 0, TOSHIBA_MMC_UNLOCK_KEY_LENGTH);
+
+ err = mmc_gen_cmd(card, buf, 0); // read out the status by CMD56
+ printk("mmc_gen_cmd(read), err = %d\n", err);
+ if (err)
+ {
+ pr_err("Toshiba mmc fw update failed (mmc unlock key read back failed)!\n");
+ goto _DEVICE_REBOOT;
+ }
+ else
+ {
+ // If bit0 is 0x01 (sub command id), and bit3 is 0xA0, then mmc unlock sucessfully
+ if ((*(u8 *)(buf+0) == 0x01 )&&(*(u8 *)(buf+3) == 0xA0))
+ {
+ pr_info("Toshiba mmc unlock sucessfully, will do FW program next step\n");
+ }
+ else
+ {
+ pr_err("Toshiba mmc fw update failed (mmc unlock response code error)!\n");
+ goto _DEVICE_REBOOT;
+ }
+ }
+
+ if (buf)
+ kfree(buf);
+
+ // step2.1, program the Toshiba mmc FW
+ buf = kmalloc(TOSHIBA_MMC_FW_LENGTH, GFP_KERNEL);
+ if (buf == NULL)
+ {
+ pr_err("Toshiba mmc fw update failed (memory allocate failed)!\n");
+ goto _DEVICE_REBOOT;
+ }
+
+ memcpy(buf, toshiba_19n_fwdata_16GB_016G92, TOSHIBA_MMC_FW_LENGTH);
+
+ err = mmc_fw_multi_block_rw(card, buf, 1); // program the MMC FW 
+ if (err)
+ {
+ pr_err("Toshiba mmc fw update failed (mmc fw program failed)!\n");
+ goto _DEVICE_REBOOT;
+ }
+
+ // step2.2, read back the Toshiba mmc FW
+ /*memset(buf, 0, TOSHIBA_MMC_FW_LENGTH);
+
+ err = mmc_fw_multi_block_rw(card, buf, 0); // read back the MMC FW
+ if (err)
+ {
+ pr_err("Toshiba mmc fw update failed(mmc fw read back failed)!\n");
+ goto _DEVICE_REBOOT;
+ }*/
+
+ if (buf)
+ kfree(buf);
+
+ // step3.1, Assert CMD0
+ mmc_go_idle(card->host);
+
+ pr_info("Toshiba mmc fw update sucessfully\n");
+
+_DEVICE_REBOOT:
+ pr_info("Device will reboot in 2 senconds...\n");
+ mdelay(2000);
+ emergency_restart();
+ return err;
+}+/* funtion description: Read and write by CMD56 (MMC_GEN_CMD)
+ * paraters: 
+ * card: mmc card type
+ * buf: for read and write purpose, the size is 512B;
+ * write: 1 for write; 0 for read; Don't use other number.
+ * return value: 0 for OK; others for error number.
+ * author: Guangwei Jiang
+ * date:2014-12-18
+*/
+int mmc_gen_cmd(struct mmc_card *card, void *buf, int write)
+{
+ struct mmc_request mrq;
+ struct mmc_command cmd;
+ struct mmc_data data;
+ struct mmc_command stop;
+ struct scatterlist sg;
+ void *data_buf;
+ unsigned long timeout;
+ u32 status;
+ int err;
+ //int i;
+
+ BUG_ON(!card);
+ BUG_ON(!card->host);
+
+ mmc_set_blocklen(card, 512);
+
+ data_buf = kmalloc(512, GFP_KERNEL);
+ if (data_buf == NULL)
+ return -ENOMEM;
+
+ if (write != 0)
+ memcpy(data_buf, buf, 512);
+
+ memset(&mrq, 0, sizeof(struct mmc_request));
+ memset(&cmd, 0, sizeof(struct mmc_command));
+ memset(&data, 0, sizeof(struct mmc_data));
+ memset(&stop, 0, sizeof(struct mmc_command));
+
+ mrq.cmd = &cmd;
+ mrq.data = &data;
+ mrq.stop = NULL;
+
+ cmd.opcode = MMC_GEN_CMD;
+ cmd.arg = write? 0x00: 0x01;
+
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+
+ data.blksz = 512;
+ data.blocks = 1;
+ data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
+ data.sg = &sg;
+ data.sg_len = 1;
+
+ /*stop.opcode = MMC_STOP_TRANSMISSION;
+ stop.arg = 0;
+ stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;*/
+
+ sg_init_one(&sg, data_buf, 512);
+
+ mmc_set_data_timeout(&data, card);
+
+ mmc_claim_host(card->host);
+ mmc_wait_for_req(card->host, &mrq);
+ mmc_release_host(card->host);
+
+ /* Must check status to be sure of no errors */
+ timeout = jiffies + msecs_to_jiffies(MMC_OPS_TIMEOUT_MS);
+ do {
+ err = mmc_send_status(card, &status);
+ if (err)
+ return err;
+ if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY)
+ break;
+ if (mmc_host_is_spi(card->host))
+ break;
+
+ /* Timeout if the device never leaves the program state. */
+ if (time_after(jiffies, timeout)) {
+ pr_err("%s: Card stuck in programming state! %s\n",
+ mmc_hostname(card->host), __func__);
+ return -ETIMEDOUT;
+ }
+ } while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
+
+ if (write == 0)
+ {
+ memcpy(buf, data_buf, 512);
+ }
+ kfree(data_buf);
+
+ /*if (write == 0)
+ pr_info("\n\nCMD56 read content as below:\n");
+ else
+ pr_info("\n\nCMD56 write content as below:\n");
+ for (i = 0; i < 512; i++)
+ {
+ printk("0x%2x ", *(u8 *)(buf+i));
+
+ if ((i+1)%16 == 0)
+ printk("\n");
+ }*/
+
+
+ if (cmd.error)
+ {
+ pr_err("%s, cmd error, error code %d\n", __func__, cmd.error);
+ return cmd.error;
+ }
+ if (data.error)
+ {
+ pr_err("%s, data error, error code %d\n", __func__, data.error);
+ return data.error;
+ }
+ if (stop.error)
+ {
+ pr_err("%s, stop error, error code %d\n", __func__, stop.error);
+ return stop.error;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(mmc_gen_cmd);+/* funtion description: Read and write eMMC FW by command
+ *                      MMC_READ_MULTIPLE_BLOCK(CMD18)/MMC_WRITE_MULTIPLE_BLOCK(CMD25)
+ * paraters: 
+ * card: mmc card type
+ * buf: for read and write purpose, the size is defined by TOSHIBA_MMC_FW_LENGTH;
+ * write: 1 for write; 0 for read; Don't use other number.
+ * return value: 0 for OK; others for error number.
+ * author: Guangwei Jiang
+ * date:2014-12-19
+*/
+int mmc_fw_multi_block_rw(struct mmc_card *card, void *buf, int write)
+{
+ struct mmc_request mrq;
+ struct mmc_command cmd;
+ struct mmc_data data;
+ struct mmc_command stop;
+ struct scatterlist sg;
+ void *data_buf;
+ unsigned long timeout;
+ u32 status;
+ int err;
+ //int i;
+
+ BUG_ON(!card);
+ BUG_ON(!card->host);
+
+ mmc_set_blocklen(card, 512);
+
+ data_buf = kmalloc(TOSHIBA_MMC_FW_LENGTH, GFP_KERNEL);
+ if (data_buf == NULL)
+ return -ENOMEM;
+
+ if (write != 0)
+ memcpy(data_buf, buf, TOSHIBA_MMC_FW_LENGTH);
+
+ memset(&mrq, 0, sizeof(struct mmc_request));
+ memset(&cmd, 0, sizeof(struct mmc_command));
+ memset(&data, 0, sizeof(struct mmc_data));
+ memset(&stop, 0, sizeof(struct mmc_command));
+
+ mrq.cmd = &cmd;
+ mrq.data = &data;
+ mrq.stop = &stop;
+
+ cmd.opcode = write? MMC_WRITE_MULTIPLE_BLOCK : MMC_READ_MULTIPLE_BLOCK;
+ cmd.arg = 0x00;
+
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+
+ data.blksz = 512;
+ data.blocks = TOSHIBA_MMC_FW_LENGTH/512;
+ data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
+ data.sg = &sg;
+ data.sg_len = 1;
+
+ stop.opcode = MMC_STOP_TRANSMISSION;
+ stop.arg = 0;
+ stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+
+ sg_init_one(&sg, data_buf, TOSHIBA_MMC_FW_LENGTH);
+
+ mmc_set_data_timeout(&data, card);
+
+ mmc_claim_host(card->host);
+ mmc_wait_for_req(card->host, &mrq);
+ mmc_release_host(card->host);
+
+ /* Must check status to be sure of no errors */
+ timeout = jiffies + msecs_to_jiffies(MMC_OPS_TIMEOUT_MS);
+ do {
+ err = mmc_send_status(card, &status);
+ if (err)
+ return err;
+ if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY)
+ break;
+ if (mmc_host_is_spi(card->host))
+ break;
+
+ /* Timeout if the device never leaves the program state. */
+ if (time_after(jiffies, timeout)) {
+ pr_err("%s: Card stuck in programming state! %s\n",
+ mmc_hostname(card->host), __func__);
+ return -ETIMEDOUT;
+ }
+ } while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
+
+
+ if (write == 0)
+ {
+ memcpy(buf, data_buf, TOSHIBA_MMC_FW_LENGTH);
+ }
+ kfree(data_buf);
+
+ /*if (write == 0)
+ {
+ pr_info("\n\nToshiba emmc fw read content as below:\n");
+ for (i = 0; i < TOSHIBA_MMC_FW_LENGTH; i++) 
+ {
+ printk("0x%2x ", *(u8 *)(buf+i));
+
+ if ((i+1)%16 == 0)
+ printk("\n");
+ }
+ }
+ else
+ {
+ printk("\n\nToshiba emmc fw  write content as below:\n");
+ for (i = 0; i < TOSHIBA_MMC_FW_LENGTH; i++) 
+ {
+ printk("0x%2x ", *(u8 *)(buf+i));
+
+ if ((i+1)%16 == 0)
+ printk("\n");
+ }
+ }*/
+
+ if (cmd.error)
+ {
+ pr_err("%s, cmd error, error code %d\n", __func__, cmd.error);
+ return cmd.error;
+ }
+ if (data.error)
+ {
+ pr_err("%s, data error, error code %d\n", __func__, data.error);
+ return data.error;
+ }
+ if (stop.error)
+ {
+ pr_err("%s, stop error, error code %d\n", __func__, stop.error);
+ return stop.error;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(mmc_fw_multi_block_rw);


上一条: eMMC分区详解
下一条: NAND闪存技术和市场分析
相关文章Extended reading
天玑9000能效登顶安卓旗舰芯片排行No1, 旗舰手机必选!
UWB芯片
最快下半年!安卓在这项性能上终于要反超iPhone
天玑9000性能被认可,红米、vivo、OPPO三款旗舰谁最受欢迎?
坚果J10S稳压极米H3S一头