/*
 * Copyright (C) 2010-2014 The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <endian.h>
#include <libpayload.h>
#include <stdint.h>

#include "config.h"
#include "drivers/storage/blockdev.h"
#include "drivers/storage/ipq806x_mmc.h"

#define USEC_PER_SEC	(1000000L)
#define MAX_DELAY_MS	100

static int mmc_boot_send_command(MmcCtrlr *ctrlr,
				 MmcCommand *cmd, MmcData *data);

/*
 * Read a register in a loop until the masked read value matches the expected
 * value, up to MAX_DELAY_MS milliseconds.
 *
 * Save the last read value at the user provided address, if there is one.
 * Return success or error on timeout.
 */
static int wait_on_reg(void *reg_addr, uint32_t mask,
		   uint32_t expected_value, uint32_t  *last_read_value)
{
	unsigned start_ts;
	unsigned value;
	unsigned d = MAX_DELAY_MS * timer_hz() / 1000;

	start_ts = timer_raw_value(); /* Get initial time stamp. */

	do {
		value = readl(reg_addr);

		if ((timer_raw_value() - start_ts) > d) {
			mmc_error("Timeout waiting on %p for %#x:%#x\n",
				  reg_addr, mask, expected_value);
			return MMC_INVALID_ERR;
		}
	} while ((value & mask) != expected_value);

	if (last_read_value)
		*last_read_value = value;

	return MMC_BOOT_E_SUCCESS;
}

/*
 * mmc_mclk_reg_wr_delay should be called after every writes to
 * the MCI_POWER, MCI_CLK, MCI_CMD, or MCI_DATA_CTL register.
 * todo: add special purpose writel for this to encapsulate
 */
static void mmc_mclk_reg_wr_delay(MmcCtrlr *ctrlr)
{
	QcomMmcHost *mmc_host = container_of(ctrlr, QcomMmcHost, mmc);

	/* Wait for the MMC_BOOT_MCI register write to go through. */
	wait_on_reg(MMC_BOOT_MCI_STATUS2(mmc_host->mci_base),
		    MMC_BOOT_MCI_MCLK_REG_WR_ACTIVE,
		    0, NULL);
}

void mmc_boot_mci_clk_enable(MmcCtrlr *ctrlr)
{
	QcomMmcHost *mmc_host = container_of(ctrlr, QcomMmcHost, mmc);
	uint32_t reg;

	reg = (MMC_BOOT_MCI_CLK_ENABLE | MMC_BOOT_MCI_CLK_ENA_FLOW |
		MMC_BOOT_MCI_CLK_IN_FEEDBACK);

	writel(reg, MMC_BOOT_MCI_CLK(mmc_host->mci_base));

	/* Wait for the MMC_BOOT_MCI_CLK write to go through. */
	mmc_mclk_reg_wr_delay(ctrlr);

	/* Enable power save */
	reg |= MMC_BOOT_MCI_CLK_PWRSAVE;
	writel(reg, MMC_BOOT_MCI_CLK(mmc_host->mci_base));

	/* Wait for the MMC_BOOT_MCI_CLK write to go through. */
	mmc_mclk_reg_wr_delay(ctrlr);
}

/*
 * A command to set the data bus width for card. Set width to either
 * 1 BIT, 4 BIT or 8 BIT.
 */
static int mmc_boot_set_bus_width(MmcCtrlr *ctrlr, unsigned width)
{
	QcomMmcHost *mmc_host = container_of(ctrlr, QcomMmcHost, mmc);
	uint32_t mmc_reg;

	/* set MCI_CLK accordingly */
	mmc_reg = readl(MMC_BOOT_MCI_CLK(mmc_host->mci_base));
	mmc_reg &= ~MMC_BOOT_MCI_CLK_WIDEBUS_MODE;

	switch (width) {
	case 1:
		mmc_reg |= MMC_BOOT_MCI_CLK_WIDEBUS_1_BIT;
		break;
	case 4:
		mmc_reg |= MMC_BOOT_MCI_CLK_WIDEBUS_4_BIT;
		break;
	case 8:
		mmc_reg |= MMC_BOOT_MCI_CLK_WIDEBUS_8_BIT;
		break;
	default:
		mmc_error("Invalid MMC bus width.");
		return MMC_UNUSABLE_ERR;
	}

	writel(mmc_reg, MMC_BOOT_MCI_CLK(mmc_host->mci_base));

	/* Wait for the MMC_BOOT_MCI_CLK write to go through. */
	mmc_mclk_reg_wr_delay(ctrlr);

	return MMC_BOOT_E_SUCCESS;
}

