Commit 59815d6d authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'mmc-v5.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc

Pull MMC fixes from Ulf Hansson:

 - Fix HS400 tuning for ACPI ID AMDI0040

 - Fix reset of CQHCI for Intel GLK-based controllers

 - Use correct timeout clock for Tegra186/194/210

 - Fix eMMC mounting on mt7622/Bpi-64

* tag 'mmc-v5.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc:
  sdhci: tegra: Add missing TMCLK for data timeout
  arm64: tegra: Add missing timeout clock to Tegra194 SDMMC nodes
  arm64: tegra: Add missing timeout clock to Tegra186 SDMMC nodes
  arm64: tegra: Add missing timeout clock to Tegra210 SDMMC
  dt-bindings: mmc: tegra: Add tmclk for Tegra210 and later
  sdhci: tegra: Remove SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK for Tegra186
  sdhci: tegra: Remove SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK for Tegra210
  arm64: dts: mt7622: add reset node for mmc device
  dt-bindings: mmc: Add missing description for clk_in/out_sd1
  mmc: mediatek: add optional module reset property
  mmc: dt-bindings: Add resets/reset-names for Mediatek MMC bindings
  mmc: sdhci-pci: Fix SDHCI_RESET_ALL for CQHCI for Intel GLK-based controllers
  mmc: sdhci-acpi: Fix HS400 tuning for AMDI0040
