Re: [PATCH v7 08/14] mmc: sdhci-msm: Implement set_clock callback for sdhci-msm

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

 



On 16/11/16 06:42, Ritesh Harjani wrote:
> Hi,
> 
> On 11/15/2016 10:40 AM, Ritesh Harjani wrote:
>> Hi Stephen/Adrian,
>>
>> On 11/15/2016 1:07 AM, Stephen Boyd wrote:
>>> On 11/14, Ritesh Harjani wrote:
>>>> @@ -577,6 +578,90 @@ static unsigned int
>>>> sdhci_msm_get_min_clock(struct sdhci_host *host)
>>>>      return SDHCI_MSM_MIN_CLOCK;
>>>>  }
>>>>
>>>> +/**
>>>> + * __sdhci_msm_set_clock - sdhci_msm clock control.
>>>> + *
>>>> + * Description:
>>>> + * Implement MSM version of sdhci_set_clock.
>>>> + * This is required since MSM controller does not
>>>> + * use internal divider and instead directly control
>>>> + * the GCC clock as per HW recommendation.
>>>> + **/
>>>> +void __sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
>>>> +{
>>>> +    u16 clk;
>>>> +    unsigned long timeout;
>>>> +
>>>> +    /*
>>>> +     * Keep actual_clock as zero -
>>>> +     * - since there is no divider used so no need of having
>>>> actual_clock.
>>>> +     * - MSM controller uses SDCLK for data timeout calculation. If
>>>> +     *   actual_clock is zero, host->clock is taken for calculation.
>>>> +     */
>>>> +    host->mmc->actual_clock = 0;
>>>> +
>>>> +    sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
>>>> +
>>>> +    if (clock == 0)
>>>> +        return;
>>>> +
>>>> +    /*
>>>> +     * MSM controller do not use clock divider.
>>>> +     * Thus read SDHCI_CLOCK_CONTROL and only enable
>>>> +     * clock with no divider value programmed.
>>>> +     */
>>>> +    clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
>>>> +
>>>> +    clk |= SDHCI_CLOCK_INT_EN;
>>>> +    sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
>>>> +
>>>> +    /* Wait max 20 ms */
>>>> +    timeout = 20;
>>>> +    while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
>>>> +        & SDHCI_CLOCK_INT_STABLE)) {
>>>> +        if (timeout == 0) {
>>>> +            pr_err("%s: Internal clock never stabilised\n",
>>>> +                   mmc_hostname(host->mmc));
>>>> +            return;
>>>> +        }
>>>> +        timeout--;
>>>> +        mdelay(1);
>>>> +    }
>>>> +
>>>> +    clk |= SDHCI_CLOCK_CARD_EN;
>>>> +    sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
>>>
>>> This is almost a copy/paste of sdhci_set_clock(). Can we make
>>> sdhci_set_clock() call a __sdhci_set_clock() function that takes
>>> unsigned int clock, and also a flag indicating if we want to set
>>> the internal clock divider or not? Then we can call
>>> __sdhci_set_clock() from sdhci_set_clock() with (clock, true) as
>>> arguments and (clock, false).
> Actually what you may be referring here is some sort of quirks which is not
> entertained any more for sdhci driver.
> sdhci is tending towards becoming a library and hence such changes are
> restricted.
> 
> But I think we may do below changes to avoid duplication of code which
> enables the sdhci internal clock and waits for internal clock to be stable.
> 
> Adrian, could you please tell if this should be ok?

That seems fine, but the name seems too long - how about changing
sdhci_set_clock_enable to sdhci_enable_clk.