/*
 * Decode type of error caused during read and write
 */
static int mmc_boot_data_status_decode(unsigned mmc_status)
{
	if (!(mmc_status & (MMC_READ_ERROR|MMC_WRITE_ERROR)))
		return 0;

	/*
	 * If DATA_CRC_FAIL bit is set to 1 then CRC error was detected by
	 * card/device during the data transfer
	 */
	if (mmc_status & MMC_BOOT_MCI_STAT_DATA_CRC_FAIL)
		return MMC_COMM_ERR;

	/*
	 * If DATA_TIMEOUT bit is set to 1 then the data transfer time
	 * exceeded the data timeout period without completing the transfer
	 */
	if (mmc_status & MMC_BOOT_MCI_STAT_DATA_TIMEOUT)
		return MMC_TIMEOUT;

	/*
	 * If RX_OVERRUN bit is set to 1 then SDCC2 tried to receive data from
	 * the card before empty storage for new received data was available.
	 * Verify that bit FLOW_ENA in MCI_CLK is set to 1 during the data
	 * xfer.
	 */
	if (mmc_status & MMC_BOOT_MCI_STAT_RX_OVRRUN) {
		/*
		 * Note: We've set FLOW_ENA bit in MCI_CLK to 1. so no need to
		 * verify for now
		 */
		return MMC_COMM_ERR;
	}
	/*
	 * If TX_UNDERRUN bit is set to 1 then SDCC2 tried to send data to
	 * the card before new data for sending was available. Verify that bit
	 * FLOW_ENA in MCI_CLK is set to 1 during the data xfer.
	 */
	if (mmc_status & MMC_BOOT_MCI_STAT_TX_UNDRUN) {
		/*
		 * Note: We've set FLOW_ENA bit in MCI_CLK to 1.
		 * so skipping it now
		 */
		return MMC_COMM_ERR;
	}
	return MMC_INVALID_ERR;
}

/*
 * Read data from SDC FIFO.
 */
static int mmc_boot_fifo_read(MmcCtrlr *ctrlr, MmcData *data)
{
	int mmc_ret = MMC_BOOT_E_SUCCESS;
	uint32_t mmc_status;
	unsigned mmc_count = 0;
	uint32_t *mmc_ptr = (uint32_t *)data->dest;
	uint32_t data_len = data->blocks * data->blocksize;
	QcomMmcHost *mmc_host = container_of(ctrlr, QcomMmcHost, mmc);

	/*
	 * Read the data from the MCI_FIFO register as long as RXDATA_AVLBL
	 * bit of MCI_STATUS register is set to 1 and bits DATA_CRC_FAIL,
	 * DATA_TIMEOUT, RX_OVERRUN of MCI_STATUS register are cleared to 0.
	 * Continue the reads until the whole transfer data is received
	 */
	while (1) {
		mmc_status = readl(MMC_BOOT_MCI_STATUS(mmc_host->mci_base));
		mmc_ret = mmc_boot_data_status_decode(mmc_status);
		if (mmc_ret != MMC_BOOT_E_SUCCESS)
			break;

		if (mmc_status & MMC_BOOT_MCI_STAT_RX_DATA_AVLBL) {
			unsigned i, read_count = 1;

			if (mmc_status & MMC_BOOT_MCI_STAT_RX_FIFO_HFULL)
				read_count = MMC_BOOT_MCI_HFIFO_COUNT;

			for (i = 0; i < read_count; i++) {
				/*
				 * FIFO contains 16 32-bit data buffer on
				 * 16 sequential addresses.
				 */
				*mmc_ptr = readl
					(MMC_BOOT_MCI_FIFO(mmc_host->mci_base)
					 +
					 (mmc_count % MMC_BOOT_MCI_FIFO_SIZE));
				mmc_ptr++;
				/* increase mmc_count by word size */
				mmc_count += sizeof(uint32_t);
			}
			/* quit if we have read enough of data */
			if (mmc_count == data_len)
				break;
		} else if (mmc_status & MMC_BOOT_MCI_STAT_DATA_END) {
			break;
		}
	}

	return mmc_ret;
}

