mmc: at91_mci: fix multiblock SDIO transfers

The AT91 MCI has special SDIO transfer types: SDIO block and SDIO byte
transfers, but at91_mci driver doesn't use them and handles all SDIO
transfers as ordinary MMC block transfers. This causes problems for
multiple-block SDIO transfers (in particular for 256-bytes blocks).

Fix this situation by checking the opcode for SDIO CMD53 and setting
the transfer type in the AT91_MCI_CMDR register properly.

This patch was tested with libertas SDIO driver: problem with TX
timeouts on big packets was eliminated.

Signed-off-by: Yauhen Kharuzhy <yauhen.kharuzhy@promwad.com>
Cc: <stable@kernel.org>
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Signed-off-by: Chris Ball <cjb@laptop.org>

authored by Yauhen Kharuzhy and committed by Chris Ball a2255ff4 0a592281

+11 -4
+2
arch/arm/mach-at91/include/mach/at91_mci.h
··· 74 74 #define AT91_MCI_TRTYP_BLOCK (0 << 19) 75 75 #define AT91_MCI_TRTYP_MULTIPLE (1 << 19) 76 76 #define AT91_MCI_TRTYP_STREAM (2 << 19) 77 + #define AT91_MCI_TRTYP_SDIO_BYTE (4 << 19) 78 + #define AT91_MCI_TRTYP_SDIO_BLOCK (5 << 19) 77 79 78 80 #define AT91_MCI_BLKR 0x18 /* Block Register */ 79 81 #define AT91_MCI_BLKR_BCNT(n) ((0xffff & (n)) << 0) /* Block count */
+9 -4
drivers/mmc/host/at91_mci.c
··· 69 69 #include <linux/highmem.h> 70 70 71 71 #include <linux/mmc/host.h> 72 + #include <linux/mmc/sdio.h> 72 73 73 74 #include <asm/io.h> 74 75 #include <asm/irq.h> ··· 494 493 else if (data->flags & MMC_DATA_WRITE) 495 494 cmdr |= AT91_MCI_TRCMD_START; 496 495 497 - if (data->flags & MMC_DATA_STREAM) 498 - cmdr |= AT91_MCI_TRTYP_STREAM; 499 - if (data->blocks > 1) 500 - cmdr |= AT91_MCI_TRTYP_MULTIPLE; 496 + if (cmd->opcode == SD_IO_RW_EXTENDED) { 497 + cmdr |= AT91_MCI_TRTYP_SDIO_BLOCK; 498 + } else { 499 + if (data->flags & MMC_DATA_STREAM) 500 + cmdr |= AT91_MCI_TRTYP_STREAM; 501 + if (data->blocks > 1) 502 + cmdr |= AT91_MCI_TRTYP_MULTIPLE; 503 + } 501 504 } 502 505 else { 503 506 block_length = 0;