- Fix mmc_switch timeout
- Update mmc hwpartitiion command
- Support wait_dat0 for Freescale eSDHC/sdhci drivers
This commit is contained in:
Tom Rini 2021-10-29 08:27:32 -04:00
commit a09929cc6c
7 changed files with 89 additions and 6 deletions

View File

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

View File

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

View File

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

View File

@ -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, &regs->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[] = {

View File

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

View File

@ -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 = {

View File

@ -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)