parents f75aef39 8048822b
...@@ -30,9 +30,13 @@ allOf: ...@@ -30,9 +30,13 @@ allOf:
then: then:
properties: properties:
clock-output-names: clock-output-names:
items: oneOf:
- items:
- const: clk_out_sd0 - const: clk_out_sd0
- const: clk_in_sd0 - const: clk_in_sd0
- items:
- const: clk_out_sd1
- const: clk_in_sd1
properties: properties:
compatible: compatible:
......
...@@ -50,6 +50,8 @@ Optional properties: ...@@ -50,6 +50,8 @@ Optional properties:
error caused by stop clock(fifo full) error caused by stop clock(fifo full)
Valid range = [0:0x7]. if not present, default value is 0. Valid range = [0:0x7]. if not present, default value is 0.
applied to compatible "mediatek,mt2701-mmc". applied to compatible "mediatek,mt2701-mmc".
- resets: Phandle and reset specifier pair to softreset line of MSDC IP.
- reset-names: Should be "hrst".
Examples: Examples:
mmc0: mmc@11230000 { mmc0: mmc@11230000 {
......
...@@ -15,8 +15,15 @@ Required properties: ...@@ -15,8 +15,15 @@ Required properties:
- "nvidia,tegra210-sdhci": for Tegra210 - "nvidia,tegra210-sdhci": for Tegra210
- "nvidia,tegra186-sdhci": for Tegra186 - "nvidia,tegra186-sdhci": for Tegra186
- "nvidia,tegra194-sdhci": for Tegra194 - "nvidia,tegra194-sdhci": for Tegra194
- clocks : Must contain one entry, for the module clock. - clocks: For Tegra210, Tegra186 and Tegra194 must contain two entries.
See ../clocks/clock-bindings.txt for details. One for the module clock and one for the timeout clock.
For all other Tegra devices, must contain a single entry for
the module clock. See ../clocks/clock-bindings.txt for details.
- clock-names: For Tegra210, Tegra186 and Tegra194 must contain the
strings 'sdhci' and 'tmclk' to represent the module and
the timeout clocks, respectively.
For all other Tegra devices must contain the string 'sdhci'
to represent the module clock.
- resets : Must contain an entry for each entry in reset-names. - resets : Must contain an entry for each entry in reset-names.
See ../reset/reset.txt for details. See ../reset/reset.txt for details.
- reset-names : Must include the following entries: - reset-names : Must include the following entries:
...@@ -99,7 +106,7 @@ Optional properties for Tegra210, Tegra186 and Tegra194: ...@@ -99,7 +106,7 @@ Optional properties for Tegra210, Tegra186 and Tegra194:
Example: Example:
sdhci@700b0000 { sdhci@700b0000 {
compatible = "nvidia,tegra210-sdhci", "nvidia,tegra124-sdhci"; compatible = "nvidia,tegra124-sdhci";
reg = <0x0 0x700b0000 0x0 0x200>; reg = <0x0 0x700b0000 0x0 0x200>;
interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA210_CLK_SDMMC1>; clocks = <&tegra_car TEGRA210_CLK_SDMMC1>;
...@@ -115,3 +122,22 @@ sdhci@700b0000 { ...@@ -115,3 +122,22 @@ sdhci@700b0000 {
nvidia,pad-autocal-pull-down-offset-1v8 = <0x7b>; nvidia,pad-autocal-pull-down-offset-1v8 = <0x7b>;
status = "disabled"; status = "disabled";
}; };
sdhci@700b0000 {
compatible = "nvidia,tegra210-sdhci";
reg = <0x0 0x700b0000 0x0 0x200>;
interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA210_CLK_SDMMC1>,
<&tegra_car TEGRA210_CLK_SDMMC_LEGACY>;
clock-names = "sdhci", "tmclk";
resets = <&tegra_car 14>;
reset-names = "sdhci";
pinctrl-names = "sdmmc-3v3", "sdmmc-1v8";
pinctrl-0 = <&sdmmc1_3v3>;
pinctrl-1 = <&sdmmc1_1v8>;
nvidia,pad-autocal-pull-up-offset-3v3 = <0x00>;
nvidia,pad-autocal-pull-down-offset-3v3 = <0x7d>;
nvidia,pad-autocal-pull-up-offset-1v8 = <0x7b>;
nvidia,pad-autocal-pull-down-offset-1v8 = <0x7b>;
status = "disabled";
};
...@@ -686,6 +686,8 @@ mmc0: mmc@11230000 { ...@@ -686,6 +686,8 @@ mmc0: mmc@11230000 {
clocks = <&pericfg CLK_PERI_MSDC30_0_PD>, clocks = <&pericfg CLK_PERI_MSDC30_0_PD>,
<&topckgen CLK_TOP_MSDC50_0_SEL>; <&topckgen CLK_TOP_MSDC50_0_SEL>;
clock-names = "source", "hclk"; clock-names = "source", "hclk";
resets = <&pericfg MT7622_PERI_MSDC0_SW_RST>;
reset-names = "hrst";
status = "disabled"; status = "disabled";
}; };
......
...@@ -337,8 +337,9 @@ sdmmc1: mmc@3400000 { ...@@ -337,8 +337,9 @@ sdmmc1: mmc@3400000 {
compatible = "nvidia,tegra186-sdhci"; compatible = "nvidia,tegra186-sdhci";
reg = <0x0 0x03400000 0x0 0x10000>; reg = <0x0 0x03400000 0x0 0x10000>;
interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&bpmp TEGRA186_CLK_SDMMC1>; clocks = <&bpmp TEGRA186_CLK_SDMMC1>,
clock-names = "sdhci"; <&bpmp TEGRA186_CLK_SDMMC_LEGACY_TM>;
clock-names = "sdhci", "tmclk";
resets = <&bpmp TEGRA186_RESET_SDMMC1>; resets = <&bpmp TEGRA186_RESET_SDMMC1>;
reset-names = "sdhci"; reset-names = "sdhci";
interconnects = <&mc TEGRA186_MEMORY_CLIENT_SDMMCRA &emc>, interconnects = <&mc TEGRA186_MEMORY_CLIENT_SDMMCRA &emc>,
...@@ -366,8 +367,9 @@ sdmmc2: mmc@3420000 { ...@@ -366,8 +367,9 @@ sdmmc2: mmc@3420000 {
compatible = "nvidia,tegra186-sdhci"; compatible = "nvidia,tegra186-sdhci";
reg = <0x0 0x03420000 0x0 0x10000>; reg = <0x0 0x03420000 0x0 0x10000>;
interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&bpmp TEGRA186_CLK_SDMMC2>; clocks = <&bpmp TEGRA186_CLK_SDMMC2>,
clock-names = "sdhci"; <&bpmp TEGRA186_CLK_SDMMC_LEGACY_TM>;
clock-names = "sdhci", "tmclk";
resets = <&bpmp TEGRA186_RESET_SDMMC2>; resets = <&bpmp TEGRA186_RESET_SDMMC2>;
reset-names = "sdhci"; reset-names = "sdhci";
interconnects = <&mc TEGRA186_MEMORY_CLIENT_SDMMCRAA &emc>, interconnects = <&mc TEGRA186_MEMORY_CLIENT_SDMMCRAA &emc>,
...@@ -390,8 +392,9 @@ sdmmc3: mmc@3440000 { ...@@ -390,8 +392,9 @@ sdmmc3: mmc@3440000 {
compatible = "nvidia,tegra186-sdhci"; compatible = "nvidia,tegra186-sdhci";
reg = <0x0 0x03440000 0x0 0x10000>; reg = <0x0 0x03440000 0x0 0x10000>;
interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&bpmp TEGRA186_CLK_SDMMC3>; clocks = <&bpmp TEGRA186_CLK_SDMMC3>,
clock-names = "sdhci"; <&bpmp TEGRA186_CLK_SDMMC_LEGACY_TM>;
clock-names = "sdhci", "tmclk";
resets = <&bpmp TEGRA186_RESET_SDMMC3>; resets = <&bpmp TEGRA186_RESET_SDMMC3>;
reset-names = "sdhci"; reset-names = "sdhci";
interconnects = <&mc TEGRA186_MEMORY_CLIENT_SDMMCR &emc>, interconnects = <&mc TEGRA186_MEMORY_CLIENT_SDMMCR &emc>,
...@@ -416,8 +419,9 @@ sdmmc4: mmc@3460000 { ...@@ -416,8 +419,9 @@ sdmmc4: mmc@3460000 {
compatible = "nvidia,tegra186-sdhci"; compatible = "nvidia,tegra186-sdhci";
reg = <0x0 0x03460000 0x0 0x10000>; reg = <0x0 0x03460000 0x0 0x10000>;
interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&bpmp TEGRA186_CLK_SDMMC4>; clocks = <&bpmp TEGRA186_CLK_SDMMC4>,
clock-names = "sdhci"; <&bpmp TEGRA186_CLK_SDMMC_LEGACY_TM>;
clock-names = "sdhci", "tmclk";
assigned-clocks = <&bpmp TEGRA186_CLK_SDMMC4>, assigned-clocks = <&bpmp TEGRA186_CLK_SDMMC4>,
<&bpmp TEGRA186_CLK_PLLC4_VCO>; <&bpmp TEGRA186_CLK_PLLC4_VCO>;
assigned-clock-parents = <&bpmp TEGRA186_CLK_PLLC4_VCO>; assigned-clock-parents = <&bpmp TEGRA186_CLK_PLLC4_VCO>;
......
...@@ -460,8 +460,9 @@ sdmmc1: mmc@3400000 { ...@@ -460,8 +460,9 @@ sdmmc1: mmc@3400000 {
compatible = "nvidia,tegra194-sdhci"; compatible = "nvidia,tegra194-sdhci";
reg = <0x03400000 0x10000>; reg = <0x03400000 0x10000>;
interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&bpmp TEGRA194_CLK_SDMMC1>; clocks = <&bpmp TEGRA194_CLK_SDMMC1>,
clock-names = "sdhci"; <&bpmp TEGRA194_CLK_SDMMC_LEGACY_TM>;
clock-names = "sdhci", "tmclk";
resets = <&bpmp TEGRA194_RESET_SDMMC1>; resets = <&bpmp TEGRA194_RESET_SDMMC1>;
reset-names = "sdhci"; reset-names = "sdhci";
interconnects = <&mc TEGRA194_MEMORY_CLIENT_SDMMCRA &emc>, interconnects = <&mc TEGRA194_MEMORY_CLIENT_SDMMCRA &emc>,
...@@ -485,8 +486,9 @@ sdmmc3: mmc@3440000 { ...@@ -485,8 +486,9 @@ sdmmc3: mmc@3440000 {
compatible = "nvidia,tegra194-sdhci"; compatible = "nvidia,tegra194-sdhci";
reg = <0x03440000 0x10000>; reg = <0x03440000 0x10000>;
interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&bpmp TEGRA194_CLK_SDMMC3>; clocks = <&bpmp TEGRA194_CLK_SDMMC3>,
clock-names = "sdhci"; <&bpmp TEGRA194_CLK_SDMMC_LEGACY_TM>;
clock-names = "sdhci", "tmclk";
resets = <&bpmp TEGRA194_RESET_SDMMC3>; resets = <&bpmp TEGRA194_RESET_SDMMC3>;
reset-names = "sdhci"; reset-names = "sdhci";
interconnects = <&mc TEGRA194_MEMORY_CLIENT_SDMMCR &emc>, interconnects = <&mc TEGRA194_MEMORY_CLIENT_SDMMCR &emc>,
...@@ -511,8 +513,9 @@ sdmmc4: mmc@3460000 { ...@@ -511,8 +513,9 @@ sdmmc4: mmc@3460000 {
compatible = "nvidia,tegra194-sdhci"; compatible = "nvidia,tegra194-sdhci";
reg = <0x03460000 0x10000>; reg = <0x03460000 0x10000>;
interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&bpmp TEGRA194_CLK_SDMMC4>; clocks = <&bpmp TEGRA194_CLK_SDMMC4>,
clock-names = "sdhci"; <&bpmp TEGRA194_CLK_SDMMC_LEGACY_TM>;
clock-names = "sdhci", "tmclk";
assigned-clocks = <&bpmp TEGRA194_CLK_SDMMC4>, assigned-clocks = <&bpmp TEGRA194_CLK_SDMMC4>,
<&bpmp TEGRA194_CLK_PLLC4>; <&bpmp TEGRA194_CLK_PLLC4>;
assigned-clock-parents = assigned-clock-parents =
......
...@@ -1194,8 +1194,9 @@ mmc@700b0000 { ...@@ -1194,8 +1194,9 @@ mmc@700b0000 {
compatible = "nvidia,tegra210-sdhci"; compatible = "nvidia,tegra210-sdhci";
reg = <0x0 0x700b0000 0x0 0x200>; reg = <0x0 0x700b0000 0x0 0x200>;
interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA210_CLK_SDMMC1>; clocks = <&tegra_car TEGRA210_CLK_SDMMC1>,
clock-names = "sdhci"; <&tegra_car TEGRA210_CLK_SDMMC_LEGACY>;
clock-names = "sdhci", "tmclk";
resets = <&tegra_car 14>; resets = <&tegra_car 14>;
reset-names = "sdhci"; reset-names = "sdhci";
pinctrl-names = "sdmmc-3v3", "sdmmc-1v8", pinctrl-names = "sdmmc-3v3", "sdmmc-1v8",
...@@ -1222,8 +1223,9 @@ mmc@700b0200 { ...@@ -1222,8 +1223,9 @@ mmc@700b0200 {
compatible = "nvidia,tegra210-sdhci"; compatible = "nvidia,tegra210-sdhci";
reg = <0x0 0x700b0200 0x0 0x200>; reg = <0x0 0x700b0200 0x0 0x200>;
interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA210_CLK_SDMMC2>; clocks = <&tegra_car TEGRA210_CLK_SDMMC2>,
clock-names = "sdhci"; <&tegra_car TEGRA210_CLK_SDMMC_LEGACY>;
clock-names = "sdhci", "tmclk";
resets = <&tegra_car 9>; resets = <&tegra_car 9>;
reset-names = "sdhci"; reset-names = "sdhci";
pinctrl-names = "sdmmc-1v8-drv"; pinctrl-names = "sdmmc-1v8-drv";
...@@ -1239,8 +1241,9 @@ mmc@700b0400 { ...@@ -1239,8 +1241,9 @@ mmc@700b0400 {
compatible = "nvidia,tegra210-sdhci"; compatible = "nvidia,tegra210-sdhci";
reg = <0x0 0x700b0400 0x0 0x200>; reg = <0x0 0x700b0400 0x0 0x200>;
interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA210_CLK_SDMMC3>; clocks = <&tegra_car TEGRA210_CLK_SDMMC3>,
clock-names = "sdhci"; <&tegra_car TEGRA210_CLK_SDMMC_LEGACY>;
clock-names = "sdhci", "tmclk";
resets = <&tegra_car 69>; resets = <&tegra_car 69>;
reset-names = "sdhci"; reset-names = "sdhci";
pinctrl-names = "sdmmc-3v3", "sdmmc-1v8", pinctrl-names = "sdmmc-3v3", "sdmmc-1v8",
...@@ -1262,8 +1265,9 @@ mmc@700b0600 { ...@@ -1262,8 +1265,9 @@ mmc@700b0600 {
compatible = "nvidia,tegra210-sdhci"; compatible = "nvidia,tegra210-sdhci";
reg = <0x0 0x700b0600 0x0 0x200>; reg = <0x0 0x700b0600 0x0 0x200>;
interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA210_CLK_SDMMC4>; clocks = <&tegra_car TEGRA210_CLK_SDMMC4>,
clock-names = "sdhci"; <&tegra_car TEGRA210_CLK_SDMMC_LEGACY>;
clock-names = "sdhci", "tmclk";
resets = <&tegra_car 15>; resets = <&tegra_car 15>;
reset-names = "sdhci"; reset-names = "sdhci";
pinctrl-names = "sdmmc-3v3-drv", "sdmmc-1v8-drv"; pinctrl-names = "sdmmc-3v3-drv", "sdmmc-1v8-drv";
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/reset.h>
#include <linux/mmc/card.h> #include <linux/mmc/card.h>
#include <linux/mmc/core.h> #include <linux/mmc/core.h>
...@@ -419,6 +420,7 @@ struct msdc_host { ...@@ -419,6 +420,7 @@ struct msdc_host {
struct pinctrl_state *pins_uhs; struct pinctrl_state *pins_uhs;
struct delayed_work req_timeout; struct delayed_work req_timeout;
int irq; /* host interrupt */ int irq; /* host interrupt */
struct reset_control *reset;
struct clk *src_clk; /* msdc source clock */ struct clk *src_clk; /* msdc source clock */
struct clk *h_clk; /* msdc h_clk */ struct clk *h_clk; /* msdc h_clk */
...@@ -1592,6 +1594,12 @@ static void msdc_init_hw(struct msdc_host *host) ...@@ -1592,6 +1594,12 @@ static void msdc_init_hw(struct msdc_host *host)
u32 val; u32 val;
u32 tune_reg = host->dev_comp->pad_tune_reg; u32 tune_reg = host->dev_comp->pad_tune_reg;
if (host->reset) {
reset_control_assert(host->reset);
usleep_range(10, 50);
reset_control_deassert(host->reset);
}
/* Configure to MMC/SD mode, clock free running */ /* Configure to MMC/SD mode, clock free running */
sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_MODE | MSDC_CFG_CKPDN); sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_MODE | MSDC_CFG_CKPDN);
...@@ -2390,6 +2398,11 @@ static int msdc_drv_probe(struct platform_device *pdev) ...@@ -2390,6 +2398,11 @@ static int msdc_drv_probe(struct platform_device *pdev)
if (IS_ERR(host->src_clk_cg)) if (IS_ERR(host->src_clk_cg))
host->src_clk_cg = NULL; host->src_clk_cg = NULL;
host->reset = devm_reset_control_get_optional_exclusive(&pdev->dev,
"hrst");
if (IS_ERR(host->reset))
return PTR_ERR(host->reset);
host->irq = platform_get_irq(pdev, 0); host->irq = platform_get_irq(pdev, 0);
if (host->irq < 0) { if (host->irq < 0) {
ret = -EINVAL; ret = -EINVAL;
......
...@@ -535,6 +535,11 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_qcom_sd = { ...@@ -535,6 +535,11 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_qcom_sd = {
.caps = MMC_CAP_NONREMOVABLE, .caps = MMC_CAP_NONREMOVABLE,
}; };
struct amd_sdhci_host {
bool tuned_clock;
bool dll_enabled;
};
/* AMD sdhci reset dll register. */ /* AMD sdhci reset dll register. */
#define SDHCI_AMD_RESET_DLL_REGISTER 0x908 #define SDHCI_AMD_RESET_DLL_REGISTER 0x908
...@@ -555,26 +560,66 @@ static void sdhci_acpi_amd_hs400_dll(struct sdhci_host *host) ...@@ -555,26 +560,66 @@ static void sdhci_acpi_amd_hs400_dll(struct sdhci_host *host)
} }
/* /*
* For AMD Platform it is required to disable the tuning * The initialization sequence for HS400 is:
* bit first controller to bring to HS Mode from HS200 * HS->HS200->Perform Tuning->HS->HS400
* mode, later enable to tune to HS400 mode. *
* The re-tuning sequence is:
* HS400->DDR52->HS->HS200->Perform Tuning->HS->HS400
*
* The AMD eMMC Controller can only use the tuned clock while in HS200 and HS400
* mode. If we switch to a different mode, we need to disable the tuned clock.
* If we have previously performed tuning and switch back to HS200 or
* HS400, we can re-enable the tuned clock.
*
*/ */
static void amd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) static void amd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{ {
struct sdhci_host *host = mmc_priv(mmc); struct sdhci_host *host = mmc_priv(mmc);
struct sdhci_acpi_host *acpi_host = sdhci_priv(host);
struct amd_sdhci_host *amd_host = sdhci_acpi_priv(acpi_host);
unsigned int old_timing = host->timing; unsigned int old_timing = host->timing;
u16 val;
sdhci_set_ios(mmc, ios); sdhci_set_ios(mmc, ios);
if (old_timing == MMC_TIMING_MMC_HS200 &&
ios->timing == MMC_TIMING_MMC_HS) if (old_timing != host->timing && amd_host->tuned_clock) {
sdhci_writew(host, 0x9, SDHCI_HOST_CONTROL2); if (host->timing == MMC_TIMING_MMC_HS400 ||
if (old_timing != MMC_TIMING_MMC_HS400 && host->timing == MMC_TIMING_MMC_HS200) {
ios->timing == MMC_TIMING_MMC_HS400) { val = sdhci_readw(host, SDHCI_HOST_CONTROL2);
sdhci_writew(host, 0x80, SDHCI_HOST_CONTROL2); val |= SDHCI_CTRL_TUNED_CLK;
sdhci_writew(host, val, SDHCI_HOST_CONTROL2);
} else {
val = sdhci_readw(host, SDHCI_HOST_CONTROL2);
val &= ~SDHCI_CTRL_TUNED_CLK;
sdhci_writew(host, val, SDHCI_HOST_CONTROL2);
}
/* DLL is only required for HS400 */
if (host->timing == MMC_TIMING_MMC_HS400 &&
!amd_host->dll_enabled) {
sdhci_acpi_amd_hs400_dll(host); sdhci_acpi_amd_hs400_dll(host);
amd_host->dll_enabled = true;
}
} }
} }
static int amd_sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
{
int err;
struct sdhci_host *host = mmc_priv(mmc);
struct sdhci_acpi_host *acpi_host = sdhci_priv(host);
struct amd_sdhci_host *amd_host = sdhci_acpi_priv(acpi_host);
amd_host->tuned_clock = false;
err = sdhci_execute_tuning(mmc, opcode);
if (!err && !host->tuning_err)
amd_host->tuned_clock = true;
return err;
}
static const struct sdhci_ops sdhci_acpi_ops_amd = { static const struct sdhci_ops sdhci_acpi_ops_amd = {
.set_clock = sdhci_set_clock, .set_clock = sdhci_set_clock,
.set_bus_width = sdhci_set_bus_width, .set_bus_width = sdhci_set_bus_width,
...@@ -602,6 +647,7 @@ static int sdhci_acpi_emmc_amd_probe_slot(struct platform_device *pdev, ...@@ -602,6 +647,7 @@ static int sdhci_acpi_emmc_amd_probe_slot(struct platform_device *pdev,
host->mmc_host_ops.select_drive_strength = amd_select_drive_strength; host->mmc_host_ops.select_drive_strength = amd_select_drive_strength;
host->mmc_host_ops.set_ios = amd_set_ios; host->mmc_host_ops.set_ios = amd_set_ios;
host->mmc_host_ops.execute_tuning = amd_sdhci_execute_tuning;
return 0; return 0;
} }
...@@ -613,6 +659,7 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_amd_emmc = { ...@@ -613,6 +659,7 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_amd_emmc = {
SDHCI_QUIRK_32BIT_ADMA_SIZE, SDHCI_QUIRK_32BIT_ADMA_SIZE,
.quirks2 = SDHCI_QUIRK2_BROKEN_64_BIT_DMA, .quirks2 = SDHCI_QUIRK2_BROKEN_64_BIT_DMA,
.probe_slot = sdhci_acpi_emmc_amd_probe_slot, .probe_slot = sdhci_acpi_emmc_amd_probe_slot,
.priv_size = sizeof(struct amd_sdhci_host),
}; };
struct sdhci_acpi_uid_slot { struct sdhci_acpi_uid_slot {
......
...@@ -232,6 +232,14 @@ static void sdhci_pci_dumpregs(struct mmc_host *mmc) ...@@ -232,6 +232,14 @@ static void sdhci_pci_dumpregs(struct mmc_host *mmc)
sdhci_dumpregs(mmc_priv(mmc)); sdhci_dumpregs(mmc_priv(mmc));
} }
static void sdhci_cqhci_reset(struct sdhci_host *host, u8 mask)
{
if ((host->mmc->caps2 & MMC_CAP2_CQE) && (mask & SDHCI_RESET_ALL) &&
host->mmc->cqe_private)
cqhci_deactivate(host->mmc);
sdhci_reset(host, mask);
}
/*****************************************************************************\ /*****************************************************************************\
* * * *
* Hardware specific quirk handling * * Hardware specific quirk handling *
...@@ -718,7 +726,7 @@ static const struct sdhci_ops sdhci_intel_glk_ops = { ...@@ -718,7 +726,7 @@ static const struct sdhci_ops sdhci_intel_glk_ops = {
.set_power = sdhci_intel_set_power, .set_power = sdhci_intel_set_power,
.enable_dma = sdhci_pci_enable_dma, .enable_dma = sdhci_pci_enable_dma,
.set_bus_width = sdhci_set_bus_width, .set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset, .reset = sdhci_cqhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling, .set_uhs_signaling = sdhci_set_uhs_signaling,
.hw_reset = sdhci_pci_hw_reset, .hw_reset = sdhci_pci_hw_reset,
.irq = sdhci_cqhci_irq, .irq = sdhci_cqhci_irq,
......
...@@ -110,6 +110,12 @@ ...@@ -110,6 +110,12 @@
#define NVQUIRK_DIS_CARD_CLK_CONFIG_TAP BIT(8) #define NVQUIRK_DIS_CARD_CLK_CONFIG_TAP BIT(8)
#define NVQUIRK_CQHCI_DCMD_R1B_CMD_TIMING BIT(9) #define NVQUIRK_CQHCI_DCMD_R1B_CMD_TIMING BIT(9)
/*
* NVQUIRK_HAS_TMCLK is for SoC's having separate timeout clock for Tegra
* SDMMC hardware data timeout.
*/
#define NVQUIRK_HAS_TMCLK BIT(10)
/* SDMMC CQE Base Address for Tegra Host Ver 4.1 and Higher */ /* SDMMC CQE Base Address for Tegra Host Ver 4.1 and Higher */
#define SDHCI_TEGRA_CQE_BASE_ADDR 0xF000 #define SDHCI_TEGRA_CQE_BASE_ADDR 0xF000
...@@ -140,6 +146,7 @@ struct sdhci_tegra_autocal_offsets { ...@@ -140,6 +146,7 @@ struct sdhci_tegra_autocal_offsets {
struct sdhci_tegra { struct sdhci_tegra {
const struct sdhci_tegra_soc_data *soc_data; const struct sdhci_tegra_soc_data *soc_data;
struct gpio_desc *power_gpio; struct gpio_desc *power_gpio;
struct clk *tmclk;
bool ddr_signaling; bool ddr_signaling;
bool pad_calib_required; bool pad_calib_required;
bool pad_control_available; bool pad_control_available;
...@@ -1418,7 +1425,6 @@ static const struct sdhci_ops tegra210_sdhci_ops = { ...@@ -1418,7 +1425,6 @@ static const struct sdhci_ops tegra210_sdhci_ops = {
static const struct sdhci_pltfm_data sdhci_tegra210_pdata = { static const struct sdhci_pltfm_data sdhci_tegra210_pdata = {
.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
SDHCI_QUIRK_SINGLE_POWER_WRITE | SDHCI_QUIRK_SINGLE_POWER_WRITE |
SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_NO_HISPD_BIT |
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
...@@ -1434,7 +1440,8 @@ static const struct sdhci_tegra_soc_data soc_data_tegra210 = { ...@@ -1434,7 +1440,8 @@ static const struct sdhci_tegra_soc_data soc_data_tegra210 = {
NVQUIRK_HAS_PADCALIB | NVQUIRK_HAS_PADCALIB |
NVQUIRK_DIS_CARD_CLK_CONFIG_TAP | NVQUIRK_DIS_CARD_CLK_CONFIG_TAP |
NVQUIRK_ENABLE_SDR50 | NVQUIRK_ENABLE_SDR50 |
NVQUIRK_ENABLE_SDR104, NVQUIRK_ENABLE_SDR104 |
NVQUIRK_HAS_TMCLK,
.min_tap_delay = 106, .min_tap_delay = 106,
.max_tap_delay = 185, .max_tap_delay = 185,
}; };
...@@ -1456,7 +1463,6 @@ static const struct sdhci_ops tegra186_sdhci_ops = { ...@@ -1456,7 +1463,6 @@ static const struct sdhci_ops tegra186_sdhci_ops = {
static const struct sdhci_pltfm_data sdhci_tegra186_pdata = { static const struct sdhci_pltfm_data sdhci_tegra186_pdata = {
.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
SDHCI_QUIRK_SINGLE_POWER_WRITE | SDHCI_QUIRK_SINGLE_POWER_WRITE |
SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_NO_HISPD_BIT |
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
...@@ -1473,6 +1479,7 @@ static const struct sdhci_tegra_soc_data soc_data_tegra186 = { ...@@ -1473,6 +1479,7 @@ static const struct sdhci_tegra_soc_data soc_data_tegra186 = {
NVQUIRK_DIS_CARD_CLK_CONFIG_TAP | NVQUIRK_DIS_CARD_CLK_CONFIG_TAP |
NVQUIRK_ENABLE_SDR50 | NVQUIRK_ENABLE_SDR50 |
NVQUIRK_ENABLE_SDR104 | NVQUIRK_ENABLE_SDR104 |
NVQUIRK_HAS_TMCLK |
NVQUIRK_CQHCI_DCMD_R1B_CMD_TIMING, NVQUIRK_CQHCI_DCMD_R1B_CMD_TIMING,
.min_tap_delay = 84, .min_tap_delay = 84,
.max_tap_delay = 136, .max_tap_delay = 136,
...@@ -1485,7 +1492,8 @@ static const struct sdhci_tegra_soc_data soc_data_tegra194 = { ...@@ -1485,7 +1492,8 @@ static const struct sdhci_tegra_soc_data soc_data_tegra194 = {
NVQUIRK_HAS_PADCALIB | NVQUIRK_HAS_PADCALIB |
NVQUIRK_DIS_CARD_CLK_CONFIG_TAP | NVQUIRK_DIS_CARD_CLK_CONFIG_TAP |
NVQUIRK_ENABLE_SDR50 | NVQUIRK_ENABLE_SDR50 |
NVQUIRK_ENABLE_SDR104, NVQUIRK_ENABLE_SDR104 |
NVQUIRK_HAS_TMCLK,
.min_tap_delay = 96, .min_tap_delay = 96,
.max_tap_delay = 139, .max_tap_delay = 139,
}; };
...@@ -1613,6 +1621,43 @@ static int sdhci_tegra_probe(struct platform_device *pdev) ...@@ -1613,6 +1621,43 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
goto err_power_req; goto err_power_req;
} }
/*
* Tegra210 has a separate SDMMC_LEGACY_TM clock used for host
* timeout clock and SW can choose TMCLK or SDCLK for hardware
* data timeout through the bit USE_TMCLK_FOR_DATA_TIMEOUT of
* the register SDHCI_TEGRA_VENDOR_SYS_SW_CTRL.
*
* USE_TMCLK_FOR_DATA_TIMEOUT bit default is set to 1 and SDMMC uses
* 12Mhz TMCLK which is advertised in host capability register.
* With TMCLK of 12Mhz provides maximum data timeout period that can
* be achieved is 11s better than using SDCLK for data timeout.
*
* So, TMCLK is set to 12Mhz and kept enabled all the time on SoC's
* supporting separate TMCLK.
*/
if (soc_data->nvquirks & NVQUIRK_HAS_TMCLK) {
clk = devm_clk_get(&pdev->dev, "tmclk");
if (IS_ERR(clk)) {
rc = PTR_ERR(clk);
if (rc == -EPROBE_DEFER)
goto err_power_req;
dev_warn(&pdev->dev, "failed to get tmclk: %d\n", rc);
clk = NULL;
}
clk_set_rate(clk, 12000000);
rc = clk_prepare_enable(clk);
if (rc) {
dev_err(&pdev->dev,
"failed to enable tmclk: %d\n", rc);
goto err_power_req;
}
tegra_host->tmclk = clk;
}
clk = devm_clk_get(mmc_dev(host->mmc), NULL); clk = devm_clk_get(mmc_dev(host->mmc), NULL);
if (IS_ERR(clk)) { if (IS_ERR(clk)) {
rc = PTR_ERR(clk); rc = PTR_ERR(clk);
...@@ -1656,6 +1701,7 @@ static int sdhci_tegra_probe(struct platform_device *pdev) ...@@ -1656,6 +1701,7 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
err_rst_get: err_rst_get:
clk_disable_unprepare(pltfm_host->clk); clk_disable_unprepare(pltfm_host->clk);
err_clk_get: err_clk_get:
clk_disable_unprepare(tegra_host->tmclk);
err_power_req: err_power_req:
err_parse_dt: err_parse_dt:
sdhci_pltfm_free(pdev); sdhci_pltfm_free(pdev);
...@@ -1673,6 +1719,7 @@ static int sdhci_tegra_remove(struct platform_device *pdev) ...@@ -1673,6 +1719,7 @@ static int sdhci_tegra_remove(struct platform_device *pdev)
reset_control_assert(tegra_host->rst); reset_control_assert(tegra_host->rst);
usleep_range(2000, 4000); usleep_range(2000, 4000);
clk_disable_unprepare(pltfm_host->clk); clk_disable_unprepare(pltfm_host->clk);
clk_disable_unprepare(tegra_host->tmclk);
sdhci_pltfm_free(pdev); sdhci_pltfm_free(pdev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment