Received: by 2002:ac0:a5a7:0:0:0:0:0 with SMTP id m36-v6csp5061148imm; Tue, 31 Jul 2018 05:00:52 -0700 (PDT) X-Google-Smtp-Source: AAOMgpfTI255n+B6mRPzGsfV6c98oPU7obhQ0rlc9WpE9f2XQCiZeiRm7nYB43ohxByoyBdsiyW7 X-Received: by 2002:a17:902:9302:: with SMTP id bc2-v6mr20177258plb.280.1533038452836; Tue, 31 Jul 2018 05:00:52 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1533038452; cv=none; d=google.com; s=arc-20160816; b=nmzP6aOPSF09ROtffBQkjhL+0xm/B5G+JMuRT4a3HQ2frKwZUefmR7XAnb338Os9bJ cvJ1k/LR6hHHmnkwahMWz9KUa38i0yXWwLzp1QLavD2bUgq0yj7w2llcM8pY4kYvZuEs 888MX0y7Z0xM2W5wd06gqeyNUePnFcl7s4Z+eo5wFzQND1PkjnOFfdvYRXYkWNHQ8oPn 7+clPAXVimLT7XeAHYx1c27PVr9GMCJXPvMbODr7zD7yIVJugivijFMzv6cjdP9Vgx6A VuNbh7PsugcXKLCWY2tkrXa4s9UuGgM8ScMZ0AapesijzMTFaCiXOCXcELwteG+9Yq9o FgDg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:subject:cc:to:from:date :arc-authentication-results; bh=SAps2BVZJ6e2Rn9e5rf+nZmmqvjj4XlC2SwyXgWhkf0=; b=QHqn+DPhcgU1zJqxNeHBmcBeG/oCBlh57V3sekDHu8rBzuaO4bNfRZrRul81XjVoUW JA80GcyI30Fn6H1/uirvt8VOekOi7ljVNIF5meE2+GeRmo0Au3ZTipJJaoKjVSxYnl28 Jvp9ENbHHnAuJidYc3pvSd4bEhKjh1+XEOIRTWp1JH1mSN4QlCraCc1Y6TTs2aoYnboW gv9HYEI0dMosPw7wiCpOCUHfQ2zvCkZYNJ/td7F0NfofqRYyHg886MAV0f8hH5Bv7dvP czIqhgMUQHbT8srbArsRJONDekFDFsXz8vdSXC426K5TFTlmXW+nkzTXGZyAF/ZSDZD2 KnJg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=nvidia.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id d21-v6si13500958pgn.222.2018.07.31.05.00.38; Tue, 31 Jul 2018 05:00:52 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=nvidia.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732129AbeGaNjs (ORCPT + 99 others); Tue, 31 Jul 2018 09:39:48 -0400 Received: from hqemgate14.nvidia.com ([216.228.121.143]:7896 "EHLO hqemgate14.nvidia.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731988AbeGaNjs (ORCPT ); Tue, 31 Jul 2018 09:39:48 -0400 Received: from hqpgpgate101.nvidia.com (Not Verified[216.228.121.13]) by hqemgate14.nvidia.com (using TLS: TLSv1, AES128-SHA) id ; Tue, 31 Jul 2018 04:59:37 -0700 Received: from HQMAIL101.nvidia.com ([172.20.161.6]) by hqpgpgate101.nvidia.com (PGP Universal service); Tue, 31 Jul 2018 04:59:48 -0700 X-PGP-Universal: processed; by hqpgpgate101.nvidia.com on Tue, 31 Jul 2018 04:59:48 -0700 Received: from dhcp-10-21-25-168 (10.21.25.201) by HQMAIL101.nvidia.com (172.20.187.10) with Microsoft SMTP Server (TLS) id 15.0.1347.2; Tue, 31 Jul 2018 11:59:44 +0000 Date: Tue, 31 Jul 2018 14:59:38 +0300 From: Aapo Vienamo To: Stefan Agner CC: Ulf Hansson , Rob Herring , Mark Rutland , Thierry Reding , Jonathan Hunter , "Adrian Hunter" , Mikko Perttunen , , , , , Subject: Re: [PATCH v2 03/10] mmc: tegra: Reconfigure pad voltages during voltage switching Message-ID: <20180731145938.58c9a96c@dhcp-10-21-25-168> In-Reply-To: References: X-NVConfidentiality: public MIME-Version: 1.0 Content-Type: text/plain; charset="US-ASCII" Content-Transfer-Encoding: 7bit X-Originating-IP: [10.21.25.201] X-ClientProxiedBy: UKMAIL102.nvidia.com (10.26.138.15) To HQMAIL101.nvidia.com (172.20.187.10) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Tue, 31 Jul 2018 11:15:41 +0200 Stefan Agner wrote: > On 27.07.2018 10:44, Aapo Vienamo wrote: > > On Thu, 26 Jul 2018 15:33:11 +0200 > > Stefan Agner 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 > >> > --- > >> > 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 > >> > #include > >> > #include > >> > +#include > >> > #include > >> > #include > >> > #include > >> > @@ -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