/*
 * Write data to SDC FIFO.
 */
static int mmc_boot_fifo_write(MmcCtrlr *ctrlr, MmcData *data)
{

	int mmc_ret = MMC_BOOT_E_SUCCESS;
	uint32_t mmc_status;
	unsigned mmc_count = 0;
	unsigned count;
	uint32_t *mmc_ptr = (uint32_t *) data->src;
	uint32_t data_len = data->blocks * data->blocksize;
	QcomMmcHost *mmc_host = container_of(ctrlr, QcomMmcHost, mmc);
	uint32_t mmc_reg;

	/*
	 * Set appropriate fields and write the MCI_DATA_CTL register.
	 * Set ENABLE bit to enable the data transfer.
	 */
	mmc_reg = MMC_BOOT_MCI_DATA_ENABLE;
	/*
	 * Clear DIRECTION bit to enable transfer from host to card.
	 * Clear MODE bit to enable block oriented data transfer.
	 * Set DM_ENABLE bit in order to enable DMA, otherwise clear it.
	 * Write size of block to be used during the data transfer to
	 * BLOCKSIZE field
	 *
	 * For MMC cards only, if stream data transfer mode is desired, set
	 * MODE bit.
	 */
	mmc_reg |= ctrlr->media->write_bl_len << MMC_BOOT_MCI_BLKSIZE_POS;
	writel(mmc_reg, MMC_BOOT_MCI_DATA_CTL(mmc_host->mci_base));

	/* Wait for the MMC_BOOT_MCI_DATA_CTL write to go through. */
	mmc_mclk_reg_wr_delay(ctrlr);

	/* Write the transfer data to SDCC3 FIFO */
	while (1) {
		mmc_status = readl(MMC_BOOT_MCI_STATUS(mmc_host->mci_base));

		/* Bytes left to write */
		count = data_len - mmc_count;

		/* Break if whole data is transferred */
		if (!count)
			break;

		/*
		 * Write half FIFO or less (remaining) words in MCI_FIFO as
		 * long as either TX_FIFO_EMPTY or TX_FIFO_HFULL bits of
		 * MCI_STATUS register are set.
		 */
		if ((mmc_status & MMC_BOOT_MCI_STAT_TX_FIFO_EMPTY) ||
			(mmc_status & MMC_BOOT_MCI_STAT_TX_FIFO_HFULL)) {
			/* Write minimum of half FIFO and remaining words */
			unsigned sz = ((count >> 2) >  MMC_BOOT_MCI_HFIFO_COUNT)
				? MMC_BOOT_MCI_HFIFO_COUNT : (count >> 2);

			for (int i = 0; i < sz; i++) {
				writel(*mmc_ptr,
				       MMC_BOOT_MCI_FIFO(mmc_host->mci_base));
				mmc_ptr++;
				/* increase mmc_count by word size */
				mmc_count += sizeof(uint32_t);
			}
		}
	}

	do {
		mmc_status = readl(MMC_BOOT_MCI_STATUS(mmc_host->mci_base));
		mmc_ret = mmc_boot_data_status_decode(mmc_status);
		if (mmc_ret != MMC_BOOT_E_SUCCESS)
			break;
	} while (!(mmc_status & MMC_BOOT_MCI_STAT_DATA_END));

	return mmc_ret;

}

