
From: Shrinivas Sahukar shrinivas.sahukar@lntinfotech.com
Signed-off-by: Shrinivas Sahukar shrinivas.sahukar@lntinfotech.com --- drivers/mmc/qc_mmc.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 68 insertions(+), 3 deletions(-)
diff --git a/drivers/mmc/qc_mmc.c b/drivers/mmc/qc_mmc.c index 930c410..9949cda 100644 --- a/drivers/mmc/qc_mmc.c +++ b/drivers/mmc/qc_mmc.c @@ -180,6 +180,65 @@ static unsigned int mmc_boot_fifo_read(unsigned int *mmc_ptr, return mmc_ret; }
+/* + * Write data to SDC FIFO. + */ +static unsigned int mmc_boot_fifo_write(unsigned int *mmc_ptr, + unsigned int data_len, struct mmc *mmc) +{ + unsigned int mmc_ret = MMC_BOOT_E_SUCCESS; + unsigned int mmc_status = 0; + unsigned int mmc_count = 0; + unsigned int write_error = MMC_BOOT_MCI_STAT_DATA_CRC_FAIL | + MMC_BOOT_MCI_STAT_DATA_TIMEOUT | MMC_BOOT_MCI_STAT_TX_UNDRUN; + unsigned int i; + struct mmc_priv *priv = (struct mmc_priv *)mmc->priv; + unsigned long reg_status, reg_fifo; + + reg_status = mmc_boot_mci_reg(priv->base, MMC_BOOT_MCI_STATUS); + reg_fifo = mmc_boot_mci_reg(priv->base, MMC_BOOT_MCI_FIFO); + + /* Write the transfer data to SDCC3 FIFO */ + do { + mmc_ret = MMC_BOOT_E_SUCCESS; + mmc_status = readl(reg_status); + if (mmc_status & write_error) { + mmc_ret = mmc_boot_status_error(mmc_status); + break; + } + /* Write the data in MCI_FIFO register as long as TXFIFO_FULL + bit of MCI_STATUS register is 0. Continue the writes until + the whole transfer data is written. */ + if (((data_len - mmc_count) >= MMC_BOOT_MCI_FIFO_SIZE / 2) && + (mmc_status & MMC_BOOT_MCI_STAT_TX_FIFO_HFULL)) { + unsigned write_count = 1; + write_count = MMC_BOOT_MCI_HFIFO_COUNT; + for (i = 0; i < write_count; i++) { + /* FIFO contains 16 32-bit data buffer + on 16 sequential addresses */ + writel(*mmc_ptr, reg_fifo + + (mmc_count % MMC_BOOT_MCI_FIFO_SIZE)); + mmc_ptr++; + /* increase mmc_count by word size */ + mmc_count += sizeof(unsigned int); + } + + } else if (!(mmc_status & MMC_BOOT_MCI_STAT_TX_FIFO_FULL) + && (mmc_count != data_len)) { + /* FIFO contains 16 32-bit data buffer + on 16 sequential addresses */ + writel(*mmc_ptr, reg_fifo + + (mmc_count % MMC_BOOT_MCI_FIFO_SIZE)); + mmc_ptr++; + /* increase mmc_count by word size */ + mmc_count += sizeof(unsigned int); + } else if ((mmc_status & MMC_BOOT_MCI_STAT_DATA_END)) { + break; + } + } while (1); + return mmc_ret; +} + static unsigned int mmc_boot_fifo_data_transfer(unsigned int *data_ptr, unsigned int data_len, unsigned char direction, @@ -189,6 +248,8 @@ static unsigned int mmc_boot_fifo_data_transfer(unsigned int *data_ptr,
if (direction == MMC_BOOT_DATA_READ) mmc_ret = mmc_boot_fifo_read(data_ptr, data_len, mmc); + else + mmc_ret = mmc_boot_fifo_write(data_ptr, data_len, mmc);
return mmc_ret; } @@ -350,7 +411,7 @@ static unsigned int mmc_boot_send_command(struct mmc_cmd *cmd, break; }
- } while (1); + } while (1);
return mmc_return; } @@ -413,6 +474,7 @@ int mmc_boot_send_command_map(struct mmc *mmc, struct mmc_data *data) { unsigned int mmc_ret = MMC_BOOT_E_SUCCESS; + unsigned char direction = 0;
/* todo: do we need to fill in command type ?? */
@@ -434,6 +496,10 @@ int mmc_boot_send_command_map(struct mmc *mmc, mmc->read_bl_len = MMC_BOOT_RD_BLOCK_LEN; data->blocksize = MMC_BOOT_RD_BLOCK_LEN; } + direction = MMC_BOOT_DATA_READ; + } else if ((cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK) || + (cmd->cmdidx == MMC_CMD_WRITE_SINGLE_BLOCK)) { + direction = MMC_BOOT_DATA_WRITE; } else if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) { /* explicitly disable the prg enabled flag */ cmd->flags &= ~MMC_BOOT_PROGRAM_ENABLED; @@ -441,7 +507,6 @@ int mmc_boot_send_command_map(struct mmc *mmc, cmd->flags |= MMC_BOOT_XFER_MODE_BLOCK; }
- /* For Data cmd's */ if (data != NULL) mmc_boot_init_data(mmc, cmd, data); @@ -460,7 +525,7 @@ int mmc_boot_send_command_map(struct mmc *mmc, return mmc_ret; mmc_boot_fifo_data_transfer((unsigned int *) data->dest, data->blocks * data->blocksize, - MMC_BOOT_DATA_READ, + direction, mmc); }