Hi Seunguk, > -----Original Message----- > From: linux-mmc-owner@xxxxxxxxxxxxxxx [mailto:linux-mmc- > owner@xxxxxxxxxxxxxxx] On Behalf Of Seunguk Shin > Sent: Monday, March 31, 2014 1:52 PM > To: linux-mmc@xxxxxxxxxxxxxxx; Avi Shchislowski; chris@xxxxxxxxxx; > cpgs@xxxxxxxxxxx > Subject: Re: [RFC PATCH 1/1 ]mmc: Support-FFU-for-eMMC-v5.0 > > Some of Samsung eMMC does not show the argument for ffu in ext_csd. > In case of this, eMMC shows 0x0 from ext_csd, Host has to modify the > argument. > > Add "#define CID_MANFID_SAMSUNG 0x15" > > > +int mmc_ffu_download(struct mmc_card *card, struct mmc_command > *cmd, > > + u8 *data, int buf_bytes) > > +{ > > + u8 ext_csd[CARD_BLOCK_SIZE]; > > + int err; > > + int ret; > > + > > + /* Read the EXT_CSD */ > > + err = mmc_send_ext_csd(card, ext_csd); > > + if (err) { > > + pr_err("FFU: %s: error %d sending ext_csd\n", > > + mmc_hostname(card->host), err); > > + goto exit; > > + } > > + > > + /* Check if FFU is supported by card */ > > + if (!FFU_SUPPORTED_MODE(ext_csd[EXT_CSD_SUPPORTED_MODE])) > { > > + err = -EINVAL; > > + pr_err("FFU: %s: error %d FFU is not supported\n", > > + mmc_hostname(card->host), err); > > + goto exit; > > + } > > + > > + err = mmc_host_set_ffu(card, ext_csd[EXT_CSD_FW_CONFIG]); > > + if (err) { > > + pr_err("FFU: %s: error %d FFU is not supported\n", > > + mmc_hostname(card->host), err); > > + err = -EINVAL; > > + goto exit; > > + } > > + > > + /* set device to FFU mode */ > > + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, > EXT_CSD_MODE_CONFIG, > > + MMC_FFU_MODE_SET, card->ext_csd.generic_cmd6_time); > > + if (err) { > > + pr_err("FFU: %s: error %d FFU is not supported\n", > > + mmc_hostname(card->host), err); > > + goto exit_normal; > > + } > > + > > + /* set CMD ARG */ > > + cmd->arg = ext_csd[EXT_CSD_FFU_ARG] | > > + ext_csd[EXT_CSD_FFU_ARG + 1] << 8 | > > + ext_csd[EXT_CSD_FFU_ARG + 2] << 16 | > > + ext_csd[EXT_CSD_FFU_ARG + 3] << 24; > > + > > Add followings > " > /* If arg is zero, should be set to a special value for samsung eMMC */ > if ( card->cid.manfid == CID_MANFID_SAMSUNG && cmd->arg == 0x0 ) { > cmd->arg = 0xc7810000; > } > " This code is provides a generic FFU solution. I think it will be better to implement the Samsung-specific part as a QUIRK in MMC driver, and commit this as a separate patch. > > > + err = mmc_ffu_write(card, data, cmd->arg, buf_bytes); > > + > > +exit_normal: > > + /* host switch back to work in normal MMC Read/Write commands */ > > + ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, > > + EXT_CSD_MODE_CONFIG, MMC_FFU_MODE_NORMAL, > > + card->ext_csd.generic_cmd6_time); > > + if (ret) > > + err = ret; > > + > > +exit: > > + return err; > > +} > > +EXPORT_SYMBOL(mmc_ffu_download); > > + > > > > eMMC 5.0 Spec. says if device does not support MODE_OPERATION_CODES, > device doesn't need to use > NUMBER_OF_FW_SECTORS_CORRECTLY_PROGRAMMED. > So, it's better to move the code for checking this value to > FFU_FEATURES(ext_csd[EXT_CSD_FFU_FEATURES] OK, will be checked only in case of MODE_OPERATION_CODES is NOT supported. > > > +int mmc_ffu_install(struct mmc_card *card) { > > + u8 ext_csd[CARD_BLOCK_SIZE]; > > + int err; > > + u32 ffu_data_len; > > + u32 timeout; > > + > > + err = mmc_send_ext_csd(card, ext_csd); > > + if (err) { > > + pr_err("FFU: %s: error %d sending ext_csd\n", > > + mmc_hostname(card->host), err); > > + goto exit; > > + } > > + > > + /* Check if FFU is supported */ > > + if (!FFU_SUPPORTED_MODE(ext_csd[EXT_CSD_SUPPORTED_MODE]) > || > > + FFU_CONFIG(ext_csd[EXT_CSD_FW_CONFIG])) { > > + err = -EINVAL; > > + pr_err("FFU: %s: error %d FFU is not supported\n", > > + mmc_hostname(card->host), err); > > + goto exit; > > + } > > Remove followings > " > ffu_data_len = ext_csd[EXT_CSD_NUM_OF_FW_SEC_PROG]| > ext_csd[EXT_CSD_NUM_OF_FW_SEC_PROG + 1] << 8 | > ext_csd[EXT_CSD_NUM_OF_FW_SEC_PROG + 2] << 16 | > ext_csd[EXT_CSD_NUM_OF_FW_SEC_PROG + 3] << 24; > > if (!ffu_data_len) { > err = -EPERM; > return err; > } > " > > > + > > + /* check mode operation */ > > + if (!FFU_FEATURES(ext_csd[EXT_CSD_FFU_FEATURES])) { > > + /* restart the eMMC */ > > + err = mmc_ffu_restart(card); > > + if (err) { > > + pr_err("FFU: %s: error %d FFU install:\n", > > + mmc_hostname(card->host), err); > > + } > > + } else { > > Add followings > " > ffu_data_len = ext_csd[EXT_CSD_NUM_OF_FW_SEC_PROG]| > ext_csd[EXT_CSD_NUM_OF_FW_SEC_PROG + 1] << 8 > | > ext_csd[EXT_CSD_NUM_OF_FW_SEC_PROG + 2] << > 16 | > ext_csd[EXT_CSD_NUM_OF_FW_SEC_PROG + 3] << 24; > > if (!ffu_data_len) { > err = -EPERM; > return err; > } > " > > > + /* set device to FFU mode */ > > + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, > > + EXT_CSD_MODE_CONFIG, 0x1, > > + card->ext_csd.generic_cmd6_time); > > + if (err) { > > + pr_err("FFU: %s: error %d FFU is not > supported\n", > > + mmc_hostname(card->host), err); > > + goto exit; > > + } > > > > Checking ffu status in ext_csd should be done even if device does not support > MODE_OPERATION_CODES So, it's better to move the code for checking this > value to out of brace for FFU_FEATURES(ext_csd[EXT_CSD_FFU_FEATURES] > You are right, we will move ffu status check to be done in both modes. > > + /* set ext_csd to install mode */ > > + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, > > + EXT_CSD_MODE_OPERATION_CODES, > > + MMC_FFU_INSTALL_SET, timeout); > > + > > + if (err) { > > + pr_err("FFU: %s: error %d setting > > + install > mode\n", > > + mmc_hostname(card->host), err); > > + goto exit; > > + } > > + > > Remove followings > " > /* read ext_csd */ > err = mmc_send_ext_csd(card, ext_csd); > if (err) { > pr_err("FFU: %s: error %d sending ext_csd\n", > mmc_hostname(card->host), err); > goto exit; > } > /* return status */ > err = ext_csd[EXT_CSD_FFU_STATUS]; > if (err) { > pr_err("FFU: %s: error %d FFU install:\n", > mmc_hostname(card->host), err); > err = -EINVAL; > goto exit; > } > " > > > + } > > + > > Add followings > " > /* read ext_csd */ > err = mmc_send_ext_csd(card, ext_csd); > if (err) { > pr_err("FFU: %s: error %d sending ext_csd\n", > mmc_hostname(card->host), err); > goto exit; > } > /* return status */ > err = ext_csd[EXT_CSD_FFU_STATUS]; > if (err) { > pr_err("FFU: %s: error %d FFU install:\n", > mmc_hostname(card->host), err); > err = -EINVAL; > goto exit; > } > " > > > +exit: > > + return err; > > +} > > +EXPORT_SYMBOL(mmc_ffu_install); > > + > > > > And some device's fw should be transferred with one command. > They does not support multiple commands for fw transfer. > For these devices, MMC_IOC_MAX_BYTES should be greater. > > diff --git a/include/uapi/linux/mmc/ioctl.h b/include/uapi/linux/mmc/ioctl.h > index 1f5e689..af9ea62 100644 > --- a/include/uapi/linux/mmc/ioctl.h > +++ b/include/uapi/linux/mmc/ioctl.h > @@ -53,5 +53,5 @@ struct mmc_ioc_cmd { > * is enforced per ioctl call. For larger data transfers, use the normal > * block device operations. > */ > -#define MMC_IOC_MAX_BYTES (512L * 256) > +#define MMC_IOC_MAX_BYTES (512L * 1024) > #endif /* LINUX_MMC_IOCTL_H */ We do not feel confident enough with changing the previously defined IOCTL limitation. Our next patch (V2) should probably resolve FW size limitation - will use "udev" mechanism. > > > -- > 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 -- 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