Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mmc: dw_mmc: change to use recommended reset procedure

This patch changes the fifo reset code to follow the reset procedure
outlined in the documentation of Synopsys Mobile storage host databook.

Signed-off-by: Sonny Rao <sonnyrao@chromium.org>
Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.com>
Acked-by: Seungwon Jeon <tgih.jun@samsung.com>
[sonnyrao: fix compile for !CONFIG_MMC_DW_IDMAC case]
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

authored by

Sonny Rao and committed by
Ulf Hansson
3a33a94c 3df5b281

+69 -23
+64 -23
drivers/mmc/host/dw_mmc.c
··· 111 111 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 112 112 }; 113 113 114 - static inline bool dw_mci_fifo_reset(struct dw_mci *host); 115 - static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host); 114 + static bool dw_mci_reset(struct dw_mci *host); 116 115 117 116 #if defined(CONFIG_DEBUG_FS) 118 117 static int dw_mci_req_show(struct seq_file *s, void *v) ··· 1234 1235 * After an error, there may be data lingering 1235 1236 * in the FIFO 1236 1237 */ 1237 - dw_mci_fifo_reset(host); 1238 + dw_mci_reset(host); 1238 1239 } else { 1239 1240 data->bytes_xfered = data->blocks * data->blksz; 1240 1241 data->error = 0; ··· 1351 1352 1352 1353 /* CMD error in data command */ 1353 1354 if (mrq->cmd->error && mrq->data) 1354 - dw_mci_fifo_reset(host); 1355 + dw_mci_reset(host); 1355 1356 1356 1357 host->cmd = NULL; 1357 1358 host->data = NULL; ··· 1962 1963 } 1963 1964 1964 1965 /* Power down slot */ 1965 - if (present == 0) { 1966 - /* Clear down the FIFO */ 1967 - dw_mci_fifo_reset(host); 1968 - #ifdef CONFIG_MMC_DW_IDMAC 1969 - dw_mci_idmac_reset(host); 1970 - #endif 1971 - 1972 - } 1966 + if (present == 0) 1967 + dw_mci_reset(host); 1973 1968 1974 1969 spin_unlock_bh(&host->lock); 1975 1970 ··· 2201 2208 return false; 2202 2209 } 2203 2210 2204 - static inline bool dw_mci_fifo_reset(struct dw_mci *host) 2211 + static bool dw_mci_reset(struct dw_mci *host) 2205 2212 { 2213 + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; 2214 + bool ret = false; 2215 + 2206 2216 /* 2207 2217 * Reseting generates a block interrupt, hence setting 2208 2218 * the scatter-gather pointer to NULL. ··· 2215 2219 host->sg = NULL; 2216 2220 } 2217 2221 2218 - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); 2219 - } 2222 + if (host->use_dma) 2223 + flags |= SDMMC_CTRL_DMA_RESET; 2220 2224 2221 - static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) 2222 - { 2223 - return dw_mci_ctrl_reset(host, 2224 - SDMMC_CTRL_FIFO_RESET | 2225 - SDMMC_CTRL_RESET | 2226 - SDMMC_CTRL_DMA_RESET); 2225 + if (dw_mci_ctrl_reset(host, flags)) { 2226 + /* 2227 + * In all cases we clear the RAWINTS register to clear any 2228 + * interrupts. 2229 + */ 2230 + mci_writel(host, RINTSTS, 0xFFFFFFFF); 2231 + 2232 + /* if using dma we wait for dma_req to clear */ 2233 + if (host->use_dma) { 2234 + unsigned long timeout = jiffies + msecs_to_jiffies(500); 2235 + u32 status; 2236 + do { 2237 + status = mci_readl(host, STATUS); 2238 + if (!(status & SDMMC_STATUS_DMA_REQ)) 2239 + break; 2240 + cpu_relax(); 2241 + } while (time_before(jiffies, timeout)); 2242 + 2243 + if (status & SDMMC_STATUS_DMA_REQ) { 2244 + dev_err(host->dev, 2245 + "%s: Timeout waiting for dma_req to " 2246 + "clear during reset\n", __func__); 2247 + goto ciu_out; 2248 + } 2249 + 2250 + /* when using DMA next we reset the fifo again */ 2251 + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) 2252 + goto ciu_out; 2253 + } 2254 + } else { 2255 + /* if the controller reset bit did clear, then set clock regs */ 2256 + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { 2257 + dev_err(host->dev, "%s: fifo/dma reset bits didn't " 2258 + "clear but ciu was reset, doing clock update\n", 2259 + __func__); 2260 + goto ciu_out; 2261 + } 2262 + } 2263 + 2264 + #if IS_ENABLED(CONFIG_MMC_DW_IDMAC) 2265 + /* It is also recommended that we reset and reprogram idmac */ 2266 + dw_mci_idmac_reset(host); 2267 + #endif 2268 + 2269 + ret = true; 2270 + 2271 + ciu_out: 2272 + /* After a CTRL reset we need to have CIU set clock registers */ 2273 + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); 2274 + 2275 + return ret; 2227 2276 } 2228 2277 2229 2278 #ifdef CONFIG_OF ··· 2466 2425 } 2467 2426 2468 2427 /* Reset all blocks */ 2469 - if (!dw_mci_ctrl_all_reset(host)) 2428 + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) 2470 2429 return -ENODEV; 2471 2430 2472 2431 host->dma_ops = host->pdata->dma_ops; ··· 2653 2612 } 2654 2613 } 2655 2614 2656 - if (!dw_mci_ctrl_all_reset(host)) { 2615 + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) { 2657 2616 ret = -ENODEV; 2658 2617 return ret; 2659 2618 }
+5
drivers/mmc/host/dw_mmc.h
··· 129 129 #define SDMMC_CMD_INDX(n) ((n) & 0x1F) 130 130 /* Status register defines */ 131 131 #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) 132 + #define SDMMC_STATUS_DMA_REQ BIT(31) 132 133 /* FIFOTH register defines */ 133 134 #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ 134 135 ((r) & 0xFFF) << 16 | \ ··· 150 149 #define SDMMC_GET_VERID(x) ((x) & 0xFFFF) 151 150 /* Card read threshold */ 152 151 #define SDMMC_SET_RD_THLD(v, x) (((v) & 0x1FFF) << 16 | (x)) 152 + 153 + /* All ctrl reset bits */ 154 + #define SDMMC_CTRL_ALL_RESET_FLAGS \ 155 + (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET) 153 156 154 157 /* Register access macros */ 155 158 #define mci_readl(dev, reg) \