Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc: sdhci-of: Fix the wrong accessor to HOSTVER register mvsdio: fix config failure with some high speed SDHC cards mvsdio: ignore high speed timing requests from the core mmc/omap: Use disable_irq_nosync() from within irq handlers. sdhci-of: Add fsl,esdhc as a valid compatible to bind against mvsdio: allow automatic loading when modular mxcmmc: Fix missing return value checking in DMA setup code. mxcmmc : Reset the SDHC hardware if software timeout occurs. omap_hsmmc: Trivial fix for a typo in comment mxcmmc: decrease minimum frequency to make MMC cards work
This commit is contained in:
commit
33fa108ed1
|
@ -64,6 +64,31 @@ static int mvsd_setup_data(struct mvsd_host *host, struct mmc_data *data)
|
|||
unsigned int tmout;
|
||||
int tmout_index;
|
||||
|
||||
/*
|
||||
* Hardware weirdness. The FIFO_EMPTY bit of the HW_STATE
|
||||
* register is sometimes not set before a while when some
|
||||
* "unusual" data block sizes are used (such as with the SWITCH
|
||||
* command), even despite the fact that the XFER_DONE interrupt
|
||||
* was raised. And if another data transfer starts before
|
||||
* this bit comes to good sense (which eventually happens by
|
||||
* itself) then the new transfer simply fails with a timeout.
|
||||
*/
|
||||
if (!(mvsd_read(MVSD_HW_STATE) & (1 << 13))) {
|
||||
unsigned long t = jiffies + HZ;
|
||||
unsigned int hw_state, count = 0;
|
||||
do {
|
||||
if (time_after(jiffies, t)) {
|
||||
dev_warn(host->dev, "FIFO_EMPTY bit missing\n");
|
||||
break;
|
||||
}
|
||||
hw_state = mvsd_read(MVSD_HW_STATE);
|
||||
count++;
|
||||
} while (!(hw_state & (1 << 13)));
|
||||
dev_dbg(host->dev, "*** wait for FIFO_EMPTY bit "
|
||||
"(hw=0x%04x, count=%d, jiffies=%ld)\n",
|
||||
hw_state, count, jiffies - (t - HZ));
|
||||
}
|
||||
|
||||
/* If timeout=0 then maximum timeout index is used. */
|
||||
tmout = DIV_ROUND_UP(data->timeout_ns, host->ns_per_clk);
|
||||
tmout += data->timeout_clks;
|
||||
|
@ -620,9 +645,18 @@ static void mvsd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|||
if (ios->bus_width == MMC_BUS_WIDTH_4)
|
||||
ctrl_reg |= MVSD_HOST_CTRL_DATA_WIDTH_4_BITS;
|
||||
|
||||
/*
|
||||
* The HI_SPEED_EN bit is causing trouble with many (but not all)
|
||||
* high speed SD, SDHC and SDIO cards. Not enabling that bit
|
||||
* makes all cards work. So let's just ignore that bit for now
|
||||
* and revisit this issue if problems for not enabling this bit
|
||||
* are ever reported.
|
||||
*/
|
||||
#if 0
|
||||
if (ios->timing == MMC_TIMING_MMC_HS ||
|
||||
ios->timing == MMC_TIMING_SD_HS)
|
||||
ctrl_reg |= MVSD_HOST_CTRL_HI_SPEED_EN;
|
||||
#endif
|
||||
|
||||
host->ctrl = ctrl_reg;
|
||||
mvsd_write(MVSD_HOST_CTRL, ctrl_reg);
|
||||
|
@ -882,3 +916,4 @@ module_param(nodma, int, 0);
|
|||
MODULE_AUTHOR("Maen Suleiman, Nicolas Pitre");
|
||||
MODULE_DESCRIPTION("Marvell MMC,SD,SDIO Host Controller driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:mvsdio");
|
||||
|
|
|
@ -140,6 +140,8 @@ struct mxcmci_host {
|
|||
struct work_struct datawork;
|
||||
};
|
||||
|
||||
static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios);
|
||||
|
||||
static inline int mxcmci_use_dma(struct mxcmci_host *host)
|
||||
{
|
||||
return host->do_dma;
|
||||
|
@ -160,7 +162,7 @@ static void mxcmci_softreset(struct mxcmci_host *host)
|
|||
writew(0xff, host->base + MMC_REG_RES_TO);
|
||||
}
|
||||
|
||||
static void mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
|
||||
static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
|
||||
{
|
||||
unsigned int nob = data->blocks;
|
||||
unsigned int blksz = data->blksz;
|
||||
|
@ -168,6 +170,7 @@ static void mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
|
|||
#ifdef HAS_DMA
|
||||
struct scatterlist *sg;
|
||||
int i;
|
||||
int ret;
|
||||
#endif
|
||||
if (data->flags & MMC_DATA_STREAM)
|
||||
nob = 0xffff;
|
||||
|
@ -183,7 +186,7 @@ static void mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
|
|||
for_each_sg(data->sg, sg, data->sg_len, i) {
|
||||
if (sg->offset & 3 || sg->length & 3) {
|
||||
host->do_dma = 0;
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -192,23 +195,30 @@ static void mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
|
|||
host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg,
|
||||
data->sg_len, host->dma_dir);
|
||||
|
||||
imx_dma_setup_sg(host->dma, data->sg, host->dma_nents, datasize,
|
||||
host->res->start + MMC_REG_BUFFER_ACCESS,
|
||||
DMA_MODE_READ);
|
||||
ret = imx_dma_setup_sg(host->dma, data->sg, host->dma_nents,
|
||||
datasize,
|
||||
host->res->start + MMC_REG_BUFFER_ACCESS,
|
||||
DMA_MODE_READ);
|
||||
} else {
|
||||
host->dma_dir = DMA_TO_DEVICE;
|
||||
host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg,
|
||||
data->sg_len, host->dma_dir);
|
||||
|
||||
imx_dma_setup_sg(host->dma, data->sg, host->dma_nents, datasize,
|
||||
host->res->start + MMC_REG_BUFFER_ACCESS,
|
||||
DMA_MODE_WRITE);
|
||||
ret = imx_dma_setup_sg(host->dma, data->sg, host->dma_nents,
|
||||
datasize,
|
||||
host->res->start + MMC_REG_BUFFER_ACCESS,
|
||||
DMA_MODE_WRITE);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
dev_err(mmc_dev(host->mmc), "failed to setup DMA : %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
wmb();
|
||||
|
||||
imx_dma_enable(host->dma);
|
||||
#endif /* HAS_DMA */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd,
|
||||
|
@ -345,8 +355,11 @@ static int mxcmci_poll_status(struct mxcmci_host *host, u32 mask)
|
|||
stat = readl(host->base + MMC_REG_STATUS);
|
||||
if (stat & STATUS_ERR_MASK)
|
||||
return stat;
|
||||
if (time_after(jiffies, timeout))
|
||||
if (time_after(jiffies, timeout)) {
|
||||
mxcmci_softreset(host);
|
||||
mxcmci_set_clk_rate(host, host->clock);
|
||||
return STATUS_TIME_OUT_READ;
|
||||
}
|
||||
if (stat & mask)
|
||||
return 0;
|
||||
cpu_relax();
|
||||
|
@ -531,6 +544,7 @@ static void mxcmci_request(struct mmc_host *mmc, struct mmc_request *req)
|
|||
{
|
||||
struct mxcmci_host *host = mmc_priv(mmc);
|
||||
unsigned int cmdat = host->cmdat;
|
||||
int error;
|
||||
|
||||
WARN_ON(host->req != NULL);
|
||||
|
||||
|
@ -540,7 +554,12 @@ static void mxcmci_request(struct mmc_host *mmc, struct mmc_request *req)
|
|||
host->do_dma = 1;
|
||||
#endif
|
||||
if (req->data) {
|
||||
mxcmci_setup_data(host, req->data);
|
||||
error = mxcmci_setup_data(host, req->data);
|
||||
if (error) {
|
||||
req->cmd->error = error;
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
cmdat |= CMD_DAT_CONT_DATA_ENABLE;
|
||||
|
||||
|
@ -548,7 +567,9 @@ static void mxcmci_request(struct mmc_host *mmc, struct mmc_request *req)
|
|||
cmdat |= CMD_DAT_CONT_WRITE;
|
||||
}
|
||||
|
||||
if (mxcmci_start_cmd(host, req->cmd, cmdat))
|
||||
error = mxcmci_start_cmd(host, req->cmd, cmdat);
|
||||
out:
|
||||
if (error)
|
||||
mxcmci_finish_request(host, req);
|
||||
}
|
||||
|
||||
|
@ -724,7 +745,9 @@ static int mxcmci_probe(struct platform_device *pdev)
|
|||
goto out_clk_put;
|
||||
}
|
||||
|
||||
mmc->f_min = clk_get_rate(host->clk) >> 7;
|
||||
mmc->f_min = clk_get_rate(host->clk) >> 16;
|
||||
if (mmc->f_min < 400000)
|
||||
mmc->f_min = 400000;
|
||||
mmc->f_max = clk_get_rate(host->clk) >> 1;
|
||||
|
||||
/* recommended in data sheet */
|
||||
|
|
|
@ -822,7 +822,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
|
|||
del_timer(&host->cmd_abort_timer);
|
||||
host->abort = 1;
|
||||
OMAP_MMC_WRITE(host, IE, 0);
|
||||
disable_irq(host->irq);
|
||||
disable_irq_nosync(host->irq);
|
||||
schedule_work(&host->cmd_abort_work);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
|
|
@ -680,7 +680,7 @@ static void mmc_omap_dma_cb(int lch, u16 ch_status, void *data)
|
|||
host->dma_ch = -1;
|
||||
/*
|
||||
* DMA Callback: run in interrupt context.
|
||||
* mutex_unlock will through a kernel warning if used.
|
||||
* mutex_unlock will throw a kernel warning if used.
|
||||
*/
|
||||
up(&host->sem);
|
||||
}
|
||||
|
|
|
@ -55,7 +55,13 @@ static u32 esdhc_readl(struct sdhci_host *host, int reg)
|
|||
|
||||
static u16 esdhc_readw(struct sdhci_host *host, int reg)
|
||||
{
|
||||
return in_be16(host->ioaddr + (reg ^ 0x2));
|
||||
u16 ret;
|
||||
|
||||
if (unlikely(reg == SDHCI_HOST_VERSION))
|
||||
ret = in_be16(host->ioaddr + reg);
|
||||
else
|
||||
ret = in_be16(host->ioaddr + (reg ^ 0x2));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u8 esdhc_readb(struct sdhci_host *host, int reg)
|
||||
|
@ -277,6 +283,7 @@ static int __devexit sdhci_of_remove(struct of_device *ofdev)
|
|||
static const struct of_device_id sdhci_of_match[] = {
|
||||
{ .compatible = "fsl,mpc8379-esdhc", .data = &sdhci_esdhc, },
|
||||
{ .compatible = "fsl,mpc8536-esdhc", .data = &sdhci_esdhc, },
|
||||
{ .compatible = "fsl,esdhc", .data = &sdhci_esdhc, },
|
||||
{ .compatible = "generic-sdhci", },
|
||||
{},
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue