On Tue, 31 Jul 2018 11:15:41 +0200
Stefan Agner <ste...@agner.ch> wrote:

> On 27.07.2018 10:44, Aapo Vienamo wrote:
> > On Thu, 26 Jul 2018 15:33:11 +0200
> > Stefan Agner <ste...@agner.ch> wrote:
> >   
> >> On 26.07.2018 14:19, Aapo Vienamo wrote:  
> >> > Parse the pinctrl state and nvidia,only-1-8-v properties from the device
> >> > tree and implement pad voltage state reconfiguration in the mmc
> >> > start_signal_voltage_switch() callback. Validate the pinctrl and
> >> > regulator configuration before unmasking UHS modes. Add
> >> > NVQUIRK_NEEDS_PAD_CONTROL and add set it for Tegra210 and Tegra186.
> >> >
> >> > The pad configuration is done in the mmc callback because the order of
> >> > pad reconfiguration and sdhci voltage switch depend on the voltage to
> >> > which the transition occurs.
> >> >
> >> > Signed-off-by: Aapo Vienamo <avien...@nvidia.com>
> >> > ---
> >> >  drivers/mmc/host/sdhci-tegra.c | 140 
> >> > +++++++++++++++++++++++++++++++++++++----
> >> >  1 file changed, 127 insertions(+), 13 deletions(-)
> >> >
> >> > diff --git a/drivers/mmc/host/sdhci-tegra.c 
> >> > b/drivers/mmc/host/sdhci-tegra.c
> >> > index ddf00166..9587365 100644
> >> > --- a/drivers/mmc/host/sdhci-tegra.c
> >> > +++ b/drivers/mmc/host/sdhci-tegra.c
> >> > @@ -21,6 +21,7 @@
> >> >  #include <linux/io.h>
> >> >  #include <linux/of.h>
> >> >  #include <linux/of_device.h>
> >> > +#include <linux/pinctrl/consumer.h>
> >> >  #include <linux/reset.h>
> >> >  #include <linux/mmc/card.h>
> >> >  #include <linux/mmc/host.h>
> >> > @@ -55,6 +56,7 @@
> >> >  #define NVQUIRK_ENABLE_SDR104           BIT(4)
> >> >  #define NVQUIRK_ENABLE_DDR50            BIT(5)
> >> >  #define NVQUIRK_HAS_PADCALIB            BIT(6)
> >> > +#define NVQUIRK_NEEDS_PAD_CONTROL       BIT(7)
> >> >
> >> >  struct sdhci_tegra_soc_data {
> >> >          const struct sdhci_pltfm_data *pdata;
> >> > @@ -66,8 +68,13 @@ struct sdhci_tegra {
> >> >          struct gpio_desc *power_gpio;
> >> >          bool ddr_signaling;
> >> >          bool pad_calib_required;
> >> > +        bool pad_control_available;
> >> > +        bool only_1v8;
> >> >
> >> >          struct reset_control *rst;
> >> > +        struct pinctrl *pinctrl_sdmmc;
> >> > +        struct pinctrl_state *pinctrl_state_3v3;
> >> > +        struct pinctrl_state *pinctrl_state_1v8;
> >> >  };
> >> >
> >> >  static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg)
> >> > @@ -138,12 +145,47 @@ static unsigned int tegra_sdhci_get_ro(struct
> >> > sdhci_host *host)
> >> >          return mmc_gpio_get_ro(host->mmc);
> >> >  }
> >> >
> >> > +static bool tegra_sdhci_is_uhs_valid(struct sdhci_host *host)
> >> > +{
> >> > +        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
> >> > +        struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host);
> >> > +        const struct sdhci_tegra_soc_data *soc_data = 
> >> > tegra_host->soc_data;
> >> > +
> >> > +        /*
> >> > +         * The 1.8 V only host controllers don't need to have 
> >> > configurable
> >> > +         * regulators and pad voltages. In this case the UHS modes can 
> >> > be
> >> > +         * enabled regardless.
> >> > +         */
> >> > +        if (tegra_host->only_1v8)
> >> > +                return true;  
> >>
> >> Hm, SD always needs 3.3V capabilities, not?  
> > 
> > Yes, the controllers used for eMMCs should have the only_1v8 property
> > set and they exit the function here. With controllers used for SD cards,
> > the regulator and pad configurations are verified later in the function.
> >   
> 
> By returning true you ask the controller to enable UHS modes. However,
> if you have 1.8V only, there should be no UHS modes advertised (since SD
> cards require 1.8V).
> 
> That assumes that UHS modes are a SD card thing only (which I think
> strictly speaking should be the case).
> 
> However, at least on Tegra 3 it seems that enabling SD 3.0 is also
> required for higher eMMC speeds:
> https://patchwork.kernel.org/patch/10521147/
> 
> So UHS is probably not so much about SD card UHS modes but more about
> higher speed modes in general...

