diff options
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/host/mvsdio.c | 35 | ||||
-rw-r--r-- | drivers/mmc/host/mxcmmc.c | 47 | ||||
-rw-r--r-- | drivers/mmc/host/omap.c | 2 | ||||
-rw-r--r-- | drivers/mmc/host/omap_hsmmc.c | 2 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-of.c | 9 |
5 files changed, 80 insertions, 15 deletions
diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c index c643d0fe118f..b56d72ff06e9 100644 --- a/drivers/mmc/host/mvsdio.c +++ b/drivers/mmc/host/mvsdio.c | |||
@@ -64,6 +64,31 @@ static int mvsd_setup_data(struct mvsd_host *host, struct mmc_data *data) | |||
64 | unsigned int tmout; | 64 | unsigned int tmout; |
65 | int tmout_index; | 65 | int tmout_index; |
66 | 66 | ||
67 | /* | ||
68 | * Hardware weirdness. The FIFO_EMPTY bit of the HW_STATE | ||
69 | * register is sometimes not set before a while when some | ||
70 | * "unusual" data block sizes are used (such as with the SWITCH | ||
71 | * command), even despite the fact that the XFER_DONE interrupt | ||
72 | * was raised. And if another data transfer starts before | ||
73 | * this bit comes to good sense (which eventually happens by | ||
74 | * itself) then the new transfer simply fails with a timeout. | ||
75 | */ | ||
76 | if (!(mvsd_read(MVSD_HW_STATE) & (1 << 13))) { | ||
77 | unsigned long t = jiffies + HZ; | ||
78 | unsigned int hw_state, count = 0; | ||
79 | do { | ||
80 | if (time_after(jiffies, t)) { | ||
81 | dev_warn(host->dev, "FIFO_EMPTY bit missing\n"); | ||
82 | break; | ||
83 | } | ||
84 | hw_state = mvsd_read(MVSD_HW_STATE); | ||
85 | count++; | ||
86 | } while (!(hw_state & (1 << 13))); | ||
87 | dev_dbg(host->dev, "*** wait for FIFO_EMPTY bit " | ||
88 | "(hw=0x%04x, count=%d, jiffies=%ld)\n", | ||
89 | hw_state, count, jiffies - (t - HZ)); | ||
90 | } | ||
91 | |||
67 | /* If timeout=0 then maximum timeout index is used. */ | 92 | /* If timeout=0 then maximum timeout index is used. */ |
68 | tmout = DIV_ROUND_UP(data->timeout_ns, host->ns_per_clk); | 93 | tmout = DIV_ROUND_UP(data->timeout_ns, host->ns_per_clk); |
69 | tmout += data->timeout_clks; | 94 | tmout += data->timeout_clks; |
@@ -620,9 +645,18 @@ static void mvsd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
620 | if (ios->bus_width == MMC_BUS_WIDTH_4) | 645 | if (ios->bus_width == MMC_BUS_WIDTH_4) |
621 | ctrl_reg |= MVSD_HOST_CTRL_DATA_WIDTH_4_BITS; | 646 | ctrl_reg |= MVSD_HOST_CTRL_DATA_WIDTH_4_BITS; |
622 | 647 | ||
648 | /* | ||
649 | * The HI_SPEED_EN bit is causing trouble with many (but not all) | ||
650 | * high speed SD, SDHC and SDIO cards. Not enabling that bit | ||
651 | * makes all cards work. So let's just ignore that bit for now | ||
652 | * and revisit this issue if problems for not enabling this bit | ||
653 | * are ever reported. | ||
654 | */ | ||
655 | #if 0 | ||
623 | if (ios->timing == MMC_TIMING_MMC_HS || | 656 | if (ios->timing == MMC_TIMING_MMC_HS || |
624 | ios->timing == MMC_TIMING_SD_HS) | 657 | ios->timing == MMC_TIMING_SD_HS) |
625 | ctrl_reg |= MVSD_HOST_CTRL_HI_SPEED_EN; | 658 | ctrl_reg |= MVSD_HOST_CTRL_HI_SPEED_EN; |
659 | #endif | ||
626 | 660 | ||
627 | host->ctrl = ctrl_reg; | 661 | host->ctrl = ctrl_reg; |
628 | mvsd_write(MVSD_HOST_CTRL, ctrl_reg); | 662 | mvsd_write(MVSD_HOST_CTRL, ctrl_reg); |
@@ -882,3 +916,4 @@ module_param(nodma, int, 0); | |||
882 | MODULE_AUTHOR("Maen Suleiman, Nicolas Pitre"); | 916 | MODULE_AUTHOR("Maen Suleiman, Nicolas Pitre"); |
883 | MODULE_DESCRIPTION("Marvell MMC,SD,SDIO Host Controller driver"); | 917 | MODULE_DESCRIPTION("Marvell MMC,SD,SDIO Host Controller driver"); |
884 | MODULE_LICENSE("GPL"); | 918 | MODULE_LICENSE("GPL"); |
919 | MODULE_ALIAS("platform:mvsdio"); | ||
diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index b4a615c55f28..f4cbe473670e 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c | |||
@@ -140,6 +140,8 @@ struct mxcmci_host { | |||
140 | struct work_struct datawork; | 140 | struct work_struct datawork; |
141 | }; | 141 | }; |
142 | 142 | ||
143 | static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios); | ||
144 | |||
143 | static inline int mxcmci_use_dma(struct mxcmci_host *host) | 145 | static inline int mxcmci_use_dma(struct mxcmci_host *host) |
144 | { | 146 | { |
145 | return host->do_dma; | 147 | return host->do_dma; |
@@ -160,7 +162,7 @@ static void mxcmci_softreset(struct mxcmci_host *host) | |||
160 | writew(0xff, host->base + MMC_REG_RES_TO); | 162 | writew(0xff, host->base + MMC_REG_RES_TO); |
161 | } | 163 | } |
162 | 164 | ||
163 | static void mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) | 165 | static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) |
164 | { | 166 | { |
165 | unsigned int nob = data->blocks; | 167 | unsigned int nob = data->blocks; |
166 | unsigned int blksz = data->blksz; | 168 | unsigned int blksz = data->blksz; |
@@ -168,6 +170,7 @@ static void mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) | |||
168 | #ifdef HAS_DMA | 170 | #ifdef HAS_DMA |
169 | struct scatterlist *sg; | 171 | struct scatterlist *sg; |
170 | int i; | 172 | int i; |
173 | int ret; | ||
171 | #endif | 174 | #endif |
172 | if (data->flags & MMC_DATA_STREAM) | 175 | if (data->flags & MMC_DATA_STREAM) |
173 | nob = 0xffff; | 176 | nob = 0xffff; |
@@ -183,7 +186,7 @@ static void mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) | |||
183 | for_each_sg(data->sg, sg, data->sg_len, i) { | 186 | for_each_sg(data->sg, sg, data->sg_len, i) { |
184 | if (sg->offset & 3 || sg->length & 3) { | 187 | if (sg->offset & 3 || sg->length & 3) { |
185 | host->do_dma = 0; | 188 | host->do_dma = 0; |
186 | return; | 189 | return 0; |
187 | } | 190 | } |
188 | } | 191 | } |
189 | 192 | ||
@@ -192,23 +195,30 @@ static void mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) | |||
192 | host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg, | 195 | host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg, |
193 | data->sg_len, host->dma_dir); | 196 | data->sg_len, host->dma_dir); |
194 | 197 | ||
195 | imx_dma_setup_sg(host->dma, data->sg, host->dma_nents, datasize, | 198 | ret = imx_dma_setup_sg(host->dma, data->sg, host->dma_nents, |
196 | host->res->start + MMC_REG_BUFFER_ACCESS, | 199 | datasize, |
197 | DMA_MODE_READ); | 200 | host->res->start + MMC_REG_BUFFER_ACCESS, |
201 | DMA_MODE_READ); | ||
198 | } else { | 202 | } else { |
199 | host->dma_dir = DMA_TO_DEVICE; | 203 | host->dma_dir = DMA_TO_DEVICE; |
200 | host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg, | 204 | host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg, |
201 | data->sg_len, host->dma_dir); | 205 | data->sg_len, host->dma_dir); |
202 | 206 | ||
203 | imx_dma_setup_sg(host->dma, data->sg, host->dma_nents, datasize, | 207 | ret = imx_dma_setup_sg(host->dma, data->sg, host->dma_nents, |
204 | host->res->start + MMC_REG_BUFFER_ACCESS, | 208 | datasize, |
205 | DMA_MODE_WRITE); | 209 | host->res->start + MMC_REG_BUFFER_ACCESS, |
210 | DMA_MODE_WRITE); | ||
206 | } | 211 | } |
207 | 212 | ||
213 | if (ret) { | ||
214 | dev_err(mmc_dev(host->mmc), "failed to setup DMA : %d\n", ret); | ||
215 | return ret; | ||
216 | } | ||
208 | wmb(); | 217 | wmb(); |
209 | 218 | ||
210 | imx_dma_enable(host->dma); | 219 | imx_dma_enable(host->dma); |
211 | #endif /* HAS_DMA */ | 220 | #endif /* HAS_DMA */ |
221 | return 0; | ||
212 | } | 222 | } |
213 | 223 | ||
214 | static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd, | 224 | 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 | stat = readl(host->base + MMC_REG_STATUS); | 355 | stat = readl(host->base + MMC_REG_STATUS); |
346 | if (stat & STATUS_ERR_MASK) | 356 | if (stat & STATUS_ERR_MASK) |
347 | return stat; | 357 | return stat; |
348 | if (time_after(jiffies, timeout)) | 358 | if (time_after(jiffies, timeout)) { |
359 | mxcmci_softreset(host); | ||
360 | mxcmci_set_clk_rate(host, host->clock); | ||
349 | return STATUS_TIME_OUT_READ; | 361 | return STATUS_TIME_OUT_READ; |
362 | } | ||
350 | if (stat & mask) | 363 | if (stat & mask) |
351 | return 0; | 364 | return 0; |
352 | cpu_relax(); | 365 | cpu_relax(); |
@@ -531,6 +544,7 @@ static void mxcmci_request(struct mmc_host *mmc, struct mmc_request *req) | |||
531 | { | 544 | { |
532 | struct mxcmci_host *host = mmc_priv(mmc); | 545 | struct mxcmci_host *host = mmc_priv(mmc); |
533 | unsigned int cmdat = host->cmdat; | 546 | unsigned int cmdat = host->cmdat; |
547 | int error; | ||
534 | 548 | ||
535 | WARN_ON(host->req != NULL); | 549 | WARN_ON(host->req != NULL); |
536 | 550 | ||
@@ -540,7 +554,12 @@ static void mxcmci_request(struct mmc_host *mmc, struct mmc_request *req) | |||
540 | host->do_dma = 1; | 554 | host->do_dma = 1; |
541 | #endif | 555 | #endif |
542 | if (req->data) { | 556 | if (req->data) { |
543 | mxcmci_setup_data(host, req->data); | 557 | error = mxcmci_setup_data(host, req->data); |
558 | if (error) { | ||
559 | req->cmd->error = error; | ||
560 | goto out; | ||
561 | } | ||
562 | |||
544 | 563 | ||
545 | cmdat |= CMD_DAT_CONT_DATA_ENABLE; | 564 | cmdat |= CMD_DAT_CONT_DATA_ENABLE; |
546 | 565 | ||
@@ -548,7 +567,9 @@ static void mxcmci_request(struct mmc_host *mmc, struct mmc_request *req) | |||
548 | cmdat |= CMD_DAT_CONT_WRITE; | 567 | cmdat |= CMD_DAT_CONT_WRITE; |
549 | } | 568 | } |
550 | 569 | ||
551 | if (mxcmci_start_cmd(host, req->cmd, cmdat)) | 570 | error = mxcmci_start_cmd(host, req->cmd, cmdat); |
571 | out: | ||
572 | if (error) | ||
552 | mxcmci_finish_request(host, req); | 573 | mxcmci_finish_request(host, req); |
553 | } | 574 | } |
554 | 575 | ||
@@ -724,7 +745,9 @@ static int mxcmci_probe(struct platform_device *pdev) | |||
724 | goto out_clk_put; | 745 | goto out_clk_put; |
725 | } | 746 | } |
726 | 747 | ||
727 | mmc->f_min = clk_get_rate(host->clk) >> 7; | 748 | mmc->f_min = clk_get_rate(host->clk) >> 16; |
749 | if (mmc->f_min < 400000) | ||
750 | mmc->f_min = 400000; | ||
728 | mmc->f_max = clk_get_rate(host->clk) >> 1; | 751 | mmc->f_max = clk_get_rate(host->clk) >> 1; |
729 | 752 | ||
730 | /* recommended in data sheet */ | 753 | /* recommended in data sheet */ |
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index bfa25c01c872..dceb5ee3bda0 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c | |||
@@ -822,7 +822,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) | |||
822 | del_timer(&host->cmd_abort_timer); | 822 | del_timer(&host->cmd_abort_timer); |
823 | host->abort = 1; | 823 | host->abort = 1; |
824 | OMAP_MMC_WRITE(host, IE, 0); | 824 | OMAP_MMC_WRITE(host, IE, 0); |
825 | disable_irq(host->irq); | 825 | disable_irq_nosync(host->irq); |
826 | schedule_work(&host->cmd_abort_work); | 826 | schedule_work(&host->cmd_abort_work); |
827 | return IRQ_HANDLED; | 827 | return IRQ_HANDLED; |
828 | } | 828 | } |
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index e62a22a7f00c..c40cb96255a2 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c | |||
@@ -680,7 +680,7 @@ static void mmc_omap_dma_cb(int lch, u16 ch_status, void *data) | |||
680 | host->dma_ch = -1; | 680 | host->dma_ch = -1; |
681 | /* | 681 | /* |
682 | * DMA Callback: run in interrupt context. | 682 | * DMA Callback: run in interrupt context. |
683 | * mutex_unlock will through a kernel warning if used. | 683 | * mutex_unlock will throw a kernel warning if used. |
684 | */ | 684 | */ |
685 | up(&host->sem); | 685 | up(&host->sem); |
686 | } | 686 | } |
diff --git a/drivers/mmc/host/sdhci-of.c b/drivers/mmc/host/sdhci-of.c index 3ff4ac3abe8b..128c614d11aa 100644 --- a/drivers/mmc/host/sdhci-of.c +++ b/drivers/mmc/host/sdhci-of.c | |||
@@ -55,7 +55,13 @@ static u32 esdhc_readl(struct sdhci_host *host, int reg) | |||
55 | 55 | ||
56 | static u16 esdhc_readw(struct sdhci_host *host, int reg) | 56 | static u16 esdhc_readw(struct sdhci_host *host, int reg) |
57 | { | 57 | { |
58 | return in_be16(host->ioaddr + (reg ^ 0x2)); | 58 | u16 ret; |
59 | |||
60 | if (unlikely(reg == SDHCI_HOST_VERSION)) | ||
61 | ret = in_be16(host->ioaddr + reg); | ||
62 | else | ||
63 | ret = in_be16(host->ioaddr + (reg ^ 0x2)); | ||
64 | return ret; | ||
59 | } | 65 | } |
60 | 66 | ||
61 | static u8 esdhc_readb(struct sdhci_host *host, int reg) | 67 | 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 | static const struct of_device_id sdhci_of_match[] = { | 283 | static const struct of_device_id sdhci_of_match[] = { |
278 | { .compatible = "fsl,mpc8379-esdhc", .data = &sdhci_esdhc, }, | 284 | { .compatible = "fsl,mpc8379-esdhc", .data = &sdhci_esdhc, }, |
279 | { .compatible = "fsl,mpc8536-esdhc", .data = &sdhci_esdhc, }, | 285 | { .compatible = "fsl,mpc8536-esdhc", .data = &sdhci_esdhc, }, |
286 | { .compatible = "fsl,esdhc", .data = &sdhci_esdhc, }, | ||
280 | { .compatible = "generic-sdhci", }, | 287 | { .compatible = "generic-sdhci", }, |
281 | {}, | 288 | {}, |
282 | }; | 289 | }; |