* [PATCHv2] mmc: dw_mmc: change to use recommended reset procedure @ 2014-05-13 1:38 ` Sonny Rao 0 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-05-13 1:38 UTC (permalink / raw) To: linux-mmc Cc: grundler, linux-samsung-soc, linux-arm-kernel, jh80.chung, cjb, tgih.jun, kgene.kim, joshi, t.figa, dianders, Yuvaraj Kumar C D, Sonny Rao This patch changes the fifo reset code to follow the reset procedure outlined in the documentation of Synopsys Mobile storage host databook 7.2.13. v2: Add Generic DMA support per the documentation, move interrupt clear before wait make the test for DMA host->use_dma rather than host->using_dma add proper return values (although it appears no caller checks) Signed-off-by: Sonny Rao <sonnyrao@chromium.org> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.com> --- drivers/mmc/host/dw_mmc.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++- drivers/mmc/host/dw_mmc.h | 1 + 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 55cd110..aff57e1 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -2325,6 +2325,7 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) static inline bool dw_mci_fifo_reset(struct dw_mci *host) { + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; /* * Reseting generates a block interrupt, hence setting * the scatter-gather pointer to NULL. @@ -2334,7 +2335,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) host->sg = NULL; } - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); + /* + * The recommended method for resetting is to always reset the + * controller and the fifo, but differs slightly depending on the mode. + * The Generic DMA mode (non IDMAC) also needs to reset DMA where IDMAC + * mode resets IDMAC at the end. + * + */ +#ifndef CONFIG_MMC_DW_IDMAC + if (host->use_dma) + flags |= SDMMC_CTRL_DMA_RESET; +#endif + if (dw_mci_ctrl_reset(host, flags)) { + /* + * In all cases we clear the RAWINTS register to clear any + * interrupts. + */ + mci_writel(host, RINTSTS, 0xFFFFFFFF); + + /* if using dma we wait for dma_req to clear */ + if (host->use_dma) { + unsigned long timeout = jiffies + msecs_to_jiffies(500); + u32 status; + do { + status = mci_readl(host, STATUS); + if (!(status & SDMMC_STATUS_DMA_REQ)) + break; + cpu_relax(); + } while (time_before(jiffies, timeout)); + + if (status & SDMMC_STATUS_DMA_REQ) { + dev_err(host->dev, + "%s: Timeout waiting for dma_req to " + "clear during reset", __func__); + return false; + } + + /* when using DMA next we reset the fifo again */ + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); + } + } else { + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); + return false; + } + +#ifdef CONFIG_MMC_DW_IDMAC + /* It is also recommended that we reset and reprogram idmac */ + dw_mci_idmac_reset(host); +#endif + + /* After a CTRL reset we need to have CIU set clock registers */ + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); + + return true; } static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 6bf24ab..2505804 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -129,6 +129,7 @@ #define SDMMC_CMD_INDX(n) ((n) & 0x1F) /* Status register defines */ #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) +#define SDMMC_STATUS_DMA_REQ BIT(31) /* FIFOTH register defines */ #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ ((r) & 0xFFF) << 16 | \ -- 1.9.1.423.g4596e3a ^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCHv2] mmc: dw_mmc: change to use recommended reset procedure @ 2014-05-13 1:38 ` Sonny Rao 0 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-05-13 1:38 UTC (permalink / raw) To: linux-arm-kernel This patch changes the fifo reset code to follow the reset procedure outlined in the documentation of Synopsys Mobile storage host databook 7.2.13. v2: Add Generic DMA support per the documentation, move interrupt clear before wait make the test for DMA host->use_dma rather than host->using_dma add proper return values (although it appears no caller checks) Signed-off-by: Sonny Rao <sonnyrao@chromium.org> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.com> --- drivers/mmc/host/dw_mmc.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++- drivers/mmc/host/dw_mmc.h | 1 + 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 55cd110..aff57e1 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -2325,6 +2325,7 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) static inline bool dw_mci_fifo_reset(struct dw_mci *host) { + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; /* * Reseting generates a block interrupt, hence setting * the scatter-gather pointer to NULL. @@ -2334,7 +2335,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) host->sg = NULL; } - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); + /* + * The recommended method for resetting is to always reset the + * controller and the fifo, but differs slightly depending on the mode. + * The Generic DMA mode (non IDMAC) also needs to reset DMA where IDMAC + * mode resets IDMAC at the end. + * + */ +#ifndef CONFIG_MMC_DW_IDMAC + if (host->use_dma) + flags |= SDMMC_CTRL_DMA_RESET; +#endif + if (dw_mci_ctrl_reset(host, flags)) { + /* + * In all cases we clear the RAWINTS register to clear any + * interrupts. + */ + mci_writel(host, RINTSTS, 0xFFFFFFFF); + + /* if using dma we wait for dma_req to clear */ + if (host->use_dma) { + unsigned long timeout = jiffies + msecs_to_jiffies(500); + u32 status; + do { + status = mci_readl(host, STATUS); + if (!(status & SDMMC_STATUS_DMA_REQ)) + break; + cpu_relax(); + } while (time_before(jiffies, timeout)); + + if (status & SDMMC_STATUS_DMA_REQ) { + dev_err(host->dev, + "%s: Timeout waiting for dma_req to " + "clear during reset", __func__); + return false; + } + + /* when using DMA next we reset the fifo again */ + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); + } + } else { + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); + return false; + } + +#ifdef CONFIG_MMC_DW_IDMAC + /* It is also recommended that we reset and reprogram idmac */ + dw_mci_idmac_reset(host); +#endif + + /* After a CTRL reset we need to have CIU set clock registers */ + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); + + return true; } static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 6bf24ab..2505804 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -129,6 +129,7 @@ #define SDMMC_CMD_INDX(n) ((n) & 0x1F) /* Status register defines */ #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) +#define SDMMC_STATUS_DMA_REQ BIT(31) /* FIFOTH register defines */ #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ ((r) & 0xFFF) << 16 | \ -- 1.9.1.423.g4596e3a ^ permalink raw reply related [flat|nested] 75+ messages in thread
* RE: [PATCHv2] mmc: dw_mmc: change to use recommended reset procedure 2014-05-13 1:38 ` Sonny Rao @ 2014-05-13 5:02 ` Seungwon Jeon -1 siblings, 0 replies; 75+ messages in thread From: Seungwon Jeon @ 2014-05-13 5:02 UTC (permalink / raw) To: 'Sonny Rao', linux-mmc Cc: grundler, linux-samsung-soc, linux-arm-kernel, jh80.chung, cjb, kgene.kim, joshi, t.figa, dianders, 'Yuvaraj Kumar C D' As I mentioned in previous version, you put all reset stuff in existing fifo_reset function. Although databook mentions ciu_reset case for SBE error, it's not obvious when ciu_reset is needed in other error cases. If you intend to add some robust error handing, it would be better to make another function. Please check my comments below. On Tue, May 13, 2014, Sonny Rao wrote: > This patch changes the fifo reset code to follow the reset procedure > outlined in the documentation of Synopsys Mobile storage host databook > 7.2.13. > > v2: Add Generic DMA support > per the documentation, move interrupt clear before wait > make the test for DMA host->use_dma rather than host->using_dma > add proper return values (although it appears no caller checks) > > Signed-off-by: Sonny Rao <sonnyrao@chromium.org> > Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.com> > --- > drivers/mmc/host/dw_mmc.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++- > drivers/mmc/host/dw_mmc.h | 1 + > 2 files changed, 55 insertions(+), 1 deletion(-) > > diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c > index 55cd110..aff57e1 100644 > --- a/drivers/mmc/host/dw_mmc.c > +++ b/drivers/mmc/host/dw_mmc.c > @@ -2325,6 +2325,7 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) > > static inline bool dw_mci_fifo_reset(struct dw_mci *host) > { > + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; > /* > * Reseting generates a block interrupt, hence setting > * the scatter-gather pointer to NULL. > @@ -2334,7 +2335,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) > host->sg = NULL; > } > > - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > + /* > + * The recommended method for resetting is to always reset the > + * controller and the fifo, but differs slightly depending on the mode. > + * The Generic DMA mode (non IDMAC) also needs to reset DMA where IDMAC > + * mode resets IDMAC at the end. > + * > + */ > +#ifndef CONFIG_MMC_DW_IDMAC Is it added for generic DMA? IDMAC should be considered for dma_reseet as well. Please check databook. > + if (host->use_dma) > + flags |= SDMMC_CTRL_DMA_RESET; > +#endif > + if (dw_mci_ctrl_reset(host, flags)) { > + /* > + * In all cases we clear the RAWINTS register to clear any > + * interrupts. > + */ I think interrupt masking is needed before reset because we will not handle it anymore. And Is there any reason to move interrupt clear here compared with previous version? > + mci_writel(host, RINTSTS, 0xFFFFFFFF); > + > + /* if using dma we wait for dma_req to clear */ > + if (host->use_dma) { > + unsigned long timeout = jiffies + msecs_to_jiffies(500); > + u32 status; > + do { > + status = mci_readl(host, STATUS); > + if (!(status & SDMMC_STATUS_DMA_REQ)) > + break; > + cpu_relax(); What did you intend here? If you intent busy-wait, how about using sleep instead? > + } while (time_before(jiffies, timeout)); > + > + if (status & SDMMC_STATUS_DMA_REQ) { > + dev_err(host->dev, > + "%s: Timeout waiting for dma_req to " > + "clear during reset", __func__); > + return false; > + } > + > + /* when using DMA next we reset the fifo again */ > + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > + } > + } else { > + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); If ciu_reset is cleared, clk update below is needed? Thanks, Seungwon Jeon > + return false; > + } > + > +#ifdef CONFIG_MMC_DW_IDMAC > + /* It is also recommended that we reset and reprogram idmac */ > + dw_mci_idmac_reset(host); > +#endif > + > + /* After a CTRL reset we need to have CIU set clock registers */ > + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); > + > + return true; > } > > static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) > diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h > index 6bf24ab..2505804 100644 > --- a/drivers/mmc/host/dw_mmc.h > +++ b/drivers/mmc/host/dw_mmc.h > @@ -129,6 +129,7 @@ > #define SDMMC_CMD_INDX(n) ((n) & 0x1F) > /* Status register defines */ > #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) > +#define SDMMC_STATUS_DMA_REQ BIT(31) > /* FIFOTH register defines */ > #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ > ((r) & 0xFFF) << 16 | \ > -- > 1.9.1.423.g4596e3a > > -- > To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCHv2] mmc: dw_mmc: change to use recommended reset procedure @ 2014-05-13 5:02 ` Seungwon Jeon 0 siblings, 0 replies; 75+ messages in thread From: Seungwon Jeon @ 2014-05-13 5:02 UTC (permalink / raw) To: linux-arm-kernel As I mentioned in previous version, you put all reset stuff in existing fifo_reset function. Although databook mentions ciu_reset case for SBE error, it's not obvious when ciu_reset is needed in other error cases. If you intend to add some robust error handing, it would be better to make another function. Please check my comments below. On Tue, May 13, 2014, Sonny Rao wrote: > This patch changes the fifo reset code to follow the reset procedure > outlined in the documentation of Synopsys Mobile storage host databook > 7.2.13. > > v2: Add Generic DMA support > per the documentation, move interrupt clear before wait > make the test for DMA host->use_dma rather than host->using_dma > add proper return values (although it appears no caller checks) > > Signed-off-by: Sonny Rao <sonnyrao@chromium.org> > Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.com> > --- > drivers/mmc/host/dw_mmc.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++- > drivers/mmc/host/dw_mmc.h | 1 + > 2 files changed, 55 insertions(+), 1 deletion(-) > > diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c > index 55cd110..aff57e1 100644 > --- a/drivers/mmc/host/dw_mmc.c > +++ b/drivers/mmc/host/dw_mmc.c > @@ -2325,6 +2325,7 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) > > static inline bool dw_mci_fifo_reset(struct dw_mci *host) > { > + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; > /* > * Reseting generates a block interrupt, hence setting > * the scatter-gather pointer to NULL. > @@ -2334,7 +2335,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) > host->sg = NULL; > } > > - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > + /* > + * The recommended method for resetting is to always reset the > + * controller and the fifo, but differs slightly depending on the mode. > + * The Generic DMA mode (non IDMAC) also needs to reset DMA where IDMAC > + * mode resets IDMAC at the end. > + * > + */ > +#ifndef CONFIG_MMC_DW_IDMAC Is it added for generic DMA? IDMAC should be considered for dma_reseet as well. Please check databook. > + if (host->use_dma) > + flags |= SDMMC_CTRL_DMA_RESET; > +#endif > + if (dw_mci_ctrl_reset(host, flags)) { > + /* > + * In all cases we clear the RAWINTS register to clear any > + * interrupts. > + */ I think interrupt masking is needed before reset because we will not handle it anymore. And Is there any reason to move interrupt clear here compared with previous version? > + mci_writel(host, RINTSTS, 0xFFFFFFFF); > + > + /* if using dma we wait for dma_req to clear */ > + if (host->use_dma) { > + unsigned long timeout = jiffies + msecs_to_jiffies(500); > + u32 status; > + do { > + status = mci_readl(host, STATUS); > + if (!(status & SDMMC_STATUS_DMA_REQ)) > + break; > + cpu_relax(); What did you intend here? If you intent busy-wait, how about using sleep instead? > + } while (time_before(jiffies, timeout)); > + > + if (status & SDMMC_STATUS_DMA_REQ) { > + dev_err(host->dev, > + "%s: Timeout waiting for dma_req to " > + "clear during reset", __func__); > + return false; > + } > + > + /* when using DMA next we reset the fifo again */ > + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > + } > + } else { > + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); If ciu_reset is cleared, clk update below is needed? Thanks, Seungwon Jeon > + return false; > + } > + > +#ifdef CONFIG_MMC_DW_IDMAC > + /* It is also recommended that we reset and reprogram idmac */ > + dw_mci_idmac_reset(host); > +#endif > + > + /* After a CTRL reset we need to have CIU set clock registers */ > + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); > + > + return true; > } > > static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) > diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h > index 6bf24ab..2505804 100644 > --- a/drivers/mmc/host/dw_mmc.h > +++ b/drivers/mmc/host/dw_mmc.h > @@ -129,6 +129,7 @@ > #define SDMMC_CMD_INDX(n) ((n) & 0x1F) > /* Status register defines */ > #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) > +#define SDMMC_STATUS_DMA_REQ BIT(31) > /* FIFOTH register defines */ > #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ > ((r) & 0xFFF) << 16 | \ > -- > 1.9.1.423.g4596e3a > > -- > To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > the body of a message to majordomo at vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCHv2] mmc: dw_mmc: change to use recommended reset procedure 2014-05-13 5:02 ` Seungwon Jeon @ 2014-05-13 7:16 ` Sonny Rao -1 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-05-13 7:16 UTC (permalink / raw) To: Seungwon Jeon Cc: linux-mmc, Grant Grundler, linux-samsung-soc, linux-arm-kernel, Jaehoon Chung, Chris Ball, Kukjin Kim, sunil joshi, Tomasz Figa, Douglas Anderson, Yuvaraj Kumar C D On Mon, May 12, 2014 at 10:02 PM, Seungwon Jeon <tgih.jun@samsung.com> wrote: > As I mentioned in previous version, you put all reset stuff in existing fifo_reset function. > Although databook mentions ciu_reset case for SBE error, it's not obvious when ciu_reset is needed in other error cases. > If you intend to add some robust error handing, it would be better to make another function. The document I have actually doesn't mention error cases, it describes this procedure as "Controller/DMA/FIFO Reset Usage" so I believe it is saying this is the correct procedure in all cases, and based on our testing it seems to work. I understand the skepticism, as I shared it initially when I saw this, but based on our experience, this is correct and it doesn't need to live in a separate function. > Please check my comments below. > > On Tue, May 13, 2014, Sonny Rao wrote: >> This patch changes the fifo reset code to follow the reset procedure >> outlined in the documentation of Synopsys Mobile storage host databook >> 7.2.13. >> >> v2: Add Generic DMA support >> per the documentation, move interrupt clear before wait >> make the test for DMA host->use_dma rather than host->using_dma >> add proper return values (although it appears no caller checks) >> >> Signed-off-by: Sonny Rao <sonnyrao@chromium.org> >> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.com> >> --- >> drivers/mmc/host/dw_mmc.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++- >> drivers/mmc/host/dw_mmc.h | 1 + >> 2 files changed, 55 insertions(+), 1 deletion(-) >> >> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c >> index 55cd110..aff57e1 100644 >> --- a/drivers/mmc/host/dw_mmc.c >> +++ b/drivers/mmc/host/dw_mmc.c >> @@ -2325,6 +2325,7 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) >> >> static inline bool dw_mci_fifo_reset(struct dw_mci *host) >> { >> + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; >> /* >> * Reseting generates a block interrupt, hence setting >> * the scatter-gather pointer to NULL. >> @@ -2334,7 +2335,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) >> host->sg = NULL; >> } >> >> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >> + /* >> + * The recommended method for resetting is to always reset the >> + * controller and the fifo, but differs slightly depending on the mode. >> + * The Generic DMA mode (non IDMAC) also needs to reset DMA where IDMAC >> + * mode resets IDMAC at the end. >> + * >> + */ >> +#ifndef CONFIG_MMC_DW_IDMAC > Is it added for generic DMA? > IDMAC should be considered for dma_reseet as well. > Please check databook. > Yeah it's a little unclear. In the "7.2.13 Controller/DMA/FIFO Reset Usage" part of the document they mention It is set for what they call "generic" DMA, which I think is when there is an external DMA controller, and the part below that it says for "DW-DMA/Non-DW-DMA" that controller_reset and fifo_reset should be set. I believe this "DW-DMA" case refers to what is called IDMAC. So, I think it's not required for this case, but I admit I'm not sure why they also say "Non-DW-DMA". If you know of a good way to differentiate the "Generic DMA" case I can implement it. It wasn't clear to me if the driver even supported this "generic" dma case, but it sounds like it might, so I added this code. In practice, on the Exynos Systems we have, which are using IDMAC, the reset procedure seems to work okay without the dma_reset bit set, but I cannot test this "generic dma" case. The other places in the doc where I see them mention the dma_reset bit are "7.2.21 Transmission and Reception with Internal DMAC (IDMAC)" and the description of the CTRL register, and in "7.1 Software/Hardware Restrictions" where they say it will terminate any pending transfer. >> + if (host->use_dma) >> + flags |= SDMMC_CTRL_DMA_RESET; >> +#endif >> + if (dw_mci_ctrl_reset(host, flags)) { >> + /* >> + * In all cases we clear the RAWINTS register to clear any >> + * interrupts. >> + */ > I think interrupt masking is needed before reset because we will not handle it anymore. > And Is there any reason to move interrupt clear here compared with previous version? Yeah I moved it to match the description in the document more closely. The documents mentioned doing the interrupt clear after setting the reset bits, and before waiting for the dma_req bit in the status register to clear. We've been running it with the interrupt clear below the loop, for a while, and I just tested it with the clear above the wait to make sure it still works properly and I was able to pass the tuning process with some errors, so I believe this works fine too, and more closely matches the description in the doc that I have. >> + mci_writel(host, RINTSTS, 0xFFFFFFFF); >> + >> + /* if using dma we wait for dma_req to clear */ >> + if (host->use_dma) { >> + unsigned long timeout = jiffies + msecs_to_jiffies(500); >> + u32 status; >> + do { >> + status = mci_readl(host, STATUS); >> + if (!(status & SDMMC_STATUS_DMA_REQ)) >> + break; >> + cpu_relax(); > What did you intend here? > If you intent busy-wait, how about using sleep instead? Yes it is a busy-wait. There is similar code in dw_mci_ctrl_reset, where that function is polling without sleeps, so I was trying to match that. The cpu_relax() is something I saw in other busy-waits in the kernel, but I'm happy to take it out if you'd like. >> + } while (time_before(jiffies, timeout)); >> + >> + if (status & SDMMC_STATUS_DMA_REQ) { >> + dev_err(host->dev, >> + "%s: Timeout waiting for dma_req to " >> + "clear during reset", __func__); >> + return false; >> + } >> + >> + /* when using DMA next we reset the fifo again */ >> + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >> + } >> + } else { >> + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); > If ciu_reset is cleared, clk update below is needed? I'm honestly not sure what happens if the reset bits don't clear. The docs say controller_reset and dma_reset will auto clear after a number of clocks, but fifo_reset will clear "after completion of the reset operation" So in this particular error case I'm not sure if it's possible to recover properly or not and might hang, so I thought it best to just return the error immediately. > Thanks, > Seungwon Jeon > >> + return false; >> + } >> + >> +#ifdef CONFIG_MMC_DW_IDMAC >> + /* It is also recommended that we reset and reprogram idmac */ >> + dw_mci_idmac_reset(host); >> +#endif >> + >> + /* After a CTRL reset we need to have CIU set clock registers */ >> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); >> + >> + return true; >> } >> >> static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) >> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h >> index 6bf24ab..2505804 100644 >> --- a/drivers/mmc/host/dw_mmc.h >> +++ b/drivers/mmc/host/dw_mmc.h >> @@ -129,6 +129,7 @@ >> #define SDMMC_CMD_INDX(n) ((n) & 0x1F) >> /* Status register defines */ >> #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) >> +#define SDMMC_STATUS_DMA_REQ BIT(31) >> /* FIFOTH register defines */ >> #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ >> ((r) & 0xFFF) << 16 | \ >> -- >> 1.9.1.423.g4596e3a >> >> -- >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >> the body of a message to majordomo@vger.kernel.org >> More majordomo info at http://vger.kernel.org/majordomo-info.html > ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCHv2] mmc: dw_mmc: change to use recommended reset procedure @ 2014-05-13 7:16 ` Sonny Rao 0 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-05-13 7:16 UTC (permalink / raw) To: linux-arm-kernel On Mon, May 12, 2014 at 10:02 PM, Seungwon Jeon <tgih.jun@samsung.com> wrote: > As I mentioned in previous version, you put all reset stuff in existing fifo_reset function. > Although databook mentions ciu_reset case for SBE error, it's not obvious when ciu_reset is needed in other error cases. > If you intend to add some robust error handing, it would be better to make another function. The document I have actually doesn't mention error cases, it describes this procedure as "Controller/DMA/FIFO Reset Usage" so I believe it is saying this is the correct procedure in all cases, and based on our testing it seems to work. I understand the skepticism, as I shared it initially when I saw this, but based on our experience, this is correct and it doesn't need to live in a separate function. > Please check my comments below. > > On Tue, May 13, 2014, Sonny Rao wrote: >> This patch changes the fifo reset code to follow the reset procedure >> outlined in the documentation of Synopsys Mobile storage host databook >> 7.2.13. >> >> v2: Add Generic DMA support >> per the documentation, move interrupt clear before wait >> make the test for DMA host->use_dma rather than host->using_dma >> add proper return values (although it appears no caller checks) >> >> Signed-off-by: Sonny Rao <sonnyrao@chromium.org> >> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.com> >> --- >> drivers/mmc/host/dw_mmc.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++- >> drivers/mmc/host/dw_mmc.h | 1 + >> 2 files changed, 55 insertions(+), 1 deletion(-) >> >> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c >> index 55cd110..aff57e1 100644 >> --- a/drivers/mmc/host/dw_mmc.c >> +++ b/drivers/mmc/host/dw_mmc.c >> @@ -2325,6 +2325,7 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) >> >> static inline bool dw_mci_fifo_reset(struct dw_mci *host) >> { >> + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; >> /* >> * Reseting generates a block interrupt, hence setting >> * the scatter-gather pointer to NULL. >> @@ -2334,7 +2335,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) >> host->sg = NULL; >> } >> >> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >> + /* >> + * The recommended method for resetting is to always reset the >> + * controller and the fifo, but differs slightly depending on the mode. >> + * The Generic DMA mode (non IDMAC) also needs to reset DMA where IDMAC >> + * mode resets IDMAC at the end. >> + * >> + */ >> +#ifndef CONFIG_MMC_DW_IDMAC > Is it added for generic DMA? > IDMAC should be considered for dma_reseet as well. > Please check databook. > Yeah it's a little unclear. In the "7.2.13 Controller/DMA/FIFO Reset Usage" part of the document they mention It is set for what they call "generic" DMA, which I think is when there is an external DMA controller, and the part below that it says for "DW-DMA/Non-DW-DMA" that controller_reset and fifo_reset should be set. I believe this "DW-DMA" case refers to what is called IDMAC. So, I think it's not required for this case, but I admit I'm not sure why they also say "Non-DW-DMA". If you know of a good way to differentiate the "Generic DMA" case I can implement it. It wasn't clear to me if the driver even supported this "generic" dma case, but it sounds like it might, so I added this code. In practice, on the Exynos Systems we have, which are using IDMAC, the reset procedure seems to work okay without the dma_reset bit set, but I cannot test this "generic dma" case. The other places in the doc where I see them mention the dma_reset bit are "7.2.21 Transmission and Reception with Internal DMAC (IDMAC)" and the description of the CTRL register, and in "7.1 Software/Hardware Restrictions" where they say it will terminate any pending transfer. >> + if (host->use_dma) >> + flags |= SDMMC_CTRL_DMA_RESET; >> +#endif >> + if (dw_mci_ctrl_reset(host, flags)) { >> + /* >> + * In all cases we clear the RAWINTS register to clear any >> + * interrupts. >> + */ > I think interrupt masking is needed before reset because we will not handle it anymore. > And Is there any reason to move interrupt clear here compared with previous version? Yeah I moved it to match the description in the document more closely. The documents mentioned doing the interrupt clear after setting the reset bits, and before waiting for the dma_req bit in the status register to clear. We've been running it with the interrupt clear below the loop, for a while, and I just tested it with the clear above the wait to make sure it still works properly and I was able to pass the tuning process with some errors, so I believe this works fine too, and more closely matches the description in the doc that I have. >> + mci_writel(host, RINTSTS, 0xFFFFFFFF); >> + >> + /* if using dma we wait for dma_req to clear */ >> + if (host->use_dma) { >> + unsigned long timeout = jiffies + msecs_to_jiffies(500); >> + u32 status; >> + do { >> + status = mci_readl(host, STATUS); >> + if (!(status & SDMMC_STATUS_DMA_REQ)) >> + break; >> + cpu_relax(); > What did you intend here? > If you intent busy-wait, how about using sleep instead? Yes it is a busy-wait. There is similar code in dw_mci_ctrl_reset, where that function is polling without sleeps, so I was trying to match that. The cpu_relax() is something I saw in other busy-waits in the kernel, but I'm happy to take it out if you'd like. >> + } while (time_before(jiffies, timeout)); >> + >> + if (status & SDMMC_STATUS_DMA_REQ) { >> + dev_err(host->dev, >> + "%s: Timeout waiting for dma_req to " >> + "clear during reset", __func__); >> + return false; >> + } >> + >> + /* when using DMA next we reset the fifo again */ >> + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >> + } >> + } else { >> + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); > If ciu_reset is cleared, clk update below is needed? I'm honestly not sure what happens if the reset bits don't clear. The docs say controller_reset and dma_reset will auto clear after a number of clocks, but fifo_reset will clear "after completion of the reset operation" So in this particular error case I'm not sure if it's possible to recover properly or not and might hang, so I thought it best to just return the error immediately. > Thanks, > Seungwon Jeon > >> + return false; >> + } >> + >> +#ifdef CONFIG_MMC_DW_IDMAC >> + /* It is also recommended that we reset and reprogram idmac */ >> + dw_mci_idmac_reset(host); >> +#endif >> + >> + /* After a CTRL reset we need to have CIU set clock registers */ >> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); >> + >> + return true; >> } >> >> static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) >> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h >> index 6bf24ab..2505804 100644 >> --- a/drivers/mmc/host/dw_mmc.h >> +++ b/drivers/mmc/host/dw_mmc.h >> @@ -129,6 +129,7 @@ >> #define SDMMC_CMD_INDX(n) ((n) & 0x1F) >> /* Status register defines */ >> #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) >> +#define SDMMC_STATUS_DMA_REQ BIT(31) >> /* FIFOTH register defines */ >> #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ >> ((r) & 0xFFF) << 16 | \ >> -- >> 1.9.1.423.g4596e3a >> >> -- >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >> the body of a message to majordomo at vger.kernel.org >> More majordomo info at http://vger.kernel.org/majordomo-info.html > ^ permalink raw reply [flat|nested] 75+ messages in thread
* RE: [PATCHv2] mmc: dw_mmc: change to use recommended reset procedure 2014-05-13 7:16 ` Sonny Rao @ 2014-05-13 11:09 ` Seungwon Jeon -1 siblings, 0 replies; 75+ messages in thread From: Seungwon Jeon @ 2014-05-13 11:09 UTC (permalink / raw) To: 'Sonny Rao' Cc: 'linux-mmc', 'Grant Grundler', 'linux-samsung-soc', linux-arm-kernel, 'Jaehoon Chung', 'Chris Ball', 'Kukjin Kim', 'sunil joshi', 'Tomasz Figa', 'Douglas Anderson', 'Yuvaraj Kumar C D' On Tuesday, May 13, Sonny Rao wrote: > On Mon, May 12, 2014 at 10:02 PM, Seungwon Jeon <tgih.jun@samsung.com> wrote: > > As I mentioned in previous version, you put all reset stuff in existing fifo_reset function. > > Although databook mentions ciu_reset case for SBE error, it's not obvious when ciu_reset is needed > in other error cases. > > If you intend to add some robust error handing, it would be better to make another function. > > The document I have actually doesn't mention error cases, it describes > this procedure as "Controller/DMA/FIFO Reset Usage" so I believe it is > saying this is the correct procedure in all cases, and based on our > testing it seems to work. I understand the skepticism, as I shared it > initially when I saw this, but based on our experience, this is > correct and it doesn't need to live in a separate function. I agree this active error handling. But, existing fifo_reset function is focused on fifo reset purely. I think your change is close to error recovery and it seems overloaded to basic function. So, you suggest renaming function for new sequence. And look into dw_mci_work_routine_card(). dw_mci_idmac_reset() is redundancy. I expect it can be cleaned. <Quot> /* Clear down the FIFO */ dw_mci_fifo_reset(host); #ifdef CONFIG_MMC_DW_IDMAC dw_mci_idmac_reset(host); #endif </Quot> > > > Please check my comments below. > > > > On Tue, May 13, 2014, Sonny Rao wrote: > >> This patch changes the fifo reset code to follow the reset procedure > >> outlined in the documentation of Synopsys Mobile storage host databook > >> 7.2.13. Please remove this section number. No needed. It's old version. > >> > >> v2: Add Generic DMA support > >> per the documentation, move interrupt clear before wait > >> make the test for DMA host->use_dma rather than host->using_dma > >> add proper return values (although it appears no caller checks) > >> > >> Signed-off-by: Sonny Rao <sonnyrao@chromium.org> > >> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.com> > >> --- > >> drivers/mmc/host/dw_mmc.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++- > >> drivers/mmc/host/dw_mmc.h | 1 + > >> 2 files changed, 55 insertions(+), 1 deletion(-) > >> > >> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c > >> index 55cd110..aff57e1 100644 > >> --- a/drivers/mmc/host/dw_mmc.c > >> +++ b/drivers/mmc/host/dw_mmc.c > >> @@ -2325,6 +2325,7 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) > >> > >> static inline bool dw_mci_fifo_reset(struct dw_mci *host) > >> { > >> + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; > >> /* > >> * Reseting generates a block interrupt, hence setting > >> * the scatter-gather pointer to NULL. > >> @@ -2334,7 +2335,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) > >> host->sg = NULL; > >> } > >> > >> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > >> + /* > >> + * The recommended method for resetting is to always reset the > >> + * controller and the fifo, but differs slightly depending on the mode. > >> + * The Generic DMA mode (non IDMAC) also needs to reset DMA where IDMAC > >> + * mode resets IDMAC at the end. > >> + * > >> + */ > >> +#ifndef CONFIG_MMC_DW_IDMAC > > Is it added for generic DMA? > > IDMAC should be considered for dma_reseet as well. > > Please check databook. > > > > Yeah it's a little unclear. In the "7.2.13 Controller/DMA/FIFO Reset > Usage" part of the document they mention It is set for what they call > "generic" DMA, which I think is when there is an external DMA > controller, and the part below that it says for "DW-DMA/Non-DW-DMA" > that controller_reset and fifo_reset should be set. I believe this > "DW-DMA" case refers to what is called IDMAC. So, I think it's not > required for this case, but I admit I'm not sure why they also say > "Non-DW-DMA". If you know of a good way to differentiate the "Generic > DMA" case I can implement it. It wasn't clear to me if the driver > even supported this "generic" dma case, but it sounds like it might, > so I added this code. In practice, on the Exynos Systems we have, > which are using IDMAC, the reset procedure seems to work okay without > the dma_reset bit set, but I cannot test this "generic dma" case. > > The other places in the doc where I see them mention the dma_reset bit > are "7.2.21 Transmission and Reception with Internal DMAC (IDMAC)" > and the description of the CTRL register, and in "7.1 > Software/Hardware Restrictions" where they say it will terminate any > pending transfer. "DW-DMA" means Synopsys's DMA controller not IDMAC. SDMMC_CTRL_DMA_RESET can apply in all type DMA interface. > > >> + if (host->use_dma) > >> + flags |= SDMMC_CTRL_DMA_RESET; > >> +#endif > >> + if (dw_mci_ctrl_reset(host, flags)) { > >> + /* > >> + * In all cases we clear the RAWINTS register to clear any > >> + * interrupts. > >> + */ > > I think interrupt masking is needed before reset because we will not handle it anymore. > > And Is there any reason to move interrupt clear here compared with previous version? > > Yeah I moved it to match the description in the document more closely. > The documents mentioned doing the interrupt clear after setting the > reset bits, and before waiting for the dma_req bit in the status > register to clear. We've been running it with the interrupt clear > below the loop, for a while, and I just tested it with the clear above > the wait to make sure it still works properly and I was able to pass > the tuning process with some errors, so I believe this works fine too, > and more closely matches the description in the doc that I have. When I tried ciu_reset, I found some unexpected interrupts occurred. It means that interrupt handler will run to handle extra interrupts. Then, we may need mask the interrupt. Can you check it for test? > > >> + mci_writel(host, RINTSTS, 0xFFFFFFFF); > >> + > >> + /* if using dma we wait for dma_req to clear */ > >> + if (host->use_dma) { > >> + unsigned long timeout = jiffies + msecs_to_jiffies(500); > >> + u32 status; > >> + do { > >> + status = mci_readl(host, STATUS); > >> + if (!(status & SDMMC_STATUS_DMA_REQ)) > >> + break; > >> + cpu_relax(); > > What did you intend here? > > If you intent busy-wait, how about using sleep instead? > > Yes it is a busy-wait. There is similar code in dw_mci_ctrl_reset, > where that function is polling without sleeps, so I was trying to > match that. The cpu_relax() is something I saw in other busy-waits in > the kernel, but I'm happy to take it out if you'd like. In case of ctrl_reset, waiting is during 2 clock. If this polling status is not long, I'm OK. > > >> + } while (time_before(jiffies, timeout)); > >> + > >> + if (status & SDMMC_STATUS_DMA_REQ) { > >> + dev_err(host->dev, > >> + "%s: Timeout waiting for dma_req to " > >> + "clear during reset", __func__); > >> + return false; > >> + } > >> + > >> + /* when using DMA next we reset the fifo again */ > >> + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > >> + } > >> + } else { > >> + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); > > If ciu_reset is cleared, clk update below is needed? > > I'm honestly not sure what happens if the reset bits don't clear. The > docs say controller_reset and dma_reset will auto clear after a number > of clocks, but fifo_reset will clear "after completion of the reset > operation" So in this particular error case I'm not sure if it's > possible to recover properly or not and might hang, so I thought it > best to just return the error immediately. Yes. But at least if ciu_reset is done successfully, it may need clock update sequence again. In addition, printing reset bit[2:0] will be helpful for debug information. Thanks, Seungwon Jeon > > > Thanks, > > Seungwon Jeon > > > >> + return false; > >> + } > >> + > >> +#ifdef CONFIG_MMC_DW_IDMAC > >> + /* It is also recommended that we reset and reprogram idmac */ > >> + dw_mci_idmac_reset(host); > >> +#endif > >> + > >> + /* After a CTRL reset we need to have CIU set clock registers */ > >> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); > >> + > >> + return true; > >> } > >> > >> static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) > >> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h > >> index 6bf24ab..2505804 100644 > >> --- a/drivers/mmc/host/dw_mmc.h > >> +++ b/drivers/mmc/host/dw_mmc.h > >> @@ -129,6 +129,7 @@ > >> #define SDMMC_CMD_INDX(n) ((n) & 0x1F) > >> /* Status register defines */ > >> #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) > >> +#define SDMMC_STATUS_DMA_REQ BIT(31) > >> /* FIFOTH register defines */ > >> #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ > >> ((r) & 0xFFF) << 16 | \ > >> -- > >> 1.9.1.423.g4596e3a > >> > >> -- > >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > >> the body of a message to majordomo@vger.kernel.org > >> More majordomo info at http://vger.kernel.org/majordomo-info.html > > > -- > To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCHv2] mmc: dw_mmc: change to use recommended reset procedure @ 2014-05-13 11:09 ` Seungwon Jeon 0 siblings, 0 replies; 75+ messages in thread From: Seungwon Jeon @ 2014-05-13 11:09 UTC (permalink / raw) To: linux-arm-kernel On Tuesday, May 13, Sonny Rao wrote: > On Mon, May 12, 2014 at 10:02 PM, Seungwon Jeon <tgih.jun@samsung.com> wrote: > > As I mentioned in previous version, you put all reset stuff in existing fifo_reset function. > > Although databook mentions ciu_reset case for SBE error, it's not obvious when ciu_reset is needed > in other error cases. > > If you intend to add some robust error handing, it would be better to make another function. > > The document I have actually doesn't mention error cases, it describes > this procedure as "Controller/DMA/FIFO Reset Usage" so I believe it is > saying this is the correct procedure in all cases, and based on our > testing it seems to work. I understand the skepticism, as I shared it > initially when I saw this, but based on our experience, this is > correct and it doesn't need to live in a separate function. I agree this active error handling. But, existing fifo_reset function is focused on fifo reset purely. I think your change is close to error recovery and it seems overloaded to basic function. So, you suggest renaming function for new sequence. And look into dw_mci_work_routine_card(). dw_mci_idmac_reset() is redundancy. I expect it can be cleaned. <Quot> /* Clear down the FIFO */ dw_mci_fifo_reset(host); #ifdef CONFIG_MMC_DW_IDMAC dw_mci_idmac_reset(host); #endif </Quot> > > > Please check my comments below. > > > > On Tue, May 13, 2014, Sonny Rao wrote: > >> This patch changes the fifo reset code to follow the reset procedure > >> outlined in the documentation of Synopsys Mobile storage host databook > >> 7.2.13. Please remove this section number. No needed. It's old version. > >> > >> v2: Add Generic DMA support > >> per the documentation, move interrupt clear before wait > >> make the test for DMA host->use_dma rather than host->using_dma > >> add proper return values (although it appears no caller checks) > >> > >> Signed-off-by: Sonny Rao <sonnyrao@chromium.org> > >> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.com> > >> --- > >> drivers/mmc/host/dw_mmc.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++- > >> drivers/mmc/host/dw_mmc.h | 1 + > >> 2 files changed, 55 insertions(+), 1 deletion(-) > >> > >> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c > >> index 55cd110..aff57e1 100644 > >> --- a/drivers/mmc/host/dw_mmc.c > >> +++ b/drivers/mmc/host/dw_mmc.c > >> @@ -2325,6 +2325,7 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) > >> > >> static inline bool dw_mci_fifo_reset(struct dw_mci *host) > >> { > >> + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; > >> /* > >> * Reseting generates a block interrupt, hence setting > >> * the scatter-gather pointer to NULL. > >> @@ -2334,7 +2335,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) > >> host->sg = NULL; > >> } > >> > >> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > >> + /* > >> + * The recommended method for resetting is to always reset the > >> + * controller and the fifo, but differs slightly depending on the mode. > >> + * The Generic DMA mode (non IDMAC) also needs to reset DMA where IDMAC > >> + * mode resets IDMAC at the end. > >> + * > >> + */ > >> +#ifndef CONFIG_MMC_DW_IDMAC > > Is it added for generic DMA? > > IDMAC should be considered for dma_reseet as well. > > Please check databook. > > > > Yeah it's a little unclear. In the "7.2.13 Controller/DMA/FIFO Reset > Usage" part of the document they mention It is set for what they call > "generic" DMA, which I think is when there is an external DMA > controller, and the part below that it says for "DW-DMA/Non-DW-DMA" > that controller_reset and fifo_reset should be set. I believe this > "DW-DMA" case refers to what is called IDMAC. So, I think it's not > required for this case, but I admit I'm not sure why they also say > "Non-DW-DMA". If you know of a good way to differentiate the "Generic > DMA" case I can implement it. It wasn't clear to me if the driver > even supported this "generic" dma case, but it sounds like it might, > so I added this code. In practice, on the Exynos Systems we have, > which are using IDMAC, the reset procedure seems to work okay without > the dma_reset bit set, but I cannot test this "generic dma" case. > > The other places in the doc where I see them mention the dma_reset bit > are "7.2.21 Transmission and Reception with Internal DMAC (IDMAC)" > and the description of the CTRL register, and in "7.1 > Software/Hardware Restrictions" where they say it will terminate any > pending transfer. "DW-DMA" means Synopsys's DMA controller not IDMAC. SDMMC_CTRL_DMA_RESET can apply in all type DMA interface. > > >> + if (host->use_dma) > >> + flags |= SDMMC_CTRL_DMA_RESET; > >> +#endif > >> + if (dw_mci_ctrl_reset(host, flags)) { > >> + /* > >> + * In all cases we clear the RAWINTS register to clear any > >> + * interrupts. > >> + */ > > I think interrupt masking is needed before reset because we will not handle it anymore. > > And Is there any reason to move interrupt clear here compared with previous version? > > Yeah I moved it to match the description in the document more closely. > The documents mentioned doing the interrupt clear after setting the > reset bits, and before waiting for the dma_req bit in the status > register to clear. We've been running it with the interrupt clear > below the loop, for a while, and I just tested it with the clear above > the wait to make sure it still works properly and I was able to pass > the tuning process with some errors, so I believe this works fine too, > and more closely matches the description in the doc that I have. When I tried ciu_reset, I found some unexpected interrupts occurred. It means that interrupt handler will run to handle extra interrupts. Then, we may need mask the interrupt. Can you check it for test? > > >> + mci_writel(host, RINTSTS, 0xFFFFFFFF); > >> + > >> + /* if using dma we wait for dma_req to clear */ > >> + if (host->use_dma) { > >> + unsigned long timeout = jiffies + msecs_to_jiffies(500); > >> + u32 status; > >> + do { > >> + status = mci_readl(host, STATUS); > >> + if (!(status & SDMMC_STATUS_DMA_REQ)) > >> + break; > >> + cpu_relax(); > > What did you intend here? > > If you intent busy-wait, how about using sleep instead? > > Yes it is a busy-wait. There is similar code in dw_mci_ctrl_reset, > where that function is polling without sleeps, so I was trying to > match that. The cpu_relax() is something I saw in other busy-waits in > the kernel, but I'm happy to take it out if you'd like. In case of ctrl_reset, waiting is during 2 clock. If this polling status is not long, I'm OK. > > >> + } while (time_before(jiffies, timeout)); > >> + > >> + if (status & SDMMC_STATUS_DMA_REQ) { > >> + dev_err(host->dev, > >> + "%s: Timeout waiting for dma_req to " > >> + "clear during reset", __func__); > >> + return false; > >> + } > >> + > >> + /* when using DMA next we reset the fifo again */ > >> + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > >> + } > >> + } else { > >> + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); > > If ciu_reset is cleared, clk update below is needed? > > I'm honestly not sure what happens if the reset bits don't clear. The > docs say controller_reset and dma_reset will auto clear after a number > of clocks, but fifo_reset will clear "after completion of the reset > operation" So in this particular error case I'm not sure if it's > possible to recover properly or not and might hang, so I thought it > best to just return the error immediately. Yes. But at least if ciu_reset is done successfully, it may need clock update sequence again. In addition, printing reset bit[2:0] will be helpful for debug information. Thanks, Seungwon Jeon > > > Thanks, > > Seungwon Jeon > > > >> + return false; > >> + } > >> + > >> +#ifdef CONFIG_MMC_DW_IDMAC > >> + /* It is also recommended that we reset and reprogram idmac */ > >> + dw_mci_idmac_reset(host); > >> +#endif > >> + > >> + /* After a CTRL reset we need to have CIU set clock registers */ > >> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); > >> + > >> + return true; > >> } > >> > >> static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) > >> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h > >> index 6bf24ab..2505804 100644 > >> --- a/drivers/mmc/host/dw_mmc.h > >> +++ b/drivers/mmc/host/dw_mmc.h > >> @@ -129,6 +129,7 @@ > >> #define SDMMC_CMD_INDX(n) ((n) & 0x1F) > >> /* Status register defines */ > >> #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) > >> +#define SDMMC_STATUS_DMA_REQ BIT(31) > >> /* FIFOTH register defines */ > >> #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ > >> ((r) & 0xFFF) << 16 | \ > >> -- > >> 1.9.1.423.g4596e3a > >> > >> -- > >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > >> the body of a message to majordomo at vger.kernel.org > >> More majordomo info at http://vger.kernel.org/majordomo-info.html > > > -- > To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > the body of a message to majordomo at vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCHv2] mmc: dw_mmc: change to use recommended reset procedure 2014-05-13 11:09 ` Seungwon Jeon @ 2014-05-17 0:36 ` Sonny Rao -1 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-05-17 0:36 UTC (permalink / raw) To: Seungwon Jeon Cc: linux-mmc, Grant Grundler, linux-samsung-soc, linux-arm-kernel, Jaehoon Chung, Chris Ball, Kukjin Kim, sunil joshi, Tomasz Figa, Douglas Anderson, Yuvaraj Kumar C D On Tue, May 13, 2014 at 4:09 AM, Seungwon Jeon <tgih.jun@samsung.com> wrote: > On Tuesday, May 13, Sonny Rao wrote: >> On Mon, May 12, 2014 at 10:02 PM, Seungwon Jeon <tgih.jun@samsung.com> wrote: >> > As I mentioned in previous version, you put all reset stuff in existing fifo_reset function. >> > Although databook mentions ciu_reset case for SBE error, it's not obvious when ciu_reset is needed >> in other error cases. >> > If you intend to add some robust error handing, it would be better to make another function. >> >> The document I have actually doesn't mention error cases, it describes >> this procedure as "Controller/DMA/FIFO Reset Usage" so I believe it is >> saying this is the correct procedure in all cases, and based on our >> testing it seems to work. I understand the skepticism, as I shared it >> initially when I saw this, but based on our experience, this is >> correct and it doesn't need to live in a separate function. > I agree this active error handling. > But, existing fifo_reset function is focused on fifo reset purely. > I think your change is close to error recovery and it seems overloaded to basic function. > So, you suggest renaming function for new sequence. I think the documentation says it should always be done, not just in error recovery. I can rename the function to dw_mci_reset rather than dw_mci_fifo_reset. Is that what you mean? Or do you mean make a new function that is only called in error cases? > And look into dw_mci_work_routine_card(). dw_mci_idmac_reset() is redundancy. > I expect it can be cleaned. > > <Quot> > /* Clear down the FIFO */ > dw_mci_fifo_reset(host); > #ifdef CONFIG_MMC_DW_IDMAC > dw_mci_idmac_reset(host); > #endif > </Quot> > Ok, I'll remove that extra reset, thanks for catching. >> >> > Please check my comments below. >> > >> > On Tue, May 13, 2014, Sonny Rao wrote: >> >> This patch changes the fifo reset code to follow the reset procedure >> >> outlined in the documentation of Synopsys Mobile storage host databook >> >> 7.2.13. > Please remove this section number. > No needed. It's old version. > Ok >> >> >> >> v2: Add Generic DMA support >> >> per the documentation, move interrupt clear before wait >> >> make the test for DMA host->use_dma rather than host->using_dma >> >> add proper return values (although it appears no caller checks) >> >> >> >> Signed-off-by: Sonny Rao <sonnyrao@chromium.org> >> >> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.com> >> >> --- >> >> drivers/mmc/host/dw_mmc.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++- >> >> drivers/mmc/host/dw_mmc.h | 1 + >> >> 2 files changed, 55 insertions(+), 1 deletion(-) >> >> >> >> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c >> >> index 55cd110..aff57e1 100644 >> >> --- a/drivers/mmc/host/dw_mmc.c >> >> +++ b/drivers/mmc/host/dw_mmc.c >> >> @@ -2325,6 +2325,7 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) >> >> >> >> static inline bool dw_mci_fifo_reset(struct dw_mci *host) >> >> { >> >> + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; >> >> /* >> >> * Reseting generates a block interrupt, hence setting >> >> * the scatter-gather pointer to NULL. >> >> @@ -2334,7 +2335,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) >> >> host->sg = NULL; >> >> } >> >> >> >> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >> >> + /* >> >> + * The recommended method for resetting is to always reset the >> >> + * controller and the fifo, but differs slightly depending on the mode. >> >> + * The Generic DMA mode (non IDMAC) also needs to reset DMA where IDMAC >> >> + * mode resets IDMAC at the end. >> >> + * >> >> + */ >> >> +#ifndef CONFIG_MMC_DW_IDMAC >> > Is it added for generic DMA? >> > IDMAC should be considered for dma_reseet as well. >> > Please check databook. >> > >> >> Yeah it's a little unclear. In the "7.2.13 Controller/DMA/FIFO Reset >> Usage" part of the document they mention It is set for what they call >> "generic" DMA, which I think is when there is an external DMA >> controller, and the part below that it says for "DW-DMA/Non-DW-DMA" >> that controller_reset and fifo_reset should be set. I believe this >> "DW-DMA" case refers to what is called IDMAC. So, I think it's not >> required for this case, but I admit I'm not sure why they also say >> "Non-DW-DMA". If you know of a good way to differentiate the "Generic >> DMA" case I can implement it. It wasn't clear to me if the driver >> even supported this "generic" dma case, but it sounds like it might, >> so I added this code. In practice, on the Exynos Systems we have, >> which are using IDMAC, the reset procedure seems to work okay without >> the dma_reset bit set, but I cannot test this "generic dma" case. >> >> The other places in the doc where I see them mention the dma_reset bit >> are "7.2.21 Transmission and Reception with Internal DMAC (IDMAC)" >> and the description of the CTRL register, and in "7.1 >> Software/Hardware Restrictions" where they say it will terminate any >> pending transfer. > "DW-DMA" means Synopsys's DMA controller not IDMAC. > SDMMC_CTRL_DMA_RESET can apply in all type DMA interface. So, do you think I should always set that bit if we're using DMA? > >> >> >> + if (host->use_dma) >> >> + flags |= SDMMC_CTRL_DMA_RESET; >> >> +#endif >> >> + if (dw_mci_ctrl_reset(host, flags)) { >> >> + /* >> >> + * In all cases we clear the RAWINTS register to clear any >> >> + * interrupts. >> >> + */ >> > I think interrupt masking is needed before reset because we will not handle it anymore. >> > And Is there any reason to move interrupt clear here compared with previous version? >> >> Yeah I moved it to match the description in the document more closely. >> The documents mentioned doing the interrupt clear after setting the >> reset bits, and before waiting for the dma_req bit in the status >> register to clear. We've been running it with the interrupt clear >> below the loop, for a while, and I just tested it with the clear above >> the wait to make sure it still works properly and I was able to pass >> the tuning process with some errors, so I believe this works fine too, >> and more closely matches the description in the doc that I have. > When I tried ciu_reset, I found some unexpected interrupts occurred. > It means that interrupt handler will run to handle extra interrupts. > Then, we may need mask the interrupt. > Can you check it for test? You're right. When I have the controller reset bit set, I see one interrupt coming in shortly after we write the reset bits, which has status bits of 0x180. This has Response timeout (RTO) and Data CRC error set. It sounds like some interrupt ocurring may be expected since they say to clear RINTSTS as part of the procedure though. > >> >> >> + mci_writel(host, RINTSTS, 0xFFFFFFFF); >> >> + >> >> + /* if using dma we wait for dma_req to clear */ >> >> + if (host->use_dma) { >> >> + unsigned long timeout = jiffies + msecs_to_jiffies(500); >> >> + u32 status; >> >> + do { >> >> + status = mci_readl(host, STATUS); >> >> + if (!(status & SDMMC_STATUS_DMA_REQ)) >> >> + break; >> >> + cpu_relax(); >> > What did you intend here? >> > If you intent busy-wait, how about using sleep instead? >> >> Yes it is a busy-wait. There is similar code in dw_mci_ctrl_reset, >> where that function is polling without sleeps, so I was trying to >> match that. The cpu_relax() is something I saw in other busy-waits in >> the kernel, but I'm happy to take it out if you'd like. > In case of ctrl_reset, waiting is during 2 clock. > If this polling status is not long, I'm OK. > >> >> >> + } while (time_before(jiffies, timeout)); >> >> + >> >> + if (status & SDMMC_STATUS_DMA_REQ) { >> >> + dev_err(host->dev, >> >> + "%s: Timeout waiting for dma_req to " >> >> + "clear during reset", __func__); >> >> + return false; >> >> + } >> >> + >> >> + /* when using DMA next we reset the fifo again */ >> >> + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >> >> + } >> >> + } else { >> >> + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); >> > If ciu_reset is cleared, clk update below is needed? >> >> I'm honestly not sure what happens if the reset bits don't clear. The >> docs say controller_reset and dma_reset will auto clear after a number >> of clocks, but fifo_reset will clear "after completion of the reset >> operation" So in this particular error case I'm not sure if it's >> possible to recover properly or not and might hang, so I thought it >> best to just return the error immediately. > Yes. > But at least if ciu_reset is done successfully, it may need clock update sequence again. > In addition, printing reset bit[2:0] will be helpful for debug information. The dw_mci_ctrl_reset() function would run this code if some of the bits didn't clear: dev_err(host->dev, "Timeout resetting block (ctrl reset %#x)\n", ctrl & reset); Does that give you what you're looking for? > > Thanks, > Seungwon Jeon > >> >> > Thanks, >> > Seungwon Jeon >> > >> >> + return false; >> >> + } >> >> + >> >> +#ifdef CONFIG_MMC_DW_IDMAC >> >> + /* It is also recommended that we reset and reprogram idmac */ >> >> + dw_mci_idmac_reset(host); >> >> +#endif >> >> + >> >> + /* After a CTRL reset we need to have CIU set clock registers */ >> >> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); >> >> + >> >> + return true; >> >> } >> >> >> >> static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) >> >> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h >> >> index 6bf24ab..2505804 100644 >> >> --- a/drivers/mmc/host/dw_mmc.h >> >> +++ b/drivers/mmc/host/dw_mmc.h >> >> @@ -129,6 +129,7 @@ >> >> #define SDMMC_CMD_INDX(n) ((n) & 0x1F) >> >> /* Status register defines */ >> >> #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) >> >> +#define SDMMC_STATUS_DMA_REQ BIT(31) >> >> /* FIFOTH register defines */ >> >> #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ >> >> ((r) & 0xFFF) << 16 | \ >> >> -- >> >> 1.9.1.423.g4596e3a >> >> >> >> -- >> >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >> >> the body of a message to majordomo@vger.kernel.org >> >> More majordomo info at http://vger.kernel.org/majordomo-info.html >> > >> -- >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >> the body of a message to majordomo@vger.kernel.org >> More majordomo info at http://vger.kernel.org/majordomo-info.html > ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCHv2] mmc: dw_mmc: change to use recommended reset procedure @ 2014-05-17 0:36 ` Sonny Rao 0 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-05-17 0:36 UTC (permalink / raw) To: linux-arm-kernel On Tue, May 13, 2014 at 4:09 AM, Seungwon Jeon <tgih.jun@samsung.com> wrote: > On Tuesday, May 13, Sonny Rao wrote: >> On Mon, May 12, 2014 at 10:02 PM, Seungwon Jeon <tgih.jun@samsung.com> wrote: >> > As I mentioned in previous version, you put all reset stuff in existing fifo_reset function. >> > Although databook mentions ciu_reset case for SBE error, it's not obvious when ciu_reset is needed >> in other error cases. >> > If you intend to add some robust error handing, it would be better to make another function. >> >> The document I have actually doesn't mention error cases, it describes >> this procedure as "Controller/DMA/FIFO Reset Usage" so I believe it is >> saying this is the correct procedure in all cases, and based on our >> testing it seems to work. I understand the skepticism, as I shared it >> initially when I saw this, but based on our experience, this is >> correct and it doesn't need to live in a separate function. > I agree this active error handling. > But, existing fifo_reset function is focused on fifo reset purely. > I think your change is close to error recovery and it seems overloaded to basic function. > So, you suggest renaming function for new sequence. I think the documentation says it should always be done, not just in error recovery. I can rename the function to dw_mci_reset rather than dw_mci_fifo_reset. Is that what you mean? Or do you mean make a new function that is only called in error cases? > And look into dw_mci_work_routine_card(). dw_mci_idmac_reset() is redundancy. > I expect it can be cleaned. > > <Quot> > /* Clear down the FIFO */ > dw_mci_fifo_reset(host); > #ifdef CONFIG_MMC_DW_IDMAC > dw_mci_idmac_reset(host); > #endif > </Quot> > Ok, I'll remove that extra reset, thanks for catching. >> >> > Please check my comments below. >> > >> > On Tue, May 13, 2014, Sonny Rao wrote: >> >> This patch changes the fifo reset code to follow the reset procedure >> >> outlined in the documentation of Synopsys Mobile storage host databook >> >> 7.2.13. > Please remove this section number. > No needed. It's old version. > Ok >> >> >> >> v2: Add Generic DMA support >> >> per the documentation, move interrupt clear before wait >> >> make the test for DMA host->use_dma rather than host->using_dma >> >> add proper return values (although it appears no caller checks) >> >> >> >> Signed-off-by: Sonny Rao <sonnyrao@chromium.org> >> >> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.com> >> >> --- >> >> drivers/mmc/host/dw_mmc.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++- >> >> drivers/mmc/host/dw_mmc.h | 1 + >> >> 2 files changed, 55 insertions(+), 1 deletion(-) >> >> >> >> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c >> >> index 55cd110..aff57e1 100644 >> >> --- a/drivers/mmc/host/dw_mmc.c >> >> +++ b/drivers/mmc/host/dw_mmc.c >> >> @@ -2325,6 +2325,7 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) >> >> >> >> static inline bool dw_mci_fifo_reset(struct dw_mci *host) >> >> { >> >> + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; >> >> /* >> >> * Reseting generates a block interrupt, hence setting >> >> * the scatter-gather pointer to NULL. >> >> @@ -2334,7 +2335,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) >> >> host->sg = NULL; >> >> } >> >> >> >> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >> >> + /* >> >> + * The recommended method for resetting is to always reset the >> >> + * controller and the fifo, but differs slightly depending on the mode. >> >> + * The Generic DMA mode (non IDMAC) also needs to reset DMA where IDMAC >> >> + * mode resets IDMAC at the end. >> >> + * >> >> + */ >> >> +#ifndef CONFIG_MMC_DW_IDMAC >> > Is it added for generic DMA? >> > IDMAC should be considered for dma_reseet as well. >> > Please check databook. >> > >> >> Yeah it's a little unclear. In the "7.2.13 Controller/DMA/FIFO Reset >> Usage" part of the document they mention It is set for what they call >> "generic" DMA, which I think is when there is an external DMA >> controller, and the part below that it says for "DW-DMA/Non-DW-DMA" >> that controller_reset and fifo_reset should be set. I believe this >> "DW-DMA" case refers to what is called IDMAC. So, I think it's not >> required for this case, but I admit I'm not sure why they also say >> "Non-DW-DMA". If you know of a good way to differentiate the "Generic >> DMA" case I can implement it. It wasn't clear to me if the driver >> even supported this "generic" dma case, but it sounds like it might, >> so I added this code. In practice, on the Exynos Systems we have, >> which are using IDMAC, the reset procedure seems to work okay without >> the dma_reset bit set, but I cannot test this "generic dma" case. >> >> The other places in the doc where I see them mention the dma_reset bit >> are "7.2.21 Transmission and Reception with Internal DMAC (IDMAC)" >> and the description of the CTRL register, and in "7.1 >> Software/Hardware Restrictions" where they say it will terminate any >> pending transfer. > "DW-DMA" means Synopsys's DMA controller not IDMAC. > SDMMC_CTRL_DMA_RESET can apply in all type DMA interface. So, do you think I should always set that bit if we're using DMA? > >> >> >> + if (host->use_dma) >> >> + flags |= SDMMC_CTRL_DMA_RESET; >> >> +#endif >> >> + if (dw_mci_ctrl_reset(host, flags)) { >> >> + /* >> >> + * In all cases we clear the RAWINTS register to clear any >> >> + * interrupts. >> >> + */ >> > I think interrupt masking is needed before reset because we will not handle it anymore. >> > And Is there any reason to move interrupt clear here compared with previous version? >> >> Yeah I moved it to match the description in the document more closely. >> The documents mentioned doing the interrupt clear after setting the >> reset bits, and before waiting for the dma_req bit in the status >> register to clear. We've been running it with the interrupt clear >> below the loop, for a while, and I just tested it with the clear above >> the wait to make sure it still works properly and I was able to pass >> the tuning process with some errors, so I believe this works fine too, >> and more closely matches the description in the doc that I have. > When I tried ciu_reset, I found some unexpected interrupts occurred. > It means that interrupt handler will run to handle extra interrupts. > Then, we may need mask the interrupt. > Can you check it for test? You're right. When I have the controller reset bit set, I see one interrupt coming in shortly after we write the reset bits, which has status bits of 0x180. This has Response timeout (RTO) and Data CRC error set. It sounds like some interrupt ocurring may be expected since they say to clear RINTSTS as part of the procedure though. > >> >> >> + mci_writel(host, RINTSTS, 0xFFFFFFFF); >> >> + >> >> + /* if using dma we wait for dma_req to clear */ >> >> + if (host->use_dma) { >> >> + unsigned long timeout = jiffies + msecs_to_jiffies(500); >> >> + u32 status; >> >> + do { >> >> + status = mci_readl(host, STATUS); >> >> + if (!(status & SDMMC_STATUS_DMA_REQ)) >> >> + break; >> >> + cpu_relax(); >> > What did you intend here? >> > If you intent busy-wait, how about using sleep instead? >> >> Yes it is a busy-wait. There is similar code in dw_mci_ctrl_reset, >> where that function is polling without sleeps, so I was trying to >> match that. The cpu_relax() is something I saw in other busy-waits in >> the kernel, but I'm happy to take it out if you'd like. > In case of ctrl_reset, waiting is during 2 clock. > If this polling status is not long, I'm OK. > >> >> >> + } while (time_before(jiffies, timeout)); >> >> + >> >> + if (status & SDMMC_STATUS_DMA_REQ) { >> >> + dev_err(host->dev, >> >> + "%s: Timeout waiting for dma_req to " >> >> + "clear during reset", __func__); >> >> + return false; >> >> + } >> >> + >> >> + /* when using DMA next we reset the fifo again */ >> >> + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >> >> + } >> >> + } else { >> >> + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); >> > If ciu_reset is cleared, clk update below is needed? >> >> I'm honestly not sure what happens if the reset bits don't clear. The >> docs say controller_reset and dma_reset will auto clear after a number >> of clocks, but fifo_reset will clear "after completion of the reset >> operation" So in this particular error case I'm not sure if it's >> possible to recover properly or not and might hang, so I thought it >> best to just return the error immediately. > Yes. > But at least if ciu_reset is done successfully, it may need clock update sequence again. > In addition, printing reset bit[2:0] will be helpful for debug information. The dw_mci_ctrl_reset() function would run this code if some of the bits didn't clear: dev_err(host->dev, "Timeout resetting block (ctrl reset %#x)\n", ctrl & reset); Does that give you what you're looking for? > > Thanks, > Seungwon Jeon > >> >> > Thanks, >> > Seungwon Jeon >> > >> >> + return false; >> >> + } >> >> + >> >> +#ifdef CONFIG_MMC_DW_IDMAC >> >> + /* It is also recommended that we reset and reprogram idmac */ >> >> + dw_mci_idmac_reset(host); >> >> +#endif >> >> + >> >> + /* After a CTRL reset we need to have CIU set clock registers */ >> >> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); >> >> + >> >> + return true; >> >> } >> >> >> >> static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) >> >> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h >> >> index 6bf24ab..2505804 100644 >> >> --- a/drivers/mmc/host/dw_mmc.h >> >> +++ b/drivers/mmc/host/dw_mmc.h >> >> @@ -129,6 +129,7 @@ >> >> #define SDMMC_CMD_INDX(n) ((n) & 0x1F) >> >> /* Status register defines */ >> >> #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) >> >> +#define SDMMC_STATUS_DMA_REQ BIT(31) >> >> /* FIFOTH register defines */ >> >> #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ >> >> ((r) & 0xFFF) << 16 | \ >> >> -- >> >> 1.9.1.423.g4596e3a >> >> >> >> -- >> >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >> >> the body of a message to majordomo at vger.kernel.org >> >> More majordomo info at http://vger.kernel.org/majordomo-info.html >> > >> -- >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >> the body of a message to majordomo at vger.kernel.org >> More majordomo info at http://vger.kernel.org/majordomo-info.html > ^ permalink raw reply [flat|nested] 75+ messages in thread
* RE: [PATCHv2] mmc: dw_mmc: change to use recommended reset procedure 2014-05-17 0:36 ` Sonny Rao @ 2014-05-20 1:49 ` Seungwon Jeon -1 siblings, 0 replies; 75+ messages in thread From: Seungwon Jeon @ 2014-05-20 1:49 UTC (permalink / raw) To: 'Sonny Rao' Cc: 'Yuvaraj Kumar C D', 'linux-samsung-soc', 'Grant Grundler', 'Tomasz Figa', 'linux-mmc', 'sunil joshi', 'Douglas Anderson', 'Jaehoon Chung', 'Kukjin Kim', 'Chris Ball', linux-arm-kernel On Sat, May 17, 2014, Sonny Rao wrote: > On Tue, May 13, 2014 at 4:09 AM, Seungwon Jeon <tgih.jun@samsung.com> wrote: > > On Tuesday, May 13, Sonny Rao wrote: > >> On Mon, May 12, 2014 at 10:02 PM, Seungwon Jeon <tgih.jun@samsung.com> wrote: > >> > As I mentioned in previous version, you put all reset stuff in existing fifo_reset function. > >> > Although databook mentions ciu_reset case for SBE error, it's not obvious when ciu_reset is > needed > >> in other error cases. > >> > If you intend to add some robust error handing, it would be better to make another function. > >> > >> The document I have actually doesn't mention error cases, it describes > >> this procedure as "Controller/DMA/FIFO Reset Usage" so I believe it is > >> saying this is the correct procedure in all cases, and based on our > >> testing it seems to work. I understand the skepticism, as I shared it > >> initially when I saw this, but based on our experience, this is > >> correct and it doesn't need to live in a separate function. > > I agree this active error handling. > > But, existing fifo_reset function is focused on fifo reset purely. > > I think your change is close to error recovery and it seems overloaded to basic function. > > So, you suggest renaming function for new sequence. > > I think the documentation says it should always be done, not just in > error recovery. I can rename the function to dw_mci_reset rather than > dw_mci_fifo_reset. Is that what you mean? Or do you mean make a new > function that is only called in error cases? Both are okay. > > > And look into dw_mci_work_routine_card(). dw_mci_idmac_reset() is redundancy. > > I expect it can be cleaned. > > > > <Quot> > > /* Clear down the FIFO */ > > dw_mci_fifo_reset(host); > > #ifdef CONFIG_MMC_DW_IDMAC > > dw_mci_idmac_reset(host); > > #endif > > </Quot> > > > > Ok, I'll remove that extra reset, thanks for catching. > > >> > >> > Please check my comments below. > >> > > >> > On Tue, May 13, 2014, Sonny Rao wrote: > >> >> This patch changes the fifo reset code to follow the reset procedure > >> >> outlined in the documentation of Synopsys Mobile storage host databook > >> >> 7.2.13. > > Please remove this section number. > > No needed. It's old version. > > > > Ok > > >> >> > >> >> v2: Add Generic DMA support > >> >> per the documentation, move interrupt clear before wait > >> >> make the test for DMA host->use_dma rather than host->using_dma > >> >> add proper return values (although it appears no caller checks) > >> >> > >> >> Signed-off-by: Sonny Rao <sonnyrao@chromium.org> > >> >> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.com> > >> >> --- > >> >> drivers/mmc/host/dw_mmc.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++- > >> >> drivers/mmc/host/dw_mmc.h | 1 + > >> >> 2 files changed, 55 insertions(+), 1 deletion(-) > >> >> > >> >> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c > >> >> index 55cd110..aff57e1 100644 > >> >> --- a/drivers/mmc/host/dw_mmc.c > >> >> +++ b/drivers/mmc/host/dw_mmc.c > >> >> @@ -2325,6 +2325,7 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) > >> >> > >> >> static inline bool dw_mci_fifo_reset(struct dw_mci *host) > >> >> { > >> >> + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; > >> >> /* > >> >> * Reseting generates a block interrupt, hence setting > >> >> * the scatter-gather pointer to NULL. > >> >> @@ -2334,7 +2335,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) > >> >> host->sg = NULL; > >> >> } > >> >> > >> >> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > >> >> + /* > >> >> + * The recommended method for resetting is to always reset the > >> >> + * controller and the fifo, but differs slightly depending on the mode. > >> >> + * The Generic DMA mode (non IDMAC) also needs to reset DMA where IDMAC > >> >> + * mode resets IDMAC at the end. > >> >> + * > >> >> + */ > >> >> +#ifndef CONFIG_MMC_DW_IDMAC > >> > Is it added for generic DMA? > >> > IDMAC should be considered for dma_reseet as well. > >> > Please check databook. > >> > > >> > >> Yeah it's a little unclear. In the "7.2.13 Controller/DMA/FIFO Reset > >> Usage" part of the document they mention It is set for what they call > >> "generic" DMA, which I think is when there is an external DMA > >> controller, and the part below that it says for "DW-DMA/Non-DW-DMA" > >> that controller_reset and fifo_reset should be set. I believe this > >> "DW-DMA" case refers to what is called IDMAC. So, I think it's not > >> required for this case, but I admit I'm not sure why they also say > >> "Non-DW-DMA". If you know of a good way to differentiate the "Generic > >> DMA" case I can implement it. It wasn't clear to me if the driver > >> even supported this "generic" dma case, but it sounds like it might, > >> so I added this code. In practice, on the Exynos Systems we have, > >> which are using IDMAC, the reset procedure seems to work okay without > >> the dma_reset bit set, but I cannot test this "generic dma" case. > >> > >> The other places in the doc where I see them mention the dma_reset bit > >> are "7.2.21 Transmission and Reception with Internal DMAC (IDMAC)" > >> and the description of the CTRL register, and in "7.1 > >> Software/Hardware Restrictions" where they say it will terminate any > >> pending transfer. > > "DW-DMA" means Synopsys's DMA controller not IDMAC. > > SDMMC_CTRL_DMA_RESET can apply in all type DMA interface. > > So, do you think I should always set that bit if we're using DMA? Yes. Although you used it for general dma at first, IDMAC also needs it. > > > > >> > >> >> + if (host->use_dma) > >> >> + flags |= SDMMC_CTRL_DMA_RESET; > >> >> +#endif > >> >> + if (dw_mci_ctrl_reset(host, flags)) { > >> >> + /* > >> >> + * In all cases we clear the RAWINTS register to clear any > >> >> + * interrupts. > >> >> + */ > >> > I think interrupt masking is needed before reset because we will not handle it anymore. > >> > And Is there any reason to move interrupt clear here compared with previous version? > >> > >> Yeah I moved it to match the description in the document more closely. > >> The documents mentioned doing the interrupt clear after setting the > >> reset bits, and before waiting for the dma_req bit in the status > >> register to clear. We've been running it with the interrupt clear > >> below the loop, for a while, and I just tested it with the clear above > >> the wait to make sure it still works properly and I was able to pass > >> the tuning process with some errors, so I believe this works fine too, > >> and more closely matches the description in the doc that I have. > > When I tried ciu_reset, I found some unexpected interrupts occurred. > > It means that interrupt handler will run to handle extra interrupts. > > Then, we may need mask the interrupt. > > Can you check it for test? > > You're right. When I have the controller reset bit set, I see one > interrupt coming in shortly after we write the reset bits, which has > status bits of 0x180. This has Response timeout (RTO) and Data CRC > error set. It sounds like some interrupt ocurring may be expected > since they say to clear RINTSTS as part of the procedure though. Yes, it needs to clear RINTSTS. While this interrupt occurs, interrupt handler is called and thus tasklet function is also called. Can we handle this unexpected interrupt properly? To prevent these calling, we may need interrupt mask before resetting. > > > > > >> > >> >> + mci_writel(host, RINTSTS, 0xFFFFFFFF); > >> >> + > >> >> + /* if using dma we wait for dma_req to clear */ > >> >> + if (host->use_dma) { > >> >> + unsigned long timeout = jiffies + msecs_to_jiffies(500); > >> >> + u32 status; > >> >> + do { > >> >> + status = mci_readl(host, STATUS); > >> >> + if (!(status & SDMMC_STATUS_DMA_REQ)) > >> >> + break; > >> >> + cpu_relax(); > >> > What did you intend here? > >> > If you intent busy-wait, how about using sleep instead? > >> > >> Yes it is a busy-wait. There is similar code in dw_mci_ctrl_reset, > >> where that function is polling without sleeps, so I was trying to > >> match that. The cpu_relax() is something I saw in other busy-waits in > >> the kernel, but I'm happy to take it out if you'd like. > > In case of ctrl_reset, waiting is during 2 clock. > > If this polling status is not long, I'm OK. > > > >> > >> >> + } while (time_before(jiffies, timeout)); > >> >> + > >> >> + if (status & SDMMC_STATUS_DMA_REQ) { > >> >> + dev_err(host->dev, > >> >> + "%s: Timeout waiting for dma_req to " > >> >> + "clear during reset", __func__); > >> >> + return false; > >> >> + } > >> >> + > >> >> + /* when using DMA next we reset the fifo again */ > >> >> + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > >> >> + } > >> >> + } else { > >> >> + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); > >> > If ciu_reset is cleared, clk update below is needed? > >> > >> I'm honestly not sure what happens if the reset bits don't clear. The > >> docs say controller_reset and dma_reset will auto clear after a number > >> of clocks, but fifo_reset will clear "after completion of the reset > >> operation" So in this particular error case I'm not sure if it's > >> possible to recover properly or not and might hang, so I thought it > >> best to just return the error immediately. > > Yes. > > But at least if ciu_reset is done successfully, it may need clock update sequence again. > > In addition, printing reset bit[2:0] will be helpful for debug information. > > The dw_mci_ctrl_reset() function would run this code if some of the > bits didn't clear: > > dev_err(host->dev, > "Timeout resetting block (ctrl reset %#x)\n", > ctrl & reset); > > Does that give you what you're looking for? Ah, it was there. Thanks, Seungwon Jeon > > > > > Thanks, > > Seungwon Jeon > > > >> > >> > Thanks, > >> > Seungwon Jeon > >> > > >> >> + return false; > >> >> + } > >> >> + > >> >> +#ifdef CONFIG_MMC_DW_IDMAC > >> >> + /* It is also recommended that we reset and reprogram idmac */ > >> >> + dw_mci_idmac_reset(host); > >> >> +#endif > >> >> + > >> >> + /* After a CTRL reset we need to have CIU set clock registers */ > >> >> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); > >> >> + > >> >> + return true; > >> >> } > >> >> > >> >> static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) > >> >> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h > >> >> index 6bf24ab..2505804 100644 > >> >> --- a/drivers/mmc/host/dw_mmc.h > >> >> +++ b/drivers/mmc/host/dw_mmc.h > >> >> @@ -129,6 +129,7 @@ > >> >> #define SDMMC_CMD_INDX(n) ((n) & 0x1F) > >> >> /* Status register defines */ > >> >> #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) > >> >> +#define SDMMC_STATUS_DMA_REQ BIT(31) > >> >> /* FIFOTH register defines */ > >> >> #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ > >> >> ((r) & 0xFFF) << 16 | \ > >> >> -- > >> >> 1.9.1.423.g4596e3a > >> >> > >> >> -- > >> >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > >> >> the body of a message to majordomo@vger.kernel.org > >> >> More majordomo info at http://vger.kernel.org/majordomo-info.html > >> > > >> -- > >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > >> the body of a message to majordomo@vger.kernel.org > >> More majordomo info at http://vger.kernel.org/majordomo-info.html > > > -- > To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCHv2] mmc: dw_mmc: change to use recommended reset procedure @ 2014-05-20 1:49 ` Seungwon Jeon 0 siblings, 0 replies; 75+ messages in thread From: Seungwon Jeon @ 2014-05-20 1:49 UTC (permalink / raw) To: linux-arm-kernel On Sat, May 17, 2014, Sonny Rao wrote: > On Tue, May 13, 2014 at 4:09 AM, Seungwon Jeon <tgih.jun@samsung.com> wrote: > > On Tuesday, May 13, Sonny Rao wrote: > >> On Mon, May 12, 2014 at 10:02 PM, Seungwon Jeon <tgih.jun@samsung.com> wrote: > >> > As I mentioned in previous version, you put all reset stuff in existing fifo_reset function. > >> > Although databook mentions ciu_reset case for SBE error, it's not obvious when ciu_reset is > needed > >> in other error cases. > >> > If you intend to add some robust error handing, it would be better to make another function. > >> > >> The document I have actually doesn't mention error cases, it describes > >> this procedure as "Controller/DMA/FIFO Reset Usage" so I believe it is > >> saying this is the correct procedure in all cases, and based on our > >> testing it seems to work. I understand the skepticism, as I shared it > >> initially when I saw this, but based on our experience, this is > >> correct and it doesn't need to live in a separate function. > > I agree this active error handling. > > But, existing fifo_reset function is focused on fifo reset purely. > > I think your change is close to error recovery and it seems overloaded to basic function. > > So, you suggest renaming function for new sequence. > > I think the documentation says it should always be done, not just in > error recovery. I can rename the function to dw_mci_reset rather than > dw_mci_fifo_reset. Is that what you mean? Or do you mean make a new > function that is only called in error cases? Both are okay. > > > And look into dw_mci_work_routine_card(). dw_mci_idmac_reset() is redundancy. > > I expect it can be cleaned. > > > > <Quot> > > /* Clear down the FIFO */ > > dw_mci_fifo_reset(host); > > #ifdef CONFIG_MMC_DW_IDMAC > > dw_mci_idmac_reset(host); > > #endif > > </Quot> > > > > Ok, I'll remove that extra reset, thanks for catching. > > >> > >> > Please check my comments below. > >> > > >> > On Tue, May 13, 2014, Sonny Rao wrote: > >> >> This patch changes the fifo reset code to follow the reset procedure > >> >> outlined in the documentation of Synopsys Mobile storage host databook > >> >> 7.2.13. > > Please remove this section number. > > No needed. It's old version. > > > > Ok > > >> >> > >> >> v2: Add Generic DMA support > >> >> per the documentation, move interrupt clear before wait > >> >> make the test for DMA host->use_dma rather than host->using_dma > >> >> add proper return values (although it appears no caller checks) > >> >> > >> >> Signed-off-by: Sonny Rao <sonnyrao@chromium.org> > >> >> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.com> > >> >> --- > >> >> drivers/mmc/host/dw_mmc.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++- > >> >> drivers/mmc/host/dw_mmc.h | 1 + > >> >> 2 files changed, 55 insertions(+), 1 deletion(-) > >> >> > >> >> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c > >> >> index 55cd110..aff57e1 100644 > >> >> --- a/drivers/mmc/host/dw_mmc.c > >> >> +++ b/drivers/mmc/host/dw_mmc.c > >> >> @@ -2325,6 +2325,7 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) > >> >> > >> >> static inline bool dw_mci_fifo_reset(struct dw_mci *host) > >> >> { > >> >> + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; > >> >> /* > >> >> * Reseting generates a block interrupt, hence setting > >> >> * the scatter-gather pointer to NULL. > >> >> @@ -2334,7 +2335,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) > >> >> host->sg = NULL; > >> >> } > >> >> > >> >> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > >> >> + /* > >> >> + * The recommended method for resetting is to always reset the > >> >> + * controller and the fifo, but differs slightly depending on the mode. > >> >> + * The Generic DMA mode (non IDMAC) also needs to reset DMA where IDMAC > >> >> + * mode resets IDMAC at the end. > >> >> + * > >> >> + */ > >> >> +#ifndef CONFIG_MMC_DW_IDMAC > >> > Is it added for generic DMA? > >> > IDMAC should be considered for dma_reseet as well. > >> > Please check databook. > >> > > >> > >> Yeah it's a little unclear. In the "7.2.13 Controller/DMA/FIFO Reset > >> Usage" part of the document they mention It is set for what they call > >> "generic" DMA, which I think is when there is an external DMA > >> controller, and the part below that it says for "DW-DMA/Non-DW-DMA" > >> that controller_reset and fifo_reset should be set. I believe this > >> "DW-DMA" case refers to what is called IDMAC. So, I think it's not > >> required for this case, but I admit I'm not sure why they also say > >> "Non-DW-DMA". If you know of a good way to differentiate the "Generic > >> DMA" case I can implement it. It wasn't clear to me if the driver > >> even supported this "generic" dma case, but it sounds like it might, > >> so I added this code. In practice, on the Exynos Systems we have, > >> which are using IDMAC, the reset procedure seems to work okay without > >> the dma_reset bit set, but I cannot test this "generic dma" case. > >> > >> The other places in the doc where I see them mention the dma_reset bit > >> are "7.2.21 Transmission and Reception with Internal DMAC (IDMAC)" > >> and the description of the CTRL register, and in "7.1 > >> Software/Hardware Restrictions" where they say it will terminate any > >> pending transfer. > > "DW-DMA" means Synopsys's DMA controller not IDMAC. > > SDMMC_CTRL_DMA_RESET can apply in all type DMA interface. > > So, do you think I should always set that bit if we're using DMA? Yes. Although you used it for general dma at first, IDMAC also needs it. > > > > >> > >> >> + if (host->use_dma) > >> >> + flags |= SDMMC_CTRL_DMA_RESET; > >> >> +#endif > >> >> + if (dw_mci_ctrl_reset(host, flags)) { > >> >> + /* > >> >> + * In all cases we clear the RAWINTS register to clear any > >> >> + * interrupts. > >> >> + */ > >> > I think interrupt masking is needed before reset because we will not handle it anymore. > >> > And Is there any reason to move interrupt clear here compared with previous version? > >> > >> Yeah I moved it to match the description in the document more closely. > >> The documents mentioned doing the interrupt clear after setting the > >> reset bits, and before waiting for the dma_req bit in the status > >> register to clear. We've been running it with the interrupt clear > >> below the loop, for a while, and I just tested it with the clear above > >> the wait to make sure it still works properly and I was able to pass > >> the tuning process with some errors, so I believe this works fine too, > >> and more closely matches the description in the doc that I have. > > When I tried ciu_reset, I found some unexpected interrupts occurred. > > It means that interrupt handler will run to handle extra interrupts. > > Then, we may need mask the interrupt. > > Can you check it for test? > > You're right. When I have the controller reset bit set, I see one > interrupt coming in shortly after we write the reset bits, which has > status bits of 0x180. This has Response timeout (RTO) and Data CRC > error set. It sounds like some interrupt ocurring may be expected > since they say to clear RINTSTS as part of the procedure though. Yes, it needs to clear RINTSTS. While this interrupt occurs, interrupt handler is called and thus tasklet function is also called. Can we handle this unexpected interrupt properly? To prevent these calling, we may need interrupt mask before resetting. > > > > > >> > >> >> + mci_writel(host, RINTSTS, 0xFFFFFFFF); > >> >> + > >> >> + /* if using dma we wait for dma_req to clear */ > >> >> + if (host->use_dma) { > >> >> + unsigned long timeout = jiffies + msecs_to_jiffies(500); > >> >> + u32 status; > >> >> + do { > >> >> + status = mci_readl(host, STATUS); > >> >> + if (!(status & SDMMC_STATUS_DMA_REQ)) > >> >> + break; > >> >> + cpu_relax(); > >> > What did you intend here? > >> > If you intent busy-wait, how about using sleep instead? > >> > >> Yes it is a busy-wait. There is similar code in dw_mci_ctrl_reset, > >> where that function is polling without sleeps, so I was trying to > >> match that. The cpu_relax() is something I saw in other busy-waits in > >> the kernel, but I'm happy to take it out if you'd like. > > In case of ctrl_reset, waiting is during 2 clock. > > If this polling status is not long, I'm OK. > > > >> > >> >> + } while (time_before(jiffies, timeout)); > >> >> + > >> >> + if (status & SDMMC_STATUS_DMA_REQ) { > >> >> + dev_err(host->dev, > >> >> + "%s: Timeout waiting for dma_req to " > >> >> + "clear during reset", __func__); > >> >> + return false; > >> >> + } > >> >> + > >> >> + /* when using DMA next we reset the fifo again */ > >> >> + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > >> >> + } > >> >> + } else { > >> >> + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); > >> > If ciu_reset is cleared, clk update below is needed? > >> > >> I'm honestly not sure what happens if the reset bits don't clear. The > >> docs say controller_reset and dma_reset will auto clear after a number > >> of clocks, but fifo_reset will clear "after completion of the reset > >> operation" So in this particular error case I'm not sure if it's > >> possible to recover properly or not and might hang, so I thought it > >> best to just return the error immediately. > > Yes. > > But at least if ciu_reset is done successfully, it may need clock update sequence again. > > In addition, printing reset bit[2:0] will be helpful for debug information. > > The dw_mci_ctrl_reset() function would run this code if some of the > bits didn't clear: > > dev_err(host->dev, > "Timeout resetting block (ctrl reset %#x)\n", > ctrl & reset); > > Does that give you what you're looking for? Ah, it was there. Thanks, Seungwon Jeon > > > > > Thanks, > > Seungwon Jeon > > > >> > >> > Thanks, > >> > Seungwon Jeon > >> > > >> >> + return false; > >> >> + } > >> >> + > >> >> +#ifdef CONFIG_MMC_DW_IDMAC > >> >> + /* It is also recommended that we reset and reprogram idmac */ > >> >> + dw_mci_idmac_reset(host); > >> >> +#endif > >> >> + > >> >> + /* After a CTRL reset we need to have CIU set clock registers */ > >> >> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); > >> >> + > >> >> + return true; > >> >> } > >> >> > >> >> static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) > >> >> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h > >> >> index 6bf24ab..2505804 100644 > >> >> --- a/drivers/mmc/host/dw_mmc.h > >> >> +++ b/drivers/mmc/host/dw_mmc.h > >> >> @@ -129,6 +129,7 @@ > >> >> #define SDMMC_CMD_INDX(n) ((n) & 0x1F) > >> >> /* Status register defines */ > >> >> #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) > >> >> +#define SDMMC_STATUS_DMA_REQ BIT(31) > >> >> /* FIFOTH register defines */ > >> >> #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ > >> >> ((r) & 0xFFF) << 16 | \ > >> >> -- > >> >> 1.9.1.423.g4596e3a > >> >> > >> >> -- > >> >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > >> >> the body of a message to majordomo at vger.kernel.org > >> >> More majordomo info at http://vger.kernel.org/majordomo-info.html > >> > > >> -- > >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > >> the body of a message to majordomo at vger.kernel.org > >> More majordomo info at http://vger.kernel.org/majordomo-info.html > > > -- > To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > the body of a message to majordomo at vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCHv2] mmc: dw_mmc: change to use recommended reset procedure 2014-05-20 1:49 ` Seungwon Jeon @ 2014-05-22 18:54 ` Sonny Rao -1 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-05-22 18:54 UTC (permalink / raw) To: Seungwon Jeon Cc: linux-mmc, Grant Grundler, linux-samsung-soc, linux-arm-kernel, Jaehoon Chung, Chris Ball, Kukjin Kim, sunil joshi, Tomasz Figa, Douglas Anderson, Yuvaraj Kumar C D On Mon, May 19, 2014 at 6:49 PM, Seungwon Jeon <tgih.jun@samsung.com> wrote: > On Sat, May 17, 2014, Sonny Rao wrote: >> On Tue, May 13, 2014 at 4:09 AM, Seungwon Jeon <tgih.jun@samsung.com> wrote: >> > On Tuesday, May 13, Sonny Rao wrote: >> >> On Mon, May 12, 2014 at 10:02 PM, Seungwon Jeon <tgih.jun@samsung.com> wrote: >> >> > As I mentioned in previous version, you put all reset stuff in existing fifo_reset function. >> >> > Although databook mentions ciu_reset case for SBE error, it's not obvious when ciu_reset is >> needed >> >> in other error cases. >> >> > If you intend to add some robust error handing, it would be better to make another function. >> >> >> >> The document I have actually doesn't mention error cases, it describes >> >> this procedure as "Controller/DMA/FIFO Reset Usage" so I believe it is >> >> saying this is the correct procedure in all cases, and based on our >> >> testing it seems to work. I understand the skepticism, as I shared it >> >> initially when I saw this, but based on our experience, this is >> >> correct and it doesn't need to live in a separate function. >> > I agree this active error handling. >> > But, existing fifo_reset function is focused on fifo reset purely. >> > I think your change is close to error recovery and it seems overloaded to basic function. >> > So, you suggest renaming function for new sequence. >> >> I think the documentation says it should always be done, not just in >> error recovery. I can rename the function to dw_mci_reset rather than >> dw_mci_fifo_reset. Is that what you mean? Or do you mean make a new >> function that is only called in error cases? > Both are okay. > Ok >> >> > And look into dw_mci_work_routine_card(). dw_mci_idmac_reset() is redundancy. >> > I expect it can be cleaned. >> > >> > <Quot> >> > /* Clear down the FIFO */ >> > dw_mci_fifo_reset(host); >> > #ifdef CONFIG_MMC_DW_IDMAC >> > dw_mci_idmac_reset(host); >> > #endif >> > </Quot> >> > >> >> Ok, I'll remove that extra reset, thanks for catching. >> >> >> >> >> > Please check my comments below. >> >> > >> >> > On Tue, May 13, 2014, Sonny Rao wrote: >> >> >> This patch changes the fifo reset code to follow the reset procedure >> >> >> outlined in the documentation of Synopsys Mobile storage host databook >> >> >> 7.2.13. >> > Please remove this section number. >> > No needed. It's old version. >> > >> >> Ok >> >> >> >> >> >> >> v2: Add Generic DMA support >> >> >> per the documentation, move interrupt clear before wait >> >> >> make the test for DMA host->use_dma rather than host->using_dma >> >> >> add proper return values (although it appears no caller checks) >> >> >> >> >> >> Signed-off-by: Sonny Rao <sonnyrao@chromium.org> >> >> >> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.com> >> >> >> --- >> >> >> drivers/mmc/host/dw_mmc.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++- >> >> >> drivers/mmc/host/dw_mmc.h | 1 + >> >> >> 2 files changed, 55 insertions(+), 1 deletion(-) >> >> >> >> >> >> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c >> >> >> index 55cd110..aff57e1 100644 >> >> >> --- a/drivers/mmc/host/dw_mmc.c >> >> >> +++ b/drivers/mmc/host/dw_mmc.c >> >> >> @@ -2325,6 +2325,7 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) >> >> >> >> >> >> static inline bool dw_mci_fifo_reset(struct dw_mci *host) >> >> >> { >> >> >> + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; >> >> >> /* >> >> >> * Reseting generates a block interrupt, hence setting >> >> >> * the scatter-gather pointer to NULL. >> >> >> @@ -2334,7 +2335,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) >> >> >> host->sg = NULL; >> >> >> } >> >> >> >> >> >> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >> >> >> + /* >> >> >> + * The recommended method for resetting is to always reset the >> >> >> + * controller and the fifo, but differs slightly depending on the mode. >> >> >> + * The Generic DMA mode (non IDMAC) also needs to reset DMA where IDMAC >> >> >> + * mode resets IDMAC at the end. >> >> >> + * >> >> >> + */ >> >> >> +#ifndef CONFIG_MMC_DW_IDMAC >> >> > Is it added for generic DMA? >> >> > IDMAC should be considered for dma_reseet as well. >> >> > Please check databook. >> >> > >> >> >> >> Yeah it's a little unclear. In the "7.2.13 Controller/DMA/FIFO Reset >> >> Usage" part of the document they mention It is set for what they call >> >> "generic" DMA, which I think is when there is an external DMA >> >> controller, and the part below that it says for "DW-DMA/Non-DW-DMA" >> >> that controller_reset and fifo_reset should be set. I believe this >> >> "DW-DMA" case refers to what is called IDMAC. So, I think it's not >> >> required for this case, but I admit I'm not sure why they also say >> >> "Non-DW-DMA". If you know of a good way to differentiate the "Generic >> >> DMA" case I can implement it. It wasn't clear to me if the driver >> >> even supported this "generic" dma case, but it sounds like it might, >> >> so I added this code. In practice, on the Exynos Systems we have, >> >> which are using IDMAC, the reset procedure seems to work okay without >> >> the dma_reset bit set, but I cannot test this "generic dma" case. >> >> >> >> The other places in the doc where I see them mention the dma_reset bit >> >> are "7.2.21 Transmission and Reception with Internal DMAC (IDMAC)" >> >> and the description of the CTRL register, and in "7.1 >> >> Software/Hardware Restrictions" where they say it will terminate any >> >> pending transfer. >> > "DW-DMA" means Synopsys's DMA controller not IDMAC. >> > SDMMC_CTRL_DMA_RESET can apply in all type DMA interface. >> >> So, do you think I should always set that bit if we're using DMA? > Yes. Although you used it for general dma at first, IDMAC also needs it. > Ok, I will change that. >> >> > >> >> >> >> >> + if (host->use_dma) >> >> >> + flags |= SDMMC_CTRL_DMA_RESET; >> >> >> +#endif >> >> >> + if (dw_mci_ctrl_reset(host, flags)) { >> >> >> + /* >> >> >> + * In all cases we clear the RAWINTS register to clear any >> >> >> + * interrupts. >> >> >> + */ >> >> > I think interrupt masking is needed before reset because we will not handle it anymore. >> >> > And Is there any reason to move interrupt clear here compared with previous version? >> >> >> >> Yeah I moved it to match the description in the document more closely. >> >> The documents mentioned doing the interrupt clear after setting the >> >> reset bits, and before waiting for the dma_req bit in the status >> >> register to clear. We've been running it with the interrupt clear >> >> below the loop, for a while, and I just tested it with the clear above >> >> the wait to make sure it still works properly and I was able to pass >> >> the tuning process with some errors, so I believe this works fine too, >> >> and more closely matches the description in the doc that I have. >> > When I tried ciu_reset, I found some unexpected interrupts occurred. >> > It means that interrupt handler will run to handle extra interrupts. >> > Then, we may need mask the interrupt. >> > Can you check it for test? >> >> You're right. When I have the controller reset bit set, I see one >> interrupt coming in shortly after we write the reset bits, which has >> status bits of 0x180. This has Response timeout (RTO) and Data CRC >> error set. It sounds like some interrupt ocurring may be expected >> since they say to clear RINTSTS as part of the procedure though. > Yes, it needs to clear RINTSTS. > While this interrupt occurs, interrupt handler is called and thus tasklet function is also called. > Can we handle this unexpected interrupt properly? > To prevent these calling, we may need interrupt mask before resetting. > Ok, I traced what actually happens for me in this case, and it turns out for tuning that the extra Data CRC interrupt doesn't matter (it looks like the RTO bit I mentioned before isn't always there). This is because we're doing the fifo and controller reset from within the tasklet, which holds host->lock, it does clear RINTSTS, and also eventually calls dw_mci_request_end() which ends by setting host->state to STATE_IDLE. The tasklet then wakes up again immediately but sees the host->state as STATE_IDLE and exits. We could mask the Data CRC interrupt before doing the controller reset, if you'd like. I'll post an updated patch with the changes so far, thanks. >> >> >> > >> >> >> >> >> + mci_writel(host, RINTSTS, 0xFFFFFFFF); >> >> >> + >> >> >> + /* if using dma we wait for dma_req to clear */ >> >> >> + if (host->use_dma) { >> >> >> + unsigned long timeout = jiffies + msecs_to_jiffies(500); >> >> >> + u32 status; >> >> >> + do { >> >> >> + status = mci_readl(host, STATUS); >> >> >> + if (!(status & SDMMC_STATUS_DMA_REQ)) >> >> >> + break; >> >> >> + cpu_relax(); >> >> > What did you intend here? >> >> > If you intent busy-wait, how about using sleep instead? >> >> >> >> Yes it is a busy-wait. There is similar code in dw_mci_ctrl_reset, >> >> where that function is polling without sleeps, so I was trying to >> >> match that. The cpu_relax() is something I saw in other busy-waits in >> >> the kernel, but I'm happy to take it out if you'd like. >> > In case of ctrl_reset, waiting is during 2 clock. >> > If this polling status is not long, I'm OK. >> > >> >> >> >> >> + } while (time_before(jiffies, timeout)); >> >> >> + >> >> >> + if (status & SDMMC_STATUS_DMA_REQ) { >> >> >> + dev_err(host->dev, >> >> >> + "%s: Timeout waiting for dma_req to " >> >> >> + "clear during reset", __func__); >> >> >> + return false; >> >> >> + } >> >> >> + >> >> >> + /* when using DMA next we reset the fifo again */ >> >> >> + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >> >> >> + } >> >> >> + } else { >> >> >> + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); >> >> > If ciu_reset is cleared, clk update below is needed? >> >> >> >> I'm honestly not sure what happens if the reset bits don't clear. The >> >> docs say controller_reset and dma_reset will auto clear after a number >> >> of clocks, but fifo_reset will clear "after completion of the reset >> >> operation" So in this particular error case I'm not sure if it's >> >> possible to recover properly or not and might hang, so I thought it >> >> best to just return the error immediately. >> > Yes. >> > But at least if ciu_reset is done successfully, it may need clock update sequence again. >> > In addition, printing reset bit[2:0] will be helpful for debug information. >> >> The dw_mci_ctrl_reset() function would run this code if some of the >> bits didn't clear: >> >> dev_err(host->dev, >> "Timeout resetting block (ctrl reset %#x)\n", >> ctrl & reset); >> >> Does that give you what you're looking for? > Ah, it was there. > > Thanks, > Seungwon Jeon > >> >> > >> > Thanks, >> > Seungwon Jeon >> > >> >> >> >> > Thanks, >> >> > Seungwon Jeon >> >> > >> >> >> + return false; >> >> >> + } >> >> >> + >> >> >> +#ifdef CONFIG_MMC_DW_IDMAC >> >> >> + /* It is also recommended that we reset and reprogram idmac */ >> >> >> + dw_mci_idmac_reset(host); >> >> >> +#endif >> >> >> + >> >> >> + /* After a CTRL reset we need to have CIU set clock registers */ >> >> >> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); >> >> >> + >> >> >> + return true; >> >> >> } >> >> >> >> >> >> static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) >> >> >> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h >> >> >> index 6bf24ab..2505804 100644 >> >> >> --- a/drivers/mmc/host/dw_mmc.h >> >> >> +++ b/drivers/mmc/host/dw_mmc.h >> >> >> @@ -129,6 +129,7 @@ >> >> >> #define SDMMC_CMD_INDX(n) ((n) & 0x1F) >> >> >> /* Status register defines */ >> >> >> #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) >> >> >> +#define SDMMC_STATUS_DMA_REQ BIT(31) >> >> >> /* FIFOTH register defines */ >> >> >> #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ >> >> >> ((r) & 0xFFF) << 16 | \ >> >> >> -- >> >> >> 1.9.1.423.g4596e3a >> >> >> >> >> >> -- >> >> >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >> >> >> the body of a message to majordomo@vger.kernel.org >> >> >> More majordomo info at http://vger.kernel.org/majordomo-info.html >> >> > >> >> -- >> >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >> >> the body of a message to majordomo@vger.kernel.org >> >> More majordomo info at http://vger.kernel.org/majordomo-info.html >> > >> -- >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >> the body of a message to majordomo@vger.kernel.org >> More majordomo info at http://vger.kernel.org/majordomo-info.html > ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCHv2] mmc: dw_mmc: change to use recommended reset procedure @ 2014-05-22 18:54 ` Sonny Rao 0 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-05-22 18:54 UTC (permalink / raw) To: linux-arm-kernel On Mon, May 19, 2014 at 6:49 PM, Seungwon Jeon <tgih.jun@samsung.com> wrote: > On Sat, May 17, 2014, Sonny Rao wrote: >> On Tue, May 13, 2014 at 4:09 AM, Seungwon Jeon <tgih.jun@samsung.com> wrote: >> > On Tuesday, May 13, Sonny Rao wrote: >> >> On Mon, May 12, 2014 at 10:02 PM, Seungwon Jeon <tgih.jun@samsung.com> wrote: >> >> > As I mentioned in previous version, you put all reset stuff in existing fifo_reset function. >> >> > Although databook mentions ciu_reset case for SBE error, it's not obvious when ciu_reset is >> needed >> >> in other error cases. >> >> > If you intend to add some robust error handing, it would be better to make another function. >> >> >> >> The document I have actually doesn't mention error cases, it describes >> >> this procedure as "Controller/DMA/FIFO Reset Usage" so I believe it is >> >> saying this is the correct procedure in all cases, and based on our >> >> testing it seems to work. I understand the skepticism, as I shared it >> >> initially when I saw this, but based on our experience, this is >> >> correct and it doesn't need to live in a separate function. >> > I agree this active error handling. >> > But, existing fifo_reset function is focused on fifo reset purely. >> > I think your change is close to error recovery and it seems overloaded to basic function. >> > So, you suggest renaming function for new sequence. >> >> I think the documentation says it should always be done, not just in >> error recovery. I can rename the function to dw_mci_reset rather than >> dw_mci_fifo_reset. Is that what you mean? Or do you mean make a new >> function that is only called in error cases? > Both are okay. > Ok >> >> > And look into dw_mci_work_routine_card(). dw_mci_idmac_reset() is redundancy. >> > I expect it can be cleaned. >> > >> > <Quot> >> > /* Clear down the FIFO */ >> > dw_mci_fifo_reset(host); >> > #ifdef CONFIG_MMC_DW_IDMAC >> > dw_mci_idmac_reset(host); >> > #endif >> > </Quot> >> > >> >> Ok, I'll remove that extra reset, thanks for catching. >> >> >> >> >> > Please check my comments below. >> >> > >> >> > On Tue, May 13, 2014, Sonny Rao wrote: >> >> >> This patch changes the fifo reset code to follow the reset procedure >> >> >> outlined in the documentation of Synopsys Mobile storage host databook >> >> >> 7.2.13. >> > Please remove this section number. >> > No needed. It's old version. >> > >> >> Ok >> >> >> >> >> >> >> v2: Add Generic DMA support >> >> >> per the documentation, move interrupt clear before wait >> >> >> make the test for DMA host->use_dma rather than host->using_dma >> >> >> add proper return values (although it appears no caller checks) >> >> >> >> >> >> Signed-off-by: Sonny Rao <sonnyrao@chromium.org> >> >> >> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.com> >> >> >> --- >> >> >> drivers/mmc/host/dw_mmc.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++- >> >> >> drivers/mmc/host/dw_mmc.h | 1 + >> >> >> 2 files changed, 55 insertions(+), 1 deletion(-) >> >> >> >> >> >> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c >> >> >> index 55cd110..aff57e1 100644 >> >> >> --- a/drivers/mmc/host/dw_mmc.c >> >> >> +++ b/drivers/mmc/host/dw_mmc.c >> >> >> @@ -2325,6 +2325,7 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) >> >> >> >> >> >> static inline bool dw_mci_fifo_reset(struct dw_mci *host) >> >> >> { >> >> >> + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; >> >> >> /* >> >> >> * Reseting generates a block interrupt, hence setting >> >> >> * the scatter-gather pointer to NULL. >> >> >> @@ -2334,7 +2335,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) >> >> >> host->sg = NULL; >> >> >> } >> >> >> >> >> >> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >> >> >> + /* >> >> >> + * The recommended method for resetting is to always reset the >> >> >> + * controller and the fifo, but differs slightly depending on the mode. >> >> >> + * The Generic DMA mode (non IDMAC) also needs to reset DMA where IDMAC >> >> >> + * mode resets IDMAC at the end. >> >> >> + * >> >> >> + */ >> >> >> +#ifndef CONFIG_MMC_DW_IDMAC >> >> > Is it added for generic DMA? >> >> > IDMAC should be considered for dma_reseet as well. >> >> > Please check databook. >> >> > >> >> >> >> Yeah it's a little unclear. In the "7.2.13 Controller/DMA/FIFO Reset >> >> Usage" part of the document they mention It is set for what they call >> >> "generic" DMA, which I think is when there is an external DMA >> >> controller, and the part below that it says for "DW-DMA/Non-DW-DMA" >> >> that controller_reset and fifo_reset should be set. I believe this >> >> "DW-DMA" case refers to what is called IDMAC. So, I think it's not >> >> required for this case, but I admit I'm not sure why they also say >> >> "Non-DW-DMA". If you know of a good way to differentiate the "Generic >> >> DMA" case I can implement it. It wasn't clear to me if the driver >> >> even supported this "generic" dma case, but it sounds like it might, >> >> so I added this code. In practice, on the Exynos Systems we have, >> >> which are using IDMAC, the reset procedure seems to work okay without >> >> the dma_reset bit set, but I cannot test this "generic dma" case. >> >> >> >> The other places in the doc where I see them mention the dma_reset bit >> >> are "7.2.21 Transmission and Reception with Internal DMAC (IDMAC)" >> >> and the description of the CTRL register, and in "7.1 >> >> Software/Hardware Restrictions" where they say it will terminate any >> >> pending transfer. >> > "DW-DMA" means Synopsys's DMA controller not IDMAC. >> > SDMMC_CTRL_DMA_RESET can apply in all type DMA interface. >> >> So, do you think I should always set that bit if we're using DMA? > Yes. Although you used it for general dma at first, IDMAC also needs it. > Ok, I will change that. >> >> > >> >> >> >> >> + if (host->use_dma) >> >> >> + flags |= SDMMC_CTRL_DMA_RESET; >> >> >> +#endif >> >> >> + if (dw_mci_ctrl_reset(host, flags)) { >> >> >> + /* >> >> >> + * In all cases we clear the RAWINTS register to clear any >> >> >> + * interrupts. >> >> >> + */ >> >> > I think interrupt masking is needed before reset because we will not handle it anymore. >> >> > And Is there any reason to move interrupt clear here compared with previous version? >> >> >> >> Yeah I moved it to match the description in the document more closely. >> >> The documents mentioned doing the interrupt clear after setting the >> >> reset bits, and before waiting for the dma_req bit in the status >> >> register to clear. We've been running it with the interrupt clear >> >> below the loop, for a while, and I just tested it with the clear above >> >> the wait to make sure it still works properly and I was able to pass >> >> the tuning process with some errors, so I believe this works fine too, >> >> and more closely matches the description in the doc that I have. >> > When I tried ciu_reset, I found some unexpected interrupts occurred. >> > It means that interrupt handler will run to handle extra interrupts. >> > Then, we may need mask the interrupt. >> > Can you check it for test? >> >> You're right. When I have the controller reset bit set, I see one >> interrupt coming in shortly after we write the reset bits, which has >> status bits of 0x180. This has Response timeout (RTO) and Data CRC >> error set. It sounds like some interrupt ocurring may be expected >> since they say to clear RINTSTS as part of the procedure though. > Yes, it needs to clear RINTSTS. > While this interrupt occurs, interrupt handler is called and thus tasklet function is also called. > Can we handle this unexpected interrupt properly? > To prevent these calling, we may need interrupt mask before resetting. > Ok, I traced what actually happens for me in this case, and it turns out for tuning that the extra Data CRC interrupt doesn't matter (it looks like the RTO bit I mentioned before isn't always there). This is because we're doing the fifo and controller reset from within the tasklet, which holds host->lock, it does clear RINTSTS, and also eventually calls dw_mci_request_end() which ends by setting host->state to STATE_IDLE. The tasklet then wakes up again immediately but sees the host->state as STATE_IDLE and exits. We could mask the Data CRC interrupt before doing the controller reset, if you'd like. I'll post an updated patch with the changes so far, thanks. >> >> >> > >> >> >> >> >> + mci_writel(host, RINTSTS, 0xFFFFFFFF); >> >> >> + >> >> >> + /* if using dma we wait for dma_req to clear */ >> >> >> + if (host->use_dma) { >> >> >> + unsigned long timeout = jiffies + msecs_to_jiffies(500); >> >> >> + u32 status; >> >> >> + do { >> >> >> + status = mci_readl(host, STATUS); >> >> >> + if (!(status & SDMMC_STATUS_DMA_REQ)) >> >> >> + break; >> >> >> + cpu_relax(); >> >> > What did you intend here? >> >> > If you intent busy-wait, how about using sleep instead? >> >> >> >> Yes it is a busy-wait. There is similar code in dw_mci_ctrl_reset, >> >> where that function is polling without sleeps, so I was trying to >> >> match that. The cpu_relax() is something I saw in other busy-waits in >> >> the kernel, but I'm happy to take it out if you'd like. >> > In case of ctrl_reset, waiting is during 2 clock. >> > If this polling status is not long, I'm OK. >> > >> >> >> >> >> + } while (time_before(jiffies, timeout)); >> >> >> + >> >> >> + if (status & SDMMC_STATUS_DMA_REQ) { >> >> >> + dev_err(host->dev, >> >> >> + "%s: Timeout waiting for dma_req to " >> >> >> + "clear during reset", __func__); >> >> >> + return false; >> >> >> + } >> >> >> + >> >> >> + /* when using DMA next we reset the fifo again */ >> >> >> + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >> >> >> + } >> >> >> + } else { >> >> >> + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); >> >> > If ciu_reset is cleared, clk update below is needed? >> >> >> >> I'm honestly not sure what happens if the reset bits don't clear. The >> >> docs say controller_reset and dma_reset will auto clear after a number >> >> of clocks, but fifo_reset will clear "after completion of the reset >> >> operation" So in this particular error case I'm not sure if it's >> >> possible to recover properly or not and might hang, so I thought it >> >> best to just return the error immediately. >> > Yes. >> > But at least if ciu_reset is done successfully, it may need clock update sequence again. >> > In addition, printing reset bit[2:0] will be helpful for debug information. >> >> The dw_mci_ctrl_reset() function would run this code if some of the >> bits didn't clear: >> >> dev_err(host->dev, >> "Timeout resetting block (ctrl reset %#x)\n", >> ctrl & reset); >> >> Does that give you what you're looking for? > Ah, it was there. > > Thanks, > Seungwon Jeon > >> >> > >> > Thanks, >> > Seungwon Jeon >> > >> >> >> >> > Thanks, >> >> > Seungwon Jeon >> >> > >> >> >> + return false; >> >> >> + } >> >> >> + >> >> >> +#ifdef CONFIG_MMC_DW_IDMAC >> >> >> + /* It is also recommended that we reset and reprogram idmac */ >> >> >> + dw_mci_idmac_reset(host); >> >> >> +#endif >> >> >> + >> >> >> + /* After a CTRL reset we need to have CIU set clock registers */ >> >> >> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); >> >> >> + >> >> >> + return true; >> >> >> } >> >> >> >> >> >> static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) >> >> >> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h >> >> >> index 6bf24ab..2505804 100644 >> >> >> --- a/drivers/mmc/host/dw_mmc.h >> >> >> +++ b/drivers/mmc/host/dw_mmc.h >> >> >> @@ -129,6 +129,7 @@ >> >> >> #define SDMMC_CMD_INDX(n) ((n) & 0x1F) >> >> >> /* Status register defines */ >> >> >> #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) >> >> >> +#define SDMMC_STATUS_DMA_REQ BIT(31) >> >> >> /* FIFOTH register defines */ >> >> >> #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ >> >> >> ((r) & 0xFFF) << 16 | \ >> >> >> -- >> >> >> 1.9.1.423.g4596e3a >> >> >> >> >> >> -- >> >> >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >> >> >> the body of a message to majordomo at vger.kernel.org >> >> >> More majordomo info at http://vger.kernel.org/majordomo-info.html >> >> > >> >> -- >> >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >> >> the body of a message to majordomo at vger.kernel.org >> >> More majordomo info at http://vger.kernel.org/majordomo-info.html >> > >> -- >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >> the body of a message to majordomo at vger.kernel.org >> More majordomo info at http://vger.kernel.org/majordomo-info.html > ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCH] mmc: dw_mmc: change to use recommended reset procedure 2014-05-22 18:54 ` Sonny Rao @ 2014-05-29 0:35 ` Sonny Rao -1 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-05-29 0:35 UTC (permalink / raw) To: linux-mmc Cc: grundler, linux-samsung-soc, linux-arm-kernel, jh80.chung, cjb, tgih.jun, kgene.kim, joshi, t.figa, dianders, Yuvaraj Kumar C D, Sonny Rao 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> --- v2: Add Generic DMA support per the documentation, move interrupt clear before wait make the test for DMA host->use_dma rather than host->using_dma add proper return values (although it appears no caller checks) v3: rename fifo reset function, and change callers use this combined reset function in dw_mci_resume() just one caller left (probe), so get rid of dw_mci_ctrl_all_reset() use DMA reset bit for all systems which use DMA remove extra IDMAC reset in dw_mci_work_routine_card() do CIU clock update in error path, if CIU reset cleared drivers/mmc/host/dw_mmc.c | 85 +++++++++++++++++++++++++++++++++++------------ drivers/mmc/host/dw_mmc.h | 1 + 2 files changed, 64 insertions(+), 22 deletions(-) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 55cd110..988492c 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -111,8 +111,7 @@ static const u8 tuning_blk_pattern_8bit[] = { 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, }; -static inline bool dw_mci_fifo_reset(struct dw_mci *host); -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host); +static inline bool dw_mci_reset(struct dw_mci *host); #if defined(CONFIG_DEBUG_FS) static int dw_mci_req_show(struct seq_file *s, void *v) @@ -1254,7 +1253,7 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) * After an error, there may be data lingering * in the FIFO */ - dw_mci_fifo_reset(host); + dw_mci_reset(host); } else { data->bytes_xfered = data->blocks * data->blksz; data->error = 0; @@ -1371,7 +1370,7 @@ static void dw_mci_tasklet_func(unsigned long priv) /* CMD error in data command */ if (mrq->cmd->error && mrq->data) - dw_mci_fifo_reset(host); + dw_mci_reset(host); host->cmd = NULL; host->data = NULL; @@ -1982,14 +1981,9 @@ static void dw_mci_work_routine_card(struct work_struct *work) } /* Power down slot */ - if (present == 0) { + if (present == 0) /* Clear down the FIFO */ - dw_mci_fifo_reset(host); -#ifdef CONFIG_MMC_DW_IDMAC - dw_mci_idmac_reset(host); -#endif - - } + dw_mci_reset(host); spin_unlock_bh(&host->lock); @@ -2323,8 +2317,11 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) return false; } -static inline bool dw_mci_fifo_reset(struct dw_mci *host) +static inline bool dw_mci_reset(struct dw_mci *host) { + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; + bool ret = false; + /* * Reseting generates a block interrupt, hence setting * the scatter-gather pointer to NULL. @@ -2334,15 +2331,57 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) host->sg = NULL; } - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); -} + if (host->use_dma) + flags |= SDMMC_CTRL_DMA_RESET; -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) -{ - return dw_mci_ctrl_reset(host, - SDMMC_CTRL_FIFO_RESET | - SDMMC_CTRL_RESET | - SDMMC_CTRL_DMA_RESET); + if (dw_mci_ctrl_reset(host, flags)) { + /* + * In all cases we clear the RAWINTS register to clear any + * interrupts. + */ + mci_writel(host, RINTSTS, 0xFFFFFFFF); + + /* if using dma we wait for dma_req to clear */ + if (host->use_dma) { + unsigned long timeout = jiffies + msecs_to_jiffies(500); + u32 status; + do { + status = mci_readl(host, STATUS); + if (!(status & SDMMC_STATUS_DMA_REQ)) + break; + cpu_relax(); + } while (time_before(jiffies, timeout)); + + if (status & SDMMC_STATUS_DMA_REQ) { + dev_err(host->dev, + "%s: Timeout waiting for dma_req to " + "clear during reset", __func__); + goto ciu_out; + } + + /* when using DMA next we reset the fifo again */ + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) + goto ciu_out; + } + } else { + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); + + /* if the controller reset bit did clear, then set clock regs */ + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) + goto ciu_out; + } + + if (IS_ENABLED(CONFIG_MMC_DW_IDMAC)) + /* It is also recommended that we reset and reprogram idmac */ + dw_mci_idmac_reset(host); + + ret = true; + +ciu_out: + /* After a CTRL reset we need to have CIU set clock registers */ + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); + + return ret; } #ifdef CONFIG_OF @@ -2432,6 +2471,7 @@ int dw_mci_probe(struct dw_mci *host) const struct dw_mci_drv_data *drv_data = host->drv_data; int width, i, ret = 0; u32 fifo_size; + u32 flags; int init_slots = 0; if (!host->pdata) { @@ -2555,7 +2595,8 @@ int dw_mci_probe(struct dw_mci *host) } /* Reset all blocks */ - if (!dw_mci_ctrl_all_reset(host)) + flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET; + if (!dw_mci_ctrl_reset(host, flags)) return -ENODEV; host->dma_ops = host->pdata->dma_ops; @@ -2744,7 +2785,7 @@ int dw_mci_resume(struct dw_mci *host) } } - if (!dw_mci_ctrl_all_reset(host)) { + if (!dw_mci_reset(host)) { ret = -ENODEV; return ret; } diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 6bf24ab..2505804 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -129,6 +129,7 @@ #define SDMMC_CMD_INDX(n) ((n) & 0x1F) /* Status register defines */ #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) +#define SDMMC_STATUS_DMA_REQ BIT(31) /* FIFOTH register defines */ #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ ((r) & 0xFFF) << 16 | \ -- 1.8.3.2 ^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH] mmc: dw_mmc: change to use recommended reset procedure @ 2014-05-29 0:35 ` Sonny Rao 0 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-05-29 0:35 UTC (permalink / raw) To: linux-arm-kernel 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> --- v2: Add Generic DMA support per the documentation, move interrupt clear before wait make the test for DMA host->use_dma rather than host->using_dma add proper return values (although it appears no caller checks) v3: rename fifo reset function, and change callers use this combined reset function in dw_mci_resume() just one caller left (probe), so get rid of dw_mci_ctrl_all_reset() use DMA reset bit for all systems which use DMA remove extra IDMAC reset in dw_mci_work_routine_card() do CIU clock update in error path, if CIU reset cleared drivers/mmc/host/dw_mmc.c | 85 +++++++++++++++++++++++++++++++++++------------ drivers/mmc/host/dw_mmc.h | 1 + 2 files changed, 64 insertions(+), 22 deletions(-) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 55cd110..988492c 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -111,8 +111,7 @@ static const u8 tuning_blk_pattern_8bit[] = { 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, }; -static inline bool dw_mci_fifo_reset(struct dw_mci *host); -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host); +static inline bool dw_mci_reset(struct dw_mci *host); #if defined(CONFIG_DEBUG_FS) static int dw_mci_req_show(struct seq_file *s, void *v) @@ -1254,7 +1253,7 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) * After an error, there may be data lingering * in the FIFO */ - dw_mci_fifo_reset(host); + dw_mci_reset(host); } else { data->bytes_xfered = data->blocks * data->blksz; data->error = 0; @@ -1371,7 +1370,7 @@ static void dw_mci_tasklet_func(unsigned long priv) /* CMD error in data command */ if (mrq->cmd->error && mrq->data) - dw_mci_fifo_reset(host); + dw_mci_reset(host); host->cmd = NULL; host->data = NULL; @@ -1982,14 +1981,9 @@ static void dw_mci_work_routine_card(struct work_struct *work) } /* Power down slot */ - if (present == 0) { + if (present == 0) /* Clear down the FIFO */ - dw_mci_fifo_reset(host); -#ifdef CONFIG_MMC_DW_IDMAC - dw_mci_idmac_reset(host); -#endif - - } + dw_mci_reset(host); spin_unlock_bh(&host->lock); @@ -2323,8 +2317,11 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) return false; } -static inline bool dw_mci_fifo_reset(struct dw_mci *host) +static inline bool dw_mci_reset(struct dw_mci *host) { + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; + bool ret = false; + /* * Reseting generates a block interrupt, hence setting * the scatter-gather pointer to NULL. @@ -2334,15 +2331,57 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) host->sg = NULL; } - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); -} + if (host->use_dma) + flags |= SDMMC_CTRL_DMA_RESET; -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) -{ - return dw_mci_ctrl_reset(host, - SDMMC_CTRL_FIFO_RESET | - SDMMC_CTRL_RESET | - SDMMC_CTRL_DMA_RESET); + if (dw_mci_ctrl_reset(host, flags)) { + /* + * In all cases we clear the RAWINTS register to clear any + * interrupts. + */ + mci_writel(host, RINTSTS, 0xFFFFFFFF); + + /* if using dma we wait for dma_req to clear */ + if (host->use_dma) { + unsigned long timeout = jiffies + msecs_to_jiffies(500); + u32 status; + do { + status = mci_readl(host, STATUS); + if (!(status & SDMMC_STATUS_DMA_REQ)) + break; + cpu_relax(); + } while (time_before(jiffies, timeout)); + + if (status & SDMMC_STATUS_DMA_REQ) { + dev_err(host->dev, + "%s: Timeout waiting for dma_req to " + "clear during reset", __func__); + goto ciu_out; + } + + /* when using DMA next we reset the fifo again */ + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) + goto ciu_out; + } + } else { + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); + + /* if the controller reset bit did clear, then set clock regs */ + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) + goto ciu_out; + } + + if (IS_ENABLED(CONFIG_MMC_DW_IDMAC)) + /* It is also recommended that we reset and reprogram idmac */ + dw_mci_idmac_reset(host); + + ret = true; + +ciu_out: + /* After a CTRL reset we need to have CIU set clock registers */ + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); + + return ret; } #ifdef CONFIG_OF @@ -2432,6 +2471,7 @@ int dw_mci_probe(struct dw_mci *host) const struct dw_mci_drv_data *drv_data = host->drv_data; int width, i, ret = 0; u32 fifo_size; + u32 flags; int init_slots = 0; if (!host->pdata) { @@ -2555,7 +2595,8 @@ int dw_mci_probe(struct dw_mci *host) } /* Reset all blocks */ - if (!dw_mci_ctrl_all_reset(host)) + flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET; + if (!dw_mci_ctrl_reset(host, flags)) return -ENODEV; host->dma_ops = host->pdata->dma_ops; @@ -2744,7 +2785,7 @@ int dw_mci_resume(struct dw_mci *host) } } - if (!dw_mci_ctrl_all_reset(host)) { + if (!dw_mci_reset(host)) { ret = -ENODEV; return ret; } diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 6bf24ab..2505804 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -129,6 +129,7 @@ #define SDMMC_CMD_INDX(n) ((n) & 0x1F) /* Status register defines */ #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) +#define SDMMC_STATUS_DMA_REQ BIT(31) /* FIFOTH register defines */ #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ ((r) & 0xFFF) << 16 | \ -- 1.8.3.2 ^ permalink raw reply related [flat|nested] 75+ messages in thread
* Re: [PATCH] mmc: dw_mmc: change to use recommended reset procedure 2014-05-29 0:35 ` Sonny Rao @ 2014-05-29 5:17 ` Jaehoon Chung -1 siblings, 0 replies; 75+ messages in thread From: Jaehoon Chung @ 2014-05-29 5:17 UTC (permalink / raw) To: Sonny Rao, linux-mmc Cc: grundler, linux-samsung-soc, linux-arm-kernel, cjb, tgih.jun, kgene.kim, joshi, t.figa, dianders, Yuvaraj Kumar C D Hi, Sonny. On 05/29/2014 09:35 AM, Sonny Rao wrote: > 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> > --- > v2: Add Generic DMA support > per the documentation, move interrupt clear before wait > make the test for DMA host->use_dma rather than host->using_dma > add proper return values (although it appears no caller checks) > v3: rename fifo reset function, and change callers > use this combined reset function in dw_mci_resume() > just one caller left (probe), so get rid of dw_mci_ctrl_all_reset() > use DMA reset bit for all systems which use DMA > remove extra IDMAC reset in dw_mci_work_routine_card() > do CIU clock update in error path, if CIU reset cleared > > drivers/mmc/host/dw_mmc.c | 85 +++++++++++++++++++++++++++++++++++------------ > drivers/mmc/host/dw_mmc.h | 1 + > 2 files changed, 64 insertions(+), 22 deletions(-) > > diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c > index 55cd110..988492c 100644 > --- a/drivers/mmc/host/dw_mmc.c > +++ b/drivers/mmc/host/dw_mmc.c > @@ -111,8 +111,7 @@ static const u8 tuning_blk_pattern_8bit[] = { > 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, > }; > > -static inline bool dw_mci_fifo_reset(struct dw_mci *host); > -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host); > +static inline bool dw_mci_reset(struct dw_mci *host); > > #if defined(CONFIG_DEBUG_FS) > static int dw_mci_req_show(struct seq_file *s, void *v) > @@ -1254,7 +1253,7 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) > * After an error, there may be data lingering > * in the FIFO > */ > - dw_mci_fifo_reset(host); > + dw_mci_reset(host); > } else { > data->bytes_xfered = data->blocks * data->blksz; > data->error = 0; > @@ -1371,7 +1370,7 @@ static void dw_mci_tasklet_func(unsigned long priv) > > /* CMD error in data command */ > if (mrq->cmd->error && mrq->data) > - dw_mci_fifo_reset(host); > + dw_mci_reset(host); > > host->cmd = NULL; > host->data = NULL; > @@ -1982,14 +1981,9 @@ static void dw_mci_work_routine_card(struct work_struct *work) > } > > /* Power down slot */ > - if (present == 0) { > + if (present == 0) > /* Clear down the FIFO */ Didn't Need to change the Comment? > - dw_mci_fifo_reset(host); > -#ifdef CONFIG_MMC_DW_IDMAC > - dw_mci_idmac_reset(host); > -#endif > - > - } > + dw_mci_reset(host); > > spin_unlock_bh(&host->lock); > > @@ -2323,8 +2317,11 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) > return false; > } > > -static inline bool dw_mci_fifo_reset(struct dw_mci *host) > +static inline bool dw_mci_reset(struct dw_mci *host) > { > + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; > + bool ret = false; > + > /* > * Reseting generates a block interrupt, hence setting > * the scatter-gather pointer to NULL. > @@ -2334,15 +2331,57 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) > host->sg = NULL; > } > > - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > -} > + if (host->use_dma) > + flags |= SDMMC_CTRL_DMA_RESET; > > -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) > -{ > - return dw_mci_ctrl_reset(host, > - SDMMC_CTRL_FIFO_RESET | > - SDMMC_CTRL_RESET | > - SDMMC_CTRL_DMA_RESET); > + if (dw_mci_ctrl_reset(host, flags)) { > + /* > + * In all cases we clear the RAWINTS register to clear any > + * interrupts. > + */ > + mci_writel(host, RINTSTS, 0xFFFFFFFF); > + > + /* if using dma we wait for dma_req to clear */ > + if (host->use_dma) { > + unsigned long timeout = jiffies + msecs_to_jiffies(500); > + u32 status; > + do { > + status = mci_readl(host, STATUS); > + if (!(status & SDMMC_STATUS_DMA_REQ)) > + break; > + cpu_relax(); > + } while (time_before(jiffies, timeout)); > + > + if (status & SDMMC_STATUS_DMA_REQ) { > + dev_err(host->dev, > + "%s: Timeout waiting for dma_req to " > + "clear during reset", __func__); > + goto ciu_out; > + } > + > + /* when using DMA next we reset the fifo again */ > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) > + goto ciu_out; > + } > + } else { > + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); > + > + /* if the controller reset bit did clear, then set clock regs */ I have some confusion at this point. you added the above error message "Reset bits didn't clear". But this comment is "if the controller reset bit did clear..". I think that dev_err message would be better to locate into "if (!(mci_read(host, CTRL) & ...)". > + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) > + goto ciu_out; > + } > + > + if (IS_ENABLED(CONFIG_MMC_DW_IDMAC)) > + /* It is also recommended that we reset and reprogram idmac */ > + dw_mci_idmac_reset(host); > + > + ret = true; > + > +ciu_out: > + /* After a CTRL reset we need to have CIU set clock registers */ > + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); > + > + return ret; > } > > #ifdef CONFIG_OF > @@ -2432,6 +2471,7 @@ int dw_mci_probe(struct dw_mci *host) > const struct dw_mci_drv_data *drv_data = host->drv_data; > int width, i, ret = 0; > u32 fifo_size; > + u32 flags; > int init_slots = 0; > > if (!host->pdata) { > @@ -2555,7 +2595,8 @@ int dw_mci_probe(struct dw_mci *host) > } > > /* Reset all blocks */ > - if (!dw_mci_ctrl_all_reset(host)) > + flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET; how about adding the SDMMC_CTRL_ALL_RESET macro into header file? #define SDMMC_CTRL_ALL_RESET (.....) > + if (!dw_mci_ctrl_reset(host, flags)) > return -ENODEV; > > host->dma_ops = host->pdata->dma_ops; > @@ -2744,7 +2785,7 @@ int dw_mci_resume(struct dw_mci *host) > } > } > > - if (!dw_mci_ctrl_all_reset(host)) { > + if (!dw_mci_reset(host)) { > ret = -ENODEV; > return ret; > } > diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h > index 6bf24ab..2505804 100644 > --- a/drivers/mmc/host/dw_mmc.h > +++ b/drivers/mmc/host/dw_mmc.h > @@ -129,6 +129,7 @@ > #define SDMMC_CMD_INDX(n) ((n) & 0x1F) > /* Status register defines */ > #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) > +#define SDMMC_STATUS_DMA_REQ BIT(31) > /* FIFOTH register defines */ > #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ > ((r) & 0xFFF) << 16 | \ > ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCH] mmc: dw_mmc: change to use recommended reset procedure @ 2014-05-29 5:17 ` Jaehoon Chung 0 siblings, 0 replies; 75+ messages in thread From: Jaehoon Chung @ 2014-05-29 5:17 UTC (permalink / raw) To: linux-arm-kernel Hi, Sonny. On 05/29/2014 09:35 AM, Sonny Rao wrote: > 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> > --- > v2: Add Generic DMA support > per the documentation, move interrupt clear before wait > make the test for DMA host->use_dma rather than host->using_dma > add proper return values (although it appears no caller checks) > v3: rename fifo reset function, and change callers > use this combined reset function in dw_mci_resume() > just one caller left (probe), so get rid of dw_mci_ctrl_all_reset() > use DMA reset bit for all systems which use DMA > remove extra IDMAC reset in dw_mci_work_routine_card() > do CIU clock update in error path, if CIU reset cleared > > drivers/mmc/host/dw_mmc.c | 85 +++++++++++++++++++++++++++++++++++------------ > drivers/mmc/host/dw_mmc.h | 1 + > 2 files changed, 64 insertions(+), 22 deletions(-) > > diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c > index 55cd110..988492c 100644 > --- a/drivers/mmc/host/dw_mmc.c > +++ b/drivers/mmc/host/dw_mmc.c > @@ -111,8 +111,7 @@ static const u8 tuning_blk_pattern_8bit[] = { > 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, > }; > > -static inline bool dw_mci_fifo_reset(struct dw_mci *host); > -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host); > +static inline bool dw_mci_reset(struct dw_mci *host); > > #if defined(CONFIG_DEBUG_FS) > static int dw_mci_req_show(struct seq_file *s, void *v) > @@ -1254,7 +1253,7 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) > * After an error, there may be data lingering > * in the FIFO > */ > - dw_mci_fifo_reset(host); > + dw_mci_reset(host); > } else { > data->bytes_xfered = data->blocks * data->blksz; > data->error = 0; > @@ -1371,7 +1370,7 @@ static void dw_mci_tasklet_func(unsigned long priv) > > /* CMD error in data command */ > if (mrq->cmd->error && mrq->data) > - dw_mci_fifo_reset(host); > + dw_mci_reset(host); > > host->cmd = NULL; > host->data = NULL; > @@ -1982,14 +1981,9 @@ static void dw_mci_work_routine_card(struct work_struct *work) > } > > /* Power down slot */ > - if (present == 0) { > + if (present == 0) > /* Clear down the FIFO */ Didn't Need to change the Comment? > - dw_mci_fifo_reset(host); > -#ifdef CONFIG_MMC_DW_IDMAC > - dw_mci_idmac_reset(host); > -#endif > - > - } > + dw_mci_reset(host); > > spin_unlock_bh(&host->lock); > > @@ -2323,8 +2317,11 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) > return false; > } > > -static inline bool dw_mci_fifo_reset(struct dw_mci *host) > +static inline bool dw_mci_reset(struct dw_mci *host) > { > + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; > + bool ret = false; > + > /* > * Reseting generates a block interrupt, hence setting > * the scatter-gather pointer to NULL. > @@ -2334,15 +2331,57 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) > host->sg = NULL; > } > > - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > -} > + if (host->use_dma) > + flags |= SDMMC_CTRL_DMA_RESET; > > -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) > -{ > - return dw_mci_ctrl_reset(host, > - SDMMC_CTRL_FIFO_RESET | > - SDMMC_CTRL_RESET | > - SDMMC_CTRL_DMA_RESET); > + if (dw_mci_ctrl_reset(host, flags)) { > + /* > + * In all cases we clear the RAWINTS register to clear any > + * interrupts. > + */ > + mci_writel(host, RINTSTS, 0xFFFFFFFF); > + > + /* if using dma we wait for dma_req to clear */ > + if (host->use_dma) { > + unsigned long timeout = jiffies + msecs_to_jiffies(500); > + u32 status; > + do { > + status = mci_readl(host, STATUS); > + if (!(status & SDMMC_STATUS_DMA_REQ)) > + break; > + cpu_relax(); > + } while (time_before(jiffies, timeout)); > + > + if (status & SDMMC_STATUS_DMA_REQ) { > + dev_err(host->dev, > + "%s: Timeout waiting for dma_req to " > + "clear during reset", __func__); > + goto ciu_out; > + } > + > + /* when using DMA next we reset the fifo again */ > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) > + goto ciu_out; > + } > + } else { > + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); > + > + /* if the controller reset bit did clear, then set clock regs */ I have some confusion at this point. you added the above error message "Reset bits didn't clear". But this comment is "if the controller reset bit did clear..". I think that dev_err message would be better to locate into "if (!(mci_read(host, CTRL) & ...)". > + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) > + goto ciu_out; > + } > + > + if (IS_ENABLED(CONFIG_MMC_DW_IDMAC)) > + /* It is also recommended that we reset and reprogram idmac */ > + dw_mci_idmac_reset(host); > + > + ret = true; > + > +ciu_out: > + /* After a CTRL reset we need to have CIU set clock registers */ > + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); > + > + return ret; > } > > #ifdef CONFIG_OF > @@ -2432,6 +2471,7 @@ int dw_mci_probe(struct dw_mci *host) > const struct dw_mci_drv_data *drv_data = host->drv_data; > int width, i, ret = 0; > u32 fifo_size; > + u32 flags; > int init_slots = 0; > > if (!host->pdata) { > @@ -2555,7 +2595,8 @@ int dw_mci_probe(struct dw_mci *host) > } > > /* Reset all blocks */ > - if (!dw_mci_ctrl_all_reset(host)) > + flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET; how about adding the SDMMC_CTRL_ALL_RESET macro into header file? #define SDMMC_CTRL_ALL_RESET (.....) > + if (!dw_mci_ctrl_reset(host, flags)) > return -ENODEV; > > host->dma_ops = host->pdata->dma_ops; > @@ -2744,7 +2785,7 @@ int dw_mci_resume(struct dw_mci *host) > } > } > > - if (!dw_mci_ctrl_all_reset(host)) { > + if (!dw_mci_reset(host)) { > ret = -ENODEV; > return ret; > } > diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h > index 6bf24ab..2505804 100644 > --- a/drivers/mmc/host/dw_mmc.h > +++ b/drivers/mmc/host/dw_mmc.h > @@ -129,6 +129,7 @@ > #define SDMMC_CMD_INDX(n) ((n) & 0x1F) > /* Status register defines */ > #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) > +#define SDMMC_STATUS_DMA_REQ BIT(31) > /* FIFOTH register defines */ > #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ > ((r) & 0xFFF) << 16 | \ > ^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCH] mmc: dw_mmc: change to use recommended reset procedure 2014-05-29 5:17 ` Jaehoon Chung @ 2014-06-09 21:35 ` Sonny Rao -1 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-06-09 21:35 UTC (permalink / raw) To: Jaehoon Chung Cc: linux-mmc, Grant Grundler, linux-samsung-soc, linux-arm-kernel, Chris Ball, Seungwon Jeon, Kukjin Kim, sunil joshi, Tomasz Figa, Douglas Anderson, Yuvaraj Kumar C D On Wed, May 28, 2014 at 10:17 PM, Jaehoon Chung <jh80.chung@samsung.com> wrote: > Hi, Sonny. > > On 05/29/2014 09:35 AM, Sonny Rao wrote: >> 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> >> --- >> v2: Add Generic DMA support >> per the documentation, move interrupt clear before wait >> make the test for DMA host->use_dma rather than host->using_dma >> add proper return values (although it appears no caller checks) >> v3: rename fifo reset function, and change callers >> use this combined reset function in dw_mci_resume() >> just one caller left (probe), so get rid of dw_mci_ctrl_all_reset() >> use DMA reset bit for all systems which use DMA >> remove extra IDMAC reset in dw_mci_work_routine_card() >> do CIU clock update in error path, if CIU reset cleared >> >> drivers/mmc/host/dw_mmc.c | 85 +++++++++++++++++++++++++++++++++++------------ >> drivers/mmc/host/dw_mmc.h | 1 + >> 2 files changed, 64 insertions(+), 22 deletions(-) >> >> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c >> index 55cd110..988492c 100644 >> --- a/drivers/mmc/host/dw_mmc.c >> +++ b/drivers/mmc/host/dw_mmc.c >> @@ -111,8 +111,7 @@ static const u8 tuning_blk_pattern_8bit[] = { >> 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, >> }; >> >> -static inline bool dw_mci_fifo_reset(struct dw_mci *host); >> -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host); >> +static inline bool dw_mci_reset(struct dw_mci *host); >> >> #if defined(CONFIG_DEBUG_FS) >> static int dw_mci_req_show(struct seq_file *s, void *v) >> @@ -1254,7 +1253,7 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) >> * After an error, there may be data lingering >> * in the FIFO >> */ >> - dw_mci_fifo_reset(host); >> + dw_mci_reset(host); >> } else { >> data->bytes_xfered = data->blocks * data->blksz; >> data->error = 0; >> @@ -1371,7 +1370,7 @@ static void dw_mci_tasklet_func(unsigned long priv) >> >> /* CMD error in data command */ >> if (mrq->cmd->error && mrq->data) >> - dw_mci_fifo_reset(host); >> + dw_mci_reset(host); >> >> host->cmd = NULL; >> host->data = NULL; >> @@ -1982,14 +1981,9 @@ static void dw_mci_work_routine_card(struct work_struct *work) >> } >> >> /* Power down slot */ >> - if (present == 0) { >> + if (present == 0) >> /* Clear down the FIFO */ > Didn't Need to change the Comment? Well, it does still clear the fifo, but I can remove the comment since we are now doing more than that. >> - dw_mci_fifo_reset(host); >> -#ifdef CONFIG_MMC_DW_IDMAC >> - dw_mci_idmac_reset(host); >> -#endif >> - >> - } >> + dw_mci_reset(host); >> >> spin_unlock_bh(&host->lock); >> >> @@ -2323,8 +2317,11 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) >> return false; >> } >> >> -static inline bool dw_mci_fifo_reset(struct dw_mci *host) >> +static inline bool dw_mci_reset(struct dw_mci *host) >> { >> + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; >> + bool ret = false; >> + >> /* >> * Reseting generates a block interrupt, hence setting >> * the scatter-gather pointer to NULL. >> @@ -2334,15 +2331,57 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) >> host->sg = NULL; >> } >> >> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >> -} >> + if (host->use_dma) >> + flags |= SDMMC_CTRL_DMA_RESET; >> >> -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) >> -{ >> - return dw_mci_ctrl_reset(host, >> - SDMMC_CTRL_FIFO_RESET | >> - SDMMC_CTRL_RESET | >> - SDMMC_CTRL_DMA_RESET); >> + if (dw_mci_ctrl_reset(host, flags)) { >> + /* >> + * In all cases we clear the RAWINTS register to clear any >> + * interrupts. >> + */ >> + mci_writel(host, RINTSTS, 0xFFFFFFFF); >> + >> + /* if using dma we wait for dma_req to clear */ >> + if (host->use_dma) { >> + unsigned long timeout = jiffies + msecs_to_jiffies(500); >> + u32 status; >> + do { >> + status = mci_readl(host, STATUS); >> + if (!(status & SDMMC_STATUS_DMA_REQ)) >> + break; >> + cpu_relax(); >> + } while (time_before(jiffies, timeout)); >> + >> + if (status & SDMMC_STATUS_DMA_REQ) { >> + dev_err(host->dev, >> + "%s: Timeout waiting for dma_req to " >> + "clear during reset", __func__); >> + goto ciu_out; >> + } >> + >> + /* when using DMA next we reset the fifo again */ >> + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) >> + goto ciu_out; >> + } >> + } else { >> + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); >> + >> + /* if the controller reset bit did clear, then set clock regs */ > I have some confusion at this point. you added the above error message "Reset bits didn't clear". > But this comment is "if the controller reset bit did clear..". > > I think that dev_err message would be better to locate into "if (!(mci_read(host, CTRL) & ...)". > Ok, I'll move this error message inside the if block and make it more specific. >> + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) >> + goto ciu_out; >> + } >> + >> + if (IS_ENABLED(CONFIG_MMC_DW_IDMAC)) >> + /* It is also recommended that we reset and reprogram idmac */ >> + dw_mci_idmac_reset(host); >> + >> + ret = true; >> + >> +ciu_out: >> + /* After a CTRL reset we need to have CIU set clock registers */ >> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); >> + >> + return ret; >> } >> >> #ifdef CONFIG_OF >> @@ -2432,6 +2471,7 @@ int dw_mci_probe(struct dw_mci *host) >> const struct dw_mci_drv_data *drv_data = host->drv_data; >> int width, i, ret = 0; >> u32 fifo_size; >> + u32 flags; >> int init_slots = 0; >> >> if (!host->pdata) { >> @@ -2555,7 +2595,8 @@ int dw_mci_probe(struct dw_mci *host) >> } >> >> /* Reset all blocks */ >> - if (!dw_mci_ctrl_all_reset(host)) >> + flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET; > how about adding the SDMMC_CTRL_ALL_RESET macro into header file? > #define SDMMC_CTRL_ALL_RESET (.....) > ok I'll make a macro in dw_mmc.h for this. >> + if (!dw_mci_ctrl_reset(host, flags)) >> return -ENODEV; >> >> host->dma_ops = host->pdata->dma_ops; >> @@ -2744,7 +2785,7 @@ int dw_mci_resume(struct dw_mci *host) >> } >> } >> >> - if (!dw_mci_ctrl_all_reset(host)) { >> + if (!dw_mci_reset(host)) { >> ret = -ENODEV; >> return ret; >> } >> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h >> index 6bf24ab..2505804 100644 >> --- a/drivers/mmc/host/dw_mmc.h >> +++ b/drivers/mmc/host/dw_mmc.h >> @@ -129,6 +129,7 @@ >> #define SDMMC_CMD_INDX(n) ((n) & 0x1F) >> /* Status register defines */ >> #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) >> +#define SDMMC_STATUS_DMA_REQ BIT(31) >> /* FIFOTH register defines */ >> #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ >> ((r) & 0xFFF) << 16 | \ >> > ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCH] mmc: dw_mmc: change to use recommended reset procedure @ 2014-06-09 21:35 ` Sonny Rao 0 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-06-09 21:35 UTC (permalink / raw) To: linux-arm-kernel On Wed, May 28, 2014 at 10:17 PM, Jaehoon Chung <jh80.chung@samsung.com> wrote: > Hi, Sonny. > > On 05/29/2014 09:35 AM, Sonny Rao wrote: >> 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> >> --- >> v2: Add Generic DMA support >> per the documentation, move interrupt clear before wait >> make the test for DMA host->use_dma rather than host->using_dma >> add proper return values (although it appears no caller checks) >> v3: rename fifo reset function, and change callers >> use this combined reset function in dw_mci_resume() >> just one caller left (probe), so get rid of dw_mci_ctrl_all_reset() >> use DMA reset bit for all systems which use DMA >> remove extra IDMAC reset in dw_mci_work_routine_card() >> do CIU clock update in error path, if CIU reset cleared >> >> drivers/mmc/host/dw_mmc.c | 85 +++++++++++++++++++++++++++++++++++------------ >> drivers/mmc/host/dw_mmc.h | 1 + >> 2 files changed, 64 insertions(+), 22 deletions(-) >> >> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c >> index 55cd110..988492c 100644 >> --- a/drivers/mmc/host/dw_mmc.c >> +++ b/drivers/mmc/host/dw_mmc.c >> @@ -111,8 +111,7 @@ static const u8 tuning_blk_pattern_8bit[] = { >> 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, >> }; >> >> -static inline bool dw_mci_fifo_reset(struct dw_mci *host); >> -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host); >> +static inline bool dw_mci_reset(struct dw_mci *host); >> >> #if defined(CONFIG_DEBUG_FS) >> static int dw_mci_req_show(struct seq_file *s, void *v) >> @@ -1254,7 +1253,7 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) >> * After an error, there may be data lingering >> * in the FIFO >> */ >> - dw_mci_fifo_reset(host); >> + dw_mci_reset(host); >> } else { >> data->bytes_xfered = data->blocks * data->blksz; >> data->error = 0; >> @@ -1371,7 +1370,7 @@ static void dw_mci_tasklet_func(unsigned long priv) >> >> /* CMD error in data command */ >> if (mrq->cmd->error && mrq->data) >> - dw_mci_fifo_reset(host); >> + dw_mci_reset(host); >> >> host->cmd = NULL; >> host->data = NULL; >> @@ -1982,14 +1981,9 @@ static void dw_mci_work_routine_card(struct work_struct *work) >> } >> >> /* Power down slot */ >> - if (present == 0) { >> + if (present == 0) >> /* Clear down the FIFO */ > Didn't Need to change the Comment? Well, it does still clear the fifo, but I can remove the comment since we are now doing more than that. >> - dw_mci_fifo_reset(host); >> -#ifdef CONFIG_MMC_DW_IDMAC >> - dw_mci_idmac_reset(host); >> -#endif >> - >> - } >> + dw_mci_reset(host); >> >> spin_unlock_bh(&host->lock); >> >> @@ -2323,8 +2317,11 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) >> return false; >> } >> >> -static inline bool dw_mci_fifo_reset(struct dw_mci *host) >> +static inline bool dw_mci_reset(struct dw_mci *host) >> { >> + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; >> + bool ret = false; >> + >> /* >> * Reseting generates a block interrupt, hence setting >> * the scatter-gather pointer to NULL. >> @@ -2334,15 +2331,57 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) >> host->sg = NULL; >> } >> >> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >> -} >> + if (host->use_dma) >> + flags |= SDMMC_CTRL_DMA_RESET; >> >> -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) >> -{ >> - return dw_mci_ctrl_reset(host, >> - SDMMC_CTRL_FIFO_RESET | >> - SDMMC_CTRL_RESET | >> - SDMMC_CTRL_DMA_RESET); >> + if (dw_mci_ctrl_reset(host, flags)) { >> + /* >> + * In all cases we clear the RAWINTS register to clear any >> + * interrupts. >> + */ >> + mci_writel(host, RINTSTS, 0xFFFFFFFF); >> + >> + /* if using dma we wait for dma_req to clear */ >> + if (host->use_dma) { >> + unsigned long timeout = jiffies + msecs_to_jiffies(500); >> + u32 status; >> + do { >> + status = mci_readl(host, STATUS); >> + if (!(status & SDMMC_STATUS_DMA_REQ)) >> + break; >> + cpu_relax(); >> + } while (time_before(jiffies, timeout)); >> + >> + if (status & SDMMC_STATUS_DMA_REQ) { >> + dev_err(host->dev, >> + "%s: Timeout waiting for dma_req to " >> + "clear during reset", __func__); >> + goto ciu_out; >> + } >> + >> + /* when using DMA next we reset the fifo again */ >> + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) >> + goto ciu_out; >> + } >> + } else { >> + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); >> + >> + /* if the controller reset bit did clear, then set clock regs */ > I have some confusion at this point. you added the above error message "Reset bits didn't clear". > But this comment is "if the controller reset bit did clear..". > > I think that dev_err message would be better to locate into "if (!(mci_read(host, CTRL) & ...)". > Ok, I'll move this error message inside the if block and make it more specific. >> + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) >> + goto ciu_out; >> + } >> + >> + if (IS_ENABLED(CONFIG_MMC_DW_IDMAC)) >> + /* It is also recommended that we reset and reprogram idmac */ >> + dw_mci_idmac_reset(host); >> + >> + ret = true; >> + >> +ciu_out: >> + /* After a CTRL reset we need to have CIU set clock registers */ >> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); >> + >> + return ret; >> } >> >> #ifdef CONFIG_OF >> @@ -2432,6 +2471,7 @@ int dw_mci_probe(struct dw_mci *host) >> const struct dw_mci_drv_data *drv_data = host->drv_data; >> int width, i, ret = 0; >> u32 fifo_size; >> + u32 flags; >> int init_slots = 0; >> >> if (!host->pdata) { >> @@ -2555,7 +2595,8 @@ int dw_mci_probe(struct dw_mci *host) >> } >> >> /* Reset all blocks */ >> - if (!dw_mci_ctrl_all_reset(host)) >> + flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET; > how about adding the SDMMC_CTRL_ALL_RESET macro into header file? > #define SDMMC_CTRL_ALL_RESET (.....) > ok I'll make a macro in dw_mmc.h for this. >> + if (!dw_mci_ctrl_reset(host, flags)) >> return -ENODEV; >> >> host->dma_ops = host->pdata->dma_ops; >> @@ -2744,7 +2785,7 @@ int dw_mci_resume(struct dw_mci *host) >> } >> } >> >> - if (!dw_mci_ctrl_all_reset(host)) { >> + if (!dw_mci_reset(host)) { >> ret = -ENODEV; >> return ret; >> } >> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h >> index 6bf24ab..2505804 100644 >> --- a/drivers/mmc/host/dw_mmc.h >> +++ b/drivers/mmc/host/dw_mmc.h >> @@ -129,6 +129,7 @@ >> #define SDMMC_CMD_INDX(n) ((n) & 0x1F) >> /* Status register defines */ >> #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) >> +#define SDMMC_STATUS_DMA_REQ BIT(31) >> /* FIFOTH register defines */ >> #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ >> ((r) & 0xFFF) << 16 | \ >> > ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCH] mmc: dw_mmc: change to use recommended reset procedure 2014-06-09 21:35 ` Sonny Rao @ 2014-06-09 22:00 ` Sonny Rao -1 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-06-09 22:00 UTC (permalink / raw) To: linux-mmc Cc: grundler, linux-samsung-soc, linux-arm-kernel, jh80.chung, cjb, tgih.jun, kgene.kim, joshi, t.figa, dianders, Yuvaraj Kumar C D, Sonny Rao 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> --- v2: Add Generic DMA support per the documentation, move interrupt clear before wait make the test for DMA host->use_dma rather than host->using_dma add proper return values (although it appears no caller checks) v3: rename fifo reset function, and change callers use this combined reset function in dw_mci_resume() just one caller left (probe), so get rid of dw_mci_ctrl_all_reset() use DMA reset bit for all systems which use DMA remove extra IDMAC reset in dw_mci_work_routine_card() do CIU clock update in error path, if CIU reset cleared v4: remove comment about FIFO reset in dw_mci_work_routine_card() move down error message when control reset clears but others don't and clarify the error stating that we will still update clocks make flags for all reset bits a macro drivers/mmc/host/dw_mmc.c | 86 ++++++++++++++++++++++++++++++++++------------- drivers/mmc/host/dw_mmc.h | 5 +++ 2 files changed, 68 insertions(+), 23 deletions(-) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 55cd110..1d6d984 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -111,8 +111,7 @@ static const u8 tuning_blk_pattern_8bit[] = { 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, }; -static inline bool dw_mci_fifo_reset(struct dw_mci *host); -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host); +static inline bool dw_mci_reset(struct dw_mci *host); #if defined(CONFIG_DEBUG_FS) static int dw_mci_req_show(struct seq_file *s, void *v) @@ -1254,7 +1253,7 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) * After an error, there may be data lingering * in the FIFO */ - dw_mci_fifo_reset(host); + dw_mci_reset(host); } else { data->bytes_xfered = data->blocks * data->blksz; data->error = 0; @@ -1371,7 +1370,7 @@ static void dw_mci_tasklet_func(unsigned long priv) /* CMD error in data command */ if (mrq->cmd->error && mrq->data) - dw_mci_fifo_reset(host); + dw_mci_reset(host); host->cmd = NULL; host->data = NULL; @@ -1982,14 +1981,8 @@ static void dw_mci_work_routine_card(struct work_struct *work) } /* Power down slot */ - if (present == 0) { - /* Clear down the FIFO */ - dw_mci_fifo_reset(host); -#ifdef CONFIG_MMC_DW_IDMAC - dw_mci_idmac_reset(host); -#endif - - } + if (present == 0) + dw_mci_reset(host); spin_unlock_bh(&host->lock); @@ -2323,8 +2316,11 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) return false; } -static inline bool dw_mci_fifo_reset(struct dw_mci *host) +static inline bool dw_mci_reset(struct dw_mci *host) { + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; + bool ret = false; + /* * Reseting generates a block interrupt, hence setting * the scatter-gather pointer to NULL. @@ -2334,15 +2330,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) host->sg = NULL; } - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); -} + if (host->use_dma) + flags |= SDMMC_CTRL_DMA_RESET; -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) -{ - return dw_mci_ctrl_reset(host, - SDMMC_CTRL_FIFO_RESET | - SDMMC_CTRL_RESET | - SDMMC_CTRL_DMA_RESET); + if (dw_mci_ctrl_reset(host, flags)) { + /* + * In all cases we clear the RAWINTS register to clear any + * interrupts. + */ + mci_writel(host, RINTSTS, 0xFFFFFFFF); + + /* if using dma we wait for dma_req to clear */ + if (host->use_dma) { + unsigned long timeout = jiffies + msecs_to_jiffies(500); + u32 status; + do { + status = mci_readl(host, STATUS); + if (!(status & SDMMC_STATUS_DMA_REQ)) + break; + cpu_relax(); + } while (time_before(jiffies, timeout)); + + if (status & SDMMC_STATUS_DMA_REQ) { + dev_err(host->dev, + "%s: Timeout waiting for dma_req to " + "clear during reset", __func__); + goto ciu_out; + } + + /* when using DMA next we reset the fifo again */ + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) + goto ciu_out; + } + } else { + /* if the controller reset bit did clear, then set clock regs */ + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { + dev_err(host->dev, "%s: fifo/dma reset bits didn't " + "clear but ciu was reset, doing clock update.", + __func__); + goto ciu_out; + } + } + + if (IS_ENABLED(CONFIG_MMC_DW_IDMAC)) + /* It is also recommended that we reset and reprogram idmac */ + dw_mci_idmac_reset(host); + + ret = true; + +ciu_out: + /* After a CTRL reset we need to have CIU set clock registers */ + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); + + return ret; } #ifdef CONFIG_OF @@ -2555,7 +2595,7 @@ int dw_mci_probe(struct dw_mci *host) } /* Reset all blocks */ - if (!dw_mci_ctrl_all_reset(host)) + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) return -ENODEV; host->dma_ops = host->pdata->dma_ops; @@ -2744,7 +2784,7 @@ int dw_mci_resume(struct dw_mci *host) } } - if (!dw_mci_ctrl_all_reset(host)) { + if (!dw_mci_reset(host)) { ret = -ENODEV; return ret; } diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 6bf24ab..9ab8ccd 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -129,6 +129,7 @@ #define SDMMC_CMD_INDX(n) ((n) & 0x1F) /* Status register defines */ #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) +#define SDMMC_STATUS_DMA_REQ BIT(31) /* FIFOTH register defines */ #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ ((r) & 0xFFF) << 16 | \ @@ -150,6 +151,10 @@ /* Card read threshold */ #define SDMMC_SET_RD_THLD(v, x) (((v) & 0x1FFF) << 16 | (x)) +/* All ctrl reset bits */ +#define SDMMC_CTRL_ALL_RESET_FLAGS \ + (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET) + /* Register access macros */ #define mci_readl(dev, reg) \ __raw_readl((dev)->regs + SDMMC_##reg) -- 1.8.3.2 ^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH] mmc: dw_mmc: change to use recommended reset procedure @ 2014-06-09 22:00 ` Sonny Rao 0 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-06-09 22:00 UTC (permalink / raw) To: linux-arm-kernel 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> --- v2: Add Generic DMA support per the documentation, move interrupt clear before wait make the test for DMA host->use_dma rather than host->using_dma add proper return values (although it appears no caller checks) v3: rename fifo reset function, and change callers use this combined reset function in dw_mci_resume() just one caller left (probe), so get rid of dw_mci_ctrl_all_reset() use DMA reset bit for all systems which use DMA remove extra IDMAC reset in dw_mci_work_routine_card() do CIU clock update in error path, if CIU reset cleared v4: remove comment about FIFO reset in dw_mci_work_routine_card() move down error message when control reset clears but others don't and clarify the error stating that we will still update clocks make flags for all reset bits a macro drivers/mmc/host/dw_mmc.c | 86 ++++++++++++++++++++++++++++++++++------------- drivers/mmc/host/dw_mmc.h | 5 +++ 2 files changed, 68 insertions(+), 23 deletions(-) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 55cd110..1d6d984 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -111,8 +111,7 @@ static const u8 tuning_blk_pattern_8bit[] = { 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, }; -static inline bool dw_mci_fifo_reset(struct dw_mci *host); -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host); +static inline bool dw_mci_reset(struct dw_mci *host); #if defined(CONFIG_DEBUG_FS) static int dw_mci_req_show(struct seq_file *s, void *v) @@ -1254,7 +1253,7 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) * After an error, there may be data lingering * in the FIFO */ - dw_mci_fifo_reset(host); + dw_mci_reset(host); } else { data->bytes_xfered = data->blocks * data->blksz; data->error = 0; @@ -1371,7 +1370,7 @@ static void dw_mci_tasklet_func(unsigned long priv) /* CMD error in data command */ if (mrq->cmd->error && mrq->data) - dw_mci_fifo_reset(host); + dw_mci_reset(host); host->cmd = NULL; host->data = NULL; @@ -1982,14 +1981,8 @@ static void dw_mci_work_routine_card(struct work_struct *work) } /* Power down slot */ - if (present == 0) { - /* Clear down the FIFO */ - dw_mci_fifo_reset(host); -#ifdef CONFIG_MMC_DW_IDMAC - dw_mci_idmac_reset(host); -#endif - - } + if (present == 0) + dw_mci_reset(host); spin_unlock_bh(&host->lock); @@ -2323,8 +2316,11 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) return false; } -static inline bool dw_mci_fifo_reset(struct dw_mci *host) +static inline bool dw_mci_reset(struct dw_mci *host) { + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; + bool ret = false; + /* * Reseting generates a block interrupt, hence setting * the scatter-gather pointer to NULL. @@ -2334,15 +2330,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) host->sg = NULL; } - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); -} + if (host->use_dma) + flags |= SDMMC_CTRL_DMA_RESET; -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) -{ - return dw_mci_ctrl_reset(host, - SDMMC_CTRL_FIFO_RESET | - SDMMC_CTRL_RESET | - SDMMC_CTRL_DMA_RESET); + if (dw_mci_ctrl_reset(host, flags)) { + /* + * In all cases we clear the RAWINTS register to clear any + * interrupts. + */ + mci_writel(host, RINTSTS, 0xFFFFFFFF); + + /* if using dma we wait for dma_req to clear */ + if (host->use_dma) { + unsigned long timeout = jiffies + msecs_to_jiffies(500); + u32 status; + do { + status = mci_readl(host, STATUS); + if (!(status & SDMMC_STATUS_DMA_REQ)) + break; + cpu_relax(); + } while (time_before(jiffies, timeout)); + + if (status & SDMMC_STATUS_DMA_REQ) { + dev_err(host->dev, + "%s: Timeout waiting for dma_req to " + "clear during reset", __func__); + goto ciu_out; + } + + /* when using DMA next we reset the fifo again */ + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) + goto ciu_out; + } + } else { + /* if the controller reset bit did clear, then set clock regs */ + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { + dev_err(host->dev, "%s: fifo/dma reset bits didn't " + "clear but ciu was reset, doing clock update.", + __func__); + goto ciu_out; + } + } + + if (IS_ENABLED(CONFIG_MMC_DW_IDMAC)) + /* It is also recommended that we reset and reprogram idmac */ + dw_mci_idmac_reset(host); + + ret = true; + +ciu_out: + /* After a CTRL reset we need to have CIU set clock registers */ + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); + + return ret; } #ifdef CONFIG_OF @@ -2555,7 +2595,7 @@ int dw_mci_probe(struct dw_mci *host) } /* Reset all blocks */ - if (!dw_mci_ctrl_all_reset(host)) + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) return -ENODEV; host->dma_ops = host->pdata->dma_ops; @@ -2744,7 +2784,7 @@ int dw_mci_resume(struct dw_mci *host) } } - if (!dw_mci_ctrl_all_reset(host)) { + if (!dw_mci_reset(host)) { ret = -ENODEV; return ret; } diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 6bf24ab..9ab8ccd 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -129,6 +129,7 @@ #define SDMMC_CMD_INDX(n) ((n) & 0x1F) /* Status register defines */ #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) +#define SDMMC_STATUS_DMA_REQ BIT(31) /* FIFOTH register defines */ #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ ((r) & 0xFFF) << 16 | \ @@ -150,6 +151,10 @@ /* Card read threshold */ #define SDMMC_SET_RD_THLD(v, x) (((v) & 0x1FFF) << 16 | (x)) +/* All ctrl reset bits */ +#define SDMMC_CTRL_ALL_RESET_FLAGS \ + (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET) + /* Register access macros */ #define mci_readl(dev, reg) \ __raw_readl((dev)->regs + SDMMC_##reg) -- 1.8.3.2 ^ permalink raw reply related [flat|nested] 75+ messages in thread
* RE: [PATCH] mmc: dw_mmc: change to use recommended reset procedure 2014-06-09 22:00 ` Sonny Rao @ 2014-07-10 12:28 ` Seungwon Jeon -1 siblings, 0 replies; 75+ messages in thread From: Seungwon Jeon @ 2014-07-10 12:28 UTC (permalink / raw) To: 'Sonny Rao', linux-mmc Cc: grundler, linux-samsung-soc, linux-arm-kernel, jh80.chung, cjb, kgene.kim, joshi, t.figa, dianders, 'Yuvaraj Kumar C D' Hi Sonny, I have missed this patch. You finally choose to take extra interrupt handling. If it is not harm, it's fine. Please check one thing below. On Tue, June 10, 2014, Sonny Rao wrote: > 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> > --- > v2: Add Generic DMA support > per the documentation, move interrupt clear before wait > make the test for DMA host->use_dma rather than host->using_dma > add proper return values (although it appears no caller checks) > v3: rename fifo reset function, and change callers > use this combined reset function in dw_mci_resume() > just one caller left (probe), so get rid of dw_mci_ctrl_all_reset() > use DMA reset bit for all systems which use DMA > remove extra IDMAC reset in dw_mci_work_routine_card() > do CIU clock update in error path, if CIU reset cleared > v4: remove comment about FIFO reset in dw_mci_work_routine_card() > move down error message when control reset clears but others don't > and clarify the error stating that we will still update clocks > make flags for all reset bits a macro > > drivers/mmc/host/dw_mmc.c | 86 ++++++++++++++++++++++++++++++++++------------- > drivers/mmc/host/dw_mmc.h | 5 +++ > 2 files changed, 68 insertions(+), 23 deletions(-) > > diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c > index 55cd110..1d6d984 100644 > --- a/drivers/mmc/host/dw_mmc.c > +++ b/drivers/mmc/host/dw_mmc.c > @@ -111,8 +111,7 @@ static const u8 tuning_blk_pattern_8bit[] = { > 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, > }; > > -static inline bool dw_mci_fifo_reset(struct dw_mci *host); > -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host); > +static inline bool dw_mci_reset(struct dw_mci *host); > > #if defined(CONFIG_DEBUG_FS) > static int dw_mci_req_show(struct seq_file *s, void *v) > @@ -1254,7 +1253,7 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) > * After an error, there may be data lingering > * in the FIFO > */ > - dw_mci_fifo_reset(host); > + dw_mci_reset(host); > } else { > data->bytes_xfered = data->blocks * data->blksz; > data->error = 0; > @@ -1371,7 +1370,7 @@ static void dw_mci_tasklet_func(unsigned long priv) > > /* CMD error in data command */ > if (mrq->cmd->error && mrq->data) > - dw_mci_fifo_reset(host); > + dw_mci_reset(host); > > host->cmd = NULL; > host->data = NULL; > @@ -1982,14 +1981,8 @@ static void dw_mci_work_routine_card(struct work_struct *work) > } > > /* Power down slot */ > - if (present == 0) { > - /* Clear down the FIFO */ > - dw_mci_fifo_reset(host); > -#ifdef CONFIG_MMC_DW_IDMAC > - dw_mci_idmac_reset(host); > -#endif > - > - } > + if (present == 0) > + dw_mci_reset(host); > > spin_unlock_bh(&host->lock); > > @@ -2323,8 +2316,11 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) > return false; > } > > -static inline bool dw_mci_fifo_reset(struct dw_mci *host) > +static inline bool dw_mci_reset(struct dw_mci *host) > { > + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; > + bool ret = false; > + > /* > * Reseting generates a block interrupt, hence setting > * the scatter-gather pointer to NULL. > @@ -2334,15 +2330,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) > host->sg = NULL; > } > > - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > -} > + if (host->use_dma) > + flags |= SDMMC_CTRL_DMA_RESET; > > -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) > -{ > - return dw_mci_ctrl_reset(host, > - SDMMC_CTRL_FIFO_RESET | > - SDMMC_CTRL_RESET | > - SDMMC_CTRL_DMA_RESET); > + if (dw_mci_ctrl_reset(host, flags)) { > + /* > + * In all cases we clear the RAWINTS register to clear any > + * interrupts. > + */ > + mci_writel(host, RINTSTS, 0xFFFFFFFF); > + > + /* if using dma we wait for dma_req to clear */ > + if (host->use_dma) { > + unsigned long timeout = jiffies + msecs_to_jiffies(500); > + u32 status; > + do { > + status = mci_readl(host, STATUS); > + if (!(status & SDMMC_STATUS_DMA_REQ)) > + break; > + cpu_relax(); > + } while (time_before(jiffies, timeout)); > + > + if (status & SDMMC_STATUS_DMA_REQ) { > + dev_err(host->dev, > + "%s: Timeout waiting for dma_req to " > + "clear during reset", __func__); > + goto ciu_out; > + } > + > + /* when using DMA next we reset the fifo again */ > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) > + goto ciu_out; > + } > + } else { > + /* if the controller reset bit did clear, then set clock regs */ > + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { > + dev_err(host->dev, "%s: fifo/dma reset bits didn't " > + "clear but ciu was reset, doing clock update.", > + __func__); > + goto ciu_out; > + } > + } > + > + if (IS_ENABLED(CONFIG_MMC_DW_IDMAC)) > + /* It is also recommended that we reset and reprogram idmac */ > + dw_mci_idmac_reset(host); > + > + ret = true; > + > +ciu_out: > + /* After a CTRL reset we need to have CIU set clock registers */ > + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); > + > + return ret; > } > > #ifdef CONFIG_OF > @@ -2555,7 +2595,7 @@ int dw_mci_probe(struct dw_mci *host) > } > > /* Reset all blocks */ > - if (!dw_mci_ctrl_all_reset(host)) > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) > return -ENODEV; > > host->dma_ops = host->pdata->dma_ops; > @@ -2744,7 +2784,7 @@ int dw_mci_resume(struct dw_mci *host) > } > } > > - if (!dw_mci_ctrl_all_reset(host)) { > + if (!dw_mci_reset(host)) { Do you have any reason to use dw_mci_reset() unlike doing on probing? Thanks, Seungwon Jeon ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCH] mmc: dw_mmc: change to use recommended reset procedure @ 2014-07-10 12:28 ` Seungwon Jeon 0 siblings, 0 replies; 75+ messages in thread From: Seungwon Jeon @ 2014-07-10 12:28 UTC (permalink / raw) To: linux-arm-kernel Hi Sonny, I have missed this patch. You finally choose to take extra interrupt handling. If it is not harm, it's fine. Please check one thing below. On Tue, June 10, 2014, Sonny Rao wrote: > 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> > --- > v2: Add Generic DMA support > per the documentation, move interrupt clear before wait > make the test for DMA host->use_dma rather than host->using_dma > add proper return values (although it appears no caller checks) > v3: rename fifo reset function, and change callers > use this combined reset function in dw_mci_resume() > just one caller left (probe), so get rid of dw_mci_ctrl_all_reset() > use DMA reset bit for all systems which use DMA > remove extra IDMAC reset in dw_mci_work_routine_card() > do CIU clock update in error path, if CIU reset cleared > v4: remove comment about FIFO reset in dw_mci_work_routine_card() > move down error message when control reset clears but others don't > and clarify the error stating that we will still update clocks > make flags for all reset bits a macro > > drivers/mmc/host/dw_mmc.c | 86 ++++++++++++++++++++++++++++++++++------------- > drivers/mmc/host/dw_mmc.h | 5 +++ > 2 files changed, 68 insertions(+), 23 deletions(-) > > diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c > index 55cd110..1d6d984 100644 > --- a/drivers/mmc/host/dw_mmc.c > +++ b/drivers/mmc/host/dw_mmc.c > @@ -111,8 +111,7 @@ static const u8 tuning_blk_pattern_8bit[] = { > 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, > }; > > -static inline bool dw_mci_fifo_reset(struct dw_mci *host); > -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host); > +static inline bool dw_mci_reset(struct dw_mci *host); > > #if defined(CONFIG_DEBUG_FS) > static int dw_mci_req_show(struct seq_file *s, void *v) > @@ -1254,7 +1253,7 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) > * After an error, there may be data lingering > * in the FIFO > */ > - dw_mci_fifo_reset(host); > + dw_mci_reset(host); > } else { > data->bytes_xfered = data->blocks * data->blksz; > data->error = 0; > @@ -1371,7 +1370,7 @@ static void dw_mci_tasklet_func(unsigned long priv) > > /* CMD error in data command */ > if (mrq->cmd->error && mrq->data) > - dw_mci_fifo_reset(host); > + dw_mci_reset(host); > > host->cmd = NULL; > host->data = NULL; > @@ -1982,14 +1981,8 @@ static void dw_mci_work_routine_card(struct work_struct *work) > } > > /* Power down slot */ > - if (present == 0) { > - /* Clear down the FIFO */ > - dw_mci_fifo_reset(host); > -#ifdef CONFIG_MMC_DW_IDMAC > - dw_mci_idmac_reset(host); > -#endif > - > - } > + if (present == 0) > + dw_mci_reset(host); > > spin_unlock_bh(&host->lock); > > @@ -2323,8 +2316,11 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) > return false; > } > > -static inline bool dw_mci_fifo_reset(struct dw_mci *host) > +static inline bool dw_mci_reset(struct dw_mci *host) > { > + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; > + bool ret = false; > + > /* > * Reseting generates a block interrupt, hence setting > * the scatter-gather pointer to NULL. > @@ -2334,15 +2330,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) > host->sg = NULL; > } > > - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > -} > + if (host->use_dma) > + flags |= SDMMC_CTRL_DMA_RESET; > > -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) > -{ > - return dw_mci_ctrl_reset(host, > - SDMMC_CTRL_FIFO_RESET | > - SDMMC_CTRL_RESET | > - SDMMC_CTRL_DMA_RESET); > + if (dw_mci_ctrl_reset(host, flags)) { > + /* > + * In all cases we clear the RAWINTS register to clear any > + * interrupts. > + */ > + mci_writel(host, RINTSTS, 0xFFFFFFFF); > + > + /* if using dma we wait for dma_req to clear */ > + if (host->use_dma) { > + unsigned long timeout = jiffies + msecs_to_jiffies(500); > + u32 status; > + do { > + status = mci_readl(host, STATUS); > + if (!(status & SDMMC_STATUS_DMA_REQ)) > + break; > + cpu_relax(); > + } while (time_before(jiffies, timeout)); > + > + if (status & SDMMC_STATUS_DMA_REQ) { > + dev_err(host->dev, > + "%s: Timeout waiting for dma_req to " > + "clear during reset", __func__); > + goto ciu_out; > + } > + > + /* when using DMA next we reset the fifo again */ > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) > + goto ciu_out; > + } > + } else { > + /* if the controller reset bit did clear, then set clock regs */ > + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { > + dev_err(host->dev, "%s: fifo/dma reset bits didn't " > + "clear but ciu was reset, doing clock update.", > + __func__); > + goto ciu_out; > + } > + } > + > + if (IS_ENABLED(CONFIG_MMC_DW_IDMAC)) > + /* It is also recommended that we reset and reprogram idmac */ > + dw_mci_idmac_reset(host); > + > + ret = true; > + > +ciu_out: > + /* After a CTRL reset we need to have CIU set clock registers */ > + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); > + > + return ret; > } > > #ifdef CONFIG_OF > @@ -2555,7 +2595,7 @@ int dw_mci_probe(struct dw_mci *host) > } > > /* Reset all blocks */ > - if (!dw_mci_ctrl_all_reset(host)) > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) > return -ENODEV; > > host->dma_ops = host->pdata->dma_ops; > @@ -2744,7 +2784,7 @@ int dw_mci_resume(struct dw_mci *host) > } > } > > - if (!dw_mci_ctrl_all_reset(host)) { > + if (!dw_mci_reset(host)) { Do you have any reason to use dw_mci_reset() unlike doing on probing? Thanks, Seungwon Jeon ^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCH] mmc: dw_mmc: change to use recommended reset procedure 2014-07-10 12:28 ` Seungwon Jeon @ 2014-07-10 22:35 ` Sonny Rao -1 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-07-10 22:35 UTC (permalink / raw) To: Seungwon Jeon Cc: linux-mmc, Grant Grundler, linux-samsung-soc, linux-arm-kernel, Jaehoon Chung, Chris Ball, Kukjin Kim, sunil joshi, Tomasz Figa, Douglas Anderson, Yuvaraj Kumar C D On Thu, Jul 10, 2014 at 5:28 AM, Seungwon Jeon <tgih.jun@samsung.com> wrote: > Hi Sonny, > > I have missed this patch. > > You finally choose to take extra interrupt handling. > If it is not harm, it's fine. Hi, thanks for coming back to it. Based on my tracing, the interrupt seems to be okay and is just ignored. > > Please check one thing below. > > On Tue, June 10, 2014, Sonny Rao wrote: >> 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> >> --- >> v2: Add Generic DMA support >> per the documentation, move interrupt clear before wait >> make the test for DMA host->use_dma rather than host->using_dma >> add proper return values (although it appears no caller checks) >> v3: rename fifo reset function, and change callers >> use this combined reset function in dw_mci_resume() >> just one caller left (probe), so get rid of dw_mci_ctrl_all_reset() >> use DMA reset bit for all systems which use DMA >> remove extra IDMAC reset in dw_mci_work_routine_card() >> do CIU clock update in error path, if CIU reset cleared >> v4: remove comment about FIFO reset in dw_mci_work_routine_card() >> move down error message when control reset clears but others don't >> and clarify the error stating that we will still update clocks >> make flags for all reset bits a macro >> >> drivers/mmc/host/dw_mmc.c | 86 ++++++++++++++++++++++++++++++++++------------- >> drivers/mmc/host/dw_mmc.h | 5 +++ >> 2 files changed, 68 insertions(+), 23 deletions(-) >> >> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c >> index 55cd110..1d6d984 100644 >> --- a/drivers/mmc/host/dw_mmc.c >> +++ b/drivers/mmc/host/dw_mmc.c >> @@ -111,8 +111,7 @@ static const u8 tuning_blk_pattern_8bit[] = { >> 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, >> }; >> >> -static inline bool dw_mci_fifo_reset(struct dw_mci *host); >> -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host); >> +static inline bool dw_mci_reset(struct dw_mci *host); >> >> #if defined(CONFIG_DEBUG_FS) >> static int dw_mci_req_show(struct seq_file *s, void *v) >> @@ -1254,7 +1253,7 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) >> * After an error, there may be data lingering >> * in the FIFO >> */ >> - dw_mci_fifo_reset(host); >> + dw_mci_reset(host); >> } else { >> data->bytes_xfered = data->blocks * data->blksz; >> data->error = 0; >> @@ -1371,7 +1370,7 @@ static void dw_mci_tasklet_func(unsigned long priv) >> >> /* CMD error in data command */ >> if (mrq->cmd->error && mrq->data) >> - dw_mci_fifo_reset(host); >> + dw_mci_reset(host); >> >> host->cmd = NULL; >> host->data = NULL; >> @@ -1982,14 +1981,8 @@ static void dw_mci_work_routine_card(struct work_struct *work) >> } >> >> /* Power down slot */ >> - if (present == 0) { >> - /* Clear down the FIFO */ >> - dw_mci_fifo_reset(host); >> -#ifdef CONFIG_MMC_DW_IDMAC >> - dw_mci_idmac_reset(host); >> -#endif >> - >> - } >> + if (present == 0) >> + dw_mci_reset(host); >> >> spin_unlock_bh(&host->lock); >> >> @@ -2323,8 +2316,11 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) >> return false; >> } >> >> -static inline bool dw_mci_fifo_reset(struct dw_mci *host) >> +static inline bool dw_mci_reset(struct dw_mci *host) >> { >> + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; >> + bool ret = false; >> + >> /* >> * Reseting generates a block interrupt, hence setting >> * the scatter-gather pointer to NULL. >> @@ -2334,15 +2330,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) >> host->sg = NULL; >> } >> >> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >> -} >> + if (host->use_dma) >> + flags |= SDMMC_CTRL_DMA_RESET; >> >> -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) >> -{ >> - return dw_mci_ctrl_reset(host, >> - SDMMC_CTRL_FIFO_RESET | >> - SDMMC_CTRL_RESET | >> - SDMMC_CTRL_DMA_RESET); >> + if (dw_mci_ctrl_reset(host, flags)) { >> + /* >> + * In all cases we clear the RAWINTS register to clear any >> + * interrupts. >> + */ >> + mci_writel(host, RINTSTS, 0xFFFFFFFF); >> + >> + /* if using dma we wait for dma_req to clear */ >> + if (host->use_dma) { >> + unsigned long timeout = jiffies + msecs_to_jiffies(500); >> + u32 status; >> + do { >> + status = mci_readl(host, STATUS); >> + if (!(status & SDMMC_STATUS_DMA_REQ)) >> + break; >> + cpu_relax(); >> + } while (time_before(jiffies, timeout)); >> + >> + if (status & SDMMC_STATUS_DMA_REQ) { >> + dev_err(host->dev, >> + "%s: Timeout waiting for dma_req to " >> + "clear during reset", __func__); >> + goto ciu_out; >> + } >> + >> + /* when using DMA next we reset the fifo again */ >> + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) >> + goto ciu_out; >> + } >> + } else { >> + /* if the controller reset bit did clear, then set clock regs */ >> + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { >> + dev_err(host->dev, "%s: fifo/dma reset bits didn't " >> + "clear but ciu was reset, doing clock update.", >> + __func__); >> + goto ciu_out; >> + } >> + } >> + >> + if (IS_ENABLED(CONFIG_MMC_DW_IDMAC)) >> + /* It is also recommended that we reset and reprogram idmac */ >> + dw_mci_idmac_reset(host); >> + >> + ret = true; >> + >> +ciu_out: >> + /* After a CTRL reset we need to have CIU set clock registers */ >> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); >> + >> + return ret; >> } >> >> #ifdef CONFIG_OF >> @@ -2555,7 +2595,7 @@ int dw_mci_probe(struct dw_mci *host) >> } >> >> /* Reset all blocks */ >> - if (!dw_mci_ctrl_all_reset(host)) >> + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) >> return -ENODEV; >> >> host->dma_ops = host->pdata->dma_ops; >> @@ -2744,7 +2784,7 @@ int dw_mci_resume(struct dw_mci *host) >> } >> } >> >> - if (!dw_mci_ctrl_all_reset(host)) { >> + if (!dw_mci_reset(host)) { > Do you have any reason to use dw_mci_reset() unlike doing on probing? I really wanted to use dw_mci_reset() everwhere, including probe, because that would be simplest, where there is just one reset function always, but the host structure is not completely set up at probe time, so the code in dw_mci_reset() where we try to send a command to update clock fails, so that's why I had to just do a reset. > Thanks, > Seungwon Jeon > ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCH] mmc: dw_mmc: change to use recommended reset procedure @ 2014-07-10 22:35 ` Sonny Rao 0 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-07-10 22:35 UTC (permalink / raw) To: linux-arm-kernel On Thu, Jul 10, 2014 at 5:28 AM, Seungwon Jeon <tgih.jun@samsung.com> wrote: > Hi Sonny, > > I have missed this patch. > > You finally choose to take extra interrupt handling. > If it is not harm, it's fine. Hi, thanks for coming back to it. Based on my tracing, the interrupt seems to be okay and is just ignored. > > Please check one thing below. > > On Tue, June 10, 2014, Sonny Rao wrote: >> 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> >> --- >> v2: Add Generic DMA support >> per the documentation, move interrupt clear before wait >> make the test for DMA host->use_dma rather than host->using_dma >> add proper return values (although it appears no caller checks) >> v3: rename fifo reset function, and change callers >> use this combined reset function in dw_mci_resume() >> just one caller left (probe), so get rid of dw_mci_ctrl_all_reset() >> use DMA reset bit for all systems which use DMA >> remove extra IDMAC reset in dw_mci_work_routine_card() >> do CIU clock update in error path, if CIU reset cleared >> v4: remove comment about FIFO reset in dw_mci_work_routine_card() >> move down error message when control reset clears but others don't >> and clarify the error stating that we will still update clocks >> make flags for all reset bits a macro >> >> drivers/mmc/host/dw_mmc.c | 86 ++++++++++++++++++++++++++++++++++------------- >> drivers/mmc/host/dw_mmc.h | 5 +++ >> 2 files changed, 68 insertions(+), 23 deletions(-) >> >> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c >> index 55cd110..1d6d984 100644 >> --- a/drivers/mmc/host/dw_mmc.c >> +++ b/drivers/mmc/host/dw_mmc.c >> @@ -111,8 +111,7 @@ static const u8 tuning_blk_pattern_8bit[] = { >> 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, >> }; >> >> -static inline bool dw_mci_fifo_reset(struct dw_mci *host); >> -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host); >> +static inline bool dw_mci_reset(struct dw_mci *host); >> >> #if defined(CONFIG_DEBUG_FS) >> static int dw_mci_req_show(struct seq_file *s, void *v) >> @@ -1254,7 +1253,7 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) >> * After an error, there may be data lingering >> * in the FIFO >> */ >> - dw_mci_fifo_reset(host); >> + dw_mci_reset(host); >> } else { >> data->bytes_xfered = data->blocks * data->blksz; >> data->error = 0; >> @@ -1371,7 +1370,7 @@ static void dw_mci_tasklet_func(unsigned long priv) >> >> /* CMD error in data command */ >> if (mrq->cmd->error && mrq->data) >> - dw_mci_fifo_reset(host); >> + dw_mci_reset(host); >> >> host->cmd = NULL; >> host->data = NULL; >> @@ -1982,14 +1981,8 @@ static void dw_mci_work_routine_card(struct work_struct *work) >> } >> >> /* Power down slot */ >> - if (present == 0) { >> - /* Clear down the FIFO */ >> - dw_mci_fifo_reset(host); >> -#ifdef CONFIG_MMC_DW_IDMAC >> - dw_mci_idmac_reset(host); >> -#endif >> - >> - } >> + if (present == 0) >> + dw_mci_reset(host); >> >> spin_unlock_bh(&host->lock); >> >> @@ -2323,8 +2316,11 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) >> return false; >> } >> >> -static inline bool dw_mci_fifo_reset(struct dw_mci *host) >> +static inline bool dw_mci_reset(struct dw_mci *host) >> { >> + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; >> + bool ret = false; >> + >> /* >> * Reseting generates a block interrupt, hence setting >> * the scatter-gather pointer to NULL. >> @@ -2334,15 +2330,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) >> host->sg = NULL; >> } >> >> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >> -} >> + if (host->use_dma) >> + flags |= SDMMC_CTRL_DMA_RESET; >> >> -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) >> -{ >> - return dw_mci_ctrl_reset(host, >> - SDMMC_CTRL_FIFO_RESET | >> - SDMMC_CTRL_RESET | >> - SDMMC_CTRL_DMA_RESET); >> + if (dw_mci_ctrl_reset(host, flags)) { >> + /* >> + * In all cases we clear the RAWINTS register to clear any >> + * interrupts. >> + */ >> + mci_writel(host, RINTSTS, 0xFFFFFFFF); >> + >> + /* if using dma we wait for dma_req to clear */ >> + if (host->use_dma) { >> + unsigned long timeout = jiffies + msecs_to_jiffies(500); >> + u32 status; >> + do { >> + status = mci_readl(host, STATUS); >> + if (!(status & SDMMC_STATUS_DMA_REQ)) >> + break; >> + cpu_relax(); >> + } while (time_before(jiffies, timeout)); >> + >> + if (status & SDMMC_STATUS_DMA_REQ) { >> + dev_err(host->dev, >> + "%s: Timeout waiting for dma_req to " >> + "clear during reset", __func__); >> + goto ciu_out; >> + } >> + >> + /* when using DMA next we reset the fifo again */ >> + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) >> + goto ciu_out; >> + } >> + } else { >> + /* if the controller reset bit did clear, then set clock regs */ >> + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { >> + dev_err(host->dev, "%s: fifo/dma reset bits didn't " >> + "clear but ciu was reset, doing clock update.", >> + __func__); >> + goto ciu_out; >> + } >> + } >> + >> + if (IS_ENABLED(CONFIG_MMC_DW_IDMAC)) >> + /* It is also recommended that we reset and reprogram idmac */ >> + dw_mci_idmac_reset(host); >> + >> + ret = true; >> + >> +ciu_out: >> + /* After a CTRL reset we need to have CIU set clock registers */ >> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); >> + >> + return ret; >> } >> >> #ifdef CONFIG_OF >> @@ -2555,7 +2595,7 @@ int dw_mci_probe(struct dw_mci *host) >> } >> >> /* Reset all blocks */ >> - if (!dw_mci_ctrl_all_reset(host)) >> + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) >> return -ENODEV; >> >> host->dma_ops = host->pdata->dma_ops; >> @@ -2744,7 +2784,7 @@ int dw_mci_resume(struct dw_mci *host) >> } >> } >> >> - if (!dw_mci_ctrl_all_reset(host)) { >> + if (!dw_mci_reset(host)) { > Do you have any reason to use dw_mci_reset() unlike doing on probing? I really wanted to use dw_mci_reset() everwhere, including probe, because that would be simplest, where there is just one reset function always, but the host structure is not completely set up at probe time, so the code in dw_mci_reset() where we try to send a command to update clock fails, so that's why I had to just do a reset. > Thanks, > Seungwon Jeon > ^ permalink raw reply [flat|nested] 75+ messages in thread
* RE: [PATCH] mmc: dw_mmc: change to use recommended reset procedure 2014-07-10 22:35 ` Sonny Rao @ 2014-07-11 10:20 ` Seungwon Jeon -1 siblings, 0 replies; 75+ messages in thread From: Seungwon Jeon @ 2014-07-11 10:20 UTC (permalink / raw) To: 'Sonny Rao' Cc: 'linux-mmc', 'Grant Grundler', 'linux-samsung-soc', linux-arm-kernel, 'Jaehoon Chung', 'Chris Ball', 'Kukjin Kim', 'sunil joshi', 'Tomasz Figa', 'Douglas Anderson', 'Yuvaraj Kumar C D' On Fri, July 11, 2014, Sonny Rao wrote: > On Thu, Jul 10, 2014 at 5:28 AM, Seungwon Jeon <tgih.jun@samsung.com> wrote: > > Hi Sonny, > > > > I have missed this patch. > > > > You finally choose to take extra interrupt handling. > > If it is not harm, it's fine. > > Hi, thanks for coming back to it. Based on my tracing, the interrupt > seems to be okay and is just ignored. > > >> -static inline bool dw_mci_fifo_reset(struct dw_mci *host) > >> +static inline bool dw_mci_reset(struct dw_mci *host) "inline" is no needed anymore. > >> { > >> + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; > >> + bool ret = false; > >> + > >> /* > >> * Reseting generates a block interrupt, hence setting > >> * the scatter-gather pointer to NULL. > >> @@ -2334,15 +2330,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) > >> host->sg = NULL; > >> } > >> > >> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > >> -} > >> + if (host->use_dma) > >> + flags |= SDMMC_CTRL_DMA_RESET; > >> > >> -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) > >> -{ > >> - return dw_mci_ctrl_reset(host, > >> - SDMMC_CTRL_FIFO_RESET | > >> - SDMMC_CTRL_RESET | > >> - SDMMC_CTRL_DMA_RESET); > >> + if (dw_mci_ctrl_reset(host, flags)) { > >> + /* > >> + * In all cases we clear the RAWINTS register to clear any > >> + * interrupts. > >> + */ > >> + mci_writel(host, RINTSTS, 0xFFFFFFFF); > >> + > >> + /* if using dma we wait for dma_req to clear */ > >> + if (host->use_dma) { > >> + unsigned long timeout = jiffies + msecs_to_jiffies(500); > >> + u32 status; > >> + do { > >> + status = mci_readl(host, STATUS); > >> + if (!(status & SDMMC_STATUS_DMA_REQ)) > >> + break; > >> + cpu_relax(); > >> + } while (time_before(jiffies, timeout)); > >> + > >> + if (status & SDMMC_STATUS_DMA_REQ) { > >> + dev_err(host->dev, > >> + "%s: Timeout waiting for dma_req to " > >> + "clear during reset", __func__); > >> + goto ciu_out; > >> + } > >> + > >> + /* when using DMA next we reset the fifo again */ > >> + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) > >> + goto ciu_out; > >> + } > >> + } else { > >> + /* if the controller reset bit did clear, then set clock regs */ > >> + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { > >> + dev_err(host->dev, "%s: fifo/dma reset bits didn't " > >> + "clear but ciu was reset, doing clock update.", > >> + __func__); > >> + goto ciu_out; > >> + } > >> + } > >> + > >> + if (IS_ENABLED(CONFIG_MMC_DW_IDMAC)) > >> + /* It is also recommended that we reset and reprogram idmac */ > >> + dw_mci_idmac_reset(host); > >> + > >> + ret = true; > >> + > >> +ciu_out: > >> + /* After a CTRL reset we need to have CIU set clock registers */ > >> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); > >> + > >> + return ret; > >> } > >> > >> #ifdef CONFIG_OF > >> @@ -2555,7 +2595,7 @@ int dw_mci_probe(struct dw_mci *host) > >> } > >> > >> /* Reset all blocks */ > >> - if (!dw_mci_ctrl_all_reset(host)) > >> + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) > >> return -ENODEV; > >> > >> host->dma_ops = host->pdata->dma_ops; > >> @@ -2744,7 +2784,7 @@ int dw_mci_resume(struct dw_mci *host) > >> } > >> } > >> > >> - if (!dw_mci_ctrl_all_reset(host)) { > >> + if (!dw_mci_reset(host)) { > > Do you have any reason to use dw_mci_reset() unlike doing on probing? > > I really wanted to use dw_mci_reset() everwhere, including probe, > because that would be simplest, where there is just one reset function > always, but the host structure is not completely set up at probe time, > so the code in dw_mci_reset() where we try to send a command to update > clock fails, so that's why I had to just do a reset. Yes, if we can keep one interface, it would be good. But can you check below? Did you see the kernel panic on probing with "host->cur_slot" is NULL? If right, resume seems not different from probe in case of removable type. And dw_mci_idmac_reset() is redundant when dw_mci_reset() is used at resume. I think dw_mci_ctrl_reset() can be also used at resume like at probe for simple way. For safety's sake, "host->cur_slot" should be guaranteed it's not NULL. Thanks, Seungwon Jeon ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCH] mmc: dw_mmc: change to use recommended reset procedure @ 2014-07-11 10:20 ` Seungwon Jeon 0 siblings, 0 replies; 75+ messages in thread From: Seungwon Jeon @ 2014-07-11 10:20 UTC (permalink / raw) To: linux-arm-kernel On Fri, July 11, 2014, Sonny Rao wrote: > On Thu, Jul 10, 2014 at 5:28 AM, Seungwon Jeon <tgih.jun@samsung.com> wrote: > > Hi Sonny, > > > > I have missed this patch. > > > > You finally choose to take extra interrupt handling. > > If it is not harm, it's fine. > > Hi, thanks for coming back to it. Based on my tracing, the interrupt > seems to be okay and is just ignored. > > >> -static inline bool dw_mci_fifo_reset(struct dw_mci *host) > >> +static inline bool dw_mci_reset(struct dw_mci *host) "inline" is no needed anymore. > >> { > >> + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; > >> + bool ret = false; > >> + > >> /* > >> * Reseting generates a block interrupt, hence setting > >> * the scatter-gather pointer to NULL. > >> @@ -2334,15 +2330,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) > >> host->sg = NULL; > >> } > >> > >> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > >> -} > >> + if (host->use_dma) > >> + flags |= SDMMC_CTRL_DMA_RESET; > >> > >> -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) > >> -{ > >> - return dw_mci_ctrl_reset(host, > >> - SDMMC_CTRL_FIFO_RESET | > >> - SDMMC_CTRL_RESET | > >> - SDMMC_CTRL_DMA_RESET); > >> + if (dw_mci_ctrl_reset(host, flags)) { > >> + /* > >> + * In all cases we clear the RAWINTS register to clear any > >> + * interrupts. > >> + */ > >> + mci_writel(host, RINTSTS, 0xFFFFFFFF); > >> + > >> + /* if using dma we wait for dma_req to clear */ > >> + if (host->use_dma) { > >> + unsigned long timeout = jiffies + msecs_to_jiffies(500); > >> + u32 status; > >> + do { > >> + status = mci_readl(host, STATUS); > >> + if (!(status & SDMMC_STATUS_DMA_REQ)) > >> + break; > >> + cpu_relax(); > >> + } while (time_before(jiffies, timeout)); > >> + > >> + if (status & SDMMC_STATUS_DMA_REQ) { > >> + dev_err(host->dev, > >> + "%s: Timeout waiting for dma_req to " > >> + "clear during reset", __func__); > >> + goto ciu_out; > >> + } > >> + > >> + /* when using DMA next we reset the fifo again */ > >> + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) > >> + goto ciu_out; > >> + } > >> + } else { > >> + /* if the controller reset bit did clear, then set clock regs */ > >> + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { > >> + dev_err(host->dev, "%s: fifo/dma reset bits didn't " > >> + "clear but ciu was reset, doing clock update.", > >> + __func__); > >> + goto ciu_out; > >> + } > >> + } > >> + > >> + if (IS_ENABLED(CONFIG_MMC_DW_IDMAC)) > >> + /* It is also recommended that we reset and reprogram idmac */ > >> + dw_mci_idmac_reset(host); > >> + > >> + ret = true; > >> + > >> +ciu_out: > >> + /* After a CTRL reset we need to have CIU set clock registers */ > >> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); > >> + > >> + return ret; > >> } > >> > >> #ifdef CONFIG_OF > >> @@ -2555,7 +2595,7 @@ int dw_mci_probe(struct dw_mci *host) > >> } > >> > >> /* Reset all blocks */ > >> - if (!dw_mci_ctrl_all_reset(host)) > >> + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) > >> return -ENODEV; > >> > >> host->dma_ops = host->pdata->dma_ops; > >> @@ -2744,7 +2784,7 @@ int dw_mci_resume(struct dw_mci *host) > >> } > >> } > >> > >> - if (!dw_mci_ctrl_all_reset(host)) { > >> + if (!dw_mci_reset(host)) { > > Do you have any reason to use dw_mci_reset() unlike doing on probing? > > I really wanted to use dw_mci_reset() everwhere, including probe, > because that would be simplest, where there is just one reset function > always, but the host structure is not completely set up at probe time, > so the code in dw_mci_reset() where we try to send a command to update > clock fails, so that's why I had to just do a reset. Yes, if we can keep one interface, it would be good. But can you check below? Did you see the kernel panic on probing with "host->cur_slot" is NULL? If right, resume seems not different from probe in case of removable type. And dw_mci_idmac_reset() is redundant when dw_mci_reset() is used at resume. I think dw_mci_ctrl_reset() can be also used at resume like at probe for simple way. For safety's sake, "host->cur_slot" should be guaranteed it's not NULL. Thanks, Seungwon Jeon ^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCH] mmc: dw_mmc: change to use recommended reset procedure 2014-07-11 10:20 ` Seungwon Jeon @ 2014-07-11 19:48 ` Sonny Rao -1 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-07-11 19:48 UTC (permalink / raw) To: Seungwon Jeon Cc: linux-mmc, Grant Grundler, linux-samsung-soc, linux-arm-kernel, Jaehoon Chung, Chris Ball, Kukjin Kim, sunil joshi, Tomasz Figa, Douglas Anderson, Yuvaraj Kumar C D On Fri, Jul 11, 2014 at 3:20 AM, Seungwon Jeon <tgih.jun@samsung.com> wrote: > On Fri, July 11, 2014, Sonny Rao wrote: >> On Thu, Jul 10, 2014 at 5:28 AM, Seungwon Jeon <tgih.jun@samsung.com> wrote: >> > Hi Sonny, >> > >> > I have missed this patch. >> > >> > You finally choose to take extra interrupt handling. >> > If it is not harm, it's fine. >> >> Hi, thanks for coming back to it. Based on my tracing, the interrupt >> seems to be okay and is just ignored. >> >> >> -static inline bool dw_mci_fifo_reset(struct dw_mci *host) >> >> +static inline bool dw_mci_reset(struct dw_mci *host) > "inline" is no needed anymore. > >> >> { >> >> + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; >> >> + bool ret = false; >> >> + >> >> /* >> >> * Reseting generates a block interrupt, hence setting >> >> * the scatter-gather pointer to NULL. >> >> @@ -2334,15 +2330,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) >> >> host->sg = NULL; >> >> } >> >> >> >> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >> >> -} >> >> + if (host->use_dma) >> >> + flags |= SDMMC_CTRL_DMA_RESET; >> >> >> >> -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) >> >> -{ >> >> - return dw_mci_ctrl_reset(host, >> >> - SDMMC_CTRL_FIFO_RESET | >> >> - SDMMC_CTRL_RESET | >> >> - SDMMC_CTRL_DMA_RESET); >> >> + if (dw_mci_ctrl_reset(host, flags)) { >> >> + /* >> >> + * In all cases we clear the RAWINTS register to clear any >> >> + * interrupts. >> >> + */ >> >> + mci_writel(host, RINTSTS, 0xFFFFFFFF); >> >> + >> >> + /* if using dma we wait for dma_req to clear */ >> >> + if (host->use_dma) { >> >> + unsigned long timeout = jiffies + msecs_to_jiffies(500); >> >> + u32 status; >> >> + do { >> >> + status = mci_readl(host, STATUS); >> >> + if (!(status & SDMMC_STATUS_DMA_REQ)) >> >> + break; >> >> + cpu_relax(); >> >> + } while (time_before(jiffies, timeout)); >> >> + >> >> + if (status & SDMMC_STATUS_DMA_REQ) { >> >> + dev_err(host->dev, >> >> + "%s: Timeout waiting for dma_req to " >> >> + "clear during reset", __func__); >> >> + goto ciu_out; >> >> + } >> >> + >> >> + /* when using DMA next we reset the fifo again */ >> >> + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) >> >> + goto ciu_out; >> >> + } >> >> + } else { >> >> + /* if the controller reset bit did clear, then set clock regs */ >> >> + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { >> >> + dev_err(host->dev, "%s: fifo/dma reset bits didn't " >> >> + "clear but ciu was reset, doing clock update.", >> >> + __func__); >> >> + goto ciu_out; >> >> + } >> >> + } >> >> + >> >> + if (IS_ENABLED(CONFIG_MMC_DW_IDMAC)) >> >> + /* It is also recommended that we reset and reprogram idmac */ >> >> + dw_mci_idmac_reset(host); >> >> + >> >> + ret = true; >> >> + >> >> +ciu_out: >> >> + /* After a CTRL reset we need to have CIU set clock registers */ >> >> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); >> >> + >> >> + return ret; >> >> } >> >> >> >> #ifdef CONFIG_OF >> >> @@ -2555,7 +2595,7 @@ int dw_mci_probe(struct dw_mci *host) >> >> } >> >> >> >> /* Reset all blocks */ >> >> - if (!dw_mci_ctrl_all_reset(host)) >> >> + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) >> >> return -ENODEV; >> >> >> >> host->dma_ops = host->pdata->dma_ops; >> >> @@ -2744,7 +2784,7 @@ int dw_mci_resume(struct dw_mci *host) >> >> } >> >> } >> >> >> >> - if (!dw_mci_ctrl_all_reset(host)) { >> >> + if (!dw_mci_reset(host)) { >> > Do you have any reason to use dw_mci_reset() unlike doing on probing? >> >> I really wanted to use dw_mci_reset() everwhere, including probe, >> because that would be simplest, where there is just one reset function >> always, but the host structure is not completely set up at probe time, >> so the code in dw_mci_reset() where we try to send a command to update >> clock fails, so that's why I had to just do a reset. > > Yes, if we can keep one interface, it would be good. > But can you check below? > Did you see the kernel panic on probing with "host->cur_slot" is NULL? Yes, I think that was the one. > If right, resume seems not different from probe in case of removable type. > And dw_mci_idmac_reset() is redundant when dw_mci_reset() is used at resume. > > I think dw_mci_ctrl_reset() can be also used at resume like at probe for simple way. > For safety's sake, "host->cur_slot" should be guaranteed it's not NULL. Ok, I didn't try on removable, but I can change it to match probe, thanks for looking at this. > > Thanks, > Seungwon Jeon > ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCH] mmc: dw_mmc: change to use recommended reset procedure @ 2014-07-11 19:48 ` Sonny Rao 0 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-07-11 19:48 UTC (permalink / raw) To: linux-arm-kernel On Fri, Jul 11, 2014 at 3:20 AM, Seungwon Jeon <tgih.jun@samsung.com> wrote: > On Fri, July 11, 2014, Sonny Rao wrote: >> On Thu, Jul 10, 2014 at 5:28 AM, Seungwon Jeon <tgih.jun@samsung.com> wrote: >> > Hi Sonny, >> > >> > I have missed this patch. >> > >> > You finally choose to take extra interrupt handling. >> > If it is not harm, it's fine. >> >> Hi, thanks for coming back to it. Based on my tracing, the interrupt >> seems to be okay and is just ignored. >> >> >> -static inline bool dw_mci_fifo_reset(struct dw_mci *host) >> >> +static inline bool dw_mci_reset(struct dw_mci *host) > "inline" is no needed anymore. > >> >> { >> >> + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; >> >> + bool ret = false; >> >> + >> >> /* >> >> * Reseting generates a block interrupt, hence setting >> >> * the scatter-gather pointer to NULL. >> >> @@ -2334,15 +2330,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) >> >> host->sg = NULL; >> >> } >> >> >> >> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >> >> -} >> >> + if (host->use_dma) >> >> + flags |= SDMMC_CTRL_DMA_RESET; >> >> >> >> -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) >> >> -{ >> >> - return dw_mci_ctrl_reset(host, >> >> - SDMMC_CTRL_FIFO_RESET | >> >> - SDMMC_CTRL_RESET | >> >> - SDMMC_CTRL_DMA_RESET); >> >> + if (dw_mci_ctrl_reset(host, flags)) { >> >> + /* >> >> + * In all cases we clear the RAWINTS register to clear any >> >> + * interrupts. >> >> + */ >> >> + mci_writel(host, RINTSTS, 0xFFFFFFFF); >> >> + >> >> + /* if using dma we wait for dma_req to clear */ >> >> + if (host->use_dma) { >> >> + unsigned long timeout = jiffies + msecs_to_jiffies(500); >> >> + u32 status; >> >> + do { >> >> + status = mci_readl(host, STATUS); >> >> + if (!(status & SDMMC_STATUS_DMA_REQ)) >> >> + break; >> >> + cpu_relax(); >> >> + } while (time_before(jiffies, timeout)); >> >> + >> >> + if (status & SDMMC_STATUS_DMA_REQ) { >> >> + dev_err(host->dev, >> >> + "%s: Timeout waiting for dma_req to " >> >> + "clear during reset", __func__); >> >> + goto ciu_out; >> >> + } >> >> + >> >> + /* when using DMA next we reset the fifo again */ >> >> + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) >> >> + goto ciu_out; >> >> + } >> >> + } else { >> >> + /* if the controller reset bit did clear, then set clock regs */ >> >> + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { >> >> + dev_err(host->dev, "%s: fifo/dma reset bits didn't " >> >> + "clear but ciu was reset, doing clock update.", >> >> + __func__); >> >> + goto ciu_out; >> >> + } >> >> + } >> >> + >> >> + if (IS_ENABLED(CONFIG_MMC_DW_IDMAC)) >> >> + /* It is also recommended that we reset and reprogram idmac */ >> >> + dw_mci_idmac_reset(host); >> >> + >> >> + ret = true; >> >> + >> >> +ciu_out: >> >> + /* After a CTRL reset we need to have CIU set clock registers */ >> >> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); >> >> + >> >> + return ret; >> >> } >> >> >> >> #ifdef CONFIG_OF >> >> @@ -2555,7 +2595,7 @@ int dw_mci_probe(struct dw_mci *host) >> >> } >> >> >> >> /* Reset all blocks */ >> >> - if (!dw_mci_ctrl_all_reset(host)) >> >> + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) >> >> return -ENODEV; >> >> >> >> host->dma_ops = host->pdata->dma_ops; >> >> @@ -2744,7 +2784,7 @@ int dw_mci_resume(struct dw_mci *host) >> >> } >> >> } >> >> >> >> - if (!dw_mci_ctrl_all_reset(host)) { >> >> + if (!dw_mci_reset(host)) { >> > Do you have any reason to use dw_mci_reset() unlike doing on probing? >> >> I really wanted to use dw_mci_reset() everwhere, including probe, >> because that would be simplest, where there is just one reset function >> always, but the host structure is not completely set up at probe time, >> so the code in dw_mci_reset() where we try to send a command to update >> clock fails, so that's why I had to just do a reset. > > Yes, if we can keep one interface, it would be good. > But can you check below? > Did you see the kernel panic on probing with "host->cur_slot" is NULL? Yes, I think that was the one. > If right, resume seems not different from probe in case of removable type. > And dw_mci_idmac_reset() is redundant when dw_mci_reset() is used at resume. > > I think dw_mci_ctrl_reset() can be also used at resume like at probe for simple way. > For safety's sake, "host->cur_slot" should be guaranteed it's not NULL. Ok, I didn't try on removable, but I can change it to match probe, thanks for looking at this. > > Thanks, > Seungwon Jeon > ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCHv5] mmc: dw_mmc: change to use recommended reset procedure 2014-07-11 19:48 ` Sonny Rao @ 2014-07-11 20:53 ` Sonny Rao -1 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-07-11 20:53 UTC (permalink / raw) To: linux-mmc Cc: grundler, linux-samsung-soc, linux-arm-kernel, jh80.chung, cjb, tgih.jun, kgene.kim, joshi, t.figa, dianders, Yuvaraj Kumar C D, Sonny Rao 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> --- v2: Add Generic DMA support per the documentation, move interrupt clear before wait make the test for DMA host->use_dma rather than host->using_dma add proper return values (although it appears no caller checks) v3: rename fifo reset function, and change callers use this combined reset function in dw_mci_resume() just one caller left (probe), so get rid of dw_mci_ctrl_all_reset() use DMA reset bit for all systems which use DMA remove extra IDMAC reset in dw_mci_work_routine_card() do CIU clock update in error path, if CIU reset cleared v4: remove comment about FIFO reset in dw_mci_work_routine_card() move down error message when control reset clears but others don't and clarify the error stating that we will still update clocks make flags for all reset bits a macro v5: don't use dw_mci_reset() in dw_mci_resume() and instead match what is done in dw_mci_probe() and don't force inline dw_mci_resume() --- drivers/mmc/host/dw_mmc.c | 86 ++++++++++++++++++++++++++++++++++------------- drivers/mmc/host/dw_mmc.h | 5 +++ 2 files changed, 68 insertions(+), 23 deletions(-) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 55cd110..db25494 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -111,8 +111,7 @@ static const u8 tuning_blk_pattern_8bit[] = { 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, }; -static inline bool dw_mci_fifo_reset(struct dw_mci *host); -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host); +static bool dw_mci_reset(struct dw_mci *host); #if defined(CONFIG_DEBUG_FS) static int dw_mci_req_show(struct seq_file *s, void *v) @@ -1254,7 +1253,7 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) * After an error, there may be data lingering * in the FIFO */ - dw_mci_fifo_reset(host); + dw_mci_reset(host); } else { data->bytes_xfered = data->blocks * data->blksz; data->error = 0; @@ -1371,7 +1370,7 @@ static void dw_mci_tasklet_func(unsigned long priv) /* CMD error in data command */ if (mrq->cmd->error && mrq->data) - dw_mci_fifo_reset(host); + dw_mci_reset(host); host->cmd = NULL; host->data = NULL; @@ -1982,14 +1981,8 @@ static void dw_mci_work_routine_card(struct work_struct *work) } /* Power down slot */ - if (present == 0) { - /* Clear down the FIFO */ - dw_mci_fifo_reset(host); -#ifdef CONFIG_MMC_DW_IDMAC - dw_mci_idmac_reset(host); -#endif - - } + if (present == 0) + dw_mci_reset(host); spin_unlock_bh(&host->lock); @@ -2323,8 +2316,11 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) return false; } -static inline bool dw_mci_fifo_reset(struct dw_mci *host) +static bool dw_mci_reset(struct dw_mci *host) { + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; + bool ret = false; + /* * Reseting generates a block interrupt, hence setting * the scatter-gather pointer to NULL. @@ -2334,15 +2330,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) host->sg = NULL; } - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); -} + if (host->use_dma) + flags |= SDMMC_CTRL_DMA_RESET; -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) -{ - return dw_mci_ctrl_reset(host, - SDMMC_CTRL_FIFO_RESET | - SDMMC_CTRL_RESET | - SDMMC_CTRL_DMA_RESET); + if (dw_mci_ctrl_reset(host, flags)) { + /* + * In all cases we clear the RAWINTS register to clear any + * interrupts. + */ + mci_writel(host, RINTSTS, 0xFFFFFFFF); + + /* if using dma we wait for dma_req to clear */ + if (host->use_dma) { + unsigned long timeout = jiffies + msecs_to_jiffies(500); + u32 status; + do { + status = mci_readl(host, STATUS); + if (!(status & SDMMC_STATUS_DMA_REQ)) + break; + cpu_relax(); + } while (time_before(jiffies, timeout)); + + if (status & SDMMC_STATUS_DMA_REQ) { + dev_err(host->dev, + "%s: Timeout waiting for dma_req to " + "clear during reset", __func__); + goto ciu_out; + } + + /* when using DMA next we reset the fifo again */ + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) + goto ciu_out; + } + } else { + /* if the controller reset bit did clear, then set clock regs */ + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { + dev_err(host->dev, "%s: fifo/dma reset bits didn't " + "clear but ciu was reset, doing clock update.", + __func__); + goto ciu_out; + } + } + + if (IS_ENABLED(CONFIG_MMC_DW_IDMAC)) + /* It is also recommended that we reset and reprogram idmac */ + dw_mci_idmac_reset(host); + + ret = true; + +ciu_out: + /* After a CTRL reset we need to have CIU set clock registers */ + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); + + return ret; } #ifdef CONFIG_OF @@ -2555,7 +2595,7 @@ int dw_mci_probe(struct dw_mci *host) } /* Reset all blocks */ - if (!dw_mci_ctrl_all_reset(host)) + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) return -ENODEV; host->dma_ops = host->pdata->dma_ops; @@ -2744,7 +2784,7 @@ int dw_mci_resume(struct dw_mci *host) } } - if (!dw_mci_ctrl_all_reset(host)) { + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) { ret = -ENODEV; return ret; } diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 6bf24ab..9ab8ccd 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -129,6 +129,7 @@ #define SDMMC_CMD_INDX(n) ((n) & 0x1F) /* Status register defines */ #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) +#define SDMMC_STATUS_DMA_REQ BIT(31) /* FIFOTH register defines */ #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ ((r) & 0xFFF) << 16 | \ @@ -150,6 +151,10 @@ /* Card read threshold */ #define SDMMC_SET_RD_THLD(v, x) (((v) & 0x1FFF) << 16 | (x)) +/* All ctrl reset bits */ +#define SDMMC_CTRL_ALL_RESET_FLAGS \ + (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET) + /* Register access macros */ #define mci_readl(dev, reg) \ __raw_readl((dev)->regs + SDMMC_##reg) -- 1.8.3.2 ^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCHv5] mmc: dw_mmc: change to use recommended reset procedure @ 2014-07-11 20:53 ` Sonny Rao 0 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-07-11 20:53 UTC (permalink / raw) To: linux-arm-kernel 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> --- v2: Add Generic DMA support per the documentation, move interrupt clear before wait make the test for DMA host->use_dma rather than host->using_dma add proper return values (although it appears no caller checks) v3: rename fifo reset function, and change callers use this combined reset function in dw_mci_resume() just one caller left (probe), so get rid of dw_mci_ctrl_all_reset() use DMA reset bit for all systems which use DMA remove extra IDMAC reset in dw_mci_work_routine_card() do CIU clock update in error path, if CIU reset cleared v4: remove comment about FIFO reset in dw_mci_work_routine_card() move down error message when control reset clears but others don't and clarify the error stating that we will still update clocks make flags for all reset bits a macro v5: don't use dw_mci_reset() in dw_mci_resume() and instead match what is done in dw_mci_probe() and don't force inline dw_mci_resume() --- drivers/mmc/host/dw_mmc.c | 86 ++++++++++++++++++++++++++++++++++------------- drivers/mmc/host/dw_mmc.h | 5 +++ 2 files changed, 68 insertions(+), 23 deletions(-) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 55cd110..db25494 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -111,8 +111,7 @@ static const u8 tuning_blk_pattern_8bit[] = { 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, }; -static inline bool dw_mci_fifo_reset(struct dw_mci *host); -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host); +static bool dw_mci_reset(struct dw_mci *host); #if defined(CONFIG_DEBUG_FS) static int dw_mci_req_show(struct seq_file *s, void *v) @@ -1254,7 +1253,7 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) * After an error, there may be data lingering * in the FIFO */ - dw_mci_fifo_reset(host); + dw_mci_reset(host); } else { data->bytes_xfered = data->blocks * data->blksz; data->error = 0; @@ -1371,7 +1370,7 @@ static void dw_mci_tasklet_func(unsigned long priv) /* CMD error in data command */ if (mrq->cmd->error && mrq->data) - dw_mci_fifo_reset(host); + dw_mci_reset(host); host->cmd = NULL; host->data = NULL; @@ -1982,14 +1981,8 @@ static void dw_mci_work_routine_card(struct work_struct *work) } /* Power down slot */ - if (present == 0) { - /* Clear down the FIFO */ - dw_mci_fifo_reset(host); -#ifdef CONFIG_MMC_DW_IDMAC - dw_mci_idmac_reset(host); -#endif - - } + if (present == 0) + dw_mci_reset(host); spin_unlock_bh(&host->lock); @@ -2323,8 +2316,11 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) return false; } -static inline bool dw_mci_fifo_reset(struct dw_mci *host) +static bool dw_mci_reset(struct dw_mci *host) { + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; + bool ret = false; + /* * Reseting generates a block interrupt, hence setting * the scatter-gather pointer to NULL. @@ -2334,15 +2330,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) host->sg = NULL; } - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); -} + if (host->use_dma) + flags |= SDMMC_CTRL_DMA_RESET; -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) -{ - return dw_mci_ctrl_reset(host, - SDMMC_CTRL_FIFO_RESET | - SDMMC_CTRL_RESET | - SDMMC_CTRL_DMA_RESET); + if (dw_mci_ctrl_reset(host, flags)) { + /* + * In all cases we clear the RAWINTS register to clear any + * interrupts. + */ + mci_writel(host, RINTSTS, 0xFFFFFFFF); + + /* if using dma we wait for dma_req to clear */ + if (host->use_dma) { + unsigned long timeout = jiffies + msecs_to_jiffies(500); + u32 status; + do { + status = mci_readl(host, STATUS); + if (!(status & SDMMC_STATUS_DMA_REQ)) + break; + cpu_relax(); + } while (time_before(jiffies, timeout)); + + if (status & SDMMC_STATUS_DMA_REQ) { + dev_err(host->dev, + "%s: Timeout waiting for dma_req to " + "clear during reset", __func__); + goto ciu_out; + } + + /* when using DMA next we reset the fifo again */ + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) + goto ciu_out; + } + } else { + /* if the controller reset bit did clear, then set clock regs */ + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { + dev_err(host->dev, "%s: fifo/dma reset bits didn't " + "clear but ciu was reset, doing clock update.", + __func__); + goto ciu_out; + } + } + + if (IS_ENABLED(CONFIG_MMC_DW_IDMAC)) + /* It is also recommended that we reset and reprogram idmac */ + dw_mci_idmac_reset(host); + + ret = true; + +ciu_out: + /* After a CTRL reset we need to have CIU set clock registers */ + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); + + return ret; } #ifdef CONFIG_OF @@ -2555,7 +2595,7 @@ int dw_mci_probe(struct dw_mci *host) } /* Reset all blocks */ - if (!dw_mci_ctrl_all_reset(host)) + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) return -ENODEV; host->dma_ops = host->pdata->dma_ops; @@ -2744,7 +2784,7 @@ int dw_mci_resume(struct dw_mci *host) } } - if (!dw_mci_ctrl_all_reset(host)) { + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) { ret = -ENODEV; return ret; } diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 6bf24ab..9ab8ccd 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -129,6 +129,7 @@ #define SDMMC_CMD_INDX(n) ((n) & 0x1F) /* Status register defines */ #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) +#define SDMMC_STATUS_DMA_REQ BIT(31) /* FIFOTH register defines */ #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ ((r) & 0xFFF) << 16 | \ @@ -150,6 +151,10 @@ /* Card read threshold */ #define SDMMC_SET_RD_THLD(v, x) (((v) & 0x1FFF) << 16 | (x)) +/* All ctrl reset bits */ +#define SDMMC_CTRL_ALL_RESET_FLAGS \ + (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET) + /* Register access macros */ #define mci_readl(dev, reg) \ __raw_readl((dev)->regs + SDMMC_##reg) -- 1.8.3.2 ^ permalink raw reply related [flat|nested] 75+ messages in thread
* Re: [PATCHv5] mmc: dw_mmc: change to use recommended reset procedure 2014-07-11 20:53 ` Sonny Rao @ 2014-07-14 5:52 ` Jaehoon Chung -1 siblings, 0 replies; 75+ messages in thread From: Jaehoon Chung @ 2014-07-14 5:52 UTC (permalink / raw) To: Sonny Rao, linux-mmc Cc: grundler, linux-samsung-soc, linux-arm-kernel, cjb, tgih.jun, kgene.kim, joshi, t.figa, dianders, Yuvaraj Kumar C D On 07/12/2014 05:53 AM, Sonny Rao wrote: > 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> > --- > v2: Add Generic DMA support > per the documentation, move interrupt clear before wait > make the test for DMA host->use_dma rather than host->using_dma > add proper return values (although it appears no caller checks) > v3: rename fifo reset function, and change callers > use this combined reset function in dw_mci_resume() > just one caller left (probe), so get rid of dw_mci_ctrl_all_reset() > use DMA reset bit for all systems which use DMA > remove extra IDMAC reset in dw_mci_work_routine_card() > do CIU clock update in error path, if CIU reset cleared > v4: remove comment about FIFO reset in dw_mci_work_routine_card() > move down error message when control reset clears but others don't > and clarify the error stating that we will still update clocks > make flags for all reset bits a macro > v5: don't use dw_mci_reset() in dw_mci_resume() and instead match what > is done in dw_mci_probe() and don't force inline dw_mci_resume() > --- > drivers/mmc/host/dw_mmc.c | 86 ++++++++++++++++++++++++++++++++++------------- > drivers/mmc/host/dw_mmc.h | 5 +++ > 2 files changed, 68 insertions(+), 23 deletions(-) > > diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c > index 55cd110..db25494 100644 > --- a/drivers/mmc/host/dw_mmc.c > +++ b/drivers/mmc/host/dw_mmc.c > @@ -111,8 +111,7 @@ static const u8 tuning_blk_pattern_8bit[] = { > 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, > }; > > -static inline bool dw_mci_fifo_reset(struct dw_mci *host); > -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host); > +static bool dw_mci_reset(struct dw_mci *host); > > #if defined(CONFIG_DEBUG_FS) > static int dw_mci_req_show(struct seq_file *s, void *v) > @@ -1254,7 +1253,7 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) > * After an error, there may be data lingering > * in the FIFO > */ > - dw_mci_fifo_reset(host); > + dw_mci_reset(host); > } else { > data->bytes_xfered = data->blocks * data->blksz; > data->error = 0; > @@ -1371,7 +1370,7 @@ static void dw_mci_tasklet_func(unsigned long priv) > > /* CMD error in data command */ > if (mrq->cmd->error && mrq->data) > - dw_mci_fifo_reset(host); > + dw_mci_reset(host); > > host->cmd = NULL; > host->data = NULL; > @@ -1982,14 +1981,8 @@ static void dw_mci_work_routine_card(struct work_struct *work) > } > > /* Power down slot */ > - if (present == 0) { > - /* Clear down the FIFO */ > - dw_mci_fifo_reset(host); > -#ifdef CONFIG_MMC_DW_IDMAC > - dw_mci_idmac_reset(host); > -#endif > - > - } > + if (present == 0) > + dw_mci_reset(host); > > spin_unlock_bh(&host->lock); > > @@ -2323,8 +2316,11 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) > return false; > } > > -static inline bool dw_mci_fifo_reset(struct dw_mci *host) > +static bool dw_mci_reset(struct dw_mci *host) > { > + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; > + bool ret = false; > + > /* > * Reseting generates a block interrupt, hence setting > * the scatter-gather pointer to NULL. > @@ -2334,15 +2330,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) > host->sg = NULL; > } > > - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > -} > + if (host->use_dma) > + flags |= SDMMC_CTRL_DMA_RESET; > > -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) > -{ > - return dw_mci_ctrl_reset(host, > - SDMMC_CTRL_FIFO_RESET | > - SDMMC_CTRL_RESET | > - SDMMC_CTRL_DMA_RESET); > + if (dw_mci_ctrl_reset(host, flags)) { > + /* > + * In all cases we clear the RAWINTS register to clear any > + * interrupts. > + */ > + mci_writel(host, RINTSTS, 0xFFFFFFFF); > + > + /* if using dma we wait for dma_req to clear */ > + if (host->use_dma) { > + unsigned long timeout = jiffies + msecs_to_jiffies(500); > + u32 status; > + do { > + status = mci_readl(host, STATUS); > + if (!(status & SDMMC_STATUS_DMA_REQ)) > + break; > + cpu_relax(); > + } while (time_before(jiffies, timeout)); > + > + if (status & SDMMC_STATUS_DMA_REQ) { > + dev_err(host->dev, > + "%s: Timeout waiting for dma_req to " > + "clear during reset", __func__); Could you add the "\n"? > + goto ciu_out; > + } > + > + /* when using DMA next we reset the fifo again */ > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) > + goto ciu_out; > + } > + } else { > + /* if the controller reset bit did clear, then set clock regs */ > + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { > + dev_err(host->dev, "%s: fifo/dma reset bits didn't " > + "clear but ciu was reset, doing clock update.", > + __func__); Ditto. > + goto ciu_out; > + } > + } > + > + if (IS_ENABLED(CONFIG_MMC_DW_IDMAC)) > + /* It is also recommended that we reset and reprogram idmac */ > + dw_mci_idmac_reset(host); > + > + ret = true; > + > +ciu_out: > + /* After a CTRL reset we need to have CIU set clock registers */ > + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); > + > + return ret; > } > > #ifdef CONFIG_OF > @@ -2555,7 +2595,7 @@ int dw_mci_probe(struct dw_mci *host) > } > > /* Reset all blocks */ > - if (!dw_mci_ctrl_all_reset(host)) > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) > return -ENODEV; > > host->dma_ops = host->pdata->dma_ops; > @@ -2744,7 +2784,7 @@ int dw_mci_resume(struct dw_mci *host) > } > } > > - if (!dw_mci_ctrl_all_reset(host)) { > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) { > ret = -ENODEV; > return ret; > } > diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h > index 6bf24ab..9ab8ccd 100644 > --- a/drivers/mmc/host/dw_mmc.h > +++ b/drivers/mmc/host/dw_mmc.h > @@ -129,6 +129,7 @@ > #define SDMMC_CMD_INDX(n) ((n) & 0x1F) > /* Status register defines */ > #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) > +#define SDMMC_STATUS_DMA_REQ BIT(31) > /* FIFOTH register defines */ > #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ > ((r) & 0xFFF) << 16 | \ > @@ -150,6 +151,10 @@ > /* Card read threshold */ > #define SDMMC_SET_RD_THLD(v, x) (((v) & 0x1FFF) << 16 | (x)) > > +/* All ctrl reset bits */ > +#define SDMMC_CTRL_ALL_RESET_FLAGS \ > + (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET) > + > /* Register access macros */ > #define mci_readl(dev, reg) \ > __raw_readl((dev)->regs + SDMMC_##reg) > ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCHv5] mmc: dw_mmc: change to use recommended reset procedure @ 2014-07-14 5:52 ` Jaehoon Chung 0 siblings, 0 replies; 75+ messages in thread From: Jaehoon Chung @ 2014-07-14 5:52 UTC (permalink / raw) To: linux-arm-kernel On 07/12/2014 05:53 AM, Sonny Rao wrote: > 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> > --- > v2: Add Generic DMA support > per the documentation, move interrupt clear before wait > make the test for DMA host->use_dma rather than host->using_dma > add proper return values (although it appears no caller checks) > v3: rename fifo reset function, and change callers > use this combined reset function in dw_mci_resume() > just one caller left (probe), so get rid of dw_mci_ctrl_all_reset() > use DMA reset bit for all systems which use DMA > remove extra IDMAC reset in dw_mci_work_routine_card() > do CIU clock update in error path, if CIU reset cleared > v4: remove comment about FIFO reset in dw_mci_work_routine_card() > move down error message when control reset clears but others don't > and clarify the error stating that we will still update clocks > make flags for all reset bits a macro > v5: don't use dw_mci_reset() in dw_mci_resume() and instead match what > is done in dw_mci_probe() and don't force inline dw_mci_resume() > --- > drivers/mmc/host/dw_mmc.c | 86 ++++++++++++++++++++++++++++++++++------------- > drivers/mmc/host/dw_mmc.h | 5 +++ > 2 files changed, 68 insertions(+), 23 deletions(-) > > diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c > index 55cd110..db25494 100644 > --- a/drivers/mmc/host/dw_mmc.c > +++ b/drivers/mmc/host/dw_mmc.c > @@ -111,8 +111,7 @@ static const u8 tuning_blk_pattern_8bit[] = { > 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, > }; > > -static inline bool dw_mci_fifo_reset(struct dw_mci *host); > -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host); > +static bool dw_mci_reset(struct dw_mci *host); > > #if defined(CONFIG_DEBUG_FS) > static int dw_mci_req_show(struct seq_file *s, void *v) > @@ -1254,7 +1253,7 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) > * After an error, there may be data lingering > * in the FIFO > */ > - dw_mci_fifo_reset(host); > + dw_mci_reset(host); > } else { > data->bytes_xfered = data->blocks * data->blksz; > data->error = 0; > @@ -1371,7 +1370,7 @@ static void dw_mci_tasklet_func(unsigned long priv) > > /* CMD error in data command */ > if (mrq->cmd->error && mrq->data) > - dw_mci_fifo_reset(host); > + dw_mci_reset(host); > > host->cmd = NULL; > host->data = NULL; > @@ -1982,14 +1981,8 @@ static void dw_mci_work_routine_card(struct work_struct *work) > } > > /* Power down slot */ > - if (present == 0) { > - /* Clear down the FIFO */ > - dw_mci_fifo_reset(host); > -#ifdef CONFIG_MMC_DW_IDMAC > - dw_mci_idmac_reset(host); > -#endif > - > - } > + if (present == 0) > + dw_mci_reset(host); > > spin_unlock_bh(&host->lock); > > @@ -2323,8 +2316,11 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) > return false; > } > > -static inline bool dw_mci_fifo_reset(struct dw_mci *host) > +static bool dw_mci_reset(struct dw_mci *host) > { > + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; > + bool ret = false; > + > /* > * Reseting generates a block interrupt, hence setting > * the scatter-gather pointer to NULL. > @@ -2334,15 +2330,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) > host->sg = NULL; > } > > - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > -} > + if (host->use_dma) > + flags |= SDMMC_CTRL_DMA_RESET; > > -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) > -{ > - return dw_mci_ctrl_reset(host, > - SDMMC_CTRL_FIFO_RESET | > - SDMMC_CTRL_RESET | > - SDMMC_CTRL_DMA_RESET); > + if (dw_mci_ctrl_reset(host, flags)) { > + /* > + * In all cases we clear the RAWINTS register to clear any > + * interrupts. > + */ > + mci_writel(host, RINTSTS, 0xFFFFFFFF); > + > + /* if using dma we wait for dma_req to clear */ > + if (host->use_dma) { > + unsigned long timeout = jiffies + msecs_to_jiffies(500); > + u32 status; > + do { > + status = mci_readl(host, STATUS); > + if (!(status & SDMMC_STATUS_DMA_REQ)) > + break; > + cpu_relax(); > + } while (time_before(jiffies, timeout)); > + > + if (status & SDMMC_STATUS_DMA_REQ) { > + dev_err(host->dev, > + "%s: Timeout waiting for dma_req to " > + "clear during reset", __func__); Could you add the "\n"? > + goto ciu_out; > + } > + > + /* when using DMA next we reset the fifo again */ > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) > + goto ciu_out; > + } > + } else { > + /* if the controller reset bit did clear, then set clock regs */ > + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { > + dev_err(host->dev, "%s: fifo/dma reset bits didn't " > + "clear but ciu was reset, doing clock update.", > + __func__); Ditto. > + goto ciu_out; > + } > + } > + > + if (IS_ENABLED(CONFIG_MMC_DW_IDMAC)) > + /* It is also recommended that we reset and reprogram idmac */ > + dw_mci_idmac_reset(host); > + > + ret = true; > + > +ciu_out: > + /* After a CTRL reset we need to have CIU set clock registers */ > + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); > + > + return ret; > } > > #ifdef CONFIG_OF > @@ -2555,7 +2595,7 @@ int dw_mci_probe(struct dw_mci *host) > } > > /* Reset all blocks */ > - if (!dw_mci_ctrl_all_reset(host)) > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) > return -ENODEV; > > host->dma_ops = host->pdata->dma_ops; > @@ -2744,7 +2784,7 @@ int dw_mci_resume(struct dw_mci *host) > } > } > > - if (!dw_mci_ctrl_all_reset(host)) { > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) { > ret = -ENODEV; > return ret; > } > diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h > index 6bf24ab..9ab8ccd 100644 > --- a/drivers/mmc/host/dw_mmc.h > +++ b/drivers/mmc/host/dw_mmc.h > @@ -129,6 +129,7 @@ > #define SDMMC_CMD_INDX(n) ((n) & 0x1F) > /* Status register defines */ > #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) > +#define SDMMC_STATUS_DMA_REQ BIT(31) > /* FIFOTH register defines */ > #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ > ((r) & 0xFFF) << 16 | \ > @@ -150,6 +151,10 @@ > /* Card read threshold */ > #define SDMMC_SET_RD_THLD(v, x) (((v) & 0x1FFF) << 16 | (x)) > > +/* All ctrl reset bits */ > +#define SDMMC_CTRL_ALL_RESET_FLAGS \ > + (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET) > + > /* Register access macros */ > #define mci_readl(dev, reg) \ > __raw_readl((dev)->regs + SDMMC_##reg) > ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCHv6] mmc: dw_mmc: change to use recommended reset procedure 2014-07-14 5:52 ` Jaehoon Chung @ 2014-07-14 22:06 ` Sonny Rao -1 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-07-14 22:06 UTC (permalink / raw) To: linux-mmc Cc: grundler, linux-samsung-soc, linux-arm-kernel, jh80.chung, cjb, tgih.jun, kgene.kim, joshi, t.figa, dianders, Yuvaraj Kumar C D, Sonny Rao 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> --- v2: Add Generic DMA support per the documentation, move interrupt clear before wait make the test for DMA host->use_dma rather than host->using_dma add proper return values (although it appears no caller checks) v3: rename fifo reset function, and change callers use this combined reset function in dw_mci_resume() just one caller left (probe), so get rid of dw_mci_ctrl_all_reset() use DMA reset bit for all systems which use DMA remove extra IDMAC reset in dw_mci_work_routine_card() do CIU clock update in error path, if CIU reset cleared v4: remove comment about FIFO reset in dw_mci_work_routine_card() move down error message when control reset clears but others don't and clarify the error stating that we will still update clocks make flags for all reset bits a macro v5: don't use dw_mci_reset() in dw_mci_resume() and instead match what is done in dw_mci_probe() and don't force inline dw_mci_resume() v6: add newlines to dev_err() messages --- drivers/mmc/host/dw_mmc.c | 86 ++++++++++++++++++++++++++++++++++------------- drivers/mmc/host/dw_mmc.h | 5 +++ 2 files changed, 68 insertions(+), 23 deletions(-) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 55cd110..0c0aecb 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -111,8 +111,7 @@ static const u8 tuning_blk_pattern_8bit[] = { 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, }; -static inline bool dw_mci_fifo_reset(struct dw_mci *host); -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host); +static bool dw_mci_reset(struct dw_mci *host); #if defined(CONFIG_DEBUG_FS) static int dw_mci_req_show(struct seq_file *s, void *v) @@ -1254,7 +1253,7 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) * After an error, there may be data lingering * in the FIFO */ - dw_mci_fifo_reset(host); + dw_mci_reset(host); } else { data->bytes_xfered = data->blocks * data->blksz; data->error = 0; @@ -1371,7 +1370,7 @@ static void dw_mci_tasklet_func(unsigned long priv) /* CMD error in data command */ if (mrq->cmd->error && mrq->data) - dw_mci_fifo_reset(host); + dw_mci_reset(host); host->cmd = NULL; host->data = NULL; @@ -1982,14 +1981,8 @@ static void dw_mci_work_routine_card(struct work_struct *work) } /* Power down slot */ - if (present == 0) { - /* Clear down the FIFO */ - dw_mci_fifo_reset(host); -#ifdef CONFIG_MMC_DW_IDMAC - dw_mci_idmac_reset(host); -#endif - - } + if (present == 0) + dw_mci_reset(host); spin_unlock_bh(&host->lock); @@ -2323,8 +2316,11 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) return false; } -static inline bool dw_mci_fifo_reset(struct dw_mci *host) +static bool dw_mci_reset(struct dw_mci *host) { + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; + bool ret = false; + /* * Reseting generates a block interrupt, hence setting * the scatter-gather pointer to NULL. @@ -2334,15 +2330,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) host->sg = NULL; } - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); -} + if (host->use_dma) + flags |= SDMMC_CTRL_DMA_RESET; -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) -{ - return dw_mci_ctrl_reset(host, - SDMMC_CTRL_FIFO_RESET | - SDMMC_CTRL_RESET | - SDMMC_CTRL_DMA_RESET); + if (dw_mci_ctrl_reset(host, flags)) { + /* + * In all cases we clear the RAWINTS register to clear any + * interrupts. + */ + mci_writel(host, RINTSTS, 0xFFFFFFFF); + + /* if using dma we wait for dma_req to clear */ + if (host->use_dma) { + unsigned long timeout = jiffies + msecs_to_jiffies(500); + u32 status; + do { + status = mci_readl(host, STATUS); + if (!(status & SDMMC_STATUS_DMA_REQ)) + break; + cpu_relax(); + } while (time_before(jiffies, timeout)); + + if (status & SDMMC_STATUS_DMA_REQ) { + dev_err(host->dev, + "%s: Timeout waiting for dma_req to " + "clear during reset\n", __func__); + goto ciu_out; + } + + /* when using DMA next we reset the fifo again */ + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) + goto ciu_out; + } + } else { + /* if the controller reset bit did clear, then set clock regs */ + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { + dev_err(host->dev, "%s: fifo/dma reset bits didn't " + "clear but ciu was reset, doing clock update\n", + __func__); + goto ciu_out; + } + } + + if (IS_ENABLED(CONFIG_MMC_DW_IDMAC)) + /* It is also recommended that we reset and reprogram idmac */ + dw_mci_idmac_reset(host); + + ret = true; + +ciu_out: + /* After a CTRL reset we need to have CIU set clock registers */ + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); + + return ret; } #ifdef CONFIG_OF @@ -2555,7 +2595,7 @@ int dw_mci_probe(struct dw_mci *host) } /* Reset all blocks */ - if (!dw_mci_ctrl_all_reset(host)) + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) return -ENODEV; host->dma_ops = host->pdata->dma_ops; @@ -2744,7 +2784,7 @@ int dw_mci_resume(struct dw_mci *host) } } - if (!dw_mci_ctrl_all_reset(host)) { + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) { ret = -ENODEV; return ret; } diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 6bf24ab..9ab8ccd 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -129,6 +129,7 @@ #define SDMMC_CMD_INDX(n) ((n) & 0x1F) /* Status register defines */ #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) +#define SDMMC_STATUS_DMA_REQ BIT(31) /* FIFOTH register defines */ #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ ((r) & 0xFFF) << 16 | \ @@ -150,6 +151,10 @@ /* Card read threshold */ #define SDMMC_SET_RD_THLD(v, x) (((v) & 0x1FFF) << 16 | (x)) +/* All ctrl reset bits */ +#define SDMMC_CTRL_ALL_RESET_FLAGS \ + (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET) + /* Register access macros */ #define mci_readl(dev, reg) \ __raw_readl((dev)->regs + SDMMC_##reg) -- 2.0.0.526.g5318336 ^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCHv6] mmc: dw_mmc: change to use recommended reset procedure @ 2014-07-14 22:06 ` Sonny Rao 0 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-07-14 22:06 UTC (permalink / raw) To: linux-arm-kernel 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> --- v2: Add Generic DMA support per the documentation, move interrupt clear before wait make the test for DMA host->use_dma rather than host->using_dma add proper return values (although it appears no caller checks) v3: rename fifo reset function, and change callers use this combined reset function in dw_mci_resume() just one caller left (probe), so get rid of dw_mci_ctrl_all_reset() use DMA reset bit for all systems which use DMA remove extra IDMAC reset in dw_mci_work_routine_card() do CIU clock update in error path, if CIU reset cleared v4: remove comment about FIFO reset in dw_mci_work_routine_card() move down error message when control reset clears but others don't and clarify the error stating that we will still update clocks make flags for all reset bits a macro v5: don't use dw_mci_reset() in dw_mci_resume() and instead match what is done in dw_mci_probe() and don't force inline dw_mci_resume() v6: add newlines to dev_err() messages --- drivers/mmc/host/dw_mmc.c | 86 ++++++++++++++++++++++++++++++++++------------- drivers/mmc/host/dw_mmc.h | 5 +++ 2 files changed, 68 insertions(+), 23 deletions(-) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 55cd110..0c0aecb 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -111,8 +111,7 @@ static const u8 tuning_blk_pattern_8bit[] = { 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, }; -static inline bool dw_mci_fifo_reset(struct dw_mci *host); -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host); +static bool dw_mci_reset(struct dw_mci *host); #if defined(CONFIG_DEBUG_FS) static int dw_mci_req_show(struct seq_file *s, void *v) @@ -1254,7 +1253,7 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) * After an error, there may be data lingering * in the FIFO */ - dw_mci_fifo_reset(host); + dw_mci_reset(host); } else { data->bytes_xfered = data->blocks * data->blksz; data->error = 0; @@ -1371,7 +1370,7 @@ static void dw_mci_tasklet_func(unsigned long priv) /* CMD error in data command */ if (mrq->cmd->error && mrq->data) - dw_mci_fifo_reset(host); + dw_mci_reset(host); host->cmd = NULL; host->data = NULL; @@ -1982,14 +1981,8 @@ static void dw_mci_work_routine_card(struct work_struct *work) } /* Power down slot */ - if (present == 0) { - /* Clear down the FIFO */ - dw_mci_fifo_reset(host); -#ifdef CONFIG_MMC_DW_IDMAC - dw_mci_idmac_reset(host); -#endif - - } + if (present == 0) + dw_mci_reset(host); spin_unlock_bh(&host->lock); @@ -2323,8 +2316,11 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) return false; } -static inline bool dw_mci_fifo_reset(struct dw_mci *host) +static bool dw_mci_reset(struct dw_mci *host) { + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; + bool ret = false; + /* * Reseting generates a block interrupt, hence setting * the scatter-gather pointer to NULL. @@ -2334,15 +2330,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) host->sg = NULL; } - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); -} + if (host->use_dma) + flags |= SDMMC_CTRL_DMA_RESET; -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) -{ - return dw_mci_ctrl_reset(host, - SDMMC_CTRL_FIFO_RESET | - SDMMC_CTRL_RESET | - SDMMC_CTRL_DMA_RESET); + if (dw_mci_ctrl_reset(host, flags)) { + /* + * In all cases we clear the RAWINTS register to clear any + * interrupts. + */ + mci_writel(host, RINTSTS, 0xFFFFFFFF); + + /* if using dma we wait for dma_req to clear */ + if (host->use_dma) { + unsigned long timeout = jiffies + msecs_to_jiffies(500); + u32 status; + do { + status = mci_readl(host, STATUS); + if (!(status & SDMMC_STATUS_DMA_REQ)) + break; + cpu_relax(); + } while (time_before(jiffies, timeout)); + + if (status & SDMMC_STATUS_DMA_REQ) { + dev_err(host->dev, + "%s: Timeout waiting for dma_req to " + "clear during reset\n", __func__); + goto ciu_out; + } + + /* when using DMA next we reset the fifo again */ + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) + goto ciu_out; + } + } else { + /* if the controller reset bit did clear, then set clock regs */ + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { + dev_err(host->dev, "%s: fifo/dma reset bits didn't " + "clear but ciu was reset, doing clock update\n", + __func__); + goto ciu_out; + } + } + + if (IS_ENABLED(CONFIG_MMC_DW_IDMAC)) + /* It is also recommended that we reset and reprogram idmac */ + dw_mci_idmac_reset(host); + + ret = true; + +ciu_out: + /* After a CTRL reset we need to have CIU set clock registers */ + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); + + return ret; } #ifdef CONFIG_OF @@ -2555,7 +2595,7 @@ int dw_mci_probe(struct dw_mci *host) } /* Reset all blocks */ - if (!dw_mci_ctrl_all_reset(host)) + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) return -ENODEV; host->dma_ops = host->pdata->dma_ops; @@ -2744,7 +2784,7 @@ int dw_mci_resume(struct dw_mci *host) } } - if (!dw_mci_ctrl_all_reset(host)) { + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) { ret = -ENODEV; return ret; } diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 6bf24ab..9ab8ccd 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -129,6 +129,7 @@ #define SDMMC_CMD_INDX(n) ((n) & 0x1F) /* Status register defines */ #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) +#define SDMMC_STATUS_DMA_REQ BIT(31) /* FIFOTH register defines */ #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ ((r) & 0xFFF) << 16 | \ @@ -150,6 +151,10 @@ /* Card read threshold */ #define SDMMC_SET_RD_THLD(v, x) (((v) & 0x1FFF) << 16 | (x)) +/* All ctrl reset bits */ +#define SDMMC_CTRL_ALL_RESET_FLAGS \ + (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET) + /* Register access macros */ #define mci_readl(dev, reg) \ __raw_readl((dev)->regs + SDMMC_##reg) -- 2.0.0.526.g5318336 ^ permalink raw reply related [flat|nested] 75+ messages in thread
* RE: [PATCHv6] mmc: dw_mmc: change to use recommended reset procedure 2014-07-14 22:06 ` Sonny Rao @ 2014-07-18 13:37 ` Seungwon Jeon -1 siblings, 0 replies; 75+ messages in thread From: Seungwon Jeon @ 2014-07-18 13:37 UTC (permalink / raw) To: 'Sonny Rao', linux-mmc Cc: grundler, linux-samsung-soc, linux-arm-kernel, jh80.chung, cjb, kgene.kim, joshi, t.figa, dianders, 'Yuvaraj Kumar C D' On Tue, July 15, 2014, Sonny Rao wrote: > 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> Thanks, Seungwon Jeon > --- > v2: Add Generic DMA support > per the documentation, move interrupt clear before wait > make the test for DMA host->use_dma rather than host->using_dma > add proper return values (although it appears no caller checks) > v3: rename fifo reset function, and change callers > use this combined reset function in dw_mci_resume() > just one caller left (probe), so get rid of dw_mci_ctrl_all_reset() > use DMA reset bit for all systems which use DMA > remove extra IDMAC reset in dw_mci_work_routine_card() > do CIU clock update in error path, if CIU reset cleared > v4: remove comment about FIFO reset in dw_mci_work_routine_card() > move down error message when control reset clears but others don't > and clarify the error stating that we will still update clocks > make flags for all reset bits a macro > v5: don't use dw_mci_reset() in dw_mci_resume() and instead match what > is done in dw_mci_probe() and don't force inline dw_mci_resume() > v6: add newlines to dev_err() messages > --- > drivers/mmc/host/dw_mmc.c | 86 ++++++++++++++++++++++++++++++++++------------- > drivers/mmc/host/dw_mmc.h | 5 +++ > 2 files changed, 68 insertions(+), 23 deletions(-) > > diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c > index 55cd110..0c0aecb 100644 > --- a/drivers/mmc/host/dw_mmc.c > +++ b/drivers/mmc/host/dw_mmc.c > @@ -111,8 +111,7 @@ static const u8 tuning_blk_pattern_8bit[] = { > 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, > }; > > -static inline bool dw_mci_fifo_reset(struct dw_mci *host); > -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host); > +static bool dw_mci_reset(struct dw_mci *host); > > #if defined(CONFIG_DEBUG_FS) > static int dw_mci_req_show(struct seq_file *s, void *v) > @@ -1254,7 +1253,7 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) > * After an error, there may be data lingering > * in the FIFO > */ > - dw_mci_fifo_reset(host); > + dw_mci_reset(host); > } else { > data->bytes_xfered = data->blocks * data->blksz; > data->error = 0; > @@ -1371,7 +1370,7 @@ static void dw_mci_tasklet_func(unsigned long priv) > > /* CMD error in data command */ > if (mrq->cmd->error && mrq->data) > - dw_mci_fifo_reset(host); > + dw_mci_reset(host); > > host->cmd = NULL; > host->data = NULL; > @@ -1982,14 +1981,8 @@ static void dw_mci_work_routine_card(struct work_struct *work) > } > > /* Power down slot */ > - if (present == 0) { > - /* Clear down the FIFO */ > - dw_mci_fifo_reset(host); > -#ifdef CONFIG_MMC_DW_IDMAC > - dw_mci_idmac_reset(host); > -#endif > - > - } > + if (present == 0) > + dw_mci_reset(host); > > spin_unlock_bh(&host->lock); > > @@ -2323,8 +2316,11 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) > return false; > } > > -static inline bool dw_mci_fifo_reset(struct dw_mci *host) > +static bool dw_mci_reset(struct dw_mci *host) > { > + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; > + bool ret = false; > + > /* > * Reseting generates a block interrupt, hence setting > * the scatter-gather pointer to NULL. > @@ -2334,15 +2330,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) > host->sg = NULL; > } > > - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > -} > + if (host->use_dma) > + flags |= SDMMC_CTRL_DMA_RESET; > > -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) > -{ > - return dw_mci_ctrl_reset(host, > - SDMMC_CTRL_FIFO_RESET | > - SDMMC_CTRL_RESET | > - SDMMC_CTRL_DMA_RESET); > + if (dw_mci_ctrl_reset(host, flags)) { > + /* > + * In all cases we clear the RAWINTS register to clear any > + * interrupts. > + */ > + mci_writel(host, RINTSTS, 0xFFFFFFFF); > + > + /* if using dma we wait for dma_req to clear */ > + if (host->use_dma) { > + unsigned long timeout = jiffies + msecs_to_jiffies(500); > + u32 status; > + do { > + status = mci_readl(host, STATUS); > + if (!(status & SDMMC_STATUS_DMA_REQ)) > + break; > + cpu_relax(); > + } while (time_before(jiffies, timeout)); > + > + if (status & SDMMC_STATUS_DMA_REQ) { > + dev_err(host->dev, > + "%s: Timeout waiting for dma_req to " > + "clear during reset\n", __func__); > + goto ciu_out; > + } > + > + /* when using DMA next we reset the fifo again */ > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) > + goto ciu_out; > + } > + } else { > + /* if the controller reset bit did clear, then set clock regs */ > + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { > + dev_err(host->dev, "%s: fifo/dma reset bits didn't " > + "clear but ciu was reset, doing clock update\n", > + __func__); > + goto ciu_out; > + } > + } > + > + if (IS_ENABLED(CONFIG_MMC_DW_IDMAC)) > + /* It is also recommended that we reset and reprogram idmac */ > + dw_mci_idmac_reset(host); > + > + ret = true; > + > +ciu_out: > + /* After a CTRL reset we need to have CIU set clock registers */ > + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); > + > + return ret; > } > > #ifdef CONFIG_OF > @@ -2555,7 +2595,7 @@ int dw_mci_probe(struct dw_mci *host) > } > > /* Reset all blocks */ > - if (!dw_mci_ctrl_all_reset(host)) > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) > return -ENODEV; > > host->dma_ops = host->pdata->dma_ops; > @@ -2744,7 +2784,7 @@ int dw_mci_resume(struct dw_mci *host) > } > } > > - if (!dw_mci_ctrl_all_reset(host)) { > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) { > ret = -ENODEV; > return ret; > } > diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h > index 6bf24ab..9ab8ccd 100644 > --- a/drivers/mmc/host/dw_mmc.h > +++ b/drivers/mmc/host/dw_mmc.h > @@ -129,6 +129,7 @@ > #define SDMMC_CMD_INDX(n) ((n) & 0x1F) > /* Status register defines */ > #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) > +#define SDMMC_STATUS_DMA_REQ BIT(31) > /* FIFOTH register defines */ > #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ > ((r) & 0xFFF) << 16 | \ > @@ -150,6 +151,10 @@ > /* Card read threshold */ > #define SDMMC_SET_RD_THLD(v, x) (((v) & 0x1FFF) << 16 | (x)) > > +/* All ctrl reset bits */ > +#define SDMMC_CTRL_ALL_RESET_FLAGS \ > + (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET) > + > /* Register access macros */ > #define mci_readl(dev, reg) \ > __raw_readl((dev)->regs + SDMMC_##reg) > -- > 2.0.0.526.g5318336 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCHv6] mmc: dw_mmc: change to use recommended reset procedure @ 2014-07-18 13:37 ` Seungwon Jeon 0 siblings, 0 replies; 75+ messages in thread From: Seungwon Jeon @ 2014-07-18 13:37 UTC (permalink / raw) To: linux-arm-kernel On Tue, July 15, 2014, Sonny Rao wrote: > 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> Thanks, Seungwon Jeon > --- > v2: Add Generic DMA support > per the documentation, move interrupt clear before wait > make the test for DMA host->use_dma rather than host->using_dma > add proper return values (although it appears no caller checks) > v3: rename fifo reset function, and change callers > use this combined reset function in dw_mci_resume() > just one caller left (probe), so get rid of dw_mci_ctrl_all_reset() > use DMA reset bit for all systems which use DMA > remove extra IDMAC reset in dw_mci_work_routine_card() > do CIU clock update in error path, if CIU reset cleared > v4: remove comment about FIFO reset in dw_mci_work_routine_card() > move down error message when control reset clears but others don't > and clarify the error stating that we will still update clocks > make flags for all reset bits a macro > v5: don't use dw_mci_reset() in dw_mci_resume() and instead match what > is done in dw_mci_probe() and don't force inline dw_mci_resume() > v6: add newlines to dev_err() messages > --- > drivers/mmc/host/dw_mmc.c | 86 ++++++++++++++++++++++++++++++++++------------- > drivers/mmc/host/dw_mmc.h | 5 +++ > 2 files changed, 68 insertions(+), 23 deletions(-) > > diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c > index 55cd110..0c0aecb 100644 > --- a/drivers/mmc/host/dw_mmc.c > +++ b/drivers/mmc/host/dw_mmc.c > @@ -111,8 +111,7 @@ static const u8 tuning_blk_pattern_8bit[] = { > 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, > }; > > -static inline bool dw_mci_fifo_reset(struct dw_mci *host); > -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host); > +static bool dw_mci_reset(struct dw_mci *host); > > #if defined(CONFIG_DEBUG_FS) > static int dw_mci_req_show(struct seq_file *s, void *v) > @@ -1254,7 +1253,7 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) > * After an error, there may be data lingering > * in the FIFO > */ > - dw_mci_fifo_reset(host); > + dw_mci_reset(host); > } else { > data->bytes_xfered = data->blocks * data->blksz; > data->error = 0; > @@ -1371,7 +1370,7 @@ static void dw_mci_tasklet_func(unsigned long priv) > > /* CMD error in data command */ > if (mrq->cmd->error && mrq->data) > - dw_mci_fifo_reset(host); > + dw_mci_reset(host); > > host->cmd = NULL; > host->data = NULL; > @@ -1982,14 +1981,8 @@ static void dw_mci_work_routine_card(struct work_struct *work) > } > > /* Power down slot */ > - if (present == 0) { > - /* Clear down the FIFO */ > - dw_mci_fifo_reset(host); > -#ifdef CONFIG_MMC_DW_IDMAC > - dw_mci_idmac_reset(host); > -#endif > - > - } > + if (present == 0) > + dw_mci_reset(host); > > spin_unlock_bh(&host->lock); > > @@ -2323,8 +2316,11 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) > return false; > } > > -static inline bool dw_mci_fifo_reset(struct dw_mci *host) > +static bool dw_mci_reset(struct dw_mci *host) > { > + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; > + bool ret = false; > + > /* > * Reseting generates a block interrupt, hence setting > * the scatter-gather pointer to NULL. > @@ -2334,15 +2330,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) > host->sg = NULL; > } > > - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > -} > + if (host->use_dma) > + flags |= SDMMC_CTRL_DMA_RESET; > > -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) > -{ > - return dw_mci_ctrl_reset(host, > - SDMMC_CTRL_FIFO_RESET | > - SDMMC_CTRL_RESET | > - SDMMC_CTRL_DMA_RESET); > + if (dw_mci_ctrl_reset(host, flags)) { > + /* > + * In all cases we clear the RAWINTS register to clear any > + * interrupts. > + */ > + mci_writel(host, RINTSTS, 0xFFFFFFFF); > + > + /* if using dma we wait for dma_req to clear */ > + if (host->use_dma) { > + unsigned long timeout = jiffies + msecs_to_jiffies(500); > + u32 status; > + do { > + status = mci_readl(host, STATUS); > + if (!(status & SDMMC_STATUS_DMA_REQ)) > + break; > + cpu_relax(); > + } while (time_before(jiffies, timeout)); > + > + if (status & SDMMC_STATUS_DMA_REQ) { > + dev_err(host->dev, > + "%s: Timeout waiting for dma_req to " > + "clear during reset\n", __func__); > + goto ciu_out; > + } > + > + /* when using DMA next we reset the fifo again */ > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) > + goto ciu_out; > + } > + } else { > + /* if the controller reset bit did clear, then set clock regs */ > + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { > + dev_err(host->dev, "%s: fifo/dma reset bits didn't " > + "clear but ciu was reset, doing clock update\n", > + __func__); > + goto ciu_out; > + } > + } > + > + if (IS_ENABLED(CONFIG_MMC_DW_IDMAC)) > + /* It is also recommended that we reset and reprogram idmac */ > + dw_mci_idmac_reset(host); > + > + ret = true; > + > +ciu_out: > + /* After a CTRL reset we need to have CIU set clock registers */ > + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); > + > + return ret; > } > > #ifdef CONFIG_OF > @@ -2555,7 +2595,7 @@ int dw_mci_probe(struct dw_mci *host) > } > > /* Reset all blocks */ > - if (!dw_mci_ctrl_all_reset(host)) > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) > return -ENODEV; > > host->dma_ops = host->pdata->dma_ops; > @@ -2744,7 +2784,7 @@ int dw_mci_resume(struct dw_mci *host) > } > } > > - if (!dw_mci_ctrl_all_reset(host)) { > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) { > ret = -ENODEV; > return ret; > } > diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h > index 6bf24ab..9ab8ccd 100644 > --- a/drivers/mmc/host/dw_mmc.h > +++ b/drivers/mmc/host/dw_mmc.h > @@ -129,6 +129,7 @@ > #define SDMMC_CMD_INDX(n) ((n) & 0x1F) > /* Status register defines */ > #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) > +#define SDMMC_STATUS_DMA_REQ BIT(31) > /* FIFOTH register defines */ > #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ > ((r) & 0xFFF) << 16 | \ > @@ -150,6 +151,10 @@ > /* Card read threshold */ > #define SDMMC_SET_RD_THLD(v, x) (((v) & 0x1FFF) << 16 | (x)) > > +/* All ctrl reset bits */ > +#define SDMMC_CTRL_ALL_RESET_FLAGS \ > + (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET) > + > /* Register access macros */ > #define mci_readl(dev, reg) \ > __raw_readl((dev)->regs + SDMMC_##reg) > -- > 2.0.0.526.g5318336 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > the body of a message to majordomo at vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCHv6] mmc: dw_mmc: change to use recommended reset procedure 2014-07-14 22:06 ` Sonny Rao @ 2014-07-26 9:55 ` Ulf Hansson -1 siblings, 0 replies; 75+ messages in thread From: Ulf Hansson @ 2014-07-26 9:55 UTC (permalink / raw) To: Sonny Rao Cc: linux-mmc, Grant Grundler, linux-samsung-soc, linux-arm-kernel, Jaehoon Chung, Chris Ball, tgih.jun, Kukjin Kim, sunil joshi, Tomasz Figa, Doug Anderson, Yuvaraj Kumar C D On 15 July 2014 00:06, Sonny Rao <sonnyrao@chromium.org> wrote: > 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> Thanks! Applied for next. Kind regards Uffe > --- > v2: Add Generic DMA support > per the documentation, move interrupt clear before wait > make the test for DMA host->use_dma rather than host->using_dma > add proper return values (although it appears no caller checks) > v3: rename fifo reset function, and change callers > use this combined reset function in dw_mci_resume() > just one caller left (probe), so get rid of dw_mci_ctrl_all_reset() > use DMA reset bit for all systems which use DMA > remove extra IDMAC reset in dw_mci_work_routine_card() > do CIU clock update in error path, if CIU reset cleared > v4: remove comment about FIFO reset in dw_mci_work_routine_card() > move down error message when control reset clears but others don't > and clarify the error stating that we will still update clocks > make flags for all reset bits a macro > v5: don't use dw_mci_reset() in dw_mci_resume() and instead match what > is done in dw_mci_probe() and don't force inline dw_mci_resume() > v6: add newlines to dev_err() messages > --- > drivers/mmc/host/dw_mmc.c | 86 ++++++++++++++++++++++++++++++++++------------- > drivers/mmc/host/dw_mmc.h | 5 +++ > 2 files changed, 68 insertions(+), 23 deletions(-) > > diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c > index 55cd110..0c0aecb 100644 > --- a/drivers/mmc/host/dw_mmc.c > +++ b/drivers/mmc/host/dw_mmc.c > @@ -111,8 +111,7 @@ static const u8 tuning_blk_pattern_8bit[] = { > 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, > }; > > -static inline bool dw_mci_fifo_reset(struct dw_mci *host); > -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host); > +static bool dw_mci_reset(struct dw_mci *host); > > #if defined(CONFIG_DEBUG_FS) > static int dw_mci_req_show(struct seq_file *s, void *v) > @@ -1254,7 +1253,7 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) > * After an error, there may be data lingering > * in the FIFO > */ > - dw_mci_fifo_reset(host); > + dw_mci_reset(host); > } else { > data->bytes_xfered = data->blocks * data->blksz; > data->error = 0; > @@ -1371,7 +1370,7 @@ static void dw_mci_tasklet_func(unsigned long priv) > > /* CMD error in data command */ > if (mrq->cmd->error && mrq->data) > - dw_mci_fifo_reset(host); > + dw_mci_reset(host); > > host->cmd = NULL; > host->data = NULL; > @@ -1982,14 +1981,8 @@ static void dw_mci_work_routine_card(struct work_struct *work) > } > > /* Power down slot */ > - if (present == 0) { > - /* Clear down the FIFO */ > - dw_mci_fifo_reset(host); > -#ifdef CONFIG_MMC_DW_IDMAC > - dw_mci_idmac_reset(host); > -#endif > - > - } > + if (present == 0) > + dw_mci_reset(host); > > spin_unlock_bh(&host->lock); > > @@ -2323,8 +2316,11 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) > return false; > } > > -static inline bool dw_mci_fifo_reset(struct dw_mci *host) > +static bool dw_mci_reset(struct dw_mci *host) > { > + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; > + bool ret = false; > + > /* > * Reseting generates a block interrupt, hence setting > * the scatter-gather pointer to NULL. > @@ -2334,15 +2330,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) > host->sg = NULL; > } > > - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > -} > + if (host->use_dma) > + flags |= SDMMC_CTRL_DMA_RESET; > > -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) > -{ > - return dw_mci_ctrl_reset(host, > - SDMMC_CTRL_FIFO_RESET | > - SDMMC_CTRL_RESET | > - SDMMC_CTRL_DMA_RESET); > + if (dw_mci_ctrl_reset(host, flags)) { > + /* > + * In all cases we clear the RAWINTS register to clear any > + * interrupts. > + */ > + mci_writel(host, RINTSTS, 0xFFFFFFFF); > + > + /* if using dma we wait for dma_req to clear */ > + if (host->use_dma) { > + unsigned long timeout = jiffies + msecs_to_jiffies(500); > + u32 status; > + do { > + status = mci_readl(host, STATUS); > + if (!(status & SDMMC_STATUS_DMA_REQ)) > + break; > + cpu_relax(); > + } while (time_before(jiffies, timeout)); > + > + if (status & SDMMC_STATUS_DMA_REQ) { > + dev_err(host->dev, > + "%s: Timeout waiting for dma_req to " > + "clear during reset\n", __func__); > + goto ciu_out; > + } > + > + /* when using DMA next we reset the fifo again */ > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) > + goto ciu_out; > + } > + } else { > + /* if the controller reset bit did clear, then set clock regs */ > + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { > + dev_err(host->dev, "%s: fifo/dma reset bits didn't " > + "clear but ciu was reset, doing clock update\n", > + __func__); > + goto ciu_out; > + } > + } > + > + if (IS_ENABLED(CONFIG_MMC_DW_IDMAC)) > + /* It is also recommended that we reset and reprogram idmac */ > + dw_mci_idmac_reset(host); > + > + ret = true; > + > +ciu_out: > + /* After a CTRL reset we need to have CIU set clock registers */ > + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); > + > + return ret; > } > > #ifdef CONFIG_OF > @@ -2555,7 +2595,7 @@ int dw_mci_probe(struct dw_mci *host) > } > > /* Reset all blocks */ > - if (!dw_mci_ctrl_all_reset(host)) > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) > return -ENODEV; > > host->dma_ops = host->pdata->dma_ops; > @@ -2744,7 +2784,7 @@ int dw_mci_resume(struct dw_mci *host) > } > } > > - if (!dw_mci_ctrl_all_reset(host)) { > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) { > ret = -ENODEV; > return ret; > } > diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h > index 6bf24ab..9ab8ccd 100644 > --- a/drivers/mmc/host/dw_mmc.h > +++ b/drivers/mmc/host/dw_mmc.h > @@ -129,6 +129,7 @@ > #define SDMMC_CMD_INDX(n) ((n) & 0x1F) > /* Status register defines */ > #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) > +#define SDMMC_STATUS_DMA_REQ BIT(31) > /* FIFOTH register defines */ > #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ > ((r) & 0xFFF) << 16 | \ > @@ -150,6 +151,10 @@ > /* Card read threshold */ > #define SDMMC_SET_RD_THLD(v, x) (((v) & 0x1FFF) << 16 | (x)) > > +/* All ctrl reset bits */ > +#define SDMMC_CTRL_ALL_RESET_FLAGS \ > + (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET) > + > /* Register access macros */ > #define mci_readl(dev, reg) \ > __raw_readl((dev)->regs + SDMMC_##reg) > -- > 2.0.0.526.g5318336 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCHv6] mmc: dw_mmc: change to use recommended reset procedure @ 2014-07-26 9:55 ` Ulf Hansson 0 siblings, 0 replies; 75+ messages in thread From: Ulf Hansson @ 2014-07-26 9:55 UTC (permalink / raw) To: linux-arm-kernel On 15 July 2014 00:06, Sonny Rao <sonnyrao@chromium.org> wrote: > 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> Thanks! Applied for next. Kind regards Uffe > --- > v2: Add Generic DMA support > per the documentation, move interrupt clear before wait > make the test for DMA host->use_dma rather than host->using_dma > add proper return values (although it appears no caller checks) > v3: rename fifo reset function, and change callers > use this combined reset function in dw_mci_resume() > just one caller left (probe), so get rid of dw_mci_ctrl_all_reset() > use DMA reset bit for all systems which use DMA > remove extra IDMAC reset in dw_mci_work_routine_card() > do CIU clock update in error path, if CIU reset cleared > v4: remove comment about FIFO reset in dw_mci_work_routine_card() > move down error message when control reset clears but others don't > and clarify the error stating that we will still update clocks > make flags for all reset bits a macro > v5: don't use dw_mci_reset() in dw_mci_resume() and instead match what > is done in dw_mci_probe() and don't force inline dw_mci_resume() > v6: add newlines to dev_err() messages > --- > drivers/mmc/host/dw_mmc.c | 86 ++++++++++++++++++++++++++++++++++------------- > drivers/mmc/host/dw_mmc.h | 5 +++ > 2 files changed, 68 insertions(+), 23 deletions(-) > > diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c > index 55cd110..0c0aecb 100644 > --- a/drivers/mmc/host/dw_mmc.c > +++ b/drivers/mmc/host/dw_mmc.c > @@ -111,8 +111,7 @@ static const u8 tuning_blk_pattern_8bit[] = { > 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, > }; > > -static inline bool dw_mci_fifo_reset(struct dw_mci *host); > -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host); > +static bool dw_mci_reset(struct dw_mci *host); > > #if defined(CONFIG_DEBUG_FS) > static int dw_mci_req_show(struct seq_file *s, void *v) > @@ -1254,7 +1253,7 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) > * After an error, there may be data lingering > * in the FIFO > */ > - dw_mci_fifo_reset(host); > + dw_mci_reset(host); > } else { > data->bytes_xfered = data->blocks * data->blksz; > data->error = 0; > @@ -1371,7 +1370,7 @@ static void dw_mci_tasklet_func(unsigned long priv) > > /* CMD error in data command */ > if (mrq->cmd->error && mrq->data) > - dw_mci_fifo_reset(host); > + dw_mci_reset(host); > > host->cmd = NULL; > host->data = NULL; > @@ -1982,14 +1981,8 @@ static void dw_mci_work_routine_card(struct work_struct *work) > } > > /* Power down slot */ > - if (present == 0) { > - /* Clear down the FIFO */ > - dw_mci_fifo_reset(host); > -#ifdef CONFIG_MMC_DW_IDMAC > - dw_mci_idmac_reset(host); > -#endif > - > - } > + if (present == 0) > + dw_mci_reset(host); > > spin_unlock_bh(&host->lock); > > @@ -2323,8 +2316,11 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) > return false; > } > > -static inline bool dw_mci_fifo_reset(struct dw_mci *host) > +static bool dw_mci_reset(struct dw_mci *host) > { > + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; > + bool ret = false; > + > /* > * Reseting generates a block interrupt, hence setting > * the scatter-gather pointer to NULL. > @@ -2334,15 +2330,59 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) > host->sg = NULL; > } > > - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > -} > + if (host->use_dma) > + flags |= SDMMC_CTRL_DMA_RESET; > > -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) > -{ > - return dw_mci_ctrl_reset(host, > - SDMMC_CTRL_FIFO_RESET | > - SDMMC_CTRL_RESET | > - SDMMC_CTRL_DMA_RESET); > + if (dw_mci_ctrl_reset(host, flags)) { > + /* > + * In all cases we clear the RAWINTS register to clear any > + * interrupts. > + */ > + mci_writel(host, RINTSTS, 0xFFFFFFFF); > + > + /* if using dma we wait for dma_req to clear */ > + if (host->use_dma) { > + unsigned long timeout = jiffies + msecs_to_jiffies(500); > + u32 status; > + do { > + status = mci_readl(host, STATUS); > + if (!(status & SDMMC_STATUS_DMA_REQ)) > + break; > + cpu_relax(); > + } while (time_before(jiffies, timeout)); > + > + if (status & SDMMC_STATUS_DMA_REQ) { > + dev_err(host->dev, > + "%s: Timeout waiting for dma_req to " > + "clear during reset\n", __func__); > + goto ciu_out; > + } > + > + /* when using DMA next we reset the fifo again */ > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) > + goto ciu_out; > + } > + } else { > + /* if the controller reset bit did clear, then set clock regs */ > + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { > + dev_err(host->dev, "%s: fifo/dma reset bits didn't " > + "clear but ciu was reset, doing clock update\n", > + __func__); > + goto ciu_out; > + } > + } > + > + if (IS_ENABLED(CONFIG_MMC_DW_IDMAC)) > + /* It is also recommended that we reset and reprogram idmac */ > + dw_mci_idmac_reset(host); > + > + ret = true; > + > +ciu_out: > + /* After a CTRL reset we need to have CIU set clock registers */ > + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); > + > + return ret; > } > > #ifdef CONFIG_OF > @@ -2555,7 +2595,7 @@ int dw_mci_probe(struct dw_mci *host) > } > > /* Reset all blocks */ > - if (!dw_mci_ctrl_all_reset(host)) > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) > return -ENODEV; > > host->dma_ops = host->pdata->dma_ops; > @@ -2744,7 +2784,7 @@ int dw_mci_resume(struct dw_mci *host) > } > } > > - if (!dw_mci_ctrl_all_reset(host)) { > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) { > ret = -ENODEV; > return ret; > } > diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h > index 6bf24ab..9ab8ccd 100644 > --- a/drivers/mmc/host/dw_mmc.h > +++ b/drivers/mmc/host/dw_mmc.h > @@ -129,6 +129,7 @@ > #define SDMMC_CMD_INDX(n) ((n) & 0x1F) > /* Status register defines */ > #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) > +#define SDMMC_STATUS_DMA_REQ BIT(31) > /* FIFOTH register defines */ > #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ > ((r) & 0xFFF) << 16 | \ > @@ -150,6 +151,10 @@ > /* Card read threshold */ > #define SDMMC_SET_RD_THLD(v, x) (((v) & 0x1FFF) << 16 | (x)) > > +/* All ctrl reset bits */ > +#define SDMMC_CTRL_ALL_RESET_FLAGS \ > + (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET) > + > /* Register access macros */ > #define mci_readl(dev, reg) \ > __raw_readl((dev)->regs + SDMMC_##reg) > -- > 2.0.0.526.g5318336 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > the body of a message to majordomo at vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 75+ messages in thread
* RE: [PATCHv2] mmc: dw_mmc: change to use recommended reset procedure 2014-05-13 1:38 ` Sonny Rao @ 2014-05-13 5:19 ` Kukjin Kim -1 siblings, 0 replies; 75+ messages in thread From: Kukjin Kim @ 2014-05-13 5:19 UTC (permalink / raw) To: 'Sonny Rao', linux-mmc Cc: grundler, linux-samsung-soc, linux-arm-kernel, jh80.chung, cjb, tgih.jun, joshi, t.figa, dianders, 'Yuvaraj Kumar C D' Sonny Rao wrote: > > This patch changes the fifo reset code to follow the reset procedure > outlined in the documentation of Synopsys Mobile storage host databook > 7.2.13. > > v2: Add Generic DMA support > per the documentation, move interrupt clear before wait > make the test for DMA host->use_dma rather than host->using_dma > add proper return values (although it appears no caller checks) Above changes should be put after following '---'. > > Signed-off-by: Sonny Rao <sonnyrao@chromium.org> > Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.com> > --- Here. - Kukjin > drivers/mmc/host/dw_mmc.c | 55 > ++++++++++++++++++++++++++++++++++++++++++++++- > drivers/mmc/host/dw_mmc.h | 1 + > 2 files changed, 55 insertions(+), 1 deletion(-) ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCHv2] mmc: dw_mmc: change to use recommended reset procedure @ 2014-05-13 5:19 ` Kukjin Kim 0 siblings, 0 replies; 75+ messages in thread From: Kukjin Kim @ 2014-05-13 5:19 UTC (permalink / raw) To: linux-arm-kernel Sonny Rao wrote: > > This patch changes the fifo reset code to follow the reset procedure > outlined in the documentation of Synopsys Mobile storage host databook > 7.2.13. > > v2: Add Generic DMA support > per the documentation, move interrupt clear before wait > make the test for DMA host->use_dma rather than host->using_dma > add proper return values (although it appears no caller checks) Above changes should be put after following '---'. > > Signed-off-by: Sonny Rao <sonnyrao@chromium.org> > Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.com> > --- Here. - Kukjin > drivers/mmc/host/dw_mmc.c | 55 > ++++++++++++++++++++++++++++++++++++++++++++++- > drivers/mmc/host/dw_mmc.h | 1 + > 2 files changed, 55 insertions(+), 1 deletion(-) ^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCHv2] mmc: dw_mmc: change to use recommended reset procedure 2014-05-13 1:38 ` Sonny Rao @ 2014-05-13 8:46 ` Arnd Bergmann -1 siblings, 0 replies; 75+ messages in thread From: Arnd Bergmann @ 2014-05-13 8:46 UTC (permalink / raw) To: linux-arm-kernel Cc: Yuvaraj Kumar C D, linux-samsung-soc, grundler, t.figa, linux-mmc, joshi, dianders, jh80.chung, tgih.jun, kgene.kim, cjb, Sonny Rao On Monday 12 May 2014 18:38:41 Sonny Rao wrote: > +#ifndef CONFIG_MMC_DW_IDMAC > + if (host->use_dma) > + flags |= SDMMC_CTRL_DMA_RESET; > +#endif Can you change the above like this? if (IS_ENABLED(CONFIG_MMC_DW_IDMAC) && host->use_dma) flags |= SDMMC_CTRL_DMA_RESET; That is generally considered the preferred style these days. Arnd ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCHv2] mmc: dw_mmc: change to use recommended reset procedure @ 2014-05-13 8:46 ` Arnd Bergmann 0 siblings, 0 replies; 75+ messages in thread From: Arnd Bergmann @ 2014-05-13 8:46 UTC (permalink / raw) To: linux-arm-kernel On Monday 12 May 2014 18:38:41 Sonny Rao wrote: > +#ifndef CONFIG_MMC_DW_IDMAC > + if (host->use_dma) > + flags |= SDMMC_CTRL_DMA_RESET; > +#endif Can you change the above like this? if (IS_ENABLED(CONFIG_MMC_DW_IDMAC) && host->use_dma) flags |= SDMMC_CTRL_DMA_RESET; That is generally considered the preferred style these days. Arnd ^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: linux-next: build failure after merge of the mmc-uh tree @ 2014-08-04 13:44 Ulf Hansson 2014-08-05 1:19 ` Sonny Rao 0 siblings, 1 reply; 75+ messages in thread From: Ulf Hansson @ 2014-08-04 13:44 UTC (permalink / raw) To: Sonny Rao; +Cc: Stephen Rothwell, linux-next, linux-kernel On 28 July 2014 19:58, Sonny Rao <sonnyrao@chromium.org> wrote: > On Sun, Jul 27, 2014 at 9:46 PM, Stephen Rothwell <sfr@canb.auug.org.au> wrote: >> Hi Ulf, >> >> After merging the mmc-uh tree, today's linux-next build (arm >> multi_v7_defconfig) failed like this: >> >> drivers/mmc/host/dw_mmc.c: In function 'dw_mci_reset': >> drivers/mmc/host/dw_mmc.c:2262:3: error: implicit declaration of function 'dw_mci_idmac_reset' [-Werror=implicit-function-declaration] >> dw_mci_idmac_reset(host); >> ^ > > Hi, sorry about that. It looks like it fails to build when > CONFIG_MMC_DW_IDMAC is not set. > I changed that bit of code from using #ifdef to using just C if > statement, but I think in this case the function being called doesn't > exist when CONFIG_MMC_DW_IDMAC is not set, so that was incorrect and > we should go back to using something like: > > #if IS_ENABLED(CONFIG_MMC_DW_IDMAC) > /* It is also recommended that we reset and reprogram idmac */ > dw_mci_idmac_reset(host); > #endif > > > Ulf, I can respin the patch if you'd like or feel free to fix it > yourself too. Thanks. I haven't got the time to fix this yet, sorry. It would simplify a bit if you respin the patch, so please do so. Kind regards Uffe > > >> >> Caused by commit 25f7dadbd982 ("mmc: dw_mmc: change to use recommended >> reset procedure"). >> >> I have used the mmc-uh tree from next-20140725 for today. >> -- >> Cheers, >> Stephen Rothwell sfr@canb.auug.org.au ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCH] mmc: dw_mmc: change to use recommended reset procedure 2014-08-04 13:44 linux-next: build failure after merge of the mmc-uh tree Ulf Hansson @ 2014-08-05 1:19 ` Sonny Rao 0 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-08-05 1:19 UTC (permalink / raw) To: Ulf Hansson Cc: linux-mmc, linux-next, grundler, linux-samsung-soc, linux-kernel, Stephen Rothwell, linux-arm-kernel, jh80.chung, cjb, tgih.jun, kgene.kim, joshi, t.figa, dianders, Yuvaraj Kumar C D, Sonny Rao 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> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> [sonnyrao: fix compile for !CONFIG_MMC_DW_IDMAC case] --- drivers/mmc/host/dw_mmc.c | 87 ++++++++++++++++++++++++++++++++++------------- drivers/mmc/host/dw_mmc.h | 5 +++ 2 files changed, 69 insertions(+), 23 deletions(-) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 1ac227c..39cf54f 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -111,8 +111,7 @@ static const u8 tuning_blk_pattern_8bit[] = { 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, }; -static inline bool dw_mci_fifo_reset(struct dw_mci *host); -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host); +static bool dw_mci_reset(struct dw_mci *host); #if defined(CONFIG_DEBUG_FS) static int dw_mci_req_show(struct seq_file *s, void *v) @@ -1235,7 +1234,7 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) * After an error, there may be data lingering * in the FIFO */ - dw_mci_fifo_reset(host); + dw_mci_reset(host); } else { data->bytes_xfered = data->blocks * data->blksz; data->error = 0; @@ -1352,7 +1351,7 @@ static void dw_mci_tasklet_func(unsigned long priv) /* CMD error in data command */ if (mrq->cmd->error && mrq->data) - dw_mci_fifo_reset(host); + dw_mci_reset(host); host->cmd = NULL; host->data = NULL; @@ -1963,14 +1962,8 @@ static void dw_mci_work_routine_card(struct work_struct *work) } /* Power down slot */ - if (present == 0) { - /* Clear down the FIFO */ - dw_mci_fifo_reset(host); -#ifdef CONFIG_MMC_DW_IDMAC - dw_mci_idmac_reset(host); -#endif - - } + if (present == 0) + dw_mci_reset(host); spin_unlock_bh(&host->lock); @@ -2208,8 +2201,11 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) return false; } -static inline bool dw_mci_fifo_reset(struct dw_mci *host) +static bool dw_mci_reset(struct dw_mci *host) { + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; + bool ret = false; + /* * Reseting generates a block interrupt, hence setting * the scatter-gather pointer to NULL. @@ -2219,15 +2215,60 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) host->sg = NULL; } - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); -} + if (host->use_dma) + flags |= SDMMC_CTRL_DMA_RESET; -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) -{ - return dw_mci_ctrl_reset(host, - SDMMC_CTRL_FIFO_RESET | - SDMMC_CTRL_RESET | - SDMMC_CTRL_DMA_RESET); + if (dw_mci_ctrl_reset(host, flags)) { + /* + * In all cases we clear the RAWINTS register to clear any + * interrupts. + */ + mci_writel(host, RINTSTS, 0xFFFFFFFF); + + /* if using dma we wait for dma_req to clear */ + if (host->use_dma) { + unsigned long timeout = jiffies + msecs_to_jiffies(500); + u32 status; + do { + status = mci_readl(host, STATUS); + if (!(status & SDMMC_STATUS_DMA_REQ)) + break; + cpu_relax(); + } while (time_before(jiffies, timeout)); + + if (status & SDMMC_STATUS_DMA_REQ) { + dev_err(host->dev, + "%s: Timeout waiting for dma_req to " + "clear during reset\n", __func__); + goto ciu_out; + } + + /* when using DMA next we reset the fifo again */ + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) + goto ciu_out; + } + } else { + /* if the controller reset bit did clear, then set clock regs */ + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { + dev_err(host->dev, "%s: fifo/dma reset bits didn't " + "clear but ciu was reset, doing clock update\n", + __func__); + goto ciu_out; + } + } + +#if IS_ENABLED(CONFIG_MMC_DW_IDMAC) + /* It is also recommended that we reset and reprogram idmac */ + dw_mci_idmac_reset(host); +#endif + + ret = true; + +ciu_out: + /* After a CTRL reset we need to have CIU set clock registers */ + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); + + return ret; } #ifdef CONFIG_OF @@ -2425,7 +2466,7 @@ int dw_mci_probe(struct dw_mci *host) } /* Reset all blocks */ - if (!dw_mci_ctrl_all_reset(host)) + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) return -ENODEV; host->dma_ops = host->pdata->dma_ops; @@ -2612,7 +2653,7 @@ int dw_mci_resume(struct dw_mci *host) } } - if (!dw_mci_ctrl_all_reset(host)) { + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) { ret = -ENODEV; return ret; } diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 738fa24..08fd956 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -129,6 +129,7 @@ #define SDMMC_CMD_INDX(n) ((n) & 0x1F) /* Status register defines */ #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) +#define SDMMC_STATUS_DMA_REQ BIT(31) /* FIFOTH register defines */ #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ ((r) & 0xFFF) << 16 | \ @@ -150,6 +151,10 @@ /* Card read threshold */ #define SDMMC_SET_RD_THLD(v, x) (((v) & 0x1FFF) << 16 | (x)) +/* All ctrl reset bits */ +#define SDMMC_CTRL_ALL_RESET_FLAGS \ + (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET) + /* Register access macros */ #define mci_readl(dev, reg) \ __raw_readl((dev)->regs + SDMMC_##reg) -- 1.8.3.2 ^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH] mmc: dw_mmc: change to use recommended reset procedure @ 2014-08-05 1:19 ` Sonny Rao 0 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-08-05 1:19 UTC (permalink / raw) To: linux-arm-kernel 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> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> [sonnyrao: fix compile for !CONFIG_MMC_DW_IDMAC case] --- drivers/mmc/host/dw_mmc.c | 87 ++++++++++++++++++++++++++++++++++------------- drivers/mmc/host/dw_mmc.h | 5 +++ 2 files changed, 69 insertions(+), 23 deletions(-) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 1ac227c..39cf54f 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -111,8 +111,7 @@ static const u8 tuning_blk_pattern_8bit[] = { 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, }; -static inline bool dw_mci_fifo_reset(struct dw_mci *host); -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host); +static bool dw_mci_reset(struct dw_mci *host); #if defined(CONFIG_DEBUG_FS) static int dw_mci_req_show(struct seq_file *s, void *v) @@ -1235,7 +1234,7 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) * After an error, there may be data lingering * in the FIFO */ - dw_mci_fifo_reset(host); + dw_mci_reset(host); } else { data->bytes_xfered = data->blocks * data->blksz; data->error = 0; @@ -1352,7 +1351,7 @@ static void dw_mci_tasklet_func(unsigned long priv) /* CMD error in data command */ if (mrq->cmd->error && mrq->data) - dw_mci_fifo_reset(host); + dw_mci_reset(host); host->cmd = NULL; host->data = NULL; @@ -1963,14 +1962,8 @@ static void dw_mci_work_routine_card(struct work_struct *work) } /* Power down slot */ - if (present == 0) { - /* Clear down the FIFO */ - dw_mci_fifo_reset(host); -#ifdef CONFIG_MMC_DW_IDMAC - dw_mci_idmac_reset(host); -#endif - - } + if (present == 0) + dw_mci_reset(host); spin_unlock_bh(&host->lock); @@ -2208,8 +2201,11 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) return false; } -static inline bool dw_mci_fifo_reset(struct dw_mci *host) +static bool dw_mci_reset(struct dw_mci *host) { + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; + bool ret = false; + /* * Reseting generates a block interrupt, hence setting * the scatter-gather pointer to NULL. @@ -2219,15 +2215,60 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) host->sg = NULL; } - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); -} + if (host->use_dma) + flags |= SDMMC_CTRL_DMA_RESET; -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) -{ - return dw_mci_ctrl_reset(host, - SDMMC_CTRL_FIFO_RESET | - SDMMC_CTRL_RESET | - SDMMC_CTRL_DMA_RESET); + if (dw_mci_ctrl_reset(host, flags)) { + /* + * In all cases we clear the RAWINTS register to clear any + * interrupts. + */ + mci_writel(host, RINTSTS, 0xFFFFFFFF); + + /* if using dma we wait for dma_req to clear */ + if (host->use_dma) { + unsigned long timeout = jiffies + msecs_to_jiffies(500); + u32 status; + do { + status = mci_readl(host, STATUS); + if (!(status & SDMMC_STATUS_DMA_REQ)) + break; + cpu_relax(); + } while (time_before(jiffies, timeout)); + + if (status & SDMMC_STATUS_DMA_REQ) { + dev_err(host->dev, + "%s: Timeout waiting for dma_req to " + "clear during reset\n", __func__); + goto ciu_out; + } + + /* when using DMA next we reset the fifo again */ + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) + goto ciu_out; + } + } else { + /* if the controller reset bit did clear, then set clock regs */ + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { + dev_err(host->dev, "%s: fifo/dma reset bits didn't " + "clear but ciu was reset, doing clock update\n", + __func__); + goto ciu_out; + } + } + +#if IS_ENABLED(CONFIG_MMC_DW_IDMAC) + /* It is also recommended that we reset and reprogram idmac */ + dw_mci_idmac_reset(host); +#endif + + ret = true; + +ciu_out: + /* After a CTRL reset we need to have CIU set clock registers */ + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); + + return ret; } #ifdef CONFIG_OF @@ -2425,7 +2466,7 @@ int dw_mci_probe(struct dw_mci *host) } /* Reset all blocks */ - if (!dw_mci_ctrl_all_reset(host)) + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) return -ENODEV; host->dma_ops = host->pdata->dma_ops; @@ -2612,7 +2653,7 @@ int dw_mci_resume(struct dw_mci *host) } } - if (!dw_mci_ctrl_all_reset(host)) { + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) { ret = -ENODEV; return ret; } diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 738fa24..08fd956 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -129,6 +129,7 @@ #define SDMMC_CMD_INDX(n) ((n) & 0x1F) /* Status register defines */ #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) +#define SDMMC_STATUS_DMA_REQ BIT(31) /* FIFOTH register defines */ #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ ((r) & 0xFFF) << 16 | \ @@ -150,6 +151,10 @@ /* Card read threshold */ #define SDMMC_SET_RD_THLD(v, x) (((v) & 0x1FFF) << 16 | (x)) +/* All ctrl reset bits */ +#define SDMMC_CTRL_ALL_RESET_FLAGS \ + (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET) + /* Register access macros */ #define mci_readl(dev, reg) \ __raw_readl((dev)->regs + SDMMC_##reg) -- 1.8.3.2 ^ permalink raw reply related [flat|nested] 75+ messages in thread
* Re: [PATCH] mmc: dw_mmc: change to use recommended reset procedure 2014-08-05 1:19 ` Sonny Rao @ 2014-08-07 8:40 ` Jaehoon Chung -1 siblings, 0 replies; 75+ messages in thread From: Jaehoon Chung @ 2014-08-07 8:40 UTC (permalink / raw) To: Sonny Rao, Ulf Hansson Cc: dianders, Stephen Rothwell, linux-samsung-soc, Yuvaraj Kumar C D, grundler, t.figa, linux-mmc, linux-kernel, joshi, jh80.chung, tgih.jun, linux-next, kgene.kim, cjb, linux-arm-kernel Hi, I remembered that this patch was pushed at Ulf's tree. Since dw_mci_idmac_reset() is located into #if CONFIG_MMC_DW_IDMAC, it occurred the compiler error. And it seems that didn't need to use "IS_ENABLED()" at there. Acked-by: Jaehoon Chung <jh80.chung@samsung.com> Best Regards, Jaehoon Chung On 08/05/2014 10:19 AM, Sonny Rao wrote: > 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> > Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> > [sonnyrao: fix compile for !CONFIG_MMC_DW_IDMAC case] > --- > drivers/mmc/host/dw_mmc.c | 87 ++++++++++++++++++++++++++++++++++------------- > drivers/mmc/host/dw_mmc.h | 5 +++ > 2 files changed, 69 insertions(+), 23 deletions(-) > > diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c > index 1ac227c..39cf54f 100644 > --- a/drivers/mmc/host/dw_mmc.c > +++ b/drivers/mmc/host/dw_mmc.c > @@ -111,8 +111,7 @@ static const u8 tuning_blk_pattern_8bit[] = { > 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, > }; > > -static inline bool dw_mci_fifo_reset(struct dw_mci *host); > -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host); > +static bool dw_mci_reset(struct dw_mci *host); > > #if defined(CONFIG_DEBUG_FS) > static int dw_mci_req_show(struct seq_file *s, void *v) > @@ -1235,7 +1234,7 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) > * After an error, there may be data lingering > * in the FIFO > */ > - dw_mci_fifo_reset(host); > + dw_mci_reset(host); > } else { > data->bytes_xfered = data->blocks * data->blksz; > data->error = 0; > @@ -1352,7 +1351,7 @@ static void dw_mci_tasklet_func(unsigned long priv) > > /* CMD error in data command */ > if (mrq->cmd->error && mrq->data) > - dw_mci_fifo_reset(host); > + dw_mci_reset(host); > > host->cmd = NULL; > host->data = NULL; > @@ -1963,14 +1962,8 @@ static void dw_mci_work_routine_card(struct work_struct *work) > } > > /* Power down slot */ > - if (present == 0) { > - /* Clear down the FIFO */ > - dw_mci_fifo_reset(host); > -#ifdef CONFIG_MMC_DW_IDMAC > - dw_mci_idmac_reset(host); > -#endif > - > - } > + if (present == 0) > + dw_mci_reset(host); > > spin_unlock_bh(&host->lock); > > @@ -2208,8 +2201,11 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) > return false; > } > > -static inline bool dw_mci_fifo_reset(struct dw_mci *host) > +static bool dw_mci_reset(struct dw_mci *host) > { > + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; > + bool ret = false; > + > /* > * Reseting generates a block interrupt, hence setting > * the scatter-gather pointer to NULL. > @@ -2219,15 +2215,60 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) > host->sg = NULL; > } > > - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > -} > + if (host->use_dma) > + flags |= SDMMC_CTRL_DMA_RESET; > > -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) > -{ > - return dw_mci_ctrl_reset(host, > - SDMMC_CTRL_FIFO_RESET | > - SDMMC_CTRL_RESET | > - SDMMC_CTRL_DMA_RESET); > + if (dw_mci_ctrl_reset(host, flags)) { > + /* > + * In all cases we clear the RAWINTS register to clear any > + * interrupts. > + */ > + mci_writel(host, RINTSTS, 0xFFFFFFFF); > + > + /* if using dma we wait for dma_req to clear */ > + if (host->use_dma) { > + unsigned long timeout = jiffies + msecs_to_jiffies(500); > + u32 status; > + do { > + status = mci_readl(host, STATUS); > + if (!(status & SDMMC_STATUS_DMA_REQ)) > + break; > + cpu_relax(); > + } while (time_before(jiffies, timeout)); > + > + if (status & SDMMC_STATUS_DMA_REQ) { > + dev_err(host->dev, > + "%s: Timeout waiting for dma_req to " > + "clear during reset\n", __func__); > + goto ciu_out; > + } > + > + /* when using DMA next we reset the fifo again */ > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) > + goto ciu_out; > + } > + } else { > + /* if the controller reset bit did clear, then set clock regs */ > + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { > + dev_err(host->dev, "%s: fifo/dma reset bits didn't " > + "clear but ciu was reset, doing clock update\n", > + __func__); > + goto ciu_out; > + } > + } > + > +#if IS_ENABLED(CONFIG_MMC_DW_IDMAC) > + /* It is also recommended that we reset and reprogram idmac */ > + dw_mci_idmac_reset(host); > +#endif > + > + ret = true; > + > +ciu_out: > + /* After a CTRL reset we need to have CIU set clock registers */ > + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); > + > + return ret; > } > > #ifdef CONFIG_OF > @@ -2425,7 +2466,7 @@ int dw_mci_probe(struct dw_mci *host) > } > > /* Reset all blocks */ > - if (!dw_mci_ctrl_all_reset(host)) > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) > return -ENODEV; > > host->dma_ops = host->pdata->dma_ops; > @@ -2612,7 +2653,7 @@ int dw_mci_resume(struct dw_mci *host) > } > } > > - if (!dw_mci_ctrl_all_reset(host)) { > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) { > ret = -ENODEV; > return ret; > } > diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h > index 738fa24..08fd956 100644 > --- a/drivers/mmc/host/dw_mmc.h > +++ b/drivers/mmc/host/dw_mmc.h > @@ -129,6 +129,7 @@ > #define SDMMC_CMD_INDX(n) ((n) & 0x1F) > /* Status register defines */ > #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) > +#define SDMMC_STATUS_DMA_REQ BIT(31) > /* FIFOTH register defines */ > #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ > ((r) & 0xFFF) << 16 | \ > @@ -150,6 +151,10 @@ > /* Card read threshold */ > #define SDMMC_SET_RD_THLD(v, x) (((v) & 0x1FFF) << 16 | (x)) > > +/* All ctrl reset bits */ > +#define SDMMC_CTRL_ALL_RESET_FLAGS \ > + (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET) > + > /* Register access macros */ > #define mci_readl(dev, reg) \ > __raw_readl((dev)->regs + SDMMC_##reg) > ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCH] mmc: dw_mmc: change to use recommended reset procedure @ 2014-08-07 8:40 ` Jaehoon Chung 0 siblings, 0 replies; 75+ messages in thread From: Jaehoon Chung @ 2014-08-07 8:40 UTC (permalink / raw) To: linux-arm-kernel Hi, I remembered that this patch was pushed at Ulf's tree. Since dw_mci_idmac_reset() is located into #if CONFIG_MMC_DW_IDMAC, it occurred the compiler error. And it seems that didn't need to use "IS_ENABLED()" at there. Acked-by: Jaehoon Chung <jh80.chung@samsung.com> Best Regards, Jaehoon Chung On 08/05/2014 10:19 AM, Sonny Rao wrote: > 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> > Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> > [sonnyrao: fix compile for !CONFIG_MMC_DW_IDMAC case] > --- > drivers/mmc/host/dw_mmc.c | 87 ++++++++++++++++++++++++++++++++++------------- > drivers/mmc/host/dw_mmc.h | 5 +++ > 2 files changed, 69 insertions(+), 23 deletions(-) > > diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c > index 1ac227c..39cf54f 100644 > --- a/drivers/mmc/host/dw_mmc.c > +++ b/drivers/mmc/host/dw_mmc.c > @@ -111,8 +111,7 @@ static const u8 tuning_blk_pattern_8bit[] = { > 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, > }; > > -static inline bool dw_mci_fifo_reset(struct dw_mci *host); > -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host); > +static bool dw_mci_reset(struct dw_mci *host); > > #if defined(CONFIG_DEBUG_FS) > static int dw_mci_req_show(struct seq_file *s, void *v) > @@ -1235,7 +1234,7 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) > * After an error, there may be data lingering > * in the FIFO > */ > - dw_mci_fifo_reset(host); > + dw_mci_reset(host); > } else { > data->bytes_xfered = data->blocks * data->blksz; > data->error = 0; > @@ -1352,7 +1351,7 @@ static void dw_mci_tasklet_func(unsigned long priv) > > /* CMD error in data command */ > if (mrq->cmd->error && mrq->data) > - dw_mci_fifo_reset(host); > + dw_mci_reset(host); > > host->cmd = NULL; > host->data = NULL; > @@ -1963,14 +1962,8 @@ static void dw_mci_work_routine_card(struct work_struct *work) > } > > /* Power down slot */ > - if (present == 0) { > - /* Clear down the FIFO */ > - dw_mci_fifo_reset(host); > -#ifdef CONFIG_MMC_DW_IDMAC > - dw_mci_idmac_reset(host); > -#endif > - > - } > + if (present == 0) > + dw_mci_reset(host); > > spin_unlock_bh(&host->lock); > > @@ -2208,8 +2201,11 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) > return false; > } > > -static inline bool dw_mci_fifo_reset(struct dw_mci *host) > +static bool dw_mci_reset(struct dw_mci *host) > { > + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; > + bool ret = false; > + > /* > * Reseting generates a block interrupt, hence setting > * the scatter-gather pointer to NULL. > @@ -2219,15 +2215,60 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) > host->sg = NULL; > } > > - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > -} > + if (host->use_dma) > + flags |= SDMMC_CTRL_DMA_RESET; > > -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) > -{ > - return dw_mci_ctrl_reset(host, > - SDMMC_CTRL_FIFO_RESET | > - SDMMC_CTRL_RESET | > - SDMMC_CTRL_DMA_RESET); > + if (dw_mci_ctrl_reset(host, flags)) { > + /* > + * In all cases we clear the RAWINTS register to clear any > + * interrupts. > + */ > + mci_writel(host, RINTSTS, 0xFFFFFFFF); > + > + /* if using dma we wait for dma_req to clear */ > + if (host->use_dma) { > + unsigned long timeout = jiffies + msecs_to_jiffies(500); > + u32 status; > + do { > + status = mci_readl(host, STATUS); > + if (!(status & SDMMC_STATUS_DMA_REQ)) > + break; > + cpu_relax(); > + } while (time_before(jiffies, timeout)); > + > + if (status & SDMMC_STATUS_DMA_REQ) { > + dev_err(host->dev, > + "%s: Timeout waiting for dma_req to " > + "clear during reset\n", __func__); > + goto ciu_out; > + } > + > + /* when using DMA next we reset the fifo again */ > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) > + goto ciu_out; > + } > + } else { > + /* if the controller reset bit did clear, then set clock regs */ > + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { > + dev_err(host->dev, "%s: fifo/dma reset bits didn't " > + "clear but ciu was reset, doing clock update\n", > + __func__); > + goto ciu_out; > + } > + } > + > +#if IS_ENABLED(CONFIG_MMC_DW_IDMAC) > + /* It is also recommended that we reset and reprogram idmac */ > + dw_mci_idmac_reset(host); > +#endif > + > + ret = true; > + > +ciu_out: > + /* After a CTRL reset we need to have CIU set clock registers */ > + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); > + > + return ret; > } > > #ifdef CONFIG_OF > @@ -2425,7 +2466,7 @@ int dw_mci_probe(struct dw_mci *host) > } > > /* Reset all blocks */ > - if (!dw_mci_ctrl_all_reset(host)) > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) > return -ENODEV; > > host->dma_ops = host->pdata->dma_ops; > @@ -2612,7 +2653,7 @@ int dw_mci_resume(struct dw_mci *host) > } > } > > - if (!dw_mci_ctrl_all_reset(host)) { > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) { > ret = -ENODEV; > return ret; > } > diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h > index 738fa24..08fd956 100644 > --- a/drivers/mmc/host/dw_mmc.h > +++ b/drivers/mmc/host/dw_mmc.h > @@ -129,6 +129,7 @@ > #define SDMMC_CMD_INDX(n) ((n) & 0x1F) > /* Status register defines */ > #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) > +#define SDMMC_STATUS_DMA_REQ BIT(31) > /* FIFOTH register defines */ > #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ > ((r) & 0xFFF) << 16 | \ > @@ -150,6 +151,10 @@ > /* Card read threshold */ > #define SDMMC_SET_RD_THLD(v, x) (((v) & 0x1FFF) << 16 | (x)) > > +/* All ctrl reset bits */ > +#define SDMMC_CTRL_ALL_RESET_FLAGS \ > + (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET) > + > /* Register access macros */ > #define mci_readl(dev, reg) \ > __raw_readl((dev)->regs + SDMMC_##reg) > ^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCH] mmc: dw_mmc: change to use recommended reset procedure 2014-08-05 1:19 ` Sonny Rao (?) @ 2014-08-11 7:55 ` Ulf Hansson -1 siblings, 0 replies; 75+ messages in thread From: Ulf Hansson @ 2014-08-11 7:55 UTC (permalink / raw) To: Sonny Rao Cc: linux-mmc, linux-next, Grant Grundler, linux-samsung-soc, linux-kernel, Stephen Rothwell, linux-arm-kernel, Jaehoon Chung, Chris Ball, tgih.jun, Kukjin Kim, sunil joshi, Tomasz Figa, Doug Anderson, Yuvaraj Kumar C D On 5 August 2014 03:19, Sonny Rao <sonnyrao@chromium.org> wrote: > 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> > Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> > [sonnyrao: fix compile for !CONFIG_MMC_DW_IDMAC case] Thanks! Applied for next! Kind regards Uffe > --- > drivers/mmc/host/dw_mmc.c | 87 ++++++++++++++++++++++++++++++++++------------- > drivers/mmc/host/dw_mmc.h | 5 +++ > 2 files changed, 69 insertions(+), 23 deletions(-) > > diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c > index 1ac227c..39cf54f 100644 > --- a/drivers/mmc/host/dw_mmc.c > +++ b/drivers/mmc/host/dw_mmc.c > @@ -111,8 +111,7 @@ static const u8 tuning_blk_pattern_8bit[] = { > 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, > }; > > -static inline bool dw_mci_fifo_reset(struct dw_mci *host); > -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host); > +static bool dw_mci_reset(struct dw_mci *host); > > #if defined(CONFIG_DEBUG_FS) > static int dw_mci_req_show(struct seq_file *s, void *v) > @@ -1235,7 +1234,7 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) > * After an error, there may be data lingering > * in the FIFO > */ > - dw_mci_fifo_reset(host); > + dw_mci_reset(host); > } else { > data->bytes_xfered = data->blocks * data->blksz; > data->error = 0; > @@ -1352,7 +1351,7 @@ static void dw_mci_tasklet_func(unsigned long priv) > > /* CMD error in data command */ > if (mrq->cmd->error && mrq->data) > - dw_mci_fifo_reset(host); > + dw_mci_reset(host); > > host->cmd = NULL; > host->data = NULL; > @@ -1963,14 +1962,8 @@ static void dw_mci_work_routine_card(struct work_struct *work) > } > > /* Power down slot */ > - if (present == 0) { > - /* Clear down the FIFO */ > - dw_mci_fifo_reset(host); > -#ifdef CONFIG_MMC_DW_IDMAC > - dw_mci_idmac_reset(host); > -#endif > - > - } > + if (present == 0) > + dw_mci_reset(host); > > spin_unlock_bh(&host->lock); > > @@ -2208,8 +2201,11 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) > return false; > } > > -static inline bool dw_mci_fifo_reset(struct dw_mci *host) > +static bool dw_mci_reset(struct dw_mci *host) > { > + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; > + bool ret = false; > + > /* > * Reseting generates a block interrupt, hence setting > * the scatter-gather pointer to NULL. > @@ -2219,15 +2215,60 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) > host->sg = NULL; > } > > - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > -} > + if (host->use_dma) > + flags |= SDMMC_CTRL_DMA_RESET; > > -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) > -{ > - return dw_mci_ctrl_reset(host, > - SDMMC_CTRL_FIFO_RESET | > - SDMMC_CTRL_RESET | > - SDMMC_CTRL_DMA_RESET); > + if (dw_mci_ctrl_reset(host, flags)) { > + /* > + * In all cases we clear the RAWINTS register to clear any > + * interrupts. > + */ > + mci_writel(host, RINTSTS, 0xFFFFFFFF); > + > + /* if using dma we wait for dma_req to clear */ > + if (host->use_dma) { > + unsigned long timeout = jiffies + msecs_to_jiffies(500); > + u32 status; > + do { > + status = mci_readl(host, STATUS); > + if (!(status & SDMMC_STATUS_DMA_REQ)) > + break; > + cpu_relax(); > + } while (time_before(jiffies, timeout)); > + > + if (status & SDMMC_STATUS_DMA_REQ) { > + dev_err(host->dev, > + "%s: Timeout waiting for dma_req to " > + "clear during reset\n", __func__); > + goto ciu_out; > + } > + > + /* when using DMA next we reset the fifo again */ > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) > + goto ciu_out; > + } > + } else { > + /* if the controller reset bit did clear, then set clock regs */ > + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { > + dev_err(host->dev, "%s: fifo/dma reset bits didn't " > + "clear but ciu was reset, doing clock update\n", > + __func__); > + goto ciu_out; > + } > + } > + > +#if IS_ENABLED(CONFIG_MMC_DW_IDMAC) > + /* It is also recommended that we reset and reprogram idmac */ > + dw_mci_idmac_reset(host); > +#endif > + > + ret = true; > + > +ciu_out: > + /* After a CTRL reset we need to have CIU set clock registers */ > + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); > + > + return ret; > } > > #ifdef CONFIG_OF > @@ -2425,7 +2466,7 @@ int dw_mci_probe(struct dw_mci *host) > } > > /* Reset all blocks */ > - if (!dw_mci_ctrl_all_reset(host)) > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) > return -ENODEV; > > host->dma_ops = host->pdata->dma_ops; > @@ -2612,7 +2653,7 @@ int dw_mci_resume(struct dw_mci *host) > } > } > > - if (!dw_mci_ctrl_all_reset(host)) { > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) { > ret = -ENODEV; > return ret; > } > diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h > index 738fa24..08fd956 100644 > --- a/drivers/mmc/host/dw_mmc.h > +++ b/drivers/mmc/host/dw_mmc.h > @@ -129,6 +129,7 @@ > #define SDMMC_CMD_INDX(n) ((n) & 0x1F) > /* Status register defines */ > #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) > +#define SDMMC_STATUS_DMA_REQ BIT(31) > /* FIFOTH register defines */ > #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ > ((r) & 0xFFF) << 16 | \ > @@ -150,6 +151,10 @@ > /* Card read threshold */ > #define SDMMC_SET_RD_THLD(v, x) (((v) & 0x1FFF) << 16 | (x)) > > +/* All ctrl reset bits */ > +#define SDMMC_CTRL_ALL_RESET_FLAGS \ > + (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET) > + > /* Register access macros */ > #define mci_readl(dev, reg) \ > __raw_readl((dev)->regs + SDMMC_##reg) > -- > 1.8.3.2 > ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCH] mmc: dw_mmc: change to use recommended reset procedure @ 2014-08-11 7:55 ` Ulf Hansson 0 siblings, 0 replies; 75+ messages in thread From: Ulf Hansson @ 2014-08-11 7:55 UTC (permalink / raw) To: linux-arm-kernel On 5 August 2014 03:19, Sonny Rao <sonnyrao@chromium.org> wrote: > 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> > Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> > [sonnyrao: fix compile for !CONFIG_MMC_DW_IDMAC case] Thanks! Applied for next! Kind regards Uffe > --- > drivers/mmc/host/dw_mmc.c | 87 ++++++++++++++++++++++++++++++++++------------- > drivers/mmc/host/dw_mmc.h | 5 +++ > 2 files changed, 69 insertions(+), 23 deletions(-) > > diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c > index 1ac227c..39cf54f 100644 > --- a/drivers/mmc/host/dw_mmc.c > +++ b/drivers/mmc/host/dw_mmc.c > @@ -111,8 +111,7 @@ static const u8 tuning_blk_pattern_8bit[] = { > 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, > }; > > -static inline bool dw_mci_fifo_reset(struct dw_mci *host); > -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host); > +static bool dw_mci_reset(struct dw_mci *host); > > #if defined(CONFIG_DEBUG_FS) > static int dw_mci_req_show(struct seq_file *s, void *v) > @@ -1235,7 +1234,7 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) > * After an error, there may be data lingering > * in the FIFO > */ > - dw_mci_fifo_reset(host); > + dw_mci_reset(host); > } else { > data->bytes_xfered = data->blocks * data->blksz; > data->error = 0; > @@ -1352,7 +1351,7 @@ static void dw_mci_tasklet_func(unsigned long priv) > > /* CMD error in data command */ > if (mrq->cmd->error && mrq->data) > - dw_mci_fifo_reset(host); > + dw_mci_reset(host); > > host->cmd = NULL; > host->data = NULL; > @@ -1963,14 +1962,8 @@ static void dw_mci_work_routine_card(struct work_struct *work) > } > > /* Power down slot */ > - if (present == 0) { > - /* Clear down the FIFO */ > - dw_mci_fifo_reset(host); > -#ifdef CONFIG_MMC_DW_IDMAC > - dw_mci_idmac_reset(host); > -#endif > - > - } > + if (present == 0) > + dw_mci_reset(host); > > spin_unlock_bh(&host->lock); > > @@ -2208,8 +2201,11 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) > return false; > } > > -static inline bool dw_mci_fifo_reset(struct dw_mci *host) > +static bool dw_mci_reset(struct dw_mci *host) > { > + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; > + bool ret = false; > + > /* > * Reseting generates a block interrupt, hence setting > * the scatter-gather pointer to NULL. > @@ -2219,15 +2215,60 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) > host->sg = NULL; > } > > - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > -} > + if (host->use_dma) > + flags |= SDMMC_CTRL_DMA_RESET; > > -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) > -{ > - return dw_mci_ctrl_reset(host, > - SDMMC_CTRL_FIFO_RESET | > - SDMMC_CTRL_RESET | > - SDMMC_CTRL_DMA_RESET); > + if (dw_mci_ctrl_reset(host, flags)) { > + /* > + * In all cases we clear the RAWINTS register to clear any > + * interrupts. > + */ > + mci_writel(host, RINTSTS, 0xFFFFFFFF); > + > + /* if using dma we wait for dma_req to clear */ > + if (host->use_dma) { > + unsigned long timeout = jiffies + msecs_to_jiffies(500); > + u32 status; > + do { > + status = mci_readl(host, STATUS); > + if (!(status & SDMMC_STATUS_DMA_REQ)) > + break; > + cpu_relax(); > + } while (time_before(jiffies, timeout)); > + > + if (status & SDMMC_STATUS_DMA_REQ) { > + dev_err(host->dev, > + "%s: Timeout waiting for dma_req to " > + "clear during reset\n", __func__); > + goto ciu_out; > + } > + > + /* when using DMA next we reset the fifo again */ > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) > + goto ciu_out; > + } > + } else { > + /* if the controller reset bit did clear, then set clock regs */ > + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { > + dev_err(host->dev, "%s: fifo/dma reset bits didn't " > + "clear but ciu was reset, doing clock update\n", > + __func__); > + goto ciu_out; > + } > + } > + > +#if IS_ENABLED(CONFIG_MMC_DW_IDMAC) > + /* It is also recommended that we reset and reprogram idmac */ > + dw_mci_idmac_reset(host); > +#endif > + > + ret = true; > + > +ciu_out: > + /* After a CTRL reset we need to have CIU set clock registers */ > + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); > + > + return ret; > } > > #ifdef CONFIG_OF > @@ -2425,7 +2466,7 @@ int dw_mci_probe(struct dw_mci *host) > } > > /* Reset all blocks */ > - if (!dw_mci_ctrl_all_reset(host)) > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) > return -ENODEV; > > host->dma_ops = host->pdata->dma_ops; > @@ -2612,7 +2653,7 @@ int dw_mci_resume(struct dw_mci *host) > } > } > > - if (!dw_mci_ctrl_all_reset(host)) { > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) { > ret = -ENODEV; > return ret; > } > diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h > index 738fa24..08fd956 100644 > --- a/drivers/mmc/host/dw_mmc.h > +++ b/drivers/mmc/host/dw_mmc.h > @@ -129,6 +129,7 @@ > #define SDMMC_CMD_INDX(n) ((n) & 0x1F) > /* Status register defines */ > #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) > +#define SDMMC_STATUS_DMA_REQ BIT(31) > /* FIFOTH register defines */ > #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ > ((r) & 0xFFF) << 16 | \ > @@ -150,6 +151,10 @@ > /* Card read threshold */ > #define SDMMC_SET_RD_THLD(v, x) (((v) & 0x1FFF) << 16 | (x)) > > +/* All ctrl reset bits */ > +#define SDMMC_CTRL_ALL_RESET_FLAGS \ > + (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET) > + > /* Register access macros */ > #define mci_readl(dev, reg) \ > __raw_readl((dev)->regs + SDMMC_##reg) > -- > 1.8.3.2 > ^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCH] mmc: dw_mmc: change to use recommended reset procedure @ 2014-08-11 7:55 ` Ulf Hansson 0 siblings, 0 replies; 75+ messages in thread From: Ulf Hansson @ 2014-08-11 7:55 UTC (permalink / raw) To: Sonny Rao Cc: linux-mmc, linux-next, Grant Grundler, linux-samsung-soc, linux-kernel, Stephen Rothwell, linux-arm-kernel, Jaehoon Chung, Chris Ball, tgih.jun, Kukjin Kim, sunil joshi, Tomasz Figa, Doug Anderson, Yuvaraj Kumar C D On 5 August 2014 03:19, Sonny Rao <sonnyrao@chromium.org> wrote: > 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> > Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> > [sonnyrao: fix compile for !CONFIG_MMC_DW_IDMAC case] Thanks! Applied for next! Kind regards Uffe > --- > drivers/mmc/host/dw_mmc.c | 87 ++++++++++++++++++++++++++++++++++------------- > drivers/mmc/host/dw_mmc.h | 5 +++ > 2 files changed, 69 insertions(+), 23 deletions(-) > > diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c > index 1ac227c..39cf54f 100644 > --- a/drivers/mmc/host/dw_mmc.c > +++ b/drivers/mmc/host/dw_mmc.c > @@ -111,8 +111,7 @@ static const u8 tuning_blk_pattern_8bit[] = { > 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, > }; > > -static inline bool dw_mci_fifo_reset(struct dw_mci *host); > -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host); > +static bool dw_mci_reset(struct dw_mci *host); > > #if defined(CONFIG_DEBUG_FS) > static int dw_mci_req_show(struct seq_file *s, void *v) > @@ -1235,7 +1234,7 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) > * After an error, there may be data lingering > * in the FIFO > */ > - dw_mci_fifo_reset(host); > + dw_mci_reset(host); > } else { > data->bytes_xfered = data->blocks * data->blksz; > data->error = 0; > @@ -1352,7 +1351,7 @@ static void dw_mci_tasklet_func(unsigned long priv) > > /* CMD error in data command */ > if (mrq->cmd->error && mrq->data) > - dw_mci_fifo_reset(host); > + dw_mci_reset(host); > > host->cmd = NULL; > host->data = NULL; > @@ -1963,14 +1962,8 @@ static void dw_mci_work_routine_card(struct work_struct *work) > } > > /* Power down slot */ > - if (present == 0) { > - /* Clear down the FIFO */ > - dw_mci_fifo_reset(host); > -#ifdef CONFIG_MMC_DW_IDMAC > - dw_mci_idmac_reset(host); > -#endif > - > - } > + if (present == 0) > + dw_mci_reset(host); > > spin_unlock_bh(&host->lock); > > @@ -2208,8 +2201,11 @@ static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) > return false; > } > > -static inline bool dw_mci_fifo_reset(struct dw_mci *host) > +static bool dw_mci_reset(struct dw_mci *host) > { > + u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; > + bool ret = false; > + > /* > * Reseting generates a block interrupt, hence setting > * the scatter-gather pointer to NULL. > @@ -2219,15 +2215,60 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) > host->sg = NULL; > } > > - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > -} > + if (host->use_dma) > + flags |= SDMMC_CTRL_DMA_RESET; > > -static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) > -{ > - return dw_mci_ctrl_reset(host, > - SDMMC_CTRL_FIFO_RESET | > - SDMMC_CTRL_RESET | > - SDMMC_CTRL_DMA_RESET); > + if (dw_mci_ctrl_reset(host, flags)) { > + /* > + * In all cases we clear the RAWINTS register to clear any > + * interrupts. > + */ > + mci_writel(host, RINTSTS, 0xFFFFFFFF); > + > + /* if using dma we wait for dma_req to clear */ > + if (host->use_dma) { > + unsigned long timeout = jiffies + msecs_to_jiffies(500); > + u32 status; > + do { > + status = mci_readl(host, STATUS); > + if (!(status & SDMMC_STATUS_DMA_REQ)) > + break; > + cpu_relax(); > + } while (time_before(jiffies, timeout)); > + > + if (status & SDMMC_STATUS_DMA_REQ) { > + dev_err(host->dev, > + "%s: Timeout waiting for dma_req to " > + "clear during reset\n", __func__); > + goto ciu_out; > + } > + > + /* when using DMA next we reset the fifo again */ > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) > + goto ciu_out; > + } > + } else { > + /* if the controller reset bit did clear, then set clock regs */ > + if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { > + dev_err(host->dev, "%s: fifo/dma reset bits didn't " > + "clear but ciu was reset, doing clock update\n", > + __func__); > + goto ciu_out; > + } > + } > + > +#if IS_ENABLED(CONFIG_MMC_DW_IDMAC) > + /* It is also recommended that we reset and reprogram idmac */ > + dw_mci_idmac_reset(host); > +#endif > + > + ret = true; > + > +ciu_out: > + /* After a CTRL reset we need to have CIU set clock registers */ > + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); > + > + return ret; > } > > #ifdef CONFIG_OF > @@ -2425,7 +2466,7 @@ int dw_mci_probe(struct dw_mci *host) > } > > /* Reset all blocks */ > - if (!dw_mci_ctrl_all_reset(host)) > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) > return -ENODEV; > > host->dma_ops = host->pdata->dma_ops; > @@ -2612,7 +2653,7 @@ int dw_mci_resume(struct dw_mci *host) > } > } > > - if (!dw_mci_ctrl_all_reset(host)) { > + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) { > ret = -ENODEV; > return ret; > } > diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h > index 738fa24..08fd956 100644 > --- a/drivers/mmc/host/dw_mmc.h > +++ b/drivers/mmc/host/dw_mmc.h > @@ -129,6 +129,7 @@ > #define SDMMC_CMD_INDX(n) ((n) & 0x1F) > /* Status register defines */ > #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) > +#define SDMMC_STATUS_DMA_REQ BIT(31) > /* FIFOTH register defines */ > #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ > ((r) & 0xFFF) << 16 | \ > @@ -150,6 +151,10 @@ > /* Card read threshold */ > #define SDMMC_SET_RD_THLD(v, x) (((v) & 0x1FFF) << 16 | (x)) > > +/* All ctrl reset bits */ > +#define SDMMC_CTRL_ALL_RESET_FLAGS \ > + (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET) > + > /* Register access macros */ > #define mci_readl(dev, reg) \ > __raw_readl((dev)->regs + SDMMC_##reg) > -- > 1.8.3.2 > ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCH] mmc: dw_mmc: change to use recommended reset procedure @ 2014-03-26 11:46 ` Yuvaraj Kumar C D 0 siblings, 0 replies; 75+ messages in thread From: Yuvaraj Kumar C D @ 2014-03-26 11:46 UTC (permalink / raw) To: grundler, linux-samsung-soc, linux-arm-kernel, jh80.chung, cjb, tgih.jun, linux-mmc, sonnyrao, kgene.kim, joshi Cc: t.figa, Yuvaraj Kumar C D From: Sonny Rao <sonnyrao@chromium.org> This patch changes the fifo reset code to follow the reset procedure outlined in the documentation of Synopsys Mobile storage host databook 7.2.13. Without this patch, we could able to see eMMC was not detected after multiple reboots due to driver hangs while eMMC tuning for HS200. Signed-off-by: Sonny Rao <sonnyrao@chromium.org> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.org> --- drivers/mmc/host/dw_mmc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++- drivers/mmc/host/dw_mmc.h | 1 + 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 32dd81d..1d77431 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -2220,7 +2220,53 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) host->sg = NULL; } - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); + /* + * The recommended method for resetting is to always reset the + * controller and the fifo, but differs slightly depending on the mode. + * Note that this doesn't handle the "generic DMA" (not IDMAC) case. + */ + if (dw_mci_ctrl_reset(host, SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET)) { + unsigned long timeout = jiffies + msecs_to_jiffies(500); + u32 status, rint; + + /* if using dma we wait for dma_req to clear */ + if (host->using_dma) { + do { + status = mci_readl(host, STATUS); + if (!(status & SDMMC_STATUS_DMA_REQ)) + break; + cpu_relax(); + } while (time_before(jiffies, timeout)); + + if (status & SDMMC_STATUS_DMA_REQ) + dev_err(host->dev, + "%s: Timeout waiting for dma_req to " + "clear during reset", __func__); + + /* when using DMA next we reset the fifo again */ + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); + } + /* + * In all cases we clear the RAWINTS register to clear any + * interrupts. + */ + rint = mci_readl(host, RINTSTS); + rint = rint & (~mci_readl(host, MINTSTS)); + if (rint) + mci_writel(host, RINTSTS, rint); + + } else + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); + + #ifdef CONFIG_MMC_DW_IDMAC + /* It is also recommended that we reset and reprogram idmac */ + dw_mci_idmac_reset(host); + #endif + + /* After a CTRL reset we need to have CIU set clock registers */ + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); + + return true; } static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 738fa24..037e47a 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -129,6 +129,7 @@ #define SDMMC_CMD_INDX(n) ((n) & 0x1F) /* Status register defines */ #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) +#define SDMMC_STATUS_DMA_REQ BIT(31) /* FIFOTH register defines */ #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ ((r) & 0xFFF) << 16 | \ -- 1.7.10.4 ^ permalink raw reply related [flat|nested] 75+ messages in thread
* [PATCH] mmc: dw_mmc: change to use recommended reset procedure @ 2014-03-26 11:46 ` Yuvaraj Kumar C D 0 siblings, 0 replies; 75+ messages in thread From: Yuvaraj Kumar C D @ 2014-03-26 11:46 UTC (permalink / raw) To: linux-arm-kernel From: Sonny Rao <sonnyrao@chromium.org> This patch changes the fifo reset code to follow the reset procedure outlined in the documentation of Synopsys Mobile storage host databook 7.2.13. Without this patch, we could able to see eMMC was not detected after multiple reboots due to driver hangs while eMMC tuning for HS200. Signed-off-by: Sonny Rao <sonnyrao@chromium.org> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.org> --- drivers/mmc/host/dw_mmc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++- drivers/mmc/host/dw_mmc.h | 1 + 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 32dd81d..1d77431 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -2220,7 +2220,53 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) host->sg = NULL; } - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); + /* + * The recommended method for resetting is to always reset the + * controller and the fifo, but differs slightly depending on the mode. + * Note that this doesn't handle the "generic DMA" (not IDMAC) case. + */ + if (dw_mci_ctrl_reset(host, SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET)) { + unsigned long timeout = jiffies + msecs_to_jiffies(500); + u32 status, rint; + + /* if using dma we wait for dma_req to clear */ + if (host->using_dma) { + do { + status = mci_readl(host, STATUS); + if (!(status & SDMMC_STATUS_DMA_REQ)) + break; + cpu_relax(); + } while (time_before(jiffies, timeout)); + + if (status & SDMMC_STATUS_DMA_REQ) + dev_err(host->dev, + "%s: Timeout waiting for dma_req to " + "clear during reset", __func__); + + /* when using DMA next we reset the fifo again */ + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); + } + /* + * In all cases we clear the RAWINTS register to clear any + * interrupts. + */ + rint = mci_readl(host, RINTSTS); + rint = rint & (~mci_readl(host, MINTSTS)); + if (rint) + mci_writel(host, RINTSTS, rint); + + } else + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); + + #ifdef CONFIG_MMC_DW_IDMAC + /* It is also recommended that we reset and reprogram idmac */ + dw_mci_idmac_reset(host); + #endif + + /* After a CTRL reset we need to have CIU set clock registers */ + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); + + return true; } static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 738fa24..037e47a 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -129,6 +129,7 @@ #define SDMMC_CMD_INDX(n) ((n) & 0x1F) /* Status register defines */ #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) +#define SDMMC_STATUS_DMA_REQ BIT(31) /* FIFOTH register defines */ #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ ((r) & 0xFFF) << 16 | \ -- 1.7.10.4 ^ permalink raw reply related [flat|nested] 75+ messages in thread
* Re: [PATCH] mmc: dw_mmc: change to use recommended reset procedure 2014-03-26 11:46 ` Yuvaraj Kumar C D @ 2014-05-08 9:40 ` Yuvaraj Kumar -1 siblings, 0 replies; 75+ messages in thread From: Yuvaraj Kumar @ 2014-05-08 9:40 UTC (permalink / raw) To: Grant Grundler, linux-samsung-soc, linux-arm-kernel, Jaehoon Chung, Chris Ball, Seungwon Jeon, linux-mmc, Sonny Rao, kgene.kim, sunil joshi Cc: Tomasz Figa, Yuvaraj Kumar C D Any comments on this patch? On Wed, Mar 26, 2014 at 5:16 PM, Yuvaraj Kumar C D <yuvaraj.cd@gmail.com> wrote: > From: Sonny Rao <sonnyrao@chromium.org> > > This patch changes the fifo reset code to follow the reset procedure > outlined in the documentation of Synopsys Mobile storage host databook > 7.2.13. > Without this patch, we could able to see eMMC was not detected after > multiple reboots due to driver hangs while eMMC tuning for HS200. > > Signed-off-by: Sonny Rao <sonnyrao@chromium.org> > Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.org> > --- > drivers/mmc/host/dw_mmc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++- > drivers/mmc/host/dw_mmc.h | 1 + > 2 files changed, 48 insertions(+), 1 deletion(-) > > diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c > index 32dd81d..1d77431 100644 > --- a/drivers/mmc/host/dw_mmc.c > +++ b/drivers/mmc/host/dw_mmc.c > @@ -2220,7 +2220,53 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) > host->sg = NULL; > } > > - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > + /* > + * The recommended method for resetting is to always reset the > + * controller and the fifo, but differs slightly depending on the mode. > + * Note that this doesn't handle the "generic DMA" (not IDMAC) case. > + */ > + if (dw_mci_ctrl_reset(host, SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET)) { > + unsigned long timeout = jiffies + msecs_to_jiffies(500); > + u32 status, rint; > + > + /* if using dma we wait for dma_req to clear */ > + if (host->using_dma) { > + do { > + status = mci_readl(host, STATUS); > + if (!(status & SDMMC_STATUS_DMA_REQ)) > + break; > + cpu_relax(); > + } while (time_before(jiffies, timeout)); > + > + if (status & SDMMC_STATUS_DMA_REQ) > + dev_err(host->dev, > + "%s: Timeout waiting for dma_req to " > + "clear during reset", __func__); > + > + /* when using DMA next we reset the fifo again */ > + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > + } > + /* > + * In all cases we clear the RAWINTS register to clear any > + * interrupts. > + */ > + rint = mci_readl(host, RINTSTS); > + rint = rint & (~mci_readl(host, MINTSTS)); > + if (rint) > + mci_writel(host, RINTSTS, rint); > + > + } else > + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); > + > + #ifdef CONFIG_MMC_DW_IDMAC > + /* It is also recommended that we reset and reprogram idmac */ > + dw_mci_idmac_reset(host); > + #endif > + > + /* After a CTRL reset we need to have CIU set clock registers */ > + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); > + > + return true; > } > > static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) > diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h > index 738fa24..037e47a 100644 > --- a/drivers/mmc/host/dw_mmc.h > +++ b/drivers/mmc/host/dw_mmc.h > @@ -129,6 +129,7 @@ > #define SDMMC_CMD_INDX(n) ((n) & 0x1F) > /* Status register defines */ > #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) > +#define SDMMC_STATUS_DMA_REQ BIT(31) > /* FIFOTH register defines */ > #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ > ((r) & 0xFFF) << 16 | \ > -- > 1.7.10.4 > ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCH] mmc: dw_mmc: change to use recommended reset procedure @ 2014-05-08 9:40 ` Yuvaraj Kumar 0 siblings, 0 replies; 75+ messages in thread From: Yuvaraj Kumar @ 2014-05-08 9:40 UTC (permalink / raw) To: linux-arm-kernel Any comments on this patch? On Wed, Mar 26, 2014 at 5:16 PM, Yuvaraj Kumar C D <yuvaraj.cd@gmail.com> wrote: > From: Sonny Rao <sonnyrao@chromium.org> > > This patch changes the fifo reset code to follow the reset procedure > outlined in the documentation of Synopsys Mobile storage host databook > 7.2.13. > Without this patch, we could able to see eMMC was not detected after > multiple reboots due to driver hangs while eMMC tuning for HS200. > > Signed-off-by: Sonny Rao <sonnyrao@chromium.org> > Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.org> > --- > drivers/mmc/host/dw_mmc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++- > drivers/mmc/host/dw_mmc.h | 1 + > 2 files changed, 48 insertions(+), 1 deletion(-) > > diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c > index 32dd81d..1d77431 100644 > --- a/drivers/mmc/host/dw_mmc.c > +++ b/drivers/mmc/host/dw_mmc.c > @@ -2220,7 +2220,53 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) > host->sg = NULL; > } > > - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > + /* > + * The recommended method for resetting is to always reset the > + * controller and the fifo, but differs slightly depending on the mode. > + * Note that this doesn't handle the "generic DMA" (not IDMAC) case. > + */ > + if (dw_mci_ctrl_reset(host, SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET)) { > + unsigned long timeout = jiffies + msecs_to_jiffies(500); > + u32 status, rint; > + > + /* if using dma we wait for dma_req to clear */ > + if (host->using_dma) { > + do { > + status = mci_readl(host, STATUS); > + if (!(status & SDMMC_STATUS_DMA_REQ)) > + break; > + cpu_relax(); > + } while (time_before(jiffies, timeout)); > + > + if (status & SDMMC_STATUS_DMA_REQ) > + dev_err(host->dev, > + "%s: Timeout waiting for dma_req to " > + "clear during reset", __func__); > + > + /* when using DMA next we reset the fifo again */ > + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > + } > + /* > + * In all cases we clear the RAWINTS register to clear any > + * interrupts. > + */ > + rint = mci_readl(host, RINTSTS); > + rint = rint & (~mci_readl(host, MINTSTS)); > + if (rint) > + mci_writel(host, RINTSTS, rint); > + > + } else > + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); > + > + #ifdef CONFIG_MMC_DW_IDMAC > + /* It is also recommended that we reset and reprogram idmac */ > + dw_mci_idmac_reset(host); > + #endif > + > + /* After a CTRL reset we need to have CIU set clock registers */ > + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); > + > + return true; > } > > static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) > diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h > index 738fa24..037e47a 100644 > --- a/drivers/mmc/host/dw_mmc.h > +++ b/drivers/mmc/host/dw_mmc.h > @@ -129,6 +129,7 @@ > #define SDMMC_CMD_INDX(n) ((n) & 0x1F) > /* Status register defines */ > #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) > +#define SDMMC_STATUS_DMA_REQ BIT(31) > /* FIFOTH register defines */ > #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ > ((r) & 0xFFF) << 16 | \ > -- > 1.7.10.4 > ^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCH] mmc: dw_mmc: change to use recommended reset procedure 2014-05-08 9:40 ` Yuvaraj Kumar @ 2014-05-09 1:15 ` Jaehoon Chung -1 siblings, 0 replies; 75+ messages in thread From: Jaehoon Chung @ 2014-05-09 1:15 UTC (permalink / raw) To: Yuvaraj Kumar, Grant Grundler, linux-samsung-soc, linux-arm-kernel, Chris Ball, Seungwon Jeon, linux-mmc, Sonny Rao, kgene.kim, sunil joshi Cc: Tomasz Figa, Yuvaraj Kumar C D On 05/08/2014 06:40 PM, Yuvaraj Kumar wrote: > Any comments on this patch? > > On Wed, Mar 26, 2014 at 5:16 PM, Yuvaraj Kumar C D <yuvaraj.cd@gmail.com> wrote: >> From: Sonny Rao <sonnyrao@chromium.org> >> >> This patch changes the fifo reset code to follow the reset procedure >> outlined in the documentation of Synopsys Mobile storage host databook >> 7.2.13. >> Without this patch, we could able to see eMMC was not detected after >> multiple reboots due to driver hangs while eMMC tuning for HS200. >> >> Signed-off-by: Sonny Rao <sonnyrao@chromium.org> >> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.org> >> --- >> drivers/mmc/host/dw_mmc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++- >> drivers/mmc/host/dw_mmc.h | 1 + >> 2 files changed, 48 insertions(+), 1 deletion(-) >> >> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c >> index 32dd81d..1d77431 100644 >> --- a/drivers/mmc/host/dw_mmc.c >> +++ b/drivers/mmc/host/dw_mmc.c >> @@ -2220,7 +2220,53 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) >> host->sg = NULL; >> } >> >> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >> + /* >> + * The recommended method for resetting is to always reset the >> + * controller and the fifo, but differs slightly depending on the mode. >> + * Note that this doesn't handle the "generic DMA" (not IDMAC) case. >> + */ "not IDMAC" is confused.. >> + if (dw_mci_ctrl_reset(host, SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET)) { >> + unsigned long timeout = jiffies + msecs_to_jiffies(500); >> + u32 status, rint; >> + >> + /* if using dma we wait for dma_req to clear */ >> + if (host->using_dma) { >> + do { >> + status = mci_readl(host, STATUS); >> + if (!(status & SDMMC_STATUS_DMA_REQ)) >> + break; >> + cpu_relax(); >> + } while (time_before(jiffies, timeout)); >> + >> + if (status & SDMMC_STATUS_DMA_REQ) >> + dev_err(host->dev, >> + "%s: Timeout waiting for dma_req to " >> + "clear during reset", __func__); >> + >> + /* when using DMA next we reset the fifo again */ >> + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >> + } >> + /* >> + * In all cases we clear the RAWINTS register to clear any >> + * interrupts. >> + */ >> + rint = mci_readl(host, RINTSTS); >> + rint = rint & (~mci_readl(host, MINTSTS)); Just clear the RINTSTS register? why do you add these? >> + if (rint) >> + mci_writel(host, RINTSTS, rint); >> + >> + } else >> + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); Just display the error log? I didn't understand this. If you displayed the error log, then it needs to return the error value. >> + >> + #ifdef CONFIG_MMC_DW_IDMAC >> + /* It is also recommended that we reset and reprogram idmac */ >> + dw_mci_idmac_reset(host); >> + #endif >> + >> + /* After a CTRL reset we need to have CIU set clock registers */ >> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); >> + >> + return true; >> } >> >> static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) >> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h >> index 738fa24..037e47a 100644 >> --- a/drivers/mmc/host/dw_mmc.h >> +++ b/drivers/mmc/host/dw_mmc.h >> @@ -129,6 +129,7 @@ >> #define SDMMC_CMD_INDX(n) ((n) & 0x1F) >> /* Status register defines */ >> #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) >> +#define SDMMC_STATUS_DMA_REQ BIT(31) >> /* FIFOTH register defines */ >> #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ >> ((r) & 0xFFF) << 16 | \ >> -- >> 1.7.10.4 >> > ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCH] mmc: dw_mmc: change to use recommended reset procedure @ 2014-05-09 1:15 ` Jaehoon Chung 0 siblings, 0 replies; 75+ messages in thread From: Jaehoon Chung @ 2014-05-09 1:15 UTC (permalink / raw) To: linux-arm-kernel On 05/08/2014 06:40 PM, Yuvaraj Kumar wrote: > Any comments on this patch? > > On Wed, Mar 26, 2014 at 5:16 PM, Yuvaraj Kumar C D <yuvaraj.cd@gmail.com> wrote: >> From: Sonny Rao <sonnyrao@chromium.org> >> >> This patch changes the fifo reset code to follow the reset procedure >> outlined in the documentation of Synopsys Mobile storage host databook >> 7.2.13. >> Without this patch, we could able to see eMMC was not detected after >> multiple reboots due to driver hangs while eMMC tuning for HS200. >> >> Signed-off-by: Sonny Rao <sonnyrao@chromium.org> >> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.org> >> --- >> drivers/mmc/host/dw_mmc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++- >> drivers/mmc/host/dw_mmc.h | 1 + >> 2 files changed, 48 insertions(+), 1 deletion(-) >> >> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c >> index 32dd81d..1d77431 100644 >> --- a/drivers/mmc/host/dw_mmc.c >> +++ b/drivers/mmc/host/dw_mmc.c >> @@ -2220,7 +2220,53 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) >> host->sg = NULL; >> } >> >> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >> + /* >> + * The recommended method for resetting is to always reset the >> + * controller and the fifo, but differs slightly depending on the mode. >> + * Note that this doesn't handle the "generic DMA" (not IDMAC) case. >> + */ "not IDMAC" is confused.. >> + if (dw_mci_ctrl_reset(host, SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET)) { >> + unsigned long timeout = jiffies + msecs_to_jiffies(500); >> + u32 status, rint; >> + >> + /* if using dma we wait for dma_req to clear */ >> + if (host->using_dma) { >> + do { >> + status = mci_readl(host, STATUS); >> + if (!(status & SDMMC_STATUS_DMA_REQ)) >> + break; >> + cpu_relax(); >> + } while (time_before(jiffies, timeout)); >> + >> + if (status & SDMMC_STATUS_DMA_REQ) >> + dev_err(host->dev, >> + "%s: Timeout waiting for dma_req to " >> + "clear during reset", __func__); >> + >> + /* when using DMA next we reset the fifo again */ >> + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >> + } >> + /* >> + * In all cases we clear the RAWINTS register to clear any >> + * interrupts. >> + */ >> + rint = mci_readl(host, RINTSTS); >> + rint = rint & (~mci_readl(host, MINTSTS)); Just clear the RINTSTS register? why do you add these? >> + if (rint) >> + mci_writel(host, RINTSTS, rint); >> + >> + } else >> + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); Just display the error log? I didn't understand this. If you displayed the error log, then it needs to return the error value. >> + >> + #ifdef CONFIG_MMC_DW_IDMAC >> + /* It is also recommended that we reset and reprogram idmac */ >> + dw_mci_idmac_reset(host); >> + #endif >> + >> + /* After a CTRL reset we need to have CIU set clock registers */ >> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); >> + >> + return true; >> } >> >> static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) >> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h >> index 738fa24..037e47a 100644 >> --- a/drivers/mmc/host/dw_mmc.h >> +++ b/drivers/mmc/host/dw_mmc.h >> @@ -129,6 +129,7 @@ >> #define SDMMC_CMD_INDX(n) ((n) & 0x1F) >> /* Status register defines */ >> #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) >> +#define SDMMC_STATUS_DMA_REQ BIT(31) >> /* FIFOTH register defines */ >> #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ >> ((r) & 0xFFF) << 16 | \ >> -- >> 1.7.10.4 >> > ^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCH] mmc: dw_mmc: change to use recommended reset procedure 2014-05-09 1:15 ` Jaehoon Chung @ 2014-05-09 1:34 ` Sonny Rao -1 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-05-09 1:34 UTC (permalink / raw) To: Jaehoon Chung Cc: Yuvaraj Kumar, Grant Grundler, linux-samsung-soc, linux-arm-kernel, Chris Ball, Seungwon Jeon, linux-mmc, kgene.kim, sunil joshi, Tomasz Figa, Yuvaraj Kumar C D On Thu, May 8, 2014 at 6:15 PM, Jaehoon Chung <jh80.chung@samsung.com> wrote: > On 05/08/2014 06:40 PM, Yuvaraj Kumar wrote: >> Any comments on this patch? >> >> On Wed, Mar 26, 2014 at 5:16 PM, Yuvaraj Kumar C D <yuvaraj.cd@gmail.com> wrote: >>> From: Sonny Rao <sonnyrao@chromium.org> >>> >>> This patch changes the fifo reset code to follow the reset procedure >>> outlined in the documentation of Synopsys Mobile storage host databook >>> 7.2.13. >>> Without this patch, we could able to see eMMC was not detected after >>> multiple reboots due to driver hangs while eMMC tuning for HS200. >>> >>> Signed-off-by: Sonny Rao <sonnyrao@chromium.org> >>> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.org> >>> --- >>> drivers/mmc/host/dw_mmc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++- >>> drivers/mmc/host/dw_mmc.h | 1 + >>> 2 files changed, 48 insertions(+), 1 deletion(-) >>> >>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c >>> index 32dd81d..1d77431 100644 >>> --- a/drivers/mmc/host/dw_mmc.c >>> +++ b/drivers/mmc/host/dw_mmc.c >>> @@ -2220,7 +2220,53 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) >>> host->sg = NULL; >>> } >>> >>> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >>> + /* >>> + * The recommended method for resetting is to always reset the >>> + * controller and the fifo, but differs slightly depending on the mode. >>> + * Note that this doesn't handle the "generic DMA" (not IDMAC) case. >>> + */ > > "not IDMAC" is confused.. > The documentation describes three different possible modes. There's a mode that doesn't use IDMAC but still does DMA. But as far as I can tell this driver doesn't support that way. We can just remove that wording if it's confusing. >>> + if (dw_mci_ctrl_reset(host, SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET)) { >>> + unsigned long timeout = jiffies + msecs_to_jiffies(500); >>> + u32 status, rint; >>> + >>> + /* if using dma we wait for dma_req to clear */ >>> + if (host->using_dma) { >>> + do { >>> + status = mci_readl(host, STATUS); >>> + if (!(status & SDMMC_STATUS_DMA_REQ)) >>> + break; >>> + cpu_relax(); >>> + } while (time_before(jiffies, timeout)); >>> + >>> + if (status & SDMMC_STATUS_DMA_REQ) >>> + dev_err(host->dev, >>> + "%s: Timeout waiting for dma_req to " >>> + "clear during reset", __func__); >>> + >>> + /* when using DMA next we reset the fifo again */ >>> + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >>> + } >>> + /* >>> + * In all cases we clear the RAWINTS register to clear any >>> + * interrupts. >>> + */ >>> + rint = mci_readl(host, RINTSTS); >>> + rint = rint & (~mci_readl(host, MINTSTS)); > > Just clear the RINTSTS register? why do you add these? > This will look at what is not masked, and only clear those bits. >>> + if (rint) >>> + mci_writel(host, RINTSTS, rint); >>> + >>> + } else >>> + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); > > Just display the error log? I didn't understand this. > If you displayed the error log, then it needs to return the error value. > >>> + >>> + #ifdef CONFIG_MMC_DW_IDMAC >>> + /* It is also recommended that we reset and reprogram idmac */ >>> + dw_mci_idmac_reset(host); >>> + #endif >>> + >>> + /* After a CTRL reset we need to have CIU set clock registers */ >>> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); >>> + >>> + return true; >>> } >>> >>> static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) >>> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h >>> index 738fa24..037e47a 100644 >>> --- a/drivers/mmc/host/dw_mmc.h >>> +++ b/drivers/mmc/host/dw_mmc.h >>> @@ -129,6 +129,7 @@ >>> #define SDMMC_CMD_INDX(n) ((n) & 0x1F) >>> /* Status register defines */ >>> #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) >>> +#define SDMMC_STATUS_DMA_REQ BIT(31) >>> /* FIFOTH register defines */ >>> #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ >>> ((r) & 0xFFF) << 16 | \ >>> -- >>> 1.7.10.4 >>> >> > ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCH] mmc: dw_mmc: change to use recommended reset procedure @ 2014-05-09 1:34 ` Sonny Rao 0 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-05-09 1:34 UTC (permalink / raw) To: linux-arm-kernel On Thu, May 8, 2014 at 6:15 PM, Jaehoon Chung <jh80.chung@samsung.com> wrote: > On 05/08/2014 06:40 PM, Yuvaraj Kumar wrote: >> Any comments on this patch? >> >> On Wed, Mar 26, 2014 at 5:16 PM, Yuvaraj Kumar C D <yuvaraj.cd@gmail.com> wrote: >>> From: Sonny Rao <sonnyrao@chromium.org> >>> >>> This patch changes the fifo reset code to follow the reset procedure >>> outlined in the documentation of Synopsys Mobile storage host databook >>> 7.2.13. >>> Without this patch, we could able to see eMMC was not detected after >>> multiple reboots due to driver hangs while eMMC tuning for HS200. >>> >>> Signed-off-by: Sonny Rao <sonnyrao@chromium.org> >>> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.org> >>> --- >>> drivers/mmc/host/dw_mmc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++- >>> drivers/mmc/host/dw_mmc.h | 1 + >>> 2 files changed, 48 insertions(+), 1 deletion(-) >>> >>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c >>> index 32dd81d..1d77431 100644 >>> --- a/drivers/mmc/host/dw_mmc.c >>> +++ b/drivers/mmc/host/dw_mmc.c >>> @@ -2220,7 +2220,53 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) >>> host->sg = NULL; >>> } >>> >>> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >>> + /* >>> + * The recommended method for resetting is to always reset the >>> + * controller and the fifo, but differs slightly depending on the mode. >>> + * Note that this doesn't handle the "generic DMA" (not IDMAC) case. >>> + */ > > "not IDMAC" is confused.. > The documentation describes three different possible modes. There's a mode that doesn't use IDMAC but still does DMA. But as far as I can tell this driver doesn't support that way. We can just remove that wording if it's confusing. >>> + if (dw_mci_ctrl_reset(host, SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET)) { >>> + unsigned long timeout = jiffies + msecs_to_jiffies(500); >>> + u32 status, rint; >>> + >>> + /* if using dma we wait for dma_req to clear */ >>> + if (host->using_dma) { >>> + do { >>> + status = mci_readl(host, STATUS); >>> + if (!(status & SDMMC_STATUS_DMA_REQ)) >>> + break; >>> + cpu_relax(); >>> + } while (time_before(jiffies, timeout)); >>> + >>> + if (status & SDMMC_STATUS_DMA_REQ) >>> + dev_err(host->dev, >>> + "%s: Timeout waiting for dma_req to " >>> + "clear during reset", __func__); >>> + >>> + /* when using DMA next we reset the fifo again */ >>> + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >>> + } >>> + /* >>> + * In all cases we clear the RAWINTS register to clear any >>> + * interrupts. >>> + */ >>> + rint = mci_readl(host, RINTSTS); >>> + rint = rint & (~mci_readl(host, MINTSTS)); > > Just clear the RINTSTS register? why do you add these? > This will look at what is not masked, and only clear those bits. >>> + if (rint) >>> + mci_writel(host, RINTSTS, rint); >>> + >>> + } else >>> + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); > > Just display the error log? I didn't understand this. > If you displayed the error log, then it needs to return the error value. > >>> + >>> + #ifdef CONFIG_MMC_DW_IDMAC >>> + /* It is also recommended that we reset and reprogram idmac */ >>> + dw_mci_idmac_reset(host); >>> + #endif >>> + >>> + /* After a CTRL reset we need to have CIU set clock registers */ >>> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); >>> + >>> + return true; >>> } >>> >>> static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) >>> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h >>> index 738fa24..037e47a 100644 >>> --- a/drivers/mmc/host/dw_mmc.h >>> +++ b/drivers/mmc/host/dw_mmc.h >>> @@ -129,6 +129,7 @@ >>> #define SDMMC_CMD_INDX(n) ((n) & 0x1F) >>> /* Status register defines */ >>> #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) >>> +#define SDMMC_STATUS_DMA_REQ BIT(31) >>> /* FIFOTH register defines */ >>> #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ >>> ((r) & 0xFFF) << 16 | \ >>> -- >>> 1.7.10.4 >>> >> > ^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCH] mmc: dw_mmc: change to use recommended reset procedure 2014-05-09 1:34 ` Sonny Rao @ 2014-05-09 4:27 ` Jaehoon Chung -1 siblings, 0 replies; 75+ messages in thread From: Jaehoon Chung @ 2014-05-09 4:27 UTC (permalink / raw) To: Sonny Rao, Jaehoon Chung Cc: Yuvaraj Kumar, Grant Grundler, linux-samsung-soc, linux-arm-kernel, Chris Ball, Seungwon Jeon, linux-mmc, kgene.kim, sunil joshi, Tomasz Figa, Yuvaraj Kumar C D Hi, Sonny. I have checked the Synopsys TRM.. On 05/09/2014 10:34 AM, Sonny Rao wrote: > On Thu, May 8, 2014 at 6:15 PM, Jaehoon Chung <jh80.chung@samsung.com> wrote: >> On 05/08/2014 06:40 PM, Yuvaraj Kumar wrote: >>> Any comments on this patch? >>> >>> On Wed, Mar 26, 2014 at 5:16 PM, Yuvaraj Kumar C D <yuvaraj.cd@gmail.com> wrote: >>>> From: Sonny Rao <sonnyrao@chromium.org> >>>> >>>> This patch changes the fifo reset code to follow the reset procedure >>>> outlined in the documentation of Synopsys Mobile storage host databook >>>> 7.2.13. >>>> Without this patch, we could able to see eMMC was not detected after >>>> multiple reboots due to driver hangs while eMMC tuning for HS200. >>>> >>>> Signed-off-by: Sonny Rao <sonnyrao@chromium.org> >>>> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.org> >>>> --- >>>> drivers/mmc/host/dw_mmc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++- >>>> drivers/mmc/host/dw_mmc.h | 1 + >>>> 2 files changed, 48 insertions(+), 1 deletion(-) >>>> >>>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c >>>> index 32dd81d..1d77431 100644 >>>> --- a/drivers/mmc/host/dw_mmc.c >>>> +++ b/drivers/mmc/host/dw_mmc.c >>>> @@ -2220,7 +2220,53 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) >>>> host->sg = NULL; >>>> } >>>> >>>> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >>>> + /* >>>> + * The recommended method for resetting is to always reset the >>>> + * controller and the fifo, but differs slightly depending on the mode. >>>> + * Note that this doesn't handle the "generic DMA" (not IDMAC) case. >>>> + */ >> >> "not IDMAC" is confused.. >> > > The documentation describes three different possible modes. There's a > mode that doesn't use IDMAC but still does DMA. But as far as I can > tell this driver doesn't support that way. We can just remove that > wording if it's confusing. > >>>> + if (dw_mci_ctrl_reset(host, SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET)) { >>>> + unsigned long timeout = jiffies + msecs_to_jiffies(500); >>>> + u32 status, rint; >>>> + >>>> + /* if using dma we wait for dma_req to clear */ >>>> + if (host->using_dma) { >>>> + do { >>>> + status = mci_readl(host, STATUS); >>>> + if (!(status & SDMMC_STATUS_DMA_REQ)) >>>> + break; >>>> + cpu_relax(); >>>> + } while (time_before(jiffies, timeout)); >>>> + >>>> + if (status & SDMMC_STATUS_DMA_REQ) >>>> + dev_err(host->dev, >>>> + "%s: Timeout waiting for dma_req to " >>>> + "clear during reset", __func__); >>>> + >>>> + /* when using DMA next we reset the fifo again */ >>>> + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >>>> + } >>>> + /* >>>> + * In all cases we clear the RAWINTS register to clear any >>>> + * interrupts. >>>> + */ >>>> + rint = mci_readl(host, RINTSTS); >>>> + rint = rint & (~mci_readl(host, MINTSTS)); you use the "status or temp" instead of rint. (you can reuse the variable.) And can use "status &= ~mci_readl(host,MINTSTS);" >> >> Just clear the RINTSTS register? why do you add these? >> > > This will look at what is not masked, and only clear those bits. Well, i known if clear the RINTSTS register, recommended to use "0xfffffff" and set the value for interrupt. > >>>> + if (rint) >>>> + mci_writel(host, RINTSTS, rint); >>>> + >>>> + } else >>>> + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); >> >> Just display the error log? I didn't understand this. >> If you displayed the error log, then it needs to return the error value. >> >>>> + >>>> + #ifdef CONFIG_MMC_DW_IDMAC >>>> + /* It is also recommended that we reset and reprogram idmac */ >>>> + dw_mci_idmac_reset(host); >>>> + #endif >>>> + >>>> + /* After a CTRL reset we need to have CIU set clock registers */ >>>> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); Well, why do you send the clock update command? I didn't see that update the value related with clock. Best Regards, Jaehoon Chung >>>> + >>>> + return true; >>>> } >>>> >>>> static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) >>>> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h >>>> index 738fa24..037e47a 100644 >>>> --- a/drivers/mmc/host/dw_mmc.h >>>> +++ b/drivers/mmc/host/dw_mmc.h >>>> @@ -129,6 +129,7 @@ >>>> #define SDMMC_CMD_INDX(n) ((n) & 0x1F) >>>> /* Status register defines */ >>>> #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) >>>> +#define SDMMC_STATUS_DMA_REQ BIT(31) >>>> /* FIFOTH register defines */ >>>> #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ >>>> ((r) & 0xFFF) << 16 | \ >>>> -- >>>> 1.7.10.4 >>>> >>> >> > -- > To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCH] mmc: dw_mmc: change to use recommended reset procedure @ 2014-05-09 4:27 ` Jaehoon Chung 0 siblings, 0 replies; 75+ messages in thread From: Jaehoon Chung @ 2014-05-09 4:27 UTC (permalink / raw) To: linux-arm-kernel Hi, Sonny. I have checked the Synopsys TRM.. On 05/09/2014 10:34 AM, Sonny Rao wrote: > On Thu, May 8, 2014 at 6:15 PM, Jaehoon Chung <jh80.chung@samsung.com> wrote: >> On 05/08/2014 06:40 PM, Yuvaraj Kumar wrote: >>> Any comments on this patch? >>> >>> On Wed, Mar 26, 2014 at 5:16 PM, Yuvaraj Kumar C D <yuvaraj.cd@gmail.com> wrote: >>>> From: Sonny Rao <sonnyrao@chromium.org> >>>> >>>> This patch changes the fifo reset code to follow the reset procedure >>>> outlined in the documentation of Synopsys Mobile storage host databook >>>> 7.2.13. >>>> Without this patch, we could able to see eMMC was not detected after >>>> multiple reboots due to driver hangs while eMMC tuning for HS200. >>>> >>>> Signed-off-by: Sonny Rao <sonnyrao@chromium.org> >>>> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.org> >>>> --- >>>> drivers/mmc/host/dw_mmc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++- >>>> drivers/mmc/host/dw_mmc.h | 1 + >>>> 2 files changed, 48 insertions(+), 1 deletion(-) >>>> >>>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c >>>> index 32dd81d..1d77431 100644 >>>> --- a/drivers/mmc/host/dw_mmc.c >>>> +++ b/drivers/mmc/host/dw_mmc.c >>>> @@ -2220,7 +2220,53 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) >>>> host->sg = NULL; >>>> } >>>> >>>> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >>>> + /* >>>> + * The recommended method for resetting is to always reset the >>>> + * controller and the fifo, but differs slightly depending on the mode. >>>> + * Note that this doesn't handle the "generic DMA" (not IDMAC) case. >>>> + */ >> >> "not IDMAC" is confused.. >> > > The documentation describes three different possible modes. There's a > mode that doesn't use IDMAC but still does DMA. But as far as I can > tell this driver doesn't support that way. We can just remove that > wording if it's confusing. > >>>> + if (dw_mci_ctrl_reset(host, SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET)) { >>>> + unsigned long timeout = jiffies + msecs_to_jiffies(500); >>>> + u32 status, rint; >>>> + >>>> + /* if using dma we wait for dma_req to clear */ >>>> + if (host->using_dma) { >>>> + do { >>>> + status = mci_readl(host, STATUS); >>>> + if (!(status & SDMMC_STATUS_DMA_REQ)) >>>> + break; >>>> + cpu_relax(); >>>> + } while (time_before(jiffies, timeout)); >>>> + >>>> + if (status & SDMMC_STATUS_DMA_REQ) >>>> + dev_err(host->dev, >>>> + "%s: Timeout waiting for dma_req to " >>>> + "clear during reset", __func__); >>>> + >>>> + /* when using DMA next we reset the fifo again */ >>>> + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >>>> + } >>>> + /* >>>> + * In all cases we clear the RAWINTS register to clear any >>>> + * interrupts. >>>> + */ >>>> + rint = mci_readl(host, RINTSTS); >>>> + rint = rint & (~mci_readl(host, MINTSTS)); you use the "status or temp" instead of rint. (you can reuse the variable.) And can use "status &= ~mci_readl(host,MINTSTS);" >> >> Just clear the RINTSTS register? why do you add these? >> > > This will look at what is not masked, and only clear those bits. Well, i known if clear the RINTSTS register, recommended to use "0xfffffff" and set the value for interrupt. > >>>> + if (rint) >>>> + mci_writel(host, RINTSTS, rint); >>>> + >>>> + } else >>>> + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); >> >> Just display the error log? I didn't understand this. >> If you displayed the error log, then it needs to return the error value. >> >>>> + >>>> + #ifdef CONFIG_MMC_DW_IDMAC >>>> + /* It is also recommended that we reset and reprogram idmac */ >>>> + dw_mci_idmac_reset(host); >>>> + #endif >>>> + >>>> + /* After a CTRL reset we need to have CIU set clock registers */ >>>> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); Well, why do you send the clock update command? I didn't see that update the value related with clock. Best Regards, Jaehoon Chung >>>> + >>>> + return true; >>>> } >>>> >>>> static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) >>>> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h >>>> index 738fa24..037e47a 100644 >>>> --- a/drivers/mmc/host/dw_mmc.h >>>> +++ b/drivers/mmc/host/dw_mmc.h >>>> @@ -129,6 +129,7 @@ >>>> #define SDMMC_CMD_INDX(n) ((n) & 0x1F) >>>> /* Status register defines */ >>>> #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) >>>> +#define SDMMC_STATUS_DMA_REQ BIT(31) >>>> /* FIFOTH register defines */ >>>> #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ >>>> ((r) & 0xFFF) << 16 | \ >>>> -- >>>> 1.7.10.4 >>>> >>> >> > -- > To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > the body of a message to majordomo at vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > ^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCH] mmc: dw_mmc: change to use recommended reset procedure 2014-05-09 4:27 ` Jaehoon Chung @ 2014-05-09 7:32 ` Jaehoon Chung -1 siblings, 0 replies; 75+ messages in thread From: Jaehoon Chung @ 2014-05-09 7:32 UTC (permalink / raw) To: Jaehoon Chung, Sonny Rao Cc: Yuvaraj Kumar, Grant Grundler, linux-samsung-soc, linux-arm-kernel, Chris Ball, Seungwon Jeon, linux-mmc, kgene.kim, sunil joshi, Tomasz Figa, Yuvaraj Kumar C D Hi, Sonny. You can discard the my previous some comment. As you mentioned, this reset sequence is recommended at Synopsys TRM. Add the minor question. On 05/09/2014 01:27 PM, Jaehoon Chung wrote: > Hi, Sonny. > > I have checked the Synopsys TRM.. > > On 05/09/2014 10:34 AM, Sonny Rao wrote: >> On Thu, May 8, 2014 at 6:15 PM, Jaehoon Chung <jh80.chung@samsung.com> wrote: >>> On 05/08/2014 06:40 PM, Yuvaraj Kumar wrote: >>>> Any comments on this patch? >>>> >>>> On Wed, Mar 26, 2014 at 5:16 PM, Yuvaraj Kumar C D <yuvaraj.cd@gmail.com> wrote: >>>>> From: Sonny Rao <sonnyrao@chromium.org> >>>>> >>>>> This patch changes the fifo reset code to follow the reset procedure >>>>> outlined in the documentation of Synopsys Mobile storage host databook >>>>> 7.2.13. >>>>> Without this patch, we could able to see eMMC was not detected after >>>>> multiple reboots due to driver hangs while eMMC tuning for HS200. >>>>> >>>>> Signed-off-by: Sonny Rao <sonnyrao@chromium.org> >>>>> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.org> >>>>> --- >>>>> drivers/mmc/host/dw_mmc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++- >>>>> drivers/mmc/host/dw_mmc.h | 1 + >>>>> 2 files changed, 48 insertions(+), 1 deletion(-) >>>>> >>>>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c >>>>> index 32dd81d..1d77431 100644 >>>>> --- a/drivers/mmc/host/dw_mmc.c >>>>> +++ b/drivers/mmc/host/dw_mmc.c >>>>> @@ -2220,7 +2220,53 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) >>>>> host->sg = NULL; >>>>> } >>>>> >>>>> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >>>>> + /* >>>>> + * The recommended method for resetting is to always reset the >>>>> + * controller and the fifo, but differs slightly depending on the mode. >>>>> + * Note that this doesn't handle the "generic DMA" (not IDMAC) case. >>>>> + */ >>> >>> "not IDMAC" is confused.. >>> >> >> The documentation describes three different possible modes. There's a >> mode that doesn't use IDMAC but still does DMA. But as far as I can >> tell this driver doesn't support that way. We can just remove that >> wording if it's confusing. How did it know whether dma is generic DMA or not? >> >>>>> + if (dw_mci_ctrl_reset(host, SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET)) { >>>>> + unsigned long timeout = jiffies + msecs_to_jiffies(500); >>>>> + u32 status, rint; >>>>> + >>>>> + /* if using dma we wait for dma_req to clear */ >>>>> + if (host->using_dma) { >>>>> + do { >>>>> + status = mci_readl(host, STATUS); >>>>> + if (!(status & SDMMC_STATUS_DMA_REQ)) >>>>> + break; >>>>> + cpu_relax(); >>>>> + } while (time_before(jiffies, timeout)); >>>>> + >>>>> + if (status & SDMMC_STATUS_DMA_REQ) >>>>> + dev_err(host->dev, >>>>> + "%s: Timeout waiting for dma_req to " >>>>> + "clear during reset", __func__); >>>>> + >>>>> + /* when using DMA next we reset the fifo again */ >>>>> + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >>>>> + } >>>>> + /* >>>>> + * In all cases we clear the RAWINTS register to clear any >>>>> + * interrupts. >>>>> + */ >>>>> + rint = mci_readl(host, RINTSTS); >>>>> + rint = rint & (~mci_readl(host, MINTSTS)); > you use the "status or temp" instead of rint. (you can reuse the variable.) > And can use "status &= ~mci_readl(host,MINTSTS);" > >>> >>> Just clear the RINTSTS register? why do you add these? >>> >> >> This will look at what is not masked, and only clear those bits. > Well, i known if clear the RINTSTS register, > recommended to use "0xfffffff" and set the value for interrupt. Can be used "0xfffffff"? Best Regards, Jaehoon Chung > >> >>>>> + if (rint) >>>>> + mci_writel(host, RINTSTS, rint); >>>>> + >>>>> + } else >>>>> + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); >>> >>> Just display the error log? I didn't understand this. >>> If you displayed the error log, then it needs to return the error value. >>> >>>>> + >>>>> + #ifdef CONFIG_MMC_DW_IDMAC >>>>> + /* It is also recommended that we reset and reprogram idmac */ >>>>> + dw_mci_idmac_reset(host); >>>>> + #endif >>>>> + >>>>> + /* After a CTRL reset we need to have CIU set clock registers */ >>>>> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); > > Well, why do you send the clock update command? > I didn't see that update the value related with clock. > > Best Regards, > Jaehoon Chung > >>>>> + >>>>> + return true; >>>>> } >>>>> >>>>> static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) >>>>> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h >>>>> index 738fa24..037e47a 100644 >>>>> --- a/drivers/mmc/host/dw_mmc.h >>>>> +++ b/drivers/mmc/host/dw_mmc.h >>>>> @@ -129,6 +129,7 @@ >>>>> #define SDMMC_CMD_INDX(n) ((n) & 0x1F) >>>>> /* Status register defines */ >>>>> #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) >>>>> +#define SDMMC_STATUS_DMA_REQ BIT(31) >>>>> /* FIFOTH register defines */ >>>>> #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ >>>>> ((r) & 0xFFF) << 16 | \ >>>>> -- >>>>> 1.7.10.4 >>>>> >>>> >>> >> -- >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >> the body of a message to majordomo@vger.kernel.org >> More majordomo info at http://vger.kernel.org/majordomo-info.html >> > > -- > To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCH] mmc: dw_mmc: change to use recommended reset procedure @ 2014-05-09 7:32 ` Jaehoon Chung 0 siblings, 0 replies; 75+ messages in thread From: Jaehoon Chung @ 2014-05-09 7:32 UTC (permalink / raw) To: linux-arm-kernel Hi, Sonny. You can discard the my previous some comment. As you mentioned, this reset sequence is recommended at Synopsys TRM. Add the minor question. On 05/09/2014 01:27 PM, Jaehoon Chung wrote: > Hi, Sonny. > > I have checked the Synopsys TRM.. > > On 05/09/2014 10:34 AM, Sonny Rao wrote: >> On Thu, May 8, 2014 at 6:15 PM, Jaehoon Chung <jh80.chung@samsung.com> wrote: >>> On 05/08/2014 06:40 PM, Yuvaraj Kumar wrote: >>>> Any comments on this patch? >>>> >>>> On Wed, Mar 26, 2014 at 5:16 PM, Yuvaraj Kumar C D <yuvaraj.cd@gmail.com> wrote: >>>>> From: Sonny Rao <sonnyrao@chromium.org> >>>>> >>>>> This patch changes the fifo reset code to follow the reset procedure >>>>> outlined in the documentation of Synopsys Mobile storage host databook >>>>> 7.2.13. >>>>> Without this patch, we could able to see eMMC was not detected after >>>>> multiple reboots due to driver hangs while eMMC tuning for HS200. >>>>> >>>>> Signed-off-by: Sonny Rao <sonnyrao@chromium.org> >>>>> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.org> >>>>> --- >>>>> drivers/mmc/host/dw_mmc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++- >>>>> drivers/mmc/host/dw_mmc.h | 1 + >>>>> 2 files changed, 48 insertions(+), 1 deletion(-) >>>>> >>>>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c >>>>> index 32dd81d..1d77431 100644 >>>>> --- a/drivers/mmc/host/dw_mmc.c >>>>> +++ b/drivers/mmc/host/dw_mmc.c >>>>> @@ -2220,7 +2220,53 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) >>>>> host->sg = NULL; >>>>> } >>>>> >>>>> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >>>>> + /* >>>>> + * The recommended method for resetting is to always reset the >>>>> + * controller and the fifo, but differs slightly depending on the mode. >>>>> + * Note that this doesn't handle the "generic DMA" (not IDMAC) case. >>>>> + */ >>> >>> "not IDMAC" is confused.. >>> >> >> The documentation describes three different possible modes. There's a >> mode that doesn't use IDMAC but still does DMA. But as far as I can >> tell this driver doesn't support that way. We can just remove that >> wording if it's confusing. How did it know whether dma is generic DMA or not? >> >>>>> + if (dw_mci_ctrl_reset(host, SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET)) { >>>>> + unsigned long timeout = jiffies + msecs_to_jiffies(500); >>>>> + u32 status, rint; >>>>> + >>>>> + /* if using dma we wait for dma_req to clear */ >>>>> + if (host->using_dma) { >>>>> + do { >>>>> + status = mci_readl(host, STATUS); >>>>> + if (!(status & SDMMC_STATUS_DMA_REQ)) >>>>> + break; >>>>> + cpu_relax(); >>>>> + } while (time_before(jiffies, timeout)); >>>>> + >>>>> + if (status & SDMMC_STATUS_DMA_REQ) >>>>> + dev_err(host->dev, >>>>> + "%s: Timeout waiting for dma_req to " >>>>> + "clear during reset", __func__); >>>>> + >>>>> + /* when using DMA next we reset the fifo again */ >>>>> + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >>>>> + } >>>>> + /* >>>>> + * In all cases we clear the RAWINTS register to clear any >>>>> + * interrupts. >>>>> + */ >>>>> + rint = mci_readl(host, RINTSTS); >>>>> + rint = rint & (~mci_readl(host, MINTSTS)); > you use the "status or temp" instead of rint. (you can reuse the variable.) > And can use "status &= ~mci_readl(host,MINTSTS);" > >>> >>> Just clear the RINTSTS register? why do you add these? >>> >> >> This will look at what is not masked, and only clear those bits. > Well, i known if clear the RINTSTS register, > recommended to use "0xfffffff" and set the value for interrupt. Can be used "0xfffffff"? Best Regards, Jaehoon Chung > >> >>>>> + if (rint) >>>>> + mci_writel(host, RINTSTS, rint); >>>>> + >>>>> + } else >>>>> + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); >>> >>> Just display the error log? I didn't understand this. >>> If you displayed the error log, then it needs to return the error value. >>> >>>>> + >>>>> + #ifdef CONFIG_MMC_DW_IDMAC >>>>> + /* It is also recommended that we reset and reprogram idmac */ >>>>> + dw_mci_idmac_reset(host); >>>>> + #endif >>>>> + >>>>> + /* After a CTRL reset we need to have CIU set clock registers */ >>>>> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); > > Well, why do you send the clock update command? > I didn't see that update the value related with clock. > > Best Regards, > Jaehoon Chung > >>>>> + >>>>> + return true; >>>>> } >>>>> >>>>> static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) >>>>> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h >>>>> index 738fa24..037e47a 100644 >>>>> --- a/drivers/mmc/host/dw_mmc.h >>>>> +++ b/drivers/mmc/host/dw_mmc.h >>>>> @@ -129,6 +129,7 @@ >>>>> #define SDMMC_CMD_INDX(n) ((n) & 0x1F) >>>>> /* Status register defines */ >>>>> #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) >>>>> +#define SDMMC_STATUS_DMA_REQ BIT(31) >>>>> /* FIFOTH register defines */ >>>>> #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ >>>>> ((r) & 0xFFF) << 16 | \ >>>>> -- >>>>> 1.7.10.4 >>>>> >>>> >>> >> -- >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >> the body of a message to majordomo at vger.kernel.org >> More majordomo info at http://vger.kernel.org/majordomo-info.html >> > > -- > To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > the body of a message to majordomo at vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > ^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCH] mmc: dw_mmc: change to use recommended reset procedure 2014-05-09 7:32 ` Jaehoon Chung @ 2014-05-10 3:36 ` Sonny Rao -1 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-05-10 3:36 UTC (permalink / raw) To: Jaehoon Chung Cc: Yuvaraj Kumar, Grant Grundler, linux-samsung-soc, linux-arm-kernel, Chris Ball, Seungwon Jeon, linux-mmc, kgene.kim, sunil joshi, Tomasz Figa, Yuvaraj Kumar C D On Fri, May 9, 2014 at 12:32 AM, Jaehoon Chung <jh80.chung@samsung.com> wrote: > Hi, Sonny. > > You can discard the my previous some comment. > As you mentioned, this reset sequence is recommended at Synopsys TRM. > > Add the minor question. > > On 05/09/2014 01:27 PM, Jaehoon Chung wrote: >> Hi, Sonny. >> >> I have checked the Synopsys TRM.. >> >> On 05/09/2014 10:34 AM, Sonny Rao wrote: >>> On Thu, May 8, 2014 at 6:15 PM, Jaehoon Chung <jh80.chung@samsung.com> wrote: >>>> On 05/08/2014 06:40 PM, Yuvaraj Kumar wrote: >>>>> Any comments on this patch? >>>>> >>>>> On Wed, Mar 26, 2014 at 5:16 PM, Yuvaraj Kumar C D <yuvaraj.cd@gmail.com> wrote: >>>>>> From: Sonny Rao <sonnyrao@chromium.org> >>>>>> >>>>>> This patch changes the fifo reset code to follow the reset procedure >>>>>> outlined in the documentation of Synopsys Mobile storage host databook >>>>>> 7.2.13. >>>>>> Without this patch, we could able to see eMMC was not detected after >>>>>> multiple reboots due to driver hangs while eMMC tuning for HS200. >>>>>> >>>>>> Signed-off-by: Sonny Rao <sonnyrao@chromium.org> >>>>>> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.org> >>>>>> --- >>>>>> drivers/mmc/host/dw_mmc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++- >>>>>> drivers/mmc/host/dw_mmc.h | 1 + >>>>>> 2 files changed, 48 insertions(+), 1 deletion(-) >>>>>> >>>>>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c >>>>>> index 32dd81d..1d77431 100644 >>>>>> --- a/drivers/mmc/host/dw_mmc.c >>>>>> +++ b/drivers/mmc/host/dw_mmc.c >>>>>> @@ -2220,7 +2220,53 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) >>>>>> host->sg = NULL; >>>>>> } >>>>>> >>>>>> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >>>>>> + /* >>>>>> + * The recommended method for resetting is to always reset the >>>>>> + * controller and the fifo, but differs slightly depending on the mode. >>>>>> + * Note that this doesn't handle the "generic DMA" (not IDMAC) case. >>>>>> + */ >>>> >>>> "not IDMAC" is confused.. >>>> >>> >>> The documentation describes three different possible modes. There's a >>> mode that doesn't use IDMAC but still does DMA. But as far as I can >>> tell this driver doesn't support that way. We can just remove that >>> wording if it's confusing. > > How did it know whether dma is generic DMA or not? > That's a good question. I wasn't sure whether the driver supported it or not. It looks like it definitely supports IDMAC through the CONFIG_MMC_DW_IDMAC flag, but I wasn't sure if it was supported the generic dma. Maybe if CONFIG_MMC_DW_IDMAC isn't specified but host->dma_ops is not NULL then we are using the generic dma mode. >>> >>>>>> + if (dw_mci_ctrl_reset(host, SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET)) { >>>>>> + unsigned long timeout = jiffies + msecs_to_jiffies(500); >>>>>> + u32 status, rint; >>>>>> + >>>>>> + /* if using dma we wait for dma_req to clear */ >>>>>> + if (host->using_dma) { >>>>>> + do { >>>>>> + status = mci_readl(host, STATUS); >>>>>> + if (!(status & SDMMC_STATUS_DMA_REQ)) >>>>>> + break; >>>>>> + cpu_relax(); >>>>>> + } while (time_before(jiffies, timeout)); >>>>>> + >>>>>> + if (status & SDMMC_STATUS_DMA_REQ) >>>>>> + dev_err(host->dev, >>>>>> + "%s: Timeout waiting for dma_req to " >>>>>> + "clear during reset", __func__); >>>>>> + >>>>>> + /* when using DMA next we reset the fifo again */ >>>>>> + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >>>>>> + } >>>>>> + /* >>>>>> + * In all cases we clear the RAWINTS register to clear any >>>>>> + * interrupts. >>>>>> + */ >>>>>> + rint = mci_readl(host, RINTSTS); >>>>>> + rint = rint & (~mci_readl(host, MINTSTS)); >> you use the "status or temp" instead of rint. (you can reuse the variable.) >> And can use "status &= ~mci_readl(host,MINTSTS);" >> >>>> >>>> Just clear the RINTSTS register? why do you add these? >>>> >>> >>> This will look at what is not masked, and only clear those bits. >> Well, i known if clear the RINTSTS register, >> recommended to use "0xfffffff" and set the value for interrupt. > > Can be used "0xfffffff"? > Yeah we probably can. We just lose information about interrupts that were masked, but maybe we just don't care about any of them anyway, so it doesn't matter. > Best Regards, > Jaehoon Chung >> >>> >>>>>> + if (rint) >>>>>> + mci_writel(host, RINTSTS, rint); >>>>>> + >>>>>> + } else >>>>>> + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); >>>> >>>> Just display the error log? I didn't understand this. >>>> If you displayed the error log, then it needs to return the error value. >>>> >>>>>> + >>>>>> + #ifdef CONFIG_MMC_DW_IDMAC >>>>>> + /* It is also recommended that we reset and reprogram idmac */ >>>>>> + dw_mci_idmac_reset(host); >>>>>> + #endif >>>>>> + >>>>>> + /* After a CTRL reset we need to have CIU set clock registers */ >>>>>> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); >> >> Well, why do you send the clock update command? >> I didn't see that update the value related with clock. >> >> Best Regards, >> Jaehoon Chung >> >>>>>> + >>>>>> + return true; >>>>>> } >>>>>> >>>>>> static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) >>>>>> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h >>>>>> index 738fa24..037e47a 100644 >>>>>> --- a/drivers/mmc/host/dw_mmc.h >>>>>> +++ b/drivers/mmc/host/dw_mmc.h >>>>>> @@ -129,6 +129,7 @@ >>>>>> #define SDMMC_CMD_INDX(n) ((n) & 0x1F) >>>>>> /* Status register defines */ >>>>>> #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) >>>>>> +#define SDMMC_STATUS_DMA_REQ BIT(31) >>>>>> /* FIFOTH register defines */ >>>>>> #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ >>>>>> ((r) & 0xFFF) << 16 | \ >>>>>> -- >>>>>> 1.7.10.4 >>>>>> >>>>> >>>> >>> -- >>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >>> the body of a message to majordomo@vger.kernel.org >>> More majordomo info at http://vger.kernel.org/majordomo-info.html >>> >> >> -- >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >> the body of a message to majordomo@vger.kernel.org >> More majordomo info at http://vger.kernel.org/majordomo-info.html >> > ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCH] mmc: dw_mmc: change to use recommended reset procedure @ 2014-05-10 3:36 ` Sonny Rao 0 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-05-10 3:36 UTC (permalink / raw) To: linux-arm-kernel On Fri, May 9, 2014 at 12:32 AM, Jaehoon Chung <jh80.chung@samsung.com> wrote: > Hi, Sonny. > > You can discard the my previous some comment. > As you mentioned, this reset sequence is recommended at Synopsys TRM. > > Add the minor question. > > On 05/09/2014 01:27 PM, Jaehoon Chung wrote: >> Hi, Sonny. >> >> I have checked the Synopsys TRM.. >> >> On 05/09/2014 10:34 AM, Sonny Rao wrote: >>> On Thu, May 8, 2014 at 6:15 PM, Jaehoon Chung <jh80.chung@samsung.com> wrote: >>>> On 05/08/2014 06:40 PM, Yuvaraj Kumar wrote: >>>>> Any comments on this patch? >>>>> >>>>> On Wed, Mar 26, 2014 at 5:16 PM, Yuvaraj Kumar C D <yuvaraj.cd@gmail.com> wrote: >>>>>> From: Sonny Rao <sonnyrao@chromium.org> >>>>>> >>>>>> This patch changes the fifo reset code to follow the reset procedure >>>>>> outlined in the documentation of Synopsys Mobile storage host databook >>>>>> 7.2.13. >>>>>> Without this patch, we could able to see eMMC was not detected after >>>>>> multiple reboots due to driver hangs while eMMC tuning for HS200. >>>>>> >>>>>> Signed-off-by: Sonny Rao <sonnyrao@chromium.org> >>>>>> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.org> >>>>>> --- >>>>>> drivers/mmc/host/dw_mmc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++- >>>>>> drivers/mmc/host/dw_mmc.h | 1 + >>>>>> 2 files changed, 48 insertions(+), 1 deletion(-) >>>>>> >>>>>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c >>>>>> index 32dd81d..1d77431 100644 >>>>>> --- a/drivers/mmc/host/dw_mmc.c >>>>>> +++ b/drivers/mmc/host/dw_mmc.c >>>>>> @@ -2220,7 +2220,53 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) >>>>>> host->sg = NULL; >>>>>> } >>>>>> >>>>>> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >>>>>> + /* >>>>>> + * The recommended method for resetting is to always reset the >>>>>> + * controller and the fifo, but differs slightly depending on the mode. >>>>>> + * Note that this doesn't handle the "generic DMA" (not IDMAC) case. >>>>>> + */ >>>> >>>> "not IDMAC" is confused.. >>>> >>> >>> The documentation describes three different possible modes. There's a >>> mode that doesn't use IDMAC but still does DMA. But as far as I can >>> tell this driver doesn't support that way. We can just remove that >>> wording if it's confusing. > > How did it know whether dma is generic DMA or not? > That's a good question. I wasn't sure whether the driver supported it or not. It looks like it definitely supports IDMAC through the CONFIG_MMC_DW_IDMAC flag, but I wasn't sure if it was supported the generic dma. Maybe if CONFIG_MMC_DW_IDMAC isn't specified but host->dma_ops is not NULL then we are using the generic dma mode. >>> >>>>>> + if (dw_mci_ctrl_reset(host, SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET)) { >>>>>> + unsigned long timeout = jiffies + msecs_to_jiffies(500); >>>>>> + u32 status, rint; >>>>>> + >>>>>> + /* if using dma we wait for dma_req to clear */ >>>>>> + if (host->using_dma) { >>>>>> + do { >>>>>> + status = mci_readl(host, STATUS); >>>>>> + if (!(status & SDMMC_STATUS_DMA_REQ)) >>>>>> + break; >>>>>> + cpu_relax(); >>>>>> + } while (time_before(jiffies, timeout)); >>>>>> + >>>>>> + if (status & SDMMC_STATUS_DMA_REQ) >>>>>> + dev_err(host->dev, >>>>>> + "%s: Timeout waiting for dma_req to " >>>>>> + "clear during reset", __func__); >>>>>> + >>>>>> + /* when using DMA next we reset the fifo again */ >>>>>> + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >>>>>> + } >>>>>> + /* >>>>>> + * In all cases we clear the RAWINTS register to clear any >>>>>> + * interrupts. >>>>>> + */ >>>>>> + rint = mci_readl(host, RINTSTS); >>>>>> + rint = rint & (~mci_readl(host, MINTSTS)); >> you use the "status or temp" instead of rint. (you can reuse the variable.) >> And can use "status &= ~mci_readl(host,MINTSTS);" >> >>>> >>>> Just clear the RINTSTS register? why do you add these? >>>> >>> >>> This will look at what is not masked, and only clear those bits. >> Well, i known if clear the RINTSTS register, >> recommended to use "0xfffffff" and set the value for interrupt. > > Can be used "0xfffffff"? > Yeah we probably can. We just lose information about interrupts that were masked, but maybe we just don't care about any of them anyway, so it doesn't matter. > Best Regards, > Jaehoon Chung >> >>> >>>>>> + if (rint) >>>>>> + mci_writel(host, RINTSTS, rint); >>>>>> + >>>>>> + } else >>>>>> + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); >>>> >>>> Just display the error log? I didn't understand this. >>>> If you displayed the error log, then it needs to return the error value. >>>> >>>>>> + >>>>>> + #ifdef CONFIG_MMC_DW_IDMAC >>>>>> + /* It is also recommended that we reset and reprogram idmac */ >>>>>> + dw_mci_idmac_reset(host); >>>>>> + #endif >>>>>> + >>>>>> + /* After a CTRL reset we need to have CIU set clock registers */ >>>>>> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); >> >> Well, why do you send the clock update command? >> I didn't see that update the value related with clock. >> >> Best Regards, >> Jaehoon Chung >> >>>>>> + >>>>>> + return true; >>>>>> } >>>>>> >>>>>> static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) >>>>>> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h >>>>>> index 738fa24..037e47a 100644 >>>>>> --- a/drivers/mmc/host/dw_mmc.h >>>>>> +++ b/drivers/mmc/host/dw_mmc.h >>>>>> @@ -129,6 +129,7 @@ >>>>>> #define SDMMC_CMD_INDX(n) ((n) & 0x1F) >>>>>> /* Status register defines */ >>>>>> #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) >>>>>> +#define SDMMC_STATUS_DMA_REQ BIT(31) >>>>>> /* FIFOTH register defines */ >>>>>> #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ >>>>>> ((r) & 0xFFF) << 16 | \ >>>>>> -- >>>>>> 1.7.10.4 >>>>>> >>>>> >>>> >>> -- >>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >>> the body of a message to majordomo at vger.kernel.org >>> More majordomo info at http://vger.kernel.org/majordomo-info.html >>> >> >> -- >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >> the body of a message to majordomo at vger.kernel.org >> More majordomo info at http://vger.kernel.org/majordomo-info.html >> > ^ permalink raw reply [flat|nested] 75+ messages in thread
* RE: [PATCH] mmc: dw_mmc: change to use recommended reset procedure 2014-05-10 3:36 ` Sonny Rao @ 2014-05-10 14:08 ` Seungwon Jeon -1 siblings, 0 replies; 75+ messages in thread From: Seungwon Jeon @ 2014-05-10 14:08 UTC (permalink / raw) To: 'Sonny Rao', 'Jaehoon Chung' Cc: 'Yuvaraj Kumar', 'Grant Grundler', linux-samsung-soc, linux-arm-kernel, 'Chris Ball', 'linux-mmc', kgene.kim, 'sunil joshi', 'Tomasz Figa', 'Yuvaraj Kumar C D' Hi Sonny, Can you separate procedure? Reset all are handled in fifo-reset. And ciu reset is always needed for error handling? Thanks, Seungwon Jeon On Sat, May 10, 2014, Sonny Rao wrote: > On Fri, May 9, 2014 at 12:32 AM, Jaehoon Chung <jh80.chung@samsung.com> wrote: > > Hi, Sonny. > > > > You can discard the my previous some comment. > > As you mentioned, this reset sequence is recommended at Synopsys TRM. > > > > Add the minor question. > > > > On 05/09/2014 01:27 PM, Jaehoon Chung wrote: > >> Hi, Sonny. > >> > >> I have checked the Synopsys TRM.. > >> > >> On 05/09/2014 10:34 AM, Sonny Rao wrote: > >>> On Thu, May 8, 2014 at 6:15 PM, Jaehoon Chung <jh80.chung@samsung.com> wrote: > >>>> On 05/08/2014 06:40 PM, Yuvaraj Kumar wrote: > >>>>> Any comments on this patch? > >>>>> > >>>>> On Wed, Mar 26, 2014 at 5:16 PM, Yuvaraj Kumar C D <yuvaraj.cd@gmail.com> wrote: > >>>>>> From: Sonny Rao <sonnyrao@chromium.org> > >>>>>> > >>>>>> This patch changes the fifo reset code to follow the reset procedure > >>>>>> outlined in the documentation of Synopsys Mobile storage host databook > >>>>>> 7.2.13. > >>>>>> Without this patch, we could able to see eMMC was not detected after > >>>>>> multiple reboots due to driver hangs while eMMC tuning for HS200. > >>>>>> > >>>>>> Signed-off-by: Sonny Rao <sonnyrao@chromium.org> > >>>>>> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.org> > >>>>>> --- > >>>>>> drivers/mmc/host/dw_mmc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++- > >>>>>> drivers/mmc/host/dw_mmc.h | 1 + > >>>>>> 2 files changed, 48 insertions(+), 1 deletion(-) > >>>>>> > >>>>>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c > >>>>>> index 32dd81d..1d77431 100644 > >>>>>> --- a/drivers/mmc/host/dw_mmc.c > >>>>>> +++ b/drivers/mmc/host/dw_mmc.c > >>>>>> @@ -2220,7 +2220,53 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) > >>>>>> host->sg = NULL; > >>>>>> } > >>>>>> > >>>>>> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > >>>>>> + /* > >>>>>> + * The recommended method for resetting is to always reset the > >>>>>> + * controller and the fifo, but differs slightly depending on the mode. > >>>>>> + * Note that this doesn't handle the "generic DMA" (not IDMAC) case. > >>>>>> + */ > >>>> > >>>> "not IDMAC" is confused.. > >>>> > >>> > >>> The documentation describes three different possible modes. There's a > >>> mode that doesn't use IDMAC but still does DMA. But as far as I can > >>> tell this driver doesn't support that way. We can just remove that > >>> wording if it's confusing. > > > > How did it know whether dma is generic DMA or not? > > > > That's a good question. I wasn't sure whether the driver supported it > or not. It looks like it definitely supports IDMAC through the > CONFIG_MMC_DW_IDMAC flag, but I wasn't sure if it was supported the > generic dma. Maybe if CONFIG_MMC_DW_IDMAC isn't specified but > host->dma_ops is not NULL then we are using the generic dma mode. > > >>> > >>>>>> + if (dw_mci_ctrl_reset(host, SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET)) { > >>>>>> + unsigned long timeout = jiffies + msecs_to_jiffies(500); > >>>>>> + u32 status, rint; > >>>>>> + > >>>>>> + /* if using dma we wait for dma_req to clear */ > >>>>>> + if (host->using_dma) { > >>>>>> + do { > >>>>>> + status = mci_readl(host, STATUS); > >>>>>> + if (!(status & SDMMC_STATUS_DMA_REQ)) > >>>>>> + break; > >>>>>> + cpu_relax(); > >>>>>> + } while (time_before(jiffies, timeout)); > >>>>>> + > >>>>>> + if (status & SDMMC_STATUS_DMA_REQ) > >>>>>> + dev_err(host->dev, > >>>>>> + "%s: Timeout waiting for dma_req to " > >>>>>> + "clear during reset", __func__); > >>>>>> + > >>>>>> + /* when using DMA next we reset the fifo again */ > >>>>>> + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > >>>>>> + } > >>>>>> + /* > >>>>>> + * In all cases we clear the RAWINTS register to clear any > >>>>>> + * interrupts. > >>>>>> + */ > >>>>>> + rint = mci_readl(host, RINTSTS); > >>>>>> + rint = rint & (~mci_readl(host, MINTSTS)); > >> you use the "status or temp" instead of rint. (you can reuse the variable.) > >> And can use "status &= ~mci_readl(host,MINTSTS);" > >> > >>>> > >>>> Just clear the RINTSTS register? why do you add these? > >>>> > >>> > >>> This will look at what is not masked, and only clear those bits. > >> Well, i known if clear the RINTSTS register, > >> recommended to use "0xfffffff" and set the value for interrupt. > > > > Can be used "0xfffffff"? > > > > Yeah we probably can. We just lose information about interrupts that > were masked, but maybe we just don't care about any of them anyway, so > it doesn't matter. > > > Best Regards, > > Jaehoon Chung > >> > >>> > >>>>>> + if (rint) > >>>>>> + mci_writel(host, RINTSTS, rint); > >>>>>> + > >>>>>> + } else > >>>>>> + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); > >>>> > >>>> Just display the error log? I didn't understand this. > >>>> If you displayed the error log, then it needs to return the error value. > >>>> > >>>>>> + > >>>>>> + #ifdef CONFIG_MMC_DW_IDMAC > >>>>>> + /* It is also recommended that we reset and reprogram idmac */ > >>>>>> + dw_mci_idmac_reset(host); > >>>>>> + #endif > >>>>>> + > >>>>>> + /* After a CTRL reset we need to have CIU set clock registers */ > >>>>>> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); > >> > >> Well, why do you send the clock update command? > >> I didn't see that update the value related with clock. > >> > >> Best Regards, > >> Jaehoon Chung > >> > >>>>>> + > >>>>>> + return true; > >>>>>> } > >>>>>> > >>>>>> static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) > >>>>>> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h > >>>>>> index 738fa24..037e47a 100644 > >>>>>> --- a/drivers/mmc/host/dw_mmc.h > >>>>>> +++ b/drivers/mmc/host/dw_mmc.h > >>>>>> @@ -129,6 +129,7 @@ > >>>>>> #define SDMMC_CMD_INDX(n) ((n) & 0x1F) > >>>>>> /* Status register defines */ > >>>>>> #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) > >>>>>> +#define SDMMC_STATUS_DMA_REQ BIT(31) > >>>>>> /* FIFOTH register defines */ > >>>>>> #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ > >>>>>> ((r) & 0xFFF) << 16 | \ > >>>>>> -- > >>>>>> 1.7.10.4 > >>>>>> > >>>>> > >>>> > >>> -- > >>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > >>> the body of a message to majordomo@vger.kernel.org > >>> More majordomo info at http://vger.kernel.org/majordomo-info.html > >>> > >> > >> -- > >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > >> the body of a message to majordomo@vger.kernel.org > >> More majordomo info at http://vger.kernel.org/majordomo-info.html > >> > > > -- > To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCH] mmc: dw_mmc: change to use recommended reset procedure @ 2014-05-10 14:08 ` Seungwon Jeon 0 siblings, 0 replies; 75+ messages in thread From: Seungwon Jeon @ 2014-05-10 14:08 UTC (permalink / raw) To: linux-arm-kernel Hi Sonny, Can you separate procedure? Reset all are handled in fifo-reset. And ciu reset is always needed for error handling? Thanks, Seungwon Jeon On Sat, May 10, 2014, Sonny Rao wrote: > On Fri, May 9, 2014 at 12:32 AM, Jaehoon Chung <jh80.chung@samsung.com> wrote: > > Hi, Sonny. > > > > You can discard the my previous some comment. > > As you mentioned, this reset sequence is recommended at Synopsys TRM. > > > > Add the minor question. > > > > On 05/09/2014 01:27 PM, Jaehoon Chung wrote: > >> Hi, Sonny. > >> > >> I have checked the Synopsys TRM.. > >> > >> On 05/09/2014 10:34 AM, Sonny Rao wrote: > >>> On Thu, May 8, 2014 at 6:15 PM, Jaehoon Chung <jh80.chung@samsung.com> wrote: > >>>> On 05/08/2014 06:40 PM, Yuvaraj Kumar wrote: > >>>>> Any comments on this patch? > >>>>> > >>>>> On Wed, Mar 26, 2014 at 5:16 PM, Yuvaraj Kumar C D <yuvaraj.cd@gmail.com> wrote: > >>>>>> From: Sonny Rao <sonnyrao@chromium.org> > >>>>>> > >>>>>> This patch changes the fifo reset code to follow the reset procedure > >>>>>> outlined in the documentation of Synopsys Mobile storage host databook > >>>>>> 7.2.13. > >>>>>> Without this patch, we could able to see eMMC was not detected after > >>>>>> multiple reboots due to driver hangs while eMMC tuning for HS200. > >>>>>> > >>>>>> Signed-off-by: Sonny Rao <sonnyrao@chromium.org> > >>>>>> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.org> > >>>>>> --- > >>>>>> drivers/mmc/host/dw_mmc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++- > >>>>>> drivers/mmc/host/dw_mmc.h | 1 + > >>>>>> 2 files changed, 48 insertions(+), 1 deletion(-) > >>>>>> > >>>>>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c > >>>>>> index 32dd81d..1d77431 100644 > >>>>>> --- a/drivers/mmc/host/dw_mmc.c > >>>>>> +++ b/drivers/mmc/host/dw_mmc.c > >>>>>> @@ -2220,7 +2220,53 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) > >>>>>> host->sg = NULL; > >>>>>> } > >>>>>> > >>>>>> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > >>>>>> + /* > >>>>>> + * The recommended method for resetting is to always reset the > >>>>>> + * controller and the fifo, but differs slightly depending on the mode. > >>>>>> + * Note that this doesn't handle the "generic DMA" (not IDMAC) case. > >>>>>> + */ > >>>> > >>>> "not IDMAC" is confused.. > >>>> > >>> > >>> The documentation describes three different possible modes. There's a > >>> mode that doesn't use IDMAC but still does DMA. But as far as I can > >>> tell this driver doesn't support that way. We can just remove that > >>> wording if it's confusing. > > > > How did it know whether dma is generic DMA or not? > > > > That's a good question. I wasn't sure whether the driver supported it > or not. It looks like it definitely supports IDMAC through the > CONFIG_MMC_DW_IDMAC flag, but I wasn't sure if it was supported the > generic dma. Maybe if CONFIG_MMC_DW_IDMAC isn't specified but > host->dma_ops is not NULL then we are using the generic dma mode. > > >>> > >>>>>> + if (dw_mci_ctrl_reset(host, SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET)) { > >>>>>> + unsigned long timeout = jiffies + msecs_to_jiffies(500); > >>>>>> + u32 status, rint; > >>>>>> + > >>>>>> + /* if using dma we wait for dma_req to clear */ > >>>>>> + if (host->using_dma) { > >>>>>> + do { > >>>>>> + status = mci_readl(host, STATUS); > >>>>>> + if (!(status & SDMMC_STATUS_DMA_REQ)) > >>>>>> + break; > >>>>>> + cpu_relax(); > >>>>>> + } while (time_before(jiffies, timeout)); > >>>>>> + > >>>>>> + if (status & SDMMC_STATUS_DMA_REQ) > >>>>>> + dev_err(host->dev, > >>>>>> + "%s: Timeout waiting for dma_req to " > >>>>>> + "clear during reset", __func__); > >>>>>> + > >>>>>> + /* when using DMA next we reset the fifo again */ > >>>>>> + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); > >>>>>> + } > >>>>>> + /* > >>>>>> + * In all cases we clear the RAWINTS register to clear any > >>>>>> + * interrupts. > >>>>>> + */ > >>>>>> + rint = mci_readl(host, RINTSTS); > >>>>>> + rint = rint & (~mci_readl(host, MINTSTS)); > >> you use the "status or temp" instead of rint. (you can reuse the variable.) > >> And can use "status &= ~mci_readl(host,MINTSTS);" > >> > >>>> > >>>> Just clear the RINTSTS register? why do you add these? > >>>> > >>> > >>> This will look at what is not masked, and only clear those bits. > >> Well, i known if clear the RINTSTS register, > >> recommended to use "0xfffffff" and set the value for interrupt. > > > > Can be used "0xfffffff"? > > > > Yeah we probably can. We just lose information about interrupts that > were masked, but maybe we just don't care about any of them anyway, so > it doesn't matter. > > > Best Regards, > > Jaehoon Chung > >> > >>> > >>>>>> + if (rint) > >>>>>> + mci_writel(host, RINTSTS, rint); > >>>>>> + > >>>>>> + } else > >>>>>> + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); > >>>> > >>>> Just display the error log? I didn't understand this. > >>>> If you displayed the error log, then it needs to return the error value. > >>>> > >>>>>> + > >>>>>> + #ifdef CONFIG_MMC_DW_IDMAC > >>>>>> + /* It is also recommended that we reset and reprogram idmac */ > >>>>>> + dw_mci_idmac_reset(host); > >>>>>> + #endif > >>>>>> + > >>>>>> + /* After a CTRL reset we need to have CIU set clock registers */ > >>>>>> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); > >> > >> Well, why do you send the clock update command? > >> I didn't see that update the value related with clock. > >> > >> Best Regards, > >> Jaehoon Chung > >> > >>>>>> + > >>>>>> + return true; > >>>>>> } > >>>>>> > >>>>>> static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) > >>>>>> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h > >>>>>> index 738fa24..037e47a 100644 > >>>>>> --- a/drivers/mmc/host/dw_mmc.h > >>>>>> +++ b/drivers/mmc/host/dw_mmc.h > >>>>>> @@ -129,6 +129,7 @@ > >>>>>> #define SDMMC_CMD_INDX(n) ((n) & 0x1F) > >>>>>> /* Status register defines */ > >>>>>> #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) > >>>>>> +#define SDMMC_STATUS_DMA_REQ BIT(31) > >>>>>> /* FIFOTH register defines */ > >>>>>> #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ > >>>>>> ((r) & 0xFFF) << 16 | \ > >>>>>> -- > >>>>>> 1.7.10.4 > >>>>>> > >>>>> > >>>> > >>> -- > >>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > >>> the body of a message to majordomo at vger.kernel.org > >>> More majordomo info at http://vger.kernel.org/majordomo-info.html > >>> > >> > >> -- > >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > >> the body of a message to majordomo at vger.kernel.org > >> More majordomo info at http://vger.kernel.org/majordomo-info.html > >> > > > -- > To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > the body of a message to majordomo at vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCH] mmc: dw_mmc: change to use recommended reset procedure 2014-05-10 14:08 ` Seungwon Jeon @ 2014-05-12 21:14 ` Sonny Rao -1 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-05-12 21:14 UTC (permalink / raw) To: Seungwon Jeon Cc: Jaehoon Chung, Yuvaraj Kumar, Grant Grundler, linux-samsung-soc, linux-arm-kernel, Chris Ball, linux-mmc, Kukjin Kim, sunil joshi, Tomasz Figa, Yuvaraj Kumar C D On Sat, May 10, 2014 at 7:08 AM, Seungwon Jeon <tgih.jun@samsung.com> wrote: > Hi Sonny, > > Can you separate procedure? > Reset all are handled in fifo-reset. > And ciu reset is always needed for error handling? Yes according to the document in the "Controller/DMA/FIFO Reset Usage" section, the controller_reset bit should be set in all cases, so I don't think that it should be separated. > > Thanks, > Seungwon Jeon > > On Sat, May 10, 2014, Sonny Rao wrote: >> On Fri, May 9, 2014 at 12:32 AM, Jaehoon Chung <jh80.chung@samsung.com> wrote: >> > Hi, Sonny. >> > >> > You can discard the my previous some comment. >> > As you mentioned, this reset sequence is recommended at Synopsys TRM. >> > >> > Add the minor question. >> > >> > On 05/09/2014 01:27 PM, Jaehoon Chung wrote: >> >> Hi, Sonny. >> >> >> >> I have checked the Synopsys TRM.. >> >> >> >> On 05/09/2014 10:34 AM, Sonny Rao wrote: >> >>> On Thu, May 8, 2014 at 6:15 PM, Jaehoon Chung <jh80.chung@samsung.com> wrote: >> >>>> On 05/08/2014 06:40 PM, Yuvaraj Kumar wrote: >> >>>>> Any comments on this patch? >> >>>>> >> >>>>> On Wed, Mar 26, 2014 at 5:16 PM, Yuvaraj Kumar C D <yuvaraj.cd@gmail.com> wrote: >> >>>>>> From: Sonny Rao <sonnyrao@chromium.org> >> >>>>>> >> >>>>>> This patch changes the fifo reset code to follow the reset procedure >> >>>>>> outlined in the documentation of Synopsys Mobile storage host databook >> >>>>>> 7.2.13. >> >>>>>> Without this patch, we could able to see eMMC was not detected after >> >>>>>> multiple reboots due to driver hangs while eMMC tuning for HS200. >> >>>>>> >> >>>>>> Signed-off-by: Sonny Rao <sonnyrao@chromium.org> >> >>>>>> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.org> >> >>>>>> --- >> >>>>>> drivers/mmc/host/dw_mmc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++- >> >>>>>> drivers/mmc/host/dw_mmc.h | 1 + >> >>>>>> 2 files changed, 48 insertions(+), 1 deletion(-) >> >>>>>> >> >>>>>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c >> >>>>>> index 32dd81d..1d77431 100644 >> >>>>>> --- a/drivers/mmc/host/dw_mmc.c >> >>>>>> +++ b/drivers/mmc/host/dw_mmc.c >> >>>>>> @@ -2220,7 +2220,53 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) >> >>>>>> host->sg = NULL; >> >>>>>> } >> >>>>>> >> >>>>>> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >> >>>>>> + /* >> >>>>>> + * The recommended method for resetting is to always reset the >> >>>>>> + * controller and the fifo, but differs slightly depending on the mode. >> >>>>>> + * Note that this doesn't handle the "generic DMA" (not IDMAC) case. >> >>>>>> + */ >> >>>> >> >>>> "not IDMAC" is confused.. >> >>>> >> >>> >> >>> The documentation describes three different possible modes. There's a >> >>> mode that doesn't use IDMAC but still does DMA. But as far as I can >> >>> tell this driver doesn't support that way. We can just remove that >> >>> wording if it's confusing. >> > >> > How did it know whether dma is generic DMA or not? >> > >> >> That's a good question. I wasn't sure whether the driver supported it >> or not. It looks like it definitely supports IDMAC through the >> CONFIG_MMC_DW_IDMAC flag, but I wasn't sure if it was supported the >> generic dma. Maybe if CONFIG_MMC_DW_IDMAC isn't specified but >> host->dma_ops is not NULL then we are using the generic dma mode. >> >> >>> >> >>>>>> + if (dw_mci_ctrl_reset(host, SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET)) { >> >>>>>> + unsigned long timeout = jiffies + msecs_to_jiffies(500); >> >>>>>> + u32 status, rint; >> >>>>>> + >> >>>>>> + /* if using dma we wait for dma_req to clear */ >> >>>>>> + if (host->using_dma) { >> >>>>>> + do { >> >>>>>> + status = mci_readl(host, STATUS); >> >>>>>> + if (!(status & SDMMC_STATUS_DMA_REQ)) >> >>>>>> + break; >> >>>>>> + cpu_relax(); >> >>>>>> + } while (time_before(jiffies, timeout)); >> >>>>>> + >> >>>>>> + if (status & SDMMC_STATUS_DMA_REQ) >> >>>>>> + dev_err(host->dev, >> >>>>>> + "%s: Timeout waiting for dma_req to " >> >>>>>> + "clear during reset", __func__); >> >>>>>> + >> >>>>>> + /* when using DMA next we reset the fifo again */ >> >>>>>> + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >> >>>>>> + } >> >>>>>> + /* >> >>>>>> + * In all cases we clear the RAWINTS register to clear any >> >>>>>> + * interrupts. >> >>>>>> + */ >> >>>>>> + rint = mci_readl(host, RINTSTS); >> >>>>>> + rint = rint & (~mci_readl(host, MINTSTS)); >> >> you use the "status or temp" instead of rint. (you can reuse the variable.) >> >> And can use "status &= ~mci_readl(host,MINTSTS);" >> >> >> >>>> >> >>>> Just clear the RINTSTS register? why do you add these? >> >>>> >> >>> >> >>> This will look at what is not masked, and only clear those bits. >> >> Well, i known if clear the RINTSTS register, >> >> recommended to use "0xfffffff" and set the value for interrupt. >> > >> > Can be used "0xfffffff"? >> > >> >> Yeah we probably can. We just lose information about interrupts that >> were masked, but maybe we just don't care about any of them anyway, so >> it doesn't matter. >> >> > Best Regards, >> > Jaehoon Chung >> >> >> >>> >> >>>>>> + if (rint) >> >>>>>> + mci_writel(host, RINTSTS, rint); >> >>>>>> + >> >>>>>> + } else >> >>>>>> + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); >> >>>> >> >>>> Just display the error log? I didn't understand this. >> >>>> If you displayed the error log, then it needs to return the error value. >> >>>> >> >>>>>> + >> >>>>>> + #ifdef CONFIG_MMC_DW_IDMAC >> >>>>>> + /* It is also recommended that we reset and reprogram idmac */ >> >>>>>> + dw_mci_idmac_reset(host); >> >>>>>> + #endif >> >>>>>> + >> >>>>>> + /* After a CTRL reset we need to have CIU set clock registers */ >> >>>>>> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); >> >> >> >> Well, why do you send the clock update command? >> >> I didn't see that update the value related with clock. >> >> >> >> Best Regards, >> >> Jaehoon Chung >> >> >> >>>>>> + >> >>>>>> + return true; >> >>>>>> } >> >>>>>> >> >>>>>> static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) >> >>>>>> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h >> >>>>>> index 738fa24..037e47a 100644 >> >>>>>> --- a/drivers/mmc/host/dw_mmc.h >> >>>>>> +++ b/drivers/mmc/host/dw_mmc.h >> >>>>>> @@ -129,6 +129,7 @@ >> >>>>>> #define SDMMC_CMD_INDX(n) ((n) & 0x1F) >> >>>>>> /* Status register defines */ >> >>>>>> #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) >> >>>>>> +#define SDMMC_STATUS_DMA_REQ BIT(31) >> >>>>>> /* FIFOTH register defines */ >> >>>>>> #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ >> >>>>>> ((r) & 0xFFF) << 16 | \ >> >>>>>> -- >> >>>>>> 1.7.10.4 >> >>>>>> >> >>>>> >> >>>> >> >>> -- >> >>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >> >>> the body of a message to majordomo@vger.kernel.org >> >>> More majordomo info at http://vger.kernel.org/majordomo-info.html >> >>> >> >> >> >> -- >> >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >> >> the body of a message to majordomo@vger.kernel.org >> >> More majordomo info at http://vger.kernel.org/majordomo-info.html >> >> >> > >> -- >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >> the body of a message to majordomo@vger.kernel.org >> More majordomo info at http://vger.kernel.org/majordomo-info.html > ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCH] mmc: dw_mmc: change to use recommended reset procedure @ 2014-05-12 21:14 ` Sonny Rao 0 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-05-12 21:14 UTC (permalink / raw) To: linux-arm-kernel On Sat, May 10, 2014 at 7:08 AM, Seungwon Jeon <tgih.jun@samsung.com> wrote: > Hi Sonny, > > Can you separate procedure? > Reset all are handled in fifo-reset. > And ciu reset is always needed for error handling? Yes according to the document in the "Controller/DMA/FIFO Reset Usage" section, the controller_reset bit should be set in all cases, so I don't think that it should be separated. > > Thanks, > Seungwon Jeon > > On Sat, May 10, 2014, Sonny Rao wrote: >> On Fri, May 9, 2014 at 12:32 AM, Jaehoon Chung <jh80.chung@samsung.com> wrote: >> > Hi, Sonny. >> > >> > You can discard the my previous some comment. >> > As you mentioned, this reset sequence is recommended at Synopsys TRM. >> > >> > Add the minor question. >> > >> > On 05/09/2014 01:27 PM, Jaehoon Chung wrote: >> >> Hi, Sonny. >> >> >> >> I have checked the Synopsys TRM.. >> >> >> >> On 05/09/2014 10:34 AM, Sonny Rao wrote: >> >>> On Thu, May 8, 2014 at 6:15 PM, Jaehoon Chung <jh80.chung@samsung.com> wrote: >> >>>> On 05/08/2014 06:40 PM, Yuvaraj Kumar wrote: >> >>>>> Any comments on this patch? >> >>>>> >> >>>>> On Wed, Mar 26, 2014 at 5:16 PM, Yuvaraj Kumar C D <yuvaraj.cd@gmail.com> wrote: >> >>>>>> From: Sonny Rao <sonnyrao@chromium.org> >> >>>>>> >> >>>>>> This patch changes the fifo reset code to follow the reset procedure >> >>>>>> outlined in the documentation of Synopsys Mobile storage host databook >> >>>>>> 7.2.13. >> >>>>>> Without this patch, we could able to see eMMC was not detected after >> >>>>>> multiple reboots due to driver hangs while eMMC tuning for HS200. >> >>>>>> >> >>>>>> Signed-off-by: Sonny Rao <sonnyrao@chromium.org> >> >>>>>> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.org> >> >>>>>> --- >> >>>>>> drivers/mmc/host/dw_mmc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++- >> >>>>>> drivers/mmc/host/dw_mmc.h | 1 + >> >>>>>> 2 files changed, 48 insertions(+), 1 deletion(-) >> >>>>>> >> >>>>>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c >> >>>>>> index 32dd81d..1d77431 100644 >> >>>>>> --- a/drivers/mmc/host/dw_mmc.c >> >>>>>> +++ b/drivers/mmc/host/dw_mmc.c >> >>>>>> @@ -2220,7 +2220,53 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) >> >>>>>> host->sg = NULL; >> >>>>>> } >> >>>>>> >> >>>>>> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >> >>>>>> + /* >> >>>>>> + * The recommended method for resetting is to always reset the >> >>>>>> + * controller and the fifo, but differs slightly depending on the mode. >> >>>>>> + * Note that this doesn't handle the "generic DMA" (not IDMAC) case. >> >>>>>> + */ >> >>>> >> >>>> "not IDMAC" is confused.. >> >>>> >> >>> >> >>> The documentation describes three different possible modes. There's a >> >>> mode that doesn't use IDMAC but still does DMA. But as far as I can >> >>> tell this driver doesn't support that way. We can just remove that >> >>> wording if it's confusing. >> > >> > How did it know whether dma is generic DMA or not? >> > >> >> That's a good question. I wasn't sure whether the driver supported it >> or not. It looks like it definitely supports IDMAC through the >> CONFIG_MMC_DW_IDMAC flag, but I wasn't sure if it was supported the >> generic dma. Maybe if CONFIG_MMC_DW_IDMAC isn't specified but >> host->dma_ops is not NULL then we are using the generic dma mode. >> >> >>> >> >>>>>> + if (dw_mci_ctrl_reset(host, SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET)) { >> >>>>>> + unsigned long timeout = jiffies + msecs_to_jiffies(500); >> >>>>>> + u32 status, rint; >> >>>>>> + >> >>>>>> + /* if using dma we wait for dma_req to clear */ >> >>>>>> + if (host->using_dma) { >> >>>>>> + do { >> >>>>>> + status = mci_readl(host, STATUS); >> >>>>>> + if (!(status & SDMMC_STATUS_DMA_REQ)) >> >>>>>> + break; >> >>>>>> + cpu_relax(); >> >>>>>> + } while (time_before(jiffies, timeout)); >> >>>>>> + >> >>>>>> + if (status & SDMMC_STATUS_DMA_REQ) >> >>>>>> + dev_err(host->dev, >> >>>>>> + "%s: Timeout waiting for dma_req to " >> >>>>>> + "clear during reset", __func__); >> >>>>>> + >> >>>>>> + /* when using DMA next we reset the fifo again */ >> >>>>>> + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >> >>>>>> + } >> >>>>>> + /* >> >>>>>> + * In all cases we clear the RAWINTS register to clear any >> >>>>>> + * interrupts. >> >>>>>> + */ >> >>>>>> + rint = mci_readl(host, RINTSTS); >> >>>>>> + rint = rint & (~mci_readl(host, MINTSTS)); >> >> you use the "status or temp" instead of rint. (you can reuse the variable.) >> >> And can use "status &= ~mci_readl(host,MINTSTS);" >> >> >> >>>> >> >>>> Just clear the RINTSTS register? why do you add these? >> >>>> >> >>> >> >>> This will look at what is not masked, and only clear those bits. >> >> Well, i known if clear the RINTSTS register, >> >> recommended to use "0xfffffff" and set the value for interrupt. >> > >> > Can be used "0xfffffff"? >> > >> >> Yeah we probably can. We just lose information about interrupts that >> were masked, but maybe we just don't care about any of them anyway, so >> it doesn't matter. >> >> > Best Regards, >> > Jaehoon Chung >> >> >> >>> >> >>>>>> + if (rint) >> >>>>>> + mci_writel(host, RINTSTS, rint); >> >>>>>> + >> >>>>>> + } else >> >>>>>> + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); >> >>>> >> >>>> Just display the error log? I didn't understand this. >> >>>> If you displayed the error log, then it needs to return the error value. >> >>>> >> >>>>>> + >> >>>>>> + #ifdef CONFIG_MMC_DW_IDMAC >> >>>>>> + /* It is also recommended that we reset and reprogram idmac */ >> >>>>>> + dw_mci_idmac_reset(host); >> >>>>>> + #endif >> >>>>>> + >> >>>>>> + /* After a CTRL reset we need to have CIU set clock registers */ >> >>>>>> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); >> >> >> >> Well, why do you send the clock update command? >> >> I didn't see that update the value related with clock. >> >> >> >> Best Regards, >> >> Jaehoon Chung >> >> >> >>>>>> + >> >>>>>> + return true; >> >>>>>> } >> >>>>>> >> >>>>>> static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) >> >>>>>> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h >> >>>>>> index 738fa24..037e47a 100644 >> >>>>>> --- a/drivers/mmc/host/dw_mmc.h >> >>>>>> +++ b/drivers/mmc/host/dw_mmc.h >> >>>>>> @@ -129,6 +129,7 @@ >> >>>>>> #define SDMMC_CMD_INDX(n) ((n) & 0x1F) >> >>>>>> /* Status register defines */ >> >>>>>> #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) >> >>>>>> +#define SDMMC_STATUS_DMA_REQ BIT(31) >> >>>>>> /* FIFOTH register defines */ >> >>>>>> #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ >> >>>>>> ((r) & 0xFFF) << 16 | \ >> >>>>>> -- >> >>>>>> 1.7.10.4 >> >>>>>> >> >>>>> >> >>>> >> >>> -- >> >>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >> >>> the body of a message to majordomo at vger.kernel.org >> >>> More majordomo info at http://vger.kernel.org/majordomo-info.html >> >>> >> >> >> >> -- >> >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >> >> the body of a message to majordomo at vger.kernel.org >> >> More majordomo info at http://vger.kernel.org/majordomo-info.html >> >> >> > >> -- >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >> the body of a message to majordomo at vger.kernel.org >> More majordomo info at http://vger.kernel.org/majordomo-info.html > ^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCH] mmc: dw_mmc: change to use recommended reset procedure 2014-05-10 3:36 ` Sonny Rao @ 2014-05-12 21:44 ` Sonny Rao -1 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-05-12 21:44 UTC (permalink / raw) To: Jaehoon Chung Cc: Yuvaraj Kumar, Grant Grundler, linux-samsung-soc, linux-arm-kernel, Chris Ball, Seungwon Jeon, linux-mmc, kgene.kim, sunil joshi, Tomasz Figa, Yuvaraj Kumar C D, Douglas Anderson, james.hogan On Fri, May 9, 2014 at 8:36 PM, Sonny Rao <sonnyrao@chromium.org> wrote: > On Fri, May 9, 2014 at 12:32 AM, Jaehoon Chung <jh80.chung@samsung.com> wrote: >> Hi, Sonny. >> >> You can discard the my previous some comment. >> As you mentioned, this reset sequence is recommended at Synopsys TRM. >> >> Add the minor question. >> >> On 05/09/2014 01:27 PM, Jaehoon Chung wrote: >>> Hi, Sonny. >>> >>> I have checked the Synopsys TRM.. >>> >>> On 05/09/2014 10:34 AM, Sonny Rao wrote: >>>> On Thu, May 8, 2014 at 6:15 PM, Jaehoon Chung <jh80.chung@samsung.com> wrote: >>>>> On 05/08/2014 06:40 PM, Yuvaraj Kumar wrote: >>>>>> Any comments on this patch? >>>>>> >>>>>> On Wed, Mar 26, 2014 at 5:16 PM, Yuvaraj Kumar C D <yuvaraj.cd@gmail.com> wrote: >>>>>>> From: Sonny Rao <sonnyrao@chromium.org> >>>>>>> >>>>>>> This patch changes the fifo reset code to follow the reset procedure >>>>>>> outlined in the documentation of Synopsys Mobile storage host databook >>>>>>> 7.2.13. >>>>>>> Without this patch, we could able to see eMMC was not detected after >>>>>>> multiple reboots due to driver hangs while eMMC tuning for HS200. >>>>>>> >>>>>>> Signed-off-by: Sonny Rao <sonnyrao@chromium.org> >>>>>>> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.org> >>>>>>> --- >>>>>>> drivers/mmc/host/dw_mmc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++- >>>>>>> drivers/mmc/host/dw_mmc.h | 1 + >>>>>>> 2 files changed, 48 insertions(+), 1 deletion(-) >>>>>>> >>>>>>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c >>>>>>> index 32dd81d..1d77431 100644 >>>>>>> --- a/drivers/mmc/host/dw_mmc.c >>>>>>> +++ b/drivers/mmc/host/dw_mmc.c >>>>>>> @@ -2220,7 +2220,53 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) >>>>>>> host->sg = NULL; >>>>>>> } >>>>>>> >>>>>>> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >>>>>>> + /* >>>>>>> + * The recommended method for resetting is to always reset the >>>>>>> + * controller and the fifo, but differs slightly depending on the mode. >>>>>>> + * Note that this doesn't handle the "generic DMA" (not IDMAC) case. >>>>>>> + */ >>>>> >>>>> "not IDMAC" is confused.. >>>>> >>>> >>>> The documentation describes three different possible modes. There's a >>>> mode that doesn't use IDMAC but still does DMA. But as far as I can >>>> tell this driver doesn't support that way. We can just remove that >>>> wording if it's confusing. >> >> How did it know whether dma is generic DMA or not? >> > > That's a good question. I wasn't sure whether the driver supported it > or not. It looks like it definitely supports IDMAC through the > CONFIG_MMC_DW_IDMAC flag, but I wasn't sure if it was supported the > generic dma. Maybe if CONFIG_MMC_DW_IDMAC isn't specified but > host->dma_ops is not NULL then we are using the generic dma mode. > Doug mentioned that James Hogan might have an answer. James, are there Imgtec SoCs which use dw_mmc and use DMA but don't use the IDMAC? If so, we can add that support into this reset procedure patch. >>>> >>>>>>> + if (dw_mci_ctrl_reset(host, SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET)) { >>>>>>> + unsigned long timeout = jiffies + msecs_to_jiffies(500); >>>>>>> + u32 status, rint; >>>>>>> + >>>>>>> + /* if using dma we wait for dma_req to clear */ >>>>>>> + if (host->using_dma) { >>>>>>> + do { >>>>>>> + status = mci_readl(host, STATUS); >>>>>>> + if (!(status & SDMMC_STATUS_DMA_REQ)) >>>>>>> + break; >>>>>>> + cpu_relax(); >>>>>>> + } while (time_before(jiffies, timeout)); >>>>>>> + >>>>>>> + if (status & SDMMC_STATUS_DMA_REQ) >>>>>>> + dev_err(host->dev, >>>>>>> + "%s: Timeout waiting for dma_req to " >>>>>>> + "clear during reset", __func__); >>>>>>> + >>>>>>> + /* when using DMA next we reset the fifo again */ >>>>>>> + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >>>>>>> + } >>>>>>> + /* >>>>>>> + * In all cases we clear the RAWINTS register to clear any >>>>>>> + * interrupts. >>>>>>> + */ >>>>>>> + rint = mci_readl(host, RINTSTS); >>>>>>> + rint = rint & (~mci_readl(host, MINTSTS)); >>> you use the "status or temp" instead of rint. (you can reuse the variable.) >>> And can use "status &= ~mci_readl(host,MINTSTS);" >>> >>>>> >>>>> Just clear the RINTSTS register? why do you add these? >>>>> >>>> >>>> This will look at what is not masked, and only clear those bits. >>> Well, i known if clear the RINTSTS register, >>> recommended to use "0xfffffff" and set the value for interrupt. >> >> Can be used "0xfffffff"? >> > > Yeah we probably can. We just lose information about interrupts that > were masked, but maybe we just don't care about any of them anyway, so > it doesn't matter. > >> Best Regards, >> Jaehoon Chung >>> >>>> >>>>>>> + if (rint) >>>>>>> + mci_writel(host, RINTSTS, rint); >>>>>>> + >>>>>>> + } else >>>>>>> + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); >>>>> >>>>> Just display the error log? I didn't understand this. >>>>> If you displayed the error log, then it needs to return the error value. >>>>> >>>>>>> + >>>>>>> + #ifdef CONFIG_MMC_DW_IDMAC >>>>>>> + /* It is also recommended that we reset and reprogram idmac */ >>>>>>> + dw_mci_idmac_reset(host); >>>>>>> + #endif >>>>>>> + >>>>>>> + /* After a CTRL reset we need to have CIU set clock registers */ >>>>>>> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); >>> >>> Well, why do you send the clock update command? >>> I didn't see that update the value related with clock. >>> >>> Best Regards, >>> Jaehoon Chung >>> >>>>>>> + >>>>>>> + return true; >>>>>>> } >>>>>>> >>>>>>> static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) >>>>>>> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h >>>>>>> index 738fa24..037e47a 100644 >>>>>>> --- a/drivers/mmc/host/dw_mmc.h >>>>>>> +++ b/drivers/mmc/host/dw_mmc.h >>>>>>> @@ -129,6 +129,7 @@ >>>>>>> #define SDMMC_CMD_INDX(n) ((n) & 0x1F) >>>>>>> /* Status register defines */ >>>>>>> #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) >>>>>>> +#define SDMMC_STATUS_DMA_REQ BIT(31) >>>>>>> /* FIFOTH register defines */ >>>>>>> #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ >>>>>>> ((r) & 0xFFF) << 16 | \ >>>>>>> -- >>>>>>> 1.7.10.4 >>>>>>> >>>>>> >>>>> >>>> -- >>>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >>>> the body of a message to majordomo@vger.kernel.org >>>> More majordomo info at http://vger.kernel.org/majordomo-info.html >>>> >>> >>> -- >>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >>> the body of a message to majordomo@vger.kernel.org >>> More majordomo info at http://vger.kernel.org/majordomo-info.html >>> >> ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCH] mmc: dw_mmc: change to use recommended reset procedure @ 2014-05-12 21:44 ` Sonny Rao 0 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-05-12 21:44 UTC (permalink / raw) To: linux-arm-kernel On Fri, May 9, 2014 at 8:36 PM, Sonny Rao <sonnyrao@chromium.org> wrote: > On Fri, May 9, 2014 at 12:32 AM, Jaehoon Chung <jh80.chung@samsung.com> wrote: >> Hi, Sonny. >> >> You can discard the my previous some comment. >> As you mentioned, this reset sequence is recommended at Synopsys TRM. >> >> Add the minor question. >> >> On 05/09/2014 01:27 PM, Jaehoon Chung wrote: >>> Hi, Sonny. >>> >>> I have checked the Synopsys TRM.. >>> >>> On 05/09/2014 10:34 AM, Sonny Rao wrote: >>>> On Thu, May 8, 2014 at 6:15 PM, Jaehoon Chung <jh80.chung@samsung.com> wrote: >>>>> On 05/08/2014 06:40 PM, Yuvaraj Kumar wrote: >>>>>> Any comments on this patch? >>>>>> >>>>>> On Wed, Mar 26, 2014 at 5:16 PM, Yuvaraj Kumar C D <yuvaraj.cd@gmail.com> wrote: >>>>>>> From: Sonny Rao <sonnyrao@chromium.org> >>>>>>> >>>>>>> This patch changes the fifo reset code to follow the reset procedure >>>>>>> outlined in the documentation of Synopsys Mobile storage host databook >>>>>>> 7.2.13. >>>>>>> Without this patch, we could able to see eMMC was not detected after >>>>>>> multiple reboots due to driver hangs while eMMC tuning for HS200. >>>>>>> >>>>>>> Signed-off-by: Sonny Rao <sonnyrao@chromium.org> >>>>>>> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.org> >>>>>>> --- >>>>>>> drivers/mmc/host/dw_mmc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++- >>>>>>> drivers/mmc/host/dw_mmc.h | 1 + >>>>>>> 2 files changed, 48 insertions(+), 1 deletion(-) >>>>>>> >>>>>>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c >>>>>>> index 32dd81d..1d77431 100644 >>>>>>> --- a/drivers/mmc/host/dw_mmc.c >>>>>>> +++ b/drivers/mmc/host/dw_mmc.c >>>>>>> @@ -2220,7 +2220,53 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) >>>>>>> host->sg = NULL; >>>>>>> } >>>>>>> >>>>>>> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >>>>>>> + /* >>>>>>> + * The recommended method for resetting is to always reset the >>>>>>> + * controller and the fifo, but differs slightly depending on the mode. >>>>>>> + * Note that this doesn't handle the "generic DMA" (not IDMAC) case. >>>>>>> + */ >>>>> >>>>> "not IDMAC" is confused.. >>>>> >>>> >>>> The documentation describes three different possible modes. There's a >>>> mode that doesn't use IDMAC but still does DMA. But as far as I can >>>> tell this driver doesn't support that way. We can just remove that >>>> wording if it's confusing. >> >> How did it know whether dma is generic DMA or not? >> > > That's a good question. I wasn't sure whether the driver supported it > or not. It looks like it definitely supports IDMAC through the > CONFIG_MMC_DW_IDMAC flag, but I wasn't sure if it was supported the > generic dma. Maybe if CONFIG_MMC_DW_IDMAC isn't specified but > host->dma_ops is not NULL then we are using the generic dma mode. > Doug mentioned that James Hogan might have an answer. James, are there Imgtec SoCs which use dw_mmc and use DMA but don't use the IDMAC? If so, we can add that support into this reset procedure patch. >>>> >>>>>>> + if (dw_mci_ctrl_reset(host, SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET)) { >>>>>>> + unsigned long timeout = jiffies + msecs_to_jiffies(500); >>>>>>> + u32 status, rint; >>>>>>> + >>>>>>> + /* if using dma we wait for dma_req to clear */ >>>>>>> + if (host->using_dma) { >>>>>>> + do { >>>>>>> + status = mci_readl(host, STATUS); >>>>>>> + if (!(status & SDMMC_STATUS_DMA_REQ)) >>>>>>> + break; >>>>>>> + cpu_relax(); >>>>>>> + } while (time_before(jiffies, timeout)); >>>>>>> + >>>>>>> + if (status & SDMMC_STATUS_DMA_REQ) >>>>>>> + dev_err(host->dev, >>>>>>> + "%s: Timeout waiting for dma_req to " >>>>>>> + "clear during reset", __func__); >>>>>>> + >>>>>>> + /* when using DMA next we reset the fifo again */ >>>>>>> + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >>>>>>> + } >>>>>>> + /* >>>>>>> + * In all cases we clear the RAWINTS register to clear any >>>>>>> + * interrupts. >>>>>>> + */ >>>>>>> + rint = mci_readl(host, RINTSTS); >>>>>>> + rint = rint & (~mci_readl(host, MINTSTS)); >>> you use the "status or temp" instead of rint. (you can reuse the variable.) >>> And can use "status &= ~mci_readl(host,MINTSTS);" >>> >>>>> >>>>> Just clear the RINTSTS register? why do you add these? >>>>> >>>> >>>> This will look at what is not masked, and only clear those bits. >>> Well, i known if clear the RINTSTS register, >>> recommended to use "0xfffffff" and set the value for interrupt. >> >> Can be used "0xfffffff"? >> > > Yeah we probably can. We just lose information about interrupts that > were masked, but maybe we just don't care about any of them anyway, so > it doesn't matter. > >> Best Regards, >> Jaehoon Chung >>> >>>> >>>>>>> + if (rint) >>>>>>> + mci_writel(host, RINTSTS, rint); >>>>>>> + >>>>>>> + } else >>>>>>> + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); >>>>> >>>>> Just display the error log? I didn't understand this. >>>>> If you displayed the error log, then it needs to return the error value. >>>>> >>>>>>> + >>>>>>> + #ifdef CONFIG_MMC_DW_IDMAC >>>>>>> + /* It is also recommended that we reset and reprogram idmac */ >>>>>>> + dw_mci_idmac_reset(host); >>>>>>> + #endif >>>>>>> + >>>>>>> + /* After a CTRL reset we need to have CIU set clock registers */ >>>>>>> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); >>> >>> Well, why do you send the clock update command? >>> I didn't see that update the value related with clock. >>> >>> Best Regards, >>> Jaehoon Chung >>> >>>>>>> + >>>>>>> + return true; >>>>>>> } >>>>>>> >>>>>>> static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) >>>>>>> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h >>>>>>> index 738fa24..037e47a 100644 >>>>>>> --- a/drivers/mmc/host/dw_mmc.h >>>>>>> +++ b/drivers/mmc/host/dw_mmc.h >>>>>>> @@ -129,6 +129,7 @@ >>>>>>> #define SDMMC_CMD_INDX(n) ((n) & 0x1F) >>>>>>> /* Status register defines */ >>>>>>> #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) >>>>>>> +#define SDMMC_STATUS_DMA_REQ BIT(31) >>>>>>> /* FIFOTH register defines */ >>>>>>> #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ >>>>>>> ((r) & 0xFFF) << 16 | \ >>>>>>> -- >>>>>>> 1.7.10.4 >>>>>>> >>>>>> >>>>> >>>> -- >>>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >>>> the body of a message to majordomo at vger.kernel.org >>>> More majordomo info at http://vger.kernel.org/majordomo-info.html >>>> >>> >>> -- >>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >>> the body of a message to majordomo at vger.kernel.org >>> More majordomo info at http://vger.kernel.org/majordomo-info.html >>> >> ^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCH] mmc: dw_mmc: change to use recommended reset procedure 2014-05-12 21:44 ` Sonny Rao @ 2014-05-13 0:40 ` Sonny Rao -1 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-05-13 0:40 UTC (permalink / raw) To: Jaehoon Chung Cc: Yuvaraj Kumar, Grant Grundler, linux-samsung-soc, linux-arm-kernel, Chris Ball, Seungwon Jeon, linux-mmc, kgene.kim, sunil joshi, Tomasz Figa, Yuvaraj Kumar C D, Douglas Anderson, james.hogan On Mon, May 12, 2014 at 2:44 PM, Sonny Rao <sonnyrao@chromium.org> wrote: > On Fri, May 9, 2014 at 8:36 PM, Sonny Rao <sonnyrao@chromium.org> wrote: >> On Fri, May 9, 2014 at 12:32 AM, Jaehoon Chung <jh80.chung@samsung.com> wrote: >>> Hi, Sonny. >>> >>> You can discard the my previous some comment. >>> As you mentioned, this reset sequence is recommended at Synopsys TRM. >>> >>> Add the minor question. >>> >>> On 05/09/2014 01:27 PM, Jaehoon Chung wrote: >>>> Hi, Sonny. >>>> >>>> I have checked the Synopsys TRM.. >>>> >>>> On 05/09/2014 10:34 AM, Sonny Rao wrote: >>>>> On Thu, May 8, 2014 at 6:15 PM, Jaehoon Chung <jh80.chung@samsung.com> wrote: >>>>>> On 05/08/2014 06:40 PM, Yuvaraj Kumar wrote: >>>>>>> Any comments on this patch? >>>>>>> >>>>>>> On Wed, Mar 26, 2014 at 5:16 PM, Yuvaraj Kumar C D <yuvaraj.cd@gmail.com> wrote: >>>>>>>> From: Sonny Rao <sonnyrao@chromium.org> >>>>>>>> >>>>>>>> This patch changes the fifo reset code to follow the reset procedure >>>>>>>> outlined in the documentation of Synopsys Mobile storage host databook >>>>>>>> 7.2.13. >>>>>>>> Without this patch, we could able to see eMMC was not detected after >>>>>>>> multiple reboots due to driver hangs while eMMC tuning for HS200. >>>>>>>> >>>>>>>> Signed-off-by: Sonny Rao <sonnyrao@chromium.org> >>>>>>>> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.org> >>>>>>>> --- >>>>>>>> drivers/mmc/host/dw_mmc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++- >>>>>>>> drivers/mmc/host/dw_mmc.h | 1 + >>>>>>>> 2 files changed, 48 insertions(+), 1 deletion(-) >>>>>>>> >>>>>>>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c >>>>>>>> index 32dd81d..1d77431 100644 >>>>>>>> --- a/drivers/mmc/host/dw_mmc.c >>>>>>>> +++ b/drivers/mmc/host/dw_mmc.c >>>>>>>> @@ -2220,7 +2220,53 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) >>>>>>>> host->sg = NULL; >>>>>>>> } >>>>>>>> >>>>>>>> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >>>>>>>> + /* >>>>>>>> + * The recommended method for resetting is to always reset the >>>>>>>> + * controller and the fifo, but differs slightly depending on the mode. >>>>>>>> + * Note that this doesn't handle the "generic DMA" (not IDMAC) case. >>>>>>>> + */ >>>>>> >>>>>> "not IDMAC" is confused.. >>>>>> >>>>> >>>>> The documentation describes three different possible modes. There's a >>>>> mode that doesn't use IDMAC but still does DMA. But as far as I can >>>>> tell this driver doesn't support that way. We can just remove that >>>>> wording if it's confusing. >>> >>> How did it know whether dma is generic DMA or not? >>> >> >> That's a good question. I wasn't sure whether the driver supported it >> or not. It looks like it definitely supports IDMAC through the >> CONFIG_MMC_DW_IDMAC flag, but I wasn't sure if it was supported the >> generic dma. Maybe if CONFIG_MMC_DW_IDMAC isn't specified but >> host->dma_ops is not NULL then we are using the generic dma mode. >> > > Doug mentioned that James Hogan might have an answer. James, are > there Imgtec SoCs which use dw_mmc and use DMA but don't use the > IDMAC? If so, we can add that support into this reset procedure > patch. > In any case, whether on not anybody is using it, it looks like it's not that hard to support this mode for reset (I was just lazy the first time), we just need to add a flag to our reset. I've made that change and cleaned it up a little bit more and I'll resend this patch. >>>>> >>>>>>>> + if (dw_mci_ctrl_reset(host, SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET)) { >>>>>>>> + unsigned long timeout = jiffies + msecs_to_jiffies(500); >>>>>>>> + u32 status, rint; >>>>>>>> + >>>>>>>> + /* if using dma we wait for dma_req to clear */ >>>>>>>> + if (host->using_dma) { >>>>>>>> + do { >>>>>>>> + status = mci_readl(host, STATUS); >>>>>>>> + if (!(status & SDMMC_STATUS_DMA_REQ)) >>>>>>>> + break; >>>>>>>> + cpu_relax(); >>>>>>>> + } while (time_before(jiffies, timeout)); >>>>>>>> + >>>>>>>> + if (status & SDMMC_STATUS_DMA_REQ) >>>>>>>> + dev_err(host->dev, >>>>>>>> + "%s: Timeout waiting for dma_req to " >>>>>>>> + "clear during reset", __func__); >>>>>>>> + >>>>>>>> + /* when using DMA next we reset the fifo again */ >>>>>>>> + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >>>>>>>> + } >>>>>>>> + /* >>>>>>>> + * In all cases we clear the RAWINTS register to clear any >>>>>>>> + * interrupts. >>>>>>>> + */ >>>>>>>> + rint = mci_readl(host, RINTSTS); >>>>>>>> + rint = rint & (~mci_readl(host, MINTSTS)); >>>> you use the "status or temp" instead of rint. (you can reuse the variable.) >>>> And can use "status &= ~mci_readl(host,MINTSTS);" >>>> >>>>>> >>>>>> Just clear the RINTSTS register? why do you add these? >>>>>> >>>>> >>>>> This will look at what is not masked, and only clear those bits. >>>> Well, i known if clear the RINTSTS register, >>>> recommended to use "0xfffffff" and set the value for interrupt. >>> >>> Can be used "0xfffffff"? >>> >> >> Yeah we probably can. We just lose information about interrupts that >> were masked, but maybe we just don't care about any of them anyway, so >> it doesn't matter. >> >>> Best Regards, >>> Jaehoon Chung >>>> >>>>> >>>>>>>> + if (rint) >>>>>>>> + mci_writel(host, RINTSTS, rint); >>>>>>>> + >>>>>>>> + } else >>>>>>>> + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); >>>>>> >>>>>> Just display the error log? I didn't understand this. >>>>>> If you displayed the error log, then it needs to return the error value. >>>>>> >>>>>>>> + >>>>>>>> + #ifdef CONFIG_MMC_DW_IDMAC >>>>>>>> + /* It is also recommended that we reset and reprogram idmac */ >>>>>>>> + dw_mci_idmac_reset(host); >>>>>>>> + #endif >>>>>>>> + >>>>>>>> + /* After a CTRL reset we need to have CIU set clock registers */ >>>>>>>> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); >>>> >>>> Well, why do you send the clock update command? >>>> I didn't see that update the value related with clock. >>>> >>>> Best Regards, >>>> Jaehoon Chung >>>> >>>>>>>> + >>>>>>>> + return true; >>>>>>>> } >>>>>>>> >>>>>>>> static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) >>>>>>>> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h >>>>>>>> index 738fa24..037e47a 100644 >>>>>>>> --- a/drivers/mmc/host/dw_mmc.h >>>>>>>> +++ b/drivers/mmc/host/dw_mmc.h >>>>>>>> @@ -129,6 +129,7 @@ >>>>>>>> #define SDMMC_CMD_INDX(n) ((n) & 0x1F) >>>>>>>> /* Status register defines */ >>>>>>>> #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) >>>>>>>> +#define SDMMC_STATUS_DMA_REQ BIT(31) >>>>>>>> /* FIFOTH register defines */ >>>>>>>> #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ >>>>>>>> ((r) & 0xFFF) << 16 | \ >>>>>>>> -- >>>>>>>> 1.7.10.4 >>>>>>>> >>>>>>> >>>>>> >>>>> -- >>>>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >>>>> the body of a message to majordomo@vger.kernel.org >>>>> More majordomo info at http://vger.kernel.org/majordomo-info.html >>>>> >>>> >>>> -- >>>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >>>> the body of a message to majordomo@vger.kernel.org >>>> More majordomo info at http://vger.kernel.org/majordomo-info.html >>>> >>> ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCH] mmc: dw_mmc: change to use recommended reset procedure @ 2014-05-13 0:40 ` Sonny Rao 0 siblings, 0 replies; 75+ messages in thread From: Sonny Rao @ 2014-05-13 0:40 UTC (permalink / raw) To: linux-arm-kernel On Mon, May 12, 2014 at 2:44 PM, Sonny Rao <sonnyrao@chromium.org> wrote: > On Fri, May 9, 2014 at 8:36 PM, Sonny Rao <sonnyrao@chromium.org> wrote: >> On Fri, May 9, 2014 at 12:32 AM, Jaehoon Chung <jh80.chung@samsung.com> wrote: >>> Hi, Sonny. >>> >>> You can discard the my previous some comment. >>> As you mentioned, this reset sequence is recommended at Synopsys TRM. >>> >>> Add the minor question. >>> >>> On 05/09/2014 01:27 PM, Jaehoon Chung wrote: >>>> Hi, Sonny. >>>> >>>> I have checked the Synopsys TRM.. >>>> >>>> On 05/09/2014 10:34 AM, Sonny Rao wrote: >>>>> On Thu, May 8, 2014 at 6:15 PM, Jaehoon Chung <jh80.chung@samsung.com> wrote: >>>>>> On 05/08/2014 06:40 PM, Yuvaraj Kumar wrote: >>>>>>> Any comments on this patch? >>>>>>> >>>>>>> On Wed, Mar 26, 2014 at 5:16 PM, Yuvaraj Kumar C D <yuvaraj.cd@gmail.com> wrote: >>>>>>>> From: Sonny Rao <sonnyrao@chromium.org> >>>>>>>> >>>>>>>> This patch changes the fifo reset code to follow the reset procedure >>>>>>>> outlined in the documentation of Synopsys Mobile storage host databook >>>>>>>> 7.2.13. >>>>>>>> Without this patch, we could able to see eMMC was not detected after >>>>>>>> multiple reboots due to driver hangs while eMMC tuning for HS200. >>>>>>>> >>>>>>>> Signed-off-by: Sonny Rao <sonnyrao@chromium.org> >>>>>>>> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.org> >>>>>>>> --- >>>>>>>> drivers/mmc/host/dw_mmc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++- >>>>>>>> drivers/mmc/host/dw_mmc.h | 1 + >>>>>>>> 2 files changed, 48 insertions(+), 1 deletion(-) >>>>>>>> >>>>>>>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c >>>>>>>> index 32dd81d..1d77431 100644 >>>>>>>> --- a/drivers/mmc/host/dw_mmc.c >>>>>>>> +++ b/drivers/mmc/host/dw_mmc.c >>>>>>>> @@ -2220,7 +2220,53 @@ static inline bool dw_mci_fifo_reset(struct dw_mci *host) >>>>>>>> host->sg = NULL; >>>>>>>> } >>>>>>>> >>>>>>>> - return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >>>>>>>> + /* >>>>>>>> + * The recommended method for resetting is to always reset the >>>>>>>> + * controller and the fifo, but differs slightly depending on the mode. >>>>>>>> + * Note that this doesn't handle the "generic DMA" (not IDMAC) case. >>>>>>>> + */ >>>>>> >>>>>> "not IDMAC" is confused.. >>>>>> >>>>> >>>>> The documentation describes three different possible modes. There's a >>>>> mode that doesn't use IDMAC but still does DMA. But as far as I can >>>>> tell this driver doesn't support that way. We can just remove that >>>>> wording if it's confusing. >>> >>> How did it know whether dma is generic DMA or not? >>> >> >> That's a good question. I wasn't sure whether the driver supported it >> or not. It looks like it definitely supports IDMAC through the >> CONFIG_MMC_DW_IDMAC flag, but I wasn't sure if it was supported the >> generic dma. Maybe if CONFIG_MMC_DW_IDMAC isn't specified but >> host->dma_ops is not NULL then we are using the generic dma mode. >> > > Doug mentioned that James Hogan might have an answer. James, are > there Imgtec SoCs which use dw_mmc and use DMA but don't use the > IDMAC? If so, we can add that support into this reset procedure > patch. > In any case, whether on not anybody is using it, it looks like it's not that hard to support this mode for reset (I was just lazy the first time), we just need to add a flag to our reset. I've made that change and cleaned it up a little bit more and I'll resend this patch. >>>>> >>>>>>>> + if (dw_mci_ctrl_reset(host, SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET)) { >>>>>>>> + unsigned long timeout = jiffies + msecs_to_jiffies(500); >>>>>>>> + u32 status, rint; >>>>>>>> + >>>>>>>> + /* if using dma we wait for dma_req to clear */ >>>>>>>> + if (host->using_dma) { >>>>>>>> + do { >>>>>>>> + status = mci_readl(host, STATUS); >>>>>>>> + if (!(status & SDMMC_STATUS_DMA_REQ)) >>>>>>>> + break; >>>>>>>> + cpu_relax(); >>>>>>>> + } while (time_before(jiffies, timeout)); >>>>>>>> + >>>>>>>> + if (status & SDMMC_STATUS_DMA_REQ) >>>>>>>> + dev_err(host->dev, >>>>>>>> + "%s: Timeout waiting for dma_req to " >>>>>>>> + "clear during reset", __func__); >>>>>>>> + >>>>>>>> + /* when using DMA next we reset the fifo again */ >>>>>>>> + dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); >>>>>>>> + } >>>>>>>> + /* >>>>>>>> + * In all cases we clear the RAWINTS register to clear any >>>>>>>> + * interrupts. >>>>>>>> + */ >>>>>>>> + rint = mci_readl(host, RINTSTS); >>>>>>>> + rint = rint & (~mci_readl(host, MINTSTS)); >>>> you use the "status or temp" instead of rint. (you can reuse the variable.) >>>> And can use "status &= ~mci_readl(host,MINTSTS);" >>>> >>>>>> >>>>>> Just clear the RINTSTS register? why do you add these? >>>>>> >>>>> >>>>> This will look at what is not masked, and only clear those bits. >>>> Well, i known if clear the RINTSTS register, >>>> recommended to use "0xfffffff" and set the value for interrupt. >>> >>> Can be used "0xfffffff"? >>> >> >> Yeah we probably can. We just lose information about interrupts that >> were masked, but maybe we just don't care about any of them anyway, so >> it doesn't matter. >> >>> Best Regards, >>> Jaehoon Chung >>>> >>>>> >>>>>>>> + if (rint) >>>>>>>> + mci_writel(host, RINTSTS, rint); >>>>>>>> + >>>>>>>> + } else >>>>>>>> + dev_err(host->dev, "%s: Reset bits didn't clear", __func__); >>>>>> >>>>>> Just display the error log? I didn't understand this. >>>>>> If you displayed the error log, then it needs to return the error value. >>>>>> >>>>>>>> + >>>>>>>> + #ifdef CONFIG_MMC_DW_IDMAC >>>>>>>> + /* It is also recommended that we reset and reprogram idmac */ >>>>>>>> + dw_mci_idmac_reset(host); >>>>>>>> + #endif >>>>>>>> + >>>>>>>> + /* After a CTRL reset we need to have CIU set clock registers */ >>>>>>>> + mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); >>>> >>>> Well, why do you send the clock update command? >>>> I didn't see that update the value related with clock. >>>> >>>> Best Regards, >>>> Jaehoon Chung >>>> >>>>>>>> + >>>>>>>> + return true; >>>>>>>> } >>>>>>>> >>>>>>>> static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) >>>>>>>> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h >>>>>>>> index 738fa24..037e47a 100644 >>>>>>>> --- a/drivers/mmc/host/dw_mmc.h >>>>>>>> +++ b/drivers/mmc/host/dw_mmc.h >>>>>>>> @@ -129,6 +129,7 @@ >>>>>>>> #define SDMMC_CMD_INDX(n) ((n) & 0x1F) >>>>>>>> /* Status register defines */ >>>>>>>> #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) >>>>>>>> +#define SDMMC_STATUS_DMA_REQ BIT(31) >>>>>>>> /* FIFOTH register defines */ >>>>>>>> #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ >>>>>>>> ((r) & 0xFFF) << 16 | \ >>>>>>>> -- >>>>>>>> 1.7.10.4 >>>>>>>> >>>>>>> >>>>>> >>>>> -- >>>>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >>>>> the body of a message to majordomo at vger.kernel.org >>>>> More majordomo info at http://vger.kernel.org/majordomo-info.html >>>>> >>>> >>>> -- >>>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in >>>> the body of a message to majordomo at vger.kernel.org >>>> More majordomo info at http://vger.kernel.org/majordomo-info.html >>>> >>> ^ permalink raw reply [flat|nested] 75+ messages in thread
* Re: [PATCH] mmc: dw_mmc: change to use recommended reset procedure 2014-05-12 21:44 ` Sonny Rao @ 2014-05-13 10:13 ` James Hogan -1 siblings, 0 replies; 75+ messages in thread From: James Hogan @ 2014-05-13 10:13 UTC (permalink / raw) To: Sonny Rao, Jaehoon Chung Cc: linux-samsung-soc, Grant Grundler, Tomasz Figa, linux-mmc, sunil joshi, Douglas Anderson, Seungwon Jeon, kgene.kim, Yuvaraj Kumar, Yuvaraj Kumar C D, Chris Ball, linux-arm-kernel Hi, On 12/05/14 22:44, Sonny Rao wrote: > Doug mentioned that James Hogan might have an answer. James, are > there Imgtec SoCs which use dw_mmc and use DMA but don't use the > IDMAC? If so, we can add that support into this reset procedure > patch. Yes, the Toumaz TZ1090 SoC has the dw_mmc configured without an IDMAC, so it uses the IMG DMAC block instead. Cheers James ^ permalink raw reply [flat|nested] 75+ messages in thread
* [PATCH] mmc: dw_mmc: change to use recommended reset procedure @ 2014-05-13 10:13 ` James Hogan 0 siblings, 0 replies; 75+ messages in thread From: James Hogan @ 2014-05-13 10:13 UTC (permalink / raw) To: linux-arm-kernel Hi, On 12/05/14 22:44, Sonny Rao wrote: > Doug mentioned that James Hogan might have an answer. James, are > there Imgtec SoCs which use dw_mmc and use DMA but don't use the > IDMAC? If so, we can add that support into this reset procedure > patch. Yes, the Toumaz TZ1090 SoC has the dw_mmc configured without an IDMAC, so it uses the IMG DMAC block instead. Cheers James ^ permalink raw reply [flat|nested] 75+ messages in thread
end of thread, other threads:[~2014-08-11 7:55 UTC | newest] Thread overview: 75+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2014-05-13 1:38 [PATCHv2] mmc: dw_mmc: change to use recommended reset procedure Sonny Rao 2014-05-13 1:38 ` Sonny Rao 2014-05-13 5:02 ` Seungwon Jeon 2014-05-13 5:02 ` Seungwon Jeon 2014-05-13 7:16 ` Sonny Rao 2014-05-13 7:16 ` Sonny Rao 2014-05-13 11:09 ` Seungwon Jeon 2014-05-13 11:09 ` Seungwon Jeon 2014-05-17 0:36 ` Sonny Rao 2014-05-17 0:36 ` Sonny Rao 2014-05-20 1:49 ` Seungwon Jeon 2014-05-20 1:49 ` Seungwon Jeon 2014-05-22 18:54 ` Sonny Rao 2014-05-22 18:54 ` Sonny Rao 2014-05-29 0:35 ` [PATCH] " Sonny Rao 2014-05-29 0:35 ` Sonny Rao 2014-05-29 5:17 ` Jaehoon Chung 2014-05-29 5:17 ` Jaehoon Chung 2014-06-09 21:35 ` Sonny Rao 2014-06-09 21:35 ` Sonny Rao 2014-06-09 22:00 ` Sonny Rao 2014-06-09 22:00 ` Sonny Rao 2014-07-10 12:28 ` Seungwon Jeon 2014-07-10 12:28 ` Seungwon Jeon 2014-07-10 22:35 ` Sonny Rao 2014-07-10 22:35 ` Sonny Rao 2014-07-11 10:20 ` Seungwon Jeon 2014-07-11 10:20 ` Seungwon Jeon 2014-07-11 19:48 ` Sonny Rao 2014-07-11 19:48 ` Sonny Rao 2014-07-11 20:53 ` [PATCHv5] " Sonny Rao 2014-07-11 20:53 ` Sonny Rao 2014-07-14 5:52 ` Jaehoon Chung 2014-07-14 5:52 ` Jaehoon Chung 2014-07-14 22:06 ` [PATCHv6] " Sonny Rao 2014-07-14 22:06 ` Sonny Rao 2014-07-18 13:37 ` Seungwon Jeon 2014-07-18 13:37 ` Seungwon Jeon 2014-07-26 9:55 ` Ulf Hansson 2014-07-26 9:55 ` Ulf Hansson 2014-05-13 5:19 ` [PATCHv2] " Kukjin Kim 2014-05-13 5:19 ` Kukjin Kim 2014-05-13 8:46 ` Arnd Bergmann 2014-05-13 8:46 ` Arnd Bergmann -- strict thread matches above, loose matches on Subject: below -- 2014-08-04 13:44 linux-next: build failure after merge of the mmc-uh tree Ulf Hansson 2014-08-05 1:19 ` [PATCH] mmc: dw_mmc: change to use recommended reset procedure Sonny Rao 2014-08-05 1:19 ` Sonny Rao 2014-08-07 8:40 ` Jaehoon Chung 2014-08-07 8:40 ` Jaehoon Chung 2014-08-11 7:55 ` Ulf Hansson 2014-08-11 7:55 ` Ulf Hansson 2014-08-11 7:55 ` Ulf Hansson 2014-03-26 11:46 Yuvaraj Kumar C D 2014-03-26 11:46 ` Yuvaraj Kumar C D 2014-05-08 9:40 ` Yuvaraj Kumar 2014-05-08 9:40 ` Yuvaraj Kumar 2014-05-09 1:15 ` Jaehoon Chung 2014-05-09 1:15 ` Jaehoon Chung 2014-05-09 1:34 ` Sonny Rao 2014-05-09 1:34 ` Sonny Rao 2014-05-09 4:27 ` Jaehoon Chung 2014-05-09 4:27 ` Jaehoon Chung 2014-05-09 7:32 ` Jaehoon Chung 2014-05-09 7:32 ` Jaehoon Chung 2014-05-10 3:36 ` Sonny Rao 2014-05-10 3:36 ` Sonny Rao 2014-05-10 14:08 ` Seungwon Jeon 2014-05-10 14:08 ` Seungwon Jeon 2014-05-12 21:14 ` Sonny Rao 2014-05-12 21:14 ` Sonny Rao 2014-05-12 21:44 ` Sonny Rao 2014-05-12 21:44 ` Sonny Rao 2014-05-13 0:40 ` Sonny Rao 2014-05-13 0:40 ` Sonny Rao 2014-05-13 10:13 ` James Hogan 2014-05-13 10:13 ` James Hogan
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.