True.

> >> So if the controller is 1.8V only, then only eMMC modes are allowed.
> >>
> >> You can use MMC_CAP2_HSX00_1_8V in caps2.  
> > 
> > I can't quite follow you, how this should be used here?
> >   
> 
> Similar to 
> 
>         if (tegra_host->soc_data->nvquirks & NVQUIRK_ENABLE_DDR50)      
>                                                                    
>                 host->mmc->caps |= MMC_CAP_1_8V_DDR
> 
> You can enable higher speed eMMC modes without advertising SD card
> modes.

Makes sense. Thanks for clearing that up.

> >> So far the Tegra SDHCI driver did not use device tree to indicate modes,
> >> but maybe we should start doing that. In this case you can use
> >> mmc-hs200-1_8v/mmc-hs400-1_8v to indicate higher eMMC speed modes.
> >>  
> >> > +
> >> > +        /*
> >> > +         * If the board does not define a regulator for the SDHCI IO 
> >> > voltage,
> >> > +         * then don't advertise support for UHS modes even if the device
> >> > +         * supports it because the IO voltage cannot be configured.
> >> > +         */
> >> > +        if (IS_ERR(host->mmc->supply.vqmmc))
> >> > +                return false;  
> >>
> >> The stack should already check that and mask caps1 accordingly (see
> >> sdhci_setup_host).  
> > 
> > True, the logic seems to be duplicated here. Although also
> > tegra_sdhci_reset() needs to be change so that the bits masked off by
> > sdhci_setup_host() aren't set if this check is removed.
> >   
> 
> sdhci_setup_host() calls reset before doing initialization (e.g. in
> __sdhci_read_caps).
> 
> Checking just for vqmmc presence is bogus IMHO. It does not say anything
> about the exact capabilities of that regulator.

Yes, by itself it doesn't make much sense. It looks like the regulator
voltage checking code from sdhci_setup_host() has to be duplicated to
the tegra driver because the regulator checks are done after the reset
callback. The sdhci-tegra driver needs to make sure that the faster
signaling modes are enabled only if pinctrl properties are present on SD
controllers with variable voltage regulators.