static void mmc_boot_setup_data_transfer(MmcCtrlr *ctrlr, MmcData *data)
{
	QcomMmcHost *mmc_host = container_of(ctrlr, QcomMmcHost, mmc);
	/* Set the FLOW_ENA bit of MCI_CLK register to 1 */
	uint32_t mmc_reg = readl(MMC_BOOT_MCI_CLK(mmc_host->mci_base));

	mmc_reg |= MMC_BOOT_MCI_CLK_ENA_FLOW;
	writel(mmc_reg, MMC_BOOT_MCI_CLK(mmc_host->mci_base));
	mmc_mclk_reg_wr_delay(ctrlr);

	/*
	 * If Data Mover is used for data transfer then prepare Command
	 * List Entry and enable the Data mover to work with SDCC2.
	 * Write data timeout period to MCI_DATA_TIMER register.
	 * Data timeout period should be in card bus clock periods
	 */
	mmc_reg = 0xFFFFFFFF;
	writel(mmc_reg, MMC_BOOT_MCI_DATA_TIMER(mmc_host->mci_base));

	/*
	 * Write the total size of the transfer data to MCI_DATA_LENGTH
	 * register. For block xfer it must be multiple of the block
	 * size.
	 */
	writel(data->blocks * data->blocksize,
	       MMC_BOOT_MCI_DATA_LENGTH(mmc_host->mci_base));

	if (data->flags & MMC_DATA_READ) {
		uint32_t mmc_reg;

		/*
		 * Set appropriate fields and write the MCI_DATA_CTL register.
		 * Set ENABLE bit to enable the data transfer.
		 */
		mmc_reg = MMC_BOOT_MCI_DATA_ENABLE;
		/* Set DIRECTION bit to enable transfer from card to host */
		mmc_reg |= MMC_BOOT_MCI_DATA_DIR;
		/*
		 * Clear MODE bit to enable block oriented data transfer. For
		 * MMC cards only, if stream data transfer mode is desired,
		 * set MODE bit.
		 * If DMA is to be used, Set DM_ENABLE bit.
		 * Write size of block to be used during the data transfer to
		 * BLOCKSIZE field
		 */
		mmc_reg |= (data->blocksize << MMC_BOOT_MCI_BLKSIZE_POS);
		writel(mmc_reg, MMC_BOOT_MCI_DATA_CTL(mmc_host->mci_base));

		/* Wait for the MMC_BOOT_MCI_DATA_CTL write to go through. */
		mmc_mclk_reg_wr_delay(ctrlr);
	}
}

/*
 * Check to ensure that there is no alignment or data length errors.
 */
static int mmc_boot_check_read_data(MmcCommand *cmd)
{
	if (cmd->response[0] & MMC_BOOT_R1_BLOCK_LEN_ERR)
		return MMC_UNUSABLE_ERR;

	/* Misaligned address not matching block length. */
	if (cmd->response[0] & MMC_BOOT_R1_ADDR_ERR)
		return MMC_UNUSABLE_ERR;

	return MMC_BOOT_E_SUCCESS;
}

/*
 * Wait for command to be executed.
 */
