Re: [PATCH] mmc: renesas_sdhi: fix hang up in HS400 timing mode selection

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, 18 Sep 2019 at 00:50, Wolfram Sang
<wsa+renesas@xxxxxxxxxxxxxxxxxxxx> wrote:
>
> From: Takeshi Saito <takeshi.saito.xv@xxxxxxxxxxx>
>
> In HS400 timing mode selection, SD clock is switched like:
>
> 1) HS200 (200MHz) for tuning
> 2) High Speed (<= 52MHz) for select HS400 mode (card)
> 3) HS400 (200MHz)
>
> The SDHI controller needs its internal SCC component for HS400 and other
> modes which need tuning. However, SCC gets only fed a clock when the
> module clk is > 100MHz. Make sure the SCC is always active with tuning
> by enforcing at least 100MHz. Note that we only change the module clock.
> An internal divider ensures that we will still talk to the card at
> 52MHz.
>
> Signed-off-by: Takeshi Saito <takeshi.saito.xv@xxxxxxxxxxx>
> [wsa: don't overwrite 'new_freq', use 'mmc_doing_retune', improve docs]
> Signed-off-by: Wolfram Sang <wsa+renesas@xxxxxxxxxxxxxxxxxxxx>

Assuming you want this for stable as well, but perhaps we can also
find a commit to add a fixes tag? Do you have any suggestions for a
commit?

Kind regards
Uffe

> ---
>
> Shimoda-san: can you forward this patch to the BSP team to have a look,
> too? I needed to change their version of checking various MMC_TIMING_*
> constants because this approach did not work with current mainline for
> me. After some testing and researching, I think the solution with
> 'mmc_doing_retune' is not only working again, but also more future
> proof, in general.
>
>  drivers/mmc/host/renesas_sdhi.h               | 2 ++
>  drivers/mmc/host/renesas_sdhi_core.c          | 8 +++++++-
>  drivers/mmc/host/renesas_sdhi_internal_dmac.c | 2 ++
>  3 files changed, 11 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h
> index c0504aa90857..33a1acc67cb4 100644
> --- a/drivers/mmc/host/renesas_sdhi.h
> +++ b/drivers/mmc/host/renesas_sdhi.h
> @@ -27,6 +27,7 @@ struct renesas_sdhi_of_data {
>         dma_addr_t dma_rx_offset;
>         unsigned int bus_shift;
>         int scc_offset;
> +       unsigned int scc_base_f_min;
>         struct renesas_sdhi_scc *taps;
>         int taps_num;
>         unsigned int max_blk_count;
> @@ -49,6 +50,7 @@ struct renesas_sdhi {
>         struct pinctrl *pinctrl;
>         struct pinctrl_state *pins_default, *pins_uhs;
>         void __iomem *scc_ctl;
> +       unsigned int scc_base_f_min;
>         u32 scc_tappos;
>         u32 scc_tappos_hs400;
>  };
> diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
> index 4a2872f49a60..82a492567016 100644
> --- a/drivers/mmc/host/renesas_sdhi_core.c
> +++ b/drivers/mmc/host/renesas_sdhi_core.c
> @@ -120,16 +120,21 @@ static int renesas_sdhi_clk_enable(struct tmio_mmc_host *host)
>  }
>
>  static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host,
> -                                           unsigned int new_clock)
> +                                           unsigned int req_clock)
>  {
>         struct renesas_sdhi *priv = host_to_priv(host);
>         unsigned int freq, diff, best_freq = 0, diff_min = ~0;
> +       unsigned int new_clock = req_clock;
>         int i, ret;
>
>         /* tested only on R-Car Gen2+ currently; may work for others */
>         if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2))
>                 return clk_get_rate(priv->clk);
>
> +       /* When SCC is needed, make sure it gets a proper clock */
> +       if (mmc_doing_retune(host->mmc) && new_clock < priv->scc_base_f_min)
> +               new_clock = priv->scc_base_f_min;
> +
>         /*
>          * We want the bus clock to be as close as possible to, but no
>          * greater than, new_clock.  As we can divide by 1 << i for
> @@ -709,6 +714,7 @@ int renesas_sdhi_probe(struct platform_device *pdev,
>                 mmc_data->max_segs = of_data->max_segs;
>                 dma_priv->dma_buswidth = of_data->dma_buswidth;
>                 host->bus_shift = of_data->bus_shift;
> +               priv->scc_base_f_min = of_data->scc_base_f_min;
>         }
>
>         host->write16_hook      = renesas_sdhi_write16_hook;
> diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c
> index 751fe91c7571..7010c524b180 100644
> --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c
> +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c
> @@ -109,6 +109,8 @@ static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {
>         .capabilities2  = MMC_CAP2_NO_WRITE_PROTECT,
>         .bus_shift      = 2,
>         .scc_offset     = 0x1000,
> +       /* SCC module clock (SDnH) is enabled at 100MHz or more */
> +       .scc_base_f_min = 100000000,
>         .taps           = rcar_gen3_scc_taps,
>         .taps_num       = ARRAY_SIZE(rcar_gen3_scc_taps),
>         /* DMAC can handle 32bit blk count but only 1 segment */
> --
> 2.20.1
>



[Index of Archives]     [Linux Memonry Technology]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux