lk: msm: Fix files to have uniform coding style

No functional changes, just style code formatting style changes here.

Change-Id: Id3f1995ef97765b393c5c26259011c9ce1321106
diff --git a/platform/msm_shared/mmc.c b/platform/msm_shared/mmc.c
index 3e10002..b1fc977 100644
--- a/platform/msm_shared/mmc.c
+++ b/platform/msm_shared/mmc.c
@@ -1,2957 +1,2832 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.

-

- * Redistribution and use in source and binary forms, with or without

- * modification, are permitted provided that the following conditions are

- * met:

- *   * Redistributions of source code must retain the above copyright

- *     notice, this list of conditions and the following disclaimer.

- *   * 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.

- *   * Neither the name of Code Aurora Forum, Inc. nor the names of its

- *     contributors may be used to endorse or promote products derived

- *     from this software without specific prior written permission.

- *

- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED

- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT

- * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER 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 <debug.h>

-#include <reg.h>

-#include "mmc.h"

-#include <partition_parser.h>

-#include <platform/iomap.h>

-#include <platform/timer.h>

-

-#if MMC_BOOT_ADM

-#include "adm.h"

-#endif

-

-#ifndef NULL

-#define NULL        0

-#endif

-

-#define MMC_BOOT_DATA_READ     0

-#define MMC_BOOT_DATA_WRITE    1

-

-

-static unsigned int mmc_boot_fifo_data_transfer(unsigned int* data_ptr,

-                                                unsigned int  data_len,

-                                                unsigned char direction);

-

-static unsigned int mmc_boot_fifo_read(unsigned int* data_ptr,

-                                       unsigned int data_len);

-

-static unsigned int mmc_boot_fifo_write(unsigned int* data_ptr,

-                                        unsigned int data_len);

-

-#define ROUND_TO_PAGE(x,y) (((x) + (y)) & (~(y)))

-

-/* data access time unit in ns */

-static const unsigned int taac_unit[] =

-{ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000 };

-/* data access time value x 10 */

-static const unsigned int taac_value[] =

-{ 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 };

-

-/* data transfer rate in kbit/s */

-static const unsigned int xfer_rate_unit[] =

-{ 100, 1000, 10000, 100000, 0, 0, 0, 0 };

-/* data transfer rate value x 10*/

-static const unsigned int xfer_rate_value[] =

-{ 0, 10, 12, 13, 15, 20, 26, 30, 35, 40, 45, 52, 55, 60, 70, 80 };

-

-

-unsigned char mmc_slot = 0;

-unsigned int mmc_boot_mci_base = 0;

-

-static unsigned char ext_csd_buf[512];

-static unsigned char wp_status_buf[8];

-

-int mmc_clock_enable_disable(unsigned id, unsigned enable);

-int mmc_clock_get_rate(unsigned id);

-int mmc_clock_set_rate(unsigned id, unsigned rate);

-

-struct mmc_boot_host mmc_host;

-struct mmc_boot_card mmc_card;

-

-static unsigned int mmc_wp(unsigned int addr, unsigned int size,

-                           unsigned char set_clear_wp);

-static unsigned int mmc_boot_send_ext_cmd (struct mmc_boot_card* card,

-                                           unsigned char* buf);

-static unsigned int mmc_boot_read_reg(struct mmc_boot_card *card,

-                                      unsigned int data_len,

-                                      unsigned int command, unsigned int addr,

-                                      unsigned int *out);

-

-unsigned int SWAP_ENDIAN(unsigned int val)

-{

-    return ((val & 0xFF) << 24) |

-        (((val >> 8) & 0xFF) << 16) |

-        (((val >> 16) & 0xFF) << 8) |

-        (val >> 24);

-}

-

-

-/* Sets a timeout for read operation.

- */

-static unsigned int mmc_boot_set_read_timeout( struct mmc_boot_host* host,

-        struct mmc_boot_card* card )

-{

-    unsigned int timeout_ns = 0;

-

-    if( ( host == NULL ) || ( card == NULL ) )

-    {

-        return MMC_BOOT_E_INVAL;

-    }

-

-    if( (card->type == MMC_BOOT_TYPE_MMCHC) || (card->type == MMC_BOOT_TYPE_SDHC) )

-    {

-        card->rd_timeout_ns = 100000000;

-    }

-    else if( (card->type == MMC_BOOT_TYPE_STD_SD) || (card->type == MMC_BOOT_TYPE_STD_MMC) )

-    {

-        timeout_ns = 10 * ( (card->csd.taac_ns ) +

-                ( card->csd.nsac_clk_cycle / (host->mclk_rate/1000000000)));

-        card->rd_timeout_ns = timeout_ns;

-    }

-    else

-    {

-        return MMC_BOOT_E_NOT_SUPPORTED;

-    }

-

-    dprintf(SPEW, " Read timeout set: %d ns\n", card->rd_timeout_ns );

-

-    return MMC_BOOT_E_SUCCESS;

-}

-

-/* Sets a timeout for write operation.

- */

-static unsigned int mmc_boot_set_write_timeout( struct mmc_boot_host* host,

-        struct mmc_boot_card* card )

-{

-    unsigned int timeout_ns = 0;

-

-    if( ( host == NULL ) || ( card == NULL ) )

-    {

-        return MMC_BOOT_E_INVAL;

-    }

-

-    if( (card->type == MMC_BOOT_TYPE_MMCHC) || (card->type == MMC_BOOT_TYPE_SDHC) )

-    {

-        card->wr_timeout_ns = 100000000;

-    }

-    else if( card->type == MMC_BOOT_TYPE_STD_SD || (card->type == MMC_BOOT_TYPE_STD_MMC) )

-    {

-        timeout_ns = 10 * ( (  card->csd.taac_ns ) +

-                ( card->csd.nsac_clk_cycle / ( host->mclk_rate/1000000000 ) ) );

-        timeout_ns = timeout_ns << card->csd.r2w_factor;

-        card->wr_timeout_ns = timeout_ns;

-    }

-    else

-    {

-        return MMC_BOOT_E_NOT_SUPPORTED;

-    }

-

-    dprintf(SPEW, " Write timeout set: %d ns\n", card->wr_timeout_ns );

-

-    return MMC_BOOT_E_SUCCESS;

-}

-

-

-/*

- * Decodes CSD response received from the card. Note that we have defined only

- * few of the CSD elements in csd structure. We'll only decode those values.

- */

-static unsigned int mmc_boot_decode_and_save_csd( struct mmc_boot_card* card,

-        unsigned int* raw_csd )

-{

-    unsigned int mmc_sizeof = 0;

-    unsigned int mmc_unit = 0;

-    unsigned int mmc_value = 0;

-    unsigned int mmc_temp = 0;

-

-    struct mmc_boot_csd mmc_csd;

-

-    if( ( card == NULL ) || ( raw_csd == NULL ) )

-    {

-        return MMC_BOOT_E_INVAL;

-    }

-

-    mmc_sizeof = sizeof(unsigned int) * 8;

-

-    mmc_csd.cmmc_structure = UNPACK_BITS( raw_csd, 126, 2, mmc_sizeof );

-

-    if( (card->type == MMC_BOOT_TYPE_SDHC) ||  (card->type == MMC_BOOT_TYPE_STD_SD))

-    {

-        /* Parse CSD according to SD card spec. */

-

-        /* CSD register is little bit differnet for CSD version 2.0 High Capacity

-         * and CSD version 1.0/2.0 Standard memory cards. In Version 2.0 some of

-         * the fields have fixed values and it's not necessary for host to refer

-         * these fields in CSD sent by card */

-

-        if( mmc_csd.cmmc_structure == 1)

-        {

-            /* CSD Version 2.0 */

-            mmc_csd.card_cmd_class = UNPACK_BITS( raw_csd, 84, 12, mmc_sizeof );

-            mmc_csd.write_blk_len = 512; /* Fixed value is 9 = 2^9 = 512 */

-            mmc_csd.read_blk_len = 512;  /* Fixed value is 9 = 512 */

-            mmc_csd.r2w_factor = 0x2;    /* Fixed value: 010b */

-            mmc_csd.c_size_mult = 0;     /* not there in version 2.0 */

-            mmc_csd.c_size = UNPACK_BITS( raw_csd, 48, 22, mmc_sizeof );

-            mmc_csd.nsac_clk_cycle = UNPACK_BITS( raw_csd, 104, 8, mmc_sizeof) * 100;

-

-//TODO: Investigate the nsac and taac. Spec suggests not using this for timeouts.

-

-            mmc_unit = UNPACK_BITS( raw_csd, 112, 3, mmc_sizeof );

-            mmc_value = UNPACK_BITS( raw_csd, 115, 4, mmc_sizeof );

-            mmc_csd.taac_ns = ( taac_value[mmc_value] * taac_unit[mmc_unit]) / 10;

-

-            mmc_csd.erase_blk_len = 1;

-            mmc_csd.read_blk_misalign = 0;

-            mmc_csd.write_blk_misalign = 0;

-            mmc_csd.read_blk_partial = 0;

-            mmc_csd.write_blk_partial = 0;

-

-            mmc_unit = UNPACK_BITS( raw_csd, 96, 3, mmc_sizeof );

-            mmc_value = UNPACK_BITS( raw_csd, 99, 4, mmc_sizeof );

-            mmc_csd.tran_speed = ( xfer_rate_value[mmc_value] * xfer_rate_unit[mmc_unit]) / 10;

-

-            mmc_csd.wp_grp_size = 0x0;

-            mmc_csd.wp_grp_enable = 0x0;

-            mmc_csd.perm_wp = UNPACK_BITS( raw_csd, 13, 1, mmc_sizeof );

-            mmc_csd.temp_wp = UNPACK_BITS( raw_csd, 12, 1, mmc_sizeof );

-

-            /* Calculate the card capcity */

-            card->capacity = ( 1 + mmc_csd.c_size ) * 512 * 1024;

-        }

-        else

-        {

-            /* CSD Version 1.0 */

-            mmc_csd.card_cmd_class = UNPACK_BITS( raw_csd, 84, 12, mmc_sizeof );

-

-            mmc_temp = UNPACK_BITS( raw_csd, 22, 4, mmc_sizeof );

-            mmc_csd.write_blk_len = ( mmc_temp > 8 && mmc_temp < 12 )? ( 1 << mmc_temp ) : 512;

-

-            mmc_temp = UNPACK_BITS( raw_csd, 80, 4, mmc_sizeof );

-            mmc_csd.read_blk_len = ( mmc_temp > 8 && mmc_temp < 12 )? ( 1 << mmc_temp ) : 512;

-

-            mmc_unit = UNPACK_BITS( raw_csd, 112, 3, mmc_sizeof );

-            mmc_value = UNPACK_BITS( raw_csd, 115, 4, mmc_sizeof );

-            mmc_csd.taac_ns = ( taac_value[mmc_value] * taac_unit[mmc_unit]) / 10;

-

-            mmc_unit = UNPACK_BITS( raw_csd, 96, 3, mmc_sizeof );

-            mmc_value = UNPACK_BITS( raw_csd, 99, 4, mmc_sizeof );

-            mmc_csd.tran_speed = ( xfer_rate_value[mmc_value] * xfer_rate_unit[mmc_unit]) / 10;

-

-            mmc_csd.nsac_clk_cycle = UNPACK_BITS( raw_csd, 104, 8, mmc_sizeof ) * 100;

-

-            mmc_csd.r2w_factor = UNPACK_BITS( raw_csd, 26, 3, mmc_sizeof );

-            mmc_csd.sector_size = UNPACK_BITS( raw_csd, 39, 7, mmc_sizeof ) + 1;

-

-            mmc_csd.erase_blk_len = UNPACK_BITS( raw_csd, 46, 1, mmc_sizeof );

-            mmc_csd.read_blk_misalign = UNPACK_BITS( raw_csd, 77, 1, mmc_sizeof );

-            mmc_csd.write_blk_misalign = UNPACK_BITS( raw_csd, 78, 1, mmc_sizeof );

-            mmc_csd.read_blk_partial = UNPACK_BITS( raw_csd, 79, 1, mmc_sizeof );

-            mmc_csd.write_blk_partial = UNPACK_BITS( raw_csd, 21, 1, mmc_sizeof );

-

-            mmc_csd.c_size_mult = UNPACK_BITS( raw_csd, 47, 3, mmc_sizeof );

-            mmc_csd.c_size = UNPACK_BITS( raw_csd, 62, 12, mmc_sizeof );

-            mmc_csd.wp_grp_size = UNPACK_BITS( raw_csd, 32, 7, mmc_sizeof );

-            mmc_csd.wp_grp_enable = UNPACK_BITS( raw_csd, 31, 1, mmc_sizeof );

-            mmc_csd.perm_wp = UNPACK_BITS( raw_csd, 13, 1, mmc_sizeof );

-            mmc_csd.temp_wp = UNPACK_BITS( raw_csd, 12, 1, mmc_sizeof );

-

-            /* Calculate the card capacity */

-            mmc_temp = ( 1 << ( mmc_csd.c_size_mult + 2 ) ) * ( mmc_csd.c_size + 1 );

-            card->capacity = mmc_temp * mmc_csd.read_blk_len;

-        }

-    }

-    else

-    {

-        /* Parse CSD according to MMC card spec. */

-        mmc_csd.spec_vers      = UNPACK_BITS( raw_csd, 122, 4, mmc_sizeof );

-        mmc_csd.card_cmd_class = UNPACK_BITS( raw_csd, 84, 12, mmc_sizeof );

-        mmc_csd.write_blk_len  = 1 << UNPACK_BITS( raw_csd, 22, 4, mmc_sizeof );

-        mmc_csd.read_blk_len   = 1 << UNPACK_BITS( raw_csd, 80, 4, mmc_sizeof );

-        mmc_csd.r2w_factor     = UNPACK_BITS( raw_csd, 26, 3, mmc_sizeof );

-        mmc_csd.c_size_mult    = UNPACK_BITS( raw_csd, 47, 3, mmc_sizeof );

-        mmc_csd.c_size         = UNPACK_BITS( raw_csd, 62, 12, mmc_sizeof );

-        mmc_csd.nsac_clk_cycle = UNPACK_BITS( raw_csd, 104, 8, mmc_sizeof) * 100;

-

-        mmc_unit = UNPACK_BITS( raw_csd, 112, 3, mmc_sizeof );

-        mmc_value = UNPACK_BITS( raw_csd, 115, 4, mmc_sizeof );

-        mmc_csd.taac_ns = ( taac_value[mmc_value] * taac_unit[mmc_unit]) / 10;

-

-        mmc_csd.read_blk_misalign  = UNPACK_BITS( raw_csd, 77, 1, mmc_sizeof );

-        mmc_csd.write_blk_misalign = UNPACK_BITS( raw_csd, 78, 1, mmc_sizeof );

-        mmc_csd.read_blk_partial   = UNPACK_BITS( raw_csd, 79, 1, mmc_sizeof );

-        mmc_csd.write_blk_partial  = UNPACK_BITS( raw_csd, 21, 1, mmc_sizeof );

-        mmc_csd.tran_speed = 0x00; /* Ignore -- no use of this value. */

-

-        mmc_csd.erase_grp_size = UNPACK_BITS( raw_csd, 42, 5, mmc_sizeof );

-        mmc_csd.erase_grp_mult = UNPACK_BITS( raw_csd, 37, 5, mmc_sizeof );

-        mmc_csd.wp_grp_size = UNPACK_BITS( raw_csd, 32, 5, mmc_sizeof );

-        mmc_csd.wp_grp_enable = UNPACK_BITS( raw_csd, 31, 1, mmc_sizeof );

-        mmc_csd.perm_wp = UNPACK_BITS( raw_csd, 13, 1, mmc_sizeof );

-        mmc_csd.temp_wp = UNPACK_BITS( raw_csd, 12, 1, mmc_sizeof );

-

-        /* Calculate the card capcity */

-        if(mmc_csd.c_size != 0xFFF)

-        {

-                /* For cards less than or equal to 2GB */

-                mmc_temp = ( 1 << ( mmc_csd.c_size_mult + 2 ) ) * ( mmc_csd.c_size + 1 );

-                card->capacity = mmc_temp * mmc_csd.read_blk_len;

-        }

-        else

-        {

-                /* For cards greater than 2GB, Ext CSD register's SEC_COUNT

-                 * is used to calculate the size.

-                 */

-                unsigned long long sec_count;

-

-                sec_count = (ext_csd_buf[215] << 24) |

-                            (ext_csd_buf[214] << 16) |

-                            (ext_csd_buf[213] << 8)  |

-                             ext_csd_buf[212];

-

-                card->capacity = sec_count * 512;

-        }

-    }

-

-

-    /* save the information in card structure */

-    memcpy( (struct mmc_boot_csd *)&card->csd, (struct mmc_boot_csd *)&mmc_csd,

-            sizeof(struct mmc_boot_csd) );

-

-    dprintf(SPEW,  "Decoded CSD fields:\n" );

-    dprintf(SPEW,  "cmmc_structure: %d\n", mmc_csd.cmmc_structure );

-    dprintf(SPEW, "card_cmd_class: %x\n", mmc_csd.card_cmd_class );

-    dprintf(SPEW, "write_blk_len: %d\n", mmc_csd.write_blk_len );

-    dprintf(SPEW, "read_blk_len: %d\n", mmc_csd.read_blk_len );

-    dprintf(SPEW, "r2w_factor: %d\n", mmc_csd.r2w_factor );

-    dprintf(SPEW, "sector_size: %d\n", mmc_csd.sector_size );

-    dprintf(SPEW, "c_size_mult:%d\n", mmc_csd.c_size_mult );

-    dprintf(SPEW, "c_size: %d\n", mmc_csd.c_size );

-    dprintf(SPEW, "nsac_clk_cycle: %d\n", mmc_csd.nsac_clk_cycle );

-    dprintf(SPEW, "taac_ns: %d\n", mmc_csd.taac_ns );

-    dprintf(SPEW, "tran_speed: %d kbps\n", mmc_csd.tran_speed );

-    dprintf(SPEW, "erase_blk_len: %d\n", mmc_csd.erase_blk_len );

-    dprintf(SPEW, "read_blk_misalign: %d\n", mmc_csd.read_blk_misalign );

-    dprintf(SPEW, "write_blk_misalign: %d\n", mmc_csd.write_blk_misalign );

-    dprintf(SPEW, "read_blk_partial: %d\n", mmc_csd.read_blk_partial );

-    dprintf(SPEW, "write_blk_partial: %d\n", mmc_csd.write_blk_partial );

-    dprintf(SPEW, "Card Capacity: %llu Bytes\n", card->capacity );

-

-    return MMC_BOOT_E_SUCCESS;

-}

-

-/*

- * Decode CID sent by the card.

- */

-static unsigned int mmc_boot_decode_and_save_cid( struct mmc_boot_card* card,

-        unsigned int* raw_cid )

-{

-    struct mmc_boot_cid mmc_cid;

-    unsigned int mmc_sizeof = 0;

-    int i = 0;

-

-    if( ( card == NULL ) || ( raw_cid == NULL ) )

-    {

-        return MMC_BOOT_E_INVAL;

-    }

-

-    mmc_sizeof = sizeof( unsigned int ) * 8;

-

-    if( (card->type == MMC_BOOT_TYPE_SDHC) ||  (card->type == MMC_BOOT_TYPE_STD_SD))

-    {

-        mmc_cid.mid = UNPACK_BITS( raw_cid, 120, 8, mmc_sizeof );

-        mmc_cid.oid = UNPACK_BITS( raw_cid, 104, 16, mmc_sizeof );

-

-        for( i = 0; i < 5; i++ )

-        {

-            mmc_cid.pnm[i] = (unsigned char) UNPACK_BITS(raw_cid, \

-                                (104 - 8 * (i+1)), 8, mmc_sizeof );

-        }

-        mmc_cid.pnm[5] = 0;

-        mmc_cid.pnm[6] = 0;

-

-        mmc_cid.prv = UNPACK_BITS( raw_cid, 56, 8, mmc_sizeof );

-        mmc_cid.psn = UNPACK_BITS( raw_cid, 24, 32, mmc_sizeof );

-        mmc_cid.month = UNPACK_BITS( raw_cid, 8, 4, mmc_sizeof );

-        mmc_cid.year = UNPACK_BITS( raw_cid, 12, 8, mmc_sizeof );

-        mmc_cid.year += 2000;

-    }

-    else

-    {

-        mmc_cid.mid = UNPACK_BITS( raw_cid, 120, 8, mmc_sizeof );

-        mmc_cid.oid = UNPACK_BITS( raw_cid, 104, 16, mmc_sizeof );

-

-        for( i = 0; i < 6; i++ )

-        {

-            mmc_cid.pnm[i] = (unsigned char) UNPACK_BITS(raw_cid, \

-                                (104 - 8 * (i+1)), 8, mmc_sizeof );

-        }

-        mmc_cid.pnm[6] = 0;

-

-        mmc_cid.prv = UNPACK_BITS( raw_cid, 48, 8, mmc_sizeof );

-        mmc_cid.psn = UNPACK_BITS( raw_cid, 16, 32, mmc_sizeof );

-        mmc_cid.month = UNPACK_BITS( raw_cid, 8, 4, mmc_sizeof );

-        mmc_cid.year = UNPACK_BITS( raw_cid, 12, 4, mmc_sizeof );

-        mmc_cid.year += 1997;

-    }

-

-    /* save it in card database */

-    memcpy( ( struct mmc_boot_cid * )&card->cid, \

-            ( struct mmc_boot_cid * )&mmc_cid,   \

-            sizeof( struct mmc_boot_cid ) );

-

-    dprintf(SPEW, "Decoded CID fields:\n" );

-    dprintf(SPEW, "Manufacturer ID: %x\n", mmc_cid.mid );

-    dprintf(SPEW, "OEM ID: 0x%x\n", mmc_cid.oid );

-    dprintf(SPEW, "Product Name: %s\n", mmc_cid.pnm );

-    dprintf(SPEW, "Product revision: %d.%d\n", (mmc_cid.prv >> 4), (mmc_cid.prv & 0xF) );

-    dprintf(SPEW, "Product serial number: %X\n", mmc_cid.psn );

-    dprintf(SPEW, "Manufacturing date: %d %d\n", mmc_cid.month, mmc_cid.year );

-

-    return MMC_BOOT_E_SUCCESS;

-}

-

-/*

- * Sends specified command to a card and waits for a response.

- */

-static unsigned int mmc_boot_send_command( struct mmc_boot_command* cmd )

-{

-    unsigned int mmc_cmd = 0;

-    unsigned int mmc_status = 0;

-    unsigned int mmc_resp = 0;

-    unsigned int mmc_return = MMC_BOOT_E_SUCCESS;

-    unsigned int cmd_index = 0;

-    int i = 0;

-

-    /* basic check */

-    if( cmd == NULL )

-    {

-        return MMC_BOOT_E_INVAL;

-    }

-

-    /* 1. Write command argument to MMC_BOOT_MCI_ARGUMENT register */

-    writel( cmd->argument, MMC_BOOT_MCI_ARGUMENT );

-

-    /* Writes to MCI port are not effective for 3 ticks of PCLK.

-     * The min pclk is 144KHz which gives 6.94 us/tick.

-     * Thus 21us == 3 ticks.

-     */

-    udelay(21);

-

-    /* 2. Set appropriate fields and write MMC_BOOT_MCI_CMD */

-    /* 2a. Write command index in CMD_INDEX field */

-    cmd_index = cmd->cmd_index;

-    mmc_cmd |= cmd->cmd_index;

-    /* 2b. Set RESPONSE bit to 1 for all cmds except CMD0 */

-    if( cmd_index != CMD0_GO_IDLE_STATE )

-    {

-        mmc_cmd |= MMC_BOOT_MCI_CMD_RESPONSE;

-    }

-

-    /* 2c. Set LONGRESP bit to 1 for CMD2, CMD9 and CMD10 */

-    if( IS_RESP_136_BITS(cmd->resp_type) )

-    {

-        mmc_cmd |= MMC_BOOT_MCI_CMD_LONGRSP;

-    }

-

-    /* 2d. Set INTERRUPT bit to 1 to disable command timeout */

-

-    /* 2e. Set PENDING bit to 1 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 to 1 */

-    mmc_cmd |= MMC_BOOT_MCI_CMD_ENABLE;

-

-    /* 2g. Set PROG_ENA bit to 1 for CMD12, CMD13 issued at the end of

-       write data transfer */

-    if( ( cmd_index == CMD12_STOP_TRANSMISSION ||

-                cmd_index == CMD13_SEND_STATUS ) && cmd->prg_enabled )

-    {

-        mmc_cmd |= MMC_BOOT_MCI_CMD_PROG_ENA;

-    }

-

-    /* 2h. Set MCIABORT bit to 1 for CMD12 when working with SDIO card */

-    /* 2i. Set CCS_ENABLE bit to 1 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 );

-

-    /* 2k. Write to MMC_BOOT_MCI_CMD register */

-    writel( mmc_cmd, MMC_BOOT_MCI_CMD );

-

-    dprintf(SPEW, "Command sent: CMD%d MCI_CMD_REG:%x MCI_ARG:%x\n",

-            cmd_index, mmc_cmd, cmd->argument );

-

-    /* 3. Wait for interrupt or poll on the following bits of MCI_STATUS

-       register */

-    do{

-        /* 3a. Read MCI_STATUS register */

-        while(readl( MMC_BOOT_MCI_STATUS ) \

-                & MMC_BOOT_MCI_STAT_CMD_ACTIVE);

-

-        mmc_status = readl( MMC_BOOT_MCI_STATUS );

-

-        /* 3b. CMD_SENT bit supposed to be set to 1 only after CMD0 is sent -

-           no response required. */

-        if( ( cmd->resp_type == MMC_BOOT_RESP_NONE ) &&

-                (mmc_status & MMC_BOOT_MCI_STAT_CMD_SENT ) )

-        {

-            break;

-        }

-

-        /* 3c. If CMD_TIMEOUT bit is set then no response was received */

-        else if( mmc_status & MMC_BOOT_MCI_STAT_CMD_TIMEOUT )

-        {

-            mmc_return = MMC_BOOT_E_TIMEOUT;

-            break;

-        }

-        /* 3d. If CMD_RESPONSE_END bit is set to 1 then command's response was

-           received and CRC check passed

-           Spcial case for ACMD41: it seems to always fail CRC even if

-           the response is valid

-           */

-        else if (( mmc_status & MMC_BOOT_MCI_STAT_CMD_RESP_END ) || (cmd_index == CMD1_SEND_OP_COND)

-                || (cmd_index == CMD8_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 ) & 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_BOOT_RESP_R2 ||

-                      cmd->resp_type == MMC_BOOT_RESP_R3 ||

-                      cmd->resp_type == MMC_BOOT_RESP_R6 ||

-                      cmd->resp_type == MMC_BOOT_RESP_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( IS_RESP_136_BITS( cmd->resp_type ) )

-                {

-                    for( i = 0; i < 4; i++ )

-                    {

-                        cmd->resp[3-i] = readl( MMC_BOOT_MCI_RESP_0 + ( i * 4 ) );

-

-                    }

-                }

-                else

-                {

-                    cmd->resp[0] = readl( MMC_BOOT_MCI_RESP_0 );

-                }

-            }

-            else

-            {

-                /* command index mis-match */

-                mmc_return = MMC_BOOT_E_CMD_INDX_MISMATCH;

-            }

-

-            dprintf(SPEW, "Command response received: %X\n", cmd->resp[0] );

-            break;

-        }

-

-        /* 3e. If CMD_CRC_FAIL bit is set to 1 then cmd's response was recvd,

-           but CRC check failed. */

-        else if( ( mmc_status & MMC_BOOT_MCI_STAT_CMD_CRC_FAIL )  )

-        {

-            if(cmd_index == ACMD41_SEND_OP_COND)

-            {

-                cmd->resp[0] = readl( MMC_BOOT_MCI_RESP_0);

-            }

-            else

-                mmc_return = MMC_BOOT_E_CRC_FAIL;

-            break;

-        }

-

-    }while(1);