static int mmc_boot_wait_cmd_exec(MmcCtrlr *ctrlr,
				 MmcCommand *cmd, MmcData *data)
{
	uint32_t mmc_status;
	uint32_t mmc_resp;
	int mmc_return = MMC_BOOT_E_SUCCESS;
	unsigned cmd_index;
	QcomMmcHost *mmc_host = container_of(ctrlr, QcomMmcHost, mmc);
	int i;

	cmd_index = cmd->cmdidx;
	while (1) {
		/* 3a. Read MCI_STATUS register */
		wait_on_reg(MMC_BOOT_MCI_STATUS(mmc_host->mci_base),
			    MMC_BOOT_MCI_STAT_CMD_ACTIVE,
			    0, NULL);

		mmc_status = readl(MMC_BOOT_MCI_STATUS(mmc_host->mci_base));

		/*
		 * 3b. CMD_SENT bit supposed to be set to 1 only after
		 * CMD0 is sent - no response required.
		 */
		if ((cmd->resp_type == MMC_RSP_NONE) &&
		    (mmc_status & MMC_BOOT_MCI_STAT_CMD_SENT)) {
			break;
		}

		/*
		 * 3c. If CMD_TIMEOUT bit is set then no response was
		 * received.
		 */
		if (mmc_status & MMC_BOOT_MCI_STAT_CMD_TIMEOUT) {
			mmc_return = MMC_TIMEOUT;
			break;
		}
		/*
		 * 3d. If CMD_RESPONSE_END bit is set to 1 then command's
		 * response was received and CRC check passed Special case for
		 * ACMD41: it seems to always fail CRC even if the response is
		 * valid.
		 */
		if ((mmc_status & MMC_BOOT_MCI_STAT_CMD_RESP_END)
			 || (cmd_index == MMC_CMD_SEND_OP_COND)
			 || (cmd_index == SD_CMD_SEND_IF_COND)) {
			/*
			 * 3i. Read MCI_RESP_CMD register to verify
			 * that response index is equal to command index.
			 */
			mmc_resp = readl
				(MMC_BOOT_MCI_RESP_CMD(mmc_host->mci_base)) &
				0x3F;

			/*
			 * However, long response does not contain the command
			 * index field. In that case, response index field must
			 * be set to 111111b (0x3F).
			 */
			if ((mmc_resp == cmd_index) ||
			    (cmd->resp_type == MMC_RSP_R2 ||
			     cmd->resp_type == MMC_RSP_R3 ||
			     cmd->resp_type == MMC_RSP_R6 ||
			     cmd->resp_type == MMC_RSP_R7)) {
				/*
				 * 3j. If resp index is equal to cmd index,
				 * read command resp from MCI_RESPn registers
				 * - MCI_RESP0/1/2/3 for CMD2/9/10 - MCI_RESP0
				 * for all other registers.
				 */
				if (cmd->resp_type == MMC_RSP_R2) {
					/*
					 * Matching the words to be in
					 * framework order: Last word first.
					 */
					for (i = 0; i < 4; i++) {
						cmd->response[i] =
						    readl(MMC_BOOT_MCI_RESP_0
						    (mmc_host->mci_base)
						    + (i * 4));
					}
				} else {
					cmd->response[0] =
					    readl(MMC_BOOT_MCI_RESP_0
					    (mmc_host->mci_base));
				}
			} else {
				/* command index mis-match. */
				mmc_return = MMC_COMM_ERR;
			}

			break;
		}

		/*
		 * 3e. If CMD_CRC_FAIL bit is set to 1 then cmd's response was
		 * recvd,but CRC check failed.
		 */
		if ((mmc_status & MMC_BOOT_MCI_STAT_CMD_CRC_FAIL)) {
			if (cmd_index == SD_CMD_APP_SEND_OP_COND)
				cmd->response[0] =
				readl
				(MMC_BOOT_MCI_RESP_0(mmc_host->mci_base));
			else
				mmc_return = MMC_COMM_ERR;
			break;
		}
	}

	return mmc_return;
}

/*
 * Sends specified command to a card and waits for a response.
 */
