int (*mmc_is_wp)(int);
int (*mmc_cd)(int);
struct mxs_dma_desc *desc;
+ struct mmc_config cfg; /* mmc configuration */
};
#define MXSMMC_MAX_TIMEOUT 10000
return timeout ? 0 : COMM_ERR;
}
-static int mxsmmc_send_cmd_dma(struct mxsmmc_priv *priv, struct mmc_data *data)
+static int mxsmmc_send_cmd_dma(struct mmc *mmc, struct mxsmmc_priv *priv,
+ struct mmc_data *data)
{
uint32_t data_count = data->blocksize * data->blocks;
int dmach;
void *addr;
unsigned int flags;
struct bounce_buffer bbstate;
+ unsigned long xfer_rate = (mmc->clock ?: 400000) * mmc->bus_width;
+ unsigned long dma_timeout = data_count * 8 /
+ DIV_ROUND_UP(xfer_rate, 1000);
memset(desc, 0, sizeof(struct mxs_dma_desc));
desc->address = (dma_addr_t)desc;
dmach = MXS_DMA_CHANNEL_AHB_APBH_SSP0 + priv->id;
mxs_dma_desc_append(dmach, priv->desc);
+ /* set DMA timeout adding 250ms for min timeout according to SD spec. */
+ mxs_dma_set_timeout(dmach, dma_timeout + 250);
if (mxs_dma_go(dmach)) {
bounce_buffer_stop(&bbstate);
return COMM_ERR;
static int
mxsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
{
- struct mxsmmc_priv *priv = (struct mxsmmc_priv *)mmc->priv;
+ struct mxsmmc_priv *priv = mmc->priv;
struct mxs_ssp_regs *ssp_regs = priv->regs;
uint32_t reg;
int timeout;
ctrl0 |= SSP_CTRL0_DATA_XFER;
reg = data->blocksize * data->blocks;
-#if defined(CONFIG_MX23)
+#if defined(CONFIG_SOC_MX23)
ctrl0 |= reg & SSP_CTRL0_XFER_COUNT_MASK;
clrsetbits_le32(&ssp_regs->hw_ssp_cmd0,
((data->blocks - 1) << SSP_CMD0_BLOCK_COUNT_OFFSET) |
((ffs(data->blocksize) - 1) <<
SSP_CMD0_BLOCK_SIZE_OFFSET));
-#elif defined(CONFIG_MX28)
+#elif defined(CONFIG_SOC_MX28)
writel(reg, &ssp_regs->hw_ssp_xfer_size);
reg = ((data->blocks - 1) <<
return ret;
}
} else {
- ret = mxsmmc_send_cmd_dma(priv, data);
+ ret = mxsmmc_send_cmd_dma(mmc, priv, data);
if (ret) {
printf("MMC%d: DMA transfer failed\n",
mmc->block_dev.dev);
static void mxsmmc_set_ios(struct mmc *mmc)
{
- struct mxsmmc_priv *priv = (struct mxsmmc_priv *)mmc->priv;
+ struct mxsmmc_priv *priv = mmc->priv;
struct mxs_ssp_regs *ssp_regs = priv->regs;
/* Set the clock speed */
static int mxsmmc_init(struct mmc *mmc)
{
- struct mxsmmc_priv *priv = (struct mxsmmc_priv *)mmc->priv;
+ struct mxsmmc_priv *priv = mmc->priv;
struct mxs_ssp_regs *ssp_regs = priv->regs;
/* Reset SSP */
return 0;
}
+static const struct mmc_ops mxsmmc_ops = {
+ .send_cmd = mxsmmc_send_cmd,
+ .set_ios = mxsmmc_set_ios,
+ .init = mxsmmc_init,
+};
+
int mxsmmc_initialize(bd_t *bis, int id, int (*wp)(int), int (*cd)(int))
{
- struct mmc *mmc = NULL;
- struct mxsmmc_priv *priv = NULL;
+ struct mmc *mmc;
+ struct mxsmmc_priv *priv;
int ret;
const unsigned int mxsmmc_clk_id = mxs_ssp_clock_by_bus(id);
if (!mxs_ssp_bus_id_valid(id))
return -ENODEV;
- mmc = calloc(sizeof(struct mmc), 1);
- if (!mmc)
- return -ENOMEM;
-
priv = calloc(sizeof(struct mxsmmc_priv), 1);
- if (!priv) {
- free(mmc);
+ if (!priv)
return -ENOMEM;
- }
priv->desc = mxs_dma_desc_alloc();
if (!priv->desc) {
- free(priv);
- free(mmc);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto free_priv;
}
ret = mxs_dma_init_channel(MXS_DMA_CHANNEL_AHB_APBH_SSP0 + id);
if (ret)
- return ret;
+ goto free_priv;
priv->mmc_is_wp = wp;
priv->mmc_cd = cd;
priv->id = id;
priv->regs = mxs_ssp_regs_by_bus(id);
- sprintf(mmc->name, "MXS MMC");
- mmc->send_cmd = mxsmmc_send_cmd;
- mmc->set_ios = mxsmmc_set_ios;
- mmc->init = mxsmmc_init;
- mmc->getcd = NULL;
- mmc->getwp = NULL;
- mmc->priv = priv;
+ priv->cfg.name = "MXS MMC";
+ priv->cfg.ops = &mxsmmc_ops;
- mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
+ priv->cfg.voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
- mmc->host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT |
- MMC_MODE_HS_52MHz | MMC_MODE_HS;
+ priv->cfg.host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT |
+ MMC_MODE_HS_52MHz | MMC_MODE_HS |
+ MMC_MODE_HC;
/*
* SSPCLK = 480 * 18 / 29 / 1 = 297.731 MHz
* CLOCK_DIVIDE has to be an even value from 2 to 254, and
* CLOCK_RATE could be any integer from 0 to 255.
*/
- mmc->f_min = 400000;
- mmc->f_max = mxc_get_clock(MXC_SSP0_CLK + mxsmmc_clk_id) * 1000 / 2;
- mmc->b_max = 0x20;
-
- mmc_register(mmc);
+ priv->cfg.f_min = 400000;
+ priv->cfg.f_max = mxc_get_clock(MXC_SSP0_CLK + mxsmmc_clk_id) * 1000 / 2;
+ priv->cfg.b_max = 0x20;
+
+ mmc = mmc_create(&priv->cfg, priv);
+ if (mmc == NULL) {
+ ret = -ENOMEM;
+ goto free_dma;
+ }
return 0;
+
+free_dma:
+ mxs_dma_desc_free(priv->desc);
+free_priv:
+ free(priv);
+ return ret;
}