Field Firmware Update (ffu) may use close-ended or open ended sequence. Each such sequence is comprised of a write commands enclosed between 2 switch commands - to and from ffu mode. So for the close-ended case, it will be: cmd6->cmd23-cmd25-cmd6. Capture this sequence and make it available for the host modules, should it is needed. Signed-off-by: Avri Altman <avri.altman@xxxxxxx> --- drivers/mmc/core/block.c | 34 ++++++++++++++++++++++++++++++++++ include/linux/mmc/host.h | 1 + include/linux/mmc/mmc.h | 1 + 3 files changed, 36 insertions(+) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 3a8f27c3e310..ee5ec4686582 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -96,6 +96,10 @@ static int max_devices; static DEFINE_IDA(mmc_blk_ida); static DEFINE_IDA(mmc_rpmb_ida); +static unsigned int ffu_progress; +#define MMC_FFU_START BIT(0) /* FFU in progress */ +#define MMC_FFU_SBC BIT(1) /* close-ended FFU in progress */ + struct mmc_blk_busy_data { struct mmc_card *card; u32 status; @@ -464,6 +468,34 @@ static int mmc_blk_ioctl_copy_to_user(struct mmc_ioc_cmd __user *ic_ptr, return 0; } +bool mmc_is_ffu_cmd(struct mmc_command *cmd) +{ + return ((ffu_progress & MMC_FFU_SBC) && + cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK); +} + +static void mmc_blk_ffu_progress(struct mmc_command *cmd) +{ + if (MMC_EXTRACT_INDEX_FROM_ARG(cmd->arg) != EXT_CSD_MODE_CONFIG && + ffu_progress == 0) + return; + + if ((MMC_EXTRACT_INDEX_FROM_ARG(cmd->arg) == EXT_CSD_MODE_CONFIG) && + (cmd->opcode == MMC_SWITCH)) { + u8 value = MMC_EXTRACT_VALUE_FROM_ARG(cmd->arg); + + if (value == 1) + ffu_progress = MMC_FFU_START; + else + ffu_progress = 0; + + return; + } else if (ffu_progress == MMC_FFU_START && + cmd->opcode == MMC_SET_BLOCK_COUNT) { + ffu_progress |= MMC_FFU_SBC; + } +} + static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, struct mmc_blk_ioc_data *idata) { @@ -548,6 +580,8 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, (cmd.opcode == MMC_SWITCH)) return mmc_sanitize(card, idata->ic.cmd_timeout_ms); + mmc_blk_ffu_progress(&cmd); + /* If it's an R1B response we need some more preparations. */ busy_timeout_ms = idata->ic.cmd_timeout_ms ? : MMC_BLK_TIMEOUT_MS; r1b_resp = (cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B; diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 2f445c651742..e2cb20f7c50c 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -677,5 +677,6 @@ int mmc_send_status(struct mmc_card *card, u32 *status); int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error); int mmc_send_abort_tuning(struct mmc_host *host, u32 opcode); int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd); +bool mmc_is_ffu_cmd(struct mmc_command *cmd); #endif /* LINUX_MMC_HOST_H */ diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index 6f7993803ee7..d4d10cabaa57 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h @@ -254,6 +254,7 @@ static inline bool mmc_ready_for_data(u32 status) */ #define EXT_CSD_CMDQ_MODE_EN 15 /* R/W */ +#define EXT_CSD_MODE_CONFIG 30 /* R/W */ #define EXT_CSD_FLUSH_CACHE 32 /* W */ #define EXT_CSD_CACHE_CTRL 33 /* R/W */ #define EXT_CSD_POWER_OFF_NOTIFICATION 34 /* R/W */ -- 2.42.0