]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
Xilinx: ARM: Add multiblock MMC read support
authorJoe Hershberger <joe.hershberger@ni.com>
Fri, 20 Apr 2012 21:56:13 +0000 (16:56 -0500)
committerJagan <jaganna@xilinx.com>
Thu, 31 May 2012 07:39:19 +0000 (13:09 +0530)
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 <joe.hershberger@ni.com>
board/xilinx/dfe/mmc.c

index 232a870ae073792bd405e6cd8b9d02a46495cf3d..35c5ad9db27ad6d2d9bebb7e42bbfe106b3a9213 100755 (executable)
@@ -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 */