MMC host:

- sdhci-acpi: Fix HS400 tuning for AMDI0040
  - sdhci-pci: Fix reset of CQHCI for Intel GLK-based controllers
  - sdhci-tegra: Use correct timeout clock for Tegra186/194/210
  - mtk-sd: Fix eMMC mounting on mt7622/Bpi-64
 -----BEGIN PGP SIGNATURE-----
 
 iQJLBAABCgA1FiEEugLDXPmKSktSkQsV/iaEJXNYjCkFAl9M2g4XHHVsZi5oYW5z
 c29uQGxpbmFyby5vcmcACgkQ/iaEJXNYjCkmBA//YUe2Wx6bFAEawUI0AxUxPLXO
 6zXgwKiJgCLbgdICSbhzS/I4N8iTyT+tiRUyk78UukgKOfDH/yIkeNenqf+gWINq
 lWDJGqboj9Hn1Cm0D2qSTqPs2AJL0k6WhBFBUFvtSYtqqk/j0VVRkrpRqb96X2MK
 bGXnv0hTTed8uX/VtjHTzmj+8CMtVmHzzlC0eALYLJpNOklmbn3agDpXbpGbIDsk
 5oaTqLmRRROcvxQDes/y5HnckdQ9q13LHEiI10BSIFG6qDQ4t8KsoJGdGgola3Hq
 +oD6R/WcikM+dwuAB8jNmnSpsot6vltg2czdQ+y18RtccPpwPzpRrICFBKoayPDu
 QXG/5cd6kgS+XX/25eF5GrkR66ztEjckQm1aOgpx3yfPZJLuXhy3Rkt1DGUa+HOT
 rVaz3dngUJapO/pCl8Oy89e59zBd9yDsUVAmmUFchIiI2dthn7UReEaP7wnSc5uh
 5pK+GZfBSXK3h1E5ky7QwEY2DJ8LmqqkdyCCZHeQUPoS7lemVWH47BbuJ/zmnNoW
 VyBd+BwmW3RCn4XwpjqsOp2Ppb8MeLpPBD6m+1vd7J9eNdhgClQfpnldOzVmzG8E
 4baveGrPRIGQPXoXRAOjZfd/bTx7TfteT3vIZCH+pwkTItw0x2xi1NLwjOGXPDDE
 YLhYfGFfNFPX206UiRw=
 =rYDw
 -----END PGP SIGNATURE-----

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
This commit is contained in:
Linus Torvalds 2020-08-31 11:22:57 -07:00
commit 59815d6d1c
11 changed files with 203 additions and 43 deletions

View File

@ -30,9 +30,13 @@ allOf:
then:
properties:
clock-output-names:
items:
- const: clk_out_sd0
- const: clk_in_sd0
oneOf:
- items:
- const: clk_out_sd0
- const: clk_in_sd0
- items:
- const: clk_out_sd1
- const: clk_in_sd1
properties:
compatible:

View File

