Merge branch 'master' of http://git.denx.de/u-boot-mmc
This commit is contained in:
commit
f85fad024f
@ -120,9 +120,9 @@ static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data)
|
||||
|
||||
if (host->fifo_mode && size) {
|
||||
len = 0;
|
||||
if (data->flags == MMC_DATA_READ) {
|
||||
if ((dwmci_readl(host, DWMCI_RINTSTS) &
|
||||
DWMCI_INTMSK_RXDR)) {
|
||||
if (data->flags == MMC_DATA_READ &&
|
||||
(mask & DWMCI_INTMSK_RXDR)) {
|
||||
while (size) {
|
||||
len = dwmci_readl(host, DWMCI_STATUS);
|
||||
len = (len >> DWMCI_FIFO_SHIFT) &
|
||||
DWMCI_FIFO_MASK;
|
||||
@ -130,12 +130,13 @@ static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data)
|
||||
for (i = 0; i < len; i++)
|
||||
*buf++ =
|
||||
dwmci_readl(host, DWMCI_DATA);
|
||||
dwmci_writel(host, DWMCI_RINTSTS,
|
||||
DWMCI_INTMSK_RXDR);
|
||||
size = size > len ? (size - len) : 0;
|
||||
}
|
||||
} else {
|
||||
if ((dwmci_readl(host, DWMCI_RINTSTS) &
|
||||
DWMCI_INTMSK_TXDR)) {
|
||||
dwmci_writel(host, DWMCI_RINTSTS,
|
||||
DWMCI_INTMSK_RXDR);
|
||||
} else if (data->flags == MMC_DATA_WRITE &&
|
||||
(mask & DWMCI_INTMSK_TXDR)) {
|
||||
while (size) {
|
||||
len = dwmci_readl(host, DWMCI_STATUS);
|
||||
len = fifo_depth - ((len >>
|
||||
DWMCI_FIFO_SHIFT) &
|
||||
@ -144,11 +145,11 @@ static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data)
|
||||
for (i = 0; i < len; i++)
|
||||
dwmci_writel(host, DWMCI_DATA,
|
||||
*buf++);
|
||||
dwmci_writel(host, DWMCI_RINTSTS,
|
||||
DWMCI_INTMSK_TXDR);
|
||||
size = size > len ? (size - len) : 0;
|
||||
}
|
||||
dwmci_writel(host, DWMCI_RINTSTS,
|
||||
DWMCI_INTMSK_TXDR);
|
||||
}
|
||||
size = size > len ? (size - len) : 0;
|
||||
}
|
||||
|
||||
/* Data arrived correctly. */
|
||||
|
@ -21,6 +21,14 @@
|
||||
#include <div64.h>
|
||||
#include "mmc_private.h"
|
||||
|
||||
static const unsigned int sd_au_size[] = {
|
||||
0, SZ_16K / 512, SZ_32K / 512,
|
||||
SZ_64K / 512, SZ_128K / 512, SZ_256K / 512,
|
||||
SZ_512K / 512, SZ_1M / 512, SZ_2M / 512,
|
||||
SZ_4M / 512, SZ_8M / 512, (SZ_8M + SZ_4M) / 512,
|
||||
SZ_16M / 512, (SZ_16M + SZ_8M) / 512, SZ_32M / 512, SZ_64M / 512,
|
||||
};
|
||||
|
||||
#ifndef CONFIG_DM_MMC_OPS
|
||||
__weak int board_mmc_getwp(struct mmc *mmc)
|
||||
{
|
||||
@ -945,6 +953,62 @@ retry_scr:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sd_read_ssr(struct mmc *mmc)
|
||||
{
|
||||
int err, i;
|
||||
struct mmc_cmd cmd;
|
||||
ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16);
|
||||
struct mmc_data data;
|
||||
int timeout = 3;
|
||||
unsigned int au, eo, et, es;
|
||||
|
||||
cmd.cmdidx = MMC_CMD_APP_CMD;
|
||||
cmd.resp_type = MMC_RSP_R1;
|
||||
cmd.cmdarg = mmc->rca << 16;
|
||||
|
||||
err = mmc_send_cmd(mmc, &cmd, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
cmd.cmdidx = SD_CMD_APP_SD_STATUS;
|
||||
cmd.resp_type = MMC_RSP_R1;
|
||||
cmd.cmdarg = 0;
|
||||
|
||||
retry_ssr:
|
||||
data.dest = (char *)ssr;
|
||||
data.blocksize = 64;
|
||||
data.blocks = 1;
|
||||
data.flags = MMC_DATA_READ;
|
||||
|
||||
err = mmc_send_cmd(mmc, &cmd, &data);
|
||||
if (err) {
|
||||
if (timeout--)
|
||||
goto retry_ssr;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
ssr[i] = be32_to_cpu(ssr[i]);
|
||||
|
||||
au = (ssr[2] >> 12) & 0xF;
|
||||
if ((au <= 9) || (mmc->version == SD_VERSION_3)) {
|
||||
mmc->ssr.au = sd_au_size[au];
|
||||
es = (ssr[3] >> 24) & 0xFF;
|
||||
es |= (ssr[2] & 0xFF) << 8;
|
||||
et = (ssr[3] >> 18) & 0x3F;
|
||||
if (es && et) {
|
||||
eo = (ssr[3] >> 16) & 0x3;
|
||||
mmc->ssr.erase_timeout = (et * 1000) / es;
|
||||
mmc->ssr.erase_offset = eo * 1000;
|
||||
}
|
||||
} else {
|
||||
debug("Invalid Allocation Unit Size.\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* frequency bases */
|
||||
/* divided by 10 to be nice to platforms without floating point */
|
||||
static const int fbase[] = {
|
||||
@ -1350,6 +1414,10 @@ static int mmc_startup(struct mmc *mmc)
|
||||
mmc_set_bus_width(mmc, 4);
|
||||
}
|
||||
|
||||
err = sd_read_ssr(mmc);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (mmc->card_caps & MMC_MODE_HS)
|
||||
mmc->tran_speed = 50000000;
|
||||
else
|
||||
|
@ -100,8 +100,13 @@ unsigned long mmc_berase(struct blk_desc *block_dev, lbaint_t start,
|
||||
& ~(mmc->erase_grp_size - 1)) - 1);
|
||||
|
||||
while (blk < blkcnt) {
|
||||
blk_r = ((blkcnt - blk) > mmc->erase_grp_size) ?
|
||||
mmc->erase_grp_size : (blkcnt - blk);
|
||||
if (IS_SD(mmc) && mmc->ssr.au) {
|
||||
blk_r = ((blkcnt - blk) > mmc->ssr.au) ?
|
||||
mmc->ssr.au : (blkcnt - blk);
|
||||
} else {
|
||||
blk_r = ((blkcnt - blk) > mmc->erase_grp_size) ?
|
||||
mmc->erase_grp_size : (blkcnt - blk);
|
||||
}
|
||||
err = mmc_erase_t(mmc, start + blk, blk_r);
|
||||
if (err)
|
||||
break;
|
||||
|
@ -121,13 +121,10 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data,
|
||||
* 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.
|
||||
* Each function call will use last timeout value.
|
||||
*/
|
||||
#ifndef CONFIG_SDHCI_CMD_MAX_TIMEOUT
|
||||
#define CONFIG_SDHCI_CMD_MAX_TIMEOUT 3200
|
||||
#endif
|
||||
#define CONFIG_SDHCI_CMD_DEFAULT_TIMEOUT 100
|
||||
#define SDHCI_CMD_MAX_TIMEOUT 3200
|
||||
#define SDHCI_CMD_DEFAULT_TIMEOUT 100
|
||||
#define SDHCI_READ_STATUS_TIMEOUT 1000
|
||||
|
||||
#ifdef CONFIG_DM_MMC_OPS
|
||||
@ -151,7 +148,7 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
|
||||
unsigned start = get_timer(0);
|
||||
|
||||
/* Timeout unit - ms */
|
||||
static unsigned int cmd_timeout = CONFIG_SDHCI_CMD_DEFAULT_TIMEOUT;
|
||||
static unsigned int cmd_timeout = SDHCI_CMD_DEFAULT_TIMEOUT;
|
||||
|
||||
sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS);
|
||||
mask = SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT;
|
||||
@ -164,7 +161,7 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
|
||||
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) {
|
||||
if (2 * cmd_timeout <= SDHCI_CMD_MAX_TIMEOUT) {
|
||||
cmd_timeout += cmd_timeout;
|
||||
printf("timeout increasing to: %u ms.\n",
|
||||
cmd_timeout);
|
||||
@ -297,7 +294,7 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
|
||||
static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
|
||||
{
|
||||
struct sdhci_host *host = mmc->priv;
|
||||
unsigned int div, clk, timeout, reg;
|
||||
unsigned int div, clk = 0, timeout, reg;
|
||||
|
||||
/* Wait max 20 ms */
|
||||
timeout = 200;
|
||||
@ -321,14 +318,36 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
|
||||
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)
|
||||
/*
|
||||
* Check if the Host Controller supports Programmable Clock
|
||||
* Mode.
|
||||
*/
|
||||
if (host->clk_mul) {
|
||||
for (div = 1; div <= 1024; div++) {
|
||||
if ((mmc->cfg->f_max * host->clk_mul / div)
|
||||
<= clock)
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set Programmable Clock Mode in the Clock
|
||||
* Control register.
|
||||
*/
|
||||
clk = SDHCI_PROG_CLOCK_MODE;
|
||||
div--;
|
||||
} else {
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
div >>= 1;
|
||||
}
|
||||
} else {
|
||||
/* Version 2.00 divisors must be a power of 2. */
|
||||
@ -336,13 +355,13 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
|
||||
if ((mmc->cfg->f_max / div) <= clock)
|
||||
break;
|
||||
}
|
||||
div >>= 1;
|
||||
}
|
||||
div >>= 1;
|
||||
|
||||
if (host->set_clock)
|
||||
host->set_clock(host->index, div);
|
||||
|
||||
clk = (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
|
||||
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;
|
||||
@ -451,6 +470,8 @@ static int sdhci_init(struct mmc *mmc)
|
||||
{
|
||||
struct sdhci_host *host = mmc->priv;
|
||||
|
||||
sdhci_reset(host, SDHCI_RESET_ALL);
|
||||
|
||||
if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && !aligned_buffer) {
|
||||
aligned_buffer = memalign(8, 512*1024);
|
||||
if (!aligned_buffer) {
|
||||
@ -514,9 +535,17 @@ static const struct mmc_ops sdhci_ops = {
|
||||
int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host,
|
||||
u32 max_clk, u32 min_clk)
|
||||
{
|
||||
u32 caps;
|
||||
u32 caps, caps_1;
|
||||
|
||||
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 -EINVAL;
|
||||
}
|
||||
#endif
|
||||
host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
|
||||
|
||||
cfg->name = host->name;
|
||||
@ -534,8 +563,11 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host,
|
||||
SDHCI_CLOCK_BASE_SHIFT;
|
||||
cfg->f_max *= 1000000;
|
||||
}
|
||||
if (cfg->f_max == 0)
|
||||
if (cfg->f_max == 0) {
|
||||
printf("%s: Hardware doesn't specify base clock frequency\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (min_clk)
|
||||
cfg->f_min = min_clk;
|
||||
else {
|
||||
@ -552,6 +584,9 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host,
|
||||
if (caps & SDHCI_CAN_VDD_180)
|
||||
cfg->voltages |= MMC_VDD_165_195;
|
||||
|
||||
if (host->quirks & SDHCI_QUIRK_BROKEN_VOLTAGE)
|
||||
cfg->voltages |= host->voltages;
|
||||
|
||||
cfg->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT;
|
||||
if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) {
|
||||
if (caps & SDHCI_CAN_DO_8BIT)
|
||||
@ -564,6 +599,14 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host,
|
||||
|
||||
cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
|
||||
|
||||
/*
|
||||
* In case of Host Controller v3.00, find out whether clock
|
||||
* multiplier is supported.
|
||||
*/
|
||||
caps_1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
|
||||
host->clk_mul = (caps_1 & SDHCI_CLOCK_MUL_MASK) >>
|
||||
SDHCI_CLOCK_MUL_SHIFT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -575,27 +618,11 @@ int sdhci_bind(struct udevice *dev, struct mmc *mmc, struct mmc_config *cfg)
|
||||
#else
|
||||
int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)
|
||||
{
|
||||
#ifdef CONFIG_MMC_SDMA
|
||||
unsigned int caps;
|
||||
int ret;
|
||||
|
||||
caps = sdhci_readl(host, SDHCI_CAPABILITIES);
|
||||
if (!(caps & SDHCI_CAN_DO_SDMA)) {
|
||||
printf("%s: Your controller doesn't support SDMA!!\n",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (sdhci_setup_cfg(&host->cfg, host, max_clk, min_clk)) {
|
||||
printf("%s: Hardware doesn't specify base clock frequency\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (host->quirks & SDHCI_QUIRK_BROKEN_VOLTAGE)
|
||||
host->cfg.voltages |= host->voltages;
|
||||
|
||||
sdhci_reset(host, SDHCI_RESET_ALL);
|
||||
ret = sdhci_setup_cfg(&host->cfg, host, max_clk, min_clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
host->mmc = mmc_create(&host->cfg, host);
|
||||
if (host->mmc == NULL) {
|
||||
|
@ -11,6 +11,7 @@
|
||||
#define _MMC_H_
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <part.h>
|
||||
|
||||
@ -102,6 +103,7 @@
|
||||
#define SD_CMD_SWITCH_UHS18V 11
|
||||
|
||||
#define SD_CMD_APP_SET_BUS_WIDTH 6
|
||||
#define SD_CMD_APP_SD_STATUS 13
|
||||
#define SD_CMD_ERASE_WR_BLK_START 32
|
||||
#define SD_CMD_ERASE_WR_BLK_END 33
|
||||
#define SD_CMD_APP_SEND_OP_COND 41
|
||||
@ -392,6 +394,12 @@ struct mmc_config {
|
||||
unsigned char part_type;
|
||||
};
|
||||
|
||||
struct sd_ssr {
|
||||
unsigned int au; /* In sectors */
|
||||
unsigned int erase_timeout; /* In milliseconds */
|
||||
unsigned int erase_offset; /* In milliseconds */
|
||||
};
|
||||
|
||||
/*
|
||||
* With CONFIG_DM_MMC enabled, struct mmc can be accessed from the MMC device
|
||||
* with mmc_get_mmc_dev().
|
||||
@ -426,6 +434,7 @@ struct mmc {
|
||||
uint write_bl_len;
|
||||
uint erase_grp_size; /* in 512-byte sectors */
|
||||
uint hc_wp_grp_size; /* in 512-byte sectors */
|
||||
struct sd_ssr ssr; /* SD status register */
|
||||
u64 capacity;
|
||||
u64 capacity_user;
|
||||
u64 capacity_boot;
|
||||
|
@ -97,6 +97,7 @@
|
||||
#define SDHCI_DIV_MASK 0xFF
|
||||
#define SDHCI_DIV_MASK_LEN 8
|
||||
#define SDHCI_DIV_HI_MASK 0x300
|
||||
#define SDHCI_PROG_CLOCK_MODE 0x0020
|
||||
#define SDHCI_CLOCK_CARD_EN 0x0004
|
||||
#define SDHCI_CLOCK_INT_STABLE 0x0002
|
||||
#define SDHCI_CLOCK_INT_EN 0x0001
|
||||
@ -242,6 +243,7 @@ struct sdhci_host {
|
||||
unsigned int quirks;
|
||||
unsigned int host_caps;
|
||||
unsigned int version;
|
||||
unsigned int clk_mul; /* Clock Multiplier value */
|
||||
unsigned int clock;
|
||||
struct mmc *mmc;
|
||||
const struct sdhci_ops *ops;
|
||||
|
Loading…
Reference in New Issue
Block a user