[U-Boot] [PATCH v2] mmc: don't support write & erase for SPL builds

Pantelis Antoniou panto at antoniou-consulting.com
Fri Sep 6 15:54:19 CEST 2013


Hi Paul,

On Sep 6, 2013, at 4:43 PM, Paul Burton wrote:

> For SPL builds this is just dead code since we'll only need to read.
> Eliminating it results in a significant size reduction for the SPL
> binary, which may be critical for certain platforms where the binary
> size is highly constrained.
> 
> Signed-off-by: Paul Burton <paul.burton at imgtec.com>
> ---
> Changes in v2:
>  - Move the mmc_bwrite & mmc_berase functions to a new mmc_write.c
>    file which is only compiled for non-SPL builds, as per a request
>    from Pantelis Antoniou. This requires that a few formerly static
>    functions in mmc.c be accessible to the new file, so they are
>    declared in a new mmc_private.h header along with the write &
>    erase functions. For what it's worth I prefered v1, but hey ho.
> ---
> drivers/mmc/Makefile      |   2 +
> drivers/mmc/mmc.c         | 186 +--------------------------------------------
> drivers/mmc/mmc_private.h |  45 +++++++++++
> drivers/mmc/mmc_write.c   | 189 ++++++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 240 insertions(+), 182 deletions(-)
> create mode 100644 drivers/mmc/mmc_private.h
> create mode 100644 drivers/mmc/mmc_write.c
> 
> diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
> index bedf833..06280d1 100644
> --- a/drivers/mmc/Makefile
> +++ b/drivers/mmc/Makefile
> @@ -34,6 +34,8 @@ COBJS-$(CONFIG_EXYNOS_DWMMC) += exynos_dw_mmc.o
> COBJS-$(CONFIG_ZYNQ_SDHCI) += zynq_sdhci.o
> ifdef CONFIG_SPL_BUILD
> COBJS-$(CONFIG_SPL_MMC_BOOT) += fsl_esdhc_spl.o
> +else
> +COBJS-$(CONFIG_GENERIC_MMC) += mmc_write.o
> endif
> 
> COBJS	:= $(COBJS-y)
> diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
> index 30a985b..666f77b 100644
> --- a/drivers/mmc/mmc.c
> +++ b/drivers/mmc/mmc.c
> @@ -15,6 +15,7 @@
> #include <malloc.h>
> #include <linux/list.h>
> #include <div64.h>
> +#include "mmc_private.h"
> 
> /* Set block count limit because of 16 bit register limit on some hardware*/
> #ifndef CONFIG_SYS_MMC_MAX_BLK_COUNT
> @@ -52,8 +53,7 @@ int __board_mmc_getcd(struct mmc *mmc) {
> int board_mmc_getcd(struct mmc *mmc)__attribute__((weak,
> 	alias("__board_mmc_getcd")));
> 
> -static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
> -			struct mmc_data *data)
> +int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
> {
> 	struct mmc_data backup;
> 	int ret;
> @@ -114,7 +114,7 @@ static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
> 	return ret;
> }
> 
> -static int mmc_send_status(struct mmc *mmc, int timeout)
> +int mmc_send_status(struct mmc *mmc, int timeout)
> {
> 	struct mmc_cmd cmd;
> 	int err, retries = 5;
> @@ -162,7 +162,7 @@ static int mmc_send_status(struct mmc *mmc, int timeout)
> 	return 0;
> }
> 
> -static int mmc_set_blocklen(struct mmc *mmc, int len)
> +int mmc_set_blocklen(struct mmc *mmc, int len)
> {
> 	struct mmc_cmd cmd;
> 
> @@ -192,184 +192,6 @@ struct mmc *find_mmc_device(int dev_num)
> 	return NULL;
> }
> 
> -static ulong mmc_erase_t(struct mmc *mmc, ulong start, lbaint_t blkcnt)
> -{
> -	struct mmc_cmd cmd;
> -	ulong end;
> -	int err, start_cmd, end_cmd;
> -
> -	if (mmc->high_capacity)
> -		end = start + blkcnt - 1;
> -	else {
> -		end = (start + blkcnt - 1) * mmc->write_bl_len;
> -		start *= mmc->write_bl_len;
> -	}
> -
> -	if (IS_SD(mmc)) {
> -		start_cmd = SD_CMD_ERASE_WR_BLK_START;
> -		end_cmd = SD_CMD_ERASE_WR_BLK_END;
> -	} else {
> -		start_cmd = MMC_CMD_ERASE_GROUP_START;
> -		end_cmd = MMC_CMD_ERASE_GROUP_END;
> -	}
> -
> -	cmd.cmdidx = start_cmd;
> -	cmd.cmdarg = start;
> -	cmd.resp_type = MMC_RSP_R1;
> -
> -	err = mmc_send_cmd(mmc, &cmd, NULL);
> -	if (err)
> -		goto err_out;
> -
> -	cmd.cmdidx = end_cmd;
> -	cmd.cmdarg = end;
> -
> -	err = mmc_send_cmd(mmc, &cmd, NULL);
> -	if (err)
> -		goto err_out;
> -
> -	cmd.cmdidx = MMC_CMD_ERASE;
> -	cmd.cmdarg = SECURE_ERASE;
> -	cmd.resp_type = MMC_RSP_R1b;
> -
> -	err = mmc_send_cmd(mmc, &cmd, NULL);
> -	if (err)
> -		goto err_out;
> -
> -	return 0;
> -
> -err_out:
> -#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
> -	puts("mmc erase failed\n");
> -#endif
> -	return err;
> -}
> -
> -static unsigned long
> -mmc_berase(int dev_num, lbaint_t start, lbaint_t blkcnt)
> -{
> -	int err = 0;
> -	struct mmc *mmc = find_mmc_device(dev_num);
> -	lbaint_t blk = 0, blk_r = 0;
> -	int timeout = 1000;
> -
> -	if (!mmc)
> -		return -1;
> -
> -#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
> -	if ((start % mmc->erase_grp_size) || (blkcnt % mmc->erase_grp_size))
> -		printf("\n\nCaution! Your devices Erase group is 0x%x\n"
> -		       "The erase range would be change to "
> -		       "0x" LBAF "~0x" LBAF "\n\n",
> -		       mmc->erase_grp_size, start & ~(mmc->erase_grp_size - 1),
> -		       ((start + blkcnt + mmc->erase_grp_size)
> -		       & ~(mmc->erase_grp_size - 1)) - 1);
> -#endif
> -
> -	while (blk < blkcnt) {
> -		blk_r = ((blkcnt - blk) > mmc->erase_grp_size) ?
> -			mmc->erase_grp_size : (blkcnt - blk);
> -		err = mmc_erase_t(mmc, start + blk, blk_r);
> -		if (err)
> -			break;
> -
> -		blk += blk_r;
> -
> -		/* Waiting for the ready status */
> -		if (mmc_send_status(mmc, timeout))
> -			return 0;
> -	}
> -
> -	return blk;
> -}
> -
> -static ulong
> -mmc_write_blocks(struct mmc *mmc, lbaint_t start, lbaint_t blkcnt, const void*src)
> -{
> -	struct mmc_cmd cmd;
> -	struct mmc_data data;
> -	int timeout = 1000;
> -
> -	if ((start + blkcnt) > mmc->block_dev.lba) {
> -#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
> -		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
> -			start + blkcnt, mmc->block_dev.lba);
> -#endif
> -		return 0;
> -	}
> -
> -	if (blkcnt == 0)
> -		return 0;
> -	else if (blkcnt == 1)
> -		cmd.cmdidx = MMC_CMD_WRITE_SINGLE_BLOCK;
> -	else
> -		cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
> -
> -	if (mmc->high_capacity)
> -		cmd.cmdarg = start;
> -	else
> -		cmd.cmdarg = start * mmc->write_bl_len;
> -
> -	cmd.resp_type = MMC_RSP_R1;
> -
> -	data.src = src;
> -	data.blocks = blkcnt;
> -	data.blocksize = mmc->write_bl_len;
> -	data.flags = MMC_DATA_WRITE;
> -
> -	if (mmc_send_cmd(mmc, &cmd, &data)) {
> -#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
> -		printf("mmc write failed\n");
> -#endif
> -		return 0;
> -	}
> -
> -	/* SPI multiblock writes terminate using a special
> -	 * token, not a STOP_TRANSMISSION request.
> -	 */
> -	if (!mmc_host_is_spi(mmc) && blkcnt > 1) {
> -		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
> -		cmd.cmdarg = 0;
> -		cmd.resp_type = MMC_RSP_R1b;
> -		if (mmc_send_cmd(mmc, &cmd, NULL)) {
> -#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
> -			printf("mmc fail to send stop cmd\n");
> -#endif
> -			return 0;
> -		}
> -	}
> -
> -	/* Waiting for the ready status */
> -	if (mmc_send_status(mmc, timeout))
> -		return 0;
> -
> -	return blkcnt;
> -}
> -
> -static ulong
> -mmc_bwrite(int dev_num, lbaint_t start, lbaint_t blkcnt, const void*src)
> -{
> -	lbaint_t cur, blocks_todo = blkcnt;
> -
> -	struct mmc *mmc = find_mmc_device(dev_num);
> -	if (!mmc)
> -		return 0;
> -
> -	if (mmc_set_blocklen(mmc, mmc->write_bl_len))
> -		return 0;
> -
> -	do {
> -		cur = (blocks_todo > mmc->b_max) ?  mmc->b_max : blocks_todo;
> -		if(mmc_write_blocks(mmc, start, cur, src) != cur)
> -			return 0;
> -		blocks_todo -= cur;
> -		start += cur;
> -		src += cur * mmc->write_bl_len;
> -	} while (blocks_todo > 0);
> -
> -	return blkcnt;
> -}
> -
> static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
> 			   lbaint_t blkcnt)
> {
> diff --git a/drivers/mmc/mmc_private.h b/drivers/mmc/mmc_private.h
> new file mode 100644
> index 0000000..16dcf9f
> --- /dev/null
> +++ b/drivers/mmc/mmc_private.h
> @@ -0,0 +1,45 @@
> +/*
> + * Copyright 2008,2010 Freescale Semiconductor, Inc
> + * Andy Fleming
> + *
> + * Based (loosely) on the Linux code
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +#ifndef _MMC_PRIVATE_H_
> +#define _MMC_PRIVATE_H_
> +
> +#include <mmc.h>
> +
> +extern int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
> +			struct mmc_data *data);
> +extern int mmc_send_status(struct mmc *mmc, int timeout);
> +extern int mmc_set_blocklen(struct mmc *mmc, int len);
> +
> +#ifndef CONFIG_SPL_BUILD
> +
> +extern unsigned long mmc_berase(int dev_num, lbaint_t start, lbaint_t blkcnt);
> +
> +extern ulong mmc_bwrite(int dev_num, lbaint_t start, lbaint_t blkcnt,
> +		const void *src);
> +
> +#else /* CONFIG_SPL_BUILD */
> +
> +/* SPL will never write or erase, declare dummies to reduce code size. */
> +
> +static inline unsigned long mmc_berase(int dev_num, lbaint_t start,
> +		lbaint_t blkcnt)
> +{
> +	return 0;
> +}
> +
> +static inline ulong mmc_bwrite(int dev_num, lbaint_t start, lbaint_t blkcnt,
> +		const void *src)
> +{
> +	return 0;
> +}
> +
> +#endif /* CONFIG_SPL_BUILD */
> +
> +#endif /* _MMC_PRIVATE_H_ */
> diff --git a/drivers/mmc/mmc_write.c b/drivers/mmc/mmc_write.c
> new file mode 100644
> index 0000000..dde5cf2
> --- /dev/null
> +++ b/drivers/mmc/mmc_write.c
> @@ -0,0 +1,189 @@
> +/*
> + * Copyright 2008, Freescale Semiconductor, Inc
> + * Andy Fleming
> + *
> + * Based vaguely on the Linux code
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +#include <config.h>
> +#include <common.h>
> +#include <part.h>
> +#include "mmc_private.h"
> +
> +static ulong mmc_erase_t(struct mmc *mmc, ulong start, lbaint_t blkcnt)
> +{
> +	struct mmc_cmd cmd;
> +	ulong end;
> +	int err, start_cmd, end_cmd;
> +
> +	if (mmc->high_capacity) {
> +		end = start + blkcnt - 1;
> +	} else {
> +		end = (start + blkcnt - 1) * mmc->write_bl_len;
> +		start *= mmc->write_bl_len;
> +	}
> +
> +	if (IS_SD(mmc)) {
> +		start_cmd = SD_CMD_ERASE_WR_BLK_START;
> +		end_cmd = SD_CMD_ERASE_WR_BLK_END;
> +	} else {
> +		start_cmd = MMC_CMD_ERASE_GROUP_START;
> +		end_cmd = MMC_CMD_ERASE_GROUP_END;
> +	}
> +
> +	cmd.cmdidx = start_cmd;
> +	cmd.cmdarg = start;
> +	cmd.resp_type = MMC_RSP_R1;
> +
> +	err = mmc_send_cmd(mmc, &cmd, NULL);
> +	if (err)
> +		goto err_out;
> +
> +	cmd.cmdidx = end_cmd;
> +	cmd.cmdarg = end;
> +
> +	err = mmc_send_cmd(mmc, &cmd, NULL);
> +	if (err)
> +		goto err_out;
> +
> +	cmd.cmdidx = MMC_CMD_ERASE;
> +	cmd.cmdarg = SECURE_ERASE;
> +	cmd.resp_type = MMC_RSP_R1b;
> +
> +	err = mmc_send_cmd(mmc, &cmd, NULL);
> +	if (err)
> +		goto err_out;
> +
> +	return 0;
> +
> +err_out:
> +#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
> +	puts("mmc erase failed\n");
> +#endif
> +	return err;
> +}
> +
> +unsigned long mmc_berase(int dev_num, lbaint_t start, lbaint_t blkcnt)
> +{
> +	int err = 0;
> +	struct mmc *mmc = find_mmc_device(dev_num);
> +	lbaint_t blk = 0, blk_r = 0;
> +	int timeout = 1000;
> +
> +	if (!mmc)
> +		return -1;
> +
> +#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
> +	if ((start % mmc->erase_grp_size) || (blkcnt % mmc->erase_grp_size))
> +		printf("\n\nCaution! Your devices Erase group is 0x%x\n"
> +		       "The erase range would be change to "
> +		       "0x" LBAF "~0x" LBAF "\n\n",
> +		       mmc->erase_grp_size, start & ~(mmc->erase_grp_size - 1),
> +		       ((start + blkcnt + mmc->erase_grp_size)
> +		       & ~(mmc->erase_grp_size - 1)) - 1);
> +#endif
> +
> +	while (blk < blkcnt) {
> +		blk_r = ((blkcnt - blk) > mmc->erase_grp_size) ?
> +			mmc->erase_grp_size : (blkcnt - blk);
> +		err = mmc_erase_t(mmc, start + blk, blk_r);
> +		if (err)
> +			break;
> +
> +		blk += blk_r;
> +
> +		/* Waiting for the ready status */
> +		if (mmc_send_status(mmc, timeout))
> +			return 0;
> +	}
> +
> +	return blk;
> +}
> +
> +static ulong mmc_write_blocks(struct mmc *mmc, lbaint_t start,
> +		lbaint_t blkcnt, const void *src)
> +{
> +	struct mmc_cmd cmd;
> +	struct mmc_data data;
> +	int timeout = 1000;
> +
> +	if ((start + blkcnt) > mmc->block_dev.lba) {
> +#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
> +		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
> +		       start + blkcnt, mmc->block_dev.lba);
> +#endif
> +		return 0;
> +	}
> +
> +	if (blkcnt == 0)
> +		return 0;
> +	else if (blkcnt == 1)
> +		cmd.cmdidx = MMC_CMD_WRITE_SINGLE_BLOCK;
> +	else
> +		cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
> +
> +	if (mmc->high_capacity)
> +		cmd.cmdarg = start;
> +	else
> +		cmd.cmdarg = start * mmc->write_bl_len;
> +
> +	cmd.resp_type = MMC_RSP_R1;
> +
> +	data.src = src;
> +	data.blocks = blkcnt;
> +	data.blocksize = mmc->write_bl_len;
> +	data.flags = MMC_DATA_WRITE;
> +
> +	if (mmc_send_cmd(mmc, &cmd, &data)) {
> +#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
> +		printf("mmc write failed\n");
> +#endif
> +		return 0;
> +	}
> +
> +	/* SPI multiblock writes terminate using a special
> +	 * token, not a STOP_TRANSMISSION request.
> +	 */
> +	if (!mmc_host_is_spi(mmc) && blkcnt > 1) {
> +		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
> +		cmd.cmdarg = 0;
> +		cmd.resp_type = MMC_RSP_R1b;
> +		if (mmc_send_cmd(mmc, &cmd, NULL)) {
> +#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
> +			printf("mmc fail to send stop cmd\n");
> +#endif
> +			return 0;
> +		}
> +	}
> +
> +	/* Waiting for the ready status */
> +	if (mmc_send_status(mmc, timeout))
> +		return 0;
> +
> +	return blkcnt;
> +}
> +
> +ulong mmc_bwrite(int dev_num, lbaint_t start, lbaint_t blkcnt, const void *src)
> +{
> +	lbaint_t cur, blocks_todo = blkcnt;
> +
> +	struct mmc *mmc = find_mmc_device(dev_num);
> +	if (!mmc)
> +		return 0;
> +
> +	if (mmc_set_blocklen(mmc, mmc->write_bl_len))
> +		return 0;
> +
> +	do {
> +		cur = (blocks_todo > mmc->b_max) ?  mmc->b_max : blocks_todo;
> +		if (mmc_write_blocks(mmc, start, cur, src) != cur)
> +			return 0;
> +		blocks_todo -= cur;
> +		start += cur;
> +		src += cur * mmc->write_bl_len;
> +	} while (blocks_todo > 0);
> +
> +	return blkcnt;
> +}
> -- 
> 1.8.4
> 
> 

Acked-by: Pantelis Antoniou <panto at antoniou-consulting.com>

Looks good to me; let's hear what other people say too.

Tom?

Regards

-- Pantelis




More information about the U-Boot mailing list