From 75067aba7afbeca2101f50f78ac1b7c036778c44 Mon Sep 17 00:00:00 2001 From: Aapo Vienamo Date: Mon, 4 Jun 2018 18:35:40 +0300 Subject: mmc: tegra: Use sdhci_pltfm_clk_get_max_clock The sdhci get_max_clock callback is set to sdhci_pltfm_clk_get_max_clock and tegra_sdhci_get_max_clock is removed. It appears that the shdci-tegra specific callback was originally introduced due to the requirement that the host clock has to be twice the bus clock on DDR50 mode. As far as I can tell the only effect the removal has on DDR50 mode is in cases where the parent clock is unable to supply the requested clock rate, causing the DDR50 mode to run at a lower frequency. Currently the DDR50 mode isn't enabled on any of the SoCs and would also require configuring the SDHCI clock divider register to function properly. The problem with tegra_sdhci_get_max_clock is that it divides the clock rate by two and thus artificially limits the maximum frequency of faster signaling modes which don't have the host-bus frequency ratio requirement of DDR50 such as SDR104 and HS200. Furthermore, the call to clk_round_rate() may return an error which isn't handled by tegra_sdhci_get_max_clock. Signed-off-by: Aapo Vienamo Acked-by: Thierry Reding Tested-by: Thierry Reding Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-tegra.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) (limited to 'drivers/mmc/host/sdhci-tegra.c') diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 970d38f68939..c8745b5547d8 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -234,17 +234,6 @@ static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host, sdhci_set_uhs_signaling(host, timing); } -static unsigned int tegra_sdhci_get_max_clock(struct sdhci_host *host) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - - /* - * DDR modes require the host to run at double the card frequency, so - * the maximum rate we can support is half of the module input clock. - */ - return clk_round_rate(pltfm_host->clk, UINT_MAX) / 2; -} - static void tegra_sdhci_set_tap(struct sdhci_host *host, unsigned int tap) { u32 reg; @@ -309,7 +298,7 @@ static const struct sdhci_ops tegra_sdhci_ops = { .platform_execute_tuning = tegra_sdhci_execute_tuning, .set_uhs_signaling = tegra_sdhci_set_uhs_signaling, .voltage_switch = tegra_sdhci_voltage_switch, - .get_max_clock = tegra_sdhci_get_max_clock, + .get_max_clock = sdhci_pltfm_clk_get_max_clock, }; static const struct sdhci_pltfm_data sdhci_tegra20_pdata = { @@ -357,7 +346,7 @@ static const struct sdhci_ops tegra114_sdhci_ops = { .platform_execute_tuning = tegra_sdhci_execute_tuning, .set_uhs_signaling = tegra_sdhci_set_uhs_signaling, .voltage_switch = tegra_sdhci_voltage_switch, - .get_max_clock = tegra_sdhci_get_max_clock, + .get_max_clock = sdhci_pltfm_clk_get_max_clock, }; static const struct sdhci_pltfm_data sdhci_tegra114_pdata = { -- cgit From 127407e36f4fe3a1d5e8b9998b479956ce83a7dc Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Thu, 12 Jul 2018 09:39:02 +0200 Subject: mmc: tegra: prevent HS200 on Tegra 3 The stack assumes that SDHC controller which support SD3.0 (SDR104) do support HS200. This is not the case for Tegra 3, which does support SD 3.0 but only supports eMMC spec 4.41. Use SDHCI_QUIRK2_BROKEN_HS200 to indicate that the controller does not support HS200. Note that commit 156e14b126ff ("mmc: sdhci: fix caps2 for HS200") added the tie between SD3.0 (SDR104) and HS200. I don't think that this is necessarly true. It is fully legitimate to support SD3.0 and not support HS200. The quirk naming suggests something is broken in the controller, but this is not the case: The controller simply does not support HS200. Fixes: 7ad2ed1dfcbe ("mmc: tegra: enable UHS-I modes") Signed-off-by: Stefan Agner Tested-by: Marcel Ziswiler Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-tegra.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/mmc/host/sdhci-tegra.c') diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index c8745b5547d8..5355d06d0a5e 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -323,7 +323,8 @@ static const struct sdhci_pltfm_data sdhci_tegra30_pdata = { SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, - .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | + SDHCI_QUIRK2_BROKEN_HS200, .ops = &tegra_sdhci_ops, }; -- cgit From e300149e580863b00a736b534c7163dcf0813641 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Thu, 12 Jul 2018 09:39:03 +0200 Subject: mmc: tegra: fix eMMC DDR52 mode Make sure the clock is doubled when using eMMC DDR52 mode. Signed-off-by: Stefan Agner Tested-by: Marcel Ziswiler Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-tegra.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/mmc/host/sdhci-tegra.c') diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 5355d06d0a5e..e231c3e11bcd 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -228,7 +228,8 @@ static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host, struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); - if (timing == MMC_TIMING_UHS_DDR50) + if (timing == MMC_TIMING_UHS_DDR50 || + timing == MMC_TIMING_MMC_DDR52) tegra_host->ddr_signaling = true; sdhci_set_uhs_signaling(host, timing); -- cgit From 726df1d5a62ec8241a2823f6b23728db61178eaa Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Thu, 12 Jul 2018 09:39:04 +0200 Subject: mmc: tegra: prevent ACMD23 on Tegra 3 It seems that SD3.0 advertisement needs to be set for higher eMMC speed modes (namely DDR52) as well. The TRM states that the SD3.0 advertisement bit should be set for all controller instances, even for those not supporting UHS-I mode... When specifying vqmmc-supply as a fixed 1.8V regulator on a Tegra SD/MMC instance which is connected to a eMMC device, the stack enables SD3.0. However, enabling it has consequences: If SDHCI 3.0 support is advertised the stack enables Auto-CMD23. Unfortunately Auto-CMD23 seems not to work well with Tegra 3 currently. It leads to regular warnings: mmc2: Got command interrupt 0x00010000 even though no command operation was in progress. It is not entirely clear why those errors happens. It seems that a Linux 3.1 based downstream kernel which has Auto-CMD23 support does not show those warnings. Use quirk SDHCI_QUIRK2_ACMD23_BROKEN to prevent Auto-CMD23 being used for now. With this the eMMC works stable on high-speed mode while still announcing SD3.0. This allows to use mmc-ddr-1_8v to enables DDR52 mode. In DDR52 mode read speed improves from about 42MiB/s to 72MiB/s on an Apalis T30. Signed-off-by: Stefan Agner Tested-by: Marcel Ziswiler Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-tegra.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers/mmc/host/sdhci-tegra.c') diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index e231c3e11bcd..28b98e26106b 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -325,7 +325,15 @@ static const struct sdhci_pltfm_data sdhci_tegra30_pdata = { SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | - SDHCI_QUIRK2_BROKEN_HS200, + SDHCI_QUIRK2_BROKEN_HS200 | + /* + * Auto-CMD23 leads to "Got command interrupt 0x00010000 even + * though no command operation was in progress." + * + * The exact reason is unknown, as the same hardware seems + * to support Auto CMD23 on a downstream 3.1 kernel. + */ + SDHCI_QUIRK2_ACMD23_BROKEN, .ops = &tegra_sdhci_ops, }; -- cgit From 44350993d01c901cc201ef2663fd0fded2e03d06 Mon Sep 17 00:00:00 2001 From: Aapo Vienamo Date: Fri, 13 Jul 2018 16:17:45 +0300 Subject: mmc: tegra: Add and use tegra_sdhci_get_max_clock() Implement and use tegra_sdhci_get_max_clock() which returns the true maximum host clock rate. The issue with tegra_sdhci_get_max_clock() is that it returns the current clock rate of the host instead of the maximum one, which can lead to unnecessarily small clock rates. This differs from the previous implementation of tegra_sdhci_get_max_clock() in that it doesn't divide the result by two. Signed-off-by: Aapo Vienamo Tested-by: Marcel Ziswiler Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-tegra.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/mmc/host/sdhci-tegra.c') diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 28b98e26106b..ddf001669609 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -235,6 +235,13 @@ static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host, sdhci_set_uhs_signaling(host, timing); } +static unsigned int tegra_sdhci_get_max_clock(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + + return clk_round_rate(pltfm_host->clk, UINT_MAX); +} + static void tegra_sdhci_set_tap(struct sdhci_host *host, unsigned int tap) { u32 reg; @@ -299,7 +306,7 @@ static const struct sdhci_ops tegra_sdhci_ops = { .platform_execute_tuning = tegra_sdhci_execute_tuning, .set_uhs_signaling = tegra_sdhci_set_uhs_signaling, .voltage_switch = tegra_sdhci_voltage_switch, - .get_max_clock = sdhci_pltfm_clk_get_max_clock, + .get_max_clock = tegra_sdhci_get_max_clock, }; static const struct sdhci_pltfm_data sdhci_tegra20_pdata = { @@ -356,7 +363,7 @@ static const struct sdhci_ops tegra114_sdhci_ops = { .platform_execute_tuning = tegra_sdhci_execute_tuning, .set_uhs_signaling = tegra_sdhci_set_uhs_signaling, .voltage_switch = tegra_sdhci_voltage_switch, - .get_max_clock = sdhci_pltfm_clk_get_max_clock, + .get_max_clock = tegra_sdhci_get_max_clock, }; static const struct sdhci_pltfm_data sdhci_tegra114_pdata = { -- cgit From 57d1654ec96a49f5a093f9cbe40718c92ab5daa0 Mon Sep 17 00:00:00 2001 From: Aapo Vienamo Date: Mon, 16 Jul 2018 17:34:29 +0300 Subject: mmc: tegra: Force correct divider calculation on DDR50/52 Tegra SDHCI controllers require the SDHCI clock divider to be configured to divide the clock by two in DDR50/52 modes. Incorrectly configured clock divider results in corrupted data. Prevent the possibility of incorrectly calculating the divider value due to clock rate rounding or low parent clock frequency by not assigning host->max_clk to clk_get_rate() on tegra_sdhci_set_clock(). See the comments for further details. Fixes: a8e326a ("mmc: tegra: implement module external clock change") Signed-off-by: Aapo Vienamo Acked-by: Jon Hunter Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-tegra.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers/mmc/host/sdhci-tegra.c') diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index ddf001669609..908b23e6a03c 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -210,9 +210,24 @@ static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) if (!clock) return sdhci_set_clock(host, clock); + /* + * In DDR50/52 modes the Tegra SDHCI controllers require the SDHCI + * divider to be configured to divided the host clock by two. The SDHCI + * clock divider is calculated as part of sdhci_set_clock() by + * sdhci_calc_clk(). The divider is calculated from host->max_clk and + * the requested clock rate. + * + * By setting the host->max_clk to clock * 2 the divider calculation + * will always result in the correct value for DDR50/52 modes, + * regardless of clock rate rounding, which may happen if the value + * from clk_get_rate() is used. + */ host_clk = tegra_host->ddr_signaling ? clock * 2 : clock; clk_set_rate(pltfm_host->clk, host_clk); - host->max_clk = clk_get_rate(pltfm_host->clk); + if (tegra_host->ddr_signaling) + host->max_clk = host_clk; + else + host->max_clk = clk_get_rate(pltfm_host->clk); sdhci_set_clock(host, clock); -- cgit