static int mmc_boot_send_command(MmcCtrlr *ctrlr,
				 MmcCommand *cmd, MmcData *data)
{
	uint32_t mmc_cmd;
	int mmc_return;
	uint32_t data_transfer = 0;
	uint32_t prg_enabled = 0;
	QcomMmcHost *mmc_host = container_of(ctrlr, QcomMmcHost, mmc);

	/* basic check */
	if (cmd == NULL)
		return MMC_UNUSABLE_ERR;

	/* data transfer */
	if (data != NULL)
		if (data->flags == MMC_DATA_READ ||
			data->flags == MMC_DATA_WRITE) {
			mmc_boot_setup_data_transfer(ctrlr, data);
			data_transfer = 1;
		}

	/* 1. Write command argument to MMC_BOOT_MCI_ARGUMENT register */
	writel(cmd->cmdarg, MMC_BOOT_MCI_ARGUMENT(mmc_host->mci_base));

	/*
	 * 2. Set appropriate fields and write MMC_BOOT_MCI_CMD.
	 * 2a. Write command index in CMD_INDEX field.
	 */
	mmc_cmd = cmd->cmdidx;
	/*
	 * 2b. Set RESPONSE bit for all cmds except CMD0. And dont set
	 * RESPONSE bit for commands with no response.
	 */
	if (cmd->resp_type != MMC_RSP_NONE)
		mmc_cmd |= MMC_BOOT_MCI_CMD_RESPONSE;

	/* 2c. Set LONGRESP bit for CMD2, CMD9 and CMD10. */
	if (cmd->resp_type == MMC_RSP_R2)
		mmc_cmd |= MMC_BOOT_MCI_CMD_LONGRSP;

	/*
	 * 2d. Set INTERRUPT bit to disable command timeout.
	 * 2e. Set PENDING bit for CMD12 in the beginning of stream mode data
	 * transfer

	if (cmd->xfer_mode == MMC_BOOT_XFER_MODE_STREAM) {
		mmc_cmd |= MMC_BOOT_MCI_CMD_PENDING;
	}
	*/

	/* 2f. Set ENABLE bit. */
	mmc_cmd |= MMC_BOOT_MCI_CMD_ENABLE;

	/* 2g. Set PROG_ENA bit */
	if (cmd->resp_type == MMC_RSP_R1b ||
		cmd->cmdidx == MMC_CMD_SEND_STATUS) {
		prg_enabled = 1;
		mmc_cmd |= MMC_BOOT_MCI_CMD_PROG_ENA;
	}

	/*
	 * 2h. Set MCIABORT bit for CMD12 when working with SDIO card. 2i.
	 * Set CCS_ENABLE bit for CMD61 when Command Completion Signal of
	 * CE-ATA device is enabled.
	 * 2j. clear all static status bits.
	 */
	writel(MMC_BOOT_MCI_STATIC_STATUS,
	       MMC_BOOT_MCI_CLEAR(mmc_host->mci_base));

	/* 2k. Write to MMC_BOOT_MCI_CMD register. */
	writel(mmc_cmd, MMC_BOOT_MCI_CMD(mmc_host->mci_base));

	/* Wait for the MMC_BOOT_MCI_CMD write to go through. */
	mmc_mclk_reg_wr_delay(ctrlr);

	mmc_trace("Command sent: CMD%d MCI_CMD_REG:%x MCI_ARG:%x\n",
		  cmd->cmdidx, mmc_cmd, cmd->cmdarg);

	/*
	 * 3. Wait for interrupt or poll on the following bits of MCI_STATUS
	 * register.
	 */
	mmc_return = mmc_boot_wait_cmd_exec(ctrlr, cmd, data);

	if (mmc_return) {
		/* Timeout is a valid condition for some commands. */
		if  (mmc_return != MMC_TIMEOUT)
			mmc_error("Command execution failed: %d\n", mmc_return);
		return mmc_return;
	}

	if (prg_enabled) {
		/*
		 * Wait for interrupt or poll on PROG_DONE bit of MCI_STATUS
		 * register.
		 * PROG_DONE bit set to 1 it means that the card finished its
		 * programming and stopped driving DAT0 line to 0.
		 */
		wait_on_reg(MMC_BOOT_MCI_STATUS(mmc_host->mci_base),
			    MMC_BOOT_MCI_STAT_PROG_DONE,
			    MMC_BOOT_MCI_STAT_PROG_DONE,
			    NULL);
	}

	if (data_transfer) {
		if (data->flags & MMC_DATA_READ) {
			mmc_return = mmc_boot_check_read_data(cmd);
			if (mmc_return) {
				mmc_error("Alignment/data length errors:%d\n",
					mmc_return);
				return mmc_return;
			}
		}

		/* Read the transfer data from SDCC FIFO. */
		if (data->flags == MMC_DATA_READ)
			mmc_return = mmc_boot_fifo_read(ctrlr, data);
		else
			mmc_return = mmc_boot_fifo_write(ctrlr, data);

		if (mmc_return != MMC_BOOT_E_SUCCESS) {
			mmc_error("RXFIFO ERROR:%d\n", mmc_return);
			return mmc_return;
		}

		/* Reset DPSM. */
		writel(0, MMC_BOOT_MCI_DATA_CTL(mmc_host->mci_base));

		/* Wait for the MMC_BOOT_MCI_DATA_CTL write to go through. */
		mmc_mclk_reg_wr_delay(ctrlr);
	}

	/* 2k. Write to MMC_BOOT_MCI_CMD register. */
	writel(0, MMC_BOOT_MCI_CMD(mmc_host->mci_base));

	/* Wait for the MMC_BOOT_MCI_CMD write to go through. */
	mmc_mclk_reg_wr_delay(ctrlr);

	return MMC_BOOT_E_SUCCESS;
}

static void mmc_boot_set_ios(struct MmcCtrlr *ctrlr)
{
	int mmc_ret = MMC_BOOT_E_SUCCESS;

	/* Clock frequency should not exceed 400KHz in identification mode. */
	clock_config_mmc(ctrlr, ctrlr->bus_hz);

	mmc_ret = mmc_boot_set_bus_width(ctrlr, ctrlr->bus_width);
	if (mmc_ret != MMC_BOOT_E_SUCCESS)
		mmc_error("Set bus width error %d\n", mmc_ret);
}

