u-boot-2016/drivers/mmc/sdhci.c
Antony Arun T 6dded97c74 ipq6018: fixing "reset never completed issue"
As per the SD controller hardware design document
the SD bus power should be turned off and the iopad
voltage has to be set to 3V (default), before
doing reset for all in SD host controller.

Change-Id: Ia77bb0acefe1e619c8ae7a2bc60024bf1ac5c6cd
Signed-off-by: Antony Arun T <antothom@codeaurora.org>
2019-06-26 18:15:32 +05:30

701 lines
17 KiB
C

/*
* Copyright 2011, Marvell Semiconductor Inc.
* Lei Wen <leiwen@marvell.com>
*
* SPDX-License-Identifier: GPL-2.0+
*
* Back ported to the 8xx platform (from the 8260 platform) by
* Murray.Jensen@cmst.csiro.au, 27-Jan-01.
*/
#include <common.h>
#include <malloc.h>
#include <mmc.h>
#include <sdhci.h>
#if defined(CONFIG_FIXED_SDHCI_ALIGNED_BUFFER)
void *aligned_buffer = (void *)CONFIG_FIXED_SDHCI_ALIGNED_BUFFER;
#else
void *aligned_buffer;
#endif
#define CACHE_LINE_SIZE (CONFIG_SYS_CACHELINE_SIZE)
__weak void sdhci_bus_pwr_off(struct sdhci_host *host)
{
return;
}
static void sdhci_reset(struct sdhci_host *host, u8 mask)
{
unsigned long timeout;
if (mask & SDHCI_RESET_ALL) {
sdhci_bus_pwr_off(host);
}
/* Wait max 100 ms */
timeout = 100;
sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);
while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) {
if (timeout == 0) {
printf("%s: Reset 0x%x never completed.\n",
__func__, (int)mask);
return;
}
timeout--;
udelay(1000);
}
}
static void sdhci_cmd_done(struct sdhci_host *host, struct mmc_cmd *cmd)
{
int i;
if (cmd->resp_type & MMC_RSP_136) {
/* CRC is stripped so we need to do some shifting. */
for (i = 0; i < 4; i++) {
cmd->response[i] = sdhci_readl(host,
SDHCI_RESPONSE + (3-i)*4) << 8;
if (i != 3)
cmd->response[i] |= sdhci_readb(host,
SDHCI_RESPONSE + (3-i)*4-1);
}
} else {
cmd->response[0] = sdhci_readl(host, SDHCI_RESPONSE);
}
}
static void sdhci_transfer_pio(struct sdhci_host *host, struct mmc_data *data)
{
int i;
char *offs;
for (i = 0; i < data->blocksize; i += 4) {
offs = data->dest + i;
if (data->flags == MMC_DATA_READ)
*(u32 *)offs = sdhci_readl(host, SDHCI_BUFFER);
else
sdhci_writel(host, *(u32 *)offs, SDHCI_BUFFER);
}
}
#ifdef CONFIG_MMC_ADMA
static struct adma_desc *sdhci_prepare_descriptors(void *data, uint32_t len)
{
struct adma_desc *list;
uint32_t list_len = 0;
uint32_t remain = 0;
uint32_t i;
uint32_t table_len = 0;
if (len <= SDHCI_ADMA_DESC_LINE_SZ) {
list = (struct adma_desc *)memalign(CACHE_LINE_SIZE,
sizeof(struct adma_desc));
if (!list) {
printf("Error allocating memory\n");
assert(0);
} else {
list[0].addr = (uint32_t)data;
list[0].len = (len < SDHCI_ADMA_DESC_LINE_SZ) ? len :
(SDHCI_ADMA_DESC_LINE_SZ & 0xffff);
list[0].tran_att = SDHCI_ADMA_TRANS_VALID |
SDHCI_ADMA_TRANS_DATA | SDHCI_ADMA_TRANS_END;
#if !defined(CONFIG_SYS_DCACHE_OFF)
flush_cache((unsigned long)list,
sizeof(struct adma_desc));
#endif
}
} else {
list_len = len / SDHCI_ADMA_DESC_LINE_SZ;
remain = len - (list_len * SDHCI_ADMA_DESC_LINE_SZ);
if (remain)
list_len++;
table_len = (list_len * sizeof(struct adma_desc));
list = (struct adma_desc *) memalign( CACHE_LINE_SIZE, table_len);
if (!list) {
printf("Allocating memory failed\n");
assert(0);
} else {
memset((void *)list, 0, table_len);
for (i = 0; i < (list_len - 1); i++) {
list[i].addr = (uint32_t)data;
list[i].len = (SDHCI_ADMA_DESC_LINE_SZ & 0xffff);
list[i].tran_att = SDHCI_ADMA_TRANS_VALID |
SDHCI_ADMA_TRANS_DATA;
data += SDHCI_ADMA_DESC_LINE_SZ;
len -= SDHCI_ADMA_DESC_LINE_SZ;
}
list[list_len - 1].addr = (uint32_t)data;
list[list_len - 1].len = (len < SDHCI_ADMA_DESC_LINE_SZ)
? len : (SDHCI_ADMA_DESC_LINE_SZ & 0xffff);
list[list_len - 1].tran_att = SDHCI_ADMA_TRANS_VALID |
SDHCI_ADMA_TRANS_DATA
| SDHCI_ADMA_TRANS_END;
#if !defined(CONFIG_SYS_DCACHE_OFF)
flush_cache((unsigned long)list, table_len);
#endif
}
}
return list;
}
struct adma_desc *sdhci_adma_transfer(struct sdhci_host *host, struct mmc_data *data)
{
uint32_t sz;
void *dataptr;
struct adma_desc *adma_addr;
dataptr = data->dest;
if (data->blocksize)
sz = data->blocks * data->blocksize;
else
sz = data->blocks * SDHCI_MMC_BLK_SZ;
/* Prepare adma descriptors */
adma_addr = sdhci_prepare_descriptors(dataptr, sz);
/* Write adma address to adma register */
sdhci_writel(host, (uint32_t) adma_addr, SDHCI_ADM_ADDR_REG);
/* Write the block size */
if (data->blocksize)
sdhci_writew(host, data->blocksize, SDHCI_BLOCK_SIZE);
else
sdhci_writew(host, SDHCI_MMC_BLK_SZ, SDHCI_BLOCK_SIZE);
/*
* Write block count in block count register
*/
sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
return adma_addr;
}
#endif
static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data,
unsigned int start_addr)
{
unsigned int stat, rdy, mask, timeout, block = 0;
#ifdef CONFIG_MMC_SDMA
unsigned char ctrl;
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
ctrl &= ~SDHCI_CTRL_DMA_MASK;
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
#endif
timeout = 1000000;
rdy = SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_AVAIL;
mask = SDHCI_DATA_AVAILABLE | SDHCI_SPACE_AVAILABLE;
do {
stat = sdhci_readl(host, SDHCI_INT_STATUS);
if (stat & SDHCI_INT_ERROR) {
printf("%s: Error detected in status(0x%X)!\n",
__func__, stat);
return -1;
}
if (stat & rdy) {
if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & mask))
continue;
sdhci_writel(host, rdy, SDHCI_INT_STATUS);
sdhci_transfer_pio(host, data);
data->dest += data->blocksize;
if (++block >= data->blocks)
break;
}
#ifdef CONFIG_MMC_SDMA
if (stat & SDHCI_INT_DMA_END) {
sdhci_writel(host, SDHCI_INT_DMA_END, SDHCI_INT_STATUS);
start_addr &= ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1);
start_addr += SDHCI_DEFAULT_BOUNDARY_SIZE;
sdhci_writel(host, start_addr, SDHCI_DMA_ADDRESS);
}
#endif
if (timeout-- > 0)
udelay(10);
else {
printf("%s: Transfer data timeout\n", __func__);
return -1;
}
} while (!(stat & SDHCI_INT_DATA_END));
return 0;
}
/*
* No command will be sent by driver if card is busy, so driver must wait
* for card ready state.
* Every time when card is busy after timeout then (last) timeout value will be
* increased twice but only if it doesn't exceed global defined maximum.
* Each function call will use last timeout value. Max timeout can be redefined
* in board config file.
*/
#ifndef CONFIG_SDHCI_CMD_MAX_TIMEOUT
#define CONFIG_SDHCI_CMD_MAX_TIMEOUT 5000
#endif
#define CONFIG_SDHCI_CMD_DEFAULT_TIMEOUT 1000
static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
struct mmc_data *data)
{
struct sdhci_host *host = mmc->priv;
unsigned int stat = 0;
int ret = 0;
int trans_bytes = 0, is_aligned = 1;
u32 mask, flags, mode;
unsigned int time = 0, start_addr = 0;
int mmc_dev = mmc->block_dev.dev;
unsigned start = get_timer(0);
struct adma_desc *adma_addr = NULL;
/* Timeout unit - ms */
static unsigned int cmd_timeout = CONFIG_SDHCI_CMD_DEFAULT_TIMEOUT;
sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS);
mask = SDHCI_CMD_INHIBIT;
if ((data != NULL) || (cmd->resp_type & MMC_RSP_BUSY))
mask |= SDHCI_DATA_INHIBIT;
/* We shouldn't wait for data inihibit for stop commands, even
though they might use busy signaling */
if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
mask &= ~SDHCI_DATA_INHIBIT;
while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) {
if (time >= cmd_timeout) {
printf("%s: MMC: %d busy ", __func__, mmc_dev);
if (2 * cmd_timeout <= CONFIG_SDHCI_CMD_MAX_TIMEOUT) {
cmd_timeout += cmd_timeout;
printf("timeout increasing to: %u ms.\n",
cmd_timeout);
} else {
puts("timeout.\n");
return COMM_ERR;
}
}
time++;
udelay(1000);
}
mask = SDHCI_INT_RESPONSE;
if (!(cmd->resp_type & MMC_RSP_PRESENT))
flags = SDHCI_CMD_RESP_NONE;
else if (cmd->resp_type & MMC_RSP_136)
flags = SDHCI_CMD_RESP_LONG;
else if (cmd->resp_type & MMC_RSP_BUSY) {
flags = SDHCI_CMD_RESP_SHORT_BUSY;
mask |= SDHCI_INT_DATA_END;
} else
flags = SDHCI_CMD_RESP_SHORT;
if (cmd->resp_type & MMC_RSP_CRC)
flags |= SDHCI_CMD_CRC;
if (cmd->resp_type & MMC_RSP_OPCODE)
flags |= SDHCI_CMD_INDEX;
if (data)
flags |= SDHCI_CMD_DATA;
/* Set Transfer mode regarding to data flag */
if (data != 0) {
sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL);
mode = SDHCI_TRNS_BLK_CNT_EN;
trans_bytes = data->blocks * data->blocksize;
if (data->blocks > 1)
mode |= SDHCI_TRNS_MULTI;
if (data->flags == MMC_DATA_READ)
mode |= SDHCI_TRNS_READ;
if (data->flags == MMC_DATA_READ)
start_addr = (unsigned long)data->dest;
else
start_addr = (unsigned long)data->src;
#ifdef CONFIG_MMC_SDMA
if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) &&
(start_addr & 0x7) != 0x0) {
is_aligned = 0;
start_addr = (unsigned long)aligned_buffer;
if (data->flags != MMC_DATA_READ)
memcpy(aligned_buffer, data->src, trans_bytes);
}
#if defined(CONFIG_FIXED_SDHCI_ALIGNED_BUFFER)
/*
* Always use this bounce-buffer when
* CONFIG_FIXED_SDHCI_ALIGNED_BUFFER is defined
*/
is_aligned = 0;
start_addr = (unsigned long)aligned_buffer;
if (data->flags != MMC_DATA_READ)
memcpy(aligned_buffer, data->src, trans_bytes);
#endif
sdhci_writel(host, start_addr, SDHCI_DMA_ADDRESS);
mode |= SDHCI_TRNS_DMA;
#endif
#ifdef CONFIG_MMC_ADMA
mode |= SDHCI_TRNS_DMA;
adma_addr = sdhci_adma_transfer(host, data);
#endif
sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG,
data->blocksize),
SDHCI_BLOCK_SIZE);
sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
sdhci_writew(host, mode, SDHCI_TRANSFER_MODE);
} else if (cmd->resp_type & MMC_RSP_BUSY) {
sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL);
}
sdhci_writel(host, cmd->cmdarg, SDHCI_ARGUMENT);
#if defined(CONFIG_MMC_SDMA) || (defined(CONFIG_MMC_ADMA) && \
!defined(CONFIG_SYS_DCACHE_OFF))
flush_cache(start_addr, trans_bytes);
#endif
udelay(5);
cmd_timeout = CONFIG_SDHCI_CMD_DEFAULT_TIMEOUT;
sdhci_writew(host, SDHCI_MAKE_CMD(cmd->cmdidx, flags), SDHCI_COMMAND);
start = get_timer(0);
do {
stat = sdhci_readl(host, SDHCI_INT_STATUS);
if (stat & SDHCI_INT_ERROR)
break;
if (get_timer(start) > cmd_timeout) {
if (2 * cmd_timeout <= CONFIG_SDHCI_CMD_MAX_TIMEOUT) {
cmd_timeout += cmd_timeout;
printf("%s: MMC: %d busy "
"timeout increasing to: %u ms.\n",
__func__, mmc_dev, cmd_timeout);
} else {
printf("timeout.\n");
ret = TIMEOUT;
goto end;
}
}
} while ((stat & mask) != mask);
if (get_timer(start) >= CONFIG_SDHCI_CMD_MAX_TIMEOUT) {
if (host->quirks & SDHCI_QUIRK_BROKEN_R1B)
ret = 0;
else {
printf("%s: Timeout for status update!\n", __func__);
ret = TIMEOUT;
}
goto end;
}
if ((stat & (SDHCI_INT_ERROR | mask)) == mask) {
sdhci_cmd_done(host, cmd);
sdhci_writel(host, mask, SDHCI_INT_STATUS);
} else
ret = -1;
if (!ret && data)
ret = sdhci_transfer_data(host, data, start_addr);
if (host->quirks & SDHCI_QUIRK_WAIT_SEND_CMD)
udelay(1000);
stat = sdhci_readl(host, SDHCI_INT_STATUS);
sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS);
if (!ret) {
if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) &&
!is_aligned && (data->flags == MMC_DATA_READ))
memcpy(data->dest, aligned_buffer, trans_bytes);
ret = 0;
goto end;
}
sdhci_reset(host, SDHCI_RESET_CMD);
sdhci_reset(host, SDHCI_RESET_DATA);
if (stat & SDHCI_INT_TIMEOUT)
ret = TIMEOUT;
else
ret = COMM_ERR;
end:
if (adma_addr)
free(adma_addr);
return ret;
}
static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
{
struct sdhci_host *host = mmc->priv;
unsigned int div, clk, timeout, reg;
/* Wait max 20 ms */
timeout = 200;
while (sdhci_readl(host, SDHCI_PRESENT_STATE) &
(SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT)) {
if (timeout == 0) {
printf("%s: Timeout to wait cmd & data inhibit\n",
__func__);
return -1;
}
timeout--;
udelay(100);
}
reg = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
reg &= ~SDHCI_CLOCK_CARD_EN;
sdhci_writew(host, reg, SDHCI_CLOCK_CONTROL);
if (clock == 0)
return 0;
if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) {
/* Version 3.00 divisors must be a multiple of 2. */
if (mmc->cfg->f_max <= clock)
div = 1;
else {
for (div = 2; div < SDHCI_MAX_DIV_SPEC_300; div += 2) {
if ((mmc->cfg->f_max / div) <= clock)
break;
}
}
} else {
/* Version 2.00 divisors must be a power of 2. */
for (div = 1; div < SDHCI_MAX_DIV_SPEC_200; div *= 2) {
if ((mmc->cfg->f_max / div) <= clock)
break;
}
}
div >>= 1;
if (host->set_clock)
host->set_clock(host->index, div);
clk = (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
<< SDHCI_DIVIDER_HI_SHIFT;
clk |= SDHCI_CLOCK_INT_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
/* Wait max 20 ms */
timeout = 20;
while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
& SDHCI_CLOCK_INT_STABLE)) {
if (timeout == 0) {
printf("%s: Internal clock never stabilised.\n",
__func__);
return -1;
}
timeout--;
udelay(1000);
}
clk |= SDHCI_CLOCK_CARD_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
return 0;
}
static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
{
u8 pwr = 0;
if (power != (unsigned short)-1) {
switch (1 << power) {
case MMC_VDD_165_195:
pwr = SDHCI_POWER_180;
break;
case MMC_VDD_29_30:
case MMC_VDD_30_31:
pwr = SDHCI_POWER_300;
break;
case MMC_VDD_32_33:
case MMC_VDD_33_34:
pwr = SDHCI_POWER_330;
break;
}
}
if (pwr == 0) {
sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
return;
}
if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER)
sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
pwr |= SDHCI_POWER_ON;
sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
}
static void sdhci_set_ios(struct mmc *mmc)
{
u32 ctrl;
struct sdhci_host *host = mmc->priv;
if (host->set_control_reg)
host->set_control_reg(host);
if (mmc->clock != host->clock)
sdhci_set_clock(mmc, mmc->clock);
/* Set bus width */
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
if (mmc->bus_width == 8) {
ctrl &= ~SDHCI_CTRL_4BITBUS;
if ((SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) ||
(host->quirks & SDHCI_QUIRK_USE_WIDE8))
ctrl |= SDHCI_CTRL_8BITBUS;
} else {
if ((SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) ||
(host->quirks & SDHCI_QUIRK_USE_WIDE8))
ctrl &= ~SDHCI_CTRL_8BITBUS;
if (mmc->bus_width == 4)
ctrl |= SDHCI_CTRL_4BITBUS;
else
ctrl &= ~SDHCI_CTRL_4BITBUS;
}
if (mmc->clock > 26000000)
ctrl |= SDHCI_CTRL_HISPD;
else
ctrl &= ~SDHCI_CTRL_HISPD;
if (host->quirks & SDHCI_QUIRK_NO_HISPD_BIT)
ctrl &= ~SDHCI_CTRL_HISPD;
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
}
static int sdhci_init(struct mmc *mmc)
{
struct sdhci_host *host = mmc->priv;
if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && !aligned_buffer) {
aligned_buffer = memalign(8, 512*1024);
if (!aligned_buffer) {
printf("%s: Aligned buffer alloc failed!!!\n",
__func__);
return -1;
}
}
sdhci_set_power(host, fls(host->cfg.voltages) - 1);
if (host->quirks & SDHCI_QUIRK_NO_CD) {
unsigned int status;
sdhci_writeb(host, SDHCI_CTRL_CD_TEST_INS | SDHCI_CTRL_CD_TEST,
SDHCI_HOST_CONTROL);
status = sdhci_readl(host, SDHCI_PRESENT_STATE);
while ((!(status & SDHCI_CARD_PRESENT)) ||
(!(status & SDHCI_CARD_STATE_STABLE)) ||
(!(status & SDHCI_CARD_DETECT_PIN_LEVEL)))
status = sdhci_readl(host, SDHCI_PRESENT_STATE);
}
/* Enable only interrupts served by the SD controller */
sdhci_writel(host, SDHCI_INT_DATA_MASK | SDHCI_INT_CMD_MASK,
SDHCI_INT_ENABLE);
/* Mask all sdhci interrupt sources */
sdhci_writel(host, 0x0, SDHCI_SIGNAL_ENABLE);
return 0;
}
__weak void mmc_iopad_config(struct sdhci_host *host)
{
return;
}
static const struct mmc_ops sdhci_ops = {
.send_cmd = sdhci_send_command,
.set_ios = sdhci_set_ios,
.init = sdhci_init,
};
int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)
{
unsigned int caps;
host->cfg.name = host->name;
host->cfg.ops = &sdhci_ops;
caps = sdhci_readl(host, SDHCI_CAPABILITIES);
#ifdef CONFIG_MMC_SDMA
if (!(caps & SDHCI_CAN_DO_SDMA)) {
printf("%s: Your controller doesn't support SDMA!!\n",
__func__);
return -1;
}
#endif
if (max_clk)
host->cfg.f_max = max_clk;
else {
if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300)
host->cfg.f_max = (caps & SDHCI_CLOCK_V3_BASE_MASK)
>> SDHCI_CLOCK_BASE_SHIFT;
else
host->cfg.f_max = (caps & SDHCI_CLOCK_BASE_MASK)
>> SDHCI_CLOCK_BASE_SHIFT;
host->cfg.f_max *= 1000000;
}
if (host->cfg.f_max == 0) {
printf("%s: Hardware doesn't specify base clock frequency\n",
__func__);
return -1;
}
if (min_clk)
host->cfg.f_min = min_clk;
else {
if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300)
host->cfg.f_min = host->cfg.f_max /
SDHCI_MAX_DIV_SPEC_300;
else
host->cfg.f_min = host->cfg.f_max /
SDHCI_MAX_DIV_SPEC_200;
}
host->cfg.voltages = 0;
if (caps & SDHCI_CAN_VDD_330)
host->cfg.voltages |= MMC_VDD_32_33 | MMC_VDD_33_34;
if (caps & SDHCI_CAN_VDD_300)
host->cfg.voltages |= MMC_VDD_29_30 | MMC_VDD_30_31;
if (caps & SDHCI_CAN_VDD_180)
host->cfg.voltages |= MMC_VDD_165_195;
if (host->quirks & SDHCI_QUIRK_BROKEN_VOLTAGE)
host->cfg.voltages |= host->voltages;
host->cfg.host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_8BIT;
if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) {
if (caps & SDHCI_CAN_DO_8BIT)
host->cfg.host_caps |= MMC_MODE_8BIT;
}
if (host->host_caps)
host->cfg.host_caps |= host->host_caps;
host->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
sdhci_reset(host, SDHCI_RESET_ALL);
mmc_iopad_config(host);
host->mmc = mmc_create(&host->cfg, host);
if (host->mmc == NULL) {
printf("%s: mmc create fail!\n", __func__);
return -1;
}
host->dev_num = host->mmc->block_dev.dev;
host->mmc->has_init = 0;
host->mmc->init_in_progress = 0;
return 0;
}