diff mbox

[U-Boot,2/3] mmc: sh_sdhi: Fix the ACMD handling

Message ID 20170721212256.25961-2-marek.vasut+renesas@gmail.com
State Accepted
Commit a3f0a7d5b50aa558ecab1fc3a9f5d773eac94051
Delegated to: Jaehoon Chung
Headers show

Commit Message

Marek Vasut July 21, 2017, 9:22 p.m. UTC
The command handling in this driver is awful, esp. because the driver
depends on command numbers to determine whether this is APPCMD or not.
Also, handling of command RSP response types is totally wrong.

This patch at least plucks out some of the custom command encoding and
fixes the APPCMD handling. The RSP handling still needs work, yet that
might not be needed as it turns out the uniphier-sd.c driver is in much
better shape and supports the same IP, so we might be able to just drop
this driver in favor of the uniphier one.

Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>
Cc: Hiroyuki Yokoyama <hiroyuki.yokoyama.vx@renesas.com>
Cc: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
Cc: Jaehoon Chung <jh80.chung@samsung.com>
---
 arch/arm/mach-rmobile/include/mach/sh_sdhi.h |   5 --
 drivers/mmc/sh_sdhi.c                        | 103 ++++++++++++++-------------
 2 files changed, 55 insertions(+), 53 deletions(-)

Comments

Nobuhiro Iwamatsu Aug. 2, 2017, 11:18 p.m. UTC | #1
Hi,

2017-07-22 6:22 GMT+09:00 Marek Vasut <marek.vasut@gmail.com>:
> The command handling in this driver is awful, esp. because the driver
> depends on command numbers to determine whether this is APPCMD or not.
> Also, handling of command RSP response types is totally wrong.
>
> This patch at least plucks out some of the custom command encoding and
> fixes the APPCMD handling. The RSP handling still needs work, yet that
> might not be needed as it turns out the uniphier-sd.c driver is in much
> better shape and supports the same IP, so we might be able to just drop
> this driver in favor of the uniphier one.
>
> Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>
> Cc: Hiroyuki Yokoyama <hiroyuki.yokoyama.vx@renesas.com>
> Cc: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
> Cc: Jaehoon Chung <jh80.chung@samsung.com>

Reviewed-by: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>