@ -50,6 +50,8 @@ Optional properties:
error caused by stop clock(fifo full)
Valid range = [0:0x7]. if not present, default value is 0.
applied to compatible "mediatek,mt2701-mmc".
- resets: Phandle and reset specifier pair to softreset line of MSDC IP.
- reset-names: Should be "hrst".
Examples:
mmc0: mmc@11230000 {

View File

@ -15,8 +15,15 @@ Required properties:
- "nvidia,tegra210-sdhci": for Tegra210
- "nvidia,tegra186-sdhci": for Tegra186
- "nvidia,tegra194-sdhci": for Tegra194
- clocks : Must contain one entry, for the module clock.
See ../clocks/clock-bindings.txt for details.
- clocks: For Tegra210, Tegra186 and Tegra194 must contain two entries.
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.
See ../reset/reset.txt for details.
- reset-names : Must include the following entries:
@ -99,7 +106,7 @@ Optional properties for Tegra210, Tegra186 and Tegra194:
Example:
sdhci@700b0000 {
compatible = "nvidia,tegra210-sdhci", "nvidia,tegra124-sdhci";
compatible = "nvidia,tegra124-sdhci";
reg = <0x0 0x700b0000 0x0 0x200>;
interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA210_CLK_SDMMC1>;
@ -115,3 +122,22 @@ sdhci@700b0000 {
nvidia,pad-autocal-pull-down-offset-1v8 = <0x7b>;
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";
};

View File

@ -686,6 +686,8 @@
clocks = <&pericfg CLK_PERI_MSDC30_0_PD>,
<&topckgen CLK_TOP_MSDC50_0_SEL>;
clock-names = "source", "hclk";
resets = <&pericfg MT7622_PERI_MSDC0_SW_RST>;
reset-names = "hrst";
status = "disabled";
};

View File

@ -337,8 +337,9 @@
compatible = "nvidia,tegra186-sdhci";
reg = <0x0 0x03400000 0x0 0x10000>;
interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&bpmp TEGRA186_CLK_SDMMC1>;
clock-names = "sdhci";
clocks = <&bpmp TEGRA186_CLK_SDMMC1>,
<&bpmp TEGRA186_CLK_SDMMC_LEGACY_TM>;
clock-names = "sdhci", "tmclk";
resets = <&bpmp TEGRA186_RESET_SDMMC1>;
reset-names = "sdhci";
interconnects = <&mc TEGRA186_MEMORY_CLIENT_SDMMCRA &emc>,
@ -366,8 +367,9 @@
compatible = "nvidia,tegra186-sdhci";
reg = <0x0 0x03420000 0x0 0x10000>;
interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&bpmp TEGRA186_CLK_SDMMC2>;
clock-names = "sdhci";
clocks = <&bpmp TEGRA186_CLK_SDMMC2>,
<&bpmp TEGRA186_CLK_SDMMC_LEGACY_TM>;
clock-names = "sdhci", "tmclk";
resets = <&bpmp TEGRA186_RESET_SDMMC2>;
reset-names = "sdhci";
interconnects = <&mc TEGRA186_MEMORY_CLIENT_SDMMCRAA &emc>,
@ -390,8 +392,9 @@
compatible = "nvidia,tegra186-sdhci";
reg = <0x0 0x03440000 0x0 0x10000>;
interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&bpmp TEGRA186_CLK_SDMMC3>;
clock-names = "sdhci";
clocks = <&bpmp TEGRA186_CLK_SDMMC3>,
<&bpmp TEGRA186_CLK_SDMMC_LEGACY_TM>;
clock-names = "sdhci", "tmclk";
resets = <&bpmp TEGRA186_RESET_SDMMC3>;
reset-names = "sdhci";
interconnects = <&mc TEGRA186_MEMORY_CLIENT_SDMMCR &emc>,
@ -416,8 +419,9 @@
compatible = "nvidia,tegra186-sdhci";
reg = <0x0 0x03460000 0x0 0x10000>;
interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&bpmp TEGRA186_CLK_SDMMC4>;
clock-names = "sdhci";
clocks = <&bpmp TEGRA186_CLK_SDMMC4>,
<&bpmp TEGRA186_CLK_SDMMC_LEGACY_TM>;
clock-names = "sdhci", "tmclk";
assigned-clocks = <&bpmp TEGRA186_CLK_SDMMC4>,
<&bpmp TEGRA186_CLK_PLLC4_VCO>;
assigned-clock-parents = <&bpmp TEGRA186_CLK_PLLC4_VCO>;

View File

@ -460,8 +460,9 @@
compatible = "nvidia,tegra194-sdhci";
reg = <0x03400000 0x10000>;
interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&bpmp TEGRA194_CLK_SDMMC1>;
clock-names = "sdhci";
clocks = <&bpmp TEGRA194_CLK_SDMMC1>,
<&bpmp TEGRA194_CLK_SDMMC_LEGACY_TM>;
clock-names = "sdhci", "tmclk";
resets = <&bpmp TEGRA194_RESET_SDMMC1>;
reset-names = "sdhci";
interconnects = <&mc TEGRA194_MEMORY_CLIENT_SDMMCRA &emc>,
@ -485,8 +486,9 @@
compatible = "nvidia,tegra194-sdhci";
reg = <0x03440000 0x10000>;
interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&bpmp TEGRA194_CLK_SDMMC3>;
clock-names = "sdhci";
clocks = <&bpmp TEGRA194_CLK_SDMMC3>,
<&bpmp TEGRA194_CLK_SDMMC_LEGACY_TM>;
clock-names = "sdhci", "tmclk";
resets = <&bpmp TEGRA194_RESET_SDMMC3>;
reset-names = "sdhci";
interconnects = <&mc TEGRA194_MEMORY_CLIENT_SDMMCR &emc>,
@ -511,8 +513,9 @@
compatible = "nvidia,tegra194-sdhci";
reg = <0x03460000 0x10000>;
interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&bpmp TEGRA194_CLK_SDMMC4>;
clock-names = "sdhci";
clocks = <&bpmp TEGRA194_CLK_SDMMC4>,
<&bpmp TEGRA194_CLK_SDMMC_LEGACY_TM>;
clock-names = "sdhci", "tmclk";
assigned-clocks = <&bpmp TEGRA194_CLK_SDMMC4>,
<&bpmp TEGRA194_CLK_PLLC4>;
assigned-clock-parents =

View File

@ -1194,8 +1194,9 @@
compatible = "nvidia,tegra210-sdhci";
reg = <0x0 0x700b0000 0x0 0x200>;
interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA210_CLK_SDMMC1>;
clock-names = "sdhci";
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",
@ -1222,8 +1223,9 @@
compatible = "nvidia,tegra210-sdhci";
reg = <0x0 0x700b0200 0x0 0x200>;
interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA210_CLK_SDMMC2>;
clock-names = "sdhci";
clocks = <&tegra_car TEGRA210_CLK_SDMMC2>,
<&tegra_car TEGRA210_CLK_SDMMC_LEGACY>;
clock-names = "sdhci", "tmclk";
resets = <&tegra_car 9>;
reset-names = "sdhci";
pinctrl-names = "sdmmc-1v8-drv";
@ -1239,8 +1241,9 @@
compatible = "nvidia,tegra210-sdhci";
reg = <0x0 0x700b0400 0x0 0x200>;
interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA210_CLK_SDMMC3>;
clock-names = "sdhci";
clocks = <&tegra_car TEGRA210_CLK_SDMMC3>,
<&tegra_car TEGRA210_CLK_SDMMC_LEGACY>;
clock-names = "sdhci", "tmclk";
resets = <&tegra_car 69>;
reset-names = "sdhci";
pinctrl-names = "sdmmc-3v3", "sdmmc-1v8",
@ -1262,8 +1265,9 @@
compatible = "nvidia,tegra210-sdhci";
reg = <0x0 0x700b0600 0x0 0x200>;
interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA210_CLK_SDMMC4>;
clock-names = "sdhci";
clocks = <&tegra_car TEGRA210_CLK_SDMMC4>,
<&tegra_car TEGRA210_CLK_SDMMC_LEGACY>;
clock-names = "sdhci", "tmclk";
resets = <&tegra_car 15>;
reset-names = "sdhci";
pinctrl-names = "sdmmc-3v3-drv", "sdmmc-1v8-drv";

View File

@ -22,6 +22,7 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/reset.h>
#include <linux/mmc/card.h>
#include <linux/mmc/core.h>
@ -419,6 +420,7 @@ struct msdc_host {
struct pinctrl_state *pins_uhs;
struct delayed_work req_timeout;
int irq; /* host interrupt */
struct reset_control *reset;
struct clk *src_clk; /* msdc source clock */
struct clk *h_clk; /* msdc h_clk */
@ -1592,6 +1594,12 @@ static void msdc_init_hw(struct msdc_host *host)
u32 val;
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 */
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)
if (IS_ERR(host->src_clk_cg))
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);
if (host->irq < 0) {
ret = -EINVAL;

View File

@ -535,6 +535,11 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_qcom_sd = {
.caps = MMC_CAP_NONREMOVABLE,
};
struct amd_sdhci_host {
bool tuned_clock;
bool dll_enabled;
};
/* AMD sdhci reset dll register. */
#define SDHCI_AMD_RESET_DLL_REGISTER 0x908
@ -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
* bit first controller to bring to HS Mode from HS200
* mode, later enable to tune to HS400 mode.
* The initialization sequence for HS400 is:
* HS->HS200->Perform Tuning->HS->HS400
*
* 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)
{
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;
u16 val;
sdhci_set_ios(mmc, ios);
if (old_timing == MMC_TIMING_MMC_HS200 &&
ios->timing == MMC_TIMING_MMC_HS)
sdhci_writew(host, 0x9, SDHCI_HOST_CONTROL2);
if (old_timing != MMC_TIMING_MMC_HS400 &&
ios->timing == MMC_TIMING_MMC_HS400) {
sdhci_writew(host, 0x80, SDHCI_HOST_CONTROL2);
sdhci_acpi_amd_hs400_dll(host);
if (old_timing != host->timing && amd_host->tuned_clock) {
if (host->timing == MMC_TIMING_MMC_HS400 ||
host->timing == MMC_TIMING_MMC_HS200) {
val = sdhci_readw(host, 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);
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 = {
.set_clock = sdhci_set_clock,
.set_bus_width = sdhci_set_bus_width,
@ -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.set_ios = amd_set_ios;
host->mmc_host_ops.execute_tuning = amd_sdhci_execute_tuning;
return 0;
}
@ -613,6 +659,7 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_amd_emmc = {
SDHCI_QUIRK_32BIT_ADMA_SIZE,
.quirks2 = SDHCI_QUIRK2_BROKEN_64_BIT_DMA,
.probe_slot = sdhci_acpi_emmc_amd_probe_slot,
.priv_size = sizeof(struct amd_sdhci_host),
};
struct sdhci_acpi_uid_slot {

View File

@ -232,6 +232,14 @@ static void sdhci_pci_dumpregs(struct mmc_host *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 *
@ -718,7 +726,7 @@ static const struct sdhci_ops sdhci_intel_glk_ops = {
.set_power = sdhci_intel_set_power,
.enable_dma = sdhci_pci_enable_dma,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.reset = sdhci_cqhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
.hw_reset = sdhci_pci_hw_reset,
.irq = sdhci_cqhci_irq,

View File

@ -110,6 +110,12 @@
#define NVQUIRK_DIS_CARD_CLK_CONFIG_TAP BIT(8)
#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 */
#define SDHCI_TEGRA_CQE_BASE_ADDR 0xF000
@ -140,6 +146,7 @@ struct sdhci_tegra_autocal_offsets {
struct sdhci_tegra {
const struct sdhci_tegra_soc_data *soc_data;
struct gpio_desc *power_gpio;
struct clk *tmclk;
bool ddr_signaling;
bool pad_calib_required;
bool pad_control_available;
@ -1418,7 +1425,6 @@ static const struct sdhci_ops tegra210_sdhci_ops = {
static const struct sdhci_pltfm_data sdhci_tegra210_pdata = {
.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
SDHCI_QUIRK_SINGLE_POWER_WRITE |
SDHCI_QUIRK_NO_HISPD_BIT |
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
@ -1434,7 +1440,8 @@ static const struct sdhci_tegra_soc_data soc_data_tegra210 = {
NVQUIRK_HAS_PADCALIB |
NVQUIRK_DIS_CARD_CLK_CONFIG_TAP |
NVQUIRK_ENABLE_SDR50 |
NVQUIRK_ENABLE_SDR104,
NVQUIRK_ENABLE_SDR104 |
NVQUIRK_HAS_TMCLK,
.min_tap_delay = 106,
.max_tap_delay = 185,
};
@ -1456,7 +1463,6 @@ static const struct sdhci_ops tegra186_sdhci_ops = {
static const struct sdhci_pltfm_data sdhci_tegra186_pdata = {
.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
SDHCI_QUIRK_SINGLE_POWER_WRITE |
SDHCI_QUIRK_NO_HISPD_BIT |
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
@ -1473,6 +1479,7 @@ static const struct sdhci_tegra_soc_data soc_data_tegra186 = {
NVQUIRK_DIS_CARD_CLK_CONFIG_TAP |
NVQUIRK_ENABLE_SDR50 |
NVQUIRK_ENABLE_SDR104 |
NVQUIRK_HAS_TMCLK |
NVQUIRK_CQHCI_DCMD_R1B_CMD_TIMING,
.min_tap_delay = 84,
.max_tap_delay = 136,
@ -1485,7 +1492,8 @@ static const struct sdhci_tegra_soc_data soc_data_tegra194 = {
NVQUIRK_HAS_PADCALIB |
NVQUIRK_DIS_CARD_CLK_CONFIG_TAP |
NVQUIRK_ENABLE_SDR50 |
NVQUIRK_ENABLE_SDR104,
NVQUIRK_ENABLE_SDR104 |
NVQUIRK_HAS_TMCLK,
.min_tap_delay = 96,
.max_tap_delay = 139,
};
@ -1613,6 +1621,43 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
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);
if (IS_ERR(clk)) {
rc = PTR_ERR(clk);
@ -1656,6 +1701,7 @@ err_add_host:
err_rst_get:
clk_disable_unprepare(pltfm_host->clk);
err_clk_get:
clk_disable_unprepare(tegra_host->tmclk);
err_power_req:
err_parse_dt:
sdhci_pltfm_free(pdev);
@ -1673,6 +1719,7 @@ static int sdhci_tegra_remove(struct platform_device *pdev)
reset_control_assert(tegra_host->rst);
usleep_range(2000, 4000);
clk_disable_unprepare(pltfm_host->clk);
clk_disable_unprepare(tegra_host->tmclk);
sdhci_pltfm_free(pdev);