> I think we should do something like this:
> 
>       if (there is a host->mmc->supply.vqmmc) {
>               if (host->mmc->supply.vqmmc can do 1.8V (or/and also 1.2V?)) {
>                       /* 
>                        * Enable SDHCI spec v3.00 support
>                        * This is required for SD UHS modes as well as higher 
> eMMC speeds
>                        */
>                       if (soc_data->nvquirks & NVQUIRK_ENABLE_SDHCI_SPEC_300)
>                               misc_ctrl |= 
> SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300;
> 
>                       if (host->mmc->supply.vqmmc can do 3.3V) {
>                               /*
>                                * Proper SD voltage switching is possible, 
> advertise SD UHS 
>                                * modes as supported by host
>                                */
>                               if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR50)
>                                       misc_ctrl |= 
> SDHCI_MISC_CTRL_ENABLE_SDR50;
>                               if (soc_data->nvquirks & NVQUIRK_ENABLE_DDR50)
>                                       misc_ctrl |= 
> SDHCI_MISC_CTRL_ENABLE_DDR50;
>                               if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR104)
>                                       misc_ctrl |= 
> SDHCI_MISC_CTRL_ENABLE_SDR104;
>                               if (soc_data->nvquirks & 
> SDHCI_MISC_CTRL_ENABLE_SDR50)
>                                       clk_ctrl |= 
> SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE;
>                       }
>               }
>       }
> 
> 
> 
> 
> >> > +
> >> > +        /*
> >> > +         * Later SoC generations require software pad voltage 
> >> > configuration.
> >> > +         * The UHS modes should only be enabled if the pad 
> >> > configuration states
> >> > +         * are available on platforms where they are required in order 
> >> > to switch
> >> > +         * the signaling voltage.
> >> > +         */
> >> > +        if (soc_data->nvquirks & NVQUIRK_NEEDS_PAD_CONTROL)
> >> > +                return tegra_host->pad_control_available;
> >> > +
> >> > +        return false;
> >> > +}
> >> > +
> >> >  static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask)
> >> >  {
> >> >          struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
> >> >          struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host);
> >> >          const struct sdhci_tegra_soc_data *soc_data = 
> >> > tegra_host->soc_data;
> >> >          u32 misc_ctrl, clk_ctrl;
> >> > +        bool uhs_valid;
> >> >
> >> >          sdhci_reset(host, mask);
> >> >
> >> > @@ -160,13 +202,8 @@ static void tegra_sdhci_reset(struct sdhci_host
> >> > *host, u8 mask)
> >> >
> >> >          clk_ctrl &= ~SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE;
> >> >
> >> > -        /*
> >> > -         * If the board does not define a regulator for the SDHCI
> >> > -         * IO voltage, then don't advertise support for UHS modes
> >> > -         * even if the device supports it because the IO voltage
> >> > -         * cannot be configured.
> >> > -         */
> >> > -        if (!IS_ERR(host->mmc->supply.vqmmc)) {
> >> > +        uhs_valid = tegra_sdhci_is_uhs_valid(host);
> >> > +        if (uhs_valid) {
> >> >                  /* Erratum: Enable SDHCI spec v3.00 support */
> >> >                  if (soc_data->nvquirks & NVQUIRK_ENABLE_SDHCI_SPEC_300)
> >> >                          misc_ctrl |= 
> >> > SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300;
> >> > @@ -286,14 +323,80 @@ static int tegra_sdhci_execute_tuning(struct
> >> > sdhci_host *host, u32 opcode)
> >> >          return mmc_send_tuning(host->mmc, opcode, NULL);
> >> >  }
> >> >
> >> > -static void tegra_sdhci_voltage_switch(struct sdhci_host *host)
> >> > +static int tegra_sdhci_set_padctrl(struct sdhci_host *host, int voltage)
> >> >  {
> >> >          struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
> >> >          struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host);
> >> > -        const struct sdhci_tegra_soc_data *soc_data = 
> >> > tegra_host->soc_data;
> >> > +        int ret;
> >> > +
> >> > +        if (!tegra_host->pad_control_available)
> >> > +                return 0;
> >> > +
> >> > +        if (voltage == MMC_SIGNAL_VOLTAGE_180) {
> >> > +                ret = pinctrl_select_state(tegra_host->pinctrl_sdmmc,
> >> > +                                           
> >> > tegra_host->pinctrl_state_1v8);
> >> > +                if (ret < 0)
> >> > +                        dev_err(mmc_dev(host->mmc),
> >> > +                                "setting 1.8V failed, ret: %d\n", ret);
> >> > +        } else {
> >> > +                ret = pinctrl_select_state(tegra_host->pinctrl_sdmmc,
> >> > +                                           
> >> > tegra_host->pinctrl_state_3v3);
> >> > +                if (ret < 0)
> >> > +                        dev_err(mmc_dev(host->mmc),
> >> > +                                "setting 3.3V failed, ret: %d\n", ret);
> >> > +        }
> >> >
> >> > -        if (soc_data->nvquirks & NVQUIRK_HAS_PADCALIB)
> >> > -                tegra_host->pad_calib_required = true;  
> 
> Is this really not needed anymore?

Good catch. That probably happened accidentally during a rebase.

> >> > +        return ret;
> >> > +}
> >> > +
> >> > +static int sdhci_tegra_start_signal_voltage_switch(struct mmc_host *mmc,
> >> > +                                                   struct mmc_ios *ios)
> >> > +{
> >> > +        struct sdhci_host *host = mmc_priv(mmc);
> >> > +        int ret = 0;
> >> > +
> >> > +        if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
> >> > +                ret = tegra_sdhci_set_padctrl(host, 
> >> > ios->signal_voltage);
> >> > +                if (ret < 0)
> >> > +                        return ret;
> >> > +                ret = sdhci_start_signal_voltage_switch(mmc, ios);
> >> > +        } else if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
> >> > +                ret = sdhci_start_signal_voltage_switch(mmc, ios);
> >> > +                if (ret < 0)
> >> > +                        return ret;
> >> > +                ret = tegra_sdhci_set_padctrl(host, 
> >> > ios->signal_voltage);  
> >>
> >> So depending on voltage you first set the pads setting and then do the
> >> signaling voltage switch. Is this necessary? Why?  
> > 
> > This is done to enforce the constraint of keeping the signaling voltage
> > always less or equal to the pad voltage. Driving 3.3 V into a pad that
> > has been configured to 1.8 V will damage it. This is stated in the
> > Tegra210 and Tegra186 TRMs in SDMMC Initialization Sequece sections of
> > controllers supporting voltage switching.
> > 
> > Here when switching from 3.3 V to 1.8 V the regulator is first
> > configured to 1.8 V by sdhci_start_signal_voltage_switch() and after
> > that the pad is configured to 1.8 V. When going in the other direction
> > the pad needs to be first configured to 3.3 V before the regulator
> > voltage can be raised.  
> 
> Ok makes sense. Can you add a comment, e.g. /* Order of operation
> matters, it make sure to keep signaling voltage below pad voltage */
> 
> >   
> >> > +        }
> >> > +
> >> > +        return ret;
> >> > +}
> >> > +
> >> > +static void tegra_sdhci_init_pinctrl_info(struct device *dev,
> >> > +                                          struct sdhci_tegra 
> >> > *tegra_host)
> >> > +{
> >> > +        tegra_host->pinctrl_sdmmc = devm_pinctrl_get(dev);
> >> > +        if (IS_ERR(tegra_host->pinctrl_sdmmc)) {
> >> > +                dev_dbg(dev, "No pinctrl info, err: %ld\n",
> >> > +                        PTR_ERR(tegra_host->pinctrl_sdmmc));
> >> > +                return;
> >> > +        }
> >> > +
> >> > +        tegra_host->pinctrl_state_3v3 =
> >> > +                pinctrl_lookup_state(tegra_host->pinctrl_sdmmc, 
> >> > "sdmmc-3v3");
> >> > +        if (IS_ERR(tegra_host->pinctrl_state_3v3)) {
> >> > +                dev_err(dev, "Missing 3.3V pad state, err: %ld\n",
> >> > +                        PTR_ERR(tegra_host->pinctrl_state_3v3));
> >> > +                return;
> >> > +        }
> >> > +
> >> > +        tegra_host->pinctrl_state_1v8 =
> >> > +                pinctrl_lookup_state(tegra_host->pinctrl_sdmmc, 
> >> > "sdmmc-1v8");
> >> > +        if (IS_ERR(tegra_host->pinctrl_state_1v8)) {
> >> > +                dev_err(dev, "Missing 1.8V pad state, err: %ld\n",
> >> > +                          PTR_ERR(tegra_host->pinctrl_state_3v3));  
> >>
> >> Is missing pad states considered as error? If yes, we should return a
> >> error code and make the probe function fail.
> >>
> >> If it is ok to run it without the states, then this should be dev_warn
> >> or dev_info.  
> > 
> > I don't think failing probe due to missing pinctrl entries can be done
> > because it would break backwards compatibility with pre-existing dtbs.
> > Also SDHCI controllers with fixed signaling voltage don't support pad
> > voltage reconfiguration and therefore the pinctrl properties won't be
> > there either. In the case of fixed voltage SDHCI controllers the
> > "nvidia,only-1-8-v" property is used to signal that pad reconfiguration
> > doesn't need to be performed.  
> 
> Ok, if they are not mandatory, just use dev_warn(...).
> 
> Btw,
> 
> +    if (soc_data->nvquirks & NVQUIRK_NEEDS_PAD_CONTROL) {
> +        host->mmc_host_ops.start_signal_voltage_switch =
> +            sdhci_tegra_start_signal_voltage_switch;
> +        tegra_sdhci_init_pinctrl_info(&pdev->dev, tegra_host);
> +    }
> +
> 
> Can we make tegra_sdhci_init_pinctrl_info return a boolean and do the
> tegra_host->pad_control_available assignment here? I think this would be
> cleaner.
> 
> It also won't assign host->mmc_host_ops.start_signal_voltage_switch if
> not needed.
> 
>       if (soc_data->nvquirks & NVQUIRK_NEEDS_PAD_CONTROL &&
>           tegra_sdhci_init_pinctrl_info(&pdev->dev, tegra_host)) {
>               host->mmc_host_ops.start_signal_voltage_switch =
>                       sdhci_tegra_start_signal_voltage_switch;
>               tegra_host->pad_control_available = true;
>       }

 -Aapo

Reply via email to