From 5fb49bcd309884b504d64f0bc3a369505f7a5031 Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Fri, 20 Apr 2012 16:56:13 -0500 Subject: [PATCH] Xilinx: ARM: Add multiblock MMC read support Direct buffer DMA is currently broken. I suspect an alignment requirement. The latest u-boot upstream aligns the DOS partition and FAT fs buffers. The intermediate DMA buffer is too small for most transfers. Signed-off-by: Joe Hershberger --- board/xilinx/dfe/mmc.c | 57 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 11 deletions(-) diff --git a/board/xilinx/dfe/mmc.c b/board/xilinx/dfe/mmc.c index 232a870ae07..35c5ad9db27 100755 --- a/board/xilinx/dfe/mmc.c +++ b/board/xilinx/dfe/mmc.c @@ -177,13 +177,13 @@ make_command (unsigned cmd) case CMD12: case ACMD13: case CMD16: + case CMD23: retval |= RSP_R1; break; case CMD17: + case CMD18: retval |= RSP_R1|SD_CMD_DATA; break; - case CMD18: - case CMD23: case ACMD23: case CMD24: case CMD25: @@ -199,6 +199,9 @@ make_command (unsigned cmd) break; case CMD58: break; + default: + printf("Unknown command\n"); + break; } return retval; @@ -209,6 +212,7 @@ static int pele_sdh_request(struct mmc *mmc, struct mmc_cmd *cmd, { u32 status; u16 cmdreg; + u16 modereg; int result = 0; #ifdef DEBUG_VERBOSE @@ -217,42 +221,71 @@ static int pele_sdh_request(struct mmc *mmc, struct mmc_cmd *cmd, #endif cmd->response[0] = 0; + cmdreg = make_command(cmd->cmdidx); /* Wait until the device is willing to accept commands */ do { status = sd_in32(SD_PRES_STATE_R); } while (status & (SD_CMD_INHIBIT|SD_DATA_INHIBIT)); - /* Set the DMA address to the DMA buffer. + /* + * Set the DMA address to the DMA buffer. * This is only relevant for data commands. * u-boot performs a copy rather than DMA directly into the user * buffer because the controller can't DMA into the first 512K * of DDR. */ +#ifdef DEBUG_VERBOSE + printf("data->dest = %p (%d) (%d * %d)\n", data->dest, + (cmdreg & SD_CMD_DATA) ? data->blocks : 0, data->blocks, + data->blocksize); +#endif + +#ifdef CONFIG_ZYNQ_SD_DIRECT_DMA + /* + * Added based on above comment. + * No evidence in the TRM supports this that I could find, though + */ + if (data->dest < 0x80000) { + printf("Cannot DMA to lowest 512k of DDR\n"); + return COMM_ERR; + } + sd_out32(SD_DMA_ADDR_R, (u32)data->dest); +#else + if ((cmdreg & SD_CMD_DATA) && data->blocksize * data->blocks > 512) { + printf("MMC driver buffer too small\n"); + return COMM_ERR; + } sd_out32(SD_DMA_ADDR_R, (u32)sd_dma_buffer); +#endif - /* 512 bytes + /* + * 512 bytes * This is only relevant for data commands. */ - sd_out16(SD_BLOCK_SZ_R, 0x200); - sd_out16(SD_BLOCK_CNT_R, 1); + if (cmdreg & SD_CMD_DATA) { + sd_out16(SD_BLOCK_SZ_R, data->blocksize); + sd_out16(SD_BLOCK_CNT_R, data->blocks); + } sd_out8(SD_TIMEOUT_CTL_R, 0xA); sd_out32(SD_ARG_R, cmd->cmdarg); - /* Set the transfer mode to read, simple DMA, single block + /* + * Set the transfer mode to read, simple DMA, single block * (applicable only to data commands) * This is all that this software supports. */ - sd_out16(SD_TRNS_MODE_R, - SD_TRNS_BLK_CNT_EN|SD_TRNS_READ|SD_TRNS_DMA); + modereg = SD_TRNS_BLK_CNT_EN | SD_TRNS_READ | SD_TRNS_DMA; + if (data->blocks > 1) + modereg |= SD_TRNS_MULTI; + sd_out16(SD_TRNS_MODE_R, modereg); /* Clear all pending interrupt status */ sd_out32(SD_INT_STAT_R, 0xFFFFFFFF); /* Initiate the command */ - cmdreg = make_command(cmd->cmdidx); sd_out16(SD_CMD_R, cmdreg); /* Poll until operation complete */ @@ -307,9 +340,11 @@ static int pele_sdh_request(struct mmc *mmc, struct mmc_cmd *cmd, cmd->response[0] = sd_in32(SD_RSP_R); } +#ifndef CONFIG_ZYNQ_SD_DIRECT_DMA if (cmdreg & SD_CMD_DATA) { - memcpy(data->dest, sd_dma_buffer, 512); + memcpy(data->dest, sd_dma_buffer, data->blocks * data->blocksize); } +#endif exit: /* Clear all pending interrupt status */ -- 2.47.3