/*
 * Initialize host structure, set and enable clock-rate and power mode.
 */
static int mmc_boot_init(QcomMmcHost *host)
{
	uint32_t mmc_pwr;

	/* Initialize any clocks needed for SDC controller */
	clock_init_mmc(host->instance);

	/* Initialize the GPIO's required for the board. */
	board_mmc_gpio_config();

	/* Save the version of the mmc controller. */
	host->mmc_cont_version = readl(MMC_BOOT_MCI_VERSION(host->mci_base));

	/* Setup initial freq to 400KHz. */
	clock_config_mmc(&(host->mmc), MMC_CLK_400KHZ);

	/* set power mode. */
	mmc_pwr = (MMC_BOOT_MCI_PWR_ON | MMC_BOOT_MCI_PWR_UP);
	writel(mmc_pwr, MMC_BOOT_MCI_POWER(host->mci_base));

	/* Wait for the MMC_BOOT_MCI_POWER write to go through. */
	mmc_mclk_reg_wr_delay(&(host->mmc));

	/* Clear interrupt in mci status. */
	writel(0xFFFFFFFF, MMC_BOOT_MCI_CLEAR(host->mci_base));

	return MMC_BOOT_E_SUCCESS;
}

/*
 * Entry point to MMC boot process.
 */
static int qcom_mmc_update(BlockDevCtrlrOps *me)
{
	QcomMmcHost *mmc_host = container_of(me, QcomMmcHost, mmc.ctrlr.ops);
	int mmc_ret = MMC_BOOT_E_SUCCESS;

	/* Initialize necessary data structure and enable/set clock and power */
	mmc_trace("Initializing MMC host data structure and clock!\n");
	mmc_ret = mmc_boot_init(mmc_host);
	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
		mmc_error("MMC Boot: Error Initializing MMC Card!!!\n");
		return -1;
	}

	if (mmc_setup_media(&(mmc_host->mmc)))
		return -1;

	mmc_host->mmc.media->dev.name = "qcom_mmc";
	mmc_host->mmc.media->dev.removable = 0;
	mmc_host->mmc.media->dev.ops.read = &block_mmc_read;
	mmc_host->mmc.media->dev.ops.write = &block_mmc_write;
	mmc_host->mmc.media->dev.ops.new_stream = &new_simple_stream;

	list_insert_after(&(mmc_host->mmc.media->dev.list_node),
				  &fixed_block_devices);
		mmc_host->mmc.ctrlr.need_update = 0;

	return 0;
}

QcomMmcHost *new_qcom_mmc_host(unsigned slot, uint32_t base, int bus_width)
{
	QcomMmcHost *new_host = xzalloc(sizeof(QcomMmcHost));

	if (new_host) {
		new_host->instance = slot;
		new_host->mci_base = (uint8_t *)base;

		new_host->mmc.ctrlr.ops.update = qcom_mmc_update;
		new_host->mmc.ctrlr.need_update = 1;
		new_host->mmc.set_ios = &mmc_boot_set_ios;
		new_host->mmc.send_cmd = mmc_boot_send_command;
		new_host->mmc.bus_hz = MMC_CLK_400KHZ;
		new_host->mmc.f_max = MMC_CLK_48MHZ;
		new_host->mmc.f_min = MMC_CLK_400KHZ;
		new_host->mmc.hardcoded_voltage =
			MMC_BOOT_OCR_27_36 | MMC_BOOT_OCR_SEC_MODE;
		new_host->mmc.voltages = MMC_BOOT_OCR_27_36;
		/* Some controllers use 16-bit regs.*/
		new_host->mmc.b_max = 0xFFFF;
		new_host->mmc.bus_width = bus_width;
		new_host->mmc.bus_hz = new_host->mmc.f_min;
		new_host->mmc.caps = (bus_width == 8) ?
					MMC_MODE_8BIT : MMC_MODE_4BIT;
		new_host->mmc.caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz |
			MMC_MODE_HC;
	}

	return new_host;
}