> ---
>  arch/arm/mach-rmobile/include/mach/sh_sdhi.h |   5 --
>  drivers/mmc/sh_sdhi.c                        | 103 ++++++++++++++-------------
>  2 files changed, 55 insertions(+), 53 deletions(-)
>
> diff --git a/arch/arm/mach-rmobile/include/mach/sh_sdhi.h b/arch/arm/mach-rmobile/include/mach/sh_sdhi.h
> index 1fb0648b12..00a135faa1 100644
> --- a/arch/arm/mach-rmobile/include/mach/sh_sdhi.h
> +++ b/arch/arm/mach-rmobile/include/mach/sh_sdhi.h
> @@ -49,11 +49,6 @@
>
>  /* SDHI CMD VALUE */
>  #define CMD_MASK                       0x0000ffff
> -#define SDHI_APP                       0x0040
> -#define SDHI_MMC_SEND_OP_COND          0x0701
> -#define SDHI_SD_APP_SEND_SCR           0x0073
> -#define SDHI_SD_SWITCH                 0x1C06
> -#define SDHI_MMC_SEND_EXT_CSD          0x1C08
>
>  /* SDHI_PORTSEL */
>  #define USE_1PORT                      (1 << 8) /* 1 port */
> diff --git a/drivers/mmc/sh_sdhi.c b/drivers/mmc/sh_sdhi.c
> index fd710399b6..3c5616e507 100644
> --- a/drivers/mmc/sh_sdhi.c
> +++ b/drivers/mmc/sh_sdhi.c
> @@ -31,6 +31,7 @@ struct sh_sdhi_host {
>         unsigned char wait_int;
>         unsigned char sd_error;
>         unsigned char detect_waiting;
> +       unsigned char app_cmd;
>  };
>
>  static inline void sh_sdhi_writeq(struct sh_sdhi_host *host, int reg, u64 val)
> @@ -475,65 +476,64 @@ static void sh_sdhi_get_response(struct sh_sdhi_host *host, struct mmc_cmd *cmd)
>  static unsigned short sh_sdhi_set_cmd(struct sh_sdhi_host *host,
>                         struct mmc_data *data, unsigned short opc)
>  {
> -       switch (opc) {
> -       case SD_CMD_APP_SEND_OP_COND:
> -       case SD_CMD_APP_SEND_SCR:
> -               opc |= SDHI_APP;
> -               break;
> -       case SD_CMD_APP_SET_BUS_WIDTH:
> -                /* SD_APP_SET_BUS_WIDTH*/
> +       if (host->app_cmd) {
>                 if (!data)
> -                       opc |= SDHI_APP;
> -               else /* SD_SWITCH */
> -                       opc = SDHI_SD_SWITCH;
> -               break;
> -       case MMC_CMD_SEND_OP_COND:
> -               opc = SDHI_MMC_SEND_OP_COND;
> -               break;
> +                       host->app_cmd = 0;
> +               return opc | BIT(6);
> +       }
> +
> +       switch (opc) {
> +       case MMC_CMD_SWITCH:
> +               return opc | (data ? 0x1c00 : 0x40);
>         case MMC_CMD_SEND_EXT_CSD:
> -               if (data)
> -                       opc = SDHI_MMC_SEND_EXT_CSD;
> -               break;
> +               return opc | (data ? 0x1c00 : 0);
> +       case MMC_CMD_SEND_OP_COND:
> +               return opc | 0x0700;
> +       case MMC_CMD_APP_CMD:
> +               host->app_cmd = 1;
>         default:
> -               break;
> +               return opc;
>         }
> -       return opc;
>  }
>
>  static unsigned short sh_sdhi_data_trans(struct sh_sdhi_host *host,
>                         struct mmc_data *data, unsigned short opc)
>  {
> -       unsigned short ret;
> -
> -       switch (opc) {
> -       case MMC_CMD_READ_MULTIPLE_BLOCK:
> -               ret = sh_sdhi_multi_read(host, data);
> -               break;
> -       case MMC_CMD_WRITE_MULTIPLE_BLOCK:
> -               ret = sh_sdhi_multi_write(host, data);
> -               break;
> -       case MMC_CMD_WRITE_SINGLE_BLOCK:
> -               ret = sh_sdhi_single_write(host, data);
> -               break;
> -       case MMC_CMD_READ_SINGLE_BLOCK:
> -       case SDHI_SD_APP_SEND_SCR:
> -       case SDHI_SD_SWITCH: /* SD_SWITCH */
> -       case SDHI_MMC_SEND_EXT_CSD:
> -               ret = sh_sdhi_single_read(host, data);
> -               break;
> -       default:
> -               printf(DRIVER_NAME": SD: NOT SUPPORT CMD = d'%04d\n", opc);
> -               ret = -EINVAL;
> -               break;
> +       if (host->app_cmd) {
> +               host->app_cmd = 0;
> +               switch (opc) {
> +               case SD_CMD_APP_SEND_SCR:
> +               case SD_CMD_APP_SD_STATUS:
> +                       return sh_sdhi_single_read(host, data);
> +               default:
> +                       printf(DRIVER_NAME": SD: NOT SUPPORT APP CMD = d'%04d\n",
> +                               opc);
> +                       return -EINVAL;
> +               }
> +       } else {
> +               switch (opc) {
> +               case MMC_CMD_WRITE_MULTIPLE_BLOCK:
> +                       return sh_sdhi_multi_write(host, data);
> +               case MMC_CMD_READ_MULTIPLE_BLOCK:
> +                       return sh_sdhi_multi_read(host, data);
> +               case MMC_CMD_WRITE_SINGLE_BLOCK:
> +                       return sh_sdhi_single_write(host, data);
> +               case MMC_CMD_READ_SINGLE_BLOCK:
> +               case MMC_CMD_SWITCH:
> +               case MMC_CMD_SEND_EXT_CSD:;
> +                       return sh_sdhi_single_read(host, data);
> +               default:
> +                       printf(DRIVER_NAME": SD: NOT SUPPORT CMD = d'%04d\n", opc);
> +                       return -EINVAL;
> +               }
>         }
> -       return ret;
>  }
>
>  static int sh_sdhi_start_cmd(struct sh_sdhi_host *host,
>                         struct mmc_data *data, struct mmc_cmd *cmd)
>  {
>         long time;
> -       unsigned short opc = cmd->cmdidx;
> +       unsigned short shcmd, opc = cmd->cmdidx;
>         int ret = 0;
>         unsigned long timeout;
>
> @@ -561,7 +561,8 @@ static int sh_sdhi_start_cmd(struct sh_sdhi_host *host,
>                 }
>                 sh_sdhi_writew(host, SDHI_SIZE, data->blocksize);
>         }
> -       opc = sh_sdhi_set_cmd(host, data, opc);
> +
> +       shcmd = sh_sdhi_set_cmd(host, data, opc);
>
>         /*
>          *  U-Boot cannot use interrupt.
> @@ -592,11 +593,12 @@ static int sh_sdhi_start_cmd(struct sh_sdhi_host *host,
>                        INFO2M_RESP_TIMEOUT | INFO2M_ILA) &
>                        sh_sdhi_readw(host, SDHI_INFO2_MASK));
>
> -       sh_sdhi_writew(host, SDHI_CMD, (unsigned short)(opc & CMD_MASK));
> -
> +       sh_sdhi_writew(host, SDHI_CMD, (unsigned short)(shcmd & CMD_MASK));
>         time = sh_sdhi_wait_interrupt_flag(host);
> -       if (!time)
> +       if (!time) {
> +               host->app_cmd = 0;
>                 return sh_sdhi_error_manage(host);
> +       }
>
>         if (host->sd_error) {
>                 switch (cmd->cmdidx) {
> @@ -614,15 +616,20 @@ static int sh_sdhi_start_cmd(struct sh_sdhi_host *host,
>                 }
>                 host->sd_error = 0;
>                 host->wait_int = 0;
> +               host->app_cmd = 0;
>                 return ret;
>         }
> -       if (sh_sdhi_readw(host, SDHI_INFO1) & INFO1_RESP_END)
> +
> +       if (sh_sdhi_readw(host, SDHI_INFO1) & INFO1_RESP_END) {
> +               host->app_cmd = 0;
>                 return -EINVAL;
> +       }
>
>         if (host->wait_int) {
>                 sh_sdhi_get_response(host, cmd);
>                 host->wait_int = 0;
>         }
> +
>         if (data)
>                 ret = sh_sdhi_data_trans(host, data, opc);
>
> --
> 2.11.0
>
Jaehoon Chung Aug. 17, 2017, 5:39 a.m. UTC | #2
On 07/22/2017 06:22 AM, Marek Vasut wrote:
> The command handling in this driver is awful, esp. because the driver
> depends on command numbers to determine whether this is APPCMD or not.
> Also, handling of command RSP response types is totally wrong.
> 
> This patch at least plucks out some of the custom command encoding and
> fixes the APPCMD handling. The RSP handling still needs work, yet that
> might not be needed as it turns out the uniphier-sd.c driver is in much
> better shape and supports the same IP, so we might be able to just drop
> this driver in favor of the uniphier one.
> 
> Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>
> Cc: Hiroyuki Yokoyama <hiroyuki.yokoyama.vx@renesas.com>
> Cc: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
> Cc: Jaehoon Chung <jh80.chung@samsung.com>
> Reviewed-by: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>

Applied to u-boot-mmc. Sorry for late!

Best Regards,
Jaehoon Chung


> ---
>  arch/arm/mach-rmobile/include/mach/sh_sdhi.h |   5 --
>  drivers/mmc/sh_sdhi.c                        | 103 ++++++++++++++-------------
>  2 files changed, 55 insertions(+), 53 deletions(-)
> 
> diff --git a/arch/arm/mach-rmobile/include/mach/sh_sdhi.h b/arch/arm/mach-rmobile/include/mach/sh_sdhi.h
> index 1fb0648b12..00a135faa1 100644
> --- a/arch/arm/mach-rmobile/include/mach/sh_sdhi.h
> +++ b/arch/arm/mach-rmobile/include/mach/sh_sdhi.h
> @@ -49,11 +49,6 @@
>  
>  /* SDHI CMD VALUE */
>  #define CMD_MASK			0x0000ffff
> -#define SDHI_APP			0x0040
> -#define SDHI_MMC_SEND_OP_COND		0x0701
> -#define SDHI_SD_APP_SEND_SCR		0x0073
> -#define SDHI_SD_SWITCH			0x1C06
> -#define SDHI_MMC_SEND_EXT_CSD		0x1C08
>  
>  /* SDHI_PORTSEL */
>  #define USE_1PORT			(1 << 8) /* 1 port */
> diff --git a/drivers/mmc/sh_sdhi.c b/drivers/mmc/sh_sdhi.c
> index fd710399b6..3c5616e507 100644
> --- a/drivers/mmc/sh_sdhi.c
> +++ b/drivers/mmc/sh_sdhi.c
> @@ -31,6 +31,7 @@ struct sh_sdhi_host {
>  	unsigned char wait_int;
>  	unsigned char sd_error;
>  	unsigned char detect_waiting;
> +	unsigned char app_cmd;
>  };
>  
>  static inline void sh_sdhi_writeq(struct sh_sdhi_host *host, int reg, u64 val)
> @@ -475,65 +476,64 @@ static void sh_sdhi_get_response(struct sh_sdhi_host *host, struct mmc_cmd *cmd)
>  static unsigned short sh_sdhi_set_cmd(struct sh_sdhi_host *host,
>  			struct mmc_data *data, unsigned short opc)
>  {
> -	switch (opc) {
> -	case SD_CMD_APP_SEND_OP_COND:
> -	case SD_CMD_APP_SEND_SCR:
> -		opc |= SDHI_APP;
> -		break;
> -	case SD_CMD_APP_SET_BUS_WIDTH:
> -		 /* SD_APP_SET_BUS_WIDTH*/
> +	if (host->app_cmd) {
>  		if (!data)
> -			opc |= SDHI_APP;
> -		else /* SD_SWITCH */
> -			opc = SDHI_SD_SWITCH;
> -		break;
> -	case MMC_CMD_SEND_OP_COND:
> -		opc = SDHI_MMC_SEND_OP_COND;
> -		break;
> +			host->app_cmd = 0;
> +		return opc | BIT(6);
> +	}
> +
> +	switch (opc) {
> +	case MMC_CMD_SWITCH:
> +		return opc | (data ? 0x1c00 : 0x40);
>  	case MMC_CMD_SEND_EXT_CSD:
> -		if (data)
> -			opc = SDHI_MMC_SEND_EXT_CSD;
> -		break;
> +		return opc | (data ? 0x1c00 : 0);
> +	case MMC_CMD_SEND_OP_COND:
> +		return opc | 0x0700;
> +	case MMC_CMD_APP_CMD:
> +		host->app_cmd = 1;
>  	default:
> -		break;
> +		return opc;
>  	}
> -	return opc;
>  }
>  
>  static unsigned short sh_sdhi_data_trans(struct sh_sdhi_host *host,
>  			struct mmc_data *data, unsigned short opc)
>  {
> -	unsigned short ret;
> -
> -	switch (opc) {
> -	case MMC_CMD_READ_MULTIPLE_BLOCK:
> -		ret = sh_sdhi_multi_read(host, data);
> -		break;
> -	case MMC_CMD_WRITE_MULTIPLE_BLOCK:
> -		ret = sh_sdhi_multi_write(host, data);
> -		break;
> -	case MMC_CMD_WRITE_SINGLE_BLOCK:
> -		ret = sh_sdhi_single_write(host, data);
> -		break;
> -	case MMC_CMD_READ_SINGLE_BLOCK:
> -	case SDHI_SD_APP_SEND_SCR:
> -	case SDHI_SD_SWITCH: /* SD_SWITCH */
> -	case SDHI_MMC_SEND_EXT_CSD:
> -		ret = sh_sdhi_single_read(host, data);
> -		break;
> -	default:
> -		printf(DRIVER_NAME": SD: NOT SUPPORT CMD = d'%04d\n", opc);
> -		ret = -EINVAL;
> -		break;
> +	if (host->app_cmd) {
> +		host->app_cmd = 0;
> +		switch (opc) {
> +		case SD_CMD_APP_SEND_SCR:
> +		case SD_CMD_APP_SD_STATUS:
> +			return sh_sdhi_single_read(host, data);
> +		default:
> +			printf(DRIVER_NAME": SD: NOT SUPPORT APP CMD = d'%04d\n",
> +				opc);
> +			return -EINVAL;
> +		}
> +	} else {
> +		switch (opc) {
> +		case MMC_CMD_WRITE_MULTIPLE_BLOCK:
> +			return sh_sdhi_multi_write(host, data);
> +		case MMC_CMD_READ_MULTIPLE_BLOCK:
> +			return sh_sdhi_multi_read(host, data);
> +		case MMC_CMD_WRITE_SINGLE_BLOCK:
> +			return sh_sdhi_single_write(host, data);
> +		case MMC_CMD_READ_SINGLE_BLOCK:
> +		case MMC_CMD_SWITCH:
> +		case MMC_CMD_SEND_EXT_CSD:;
> +			return sh_sdhi_single_read(host, data);
> +		default:
> +			printf(DRIVER_NAME": SD: NOT SUPPORT CMD = d'%04d\n", opc);
> +			return -EINVAL;
> +		}
>  	}
> -	return ret;
>  }
>  
>  static int sh_sdhi_start_cmd(struct sh_sdhi_host *host,
>  			struct mmc_data *data, struct mmc_cmd *cmd)
>  {
>  	long time;
> -	unsigned short opc = cmd->cmdidx;
> +	unsigned short shcmd, opc = cmd->cmdidx;
>  	int ret = 0;
>  	unsigned long timeout;
>  
> @@ -561,7 +561,8 @@ static int sh_sdhi_start_cmd(struct sh_sdhi_host *host,
>  		}
>  		sh_sdhi_writew(host, SDHI_SIZE, data->blocksize);
>  	}
> -	opc = sh_sdhi_set_cmd(host, data, opc);
> +
> +	shcmd = sh_sdhi_set_cmd(host, data, opc);
>  
>  	/*
>  	 *  U-Boot cannot use interrupt.
> @@ -592,11 +593,12 @@ static int sh_sdhi_start_cmd(struct sh_sdhi_host *host,
>  		       INFO2M_RESP_TIMEOUT | INFO2M_ILA) &
>  		       sh_sdhi_readw(host, SDHI_INFO2_MASK));
>  
> -	sh_sdhi_writew(host, SDHI_CMD, (unsigned short)(opc & CMD_MASK));
> -
> +	sh_sdhi_writew(host, SDHI_CMD, (unsigned short)(shcmd & CMD_MASK));
>  	time = sh_sdhi_wait_interrupt_flag(host);
> -	if (!time)
> +	if (!time) {
> +		host->app_cmd = 0;
>  		return sh_sdhi_error_manage(host);
> +	}
>  
>  	if (host->sd_error) {
>  		switch (cmd->cmdidx) {
> @@ -614,15 +616,20 @@ static int sh_sdhi_start_cmd(struct sh_sdhi_host *host,
>  		}
>  		host->sd_error = 0;
>  		host->wait_int = 0;
> +		host->app_cmd = 0;
>  		return ret;
>  	}
> -	if (sh_sdhi_readw(host, SDHI_INFO1) & INFO1_RESP_END)
> +
> +	if (sh_sdhi_readw(host, SDHI_INFO1) & INFO1_RESP_END) {
> +		host->app_cmd = 0;
>  		return -EINVAL;
> +	}
>  
>  	if (host->wait_int) {
>  		sh_sdhi_get_response(host, cmd);
>  		host->wait_int = 0;
>  	}
> +
>  	if (data)
>  		ret = sh_sdhi_data_trans(host, data, opc);
>  
>
diff mbox

Patch

diff --git a/arch/arm/mach-rmobile/include/mach/sh_sdhi.h b/arch/arm/mach-rmobile/include/mach/sh_sdhi.h
index 1fb0648b12..00a135faa1 100644
--- a/arch/arm/mach-rmobile/include/mach/sh_sdhi.h
+++ b/arch/arm/mach-rmobile/include/mach/sh_sdhi.h
@@ -49,11 +49,6 @@ 
 
 /* SDHI CMD VALUE */
 #define CMD_MASK			0x0000ffff
-#define SDHI_APP			0x0040
-#define SDHI_MMC_SEND_OP_COND		0x0701
-#define SDHI_SD_APP_SEND_SCR		0x0073
-#define SDHI_SD_SWITCH			0x1C06
-#define SDHI_MMC_SEND_EXT_CSD		0x1C08
 
 /* SDHI_PORTSEL */
 #define USE_1PORT			(1 << 8) /* 1 port */
diff --git a/drivers/mmc/sh_sdhi.c b/drivers/mmc/sh_sdhi.c
index fd710399b6..3c5616e507 100644
--- a/drivers/mmc/sh_sdhi.c
+++ b/drivers/mmc/sh_sdhi.c
@@ -31,6 +31,7 @@  struct sh_sdhi_host {
 	unsigned char wait_int;
 	unsigned char sd_error;
 	unsigned char detect_waiting;
+	unsigned char app_cmd;
 };
 
 static inline void sh_sdhi_writeq(struct sh_sdhi_host *host, int reg, u64 val)
@@ -475,65 +476,64 @@  static void sh_sdhi_get_response(struct sh_sdhi_host *host, struct mmc_cmd *cmd)
 static unsigned short sh_sdhi_set_cmd(struct sh_sdhi_host *host,
 			struct mmc_data *data, unsigned short opc)
 {
-	switch (opc) {
-	case SD_CMD_APP_SEND_OP_COND:
-	case SD_CMD_APP_SEND_SCR:
-		opc |= SDHI_APP;
-		break;
-	case SD_CMD_APP_SET_BUS_WIDTH:
-		 /* SD_APP_SET_BUS_WIDTH*/
+	if (host->app_cmd) {
 		if (!data)
-			opc |= SDHI_APP;
-		else /* SD_SWITCH */
-			opc = SDHI_SD_SWITCH;
-		break;
-	case MMC_CMD_SEND_OP_COND:
-		opc = SDHI_MMC_SEND_OP_COND;
-		break;
+			host->app_cmd = 0;
+		return opc | BIT(6);
+	}
+
+	switch (opc) {
+	case MMC_CMD_SWITCH:
+		return opc | (data ? 0x1c00 : 0x40);
 	case MMC_CMD_SEND_EXT_CSD:
-		if (data)
-			opc = SDHI_MMC_SEND_EXT_CSD;
-		break;
+		return opc | (data ? 0x1c00 : 0);
+	case MMC_CMD_SEND_OP_COND:
+		return opc | 0x0700;
+	case MMC_CMD_APP_CMD:
+		host->app_cmd = 1;
 	default:
-		break;
+		return opc;
 	}
-	return opc;
 }
 
 static unsigned short sh_sdhi_data_trans(struct sh_sdhi_host *host,
 			struct mmc_data *data, unsigned short opc)
 {
-	unsigned short ret;
-
-	switch (opc) {
-	case MMC_CMD_READ_MULTIPLE_BLOCK:
-		ret = sh_sdhi_multi_read(host, data);
-		break;
-	case MMC_CMD_WRITE_MULTIPLE_BLOCK:
-		ret = sh_sdhi_multi_write(host, data);
-		break;
-	case MMC_CMD_WRITE_SINGLE_BLOCK:
-		ret = sh_sdhi_single_write(host, data);
-		break;
-	case MMC_CMD_READ_SINGLE_BLOCK:
-	case SDHI_SD_APP_SEND_SCR:
-	case SDHI_SD_SWITCH: /* SD_SWITCH */
-	case SDHI_MMC_SEND_EXT_CSD:
-		ret = sh_sdhi_single_read(host, data);
-		break;
-	default:
-		printf(DRIVER_NAME": SD: NOT SUPPORT CMD = d'%04d\n", opc);
-		ret = -EINVAL;
-		break;
+	if (host->app_cmd) {
+		host->app_cmd = 0;
+		switch (opc) {
+		case SD_CMD_APP_SEND_SCR:
+		case SD_CMD_APP_SD_STATUS:
+			return sh_sdhi_single_read(host, data);
+		default:
+			printf(DRIVER_NAME": SD: NOT SUPPORT APP CMD = d'%04d\n",
+				opc);
+			return -EINVAL;
+		}
+	} else {
+		switch (opc) {
+		case MMC_CMD_WRITE_MULTIPLE_BLOCK:
+			return sh_sdhi_multi_write(host, data);
+		case MMC_CMD_READ_MULTIPLE_BLOCK:
+			return sh_sdhi_multi_read(host, data);
+		case MMC_CMD_WRITE_SINGLE_BLOCK:
+			return sh_sdhi_single_write(host, data);
+		case MMC_CMD_READ_SINGLE_BLOCK:
+		case MMC_CMD_SWITCH:
+		case MMC_CMD_SEND_EXT_CSD:;
+			return sh_sdhi_single_read(host, data);
+		default:
+			printf(DRIVER_NAME": SD: NOT SUPPORT CMD = d'%04d\n", opc);
+			return -EINVAL;
+		}
 	}
-	return ret;
 }
 
 static int sh_sdhi_start_cmd(struct sh_sdhi_host *host,
 			struct mmc_data *data, struct mmc_cmd *cmd)
 {
 	long time;
-	unsigned short opc = cmd->cmdidx;
+	unsigned short shcmd, opc = cmd->cmdidx;
 	int ret = 0;
 	unsigned long timeout;
 
@@ -561,7 +561,8 @@  static int sh_sdhi_start_cmd(struct sh_sdhi_host *host,
 		}
 		sh_sdhi_writew(host, SDHI_SIZE, data->blocksize);
 	}
-	opc = sh_sdhi_set_cmd(host, data, opc);
+
+	shcmd = sh_sdhi_set_cmd(host, data, opc);
 
 	/*
 	 *  U-Boot cannot use interrupt.
@@ -592,11 +593,12 @@  static int sh_sdhi_start_cmd(struct sh_sdhi_host *host,
 		       INFO2M_RESP_TIMEOUT | INFO2M_ILA) &
 		       sh_sdhi_readw(host, SDHI_INFO2_MASK));
 
-	sh_sdhi_writew(host, SDHI_CMD, (unsigned short)(opc & CMD_MASK));
-
+	sh_sdhi_writew(host, SDHI_CMD, (unsigned short)(shcmd & CMD_MASK));
 	time = sh_sdhi_wait_interrupt_flag(host);
-	if (!time)
+	if (!time) {
+		host->app_cmd = 0;
 		return sh_sdhi_error_manage(host);
+	}
 
 	if (host->sd_error) {
 		switch (cmd->cmdidx) {
@@ -614,15 +616,20 @@  static int sh_sdhi_start_cmd(struct sh_sdhi_host *host,
 		}
 		host->sd_error = 0;
 		host->wait_int = 0;
+		host->app_cmd = 0;
 		return ret;
 	}
-	if (sh_sdhi_readw(host, SDHI_INFO1) & INFO1_RESP_END)
+
+	if (sh_sdhi_readw(host, SDHI_INFO1) & INFO1_RESP_END) {
+		host->app_cmd = 0;
 		return -EINVAL;
+	}
 
 	if (host->wait_int) {
 		sh_sdhi_get_response(host, cmd);
 		host->wait_int = 0;
 	}
+
 	if (data)
 		ret = sh_sdhi_data_trans(host, data, opc);