提交 33fa108e 编写于 作者: L Linus Torvalds

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
...@@ -64,6 +64,31 @@ static int mvsd_setup_data(struct mvsd_host *host, struct mmc_data *data) ...@@ -64,6 +64,31 @@ static int mvsd_setup_data(struct mvsd_host *host, struct mmc_data *data)
unsigned int tmout; unsigned int tmout;
int tmout_index; 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. */ /* If timeout=0 then maximum timeout index is used. */
tmout = DIV_ROUND_UP(data->timeout_ns, host->ns_per_clk); tmout = DIV_ROUND_UP(data->timeout_ns, host->ns_per_clk);
tmout += data->timeout_clks; tmout += data->timeout_clks;
...@@ -620,9 +645,18 @@ static void mvsd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ...@@ -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) if (ios->bus_width == MMC_BUS_WIDTH_4)
ctrl_reg |= MVSD_HOST_CTRL_DATA_WIDTH_4_BITS; 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 || if (ios->timing == MMC_TIMING_MMC_HS ||
ios->timing == MMC_TIMING_SD_HS) ios->timing == MMC_TIMING_SD_HS)
ctrl_reg |= MVSD_HOST_CTRL_HI_SPEED_EN; ctrl_reg |= MVSD_HOST_CTRL_HI_SPEED_EN;
#endif
host->ctrl = ctrl_reg; host->ctrl = ctrl_reg;
mvsd_write(MVSD_HOST_CTRL, ctrl_reg); mvsd_write(MVSD_HOST_CTRL, ctrl_reg);
...@@ -882,3 +916,4 @@ module_param(nodma, int, 0); ...@@ -882,3 +916,4 @@ module_param(nodma, int, 0);
MODULE_AUTHOR("Maen Suleiman, Nicolas Pitre"); MODULE_AUTHOR("Maen Suleiman, Nicolas Pitre");
MODULE_DESCRIPTION("Marvell MMC,SD,SDIO Host Controller driver"); MODULE_DESCRIPTION("Marvell MMC,SD,SDIO Host Controller driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:mvsdio");
...@@ -140,6 +140,8 @@ struct mxcmci_host { ...@@ -140,6 +140,8 @@ struct mxcmci_host {
struct work_struct datawork; 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) static inline int mxcmci_use_dma(struct mxcmci_host *host)
{ {
return host->do_dma; return host->do_dma;
...@@ -160,7 +162,7 @@ static void mxcmci_softreset(struct mxcmci_host *host) ...@@ -160,7 +162,7 @@ static void mxcmci_softreset(struct mxcmci_host *host)
writew(0xff, host->base + MMC_REG_RES_TO); 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 nob = data->blocks;
unsigned int blksz = data->blksz; unsigned int blksz = data->blksz;
...@@ -168,6 +170,7 @@ static void mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) ...@@ -168,6 +170,7 @@ static void mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
#ifdef HAS_DMA #ifdef HAS_DMA
struct scatterlist *sg; struct scatterlist *sg;
int i; int i;
int ret;
#endif #endif
if (data->flags & MMC_DATA_STREAM) if (data->flags & MMC_DATA_STREAM)
nob = 0xffff; nob = 0xffff;
...@@ -183,7 +186,7 @@ static void mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) ...@@ -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) { for_each_sg(data->sg, sg, data->sg_len, i) {
if (sg->offset & 3 || sg->length & 3) { if (sg->offset & 3 || sg->length & 3) {
host->do_dma = 0; host->do_dma = 0;
return; return 0;
} }
} }
...@@ -192,23 +195,30 @@ static void mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) ...@@ -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, host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg,
data->sg_len, host->dma_dir); data->sg_len, host->dma_dir);
imx_dma_setup_sg(host->dma, data->sg, host->dma_nents, datasize, ret = imx_dma_setup_sg(host->dma, data->sg, host->dma_nents,
host->res->start + MMC_REG_BUFFER_ACCESS, datasize,
DMA_MODE_READ); host->res->start + MMC_REG_BUFFER_ACCESS,
DMA_MODE_READ);
} else { } else {
host->dma_dir = DMA_TO_DEVICE; host->dma_dir = DMA_TO_DEVICE;
host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg, host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg,
data->sg_len, host->dma_dir); data->sg_len, host->dma_dir);
imx_dma_setup_sg(host->dma, data->sg, host->dma_nents, datasize, ret = imx_dma_setup_sg(host->dma, data->sg, host->dma_nents,
host->res->start + MMC_REG_BUFFER_ACCESS, datasize,
DMA_MODE_WRITE); 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(); wmb();
imx_dma_enable(host->dma); imx_dma_enable(host->dma);
#endif /* HAS_DMA */ #endif /* HAS_DMA */
return 0;
} }
static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd, 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) ...@@ -345,8 +355,11 @@ static int mxcmci_poll_status(struct mxcmci_host *host, u32 mask)
stat = readl(host->base + MMC_REG_STATUS); stat = readl(host->base + MMC_REG_STATUS);
if (stat & STATUS_ERR_MASK) if (stat & STATUS_ERR_MASK)
return stat; 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; return STATUS_TIME_OUT_READ;
}
if (stat & mask) if (stat & mask)
return 0; return 0;
cpu_relax(); cpu_relax();
...@@ -531,6 +544,7 @@ static void mxcmci_request(struct mmc_host *mmc, struct mmc_request *req) ...@@ -531,6 +544,7 @@ static void mxcmci_request(struct mmc_host *mmc, struct mmc_request *req)
{ {
struct mxcmci_host *host = mmc_priv(mmc); struct mxcmci_host *host = mmc_priv(mmc);
unsigned int cmdat = host->cmdat; unsigned int cmdat = host->cmdat;
int error;
WARN_ON(host->req != NULL); WARN_ON(host->req != NULL);
...@@ -540,7 +554,12 @@ static void mxcmci_request(struct mmc_host *mmc, struct mmc_request *req) ...@@ -540,7 +554,12 @@ static void mxcmci_request(struct mmc_host *mmc, struct mmc_request *req)
host->do_dma = 1; host->do_dma = 1;
#endif #endif
if (req->data) { 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; cmdat |= CMD_DAT_CONT_DATA_ENABLE;
...@@ -548,7 +567,9 @@ static void mxcmci_request(struct mmc_host *mmc, struct mmc_request *req) ...@@ -548,7 +567,9 @@ static void mxcmci_request(struct mmc_host *mmc, struct mmc_request *req)
cmdat |= CMD_DAT_CONT_WRITE; 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); mxcmci_finish_request(host, req);
} }
...@@ -724,7 +745,9 @@ static int mxcmci_probe(struct platform_device *pdev) ...@@ -724,7 +745,9 @@ static int mxcmci_probe(struct platform_device *pdev)
goto out_clk_put; 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; mmc->f_max = clk_get_rate(host->clk) >> 1;
/* recommended in data sheet */ /* recommended in data sheet */
......
...@@ -822,7 +822,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) ...@@ -822,7 +822,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
del_timer(&host->cmd_abort_timer); del_timer(&host->cmd_abort_timer);
host->abort = 1; host->abort = 1;
OMAP_MMC_WRITE(host, IE, 0); OMAP_MMC_WRITE(host, IE, 0);
disable_irq(host->irq); disable_irq_nosync(host->irq);
schedule_work(&host->cmd_abort_work); schedule_work(&host->cmd_abort_work);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
......
...@@ -680,7 +680,7 @@ static void mmc_omap_dma_cb(int lch, u16 ch_status, void *data) ...@@ -680,7 +680,7 @@ static void mmc_omap_dma_cb(int lch, u16 ch_status, void *data)
host->dma_ch = -1; host->dma_ch = -1;
/* /*
* DMA Callback: run in interrupt context. * 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); up(&host->sem);
} }
......
...@@ -55,7 +55,13 @@ static u32 esdhc_readl(struct sdhci_host *host, int reg) ...@@ -55,7 +55,13 @@ static u32 esdhc_readl(struct sdhci_host *host, int reg)
static u16 esdhc_readw(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) static u8 esdhc_readb(struct sdhci_host *host, int reg)
...@@ -277,6 +283,7 @@ static int __devexit sdhci_of_remove(struct of_device *ofdev) ...@@ -277,6 +283,7 @@ static int __devexit sdhci_of_remove(struct of_device *ofdev)
static const struct of_device_id sdhci_of_match[] = { static const struct of_device_id sdhci_of_match[] = {
{ .compatible = "fsl,mpc8379-esdhc", .data = &sdhci_esdhc, }, { .compatible = "fsl,mpc8379-esdhc", .data = &sdhci_esdhc, },
{ .compatible = "fsl,mpc8536-esdhc", .data = &sdhci_esdhc, }, { .compatible = "fsl,mpc8536-esdhc", .data = &sdhci_esdhc, },
{ .compatible = "fsl,esdhc", .data = &sdhci_esdhc, },
{ .compatible = "generic-sdhci", }, { .compatible = "generic-sdhci", },
{}, {},
}; };
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册