-

-    return mmc_return;

-}

-

-/*

- * Reset all the cards to idle condition (CMD 0)

- */

-static unsigned int mmc_boot_reset_cards( void )

-{

-    struct mmc_boot_command cmd;

-

-    memset( (struct mmc_boot_command *)&cmd, 0,

-            sizeof(struct mmc_boot_command) );

-

-    cmd.cmd_index = CMD0_GO_IDLE_STATE;

-    cmd.argument = 0; // stuff bits - ignored

-    cmd.cmd_type = MMC_BOOT_CMD_BCAST;

-    cmd.resp_type = MMC_BOOT_RESP_NONE;

-

-    /* send command */

-    return mmc_boot_send_command( &cmd );

-}

-

-/*

- * Send CMD1 to know whether the card supports host VDD profile or not.

- */

-static unsigned int mmc_boot_send_op_cond( struct mmc_boot_host* host,

-        struct mmc_boot_card* card )

-{

-    struct mmc_boot_command cmd;

-    unsigned int mmc_resp = 0;

-    unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;

-

-    /* basic check */

-    if( ( host == NULL ) || ( card == NULL ) )

-    {

-        return MMC_BOOT_E_INVAL;

-    }

-

-    memset( (struct mmc_boot_command *)&cmd, 0,

-            sizeof(struct mmc_boot_command) );

-

-    /* CMD1 format:

-     * [31] Busy bit

-     * [30:29] Access mode

-     * [28:24] reserved

-     * [23:15] 2.7-3.6

-     * [14:8]  2.0-2.6

-     * [7]     1.7-1.95

-     * [6:0]   reserved

-     */

-

-    cmd.cmd_index = CMD1_SEND_OP_COND;

-    cmd.argument = host->ocr;

-    cmd.cmd_type = MMC_BOOT_CMD_BCAST_W_RESP;

-    cmd.resp_type = MMC_BOOT_RESP_R3;

-

-    mmc_ret = mmc_boot_send_command( &cmd );

-    if( mmc_ret != MMC_BOOT_E_SUCCESS )

-    {

-        return mmc_ret;

-    }

-

-    /* Now it's time to examine response */

-    mmc_resp = cmd.resp[0];

-

-    /* Response contains card's ocr. Update card's information */

-    card->ocr = mmc_resp;

-

-    /* Check the response for busy status */

-    if( !( mmc_resp & MMC_BOOT_OCR_BUSY ) )

-    {

-        return MMC_BOOT_E_CARD_BUSY;

-    }

-

-    if(mmc_resp & MMC_BOOT_OCR_SEC_MODE)

-    {

-        card->type = MMC_BOOT_TYPE_MMCHC;

-    }

-    else

-    {

-        card->type = MMC_BOOT_TYPE_STD_MMC;

-    }

-    return MMC_BOOT_E_SUCCESS;

-}

-

-/*

- * Request any card to send its uniquie card identification (CID) number (CMD2).

- */

-static unsigned int mmc_boot_all_send_cid( struct mmc_boot_card* card )

-{

-    struct mmc_boot_command cmd;

-    unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;

-

-    /* basic check */

-    if( card == NULL )

-    {

-        return MMC_BOOT_E_INVAL;

-    }

-

-    memset( (struct mmc_boot_command *)&cmd, 0,

-            sizeof(struct mmc_boot_command) );

-

-    /* CMD2 Format:

-     * [31:0] stuff bits

-     */

-    cmd.cmd_index = CMD2_ALL_SEND_CID;

-    cmd.argument = 0;

-    cmd.cmd_type = MMC_BOOT_CMD_BCAST_W_RESP;

-    cmd.resp_type = MMC_BOOT_RESP_R2;

-

-    /* send command */

-    mmc_ret = mmc_boot_send_command( &cmd );

-    if( mmc_ret != MMC_BOOT_E_SUCCESS )

-    {

-        return mmc_ret;

-    }

-

-    /* Response contains card's 128 bits CID register */

-    mmc_ret = mmc_boot_decode_and_save_cid( card, cmd.resp );

-    if( mmc_ret != MMC_BOOT_E_SUCCESS )

-    {

-        return mmc_ret;

-    }

-    return MMC_BOOT_E_SUCCESS;

-}

-

-/*

- * Ask any card to send it's relative card address (RCA).This RCA number is

- * shorter than CID and is used by the host to address the card in future (CMD3)

- */

-static unsigned int mmc_boot_send_relative_address( struct mmc_boot_card* card )

-{

-    struct mmc_boot_command cmd;

-    unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;

-

-    /* basic check */

-    if( card == NULL )

-    {

-        return MMC_BOOT_E_INVAL;

-    }

-

-    memset( (struct mmc_boot_command *)&cmd, 0,

-            sizeof(struct mmc_boot_command) );

-

-    /* CMD3 Format:

-     * [31:0] stuff bits

-     */

-    if(card->type == MMC_BOOT_TYPE_SDHC || card->type == MMC_BOOT_TYPE_STD_SD)

-    {

-        cmd.cmd_index = CMD3_SEND_RELATIVE_ADDR;

-        cmd.argument = 0;

-        cmd.cmd_type = MMC_BOOT_CMD_BCAST_W_RESP;

-        cmd.resp_type = MMC_BOOT_RESP_R6;

-

-        /* send command */

-        mmc_ret = mmc_boot_send_command( &cmd );

-        if( mmc_ret != MMC_BOOT_E_SUCCESS )

-        {

-            return mmc_ret;

-        }

-        /* For sD, card will send RCA. Store it */

-        card->rca =  (cmd.resp[0] >> 16);

-    }

-    else

-    {

-        cmd.cmd_index = CMD3_SEND_RELATIVE_ADDR;

-        cmd.argument = (MMC_RCA << 16);

-        card->rca =  (cmd.argument >> 16);

-        cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;

-        cmd.resp_type = MMC_BOOT_RESP_R1;

-

-        /* send command */

-        mmc_ret = mmc_boot_send_command( &cmd );

-        if( mmc_ret != MMC_BOOT_E_SUCCESS )

-        {

-            return mmc_ret;

-        }

-    }

-

-    return MMC_BOOT_E_SUCCESS;

-}

-

-/*

- * Requests card to send it's CSD register's contents. (CMD9)

- */

-static unsigned int mmc_boot_send_csd( struct mmc_boot_card* card,

-                                       unsigned int* raw_csd )

-{

-    struct mmc_boot_command cmd;

-    unsigned int mmc_arg = 0;

-    unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;

-

-    /* basic check */

-    if( card == NULL )

-    {

-        return MMC_BOOT_E_INVAL;

-    }

-

-    memset( (struct mmc_boot_command *)&cmd, 0,

-            sizeof(struct mmc_boot_command) );

-

-    /* CMD9 Format:

-     * [31:16] RCA

-     * [15:0] stuff bits

-     */

-    mmc_arg |= card->rca << 16;

-

-    cmd.cmd_index = CMD9_SEND_CSD;

-    cmd.argument = mmc_arg;

-    cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;

-    cmd.resp_type = MMC_BOOT_RESP_R2;

-

-    /* send command */

-    mmc_ret = mmc_boot_send_command( &cmd );

-    if( mmc_ret != MMC_BOOT_E_SUCCESS )

-    {

-        return mmc_ret;

-    }

-

-    /* response contains the card csd */

-    memcpy(raw_csd, cmd.resp, sizeof(cmd.resp));

-

-    return MMC_BOOT_E_SUCCESS;

-}

-

-/*

- * Selects a card by sending CMD7 to the card with its RCA.

- * If RCA field is set as 0 ( or any other address ),

- * the card will be de-selected. (CMD7)

- */

-static unsigned int mmc_boot_select_card( struct mmc_boot_card* card,

-        unsigned int rca )

-{

-    struct mmc_boot_command cmd;

-    unsigned int mmc_arg = 0;

-    unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;

-

-    /* basic check */

-    if( card == NULL )

-    {

-        return MMC_BOOT_E_INVAL;

-    }

-

-    memset( (struct mmc_boot_command *)&cmd, 0,

-            sizeof(struct mmc_boot_command) );

-

-    /* CMD7 Format:

-     * [31:16] RCA

-     * [15:0] stuff bits

-     */

-    mmc_arg |= rca << 16;

-

-    cmd.cmd_index = CMD7_SELECT_DESELECT_CARD;

-    cmd.argument = mmc_arg;

-    cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;

-    /* If we are deselecting card, we do not get response */

-    if( rca == card->rca && rca)

-    {

-        if(card->type == MMC_BOOT_TYPE_SDHC || card->type == MMC_BOOT_TYPE_STD_SD)

-            cmd.resp_type = MMC_BOOT_RESP_R1B;

-        else

-            cmd.resp_type = MMC_BOOT_RESP_R1;

-    }

-    else

-    {

-        cmd.resp_type = MMC_BOOT_RESP_NONE;

-    }

-

-    /* send command */

-    mmc_ret = mmc_boot_send_command( &cmd );

-    if( mmc_ret != MMC_BOOT_E_SUCCESS )

-    {

-        return mmc_ret;

-    }

-

-    /* As of now no need to look into a response. If it's required

-     * we'll explore later on */

-

-    return MMC_BOOT_E_SUCCESS;

-}

-

-/*

- * Send command to set block length.

- */

-static unsigned int mmc_boot_set_block_len( struct mmc_boot_card* card,

-        unsigned int block_len )

-{

-    struct mmc_boot_command cmd;

-    unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;

-

-    /* basic check */

-    if( card == NULL )

-    {

-        return MMC_BOOT_E_INVAL;

-    }

-

-    memset( (struct mmc_boot_command *)&cmd, 0,

-            sizeof(struct mmc_boot_command) );

-

-    /* CMD16 Format:

-     * [31:0] block length

-     */

-

-    cmd.cmd_index = CMD16_SET_BLOCKLEN;

-    cmd.argument = block_len;

-    cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;

-    cmd.resp_type = MMC_BOOT_RESP_R1;

-

-    /* send command */

-    mmc_ret = mmc_boot_send_command( &cmd );

-    if( mmc_ret != MMC_BOOT_E_SUCCESS )

-    {

-        return mmc_ret;

-    }

-

-    /* If blocklength is larger than 512 bytes,

-     * the card sets BLOCK_LEN_ERROR bit. */

-    if( cmd.resp[0] & MMC_BOOT_R1_BLOCK_LEN_ERR )

-    {

-        return MMC_BOOT_E_BLOCKLEN_ERR;

-    }

-    return MMC_BOOT_E_SUCCESS;

-}

-

-/*

- * Requests the card to stop transmission of data.

- */

-static unsigned int mmc_boot_send_stop_transmission( struct mmc_boot_card* card,

-        unsigned int prg_enabled )

-{

-    struct mmc_boot_command cmd;

-    unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;

-

-    /* basic check */

-    if( card == NULL )

-    {

-        return MMC_BOOT_E_INVAL;

-    }

-

-    memset( (struct mmc_boot_command *)&cmd, 0,

-            sizeof(struct mmc_boot_command) );

-

-    /* CMD12 Format:

-     * [31:0] stuff bits

-     */

-

-    cmd.cmd_index = CMD12_STOP_TRANSMISSION;

-    cmd.argument = 0;

-    cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;

-    cmd.resp_type = MMC_BOOT_RESP_R1B;

-    cmd.xfer_mode = MMC_BOOT_XFER_MODE_BLOCK;

-    cmd.prg_enabled = prg_enabled;

-

-    /* send command */

-    mmc_ret = mmc_boot_send_command( &cmd );

-    if( mmc_ret != MMC_BOOT_E_SUCCESS )

-    {

-        return mmc_ret;

-    }

-    return MMC_BOOT_E_SUCCESS;

-}

-

-/*

- * Get the card's current status

- */

-static unsigned int mmc_boot_get_card_status( struct mmc_boot_card* card,

-        unsigned int prg_enabled, unsigned int* status )

-{

-    struct mmc_boot_command cmd;

-    unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;

-

-    /* basic check */

-    if( card == NULL )

-    {

-        return MMC_BOOT_E_INVAL;

-    }

-

-    memset( (struct mmc_boot_command *)&cmd, 0,

-            sizeof(struct mmc_boot_command) );

-

-    /* CMD13 Format:

-     * [31:16] RCA

-     * [15:0] stuff bits

-     */

-    cmd.cmd_index = CMD13_SEND_STATUS;

-    cmd.argument = card->rca << 16;

-    cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;

-    cmd.resp_type = MMC_BOOT_RESP_R1;

-    cmd.prg_enabled = prg_enabled;

-

-    /* send command */

-    mmc_ret = mmc_boot_send_command( &cmd );

-    if( mmc_ret != MMC_BOOT_E_SUCCESS )

-    {

-        return mmc_ret;

-    }

-

-    /* Checking ADDR_OUT_OF_RANGE error in CMD13 response */

-    if(IS_ADDR_OUT_OF_RANGE(cmd.resp[0]))

-    {

-        return MMC_BOOT_E_FAILURE;

-    }

-

-    *status = cmd.resp[0];

-    return MMC_BOOT_E_SUCCESS;

-}

-

-/*

- * Decode type of error caused during read and write

- */

-static unsigned int mmc_boot_status_error(unsigned mmc_status)

-{

-    unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;

-

-    /* 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 )

-    {

-        mmc_ret = MMC_BOOT_E_DATA_CRC_FAIL;

-    }

-    /* If DATA_TIMEOUT bit is set to 1 then the data transfer time exceeded

-       the data timeout period without completing the transfer */

-    else if( mmc_status & MMC_BOOT_MCI_STAT_DATA_TIMEOUT )

-    {

-        mmc_ret = MMC_BOOT_E_DATA_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.*/

-    else 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 */

-        mmc_ret = MMC_BOOT_E_RX_OVRRUN;

-    }

-    /* 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.*/

-    else 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*/

-        mmc_ret = MMC_BOOT_E_RX_OVRRUN;

-    }

-    return mmc_ret;

-}

-

-/*

- * Send ext csd command.

- */

-static unsigned int mmc_boot_send_ext_cmd (struct mmc_boot_card* card, unsigned char* buf)

-{

-    struct mmc_boot_command cmd;

-    unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;

-    unsigned int mmc_reg = 0;

-    unsigned int* mmc_ptr = (unsigned int *)buf;

-

-    memset(buf,0, 512);

-

-    /* basic check */

-    if( card == NULL )

-    {

-        return MMC_BOOT_E_INVAL;

-    }

-

-    /* set block len */

-    if( (card->type != MMC_BOOT_TYPE_MMCHC) && (card->type != MMC_BOOT_TYPE_SDHC) )

-    {

-        mmc_ret = mmc_boot_set_block_len( card, 512);

-        if( mmc_ret != MMC_BOOT_E_SUCCESS )

-        {

-            dprintf(CRITICAL, "Error No.%d: Failure setting block length for Card (RCA:%s)\n",

-                    mmc_ret, (char *)(card->rca) );

-            return mmc_ret;

-        }

-    }

-

-    /* Set the FLOW_ENA bit of MCI_CLK register to 1 */

-    mmc_reg = readl( MMC_BOOT_MCI_CLK );

-    mmc_reg |= MMC_BOOT_MCI_CLK_ENA_FLOW ;

-    writel( mmc_reg, MMC_BOOT_MCI_CLK );

-

-    /* 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 );

-    writel( 512, MMC_BOOT_MCI_DATA_LENGTH );

-

-    /* Set appropriate fields and write the MCI_DATA_CTL register. */

-    /* Set ENABLE bit to 1 to enable the data transfer. */

-    mmc_reg = MMC_BOOT_MCI_DATA_ENABLE | MMC_BOOT_MCI_DATA_DIR | (512 << MMC_BOOT_MCI_BLKSIZE_POS);

-

-#if MMC_BOOT_ADM

-    mmc_reg |= MMC_BOOT_MCI_DATA_DM_ENABLE;

-#endif

-

-    writel( mmc_reg, MMC_BOOT_MCI_DATA_CTL );

-

-    memset( (struct mmc_boot_command *)&cmd, 0,

-            sizeof(struct mmc_boot_command) );

-    /* CMD8 */

-    cmd.cmd_index = CMD8_SEND_EXT_CSD;

-    cmd.cmd_type  = MMC_BOOT_CMD_ADDRESS;

-    cmd.resp_type = MMC_BOOT_RESP_R1;

-    cmd.xfer_mode = MMC_BOOT_XFER_MODE_BLOCK;

-

-    /* send command */

-    mmc_ret = mmc_boot_send_command( &cmd );

-    if( mmc_ret != MMC_BOOT_E_SUCCESS )

-    {

-        return mmc_ret;

-    }

-

-    /* Read the transfer data from SDCC FIFO. */

-    mmc_ret = mmc_boot_fifo_data_transfer(mmc_ptr, 512, MMC_BOOT_DATA_READ);

-

-    return mmc_ret;

-}

-

-/*

- * Switch command

- */

-static unsigned int mmc_boot_switch_cmd (struct mmc_boot_card* card,

-        unsigned access,

-        unsigned index,

-        unsigned value)

-{

-

-    struct mmc_boot_command cmd;

-    unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;

-

-    /* basic check */

-    if( card == NULL )

-    {

-        return MMC_BOOT_E_INVAL;

-    }

-

-    memset( (struct mmc_boot_command *)&cmd, 0,

-            sizeof(struct mmc_boot_command) );

-

-    /* CMD6 Format:

-     * [31:26] set to 0

-     * [25:24] access

-     * [23:16] index

-     * [15:8] value

-     * [7:3] set to 0

-     * [2:0] cmd set

-     */

-    cmd.cmd_index = CMD6_SWITCH_FUNC;

-    cmd.argument |= (access << 24);

-    cmd.argument |= (index << 16);

-    cmd.argument |= (value << 8);

-    cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;

-    cmd.resp_type = MMC_BOOT_RESP_R1B;

-

-    mmc_ret = mmc_boot_send_command( &cmd );

-    if( mmc_ret != MMC_BOOT_E_SUCCESS )

-    {

-        return mmc_ret;

-    }

-

-    return MMC_BOOT_E_SUCCESS;

-}

-

-/*

- * A command to set the data bus width for card. Set width to either

- */

-static unsigned int mmc_boot_set_bus_width( struct mmc_boot_card* card,

-        unsigned int width )

-{

-    unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;

-    unsigned int mmc_reg = 0;

-    unsigned int mmc_width = 0;

-    unsigned int status;

-    unsigned int wait_count = 100;

-

-

-    if( width != MMC_BOOT_BUS_WIDTH_1_BIT)

-    {

-        mmc_width = width-1;

-    }

-

-

-    mmc_ret = mmc_boot_switch_cmd(card, MMC_BOOT_ACCESS_WRITE,

-                                        MMC_BOOT_EXT_CMMC_BUS_WIDTH, mmc_width);

-

-    if( mmc_ret != MMC_BOOT_E_SUCCESS )

-    {

-        return mmc_ret;

-    }

-

-    /* Wait for the card to complete the switch command processing */

-    do

-    {

-        mmc_ret = mmc_boot_get_card_status(card, 0, &status);

-        if(mmc_ret != MMC_BOOT_E_SUCCESS)

-        {

-            return mmc_ret;

-        }

-

-        wait_count--;

-        if(wait_count == 0)

-        {

-            return MMC_BOOT_E_FAILURE;

-        }

-    }while( MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_PROG_STATE );

-

-

-    /* set MCI_CLK accordingly */

-    mmc_reg = readl( MMC_BOOT_MCI_CLK );

-    mmc_reg &= ~MMC_BOOT_MCI_CLK_WIDEBUS_MODE;

-    if ( width == MMC_BOOT_BUS_WIDTH_1_BIT )

-    {

-        mmc_reg |=  MMC_BOOT_MCI_CLK_WIDEBUS_1_BIT;

-    }

-    else if (width == MMC_BOOT_BUS_WIDTH_4_BIT )

-    {

-        mmc_reg |=  MMC_BOOT_MCI_CLK_WIDEBUS_4_BIT;

-    }

-    else if (width == MMC_BOOT_BUS_WIDTH_8_BIT )

-    {

-        mmc_reg |=  MMC_BOOT_MCI_CLK_WIDEBUS_8_BIT;

-    }

-    writel( mmc_reg, MMC_BOOT_MCI_CLK );

-

-    mdelay(10); // Giving some time to card to stabilize.

-

-    return MMC_BOOT_E_SUCCESS;

-}

-

-

-/*

- * A command to start data read from card. Either a single block or

- * multiple blocks can be read. Multiple blocks read will continuously

- * transfer data from card to host unless requested to stop by issuing

- * CMD12 - STOP_TRANSMISSION.

- */

-static unsigned int mmc_boot_send_read_command( struct mmc_boot_card* card,

-        unsigned int xfer_type,

-        unsigned int data_addr )

-{

-    struct mmc_boot_command cmd;

-    unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;

-

-    /* basic check */

-    if( card == NULL )

-    {

-        return MMC_BOOT_E_INVAL;

-    }

-

-    memset( (struct mmc_boot_command *)&cmd, 0,

-            sizeof(struct mmc_boot_command) );

-

-    /* CMD17/18 Format:

-     * [31:0] Data Address

-     */

-    if( xfer_type == MMC_BOOT_XFER_MULTI_BLOCK )

-    {

-        cmd.cmd_index = CMD18_READ_MULTIPLE_BLOCK;

-    }

-    else

-    {

-        cmd.cmd_index = CMD17_READ_SINGLE_BLOCK;

-    }

-

-    cmd.argument = data_addr;

-    cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;

-    cmd.resp_type = MMC_BOOT_RESP_R1;

-

-    /* send command */

-    mmc_ret = mmc_boot_send_command( &cmd );

-    if( mmc_ret != MMC_BOOT_E_SUCCESS )

-    {

-        return mmc_ret;

-    }

-

-    /* Response contains 32 bit Card status. Here we'll check

-       BLOCK_LEN_ERROR and ADDRESS_ERROR */

-    if( cmd.resp[0] & MMC_BOOT_R1_BLOCK_LEN_ERR )

-    {

-        return MMC_BOOT_E_BLOCKLEN_ERR;

-    }

-    /* Misaligned address not matching block length */

-    if( cmd.resp[0] & MMC_BOOT_R1_ADDR_ERR )

-    {

-        return MMC_BOOT_E_ADDRESS_ERR;

-    }

-

-    return MMC_BOOT_E_SUCCESS;

-}

-

-/*

- * A command to start data write to card. Either a single block or

- * multiple blocks can be written. Multiple block write will continuously

- * transfer data from host to card unless requested to stop by issuing

- * CMD12 - STOP_TRANSMISSION.

- */

-static unsigned int mmc_boot_send_write_command( struct mmc_boot_card* card,

-        unsigned int xfer_type,

-        unsigned int data_addr )

-{

-    struct mmc_boot_command cmd;

-    unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;

-

-    /* basic check */

-    if( card == NULL )

-    {

-        return MMC_BOOT_E_INVAL;

-    }

-

-    memset( (struct mmc_boot_command *)&cmd, 0,

-            sizeof(struct mmc_boot_command) );

-

-    /* CMD24/25 Format:

-     * [31:0] Data Address

-     */

-    if( xfer_type == MMC_BOOT_XFER_MULTI_BLOCK )

-    {

-        cmd.cmd_index = CMD25_WRITE_MULTIPLE_BLOCK;

-    }

-    else

-    {

-        cmd.cmd_index = CMD24_WRITE_SINGLE_BLOCK;

-    }

-

-    cmd.argument = data_addr;

-    cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;

-    cmd.resp_type = MMC_BOOT_RESP_R1;

-

-    /* send command */

-    mmc_ret = mmc_boot_send_command( &cmd );

-    if( mmc_ret != MMC_BOOT_E_SUCCESS )

-    {

-        return mmc_ret;

-    }

-

-    /* Response contains 32 bit Card status. Here we'll check

-       BLOCK_LEN_ERROR and ADDRESS_ERROR */

-    if( cmd.resp[0] & MMC_BOOT_R1_BLOCK_LEN_ERR )

-    {

-        return MMC_BOOT_E_BLOCKLEN_ERR;

-    }

-    /* Misaligned address not matching block length */

-    if( cmd.resp[0] & MMC_BOOT_R1_ADDR_ERR )

-    {

-        return MMC_BOOT_E_ADDRESS_ERR;

-    }

-

-    return MMC_BOOT_E_SUCCESS;

-}

-

-

-/*

- * Write data_len data to address specified by data_addr. data_len is

- * multiple of blocks for block data transfer.

- */

-unsigned int mmc_boot_write_to_card( struct mmc_boot_host* host,

-        struct mmc_boot_card* card,

-        unsigned long long data_addr,

-        unsigned int data_len,

-        unsigned int* in )

-{

-    unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;

-    unsigned int mmc_status = 0;

-    unsigned int mmc_reg = 0;

-    unsigned int addr;

-    unsigned int xfer_type;

-    unsigned int status;

-

-    if( ( host == NULL ) || ( card == NULL ) )

-    {

-        return MMC_BOOT_E_INVAL;

-    }

-

-    /* Set block length. High Capacity MMC/SD card uses fixed 512 bytes block

-       length. So no need to send CMD16. */

-    if( (card->type != MMC_BOOT_TYPE_MMCHC) && (card->type != MMC_BOOT_TYPE_SDHC) )

-    {

-        mmc_ret = mmc_boot_set_block_len( card, card->wr_block_len );

-        if( mmc_ret != MMC_BOOT_E_SUCCESS )

-        {

-            dprintf(CRITICAL, "Error No.%d: Failure setting block length for Card\

-                    (RCA:%s)\n", mmc_ret, (char *)(card->rca) );

-            return mmc_ret;

-        }

-    }

-

-    /* use multi-block mode to transfer for data larger than a block */

-    xfer_type = (data_len > card->rd_block_len) ? MMC_BOOT_XFER_MULTI_BLOCK :

-        MMC_BOOT_XFER_SINGLE_BLOCK;

-

-    /* For MMCHC/SDHC data address is specified in unit of 512B */

-    addr = ( (card->type != MMC_BOOT_TYPE_MMCHC) && (card->type != MMC_BOOT_TYPE_SDHC) )

-        ? (unsigned int) data_addr : (unsigned int) (data_addr / 512);

-

-    /* Set the FLOW_ENA bit of MCI_CLK register to 1 */

-    mmc_reg = readl( MMC_BOOT_MCI_CLK );

-    mmc_reg |= MMC_BOOT_MCI_CLK_ENA_FLOW ;

-    writel( mmc_reg, MMC_BOOT_MCI_CLK );

-

-    /* Write data timeout period to MCI_DATA_TIMER register */

-    /* Data timeout period should be in card bus clock periods */

-    /*TODO: Fix timeout value*/

-    mmc_reg = 0xFFFFFFFF;

-    writel( mmc_reg, MMC_BOOT_MCI_DATA_TIMER );

-

-    /* Write the total size of the transfer data to MCI_DATA_LENGTH register */

-    writel( data_len, MMC_BOOT_MCI_DATA_LENGTH );

-

-    /* Send command to the card/device in order to start the write data xfer.

-       The possible commands are CMD24/25/53/60/61 */

-    mmc_ret = mmc_boot_send_write_command( card, xfer_type, addr );

-    if( mmc_ret != MMC_BOOT_E_SUCCESS )

-    {

-        dprintf(CRITICAL, "Error No.%d: Failure sending write command to the\

-                Card(RCA:%x)\n", mmc_ret, card->rca );

-        return mmc_ret;

-    }

-

-    /* Set appropriate fields and write the MCI_DATA_CTL register */

-    /* Set ENABLE bit to 1 to enable the data transfer. */

-    mmc_reg = 0;

-    mmc_reg |= MMC_BOOT_MCI_DATA_ENABLE;

-    /* Clear DIRECTION bit to 0 to enable transfer from host to card */

-    /* Clear MODE bit to 0 to enable block oriented data transfer. For

-       MMC cards only, if stream data transfer mode is desired, set

-       MODE bit to 1. */

-

-    /* Set DM_ENABLE bit to 1 in order to enable DMA, otherwise set 0 */

-

-#if MMC_BOOT_ADM

-    mmc_reg |= MMC_BOOT_MCI_DATA_DM_ENABLE;

-#endif

-

-    /* Write size of block to be used during the data transfer to

-       BLOCKSIZE field */

-    mmc_reg |= card->wr_block_len << MMC_BOOT_MCI_BLKSIZE_POS;

-    writel( mmc_reg, MMC_BOOT_MCI_DATA_CTL );

-

-    /* write data to FIFO */

-    mmc_ret = mmc_boot_fifo_data_transfer(in, data_len, MMC_BOOT_DATA_WRITE);

-

-    if( mmc_ret != MMC_BOOT_E_SUCCESS )

-    {

-        dprintf(CRITICAL, "Error No.%d: Failure on data transfer from the \

-                Card(RCA:%x)\n", mmc_ret, card->rca );

-        /* In case of any failure happening for multi block transfer */

-        if( xfer_type == MMC_BOOT_XFER_MULTI_BLOCK )

-            mmc_boot_send_stop_transmission( card, 1 );

-        return mmc_ret;

-    }

-

-    /* Send command to the card/device in order to poll the de-assertion of

-       card/device BUSY condition. It is important to set PROG_ENA bit in

-       MCI_CLK register before sending the command. Possible commands are

-       CMD12/13. */

-    if( xfer_type == MMC_BOOT_XFER_MULTI_BLOCK )

-    {

-        mmc_ret = mmc_boot_send_stop_transmission( card, 1 );

-        if( mmc_ret != MMC_BOOT_E_SUCCESS )

-        {

-            dprintf(CRITICAL, "Error No.%d: Failure sending Stop Transmission \

-                    command to the Card(RCA:%x)\n", mmc_ret, card->rca );

-            return mmc_ret;

-        }

-    }

-    else

-    {

-        mmc_ret = mmc_boot_get_card_status( card, 1, &status );

-        if( mmc_ret != MMC_BOOT_E_SUCCESS )

-        {

-            dprintf(CRITICAL, "Error No.%d: Failure getting card status of Card(RCA:%x)\n",

-                    mmc_ret, card->rca );

-            return mmc_ret;

-        }

-    }

-

-    /* Wait for interrupt or poll on PROG_DONE bit of MCI_STATUS register. If

-       PROG_DONE bit is set to 1 it means that the card finished it programming

-       and stopped driving DAT0 line to 0 */

-    do

-    {

-        mmc_status = readl( MMC_BOOT_MCI_STATUS );

-        if( mmc_status & MMC_BOOT_MCI_STAT_PROG_DONE )

-        {

-            break;

-        }

-    } while(1);

-

-    return MMC_BOOT_E_SUCCESS;

-}

+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
 
-

-/*

- * Adjust the interface speed to optimal speed

- */

-static unsigned int mmc_boot_adjust_interface_speed( struct mmc_boot_host* host,

-        struct mmc_boot_card* card )

-{

-    unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;

-    unsigned int status;

-    unsigned int wait_count = 100;

-

-    /* Setting HS_TIMING in EXT_CSD (CMD6) */

-    mmc_ret = mmc_boot_switch_cmd(card, MMC_BOOT_ACCESS_WRITE,

-                                        MMC_BOOT_EXT_CMMC_HS_TIMING, 1);

-

-    if(mmc_ret!= MMC_BOOT_E_SUCCESS)

-    {

-        return mmc_ret;

-    }

-

-    /* Wait for the card to complete the switch command processing */

-    do

-    {

-        mmc_ret = mmc_boot_get_card_status(card, 0, &status);

-        if(mmc_ret != MMC_BOOT_E_SUCCESS)

-        {

-            return mmc_ret;

-        }

-

-        wait_count--;

-        if(wait_count == 0)

-        {

-            return MMC_BOOT_E_FAILURE;

-        }

-    }while( MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_PROG_STATE );

-

-

-    clock_config_mmc(mmc_slot, MMC_CLK_50MHZ);

-

-    host->mclk_rate = MMC_CLK_50MHZ;

-

-    return MMC_BOOT_E_SUCCESS;

-}

-

-static unsigned int mmc_boot_set_block_count( struct mmc_boot_card* card,

-        unsigned int block_count )

-{

-    struct mmc_boot_command cmd;

-    unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;

-

-    /* basic check */

-    if( card == NULL )

-    {

-        return MMC_BOOT_E_INVAL;

-    }

-

-    memset( (struct mmc_boot_command *)&cmd, 0,

-            sizeof(struct mmc_boot_command) );

-

-    /* CMD23 Format:

-     * [15:0] number of blocks

-     */

-

-    cmd.cmd_index = CMD23_SET_BLOCK_COUNT;

-    cmd.argument = block_count;

-    cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;

-    cmd.resp_type = MMC_BOOT_RESP_R1;

-

-    /* send command */

-    mmc_ret = mmc_boot_send_command( &cmd );

-    if( mmc_ret != MMC_BOOT_E_SUCCESS )

-    {

-        return mmc_ret;

-    }

-

-    if( cmd.resp[0] & MMC_BOOT_R1_OUT_OF_RANGE)

-    {

-        return MMC_BOOT_E_BLOCKLEN_ERR;

-    }

-

-    return MMC_BOOT_E_SUCCESS;

-}

-

-/*

- * Reads a data of data_len from the address specified. data_len

- * should be multiple of block size for block data transfer.

- */

-unsigned int mmc_boot_read_from_card( struct mmc_boot_host* host,

-        struct mmc_boot_card* card,

-        unsigned long long data_addr,

-        unsigned int data_len,

-        unsigned int* out )

-{

-    unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;

-    unsigned int mmc_reg = 0;

-    unsigned int xfer_type;

-    unsigned int addr = 0;

-    unsigned char open_ended_read = 1;

-

-    if ( ( host == NULL ) || ( card == NULL ) )

-    {

-        return MMC_BOOT_E_INVAL;

-    }

-

-    /* Set block length. High Capacity MMC/SD card uses fixed 512 bytes block

-       length. So no need to send CMD16. */

-    if ( (card->type != MMC_BOOT_TYPE_MMCHC) && (card->type != MMC_BOOT_TYPE_SDHC) )

-    {

-        mmc_ret = mmc_boot_set_block_len( card, card->rd_block_len );

-        if ( mmc_ret != MMC_BOOT_E_SUCCESS )

-        {

-            dprintf(CRITICAL, "Error No.%d: Failure setting block length for Card (RCA:%s)\n",

-                    mmc_ret, (char *)(card->rca) );

-            return mmc_ret;

-        }

-    }

-

-    /* use multi-block mode to transfer for data larger than a block */

-    xfer_type = (data_len > card->rd_block_len) ? MMC_BOOT_XFER_MULTI_BLOCK :

-        MMC_BOOT_XFER_SINGLE_BLOCK;

-

-    if(xfer_type == MMC_BOOT_XFER_MULTI_BLOCK)

-    {

-        if( (card->type == MMC_BOOT_TYPE_MMCHC) || (card->type == MMC_BOOT_TYPE_STD_MMC) )

-        {

-            /* Virtio model does not support open-ended multi-block reads.

-             * So, block count must be set before sending read command.

-             * All SD cards do not support this command. Restrict this to MMC.

-             */

-            mmc_ret = mmc_boot_set_block_count( card, data_len/(card->rd_block_len));

-            if( mmc_ret != MMC_BOOT_E_SUCCESS )

-            {

-                dprintf(CRITICAL, "Error No.%d: Failure setting read block count for Card (RCA:%s)\n",

-                        mmc_ret, (char *)(card->rca) );

-                return mmc_ret;

-            }

-

-            open_ended_read = 0;

-        }

-    }

-

-    /* Set the FLOW_ENA bit of MCI_CLK register to 1 */

-    /* Note: It's already enabled */

-

-    /* 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 = (unsigned long)(card->rd_timeout_ns / 1000000) *

-        (host->mclk_rate / 1000);

-    mmc_reg += 1000; // add some extra clock cycles to be safe

-    mmc_reg = mmc_reg/2;

-    writel( mmc_reg, MMC_BOOT_MCI_DATA_TIMER );

-

-    /* 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_len, MMC_BOOT_MCI_DATA_LENGTH );

-

-    /* For MMCHC/SDHC data address is specified in unit of 512B */

-    addr = ( (card->type != MMC_BOOT_TYPE_MMCHC) && (card->type != MMC_BOOT_TYPE_SDHC) )

-        ? (unsigned int) data_addr :(unsigned int) (data_addr / 512);

-

-    /* Set appropriate fields and write the MCI_DATA_CTL register. */

-    /* Set ENABLE bit to 1 to enable the data transfer. */

-    mmc_reg = 0;

-    mmc_reg |= MMC_BOOT_MCI_DATA_ENABLE;

-    /* Clear DIRECTION bit to 1 to enable transfer from card to host */

-    mmc_reg |= MMC_BOOT_MCI_DATA_DIR;

-    /* Clear MODE bit to 0 to enable block oriented data transfer. For

-       MMC cards only, if stream data transfer mode is desired, set

-       MODE bit to 1. */

-

-    /* If DMA is to be used, Set DM_ENABLE bit to 1 */

-

-#if MMC_BOOT_ADM

-        mmc_reg |= MMC_BOOT_MCI_DATA_DM_ENABLE;

-#endif

-

-    /* Write size of block to be used during the data transfer to

-       BLOCKSIZE field */

-    mmc_reg |= (card->rd_block_len << MMC_BOOT_MCI_BLKSIZE_POS);

-    writel( mmc_reg, MMC_BOOT_MCI_DATA_CTL );

-

-    /* Send command to the card/device in order to start the read data

-       transfer. Possible commands: CMD17/18/53/60/61. */

-    mmc_ret = mmc_boot_send_read_command( card, xfer_type, addr );

-    if( mmc_ret != MMC_BOOT_E_SUCCESS )

-    {

-        dprintf(CRITICAL, "Error No.%d: Failure sending read command to the Card(RCA:%x)\n",

-                mmc_ret, card->rca );

-        return mmc_ret;

-    }

-

-    /* Read the transfer data from SDCC FIFO. */

-    mmc_ret = mmc_boot_fifo_data_transfer(out, data_len, MMC_BOOT_DATA_READ);

-

-    if( mmc_ret != MMC_BOOT_E_SUCCESS )

-    {

-        dprintf(CRITICAL, "Error No.%d: Failure on data transfer from the \

-                Card(RCA:%x)\n", mmc_ret, card->rca );

-        return mmc_ret;

-    }

-

-    /* In case a multiple block transfer was performed, send CMD12 to the

-       card/device in order to indicate the end of read data transfer */

-    if( (xfer_type == MMC_BOOT_XFER_MULTI_BLOCK) && open_ended_read )

-    {

-        mmc_ret = mmc_boot_send_stop_transmission( card, 0 );

-        if( mmc_ret != MMC_BOOT_E_SUCCESS )

-        {

-            dprintf(CRITICAL, "Error No.%d: Failure sending Stop Transmission \

-                    command to the Card(RCA:%x)\n", mmc_ret, card->rca );

-            return mmc_ret;

-        }

-    }

-

-    return MMC_BOOT_E_SUCCESS;

-}

-

-/*

- * Initialize host structure, set and enable clock-rate and power mode.

- */

-unsigned int mmc_boot_init( struct mmc_boot_host* host )

-{

-    unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;

-    unsigned int mmc_pwr = 0;

-

-

-    host->ocr = MMC_BOOT_OCR_27_36 | MMC_BOOT_OCR_SEC_MODE;

-    host->cmd_retry = MMC_BOOT_MAX_COMMAND_RETRY;

-

-    /* Initialize any clocks needed for SDC controller */

-    clock_init_mmc(mmc_slot);

-

-    /* Setup initial freq to 400KHz */

-    clock_config_mmc(mmc_slot, MMC_CLK_400KHZ);

-

-    host->mclk_rate = MMC_CLK_400KHZ;

-

-    /* set power mode*/

-    /* give some time to reach minimum voltate */

-    mdelay(2);

-    mmc_pwr &= ~MMC_BOOT_MCI_PWR_UP;

-    mmc_pwr |= MMC_BOOT_MCI_PWR_ON;

-    mmc_pwr |= MMC_BOOT_MCI_PWR_UP;

-    writel( mmc_pwr, MMC_BOOT_MCI_POWER );

-    /* some more time to stabilize voltage */

-    mdelay(2);

-

-    return MMC_BOOT_E_SUCCESS;

-}

-

-/*

- * Performs card identification process:

- * - get card's unique identification number (CID)

- * - get(for sd)/set (for mmc) relative card address (RCA)

- * - get CSD

- * - select the card, thus transitioning it to Transfer State

- * - get Extended CSD (for mmc)

- */

-static unsigned int mmc_boot_identify_card( struct mmc_boot_host* host,

-        struct mmc_boot_card* card)

-{

-    unsigned int mmc_return = MMC_BOOT_E_SUCCESS;

-    unsigned int raw_csd[4];

-

-    /* basic check */

-    if( ( host == NULL ) || ( card == NULL ) )

-    {

-        return MMC_BOOT_E_INVAL;

-    }

-

-    /* Ask card to send its unique card identification (CID) number (CMD2) */

-    mmc_return = mmc_boot_all_send_cid( card );

-    if( mmc_return != MMC_BOOT_E_SUCCESS )

-    {

-        dprintf(CRITICAL, "Error No. %d: Failure getting card's CID number!\n",

-                mmc_return );

-        return mmc_return;

-    }

-

-    /* Ask card to send a relative card address (RCA) (CMD3) */

-    mmc_return = mmc_boot_send_relative_address( card );

-    if( mmc_return != MMC_BOOT_E_SUCCESS )

-    {

-        dprintf(CRITICAL, "Error No. %d: Failure getting card's RCA!\n",

-                mmc_return );

-        return mmc_return;

-    }

-

-    /* Get card's CSD register (CMD9) */

-    mmc_return = mmc_boot_send_csd( card, raw_csd );

-    if( mmc_return != MMC_BOOT_E_SUCCESS )

-    {

-        dprintf(CRITICAL, "Error No.%d: Failure getting card's CSD information!\n",

-                mmc_return );

-        return mmc_return;

-    }

-

-    /* Select the card (CMD7) */

-    mmc_return = mmc_boot_select_card( card, card->rca );

-    if( mmc_return != MMC_BOOT_E_SUCCESS )

-    {

-        dprintf(CRITICAL, "Error No.%d: Failure selecting the Card with RCA: %x\n",

-                mmc_return, card->rca );

-        return mmc_return;

-    }

-

-    /* Set the card status as active */

-    card->status = MMC_BOOT_STATUS_ACTIVE;

-

-    if( (card->type == MMC_BOOT_TYPE_STD_MMC) ||  (card->type == MMC_BOOT_TYPE_MMCHC))

-    {

-        /* For MMC cards, also get the extended csd */

-        mmc_return = mmc_boot_send_ext_cmd( card, ext_csd_buf);

-

-        if( mmc_return != MMC_BOOT_E_SUCCESS )

-        {

-                dprintf(CRITICAL, "Error No.%d: Failure getting card's ExtCSD information!\n",

-                        mmc_return );

-

-                return mmc_return;

-        }

-

-    }

-

-    /* Decode and save the CSD register */

-    mmc_return = mmc_boot_decode_and_save_csd( card, raw_csd );

-    if( mmc_return != MMC_BOOT_E_SUCCESS )

-    {

-        dprintf(CRITICAL, "Error No.%d: Failure decoding card's CSD information!\n",

-                        mmc_return );

-        return mmc_return;

-    }

-

-    /* Once CSD is received, set read and write timeout value now itself */

-    mmc_return = mmc_boot_set_read_timeout( host, card );

-    if( mmc_return != MMC_BOOT_E_SUCCESS )

-    {

-        dprintf(CRITICAL, "Error No.%d: Failure setting Read Timeout value!\n",

-                mmc_return );

-        return mmc_return;

-    }

-

-    mmc_return = mmc_boot_set_write_timeout( host, card );

-    if( mmc_return != MMC_BOOT_E_SUCCESS )

-    {

-        dprintf(CRITICAL, "Error No.%d: Failure setting Write Timeout value!\n",

-                mmc_return );

-        return mmc_return;

-    }

-

-    return MMC_BOOT_E_SUCCESS;

-}

-

-static unsigned int mmc_boot_send_app_cmd(unsigned int rca)

-{

-    struct mmc_boot_command cmd;

-    unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;

-

-    memset( (struct mmc_boot_command *)&cmd, 0,

-            sizeof(struct mmc_boot_command) );

-

-    cmd.cmd_index = CMD55_APP_CMD;

-    cmd.argument = (rca << 16);

-    cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;

-    cmd.resp_type = MMC_BOOT_RESP_R1;

-

-    mmc_ret = mmc_boot_send_command(&cmd);

-

-    if( mmc_ret != MMC_BOOT_E_SUCCESS )

-    {

-        return mmc_ret;

-    }

-

-    return MMC_BOOT_E_SUCCESS;

-}

-

-static unsigned int mmc_boot_sd_init_card(struct mmc_boot_card* card)

-{

-    unsigned int i,mmc_ret;

-    unsigned int ocr_cmd_arg;

-    struct mmc_boot_command cmd;

-

-    memset( (struct mmc_boot_command *)&cmd, 0,

-            sizeof(struct mmc_boot_command) );

-

-    /* Send CMD8 to set interface condition */

-    for(i=0;i<3;i++)

-    {

-        cmd.cmd_index = CMD8_SEND_IF_COND;

-        cmd.argument = MMC_BOOT_SD_HC_VOLT_SUPPLIED;

-        cmd.cmd_type = MMC_BOOT_CMD_BCAST_W_RESP;

-        cmd.resp_type = MMC_BOOT_RESP_R7;

-

-        mmc_ret = mmc_boot_send_command(&cmd);

-        if( mmc_ret == MMC_BOOT_E_SUCCESS )

-        {

-            if(cmd.resp[0] != MMC_BOOT_SD_HC_VOLT_SUPPLIED)

-                return MMC_BOOT_E_FAILURE;

-            /* Set argument for ACMD41 */

-            ocr_cmd_arg = MMC_BOOT_SD_NEG_OCR | MMC_BOOT_SD_HC_HCS;

-            break;

-        }

-        mdelay(1);

-    }

-

-    /* Send ACMD41 to set operating condition */

-    /* Try for a max of 1 sec as per spec */

-    for(i=0;i<20;i++)

-    {

-        mmc_ret = mmc_boot_send_app_cmd(0);

-        if( mmc_ret != MMC_BOOT_E_SUCCESS )

-        {

-            return mmc_ret;

-        }

-

-        cmd.cmd_index = ACMD41_SEND_OP_COND;

-        cmd.argument = ocr_cmd_arg;

-        cmd.cmd_type = MMC_BOOT_CMD_BCAST_W_RESP;

-        cmd.resp_type = MMC_BOOT_RESP_R3;

-

-        mmc_ret = mmc_boot_send_command(&cmd);

-        if( mmc_ret != MMC_BOOT_E_SUCCESS )

-        {

-            return mmc_ret;

-        }

-        else if (cmd.resp[0] & MMC_BOOT_SD_DEV_READY)

-        {

-            /* Check for HC */

-            if(cmd.resp[0] & (1 << 30))

-            {

-                card->type = MMC_BOOT_TYPE_SDHC;

-            }

-            else

-            {

-                card->type = MMC_BOOT_TYPE_STD_SD;

-            }

-            break;

-        }

-        mdelay(50);

-    }

-    return MMC_BOOT_E_SUCCESS;

-}

-

-/*

- * Routine to initialize MMC card. It resets a card to idle state, verify operating

- * voltage and set the card inready state.

- */

-static unsigned int mmc_boot_init_card( struct mmc_boot_host* host,

-        struct mmc_boot_card* card )

-{

-    unsigned int mmc_retry = 0;

-    unsigned int mmc_return = MMC_BOOT_E_SUCCESS;

-

-    /* basic check */

-    if( ( host == NULL ) || ( card == NULL ) )

-    {

-        return MMC_BOOT_E_INVAL;

-    }

-

-    /* 1. Card Reset - CMD0 */

-    mmc_return = mmc_boot_reset_cards();

-    if( mmc_return != MMC_BOOT_E_SUCCESS )

-    {

-        dprintf(CRITICAL, "Error No.:%d: Failure resetting MMC cards!\n", mmc_return);

-        return mmc_return;

-    }

-

-    /* 2. Card Initialization process */

-

-    /* Send CMD1 to identify and reject cards that do not match host's VDD range

-       profile. Cards sends its OCR register in response.

-       */

-    mmc_retry = 0;

-    do

-    {

-        mmc_return = mmc_boot_send_op_cond( host, card );

-        /* Card returns busy status. We'll retry again! */

-        if( mmc_return == MMC_BOOT_E_CARD_BUSY )

-        {

-            mmc_retry++;

-            mdelay(1);

-            continue;

-        }

-        else if( mmc_return == MMC_BOOT_E_SUCCESS )

-        {

-            break;

-        }

-        else

-        {

-            dprintf(CRITICAL, "Error No. %d: Failure Initializing MMC Card!\n",

-                    mmc_return );

-

-            /* Check for sD card */

-            mmc_return = mmc_boot_sd_init_card(card);

-            return mmc_return;

-        }

-    }while( mmc_retry < host->cmd_retry );

-

-    /* If card still returned busy status we are out of luck.

-     * Card cannot be initialized */

-    if( mmc_return == MMC_BOOT_E_CARD_BUSY )

-    {

-        dprintf(CRITICAL, "Error No. %d: Card has busy status set. \

-                Initialization not completed\n", mmc_return );

-        return MMC_BOOT_E_CARD_BUSY;

-    }

-    return MMC_BOOT_E_SUCCESS;

-}

-

-

-static unsigned int mmc_boot_set_sd_bus_width(struct mmc_boot_card* card, unsigned int width)

-{

-    struct mmc_boot_command cmd;

-    unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;

-    unsigned int sd_reg;

-

-    mmc_ret = mmc_boot_send_app_cmd(card->rca);

-

-    if( mmc_ret != MMC_BOOT_E_SUCCESS )

-    {

-        return mmc_ret;

-    }

-

-    memset( (struct mmc_boot_command *)&cmd, 0,

-            sizeof(struct mmc_boot_command) );

-

-    /* Send ACMD6 to set bus width */

-    cmd.cmd_index = ACMD6_SET_BUS_WIDTH;

-    /* 10 => 4 bit wide */

-    if ( width == MMC_BOOT_BUS_WIDTH_1_BIT )

-    {

-        cmd.argument = 0;

-    }

-    else if (width == MMC_BOOT_BUS_WIDTH_4_BIT )

-    {

-        cmd.argument = (1<<1);

-    }

-    cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;

-    cmd.resp_type = MMC_BOOT_RESP_R1;

-

-    mmc_ret = mmc_boot_send_command(&cmd);

-

-    if( mmc_ret != MMC_BOOT_E_SUCCESS )

-    {

-        return mmc_ret;

-    }

-

-    /* set MCI_CLK accordingly */

-    sd_reg = readl( MMC_BOOT_MCI_CLK );

-    sd_reg &= ~MMC_BOOT_MCI_CLK_WIDEBUS_MODE;

-    if ( width == MMC_BOOT_BUS_WIDTH_1_BIT )

-    {

-        sd_reg |=  MMC_BOOT_MCI_CLK_WIDEBUS_1_BIT;

-    }

-    else if (width == MMC_BOOT_BUS_WIDTH_4_BIT )

-    {

-        sd_reg |=  MMC_BOOT_MCI_CLK_WIDEBUS_4_BIT;

-    }

-    else if (width == MMC_BOOT_BUS_WIDTH_8_BIT )

-    {

-        sd_reg |=  MMC_BOOT_MCI_CLK_WIDEBUS_8_BIT;

-    }

-    writel( sd_reg, MMC_BOOT_MCI_CLK );

-

-    mdelay(10); // Giving some time to card to stabilize.

-

-    return MMC_BOOT_E_SUCCESS;

-}

-

-static unsigned int mmc_boot_set_sd_hs(struct mmc_boot_host* host, struct mmc_boot_card* card)

-{

-    unsigned char sw_buf[64];

-    unsigned int mmc_ret;

-

-    /* CMD6 is a data transfer command. sD card returns 512 bits of data*/

-    /* Refer 4.3.10 of sD card specification 3.0 */

-    mmc_ret = mmc_boot_read_reg(card,64,CMD6_SWITCH_FUNC,MMC_BOOT_SD_SWITCH_HS,

-                               (unsigned int *)&sw_buf);

-

-    if( mmc_ret != MMC_BOOT_E_SUCCESS )

-    {

-        return mmc_ret;

-    }

-

-    mdelay(1);

-

-    clock_config_mmc(mmc_slot, MMC_CLK_50MHZ);

-

-    host->mclk_rate = MMC_CLK_50MHZ;

-

-    return MMC_BOOT_E_SUCCESS;

-}

-

-/*

- * Performs initialization and identification of all the MMC cards connected

- * to the host.

- */

-

-static unsigned int mmc_boot_init_and_identify_cards( struct mmc_boot_host* host, struct mmc_boot_card* card )

-{

-    unsigned int mmc_return = MMC_BOOT_E_SUCCESS;

-    unsigned int status;

-

-    /* Basic check */

-    if( host == NULL )

-    {

-        return MMC_BOOT_E_INVAL;

-    }

-

-    /* Initialize MMC card structure */

-    card->status = MMC_BOOT_STATUS_INACTIVE;

-    card->rd_block_len = MMC_BOOT_RD_BLOCK_LEN;

-    card->wr_block_len = MMC_BOOT_WR_BLOCK_LEN;

-

-    /* Start initialization process (CMD0 & CMD1) */

-    mmc_return = mmc_boot_init_card( host, card );

-    if( mmc_return != MMC_BOOT_E_SUCCESS )

-    {

-        return mmc_return;

-    }

-

-    /* Identify (CMD2, CMD3 & CMD9) and select the card (CMD7) */

-    mmc_return = mmc_boot_identify_card( host, card );

-    if( mmc_return != MMC_BOOT_E_SUCCESS )

-    {

-        return mmc_return;

-    }

-

-    if(card->type == MMC_BOOT_TYPE_SDHC || card->type == MMC_BOOT_TYPE_STD_SD)

-    {

-        /* Setting sD card to high speed without checking card's capability.

-           Cards that do not support high speed may fail to boot */

-        mmc_return = mmc_boot_set_sd_hs(host, card);

-        if(mmc_return != MMC_BOOT_E_SUCCESS)

-        {

-            return mmc_return;

-        }

-

-        mmc_return = mmc_boot_set_sd_bus_width(card, MMC_BOOT_BUS_WIDTH_4_BIT);

-        if(mmc_return != MMC_BOOT_E_SUCCESS)

-        {

-            dprintf(CRITICAL,"Couldn't set 4bit mode for sD card\n");

-            mmc_return = mmc_boot_set_sd_bus_width(card, MMC_BOOT_BUS_WIDTH_1_BIT);

-            if(mmc_return != MMC_BOOT_E_SUCCESS)

-            {

-                dprintf(CRITICAL, "Error No.%d: Failed in setting bus width!\n",

-                        mmc_return);

-                return mmc_return;

-            }

-        }

-    }

-    else

-    {

-        /* set interface speed */

-        mmc_return = mmc_boot_adjust_interface_speed( host, card );

-        if( mmc_return != MMC_BOOT_E_SUCCESS )

-        {

-            dprintf(CRITICAL, "Error No.%d: Error adjusting interface speed!\n",

-                    mmc_return );

-            return mmc_return;

-        }

-

-        /* enable wide bus */

-        mmc_return = mmc_boot_set_bus_width( card, MMC_BOOT_BUS_WIDTH_4_BIT );

-        if( mmc_return != MMC_BOOT_E_SUCCESS )

-        {

-            dprintf(CRITICAL, "Error No.%d: Failure to set wide bus for Card(RCA:%x)\n",

-                    mmc_return, card->rca );

-            return mmc_return;

-        }

-    }

-

-    /* Just checking whether we're in TRAN state after changing speed and bus width */

-    mmc_return = mmc_boot_get_card_status(card, 0, &status);

-    if(mmc_return != MMC_BOOT_E_SUCCESS)

-    {

-        return mmc_return;

-    }

-

-    if(MMC_BOOT_CARD_STATUS(status) != MMC_BOOT_TRAN_STATE)

-        return MMC_BOOT_E_FAILURE;

-

-    return MMC_BOOT_E_SUCCESS;

-}

-

+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * 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.
+ *   * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER 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.
+ */
 
-void mmc_display_ext_csd(void)

-{

-    dprintf(SPEW,  "part_config: %x\n", ext_csd_buf[179] );

-    dprintf(SPEW,  "erase_group_def: %x\n", ext_csd_buf[175] );

-    dprintf(SPEW,  "user_wp: %x\n", ext_csd_buf[171] );

-}

+#include <string.h>
+#include <stdlib.h>
+#include <debug.h>
+#include <reg.h>
+#include "mmc.h"
+#include <partition_parser.h>
+#include <platform/iomap.h>
+#include <platform/timer.h>
 
+#if MMC_BOOT_ADM
+#include "adm.h"
+#endif
 
+#ifndef NULL
+#define NULL        0
+#endif
 
-void mmc_display_csd(void)

-{

-    dprintf(SPEW,  "erase_grpsize: %d\n", mmc_card.csd.erase_grp_size );

-    dprintf(SPEW,  "erase_grpmult: %d\n", mmc_card.csd.erase_grp_mult );

-    dprintf(SPEW,  "wp_grpsize: %d\n", mmc_card.csd.wp_grp_size );

-    dprintf(SPEW,  "wp_grpen: %d\n", mmc_card.csd.wp_grp_enable );

-    dprintf(SPEW,  "perm_wp: %d\n", mmc_card.csd.perm_wp );

-    dprintf(SPEW,  "temp_wp: %d\n", mmc_card.csd.temp_wp );

-}

+#define MMC_BOOT_DATA_READ     0
+#define MMC_BOOT_DATA_WRITE    1
 
+static unsigned int mmc_boot_fifo_data_transfer(unsigned int *data_ptr,
+						unsigned int data_len,
+						unsigned char direction);
 
+static unsigned int mmc_boot_fifo_read(unsigned int *data_ptr,
+				       unsigned int data_len);
 
-/*

- * Entry point to MMC boot process

- */

-unsigned int mmc_boot_main(unsigned char slot, unsigned int base)

-{

-    unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;

-

-    memset( (struct mmc_boot_host*)&mmc_host, 0, sizeof( struct mmc_boot_host ) );

-    memset( (struct mmc_boot_card*)&mmc_card, 0, sizeof(struct mmc_boot_card) );

-

-    mmc_slot = slot;

-    mmc_boot_mci_base = base;

-

-    /* Initialize necessary data structure and enable/set clock and power */

-    dprintf(SPEW," Initializing MMC host data structure and clock!\n" );

-    mmc_ret = mmc_boot_init( &mmc_host );

-    if( mmc_ret != MMC_BOOT_E_SUCCESS )

-    {

-        dprintf(CRITICAL,  "MMC Boot: Error Initializing MMC Card!!!\n" );

-        return MMC_BOOT_E_FAILURE;

-    }

-

-    /* Initialize and identify cards connected to host */

-    mmc_ret = mmc_boot_init_and_identify_cards( &mmc_host, &mmc_card );

-    if( mmc_ret != MMC_BOOT_E_SUCCESS )

-    {

-        dprintf(CRITICAL, "MMC Boot: Failed detecting MMC/SDC @ slot%d\n",slot);

-        return MMC_BOOT_E_FAILURE;

-    }

-

-    mmc_display_csd();

-    mmc_display_ext_csd();

-

-    mmc_ret = partition_read_table(&mmc_host, &mmc_card);
-    return mmc_ret;

-}

-

-/*

- * MMC write function

- */

-unsigned int mmc_write (unsigned long long data_addr, unsigned int data_len, unsigned int* in)

-{

-    int val = 0;

-    unsigned int write_size = ((unsigned)(0xFFFFFF/512))*512;

-    unsigned offset = 0;

-    unsigned int *sptr = in;

+static unsigned int mmc_boot_fifo_write(unsigned int *data_ptr,
+					unsigned int data_len);
 
-    if(data_len % 512)

-        data_len = ROUND_TO_PAGE(data_len, 511);

+#define ROUND_TO_PAGE(x,y) (((x) + (y)) & (~(y)))
 
-    while(data_len > write_size)

-    {

-        val = mmc_boot_write_to_card( &mmc_host, &mmc_card, \

-                                      data_addr + offset, \

-                                      write_size, sptr);

-        if(val)

-        {

-            return val;

-        }

-

-        sptr += (write_size/sizeof(unsigned));

-        offset += write_size;

-        data_len -= write_size;

-    }

-    if (data_len)

-    {

-        val = mmc_boot_write_to_card( &mmc_host, &mmc_card, \

-                                      data_addr + offset, \

-                                      data_len, sptr);

-    }

-    return val;

-}

+/* data access time unit in ns */
+static const unsigned int taac_unit[] =
+    { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000 };
+/* data access time value x 10 */
+static const unsigned int taac_value[] =
+    { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 };
 
-/*

- * MMC read function

- */

-

-unsigned int mmc_read (unsigned long long data_addr, unsigned int* out, unsigned int data_len)

-{

-    int val = 0;

-    val = mmc_boot_read_from_card( &mmc_host, &mmc_card, data_addr, data_len, out);

-    return val;

-}

-

-/*

- * Function to read registers from MMC or SD card

- */

-static unsigned int mmc_boot_read_reg(struct mmc_boot_card *card,

-                                      unsigned int data_len,

-                                      unsigned int command, unsigned int addr,

-                                      unsigned int *out)

-{

-    struct mmc_boot_command cmd;

-    unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;

-    unsigned int mmc_reg = 0;

-

-    /* Set the FLOW_ENA bit of MCI_CLK register to 1 */

-    mmc_reg = readl( MMC_BOOT_MCI_CLK );

-    mmc_reg |= MMC_BOOT_MCI_CLK_ENA_FLOW ;

-    writel( mmc_reg, MMC_BOOT_MCI_CLK );

-

-    /* 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 );

-    writel( data_len, MMC_BOOT_MCI_DATA_LENGTH );

-

-    /* Set appropriate fields and write the MCI_DATA_CTL register. */

-    /* Set ENABLE bit to 1 to enable the data transfer. */

-    mmc_reg = MMC_BOOT_MCI_DATA_ENABLE | MMC_BOOT_MCI_DATA_DIR | (data_len << MMC_BOOT_MCI_BLKSIZE_POS);

-

-#if MMC_BOOT_ADM

-    mmc_reg |= MMC_BOOT_MCI_DATA_DM_ENABLE;

-#endif

-

-    writel( mmc_reg, MMC_BOOT_MCI_DATA_CTL );

-

-    memset( (struct mmc_boot_command *)&cmd, 0,

-            sizeof(struct mmc_boot_command) );

-

-    cmd.cmd_index = command;

-    cmd.argument = addr;

-    cmd.cmd_type  = MMC_BOOT_CMD_ADDRESS;

-    cmd.resp_type = MMC_BOOT_RESP_R1;

-

-    /* send command */

-    mmc_ret = mmc_boot_send_command( &cmd );

-    if( mmc_ret != MMC_BOOT_E_SUCCESS )

-    {

-        return mmc_ret;

-    }

-

-    /* Read the transfer data from SDCC FIFO. */

-    mmc_ret = mmc_boot_fifo_data_transfer(out, data_len, MMC_BOOT_DATA_READ);

-

-    if( mmc_ret != MMC_BOOT_E_SUCCESS )

-    {

-        dprintf(CRITICAL, "Error No.%d: Failure on data transfer from the \

-                Card(RCA:%x)\n", mmc_ret, card->rca );

-        return mmc_ret;

-    }

-

-    return MMC_BOOT_E_SUCCESS;

-}

-

-/*

- * Function to set/clear power-on write protection for the user area partitions

- */

-static unsigned int mmc_boot_set_clr_power_on_wp_user(struct mmc_boot_card* card,

-                                                      unsigned int addr,

-                                                      unsigned int size,

-                                                      unsigned char set_clear_wp)

-{

-    struct mmc_boot_command cmd;

-    unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;

-    unsigned int wp_group_size, loop_count;

-    unsigned int status;

-

-    memset( (struct mmc_boot_command *)&cmd, 0,

-            sizeof(struct mmc_boot_command) );

-

-    /* Disabling PERM_WP for USER AREA (CMD6) */

-    mmc_ret = mmc_boot_switch_cmd(card, MMC_BOOT_ACCESS_WRITE,

-                                  MMC_BOOT_EXT_USER_WP,

-                                  MMC_BOOT_US_PERM_WP_DIS);

-

-    if(mmc_ret != MMC_BOOT_E_SUCCESS)

-    {

-        return mmc_ret;

-    }

-

-    /* Sending CMD13 to check card status */

-    do

-    {

-        mmc_ret = mmc_boot_get_card_status( card, 0 ,&status);

-        if(MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_TRAN_STATE)

-            break;

-    } while( (mmc_ret == MMC_BOOT_E_SUCCESS) &&

-        (MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_PROG_STATE));

-

-    if( mmc_ret != MMC_BOOT_E_SUCCESS )

-    {

-        return mmc_ret;

-    }

-

-    mmc_ret = mmc_boot_send_ext_cmd (card,ext_csd_buf);

-

-    if(mmc_ret != MMC_BOOT_E_SUCCESS)

-    {

-        return mmc_ret;

-    }

-

-    /* Make sure power-on write protection for user area is not disabled

-       and permanent write protection for user area is not enabled */

-

-    if((IS_BIT_SET_EXT_CSD(MMC_BOOT_EXT_USER_WP, MMC_BOOT_US_PERM_WP_EN)) ||

-       (IS_BIT_SET_EXT_CSD(MMC_BOOT_EXT_USER_WP, MMC_BOOT_US_PWR_WP_DIS)))

-    {

-        return MMC_BOOT_E_FAILURE;

-    }

-

-    if(ext_csd_buf[MMC_BOOT_EXT_ERASE_GROUP_DEF])

-    {

-        /* wp_group_size = 512KB * HC_WP_GRP_SIZE * HC_ERASE_GRP_SIZE.

-           Getting write protect group size in sectors here. */

-

-        wp_group_size = (512*1024) * ext_csd_buf[MMC_BOOT_EXT_HC_WP_GRP_SIZE] *

-                    ext_csd_buf[MMC_BOOT_EXT_HC_ERASE_GRP_SIZE] /

-                    MMC_BOOT_WR_BLOCK_LEN;

-    }

-    else

-    {

-        /* wp_group_size = (WP_GRP_SIZE + 1) * (ERASE_GRP_SIZE + 1)

-                                             * (ERASE_GRP_MULT + 1).

-           This is defined as the number of write blocks directly */

-

-        wp_group_size = (card->csd.erase_grp_size + 1) *

-                    (card->csd.erase_grp_mult + 1) *

-                    (card->csd.wp_grp_size + 1);

-    }

-

-    if(wp_group_size == 0)

-    {

-        return MMC_BOOT_E_FAILURE;

-    }

-

-    /* Setting POWER_ON_WP for USER AREA (CMD6) */

-

-    mmc_ret = mmc_boot_switch_cmd(card, MMC_BOOT_ACCESS_WRITE,

-                                  MMC_BOOT_EXT_USER_WP,

-                                  MMC_BOOT_US_PWR_WP_EN);

-

-    if(mmc_ret != MMC_BOOT_E_SUCCESS)

-    {

-        return mmc_ret;

-    }

-

-    /* Sending CMD13 to check card status */

-    do

-    {

-        mmc_ret = mmc_boot_get_card_status( card, 0 ,&status);

-        if(MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_TRAN_STATE)

-            break;

-    } while( (mmc_ret == MMC_BOOT_E_SUCCESS) &&

-        (MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_PROG_STATE));

-

-    if( mmc_ret != MMC_BOOT_E_SUCCESS )

-    {

-        return mmc_ret;

-    }

-

-    /* Calculating the loop count for sending SET_WRITE_PROTECT (CMD28)

-       or CLEAR_WRITE_PROTECT (CMD29).

-       We are write protecting the partitions in blocks of write protect

-       group sizes only */

-

-    if(size % wp_group_size)

-    {

-        loop_count = (size / wp_group_size) + 1;

-    }

-    else

-    {

-        loop_count = (size / wp_group_size);

-    }

-

-    if(set_clear_wp)

-        cmd.cmd_index = CMD28_SET_WRITE_PROTECT;

-    else

-        cmd.cmd_index = CMD29_CLEAR_WRITE_PROTECT;

-

-    cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;

-    cmd.resp_type = MMC_BOOT_RESP_R1B;

-

-    for (unsigned int i = 0; i < loop_count; i++)

-    {

-        /* Sending CMD28 for each WP group size

-           address is in sectors already */

-        cmd.argument = (addr + (i * wp_group_size));

-

-        mmc_ret = mmc_boot_send_command( &cmd );

-

-        if(mmc_ret != MMC_BOOT_E_SUCCESS)

-        {

-            return mmc_ret;

-        }

-

-        /* Checking ADDR_OUT_OF_RANGE error in CMD28 response */

-        if(IS_ADDR_OUT_OF_RANGE(cmd.resp[0]))

-        {

-            return MMC_BOOT_E_FAILURE;

-        }

-

-        /* Sending CMD13 to check card status */

-        do

-        {

-            mmc_ret = mmc_boot_get_card_status( card, 0 ,&status);

-            if(MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_TRAN_STATE)

-                break;

-        } while( (mmc_ret == MMC_BOOT_E_SUCCESS) &&

-            (MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_PROG_STATE));

-

-        if( mmc_ret != MMC_BOOT_E_SUCCESS )

-        {

-            return mmc_ret;

-        }

-    }

-

-    return MMC_BOOT_E_SUCCESS;

-}

-

-/*

- * Function to get Write Protect status of the given sector

- */

-static unsigned int mmc_boot_get_wp_status (struct mmc_boot_card* card,

-                                            unsigned int sector)

-{

-    unsigned int rc = MMC_BOOT_E_SUCCESS;

-    memset(wp_status_buf, 0, 8);

-

-    rc = mmc_boot_read_reg(card, 8, CMD31_SEND_WRITE_PROT_TYPE, sector,
-                           (unsigned int *) wp_status_buf);

-    return rc;

-}

-

-/*

- * Test Function for setting Write protect for given sector

- */

-static unsigned int mmc_wp(unsigned int sector, unsigned int size,

-                           unsigned char set_clear_wp)

-{

-    unsigned int rc = MMC_BOOT_E_SUCCESS;

-

-    /* Checking whether group write protection feature is available */

-    if(mmc_card.csd.wp_grp_enable)

-    {

-        rc = mmc_boot_get_wp_status(&mmc_card,sector);

-        rc = mmc_boot_set_clr_power_on_wp_user(&mmc_card,sector,size,set_clear_wp);

-        rc = mmc_boot_get_wp_status(&mmc_card,sector);

-        return rc;

-    }

-    else

-        return MMC_BOOT_E_FAILURE;

-}

-

-void mmc_wp_test(void)

-{

-    unsigned int mmc_ret=0;

-    mmc_ret = mmc_wp(0xE06000,0x5000,1);

-}

-

-

-unsigned mmc_get_psn(void)

-{

-	return mmc_card.cid.psn;

+/* data transfer rate in kbit/s */
+static const unsigned int xfer_rate_unit[] =
+    { 100, 1000, 10000, 100000, 0, 0, 0, 0 };
+/* data transfer rate value x 10*/
+static const unsigned int xfer_rate_value[] =
+    { 0, 10, 12, 13, 15, 20, 26, 30, 35, 40, 45, 52, 55, 60, 70, 80 };
+
+unsigned char mmc_slot = 0;
+unsigned int mmc_boot_mci_base = 0;
+
+static unsigned char ext_csd_buf[512];
+static unsigned char wp_status_buf[8];
+
+int mmc_clock_enable_disable(unsigned id, unsigned enable);
+int mmc_clock_get_rate(unsigned id);
+int mmc_clock_set_rate(unsigned id, unsigned rate);
+
+struct mmc_boot_host mmc_host;
+struct mmc_boot_card mmc_card;
+
+static unsigned int mmc_wp(unsigned int addr, unsigned int size,
+			   unsigned char set_clear_wp);
+static unsigned int mmc_boot_send_ext_cmd(struct mmc_boot_card *card,
+					  unsigned char *buf);
+static unsigned int mmc_boot_read_reg(struct mmc_boot_card *card,
+				      unsigned int data_len,
+				      unsigned int command,
+				      unsigned int addr, unsigned int *out);
+
+unsigned int SWAP_ENDIAN(unsigned int val)
+{
+	return ((val & 0xFF) << 24) |
+	    (((val >> 8) & 0xFF) << 16) | (((val >> 16) & 0xFF) << 8) | (val >>
+									 24);
 }
 
-/*

- * Read/write data from/to SDC FIFO.

- */

-static unsigned int mmc_boot_fifo_data_transfer(unsigned int* data_ptr,

-                                                unsigned int  data_len,

-                                                unsigned char direction)

-{

-        unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;

-

-#if MMC_BOOT_ADM

-        adm_result_t ret;

-        adm_dir_t adm_dir;

-

-        if(direction == MMC_BOOT_DATA_READ)

-        {

-                adm_dir = ADM_MMC_READ;

-        }

-        else

-        {

-                adm_dir = ADM_MMC_WRITE;

-        }

-

-        ret = adm_transfer_mmc_data(mmc_slot,

-                                    (unsigned char*) data_ptr,

-                                    data_len,

-                                    adm_dir);

-

-        if(ret != ADM_RESULT_SUCCESS)

-        {

-                dprintf(CRITICAL, "MMC ADM transfer error: %d\n", ret);

-                mmc_ret = MMC_BOOT_E_FAILURE;

-        }

-#else

-

-        if(direction == MMC_BOOT_DATA_READ)

-        {

-                mmc_ret = mmc_boot_fifo_read(data_ptr, data_len);

-        }

-        else

-        {

-                mmc_ret = mmc_boot_fifo_write(data_ptr, data_len);

-        }

-#endif

-        return mmc_ret;

-}

-

-/*

- * Read data to SDC FIFO.

- */

-static unsigned int mmc_boot_fifo_read(unsigned int* mmc_ptr,

-                                       unsigned int  data_len)

-{

-    unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;

-    unsigned int mmc_status = 0;

-    unsigned int mmc_count = 0;

-    unsigned int read_error = MMC_BOOT_MCI_STAT_DATA_CRC_FAIL | \

-                                 MMC_BOOT_MCI_STAT_DATA_TIMEOUT  | \

-                                 MMC_BOOT_MCI_STAT_RX_OVRRUN;

-

-

-    /* 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 */

-

-    do

-    {

-        mmc_ret = MMC_BOOT_E_SUCCESS;

-        mmc_status = readl( MMC_BOOT_MCI_STATUS );

-

-        if( mmc_status & read_error )

-        {

-            mmc_ret = mmc_boot_status_error(mmc_status);

-            break;

-        }

-

-        if( mmc_status & MMC_BOOT_MCI_STAT_RX_DATA_AVLBL )

-        {

-            unsigned read_count = 1;

-            if ( mmc_status & MMC_BOOT_MCI_STAT_RX_FIFO_HFULL)

-            {

-                read_count = MMC_BOOT_MCI_HFIFO_COUNT;

-            }

-

-            for (unsigned int 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_count % MMC_BOOT_MCI_FIFO_SIZE ) );

-                mmc_ptr++;

-                /* increase mmc_count by word size */

-                mmc_count += sizeof( unsigned int );

-            }

-            /* 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;

-        }

-    }while(1);

-

-    return mmc_ret;

-}

-

-/*

- * Write data to SDC FIFO.

- */

-static unsigned int mmc_boot_fifo_write(unsigned int* mmc_ptr,

-                                        unsigned int data_len)

-{

-    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;

-

-

-    /* Write the transfer data to SDCC3 FIFO */

-    do

-    {

-        mmc_ret = MMC_BOOT_E_SUCCESS;

-        mmc_status = readl( MMC_BOOT_MCI_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 ))

-        {

-            for (int i=0; i < MMC_BOOT_MCI_HFIFO_COUNT; i++ )

-            {

-                /* FIFO contains 16 32-bit data buffer on 16 sequential addresses*/

-                writel( *mmc_ptr, MMC_BOOT_MCI_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, MMC_BOOT_MCI_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; //success

-        }

-

-    } while(1);

-    return mmc_ret;

-}

+/* Sets a timeout for read operation.
+ */
+static unsigned int
+mmc_boot_set_read_timeout(struct mmc_boot_host *host,
+			  struct mmc_boot_card *card)
+{
+	unsigned int timeout_ns = 0;
 
-

-/*

- * CMD35_ERASE_GROUP_START

- */

-

-static unsigned int mmc_boot_send_erase_group_start(struct mmc_boot_card* card,

-                                                    unsigned long long data_addr )

-{

-   struct mmc_boot_command cmd;

-   unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;

-

-   if( card == NULL)

-       return MMC_BOOT_E_INVAL;

-

-   memset((struct mmc_boot_command *)&cmd, 0,

-          sizeof(struct mmc_boot_command));

-

-   cmd.cmd_index = CMD35_ERASE_GROUP_START;

-   cmd.argument = data_addr;

-   cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;

-   cmd.resp_type = MMC_BOOT_RESP_R1;

-

-   mmc_ret = mmc_boot_send_command( &cmd );

-   if( mmc_ret != MMC_BOOT_E_SUCCESS )

-   {

-       return mmc_ret;

-   }

-

-   /* Checking for address error */

-   if( IS_ADDR_OUT_OF_RANGE(cmd.resp[0]) )

-   {

-       return MMC_BOOT_E_BLOCKLEN_ERR;

-   }

-

-   return MMC_BOOT_E_SUCCESS;

-

-}

-

-/*

- * CMD36 ERASE GROUP END

- */

-static unsigned int mmc_boot_send_erase_group_end(struct mmc_boot_card* card,

-                                                  unsigned long long data_addr )

-{

-   struct mmc_boot_command cmd;

-   unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;

-

-   if( card == NULL)

-       return MMC_BOOT_E_INVAL;

-

-   memset((struct mmc_boot_command *)&cmd, 0,

-          sizeof(struct mmc_boot_command));

-

-   cmd.cmd_index = CMD36_ERASE_GROUP_END;

-   cmd.argument = data_addr;

-   cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;

-   cmd.resp_type = MMC_BOOT_RESP_R1;

-

-   mmc_ret = mmc_boot_send_command( &cmd );

-   if( mmc_ret != MMC_BOOT_E_SUCCESS )

-   {

-       return mmc_ret;

-   }

-

-   /* Checking for address error */

-   if(IS_ADDR_OUT_OF_RANGE(cmd.resp[0]))

-   {

-       return MMC_BOOT_E_BLOCKLEN_ERR;

-   }

-

-   return MMC_BOOT_E_SUCCESS;

-}

-

-/*

- * CMD38 ERASE

- */

-static unsigned int mmc_boot_send_erase(struct mmc_boot_card* card )

-{

-

-   struct mmc_boot_command cmd;

-   unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;

-   unsigned int status;

-

-   if( card == NULL)

-       return MMC_BOOT_E_INVAL;

-

-   memset((struct mmc_boot_command *)&cmd, 0,

-          sizeof(struct mmc_boot_command));

-

-   cmd.cmd_index = CMD38_ERASE;

-   cmd.argument = 0x00000000;

-   cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;

-   cmd.resp_type = MMC_BOOT_RESP_R1B;

-

-   /* Checking if the card is in the transfer state */

-   do

-   {

-       mmc_ret = mmc_boot_get_card_status( card, 0 ,&status);

-       if(MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_TRAN_STATE)

-           break;

-   } while( (mmc_ret == MMC_BOOT_E_SUCCESS) &&

-               (MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_PROG_STATE));

-

-   if( mmc_ret != MMC_BOOT_E_SUCCESS )

-   {

-       return mmc_ret;

-   }

-   mmc_ret = mmc_boot_send_command( &cmd );

-   if( mmc_ret != MMC_BOOT_E_SUCCESS )

-   {

-       return mmc_ret;

-   }

-

-   /* Checking for write protect */

-   if( cmd.resp[0] & MMC_BOOT_R1_WP_ERASE_SKIP )

-   {

-       dprintf(CRITICAL , "Write protect enabled for sector \n");

-       return;

-   }

-

-   /* Checking if the erase operation for the card is compelete */

-   do

-   {

-       mmc_ret = mmc_boot_get_card_status( card, 0 ,&status);

-       if(MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_TRAN_STATE)

-           break;

-   } while( (mmc_ret == MMC_BOOT_E_SUCCESS) &&

-                (MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_PROG_STATE));

-

-   if( mmc_ret != MMC_BOOT_E_SUCCESS )

-   {

-       return mmc_ret;

-   }

-

-   return MMC_BOOT_E_SUCCESS;

-}

-

-/*

- * Function to erase data on the eMMC card

- */

-unsigned int mmc_erase_card ( unsigned long long data_addr, unsigned long long size)

-{

-    unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;

-    unsigned long long erase_grp_size;

-    unsigned long long data_end = 0x00000000;

-    unsigned long long loop_count;

-    unsigned int out[512] = {0};

-

-    /* Converting size to sectors */

-    size =size /512;

-

-

-    if(ext_csd_buf[MMC_BOOT_EXT_ERASE_GROUP_DEF])

-    {

-        erase_grp_size = (512 * ext_csd_buf[MMC_BOOT_EXT_HC_ERASE_GRP_SIZE]* 1024);

-        erase_grp_size = erase_grp_size/512;

-    }

-    else

-    {

-        erase_grp_size = (mmc_card.csd.erase_grp_size + 1) *

-                         (mmc_card.csd.erase_grp_mult + 1);

-    }

-

-    if( erase_grp_size == 0 )

-    {

-        return MMC_BOOT_E_FAILURE;

-    }

-

-    if(size % erase_grp_size)

-    {

-          dprintf(CRITICAL, "Overflow beyond ERASE_GROUP_SIZE:%llu\n",

-                         (size % erase_grp_size));

-

-    }

-    loop_count = (size / erase_grp_size);

-    /*

-     *In case the partition size is less than the erase_grp_size

-      0 is written to the first block of the partition.

-     */

-    if( loop_count < 1 )

-    {

-        mmc_ret = mmc_write(data_addr, 512 ,(unsigned int *)out);

-        if (mmc_ret != MMC_BOOT_E_SUCCESS)

-            return mmc_ret;

-        else

-            return MMC_BOOT_E_SUCCESS;

-    }

-    else

-    {

-        data_addr = ( (mmc_card.type != MMC_BOOT_TYPE_MMCHC) &&

-                      (mmc_card.type != MMC_BOOT_TYPE_SDHC) )

-                      ? (unsigned int) data_addr :(unsigned int) (data_addr / 512);

-        data_end = data_addr + erase_grp_size * (loop_count-1);

-    }

-

-    /* Sending CMD35 */

-    mmc_ret = mmc_boot_send_erase_group_start (&mmc_card , data_addr);

-    if( mmc_ret != MMC_BOOT_E_SUCCESS)

-    {

-        dprintf(CRITICAL, "Error %d: Failure sending erase group start "

-                          "command to the card (RCA:%x)\n", mmc_ret, mmc_card.rca);

-        return mmc_ret;

-    }

-

-    /* Sending CMD36 */

-    mmc_ret = mmc_boot_send_erase_group_end (&mmc_card , data_end - 1);

-    if( mmc_ret != MMC_BOOT_E_SUCCESS)

-    {

-        dprintf(CRITICAL, "Error %d: Failure sending erase group end "

-                          "command to the card (RCA:%x)\n", mmc_ret, mmc_card.rca);

-        return mmc_ret;

-    }

-

-    for( unsigned long long i = 0; i < loop_count ;i++ )

-    {

-        /* Sending CMD38 */

-        mmc_ret = mmc_boot_send_erase (&mmc_card );

-        if( mmc_ret != MMC_BOOT_E_SUCCESS)

-        {

-            dprintf(CRITICAL, "Error %d: Failure sending erase command "

-                              "to the card (RCA:%x)\n", mmc_ret, mmc_card.rca );

-            return mmc_ret;

-

-        }

-    }

-    dprintf(CRITICAL, "ERASE SUCCESSFULLY COMPLETED\n");

-    return MMC_BOOT_E_SUCCESS;

+	if ((host == NULL) || (card == NULL)) {
+		return MMC_BOOT_E_INVAL;
+	}
+
+	if ((card->type == MMC_BOOT_TYPE_MMCHC)
+	    || (card->type == MMC_BOOT_TYPE_SDHC)) {
+		card->rd_timeout_ns = 100000000;
+	} else if ((card->type == MMC_BOOT_TYPE_STD_SD)
+		   || (card->type == MMC_BOOT_TYPE_STD_MMC)) {
+		timeout_ns = 10 * ((card->csd.taac_ns) +
+				   (card->csd.nsac_clk_cycle /
+				    (host->mclk_rate / 1000000000)));
+		card->rd_timeout_ns = timeout_ns;
+	} else {
+		return MMC_BOOT_E_NOT_SUPPORTED;
+	}
+
+	dprintf(SPEW, " Read timeout set: %d ns\n", card->rd_timeout_ns);
+
+	return MMC_BOOT_E_SUCCESS;
 }
 
-struct mmc_boot_host* get_mmc_host ( void )

-{

-    return &mmc_host;

-}

-

-struct mmc_boot_card* get_mmc_card( void )

-{

-    return &mmc_card;

-}

-

+/* Sets a timeout for write operation.
+ */
+static unsigned int
+mmc_boot_set_write_timeout(struct mmc_boot_host *host,
+			   struct mmc_boot_card *card)
+{
+	unsigned int timeout_ns = 0;
+
+	if ((host == NULL) || (card == NULL)) {
+		return MMC_BOOT_E_INVAL;
+	}
+
+	if ((card->type == MMC_BOOT_TYPE_MMCHC)
+	    || (card->type == MMC_BOOT_TYPE_SDHC)) {
+		card->wr_timeout_ns = 100000000;
+	} else if (card->type == MMC_BOOT_TYPE_STD_SD
+		   || (card->type == MMC_BOOT_TYPE_STD_MMC)) {
+		timeout_ns = 10 * ((card->csd.taac_ns) +
+				   (card->csd.nsac_clk_cycle /
+				    (host->mclk_rate / 1000000000)));
+		timeout_ns = timeout_ns << card->csd.r2w_factor;
+		card->wr_timeout_ns = timeout_ns;
+	} else {
+		return MMC_BOOT_E_NOT_SUPPORTED;
+	}
+
+	dprintf(SPEW, " Write timeout set: %d ns\n", card->wr_timeout_ns);
+
+	return MMC_BOOT_E_SUCCESS;
+}
+
+/*
+ * Decodes CSD response received from the card. Note that we have defined only
+ * few of the CSD elements in csd structure. We'll only decode those values.
+ */
+static unsigned int
+mmc_boot_decode_and_save_csd(struct mmc_boot_card *card, unsigned int *raw_csd)
+{
+	unsigned int mmc_sizeof = 0;
+	unsigned int mmc_unit = 0;
+	unsigned int mmc_value = 0;
+	unsigned int mmc_temp = 0;
+
+	struct mmc_boot_csd mmc_csd;
+
+	if ((card == NULL) || (raw_csd == NULL)) {
+		return MMC_BOOT_E_INVAL;
+	}
+
+	mmc_sizeof = sizeof(unsigned int) * 8;
+
+	mmc_csd.cmmc_structure = UNPACK_BITS(raw_csd, 126, 2, mmc_sizeof);
+
+	if ((card->type == MMC_BOOT_TYPE_SDHC)
+	    || (card->type == MMC_BOOT_TYPE_STD_SD)) {
+		/* Parse CSD according to SD card spec. */
+
+		/* CSD register is little bit differnet for CSD version 2.0 High Capacity
+		 * and CSD version 1.0/2.0 Standard memory cards. In Version 2.0 some of
+		 * the fields have fixed values and it's not necessary for host to refer
+		 * these fields in CSD sent by card */
+
+		if (mmc_csd.cmmc_structure == 1) {
+			/* CSD Version 2.0 */
+			mmc_csd.card_cmd_class =
+			    UNPACK_BITS(raw_csd, 84, 12, mmc_sizeof);
+			mmc_csd.write_blk_len = 512;	/* Fixed value is 9 = 2^9 = 512 */
+			mmc_csd.read_blk_len = 512;	/* Fixed value is 9 = 512 */
+			mmc_csd.r2w_factor = 0x2;	/* Fixed value: 010b */
+			mmc_csd.c_size_mult = 0;	/* not there in version 2.0 */
+			mmc_csd.c_size =
+			    UNPACK_BITS(raw_csd, 48, 22, mmc_sizeof);
+			mmc_csd.nsac_clk_cycle =
+			    UNPACK_BITS(raw_csd, 104, 8, mmc_sizeof) * 100;
+
+//TODO: Investigate the nsac and taac. Spec suggests not using this for timeouts.
+
+			mmc_unit = UNPACK_BITS(raw_csd, 112, 3, mmc_sizeof);
+			mmc_value = UNPACK_BITS(raw_csd, 115, 4, mmc_sizeof);
+			mmc_csd.taac_ns =
+			    (taac_value[mmc_value] * taac_unit[mmc_unit]) / 10;
+
+			mmc_csd.erase_blk_len = 1;
+			mmc_csd.read_blk_misalign = 0;
+			mmc_csd.write_blk_misalign = 0;
+			mmc_csd.read_blk_partial = 0;
+			mmc_csd.write_blk_partial = 0;
+
+			mmc_unit = UNPACK_BITS(raw_csd, 96, 3, mmc_sizeof);
+			mmc_value = UNPACK_BITS(raw_csd, 99, 4, mmc_sizeof);
+			mmc_csd.tran_speed =
+			    (xfer_rate_value[mmc_value] *
+			     xfer_rate_unit[mmc_unit]) / 10;
+
+			mmc_csd.wp_grp_size = 0x0;
+			mmc_csd.wp_grp_enable = 0x0;
+			mmc_csd.perm_wp =
+			    UNPACK_BITS(raw_csd, 13, 1, mmc_sizeof);
+			mmc_csd.temp_wp =
+			    UNPACK_BITS(raw_csd, 12, 1, mmc_sizeof);
+
+			/* Calculate the card capcity */
+			card->capacity = (1 + mmc_csd.c_size) * 512 * 1024;
+		} else {
+			/* CSD Version 1.0 */
+			mmc_csd.card_cmd_class =
+			    UNPACK_BITS(raw_csd, 84, 12, mmc_sizeof);
+
+			mmc_temp = UNPACK_BITS(raw_csd, 22, 4, mmc_sizeof);
+			mmc_csd.write_blk_len = (mmc_temp > 8
+						 && mmc_temp <
+						 12) ? (1 << mmc_temp) : 512;
+
+			mmc_temp = UNPACK_BITS(raw_csd, 80, 4, mmc_sizeof);
+			mmc_csd.read_blk_len = (mmc_temp > 8
+						&& mmc_temp <
+						12) ? (1 << mmc_temp) : 512;
+
+			mmc_unit = UNPACK_BITS(raw_csd, 112, 3, mmc_sizeof);
+			mmc_value = UNPACK_BITS(raw_csd, 115, 4, mmc_sizeof);
+			mmc_csd.taac_ns =
+			    (taac_value[mmc_value] * taac_unit[mmc_unit]) / 10;
+
+			mmc_unit = UNPACK_BITS(raw_csd, 96, 3, mmc_sizeof);
+			mmc_value = UNPACK_BITS(raw_csd, 99, 4, mmc_sizeof);
+			mmc_csd.tran_speed =
+			    (xfer_rate_value[mmc_value] *
+			     xfer_rate_unit[mmc_unit]) / 10;
+
+			mmc_csd.nsac_clk_cycle =
+			    UNPACK_BITS(raw_csd, 104, 8, mmc_sizeof) * 100;
+
+			mmc_csd.r2w_factor =
+			    UNPACK_BITS(raw_csd, 26, 3, mmc_sizeof);
+			mmc_csd.sector_size =
+			    UNPACK_BITS(raw_csd, 39, 7, mmc_sizeof) + 1;
+
+			mmc_csd.erase_blk_len =
+			    UNPACK_BITS(raw_csd, 46, 1, mmc_sizeof);
+			mmc_csd.read_blk_misalign =
+			    UNPACK_BITS(raw_csd, 77, 1, mmc_sizeof);
+			mmc_csd.write_blk_misalign =
+			    UNPACK_BITS(raw_csd, 78, 1, mmc_sizeof);
+			mmc_csd.read_blk_partial =
+			    UNPACK_BITS(raw_csd, 79, 1, mmc_sizeof);
+			mmc_csd.write_blk_partial =
+			    UNPACK_BITS(raw_csd, 21, 1, mmc_sizeof);
+
+			mmc_csd.c_size_mult =
+			    UNPACK_BITS(raw_csd, 47, 3, mmc_sizeof);
+			mmc_csd.c_size =
+			    UNPACK_BITS(raw_csd, 62, 12, mmc_sizeof);
+			mmc_csd.wp_grp_size =
+			    UNPACK_BITS(raw_csd, 32, 7, mmc_sizeof);
+			mmc_csd.wp_grp_enable =
+			    UNPACK_BITS(raw_csd, 31, 1, mmc_sizeof);
+			mmc_csd.perm_wp =
+			    UNPACK_BITS(raw_csd, 13, 1, mmc_sizeof);
+			mmc_csd.temp_wp =
+			    UNPACK_BITS(raw_csd, 12, 1, mmc_sizeof);
+
+			/* Calculate the card capacity */
+			mmc_temp =
+			    (1 << (mmc_csd.c_size_mult + 2)) * (mmc_csd.c_size +
+								1);
+			card->capacity = mmc_temp * mmc_csd.read_blk_len;
+		}
+	} else {
+		/* Parse CSD according to MMC card spec. */
+		mmc_csd.spec_vers = UNPACK_BITS(raw_csd, 122, 4, mmc_sizeof);
+		mmc_csd.card_cmd_class =
+		    UNPACK_BITS(raw_csd, 84, 12, mmc_sizeof);
+		mmc_csd.write_blk_len =
+		    1 << UNPACK_BITS(raw_csd, 22, 4, mmc_sizeof);
+		mmc_csd.read_blk_len =
+		    1 << UNPACK_BITS(raw_csd, 80, 4, mmc_sizeof);
+		mmc_csd.r2w_factor = UNPACK_BITS(raw_csd, 26, 3, mmc_sizeof);
+		mmc_csd.c_size_mult = UNPACK_BITS(raw_csd, 47, 3, mmc_sizeof);
+		mmc_csd.c_size = UNPACK_BITS(raw_csd, 62, 12, mmc_sizeof);
+		mmc_csd.nsac_clk_cycle =
+		    UNPACK_BITS(raw_csd, 104, 8, mmc_sizeof) * 100;
+
+		mmc_unit = UNPACK_BITS(raw_csd, 112, 3, mmc_sizeof);
+		mmc_value = UNPACK_BITS(raw_csd, 115, 4, mmc_sizeof);
+		mmc_csd.taac_ns =
+		    (taac_value[mmc_value] * taac_unit[mmc_unit]) / 10;
+
+		mmc_csd.read_blk_misalign =
+		    UNPACK_BITS(raw_csd, 77, 1, mmc_sizeof);
+		mmc_csd.write_blk_misalign =
+		    UNPACK_BITS(raw_csd, 78, 1, mmc_sizeof);
+		mmc_csd.read_blk_partial =
+		    UNPACK_BITS(raw_csd, 79, 1, mmc_sizeof);
+		mmc_csd.write_blk_partial =
+		    UNPACK_BITS(raw_csd, 21, 1, mmc_sizeof);
+		mmc_csd.tran_speed = 0x00;	/* Ignore -- no use of this value. */
+
+		mmc_csd.erase_grp_size =
+		    UNPACK_BITS(raw_csd, 42, 5, mmc_sizeof);
+		mmc_csd.erase_grp_mult =
+		    UNPACK_BITS(raw_csd, 37, 5, mmc_sizeof);
+		mmc_csd.wp_grp_size = UNPACK_BITS(raw_csd, 32, 5, mmc_sizeof);
+		mmc_csd.wp_grp_enable = UNPACK_BITS(raw_csd, 31, 1, mmc_sizeof);
+		mmc_csd.perm_wp = UNPACK_BITS(raw_csd, 13, 1, mmc_sizeof);
+		mmc_csd.temp_wp = UNPACK_BITS(raw_csd, 12, 1, mmc_sizeof);
+
+		/* Calculate the card capcity */
+		if (mmc_csd.c_size != 0xFFF) {
+			/* For cards less than or equal to 2GB */
+			mmc_temp =
+			    (1 << (mmc_csd.c_size_mult + 2)) * (mmc_csd.c_size +
+								1);
+			card->capacity = mmc_temp * mmc_csd.read_blk_len;
+		} else {
+			/* For cards greater than 2GB, Ext CSD register's SEC_COUNT
+			 * is used to calculate the size.
+			 */
+			unsigned long long sec_count;
+
+			sec_count = (ext_csd_buf[215] << 24) |
+			    (ext_csd_buf[214] << 16) |
+			    (ext_csd_buf[213] << 8) | ext_csd_buf[212];
+
+			card->capacity = sec_count * 512;
+		}
+	}
+
+	/* save the information in card structure */
+	memcpy((struct mmc_boot_csd *)&card->csd,
+	       (struct mmc_boot_csd *)&mmc_csd, sizeof(struct mmc_boot_csd));
+
+	dprintf(SPEW, "Decoded CSD fields:\n");
+	dprintf(SPEW, "cmmc_structure: %d\n", mmc_csd.cmmc_structure);
+	dprintf(SPEW, "card_cmd_class: %x\n", mmc_csd.card_cmd_class);
+	dprintf(SPEW, "write_blk_len: %d\n", mmc_csd.write_blk_len);
+	dprintf(SPEW, "read_blk_len: %d\n", mmc_csd.read_blk_len);
+	dprintf(SPEW, "r2w_factor: %d\n", mmc_csd.r2w_factor);
+	dprintf(SPEW, "sector_size: %d\n", mmc_csd.sector_size);
+	dprintf(SPEW, "c_size_mult:%d\n", mmc_csd.c_size_mult);
+	dprintf(SPEW, "c_size: %d\n", mmc_csd.c_size);
+	dprintf(SPEW, "nsac_clk_cycle: %d\n", mmc_csd.nsac_clk_cycle);
+	dprintf(SPEW, "taac_ns: %d\n", mmc_csd.taac_ns);
+	dprintf(SPEW, "tran_speed: %d kbps\n", mmc_csd.tran_speed);
+	dprintf(SPEW, "erase_blk_len: %d\n", mmc_csd.erase_blk_len);
+	dprintf(SPEW, "read_blk_misalign: %d\n", mmc_csd.read_blk_misalign);
+	dprintf(SPEW, "write_blk_misalign: %d\n", mmc_csd.write_blk_misalign);
+	dprintf(SPEW, "read_blk_partial: %d\n", mmc_csd.read_blk_partial);
+	dprintf(SPEW, "write_blk_partial: %d\n", mmc_csd.write_blk_partial);
+	dprintf(SPEW, "Card Capacity: %llu Bytes\n", card->capacity);
+
+	return MMC_BOOT_E_SUCCESS;
+}
+
+/*
+ * Decode CID sent by the card.
+ */
+static unsigned int
+mmc_boot_decode_and_save_cid(struct mmc_boot_card *card, unsigned int *raw_cid)
+{
+	struct mmc_boot_cid mmc_cid;
+	unsigned int mmc_sizeof = 0;
+	int i = 0;
+
+	if ((card == NULL) || (raw_cid == NULL)) {
+		return MMC_BOOT_E_INVAL;
+	}
+
+	mmc_sizeof = sizeof(unsigned int) * 8;
+
+	if ((card->type == MMC_BOOT_TYPE_SDHC)
+	    || (card->type == MMC_BOOT_TYPE_STD_SD)) {
+		mmc_cid.mid = UNPACK_BITS(raw_cid, 120, 8, mmc_sizeof);
+		mmc_cid.oid = UNPACK_BITS(raw_cid, 104, 16, mmc_sizeof);
+
+		for (i = 0; i < 5; i++) {
+			mmc_cid.pnm[i] = (unsigned char)UNPACK_BITS(raw_cid,
+								    (104 -
+								     8 * (i +
+									  1)),
+								    8,
+								    mmc_sizeof);
+		}
+		mmc_cid.pnm[5] = 0;
+		mmc_cid.pnm[6] = 0;
+
+		mmc_cid.prv = UNPACK_BITS(raw_cid, 56, 8, mmc_sizeof);
+		mmc_cid.psn = UNPACK_BITS(raw_cid, 24, 32, mmc_sizeof);
+		mmc_cid.month = UNPACK_BITS(raw_cid, 8, 4, mmc_sizeof);
+		mmc_cid.year = UNPACK_BITS(raw_cid, 12, 8, mmc_sizeof);
+		mmc_cid.year += 2000;
+	} else {
+		mmc_cid.mid = UNPACK_BITS(raw_cid, 120, 8, mmc_sizeof);
+		mmc_cid.oid = UNPACK_BITS(raw_cid, 104, 16, mmc_sizeof);
+
+		for (i = 0; i < 6; i++) {
+			mmc_cid.pnm[i] = (unsigned char)UNPACK_BITS(raw_cid,
+								    (104 -
+								     8 * (i +
+									  1)),
+								    8,
+								    mmc_sizeof);
+		}
+		mmc_cid.pnm[6] = 0;
+
+		mmc_cid.prv = UNPACK_BITS(raw_cid, 48, 8, mmc_sizeof);
+		mmc_cid.psn = UNPACK_BITS(raw_cid, 16, 32, mmc_sizeof);
+		mmc_cid.month = UNPACK_BITS(raw_cid, 8, 4, mmc_sizeof);
+		mmc_cid.year = UNPACK_BITS(raw_cid, 12, 4, mmc_sizeof);
+		mmc_cid.year += 1997;
+	}
+
+	/* save it in card database */
+	memcpy((struct mmc_boot_cid *)&card->cid,
+	       (struct mmc_boot_cid *)&mmc_cid, sizeof(struct mmc_boot_cid));
+
+	dprintf(SPEW, "Decoded CID fields:\n");
+	dprintf(SPEW, "Manufacturer ID: %x\n", mmc_cid.mid);
+	dprintf(SPEW, "OEM ID: 0x%x\n", mmc_cid.oid);
+	dprintf(SPEW, "Product Name: %s\n", mmc_cid.pnm);
+	dprintf(SPEW, "Product revision: %d.%d\n", (mmc_cid.prv >> 4),
+		(mmc_cid.prv & 0xF));
+	dprintf(SPEW, "Product serial number: %X\n", mmc_cid.psn);
+	dprintf(SPEW, "Manufacturing date: %d %d\n", mmc_cid.month,
+		mmc_cid.year);
+
+	return MMC_BOOT_E_SUCCESS;
+}
+
+/*
+ * Sends specified command to a card and waits for a response.
+ */
+static unsigned int mmc_boot_send_command(struct mmc_boot_command *cmd)
+{
+	unsigned int mmc_cmd = 0;
+	unsigned int mmc_status = 0;
+	unsigned int mmc_resp = 0;
+	unsigned int mmc_return = MMC_BOOT_E_SUCCESS;
+	unsigned int cmd_index = 0;
+	int i = 0;
+
+	/* basic check */
+	if (cmd == NULL) {
+		return MMC_BOOT_E_INVAL;
+	}
+
+	/* 1. Write command argument to MMC_BOOT_MCI_ARGUMENT register */
+	writel(cmd->argument, MMC_BOOT_MCI_ARGUMENT);
+
+	/* Writes to MCI port are not effective for 3 ticks of PCLK.
+	 * The min pclk is 144KHz which gives 6.94 us/tick.
+	 * Thus 21us == 3 ticks.
+	 */
+	udelay(21);
+
+	/* 2. Set appropriate fields and write MMC_BOOT_MCI_CMD */
+	/* 2a. Write command index in CMD_INDEX field */
+	cmd_index = cmd->cmd_index;
+	mmc_cmd |= cmd->cmd_index;
+	/* 2b. Set RESPONSE bit to 1 for all cmds except CMD0 */
+	if (cmd_index != CMD0_GO_IDLE_STATE) {
+		mmc_cmd |= MMC_BOOT_MCI_CMD_RESPONSE;
+	}
+
+	/* 2c. Set LONGRESP bit to 1 for CMD2, CMD9 and CMD10 */
+	if (IS_RESP_136_BITS(cmd->resp_type)) {
+		mmc_cmd |= MMC_BOOT_MCI_CMD_LONGRSP;
+	}
+
+	/* 2d. Set INTERRUPT bit to 1 to disable command timeout */
+
+	/* 2e. Set PENDING bit to 1 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 to 1 */
+	mmc_cmd |= MMC_BOOT_MCI_CMD_ENABLE;
+
+	/* 2g. Set PROG_ENA bit to 1 for CMD12, CMD13 issued at the end of
+	   write data transfer */
+	if ((cmd_index == CMD12_STOP_TRANSMISSION ||
+	     cmd_index == CMD13_SEND_STATUS) && cmd->prg_enabled) {
+		mmc_cmd |= MMC_BOOT_MCI_CMD_PROG_ENA;
+	}
+
+	/* 2h. Set MCIABORT bit to 1 for CMD12 when working with SDIO card */
+	/* 2i. Set CCS_ENABLE bit to 1 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);
+
+	/* 2k. Write to MMC_BOOT_MCI_CMD register */
+	writel(mmc_cmd, MMC_BOOT_MCI_CMD);
+
+	dprintf(SPEW, "Command sent: CMD%d MCI_CMD_REG:%x MCI_ARG:%x\n",
+		cmd_index, mmc_cmd, cmd->argument);
+
+	/* 3. Wait for interrupt or poll on the following bits of MCI_STATUS
+	   register */
+	do {
+		/* 3a. Read MCI_STATUS register */
+		while (readl(MMC_BOOT_MCI_STATUS) &
+		       MMC_BOOT_MCI_STAT_CMD_ACTIVE) ;
+
+		mmc_status = readl(MMC_BOOT_MCI_STATUS);
+
+		/* 3b. CMD_SENT bit supposed to be set to 1 only after CMD0 is sent -
+		   no response required. */
+		if ((cmd->resp_type == MMC_BOOT_RESP_NONE) &&
+		    (mmc_status & MMC_BOOT_MCI_STAT_CMD_SENT)) {
+			break;
+		}
+
+		/* 3c. If CMD_TIMEOUT bit is set then no response was received */
+		else if (mmc_status & MMC_BOOT_MCI_STAT_CMD_TIMEOUT) {
+			mmc_return = MMC_BOOT_E_TIMEOUT;
+			break;
+		}
+		/* 3d. If CMD_RESPONSE_END bit is set to 1 then command's response was
+		   received and CRC check passed
+		   Spcial case for ACMD41: it seems to always fail CRC even if
+		   the response is valid
+		 */
+		else if ((mmc_status & MMC_BOOT_MCI_STAT_CMD_RESP_END)
+			 || (cmd_index == CMD1_SEND_OP_COND)
+			 || (cmd_index == CMD8_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) & 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_BOOT_RESP_R2 ||
+			     cmd->resp_type == MMC_BOOT_RESP_R3 ||
+			     cmd->resp_type == MMC_BOOT_RESP_R6 ||
+			     cmd->resp_type == MMC_BOOT_RESP_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 (IS_RESP_136_BITS(cmd->resp_type)) {
+					for (i = 0; i < 4; i++) {
+						cmd->resp[3 - i] =
+						    readl(MMC_BOOT_MCI_RESP_0 +
+							  (i * 4));
+
+					}
+				} else {
+					cmd->resp[0] =
+					    readl(MMC_BOOT_MCI_RESP_0);
+				}
+			} else {
+				/* command index mis-match */
+				mmc_return = MMC_BOOT_E_CMD_INDX_MISMATCH;
+			}
+
+			dprintf(SPEW, "Command response received: %X\n",
+				cmd->resp[0]);
+			break;
+		}
+
+		/* 3e. If CMD_CRC_FAIL bit is set to 1 then cmd's response was recvd,
+		   but CRC check failed. */
+		else if ((mmc_status & MMC_BOOT_MCI_STAT_CMD_CRC_FAIL)) {
+			if (cmd_index == ACMD41_SEND_OP_COND) {
+				cmd->resp[0] = readl(MMC_BOOT_MCI_RESP_0);
+			} else
+				mmc_return = MMC_BOOT_E_CRC_FAIL;
+			break;
+		}
+
+	}
+	while (1);
+
+	return mmc_return;
+}
+
+/*
+ * Reset all the cards to idle condition (CMD 0)
+ */
+static unsigned int mmc_boot_reset_cards(void)
+{
+	struct mmc_boot_command cmd;
+
+	memset((struct mmc_boot_command *)&cmd, 0,
+	       sizeof(struct mmc_boot_command));
+
+	cmd.cmd_index = CMD0_GO_IDLE_STATE;
+	cmd.argument = 0;	// stuff bits - ignored
+	cmd.cmd_type = MMC_BOOT_CMD_BCAST;
+	cmd.resp_type = MMC_BOOT_RESP_NONE;
+
+	/* send command */
+	return mmc_boot_send_command(&cmd);
+}
+
+/*
+ * Send CMD1 to know whether the card supports host VDD profile or not.
+ */
+static unsigned int
+mmc_boot_send_op_cond(struct mmc_boot_host *host, struct mmc_boot_card *card)
+{
+	struct mmc_boot_command cmd;
+	unsigned int mmc_resp = 0;
+	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
+
+	/* basic check */
+	if ((host == NULL) || (card == NULL)) {
+		return MMC_BOOT_E_INVAL;
+	}
+
+	memset((struct mmc_boot_command *)&cmd, 0,
+	       sizeof(struct mmc_boot_command));
+
+	/* CMD1 format:
+	 * [31] Busy bit
+	 * [30:29] Access mode
+	 * [28:24] reserved
+	 * [23:15] 2.7-3.6
+	 * [14:8]  2.0-2.6
+	 * [7]     1.7-1.95
+	 * [6:0]   reserved
+	 */
+
+	cmd.cmd_index = CMD1_SEND_OP_COND;
+	cmd.argument = host->ocr;
+	cmd.cmd_type = MMC_BOOT_CMD_BCAST_W_RESP;
+	cmd.resp_type = MMC_BOOT_RESP_R3;
+
+	mmc_ret = mmc_boot_send_command(&cmd);
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		return mmc_ret;
+	}
+
+	/* Now it's time to examine response */
+	mmc_resp = cmd.resp[0];
+
+	/* Response contains card's ocr. Update card's information */
+	card->ocr = mmc_resp;
+
+	/* Check the response for busy status */
+	if (!(mmc_resp & MMC_BOOT_OCR_BUSY)) {
+		return MMC_BOOT_E_CARD_BUSY;
+	}
+
+	if (mmc_resp & MMC_BOOT_OCR_SEC_MODE) {
+		card->type = MMC_BOOT_TYPE_MMCHC;
+	} else {
+		card->type = MMC_BOOT_TYPE_STD_MMC;
+	}
+	return MMC_BOOT_E_SUCCESS;
+}
+
+/*
+ * Request any card to send its uniquie card identification (CID) number (CMD2).
+ */
+static unsigned int mmc_boot_all_send_cid(struct mmc_boot_card *card)
+{
+	struct mmc_boot_command cmd;
+	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
+
+	/* basic check */
+	if (card == NULL) {
+		return MMC_BOOT_E_INVAL;
+	}
+
+	memset((struct mmc_boot_command *)&cmd, 0,
+	       sizeof(struct mmc_boot_command));
+
+	/* CMD2 Format:
+	 * [31:0] stuff bits
+	 */
+	cmd.cmd_index = CMD2_ALL_SEND_CID;
+	cmd.argument = 0;
+	cmd.cmd_type = MMC_BOOT_CMD_BCAST_W_RESP;
+	cmd.resp_type = MMC_BOOT_RESP_R2;
+
+	/* send command */
+	mmc_ret = mmc_boot_send_command(&cmd);
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		return mmc_ret;
+	}
+
+	/* Response contains card's 128 bits CID register */
+	mmc_ret = mmc_boot_decode_and_save_cid(card, cmd.resp);
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		return mmc_ret;
+	}
+	return MMC_BOOT_E_SUCCESS;
+}
+
+/*
+ * Ask any card to send it's relative card address (RCA).This RCA number is
+ * shorter than CID and is used by the host to address the card in future (CMD3)
+ */
+static unsigned int mmc_boot_send_relative_address(struct mmc_boot_card *card)
+{
+	struct mmc_boot_command cmd;
+	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
+
+	/* basic check */
+	if (card == NULL) {
+		return MMC_BOOT_E_INVAL;
+	}
+
+	memset((struct mmc_boot_command *)&cmd, 0,
+	       sizeof(struct mmc_boot_command));
+
+	/* CMD3 Format:
+	 * [31:0] stuff bits
+	 */
+	if (card->type == MMC_BOOT_TYPE_SDHC
+	    || card->type == MMC_BOOT_TYPE_STD_SD) {
+		cmd.cmd_index = CMD3_SEND_RELATIVE_ADDR;
+		cmd.argument = 0;
+		cmd.cmd_type = MMC_BOOT_CMD_BCAST_W_RESP;
+		cmd.resp_type = MMC_BOOT_RESP_R6;
+
+		/* send command */
+		mmc_ret = mmc_boot_send_command(&cmd);
+		if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+			return mmc_ret;
+		}
+		/* For sD, card will send RCA. Store it */
+		card->rca = (cmd.resp[0] >> 16);
+	} else {
+		cmd.cmd_index = CMD3_SEND_RELATIVE_ADDR;
+		cmd.argument = (MMC_RCA << 16);
+		card->rca = (cmd.argument >> 16);
+		cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;
+		cmd.resp_type = MMC_BOOT_RESP_R1;
+
+		/* send command */
+		mmc_ret = mmc_boot_send_command(&cmd);
+		if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+			return mmc_ret;
+		}
+	}
+
+	return MMC_BOOT_E_SUCCESS;
+}
+
+/*
+ * Requests card to send it's CSD register's contents. (CMD9)
+ */
+static unsigned int
+mmc_boot_send_csd(struct mmc_boot_card *card, unsigned int *raw_csd)
+{
+	struct mmc_boot_command cmd;
+	unsigned int mmc_arg = 0;
+	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
+
+	/* basic check */
+	if (card == NULL) {
+		return MMC_BOOT_E_INVAL;
+	}
+
+	memset((struct mmc_boot_command *)&cmd, 0,
+	       sizeof(struct mmc_boot_command));
+
+	/* CMD9 Format:
+	 * [31:16] RCA
+	 * [15:0] stuff bits
+	 */
+	mmc_arg |= card->rca << 16;
+
+	cmd.cmd_index = CMD9_SEND_CSD;
+	cmd.argument = mmc_arg;
+	cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;
+	cmd.resp_type = MMC_BOOT_RESP_R2;
+
+	/* send command */
+	mmc_ret = mmc_boot_send_command(&cmd);
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		return mmc_ret;
+	}
+
+	/* response contains the card csd */
+	memcpy(raw_csd, cmd.resp, sizeof(cmd.resp));
+
+	return MMC_BOOT_E_SUCCESS;
+}
+
+/*
+ * Selects a card by sending CMD7 to the card with its RCA.
+ * If RCA field is set as 0 ( or any other address ),
+ * the card will be de-selected. (CMD7)
+ */
+static unsigned int
+mmc_boot_select_card(struct mmc_boot_card *card, unsigned int rca)
+{
+	struct mmc_boot_command cmd;
+	unsigned int mmc_arg = 0;
+	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
+
+	/* basic check */
+	if (card == NULL) {
+		return MMC_BOOT_E_INVAL;
+	}
+
+	memset((struct mmc_boot_command *)&cmd, 0,
+	       sizeof(struct mmc_boot_command));
+
+	/* CMD7 Format:
+	 * [31:16] RCA
+	 * [15:0] stuff bits
+	 */
+	mmc_arg |= rca << 16;
+
+	cmd.cmd_index = CMD7_SELECT_DESELECT_CARD;
+	cmd.argument = mmc_arg;
+	cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;
+	/* If we are deselecting card, we do not get response */
+	if (rca == card->rca && rca) {
+		if (card->type == MMC_BOOT_TYPE_SDHC
+		    || card->type == MMC_BOOT_TYPE_STD_SD)
+			cmd.resp_type = MMC_BOOT_RESP_R1B;
+		else
+			cmd.resp_type = MMC_BOOT_RESP_R1;
+	} else {
+		cmd.resp_type = MMC_BOOT_RESP_NONE;
+	}
+
+	/* send command */
+	mmc_ret = mmc_boot_send_command(&cmd);
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		return mmc_ret;
+	}
+
+	/* As of now no need to look into a response. If it's required
+	 * we'll explore later on */
+
+	return MMC_BOOT_E_SUCCESS;
+}
+
+/*
+ * Send command to set block length.
+ */
+static unsigned int
+mmc_boot_set_block_len(struct mmc_boot_card *card, unsigned int block_len)
+{
+	struct mmc_boot_command cmd;
+	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
+
+	/* basic check */
+	if (card == NULL) {
+		return MMC_BOOT_E_INVAL;
+	}
+
+	memset((struct mmc_boot_command *)&cmd, 0,
+	       sizeof(struct mmc_boot_command));
+
+	/* CMD16 Format:
+	 * [31:0] block length
+	 */
+
+	cmd.cmd_index = CMD16_SET_BLOCKLEN;
+	cmd.argument = block_len;
+	cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;
+	cmd.resp_type = MMC_BOOT_RESP_R1;
+
+	/* send command */
+	mmc_ret = mmc_boot_send_command(&cmd);
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		return mmc_ret;
+	}
+
+	/* If blocklength is larger than 512 bytes,
+	 * the card sets BLOCK_LEN_ERROR bit. */
+	if (cmd.resp[0] & MMC_BOOT_R1_BLOCK_LEN_ERR) {
+		return MMC_BOOT_E_BLOCKLEN_ERR;
+	}
+	return MMC_BOOT_E_SUCCESS;
+}
+
+/*
+ * Requests the card to stop transmission of data.
+ */
+static unsigned int
+mmc_boot_send_stop_transmission(struct mmc_boot_card *card,
+				unsigned int prg_enabled)
+{
+	struct mmc_boot_command cmd;
+	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
+
+	/* basic check */
+	if (card == NULL) {
+		return MMC_BOOT_E_INVAL;
+	}
+
+	memset((struct mmc_boot_command *)&cmd, 0,
+	       sizeof(struct mmc_boot_command));
+
+	/* CMD12 Format:
+	 * [31:0] stuff bits
+	 */
+
+	cmd.cmd_index = CMD12_STOP_TRANSMISSION;
+	cmd.argument = 0;
+	cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;
+	cmd.resp_type = MMC_BOOT_RESP_R1B;
+	cmd.xfer_mode = MMC_BOOT_XFER_MODE_BLOCK;
+	cmd.prg_enabled = prg_enabled;
+
+	/* send command */
+	mmc_ret = mmc_boot_send_command(&cmd);
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		return mmc_ret;
+	}
+	return MMC_BOOT_E_SUCCESS;
+}
+
+/*
+ * Get the card's current status
+ */
+static unsigned int
+mmc_boot_get_card_status(struct mmc_boot_card *card,
+			 unsigned int prg_enabled, unsigned int *status)
+{
+	struct mmc_boot_command cmd;
+	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
+
+	/* basic check */
+	if (card == NULL) {
+		return MMC_BOOT_E_INVAL;
+	}
+
+	memset((struct mmc_boot_command *)&cmd, 0,
+	       sizeof(struct mmc_boot_command));
+
+	/* CMD13 Format:
+	 * [31:16] RCA
+	 * [15:0] stuff bits
+	 */
+	cmd.cmd_index = CMD13_SEND_STATUS;
+	cmd.argument = card->rca << 16;
+	cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;
+	cmd.resp_type = MMC_BOOT_RESP_R1;
+	cmd.prg_enabled = prg_enabled;
+
+	/* send command */
+	mmc_ret = mmc_boot_send_command(&cmd);
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		return mmc_ret;
+	}
+
+	/* Checking ADDR_OUT_OF_RANGE error in CMD13 response */
+	if (IS_ADDR_OUT_OF_RANGE(cmd.resp[0])) {
+		return MMC_BOOT_E_FAILURE;
+	}
+
+	*status = cmd.resp[0];
+	return MMC_BOOT_E_SUCCESS;
+}
+
+/*
+ * Decode type of error caused during read and write
+ */
+static unsigned int mmc_boot_status_error(unsigned mmc_status)
+{
+	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
+
+	/* 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) {
+		mmc_ret = MMC_BOOT_E_DATA_CRC_FAIL;
+	}
+	/* If DATA_TIMEOUT bit is set to 1 then the data transfer time exceeded
+	   the data timeout period without completing the transfer */
+	else if (mmc_status & MMC_BOOT_MCI_STAT_DATA_TIMEOUT) {
+		mmc_ret = MMC_BOOT_E_DATA_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. */
+	else 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 */
+		mmc_ret = MMC_BOOT_E_RX_OVRRUN;
+	}
+	/* 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. */
+	else 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 */
+		mmc_ret = MMC_BOOT_E_RX_OVRRUN;
+	}
+	return mmc_ret;
+}
+
+/*
+ * Send ext csd command.
+ */
+static unsigned int
+mmc_boot_send_ext_cmd(struct mmc_boot_card *card, unsigned char *buf)
+{
+	struct mmc_boot_command cmd;
+	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
+	unsigned int mmc_reg = 0;
+	unsigned int *mmc_ptr = (unsigned int *)buf;
+
+	memset(buf, 0, 512);
+
+	/* basic check */
+	if (card == NULL) {
+		return MMC_BOOT_E_INVAL;
+	}
+
+	/* set block len */
+	if ((card->type != MMC_BOOT_TYPE_MMCHC)
+	    && (card->type != MMC_BOOT_TYPE_SDHC)) {
+		mmc_ret = mmc_boot_set_block_len(card, 512);
+		if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+			dprintf(CRITICAL,
+				"Error No.%d: Failure setting block length for Card (RCA:%s)\n",
+				mmc_ret, (char *)(card->rca));
+			return mmc_ret;
+		}
+	}
+
+	/* Set the FLOW_ENA bit of MCI_CLK register to 1 */
+	mmc_reg = readl(MMC_BOOT_MCI_CLK);
+	mmc_reg |= MMC_BOOT_MCI_CLK_ENA_FLOW;
+	writel(mmc_reg, MMC_BOOT_MCI_CLK);
+
+	/* 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);
+	writel(512, MMC_BOOT_MCI_DATA_LENGTH);
+
+	/* Set appropriate fields and write the MCI_DATA_CTL register. */
+	/* Set ENABLE bit to 1 to enable the data transfer. */
+	mmc_reg =
+	    MMC_BOOT_MCI_DATA_ENABLE | MMC_BOOT_MCI_DATA_DIR | (512 <<
+								MMC_BOOT_MCI_BLKSIZE_POS);
+
+#if MMC_BOOT_ADM
+	mmc_reg |= MMC_BOOT_MCI_DATA_DM_ENABLE;
+#endif
+
+	writel(mmc_reg, MMC_BOOT_MCI_DATA_CTL);
+
+	memset((struct mmc_boot_command *)&cmd, 0,
+	       sizeof(struct mmc_boot_command));
+	/* CMD8 */
+	cmd.cmd_index = CMD8_SEND_EXT_CSD;
+	cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;
+	cmd.resp_type = MMC_BOOT_RESP_R1;
+	cmd.xfer_mode = MMC_BOOT_XFER_MODE_BLOCK;
+
+	/* send command */
+	mmc_ret = mmc_boot_send_command(&cmd);
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		return mmc_ret;
+	}
+
+	/* Read the transfer data from SDCC FIFO. */
+	mmc_ret = mmc_boot_fifo_data_transfer(mmc_ptr, 512, MMC_BOOT_DATA_READ);
+
+	return mmc_ret;
+}
+
+/*
+ * Switch command
+ */
+static unsigned int
+mmc_boot_switch_cmd(struct mmc_boot_card *card,
+		    unsigned access, unsigned index, unsigned value)
+{
+
+	struct mmc_boot_command cmd;
+	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
+
+	/* basic check */
+	if (card == NULL) {
+		return MMC_BOOT_E_INVAL;
+	}
+
+	memset((struct mmc_boot_command *)&cmd, 0,
+	       sizeof(struct mmc_boot_command));
+
+	/* CMD6 Format:
+	 * [31:26] set to 0
+	 * [25:24] access
+	 * [23:16] index
+	 * [15:8] value
+	 * [7:3] set to 0
+	 * [2:0] cmd set
+	 */
+	cmd.cmd_index = CMD6_SWITCH_FUNC;
+	cmd.argument |= (access << 24);
+	cmd.argument |= (index << 16);
+	cmd.argument |= (value << 8);
+	cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;
+	cmd.resp_type = MMC_BOOT_RESP_R1B;
+
+	mmc_ret = mmc_boot_send_command(&cmd);
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		return mmc_ret;
+	}
+
+	return MMC_BOOT_E_SUCCESS;
+}
+
+/*
+ * A command to set the data bus width for card. Set width to either
+ */
+static unsigned int
+mmc_boot_set_bus_width(struct mmc_boot_card *card, unsigned int width)
+{
+	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
+	unsigned int mmc_reg = 0;
+	unsigned int mmc_width = 0;
+	unsigned int status;
+	unsigned int wait_count = 100;
+
+	if (width != MMC_BOOT_BUS_WIDTH_1_BIT) {
+		mmc_width = width - 1;
+	}
+
+	mmc_ret = mmc_boot_switch_cmd(card, MMC_BOOT_ACCESS_WRITE,
+				      MMC_BOOT_EXT_CMMC_BUS_WIDTH, mmc_width);
+
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		return mmc_ret;
+	}
+
+	/* Wait for the card to complete the switch command processing */
+	do {
+		mmc_ret = mmc_boot_get_card_status(card, 0, &status);
+		if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+			return mmc_ret;
+		}
+
+		wait_count--;
+		if (wait_count == 0) {
+			return MMC_BOOT_E_FAILURE;
+		}
+	}
+	while (MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_PROG_STATE);
+
+	/* set MCI_CLK accordingly */
+	mmc_reg = readl(MMC_BOOT_MCI_CLK);
+	mmc_reg &= ~MMC_BOOT_MCI_CLK_WIDEBUS_MODE;
+	if (width == MMC_BOOT_BUS_WIDTH_1_BIT) {
+		mmc_reg |= MMC_BOOT_MCI_CLK_WIDEBUS_1_BIT;
+	} else if (width == MMC_BOOT_BUS_WIDTH_4_BIT) {
+		mmc_reg |= MMC_BOOT_MCI_CLK_WIDEBUS_4_BIT;
+	} else if (width == MMC_BOOT_BUS_WIDTH_8_BIT) {
+		mmc_reg |= MMC_BOOT_MCI_CLK_WIDEBUS_8_BIT;
+	}
+	writel(mmc_reg, MMC_BOOT_MCI_CLK);
+
+	mdelay(10);		// Giving some time to card to stabilize.
+
+	return MMC_BOOT_E_SUCCESS;
+}
+
+/*
+ * A command to start data read from card. Either a single block or
+ * multiple blocks can be read. Multiple blocks read will continuously
+ * transfer data from card to host unless requested to stop by issuing
+ * CMD12 - STOP_TRANSMISSION.
+ */
+static unsigned int
+mmc_boot_send_read_command(struct mmc_boot_card *card,
+			   unsigned int xfer_type, unsigned int data_addr)
+{
+	struct mmc_boot_command cmd;
+	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
+
+	/* basic check */
+	if (card == NULL) {
+		return MMC_BOOT_E_INVAL;
+	}
+
+	memset((struct mmc_boot_command *)&cmd, 0,
+	       sizeof(struct mmc_boot_command));
+
+	/* CMD17/18 Format:
+	 * [31:0] Data Address
+	 */
+	if (xfer_type == MMC_BOOT_XFER_MULTI_BLOCK) {
+		cmd.cmd_index = CMD18_READ_MULTIPLE_BLOCK;
+	} else {
+		cmd.cmd_index = CMD17_READ_SINGLE_BLOCK;
+	}
+
+	cmd.argument = data_addr;
+	cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;
+	cmd.resp_type = MMC_BOOT_RESP_R1;
+
+	/* send command */
+	mmc_ret = mmc_boot_send_command(&cmd);
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		return mmc_ret;
+	}
+
+	/* Response contains 32 bit Card status. Here we'll check
+	   BLOCK_LEN_ERROR and ADDRESS_ERROR */
+	if (cmd.resp[0] & MMC_BOOT_R1_BLOCK_LEN_ERR) {
+		return MMC_BOOT_E_BLOCKLEN_ERR;
+	}
+	/* Misaligned address not matching block length */
+	if (cmd.resp[0] & MMC_BOOT_R1_ADDR_ERR) {
+		return MMC_BOOT_E_ADDRESS_ERR;
+	}
+
+	return MMC_BOOT_E_SUCCESS;
+}
+
+/*
+ * A command to start data write to card. Either a single block or
+ * multiple blocks can be written. Multiple block write will continuously
+ * transfer data from host to card unless requested to stop by issuing
+ * CMD12 - STOP_TRANSMISSION.
+ */
+static unsigned int
+mmc_boot_send_write_command(struct mmc_boot_card *card,
+			    unsigned int xfer_type, unsigned int data_addr)
+{
+	struct mmc_boot_command cmd;
+	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
+
+	/* basic check */
+	if (card == NULL) {
+		return MMC_BOOT_E_INVAL;
+	}
+
+	memset((struct mmc_boot_command *)&cmd, 0,
+	       sizeof(struct mmc_boot_command));
+
+	/* CMD24/25 Format:
+	 * [31:0] Data Address
+	 */
+	if (xfer_type == MMC_BOOT_XFER_MULTI_BLOCK) {
+		cmd.cmd_index = CMD25_WRITE_MULTIPLE_BLOCK;
+	} else {
+		cmd.cmd_index = CMD24_WRITE_SINGLE_BLOCK;
+	}
+
+	cmd.argument = data_addr;
+	cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;
+	cmd.resp_type = MMC_BOOT_RESP_R1;
+
+	/* send command */
+	mmc_ret = mmc_boot_send_command(&cmd);
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		return mmc_ret;
+	}
+
+	/* Response contains 32 bit Card status. Here we'll check
+	   BLOCK_LEN_ERROR and ADDRESS_ERROR */
+	if (cmd.resp[0] & MMC_BOOT_R1_BLOCK_LEN_ERR) {
+		return MMC_BOOT_E_BLOCKLEN_ERR;
+	}
+	/* Misaligned address not matching block length */
+	if (cmd.resp[0] & MMC_BOOT_R1_ADDR_ERR) {
+		return MMC_BOOT_E_ADDRESS_ERR;
+	}
+
+	return MMC_BOOT_E_SUCCESS;
+}
+
+/*
+ * Write data_len data to address specified by data_addr. data_len is
+ * multiple of blocks for block data transfer.
+ */
+unsigned int
+mmc_boot_write_to_card(struct mmc_boot_host *host,
+		       struct mmc_boot_card *card,
+		       unsigned long long data_addr,
+		       unsigned int data_len, unsigned int *in)
+{
+	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
+	unsigned int mmc_status = 0;
+	unsigned int mmc_reg = 0;
+	unsigned int addr;
+	unsigned int xfer_type;
+	unsigned int status;
+
+	if ((host == NULL) || (card == NULL)) {
+		return MMC_BOOT_E_INVAL;
+	}
+
+	/* Set block length. High Capacity MMC/SD card uses fixed 512 bytes block
+	   length. So no need to send CMD16. */
+	if ((card->type != MMC_BOOT_TYPE_MMCHC)
+	    && (card->type != MMC_BOOT_TYPE_SDHC)) {
+		mmc_ret = mmc_boot_set_block_len(card, card->wr_block_len);
+		if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+			dprintf(CRITICAL, "Error No.%d: Failure setting block length for Card\
+                    (RCA:%s)\n", mmc_ret,
+				(char *)(card->rca));
+			return mmc_ret;
+		}
+	}
+
+	/* use multi-block mode to transfer for data larger than a block */
+	xfer_type =
+	    (data_len >
+	     card->
+	     rd_block_len) ? MMC_BOOT_XFER_MULTI_BLOCK :
+	    MMC_BOOT_XFER_SINGLE_BLOCK;
+
+	/* For MMCHC/SDHC data address is specified in unit of 512B */
+	addr = ((card->type != MMC_BOOT_TYPE_MMCHC)
+		&& (card->type !=
+		    MMC_BOOT_TYPE_SDHC)) ? (unsigned int)data_addr : (unsigned
+								      int)
+	    (data_addr / 512);
+
+	/* Set the FLOW_ENA bit of MCI_CLK register to 1 */
+	mmc_reg = readl(MMC_BOOT_MCI_CLK);
+	mmc_reg |= MMC_BOOT_MCI_CLK_ENA_FLOW;
+	writel(mmc_reg, MMC_BOOT_MCI_CLK);
+
+	/* Write data timeout period to MCI_DATA_TIMER register */
+	/* Data timeout period should be in card bus clock periods */
+	/*TODO: Fix timeout value */
+	mmc_reg = 0xFFFFFFFF;
+	writel(mmc_reg, MMC_BOOT_MCI_DATA_TIMER);
+
+	/* Write the total size of the transfer data to MCI_DATA_LENGTH register */
+	writel(data_len, MMC_BOOT_MCI_DATA_LENGTH);
+
+	/* Send command to the card/device in order to start the write data xfer.
+	   The possible commands are CMD24/25/53/60/61 */
+	mmc_ret = mmc_boot_send_write_command(card, xfer_type, addr);
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		dprintf(CRITICAL, "Error No.%d: Failure sending write command to the\
+                Card(RCA:%x)\n", mmc_ret,
+			card->rca);
+		return mmc_ret;
+	}
+
+	/* Set appropriate fields and write the MCI_DATA_CTL register */
+	/* Set ENABLE bit to 1 to enable the data transfer. */
+	mmc_reg = 0;
+	mmc_reg |= MMC_BOOT_MCI_DATA_ENABLE;
+	/* Clear DIRECTION bit to 0 to enable transfer from host to card */
+	/* Clear MODE bit to 0 to enable block oriented data transfer. For
+	   MMC cards only, if stream data transfer mode is desired, set
+	   MODE bit to 1. */
+
+	/* Set DM_ENABLE bit to 1 in order to enable DMA, otherwise set 0 */
+
+#if MMC_BOOT_ADM
+	mmc_reg |= MMC_BOOT_MCI_DATA_DM_ENABLE;
+#endif
+
+	/* Write size of block to be used during the data transfer to
+	   BLOCKSIZE field */
+	mmc_reg |= card->wr_block_len << MMC_BOOT_MCI_BLKSIZE_POS;
+	writel(mmc_reg, MMC_BOOT_MCI_DATA_CTL);
+
+	/* write data to FIFO */
+	mmc_ret =
+	    mmc_boot_fifo_data_transfer(in, data_len, MMC_BOOT_DATA_WRITE);
+
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		dprintf(CRITICAL, "Error No.%d: Failure on data transfer from the \
+                Card(RCA:%x)\n", mmc_ret,
+			card->rca);
+		/* In case of any failure happening for multi block transfer */
+		if (xfer_type == MMC_BOOT_XFER_MULTI_BLOCK)
+			mmc_boot_send_stop_transmission(card, 1);
+		return mmc_ret;
+	}
+
+	/* Send command to the card/device in order to poll the de-assertion of
+	   card/device BUSY condition. It is important to set PROG_ENA bit in
+	   MCI_CLK register before sending the command. Possible commands are
+	   CMD12/13. */
+	if (xfer_type == MMC_BOOT_XFER_MULTI_BLOCK) {
+		mmc_ret = mmc_boot_send_stop_transmission(card, 1);
+		if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+			dprintf(CRITICAL, "Error No.%d: Failure sending Stop Transmission \
+                    command to the Card(RCA:%x)\n", mmc_ret,
+				card->rca);
+			return mmc_ret;
+		}
+	} else {
+		mmc_ret = mmc_boot_get_card_status(card, 1, &status);
+		if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+			dprintf(CRITICAL,
+				"Error No.%d: Failure getting card status of Card(RCA:%x)\n",
+				mmc_ret, card->rca);
+			return mmc_ret;
+		}
+	}
+
+	/* Wait for interrupt or poll on PROG_DONE bit of MCI_STATUS register. If
+	   PROG_DONE bit is set to 1 it means that the card finished it programming
+	   and stopped driving DAT0 line to 0 */
+	do {
+		mmc_status = readl(MMC_BOOT_MCI_STATUS);
+		if (mmc_status & MMC_BOOT_MCI_STAT_PROG_DONE) {
+			break;
+		}
+	}
+	while (1);
+
+	return MMC_BOOT_E_SUCCESS;
+}
+
+/*
+ * Adjust the interface speed to optimal speed
+ */
+static unsigned int
+mmc_boot_adjust_interface_speed(struct mmc_boot_host *host,
+				struct mmc_boot_card *card)
+{
+	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
+	unsigned int status;
+	unsigned int wait_count = 100;
+
+	/* Setting HS_TIMING in EXT_CSD (CMD6) */
+	mmc_ret = mmc_boot_switch_cmd(card, MMC_BOOT_ACCESS_WRITE,
+				      MMC_BOOT_EXT_CMMC_HS_TIMING, 1);
+
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		return mmc_ret;
+	}
+
+	/* Wait for the card to complete the switch command processing */
+	do {
+		mmc_ret = mmc_boot_get_card_status(card, 0, &status);
+		if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+			return mmc_ret;
+		}
+
+		wait_count--;
+		if (wait_count == 0) {
+			return MMC_BOOT_E_FAILURE;
+		}
+	}
+	while (MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_PROG_STATE);
+
+	clock_config_mmc(mmc_slot, MMC_CLK_50MHZ);
+
+	host->mclk_rate = MMC_CLK_50MHZ;
+
+	return MMC_BOOT_E_SUCCESS;
+}
+
+static unsigned int
+mmc_boot_set_block_count(struct mmc_boot_card *card, unsigned int block_count)
+{
+	struct mmc_boot_command cmd;
+	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
+
+	/* basic check */
+	if (card == NULL) {
+		return MMC_BOOT_E_INVAL;
+	}
+
+	memset((struct mmc_boot_command *)&cmd, 0,
+	       sizeof(struct mmc_boot_command));
+
+	/* CMD23 Format:
+	 * [15:0] number of blocks
+	 */
+
+	cmd.cmd_index = CMD23_SET_BLOCK_COUNT;
+	cmd.argument = block_count;
+	cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;
+	cmd.resp_type = MMC_BOOT_RESP_R1;
+
+	/* send command */
+	mmc_ret = mmc_boot_send_command(&cmd);
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		return mmc_ret;
+	}
+
+	if (cmd.resp[0] & MMC_BOOT_R1_OUT_OF_RANGE) {
+		return MMC_BOOT_E_BLOCKLEN_ERR;
+	}
+
+	return MMC_BOOT_E_SUCCESS;
+}
+
+/*
+ * Reads a data of data_len from the address specified. data_len
+ * should be multiple of block size for block data transfer.
+ */
+unsigned int
+mmc_boot_read_from_card(struct mmc_boot_host *host,
+			struct mmc_boot_card *card,
+			unsigned long long data_addr,
+			unsigned int data_len, unsigned int *out)
+{
+	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
+	unsigned int mmc_reg = 0;
+	unsigned int xfer_type;
+	unsigned int addr = 0;
+	unsigned char open_ended_read = 1;
+
+	if ((host == NULL) || (card == NULL)) {
+		return MMC_BOOT_E_INVAL;
+	}
+
+	/* Set block length. High Capacity MMC/SD card uses fixed 512 bytes block
+	   length. So no need to send CMD16. */
+	if ((card->type != MMC_BOOT_TYPE_MMCHC)
+	    && (card->type != MMC_BOOT_TYPE_SDHC)) {
+		mmc_ret = mmc_boot_set_block_len(card, card->rd_block_len);
+		if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+			dprintf(CRITICAL,
+				"Error No.%d: Failure setting block length for Card (RCA:%s)\n",
+				mmc_ret, (char *)(card->rca));
+			return mmc_ret;
+		}
+	}
+
+	/* use multi-block mode to transfer for data larger than a block */
+	xfer_type =
+	    (data_len >
+	     card->
+	     rd_block_len) ? MMC_BOOT_XFER_MULTI_BLOCK :
+	    MMC_BOOT_XFER_SINGLE_BLOCK;
+
+	if (xfer_type == MMC_BOOT_XFER_MULTI_BLOCK) {
+		if ((card->type == MMC_BOOT_TYPE_MMCHC)
+		    || (card->type == MMC_BOOT_TYPE_STD_MMC)) {
+			/* Virtio model does not support open-ended multi-block reads.
+			 * So, block count must be set before sending read command.
+			 * All SD cards do not support this command. Restrict this to MMC.
+			 */
+			mmc_ret =
+			    mmc_boot_set_block_count(card,
+						     data_len /
+						     (card->rd_block_len));
+			if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+				dprintf(CRITICAL,
+					"Error No.%d: Failure setting read block count for Card (RCA:%s)\n",
+					mmc_ret, (char *)(card->rca));
+				return mmc_ret;
+			}
+
+			open_ended_read = 0;
+		}
+	}
+
+	/* Set the FLOW_ENA bit of MCI_CLK register to 1 */
+	/* Note: It's already enabled */
+
+	/* 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 = (unsigned long)(card->rd_timeout_ns / 1000000) *
+	    (host->mclk_rate / 1000);
+	mmc_reg += 1000;	// add some extra clock cycles to be safe
+	mmc_reg = mmc_reg / 2;
+	writel(mmc_reg, MMC_BOOT_MCI_DATA_TIMER);
+
+	/* 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_len, MMC_BOOT_MCI_DATA_LENGTH);
+
+	/* For MMCHC/SDHC data address is specified in unit of 512B */
+	addr = ((card->type != MMC_BOOT_TYPE_MMCHC)
+		&& (card->type !=
+		    MMC_BOOT_TYPE_SDHC)) ? (unsigned int)data_addr : (unsigned
+								      int)
+	    (data_addr / 512);
+
+	/* Set appropriate fields and write the MCI_DATA_CTL register. */
+	/* Set ENABLE bit to 1 to enable the data transfer. */
+	mmc_reg = 0;
+	mmc_reg |= MMC_BOOT_MCI_DATA_ENABLE;
+	/* Clear DIRECTION bit to 1 to enable transfer from card to host */
+	mmc_reg |= MMC_BOOT_MCI_DATA_DIR;
+	/* Clear MODE bit to 0 to enable block oriented data transfer. For
+	   MMC cards only, if stream data transfer mode is desired, set
+	   MODE bit to 1. */
+
+	/* If DMA is to be used, Set DM_ENABLE bit to 1 */
+
+#if MMC_BOOT_ADM
+	mmc_reg |= MMC_BOOT_MCI_DATA_DM_ENABLE;
+#endif
+
+	/* Write size of block to be used during the data transfer to
+	   BLOCKSIZE field */
+	mmc_reg |= (card->rd_block_len << MMC_BOOT_MCI_BLKSIZE_POS);
+	writel(mmc_reg, MMC_BOOT_MCI_DATA_CTL);
+
+	/* Send command to the card/device in order to start the read data
+	   transfer. Possible commands: CMD17/18/53/60/61. */
+	mmc_ret = mmc_boot_send_read_command(card, xfer_type, addr);
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		dprintf(CRITICAL,
+			"Error No.%d: Failure sending read command to the Card(RCA:%x)\n",
+			mmc_ret, card->rca);
+		return mmc_ret;
+	}
+
+	/* Read the transfer data from SDCC FIFO. */
+	mmc_ret =
+	    mmc_boot_fifo_data_transfer(out, data_len, MMC_BOOT_DATA_READ);
+
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		dprintf(CRITICAL, "Error No.%d: Failure on data transfer from the \
+                Card(RCA:%x)\n", mmc_ret,
+			card->rca);
+		return mmc_ret;
+	}
+
+	/* In case a multiple block transfer was performed, send CMD12 to the
+	   card/device in order to indicate the end of read data transfer */
+	if ((xfer_type == MMC_BOOT_XFER_MULTI_BLOCK) && open_ended_read) {
+		mmc_ret = mmc_boot_send_stop_transmission(card, 0);
+		if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+			dprintf(CRITICAL, "Error No.%d: Failure sending Stop Transmission \
+                    command to the Card(RCA:%x)\n", mmc_ret,
+				card->rca);
+			return mmc_ret;
+		}
+	}
+
+	return MMC_BOOT_E_SUCCESS;
+}
+
+/*
+ * Initialize host structure, set and enable clock-rate and power mode.
+ */
+unsigned int mmc_boot_init(struct mmc_boot_host *host)
+{
+	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
+	unsigned int mmc_pwr = 0;
+
+	host->ocr = MMC_BOOT_OCR_27_36 | MMC_BOOT_OCR_SEC_MODE;
+	host->cmd_retry = MMC_BOOT_MAX_COMMAND_RETRY;
+
+	/* Initialize any clocks needed for SDC controller */
+	clock_init_mmc(mmc_slot);
+
+	/* Setup initial freq to 400KHz */
+	clock_config_mmc(mmc_slot, MMC_CLK_400KHZ);
+
+	host->mclk_rate = MMC_CLK_400KHZ;
+
+	/* set power mode */
+	/* give some time to reach minimum voltate */
+	mdelay(2);
+	mmc_pwr &= ~MMC_BOOT_MCI_PWR_UP;
+	mmc_pwr |= MMC_BOOT_MCI_PWR_ON;
+	mmc_pwr |= MMC_BOOT_MCI_PWR_UP;
+	writel(mmc_pwr, MMC_BOOT_MCI_POWER);
+	/* some more time to stabilize voltage */
+	mdelay(2);
+
+	return MMC_BOOT_E_SUCCESS;
+}
+
+/*
+ * Performs card identification process:
+ * - get card's unique identification number (CID)
+ * - get(for sd)/set (for mmc) relative card address (RCA)
+ * - get CSD
+ * - select the card, thus transitioning it to Transfer State
+ * - get Extended CSD (for mmc)
+ */
+static unsigned int
+mmc_boot_identify_card(struct mmc_boot_host *host, struct mmc_boot_card *card)
+{
+	unsigned int mmc_return = MMC_BOOT_E_SUCCESS;
+	unsigned int raw_csd[4];
+
+	/* basic check */
+	if ((host == NULL) || (card == NULL)) {
+		return MMC_BOOT_E_INVAL;
+	}
+
+	/* Ask card to send its unique card identification (CID) number (CMD2) */
+	mmc_return = mmc_boot_all_send_cid(card);
+	if (mmc_return != MMC_BOOT_E_SUCCESS) {
+		dprintf(CRITICAL,
+			"Error No. %d: Failure getting card's CID number!\n",
+			mmc_return);
+		return mmc_return;
+	}
+
+	/* Ask card to send a relative card address (RCA) (CMD3) */
+	mmc_return = mmc_boot_send_relative_address(card);
+	if (mmc_return != MMC_BOOT_E_SUCCESS) {
+		dprintf(CRITICAL, "Error No. %d: Failure getting card's RCA!\n",
+			mmc_return);
+		return mmc_return;
+	}
+
+	/* Get card's CSD register (CMD9) */
+	mmc_return = mmc_boot_send_csd(card, raw_csd);
+	if (mmc_return != MMC_BOOT_E_SUCCESS) {
+		dprintf(CRITICAL,
+			"Error No.%d: Failure getting card's CSD information!\n",
+			mmc_return);
+		return mmc_return;
+	}
+
+	/* Select the card (CMD7) */
+	mmc_return = mmc_boot_select_card(card, card->rca);
+	if (mmc_return != MMC_BOOT_E_SUCCESS) {
+		dprintf(CRITICAL,
+			"Error No.%d: Failure selecting the Card with RCA: %x\n",
+			mmc_return, card->rca);
+		return mmc_return;
+	}
+
+	/* Set the card status as active */
+	card->status = MMC_BOOT_STATUS_ACTIVE;
+
+	if ((card->type == MMC_BOOT_TYPE_STD_MMC)
+	    || (card->type == MMC_BOOT_TYPE_MMCHC)) {
+		/* For MMC cards, also get the extended csd */
+		mmc_return = mmc_boot_send_ext_cmd(card, ext_csd_buf);
+
+		if (mmc_return != MMC_BOOT_E_SUCCESS) {
+			dprintf(CRITICAL,
+				"Error No.%d: Failure getting card's ExtCSD information!\n",
+				mmc_return);
+
+			return mmc_return;
+		}
+
+	}
+
+	/* Decode and save the CSD register */
+	mmc_return = mmc_boot_decode_and_save_csd(card, raw_csd);
+	if (mmc_return != MMC_BOOT_E_SUCCESS) {
+		dprintf(CRITICAL,
+			"Error No.%d: Failure decoding card's CSD information!\n",
+			mmc_return);
+		return mmc_return;
+	}
+
+	/* Once CSD is received, set read and write timeout value now itself */
+	mmc_return = mmc_boot_set_read_timeout(host, card);
+	if (mmc_return != MMC_BOOT_E_SUCCESS) {
+		dprintf(CRITICAL,
+			"Error No.%d: Failure setting Read Timeout value!\n",
+			mmc_return);
+		return mmc_return;
+	}
+
+	mmc_return = mmc_boot_set_write_timeout(host, card);
+	if (mmc_return != MMC_BOOT_E_SUCCESS) {
+		dprintf(CRITICAL,
+			"Error No.%d: Failure setting Write Timeout value!\n",
+			mmc_return);
+		return mmc_return;
+	}
+
+	return MMC_BOOT_E_SUCCESS;
+}
+
+static unsigned int mmc_boot_send_app_cmd(unsigned int rca)
+{
+	struct mmc_boot_command cmd;
+	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
+
+	memset((struct mmc_boot_command *)&cmd, 0,
+	       sizeof(struct mmc_boot_command));
+
+	cmd.cmd_index = CMD55_APP_CMD;
+	cmd.argument = (rca << 16);
+	cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;
+	cmd.resp_type = MMC_BOOT_RESP_R1;
+
+	mmc_ret = mmc_boot_send_command(&cmd);
+
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		return mmc_ret;
+	}
+
+	return MMC_BOOT_E_SUCCESS;
+}
+
+static unsigned int mmc_boot_sd_init_card(struct mmc_boot_card *card)
+{
+	unsigned int i, mmc_ret;
+	unsigned int ocr_cmd_arg;
+	struct mmc_boot_command cmd;
+
+	memset((struct mmc_boot_command *)&cmd, 0,
+	       sizeof(struct mmc_boot_command));
+
+	/* Send CMD8 to set interface condition */
+	for (i = 0; i < 3; i++) {
+		cmd.cmd_index = CMD8_SEND_IF_COND;
+		cmd.argument = MMC_BOOT_SD_HC_VOLT_SUPPLIED;
+		cmd.cmd_type = MMC_BOOT_CMD_BCAST_W_RESP;
+		cmd.resp_type = MMC_BOOT_RESP_R7;
+
+		mmc_ret = mmc_boot_send_command(&cmd);
+		if (mmc_ret == MMC_BOOT_E_SUCCESS) {
+			if (cmd.resp[0] != MMC_BOOT_SD_HC_VOLT_SUPPLIED)
+				return MMC_BOOT_E_FAILURE;
+			/* Set argument for ACMD41 */
+			ocr_cmd_arg = MMC_BOOT_SD_NEG_OCR | MMC_BOOT_SD_HC_HCS;
+			break;
+		}
+		mdelay(1);
+	}
+
+	/* Send ACMD41 to set operating condition */
+	/* Try for a max of 1 sec as per spec */
+	for (i = 0; i < 20; i++) {
+		mmc_ret = mmc_boot_send_app_cmd(0);
+		if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+			return mmc_ret;
+		}
+
+		cmd.cmd_index = ACMD41_SEND_OP_COND;
+		cmd.argument = ocr_cmd_arg;
+		cmd.cmd_type = MMC_BOOT_CMD_BCAST_W_RESP;
+		cmd.resp_type = MMC_BOOT_RESP_R3;
+
+		mmc_ret = mmc_boot_send_command(&cmd);
+		if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+			return mmc_ret;
+		} else if (cmd.resp[0] & MMC_BOOT_SD_DEV_READY) {
+			/* Check for HC */
+			if (cmd.resp[0] & (1 << 30)) {
+				card->type = MMC_BOOT_TYPE_SDHC;
+			} else {
+				card->type = MMC_BOOT_TYPE_STD_SD;
+			}
+			break;
+		}
+		mdelay(50);
+	}
+	return MMC_BOOT_E_SUCCESS;
+}
+
+/*
+ * Routine to initialize MMC card. It resets a card to idle state, verify operating
+ * voltage and set the card inready state.
+ */
+static unsigned int
+mmc_boot_init_card(struct mmc_boot_host *host, struct mmc_boot_card *card)
+{
+	unsigned int mmc_retry = 0;
+	unsigned int mmc_return = MMC_BOOT_E_SUCCESS;
+
+	/* basic check */
+	if ((host == NULL) || (card == NULL)) {
+		return MMC_BOOT_E_INVAL;
+	}
+
+	/* 1. Card Reset - CMD0 */
+	mmc_return = mmc_boot_reset_cards();
+	if (mmc_return != MMC_BOOT_E_SUCCESS) {
+		dprintf(CRITICAL,
+			"Error No.:%d: Failure resetting MMC cards!\n",
+			mmc_return);
+		return mmc_return;
+	}
+
+	/* 2. Card Initialization process */
+
+	/* Send CMD1 to identify and reject cards that do not match host's VDD range
+	   profile. Cards sends its OCR register in response.
+	 */
+	mmc_retry = 0;
+	do {
+		mmc_return = mmc_boot_send_op_cond(host, card);
+		/* Card returns busy status. We'll retry again! */
+		if (mmc_return == MMC_BOOT_E_CARD_BUSY) {
+			mmc_retry++;
+			mdelay(1);
+			continue;
+		} else if (mmc_return == MMC_BOOT_E_SUCCESS) {
+			break;
+		} else {
+			dprintf(CRITICAL,
+				"Error No. %d: Failure Initializing MMC Card!\n",
+				mmc_return);
+
+			/* Check for sD card */
+			mmc_return = mmc_boot_sd_init_card(card);
+			return mmc_return;
+		}
+	}
+	while (mmc_retry < host->cmd_retry);
+
+	/* If card still returned busy status we are out of luck.
+	 * Card cannot be initialized */
+	if (mmc_return == MMC_BOOT_E_CARD_BUSY) {
+		dprintf(CRITICAL, "Error No. %d: Card has busy status set. \
+                Initialization not completed\n", mmc_return);
+		return MMC_BOOT_E_CARD_BUSY;
+	}
+	return MMC_BOOT_E_SUCCESS;
+}
+
+static unsigned int
+mmc_boot_set_sd_bus_width(struct mmc_boot_card *card, unsigned int width)
+{
+	struct mmc_boot_command cmd;
+	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
+	unsigned int sd_reg;
+
+	mmc_ret = mmc_boot_send_app_cmd(card->rca);
+
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		return mmc_ret;
+	}
+
+	memset((struct mmc_boot_command *)&cmd, 0,
+	       sizeof(struct mmc_boot_command));
+
+	/* Send ACMD6 to set bus width */
+	cmd.cmd_index = ACMD6_SET_BUS_WIDTH;
+	/* 10 => 4 bit wide */
+	if (width == MMC_BOOT_BUS_WIDTH_1_BIT) {
+		cmd.argument = 0;
+	} else if (width == MMC_BOOT_BUS_WIDTH_4_BIT) {
+		cmd.argument = (1 << 1);
+	}
+	cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;
+	cmd.resp_type = MMC_BOOT_RESP_R1;
+
+	mmc_ret = mmc_boot_send_command(&cmd);
+
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		return mmc_ret;
+	}
+
+	/* set MCI_CLK accordingly */
+	sd_reg = readl(MMC_BOOT_MCI_CLK);
+	sd_reg &= ~MMC_BOOT_MCI_CLK_WIDEBUS_MODE;
+	if (width == MMC_BOOT_BUS_WIDTH_1_BIT) {
+		sd_reg |= MMC_BOOT_MCI_CLK_WIDEBUS_1_BIT;
+	} else if (width == MMC_BOOT_BUS_WIDTH_4_BIT) {
+		sd_reg |= MMC_BOOT_MCI_CLK_WIDEBUS_4_BIT;
+	} else if (width == MMC_BOOT_BUS_WIDTH_8_BIT) {
+		sd_reg |= MMC_BOOT_MCI_CLK_WIDEBUS_8_BIT;
+	}
+	writel(sd_reg, MMC_BOOT_MCI_CLK);
+
+	mdelay(10);		// Giving some time to card to stabilize.
+
+	return MMC_BOOT_E_SUCCESS;
+}
+
+static unsigned int
+mmc_boot_set_sd_hs(struct mmc_boot_host *host, struct mmc_boot_card *card)
+{
+	unsigned char sw_buf[64];
+	unsigned int mmc_ret;
+
+	/* CMD6 is a data transfer command. sD card returns 512 bits of data */
+	/* Refer 4.3.10 of sD card specification 3.0 */
+	mmc_ret =
+	    mmc_boot_read_reg(card, 64, CMD6_SWITCH_FUNC, MMC_BOOT_SD_SWITCH_HS,
+			      (unsigned int *)&sw_buf);
+
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		return mmc_ret;
+	}
+
+	mdelay(1);
+
+	clock_config_mmc(mmc_slot, MMC_CLK_50MHZ);
+
+	host->mclk_rate = MMC_CLK_50MHZ;
+
+	return MMC_BOOT_E_SUCCESS;
+}
+
+/*
+ * Performs initialization and identification of all the MMC cards connected
+ * to the host.
+ */
+
+static unsigned int
+mmc_boot_init_and_identify_cards(struct mmc_boot_host *host,
+				 struct mmc_boot_card *card)
+{
+	unsigned int mmc_return = MMC_BOOT_E_SUCCESS;
+	unsigned int status;
+
+	/* Basic check */
+	if (host == NULL) {
+		return MMC_BOOT_E_INVAL;
+	}
+
+	/* Initialize MMC card structure */
+	card->status = MMC_BOOT_STATUS_INACTIVE;
+	card->rd_block_len = MMC_BOOT_RD_BLOCK_LEN;
+	card->wr_block_len = MMC_BOOT_WR_BLOCK_LEN;
+
+	/* Start initialization process (CMD0 & CMD1) */
+	mmc_return = mmc_boot_init_card(host, card);
+	if (mmc_return != MMC_BOOT_E_SUCCESS) {
+		return mmc_return;
+	}
+
+	/* Identify (CMD2, CMD3 & CMD9) and select the card (CMD7) */
+	mmc_return = mmc_boot_identify_card(host, card);
+	if (mmc_return != MMC_BOOT_E_SUCCESS) {
+		return mmc_return;
+	}
+
+	if (card->type == MMC_BOOT_TYPE_SDHC
+	    || card->type == MMC_BOOT_TYPE_STD_SD) {
+		/* Setting sD card to high speed without checking card's capability.
+		   Cards that do not support high speed may fail to boot */
+		mmc_return = mmc_boot_set_sd_hs(host, card);
+		if (mmc_return != MMC_BOOT_E_SUCCESS) {
+			return mmc_return;
+		}
+
+		mmc_return =
+		    mmc_boot_set_sd_bus_width(card, MMC_BOOT_BUS_WIDTH_4_BIT);
+		if (mmc_return != MMC_BOOT_E_SUCCESS) {
+			dprintf(CRITICAL,
+				"Couldn't set 4bit mode for sD card\n");
+			mmc_return =
+			    mmc_boot_set_sd_bus_width(card,
+						      MMC_BOOT_BUS_WIDTH_1_BIT);
+			if (mmc_return != MMC_BOOT_E_SUCCESS) {
+				dprintf(CRITICAL,
+					"Error No.%d: Failed in setting bus width!\n",
+					mmc_return);
+				return mmc_return;
+			}
+		}
+	} else {
+		/* set interface speed */
+		mmc_return = mmc_boot_adjust_interface_speed(host, card);
+		if (mmc_return != MMC_BOOT_E_SUCCESS) {
+			dprintf(CRITICAL,
+				"Error No.%d: Error adjusting interface speed!\n",
+				mmc_return);
+			return mmc_return;
+		}
+
+		/* enable wide bus */
+		mmc_return =
+		    mmc_boot_set_bus_width(card, MMC_BOOT_BUS_WIDTH_4_BIT);
+		if (mmc_return != MMC_BOOT_E_SUCCESS) {
+			dprintf(CRITICAL,
+				"Error No.%d: Failure to set wide bus for Card(RCA:%x)\n",
+				mmc_return, card->rca);
+			return mmc_return;
+		}
+	}
+
+	/* Just checking whether we're in TRAN state after changing speed and bus width */
+	mmc_return = mmc_boot_get_card_status(card, 0, &status);
+	if (mmc_return != MMC_BOOT_E_SUCCESS) {
+		return mmc_return;
+	}
+
+	if (MMC_BOOT_CARD_STATUS(status) != MMC_BOOT_TRAN_STATE)
+		return MMC_BOOT_E_FAILURE;
+
+	return MMC_BOOT_E_SUCCESS;
+}
+
+void mmc_display_ext_csd(void)
+{
+	dprintf(SPEW, "part_config: %x\n", ext_csd_buf[179]);
+	dprintf(SPEW, "erase_group_def: %x\n", ext_csd_buf[175]);
+	dprintf(SPEW, "user_wp: %x\n", ext_csd_buf[171]);
+}
+
+void mmc_display_csd(void)
+{
+	dprintf(SPEW, "erase_grpsize: %d\n", mmc_card.csd.erase_grp_size);
+	dprintf(SPEW, "erase_grpmult: %d\n", mmc_card.csd.erase_grp_mult);
+	dprintf(SPEW, "wp_grpsize: %d\n", mmc_card.csd.wp_grp_size);
+	dprintf(SPEW, "wp_grpen: %d\n", mmc_card.csd.wp_grp_enable);
+	dprintf(SPEW, "perm_wp: %d\n", mmc_card.csd.perm_wp);
+	dprintf(SPEW, "temp_wp: %d\n", mmc_card.csd.temp_wp);
+}
+
+/*
+ * Entry point to MMC boot process
+ */
+unsigned int mmc_boot_main(unsigned char slot, unsigned int base)
+{
+	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
+
+	memset((struct mmc_boot_host *)&mmc_host, 0,
+	       sizeof(struct mmc_boot_host));
+	memset((struct mmc_boot_card *)&mmc_card, 0,
+	       sizeof(struct mmc_boot_card));
+
+	mmc_slot = slot;
+	mmc_boot_mci_base = base;
+
+	/* Initialize necessary data structure and enable/set clock and power */
+	dprintf(SPEW, " Initializing MMC host data structure and clock!\n");
+	mmc_ret = mmc_boot_init(&mmc_host);
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		dprintf(CRITICAL, "MMC Boot: Error Initializing MMC Card!!!\n");
+		return MMC_BOOT_E_FAILURE;
+	}
+
+	/* Initialize and identify cards connected to host */
+	mmc_ret = mmc_boot_init_and_identify_cards(&mmc_host, &mmc_card);
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		dprintf(CRITICAL,
+			"MMC Boot: Failed detecting MMC/SDC @ slot%d\n", slot);
+		return MMC_BOOT_E_FAILURE;
+	}
+
+	mmc_display_csd();
+	mmc_display_ext_csd();
+
+	mmc_ret = partition_read_table(&mmc_host, &mmc_card);
+	return mmc_ret;
+}
+
+/*
+ * MMC write function
+ */
+unsigned int
+mmc_write(unsigned long long data_addr, unsigned int data_len, unsigned int *in)
+{
+	int val = 0;
+	unsigned int write_size = ((unsigned)(0xFFFFFF / 512)) * 512;
+	unsigned offset = 0;
+	unsigned int *sptr = in;
+
+	if (data_len % 512)
+		data_len = ROUND_TO_PAGE(data_len, 511);
+
+	while (data_len > write_size) {
+		val = mmc_boot_write_to_card(&mmc_host, &mmc_card,
+					     data_addr + offset, write_size,
+					     sptr);
+		if (val) {
+			return val;
+		}
+
+		sptr += (write_size / sizeof(unsigned));
+		offset += write_size;
+		data_len -= write_size;
+	}
+	if (data_len) {
+		val = mmc_boot_write_to_card(&mmc_host, &mmc_card,
+					     data_addr + offset, data_len,
+					     sptr);
+	}
+	return val;
+}
+
+/*
+ * MMC read function
+ */
+
+unsigned int
+mmc_read(unsigned long long data_addr, unsigned int *out, unsigned int data_len)
+{
+	int val = 0;
+	val =
+	    mmc_boot_read_from_card(&mmc_host, &mmc_card, data_addr, data_len,
+				    out);
+	return val;
+}
+
+/*
+ * Function to read registers from MMC or SD card
+ */
+static unsigned int
+mmc_boot_read_reg(struct mmc_boot_card *card,
+		  unsigned int data_len,
+		  unsigned int command, unsigned int addr, unsigned int *out)
+{
+	struct mmc_boot_command cmd;
+	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
+	unsigned int mmc_reg = 0;
+
+	/* Set the FLOW_ENA bit of MCI_CLK register to 1 */
+	mmc_reg = readl(MMC_BOOT_MCI_CLK);
+	mmc_reg |= MMC_BOOT_MCI_CLK_ENA_FLOW;
+	writel(mmc_reg, MMC_BOOT_MCI_CLK);
+
+	/* 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);
+	writel(data_len, MMC_BOOT_MCI_DATA_LENGTH);
+
+	/* Set appropriate fields and write the MCI_DATA_CTL register. */
+	/* Set ENABLE bit to 1 to enable the data transfer. */
+	mmc_reg =
+	    MMC_BOOT_MCI_DATA_ENABLE | MMC_BOOT_MCI_DATA_DIR | (data_len <<
+								MMC_BOOT_MCI_BLKSIZE_POS);
+
+#if MMC_BOOT_ADM
+	mmc_reg |= MMC_BOOT_MCI_DATA_DM_ENABLE;
+#endif
+
+	writel(mmc_reg, MMC_BOOT_MCI_DATA_CTL);
+
+	memset((struct mmc_boot_command *)&cmd, 0,
+	       sizeof(struct mmc_boot_command));
+
+	cmd.cmd_index = command;
+	cmd.argument = addr;
+	cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;
+	cmd.resp_type = MMC_BOOT_RESP_R1;
+
+	/* send command */
+	mmc_ret = mmc_boot_send_command(&cmd);
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		return mmc_ret;
+	}
+
+	/* Read the transfer data from SDCC FIFO. */
+	mmc_ret =
+	    mmc_boot_fifo_data_transfer(out, data_len, MMC_BOOT_DATA_READ);
+
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		dprintf(CRITICAL, "Error No.%d: Failure on data transfer from the \
+                Card(RCA:%x)\n", mmc_ret,
+			card->rca);
+		return mmc_ret;
+	}
+
+	return MMC_BOOT_E_SUCCESS;
+}
+
+/*
+ * Function to set/clear power-on write protection for the user area partitions
+ */
+static unsigned int
+mmc_boot_set_clr_power_on_wp_user(struct mmc_boot_card *card,
+				  unsigned int addr,
+				  unsigned int size, unsigned char set_clear_wp)
+{
+	struct mmc_boot_command cmd;
+	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
+	unsigned int wp_group_size, loop_count;
+	unsigned int status;
+
+	memset((struct mmc_boot_command *)&cmd, 0,
+	       sizeof(struct mmc_boot_command));
+
+	/* Disabling PERM_WP for USER AREA (CMD6) */
+	mmc_ret = mmc_boot_switch_cmd(card, MMC_BOOT_ACCESS_WRITE,
+				      MMC_BOOT_EXT_USER_WP,
+				      MMC_BOOT_US_PERM_WP_DIS);
+
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		return mmc_ret;
+	}
+
+	/* Sending CMD13 to check card status */
+	do {
+		mmc_ret = mmc_boot_get_card_status(card, 0, &status);
+		if (MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_TRAN_STATE)
+			break;
+	}
+	while ((mmc_ret == MMC_BOOT_E_SUCCESS) &&
+	       (MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_PROG_STATE));
+
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		return mmc_ret;
+	}
+
+	mmc_ret = mmc_boot_send_ext_cmd(card, ext_csd_buf);
+
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		return mmc_ret;
+	}
+
+	/* Make sure power-on write protection for user area is not disabled
+	   and permanent write protection for user area is not enabled */
+
+	if ((IS_BIT_SET_EXT_CSD(MMC_BOOT_EXT_USER_WP, MMC_BOOT_US_PERM_WP_EN))
+	    ||
+	    (IS_BIT_SET_EXT_CSD(MMC_BOOT_EXT_USER_WP, MMC_BOOT_US_PWR_WP_DIS)))
+	{
+		return MMC_BOOT_E_FAILURE;
+	}
+
+	if (ext_csd_buf[MMC_BOOT_EXT_ERASE_GROUP_DEF]) {
+		/* wp_group_size = 512KB * HC_WP_GRP_SIZE * HC_ERASE_GRP_SIZE.
+		   Getting write protect group size in sectors here. */
+
+		wp_group_size =
+		    (512 * 1024) * ext_csd_buf[MMC_BOOT_EXT_HC_WP_GRP_SIZE] *
+		    ext_csd_buf[MMC_BOOT_EXT_HC_ERASE_GRP_SIZE] /
+		    MMC_BOOT_WR_BLOCK_LEN;
+	} else {
+		/* wp_group_size = (WP_GRP_SIZE + 1) * (ERASE_GRP_SIZE + 1)
+		 * (ERASE_GRP_MULT + 1).
+		 This is defined as the number of write blocks directly */
+
+		wp_group_size = (card->csd.erase_grp_size + 1) *
+		    (card->csd.erase_grp_mult + 1) * (card->csd.wp_grp_size +
+						      1);
+	}
+
+	if (wp_group_size == 0) {
+		return MMC_BOOT_E_FAILURE;
+	}
+
+	/* Setting POWER_ON_WP for USER AREA (CMD6) */
+
+	mmc_ret = mmc_boot_switch_cmd(card, MMC_BOOT_ACCESS_WRITE,
+				      MMC_BOOT_EXT_USER_WP,
+				      MMC_BOOT_US_PWR_WP_EN);
+
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		return mmc_ret;
+	}
+
+	/* Sending CMD13 to check card status */
+	do {
+		mmc_ret = mmc_boot_get_card_status(card, 0, &status);
+		if (MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_TRAN_STATE)
+			break;
+	}
+	while ((mmc_ret == MMC_BOOT_E_SUCCESS) &&
+	       (MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_PROG_STATE));
+
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		return mmc_ret;
+	}
+
+	/* Calculating the loop count for sending SET_WRITE_PROTECT (CMD28)
+	   or CLEAR_WRITE_PROTECT (CMD29).
+	   We are write protecting the partitions in blocks of write protect
+	   group sizes only */
+
+	if (size % wp_group_size) {
+		loop_count = (size / wp_group_size) + 1;
+	} else {
+		loop_count = (size / wp_group_size);
+	}
+
+	if (set_clear_wp)
+		cmd.cmd_index = CMD28_SET_WRITE_PROTECT;
+	else
+		cmd.cmd_index = CMD29_CLEAR_WRITE_PROTECT;
+
+	cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;
+	cmd.resp_type = MMC_BOOT_RESP_R1B;
+
+	for (unsigned int i = 0; i < loop_count; i++) {
+		/* Sending CMD28 for each WP group size
+		   address is in sectors already */
+		cmd.argument = (addr + (i * wp_group_size));
+
+		mmc_ret = mmc_boot_send_command(&cmd);
+
+		if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+			return mmc_ret;
+		}
+
+		/* Checking ADDR_OUT_OF_RANGE error in CMD28 response */
+		if (IS_ADDR_OUT_OF_RANGE(cmd.resp[0])) {
+			return MMC_BOOT_E_FAILURE;
+		}
+
+		/* Sending CMD13 to check card status */
+		do {
+			mmc_ret = mmc_boot_get_card_status(card, 0, &status);
+			if (MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_TRAN_STATE)
+				break;
+		}
+		while ((mmc_ret == MMC_BOOT_E_SUCCESS) &&
+		       (MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_PROG_STATE));
+
+		if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+			return mmc_ret;
+		}
+	}
+
+	return MMC_BOOT_E_SUCCESS;
+}
+
+/*
+ * Function to get Write Protect status of the given sector
+ */
+static unsigned int
+mmc_boot_get_wp_status(struct mmc_boot_card *card, unsigned int sector)
+{
+	unsigned int rc = MMC_BOOT_E_SUCCESS;
+	memset(wp_status_buf, 0, 8);
+
+	rc = mmc_boot_read_reg(card, 8, CMD31_SEND_WRITE_PROT_TYPE, sector,
+			       (unsigned int *)wp_status_buf);
+	return rc;
+}
+
+/*
+ * Test Function for setting Write protect for given sector
+ */
+static unsigned int
+mmc_wp(unsigned int sector, unsigned int size, unsigned char set_clear_wp)
+{
+	unsigned int rc = MMC_BOOT_E_SUCCESS;
+
+	/* Checking whether group write protection feature is available */
+	if (mmc_card.csd.wp_grp_enable) {
+		rc = mmc_boot_get_wp_status(&mmc_card, sector);
+		rc = mmc_boot_set_clr_power_on_wp_user(&mmc_card, sector, size,
+						       set_clear_wp);
+		rc = mmc_boot_get_wp_status(&mmc_card, sector);
+		return rc;
+	} else
+		return MMC_BOOT_E_FAILURE;
+}
+
+void mmc_wp_test(void)
+{
+	unsigned int mmc_ret = 0;
+	mmc_ret = mmc_wp(0xE06000, 0x5000, 1);
+}
+
+unsigned mmc_get_psn(void)
+{
+	return mmc_card.cid.psn;
+}
+
+/*
+ * Read/write data from/to SDC FIFO.
+ */
+static unsigned int
+mmc_boot_fifo_data_transfer(unsigned int *data_ptr,
+			    unsigned int data_len, unsigned char direction)
+{
+	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
+
+#if MMC_BOOT_ADM
+	adm_result_t ret;
+	adm_dir_t adm_dir;
+
+	if (direction == MMC_BOOT_DATA_READ) {
+		adm_dir = ADM_MMC_READ;
+	} else {
+		adm_dir = ADM_MMC_WRITE;
+	}
+
+	ret = adm_transfer_mmc_data(mmc_slot,
+				    (unsigned char *)data_ptr, data_len,
+				    adm_dir);
+
+	if (ret != ADM_RESULT_SUCCESS) {
+		dprintf(CRITICAL, "MMC ADM transfer error: %d\n", ret);
+		mmc_ret = MMC_BOOT_E_FAILURE;
+	}
+#else
+
+	if (direction == MMC_BOOT_DATA_READ) {
+		mmc_ret = mmc_boot_fifo_read(data_ptr, data_len);
+	} else {
+		mmc_ret = mmc_boot_fifo_write(data_ptr, data_len);
+	}
+#endif
+	return mmc_ret;
+}
+
+/*
+ * Read data to SDC FIFO.
+ */
+static unsigned int
+mmc_boot_fifo_read(unsigned int *mmc_ptr, unsigned int data_len)
+{
+	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
+	unsigned int mmc_status = 0;
+	unsigned int mmc_count = 0;
+	unsigned int read_error = MMC_BOOT_MCI_STAT_DATA_CRC_FAIL |
+	    MMC_BOOT_MCI_STAT_DATA_TIMEOUT | MMC_BOOT_MCI_STAT_RX_OVRRUN;
+
+	/* 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 */
+
+	do {
+		mmc_ret = MMC_BOOT_E_SUCCESS;
+		mmc_status = readl(MMC_BOOT_MCI_STATUS);
+
+		if (mmc_status & read_error) {
+			mmc_ret = mmc_boot_status_error(mmc_status);
+			break;
+		}
+
+		if (mmc_status & MMC_BOOT_MCI_STAT_RX_DATA_AVLBL) {
+			unsigned read_count = 1;
+			if (mmc_status & MMC_BOOT_MCI_STAT_RX_FIFO_HFULL) {
+				read_count = MMC_BOOT_MCI_HFIFO_COUNT;
+			}
+
+			for (unsigned int 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_count %
+						  MMC_BOOT_MCI_FIFO_SIZE));
+				mmc_ptr++;
+				/* increase mmc_count by word size */
+				mmc_count += sizeof(unsigned int);
+			}
+			/* 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;
+		}
+	}
+	while (1);
+
+	return mmc_ret;
+}
+
+/*
+ * Write data to SDC FIFO.
+ */
+static unsigned int
+mmc_boot_fifo_write(unsigned int *mmc_ptr, unsigned int data_len)
+{
+	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;
+
+	/* Write the transfer data to SDCC3 FIFO */
+	do {
+		mmc_ret = MMC_BOOT_E_SUCCESS;
+		mmc_status = readl(MMC_BOOT_MCI_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)) {
+			for (int i = 0; i < MMC_BOOT_MCI_HFIFO_COUNT; i++) {
+				/* FIFO contains 16 32-bit data buffer on 16 sequential addresses */
+				writel(*mmc_ptr, MMC_BOOT_MCI_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, MMC_BOOT_MCI_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;	//success
+		}
+
+	}
+	while (1);
+	return mmc_ret;
+}
+
+/*
+ * CMD35_ERASE_GROUP_START
+ */
+
+static unsigned int
+mmc_boot_send_erase_group_start(struct mmc_boot_card *card,
+				unsigned long long data_addr)
+{
+	struct mmc_boot_command cmd;
+	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
+
+	if (card == NULL)
+		return MMC_BOOT_E_INVAL;
+
+	memset((struct mmc_boot_command *)&cmd, 0,
+	       sizeof(struct mmc_boot_command));
+
+	cmd.cmd_index = CMD35_ERASE_GROUP_START;
+	cmd.argument = data_addr;
+	cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;
+	cmd.resp_type = MMC_BOOT_RESP_R1;
+
+	mmc_ret = mmc_boot_send_command(&cmd);
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		return mmc_ret;
+	}
+
+	/* Checking for address error */
+	if (IS_ADDR_OUT_OF_RANGE(cmd.resp[0])) {
+		return MMC_BOOT_E_BLOCKLEN_ERR;
+	}
+
+	return MMC_BOOT_E_SUCCESS;
+
+}
+
+/*
+ * CMD36 ERASE GROUP END
+ */
+static unsigned int
+mmc_boot_send_erase_group_end(struct mmc_boot_card *card,
+			      unsigned long long data_addr)
+{
+	struct mmc_boot_command cmd;
+	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
+
+	if (card == NULL)
+		return MMC_BOOT_E_INVAL;
+
+	memset((struct mmc_boot_command *)&cmd, 0,
+	       sizeof(struct mmc_boot_command));
+
+	cmd.cmd_index = CMD36_ERASE_GROUP_END;
+	cmd.argument = data_addr;
+	cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;
+	cmd.resp_type = MMC_BOOT_RESP_R1;
+
+	mmc_ret = mmc_boot_send_command(&cmd);
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		return mmc_ret;
+	}
+
+	/* Checking for address error */
+	if (IS_ADDR_OUT_OF_RANGE(cmd.resp[0])) {
+		return MMC_BOOT_E_BLOCKLEN_ERR;
+	}
+
+	return MMC_BOOT_E_SUCCESS;
+}
+
+/*
+ * CMD38 ERASE
+ */
+static unsigned int mmc_boot_send_erase(struct mmc_boot_card *card)
+{
+
+	struct mmc_boot_command cmd;
+	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
+	unsigned int status;
+
+	if (card == NULL)
+		return MMC_BOOT_E_INVAL;
+
+	memset((struct mmc_boot_command *)&cmd, 0,
+	       sizeof(struct mmc_boot_command));
+
+	cmd.cmd_index = CMD38_ERASE;
+	cmd.argument = 0x00000000;
+	cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;
+	cmd.resp_type = MMC_BOOT_RESP_R1B;
+
+	/* Checking if the card is in the transfer state */
+	do {
+		mmc_ret = mmc_boot_get_card_status(card, 0, &status);
+		if (MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_TRAN_STATE)
+			break;
+	}
+	while ((mmc_ret == MMC_BOOT_E_SUCCESS) &&
+	       (MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_PROG_STATE));
+
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		return mmc_ret;
+	}
+	mmc_ret = mmc_boot_send_command(&cmd);
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		return mmc_ret;
+	}
+
+	/* Checking for write protect */
+	if (cmd.resp[0] & MMC_BOOT_R1_WP_ERASE_SKIP) {
+		dprintf(CRITICAL, "Write protect enabled for sector \n");
+		return;
+	}
+
+	/* Checking if the erase operation for the card is compelete */
+	do {
+		mmc_ret = mmc_boot_get_card_status(card, 0, &status);
+		if (MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_TRAN_STATE)
+			break;
+	}
+	while ((mmc_ret == MMC_BOOT_E_SUCCESS) &&
+	       (MMC_BOOT_CARD_STATUS(status) == MMC_BOOT_PROG_STATE));
+
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		return mmc_ret;
+	}
+
+	return MMC_BOOT_E_SUCCESS;
+}
+
+/*
+ * Function to erase data on the eMMC card
+ */
+unsigned int
+mmc_erase_card(unsigned long long data_addr, unsigned long long size)
+{
+	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
+	unsigned long long erase_grp_size;
+	unsigned long long data_end = 0x00000000;
+	unsigned long long loop_count;
+	unsigned int out[512] = { 0 };
+
+	/* Converting size to sectors */
+	size = size / 512;
+
+	if (ext_csd_buf[MMC_BOOT_EXT_ERASE_GROUP_DEF]) {
+		erase_grp_size =
+		    (512 * ext_csd_buf[MMC_BOOT_EXT_HC_ERASE_GRP_SIZE] * 1024);
+		erase_grp_size = erase_grp_size / 512;
+	} else {
+		erase_grp_size = (mmc_card.csd.erase_grp_size + 1) *
+		    (mmc_card.csd.erase_grp_mult + 1);
+	}
+
+	if (erase_grp_size == 0) {
+		return MMC_BOOT_E_FAILURE;
+	}
+
+	if (size % erase_grp_size) {
+		dprintf(CRITICAL, "Overflow beyond ERASE_GROUP_SIZE:%llu\n",
+			(size % erase_grp_size));
+
+	}
+	loop_count = (size / erase_grp_size);
+	/*
+	 *In case the partition size is less than the erase_grp_size
+	 0 is written to the first block of the partition.
+	 */
+	if (loop_count < 1) {
+		mmc_ret = mmc_write(data_addr, 512, (unsigned int *)out);
+		if (mmc_ret != MMC_BOOT_E_SUCCESS)
+			return mmc_ret;
+		else
+			return MMC_BOOT_E_SUCCESS;
+	} else {
+		data_addr = ((mmc_card.type != MMC_BOOT_TYPE_MMCHC) &&
+			     (mmc_card.type != MMC_BOOT_TYPE_SDHC))
+		    ? (unsigned int)data_addr : (unsigned int)(data_addr / 512);
+		data_end = data_addr + erase_grp_size * (loop_count - 1);
+	}
+
+	/* Sending CMD35 */
+	mmc_ret = mmc_boot_send_erase_group_start(&mmc_card, data_addr);
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		dprintf(CRITICAL, "Error %d: Failure sending erase group start "
+			"command to the card (RCA:%x)\n", mmc_ret,
+			mmc_card.rca);
+		return mmc_ret;
+	}
+
+	/* Sending CMD36 */
+	mmc_ret = mmc_boot_send_erase_group_end(&mmc_card, data_end - 1);
+	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+		dprintf(CRITICAL, "Error %d: Failure sending erase group end "
+			"command to the card (RCA:%x)\n", mmc_ret,
+			mmc_card.rca);
+		return mmc_ret;
+	}
+
+	for (unsigned long long i = 0; i < loop_count; i++) {
+		/* Sending CMD38 */
+		mmc_ret = mmc_boot_send_erase(&mmc_card);
+		if (mmc_ret != MMC_BOOT_E_SUCCESS) {
+			dprintf(CRITICAL,
+				"Error %d: Failure sending erase command "
+				"to the card (RCA:%x)\n", mmc_ret,
+				mmc_card.rca);
+			return mmc_ret;
+
+		}
+	}
+	dprintf(CRITICAL, "ERASE SUCCESSFULLY COMPLETED\n");
+	return MMC_BOOT_E_SUCCESS;
+}
+
+struct mmc_boot_host *get_mmc_host(void)
+{
+	return &mmc_host;
+}
+
+struct mmc_boot_card *get_mmc_card(void)
+{
+	return &mmc_card;
+}