- Fix mmc_switch timeout - Update mmc hwpartitiion command - Support wait_dat0 for Freescale eSDHC/sdhci drivers
This commit is contained in:
commit
a09929cc6c
38
cmd/mmc.c
38
cmd/mmc.c
@ -593,7 +593,33 @@ static int do_mmc_list(struct cmd_tbl *cmdtp, int flag,
|
||||
}
|
||||
|
||||
#if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING)
|
||||
static int parse_hwpart_user(struct mmc_hwpart_conf *pconf,
|
||||
static void parse_hwpart_user_enh_size(struct mmc *mmc,
|
||||
struct mmc_hwpart_conf *pconf,
|
||||
char *argv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pconf->user.enh_size = 0;
|
||||
|
||||
if (!strcmp(argv, "-")) { /* The rest of eMMC */
|
||||
ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
|
||||
ret = mmc_send_ext_csd(mmc, ext_csd);
|
||||
if (ret)
|
||||
return;
|
||||
/* This value is in 512B block units */
|
||||
pconf->user.enh_size =
|
||||
((ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT + 2] << 16) +
|
||||
(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT + 1] << 8) +
|
||||
ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]) * 1024 *
|
||||
ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] *
|
||||
ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
|
||||
pconf->user.enh_size -= pconf->user.enh_start;
|
||||
} else {
|
||||
pconf->user.enh_size = dectoul(argv, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static int parse_hwpart_user(struct mmc *mmc, struct mmc_hwpart_conf *pconf,
|
||||
int argc, char *const argv[])
|
||||
{
|
||||
int i = 0;
|
||||
@ -606,8 +632,7 @@ static int parse_hwpart_user(struct mmc_hwpart_conf *pconf,
|
||||
return -1;
|
||||
pconf->user.enh_start =
|
||||
dectoul(argv[i + 1], NULL);
|
||||
pconf->user.enh_size =
|
||||
dectoul(argv[i + 2], NULL);
|
||||
parse_hwpart_user_enh_size(mmc, pconf, argv[i + 2]);
|
||||
i += 3;
|
||||
} else if (!strcmp(argv[i], "wrrel")) {
|
||||
if (i + 1 >= argc)
|
||||
@ -673,13 +698,18 @@ static int do_mmc_hwpartition(struct cmd_tbl *cmdtp, int flag,
|
||||
if (!mmc)
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
if (IS_SD(mmc)) {
|
||||
puts("SD doesn't support partitioning\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
if (argc < 1)
|
||||
return CMD_RET_USAGE;
|
||||
i = 1;
|
||||
while (i < argc) {
|
||||
if (!strcmp(argv[i], "user")) {
|
||||
i++;
|
||||
r = parse_hwpart_user(&pconf, argc-i, &argv[i]);
|
||||
r = parse_hwpart_user(mmc, &pconf, argc - i, &argv[i]);
|
||||
if (r < 0)
|
||||
return CMD_RET_USAGE;
|
||||
i += r;
|
||||
|
@ -282,6 +282,14 @@ static int host_request(struct mmc *dev,
|
||||
return result;
|
||||
}
|
||||
|
||||
static int check_peripheral_id(struct pl180_mmc_host *host, u32 periph_id)
|
||||
{
|
||||
return readl(&host->base->periph_id0) == (periph_id & 0xFF) &&
|
||||
readl(&host->base->periph_id1) == ((periph_id >> 8) & 0xFF) &&
|
||||
readl(&host->base->periph_id2) == ((periph_id >> 16) & 0xFF) &&
|
||||
readl(&host->base->periph_id3) == ((periph_id >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
static int host_set_ios(struct mmc *dev)
|
||||
{
|
||||
struct pl180_mmc_host *host = dev->priv;
|
||||
@ -337,6 +345,12 @@ static int host_set_ios(struct mmc *dev)
|
||||
sdi_clkcr &= ~(SDI_CLKCR_WIDBUS_MASK);
|
||||
sdi_clkcr |= buswidth;
|
||||
}
|
||||
/* For MMCs' with peripheral id 0x02041180 and 0x03041180, H/W flow control
|
||||
* needs to be enabled for multi block writes (MMC CMD 18).
|
||||
*/
|
||||
if (check_peripheral_id(host, 0x02041180) ||
|
||||
check_peripheral_id(host, 0x03041180))
|
||||
sdi_clkcr |= SDI_CLKCR_HWFCEN;
|
||||
|
||||
writel(sdi_clkcr, &host->base->clock);
|
||||
udelay(CLK_CHANGE_DELAY);
|
||||
|
@ -43,6 +43,7 @@
|
||||
#define SDI_CLKCR_CLKEN 0x00000100
|
||||
#define SDI_CLKCR_PWRSAV 0x00000200
|
||||
#define SDI_CLKCR_BYPASS 0x00000400
|
||||
#define SDI_CLKCR_HWFCEN 0x00001000
|
||||
#define SDI_CLKCR_WIDBUS_MASK 0x00001800
|
||||
#define SDI_CLKCR_WIDBUS_1 0x00000000
|
||||
#define SDI_CLKCR_WIDBUS_4 0x00000800
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <dm/device_compat.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <sdhci.h>
|
||||
|
||||
@ -1138,6 +1139,20 @@ int fsl_esdhc_hs400_prepare_ddr(struct udevice *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsl_esdhc_wait_dat0(struct udevice *dev, int state,
|
||||
int timeout_us)
|
||||
{
|
||||
int ret;
|
||||
u32 tmp;
|
||||
struct fsl_esdhc_priv *priv = dev_get_priv(dev);
|
||||
struct fsl_esdhc *regs = priv->esdhc_regs;
|
||||
|
||||
ret = readx_poll_timeout(esdhc_read32, ®s->prsstat, tmp,
|
||||
!!(tmp & PRSSTAT_DAT0) == !!state,
|
||||
timeout_us);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct dm_mmc_ops fsl_esdhc_ops = {
|
||||
.get_cd = fsl_esdhc_get_cd,
|
||||
.send_cmd = fsl_esdhc_send_cmd,
|
||||
@ -1147,6 +1162,7 @@ static const struct dm_mmc_ops fsl_esdhc_ops = {
|
||||
#endif
|
||||
.reinit = fsl_esdhc_reinit,
|
||||
.hs400_prepare_ddr = fsl_esdhc_hs400_prepare_ddr,
|
||||
.wait_dat0 = fsl_esdhc_wait_dat0,
|
||||
};
|
||||
|
||||
static const struct udevice_id fsl_esdhc_ids[] = {
|
||||
|
@ -819,11 +819,11 @@ static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value,
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* In cases when not allowed to poll by using CMD13 or because we aren't
|
||||
* In cases when neiter allowed to poll by using CMD13 nor we are
|
||||
* capable of polling by using mmc_wait_dat0, then rely on waiting the
|
||||
* stated timeout to be sufficient.
|
||||
*/
|
||||
if (ret == -ENOSYS || !send_status) {
|
||||
if (ret == -ENOSYS && !send_status) {
|
||||
mdelay(timeout_ms);
|
||||
return 0;
|
||||
}
|
||||
|
@ -780,6 +780,25 @@ static int sdhci_get_cd(struct udevice *dev)
|
||||
return value;
|
||||
}
|
||||
|
||||
static int sdhci_wait_dat0(struct udevice *dev, int state,
|
||||
int timeout_us)
|
||||
{
|
||||
int tmp;
|
||||
struct mmc *mmc = mmc_get_mmc_dev(dev);
|
||||
struct sdhci_host *host = mmc->priv;
|
||||
unsigned long timeout = timer_get_us() + timeout_us;
|
||||
|
||||
// readx_poll_timeout is unsuitable because sdhci_readl accepts
|
||||
// two arguments
|
||||
do {
|
||||
tmp = sdhci_readl(host, SDHCI_PRESENT_STATE);
|
||||
if (!!(tmp & SDHCI_DATA_0_LVL_MASK) == !!state)
|
||||
return 0;
|
||||
} while (!timeout_us || !time_after(timer_get_us(), timeout));
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
const struct dm_mmc_ops sdhci_ops = {
|
||||
.send_cmd = sdhci_send_command,
|
||||
.set_ios = sdhci_set_ios,
|
||||
@ -788,6 +807,7 @@ const struct dm_mmc_ops sdhci_ops = {
|
||||
#ifdef MMC_SUPPORTS_TUNING
|
||||
.execute_tuning = sdhci_execute_tuning,
|
||||
#endif
|
||||
.wait_dat0 = sdhci_wait_dat0,
|
||||
};
|
||||
#else
|
||||
static const struct mmc_ops sdhci_ops = {
|
||||
|
@ -65,6 +65,8 @@
|
||||
#define SDHCI_CARD_STATE_STABLE BIT(17)
|
||||
#define SDHCI_CARD_DETECT_PIN_LEVEL BIT(18)
|
||||
#define SDHCI_WRITE_PROTECT BIT(19)
|
||||
#define SDHCI_DATA_LVL_MASK 0x00F00000
|
||||
#define SDHCI_DATA_0_LVL_MASK BIT(20)
|
||||
|
||||
#define SDHCI_HOST_CONTROL 0x28
|
||||
#define SDHCI_CTRL_LED BIT(0)
|
||||
|
Loading…
Reference in New Issue
Block a user