> Then we may be able to call for sdhci_set_clock_enable function from
> sdhci_msm_set_clock.
> 
> 
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index 42ef3eb..28e605c 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -1343,19 +1343,8 @@ u16 sdhci_calc_clk(struct sdhci_host *host, unsigned
> int clock,
>  }
>  EXPORT_SYMBOL_GPL(sdhci_calc_clk);
> 
> -void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
> +void sdhci_set_clock_enable(struct sdhci_host *host, unsigned short clk)
>  {
> -       u16 clk;
> -       unsigned long timeout;
> -
> -       host->mmc->actual_clock = 0;
> -
> -       sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
> -
> -       if (clock == 0)
> -               return;
> -
> -       clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock);
> 
>         clk |= SDHCI_CLOCK_INT_EN;
>         sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
> @@ -1377,6 +1366,24 @@ void sdhci_set_clock(struct sdhci_host *host,
> unsigned int clock)
>         clk |= SDHCI_CLOCK_CARD_EN;
>         sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
>  }
> +EXPORT_SYMBOL_GPL(sdhci_set_clock_enable);
> +
> +void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
> +{
> +       u16 clk;
> +       unsigned long timeout;
> +
> +       host->mmc->actual_clock = 0;
> +
> +       sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
> +
> +       if (clock == 0)
> +               return;
> +
> +       clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock);
> +
> +       sdhci_set_clock_enable(host, clk);
> +}
>  EXPORT_SYMBOL_GPL(sdhci_set_clock);
> 
>  static void sdhci_set_power_reg(struct sdhci_host *host, unsigned char mode,
> diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
> index 766df17..43382e1 100644
> --- a/drivers/mmc/host/sdhci.h
> +++ b/drivers/mmc/host/sdhci.h
> @@ -681,6 +681,7 @@ static inline bool sdhci_sdio_irq_enabled(struct
> sdhci_host *host)
>  u16 sdhci_calc_clk(struct sdhci_host *host, unsigned int clock,
>                    unsigned int *actual_clock);
>  void sdhci_set_clock(struct sdhci_host *host, unsigned int clock);
> +void sdhci_set_clock_enable(struct sdhci_host *host, unsigned short clk);
>  void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
>                      unsigned short vdd);
>  void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode,
> 
> 
> 
>> Adrian,
>> Could you please comment here ?
>>
>>>
>>>> +}
>>>> +
>>>> +/* sdhci_msm_set_clock - Called with (host->lock) spinlock held. */
>>>> +static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned
>>>> int clock)
>>>> +{
>>>> +    struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
>>>> +    struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
>>>> +    int rc;
>>>> +
>>>> +    if (!clock) {
>>>> +        msm_host->clk_rate = clock;
>>>> +        goto out;
>>>> +    }
>>>> +
>>>> +    spin_unlock_irq(&host->lock);
>>>> +    if (clock != msm_host->clk_rate) {
>>>
>>> Why do we need to check here? Can't we call clk_set_rate()
>>> Unconditionally?
>> Since it may so happen that above layers may call for ->set_clock
>> function with same requested clock more than once, hence we cache the
>> host->clock here.
>> Also, since requested clock (host->clock) can be say 400Mhz but the
>> actual pltfm supported clock would be say 384MHz.
>>
>>
>>>
>>>> +        rc = clk_set_rate(msm_host->clk, clock);
>>>> +        if (rc) {
>>>> +            pr_err("%s: Failed to set clock at rate %u\n",
>>>> +                   mmc_hostname(host->mmc), clock);
>>>> +            spin_lock_irq(&host->lock);
>>>> +            goto out;
>>>
>>> Or replace the above two lines with goto err;
>> Ok, I will have another label out_lock instead of err.
>>>
>>>> +        }
>>>> +        msm_host->clk_rate = clock;
>>>> +        pr_debug("%s: Setting clock at rate %lu\n",
>>>> +             mmc_hostname(host->mmc), clk_get_rate(msm_host->clk));
>>>> +    }
>>>
>>> And put an err label here.
>> will put the label here as out_lock;
>>>
>>>> +    spin_lock_irq(&host->lock);
>>>> +out:
>>>> +    __sdhci_msm_set_clock(host, clock);
>>>> +}
>>>> +
>>>>  static const struct of_device_id sdhci_msm_dt_match[] = {
>>>>      { .compatible = "qcom,sdhci-msm-v4" },
>>>>      {},
>>>
>>
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



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

  Powered by Linux