Skip to content

Commit de25fa5

Browse files
Sowjanya Komatinenistorulf
authored andcommitted
mmc: tegra: SDMMC pads auto-calibration
Program initial drive code offsets which will be used by auto calibration process. Program fixed drive strengths for SDMMC pads in pad control register when auto cal timeouts. Fixed settings are based on Pre-SI analysis of the pad design. Signed-off-by: Sowjanya Komatineni <[email protected]> Acked-by: Adrian Hunter <[email protected]> Signed-off-by: Ulf Hansson <[email protected]>
1 parent 7c3cf5c commit de25fa5

File tree

1 file changed

+119
-41
lines changed

1 file changed

+119
-41
lines changed

drivers/mmc/host/sdhci-tegra.c

Lines changed: 119 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
#define SDHCI_TEGRA_SDMEM_COMP_PADCTRL_VREF_SEL_MASK 0x0000000f
7676
#define SDHCI_TEGRA_SDMEM_COMP_PADCTRL_VREF_SEL_VAL 0x7
7777
#define SDHCI_TEGRA_SDMEM_COMP_PADCTRL_E_INPUT_E_PWRD BIT(31)
78+
#define SDHCI_COMP_PADCTRL_DRVUPDN_OFFSET_MASK 0x07FFF000
7879

7980
#define SDHCI_TEGRA_AUTO_CAL_STATUS 0x1ec
8081
#define SDHCI_TEGRA_AUTO_CAL_ACTIVE BIT(31)
@@ -121,6 +122,8 @@ struct sdhci_tegra {
121122
struct pinctrl *pinctrl_sdmmc;
122123
struct pinctrl_state *pinctrl_state_3v3;
123124
struct pinctrl_state *pinctrl_state_1v8;
125+
struct pinctrl_state *pinctrl_state_3v3_drv;
126+
struct pinctrl_state *pinctrl_state_1v8_drv;
124127

125128
struct sdhci_tegra_autocal_offsets autocal_offsets;
126129
ktime_t last_calib;
@@ -411,6 +414,76 @@ static void tegra_sdhci_set_pad_autocal_offset(struct sdhci_host *host,
411414
sdhci_writel(host, reg, SDHCI_TEGRA_AUTO_CAL_CONFIG);
412415
}
413416

417+
static int tegra_sdhci_set_padctrl(struct sdhci_host *host, int voltage,
418+
bool state_drvupdn)
419+
{
420+
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
421+
struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host);
422+
struct sdhci_tegra_autocal_offsets *offsets =
423+
&tegra_host->autocal_offsets;
424+
struct pinctrl_state *pinctrl_drvupdn = NULL;
425+
int ret = 0;
426+
u8 drvup = 0, drvdn = 0;
427+
u32 reg;
428+
429+
if (!state_drvupdn) {
430+
/* PADS Drive Strength */
431+
if (voltage == MMC_SIGNAL_VOLTAGE_180) {
432+
if (tegra_host->pinctrl_state_1v8_drv) {
433+
pinctrl_drvupdn =
434+
tegra_host->pinctrl_state_1v8_drv;
435+
} else {
436+
drvup = offsets->pull_up_1v8_timeout;
437+
drvdn = offsets->pull_down_1v8_timeout;
438+
}
439+
} else {
440+
if (tegra_host->pinctrl_state_3v3_drv) {
441+
pinctrl_drvupdn =
442+
tegra_host->pinctrl_state_3v3_drv;
443+
} else {
444+
drvup = offsets->pull_up_3v3_timeout;
445+
drvdn = offsets->pull_down_3v3_timeout;
446+
}
447+
}
448+
449+
if (pinctrl_drvupdn != NULL) {
450+
ret = pinctrl_select_state(tegra_host->pinctrl_sdmmc,
451+
pinctrl_drvupdn);
452+
if (ret < 0)
453+
dev_err(mmc_dev(host->mmc),
454+
"failed pads drvupdn, ret: %d\n", ret);
455+
} else if ((drvup) || (drvdn)) {
456+
reg = sdhci_readl(host,
457+
SDHCI_TEGRA_SDMEM_COMP_PADCTRL);
458+
reg &= ~SDHCI_COMP_PADCTRL_DRVUPDN_OFFSET_MASK;
459+
reg |= (drvup << 20) | (drvdn << 12);
460+
sdhci_writel(host, reg,
461+
SDHCI_TEGRA_SDMEM_COMP_PADCTRL);
462+
}
463+
464+
} else {
465+
/* Dual Voltage PADS Voltage selection */
466+
if (!tegra_host->pad_control_available)
467+
return 0;
468+
469+
if (voltage == MMC_SIGNAL_VOLTAGE_180) {
470+
ret = pinctrl_select_state(tegra_host->pinctrl_sdmmc,
471+
tegra_host->pinctrl_state_1v8);
472+
if (ret < 0)
473+
dev_err(mmc_dev(host->mmc),
474+
"setting 1.8V failed, ret: %d\n", ret);
475+
} else {
476+
ret = pinctrl_select_state(tegra_host->pinctrl_sdmmc,
477+
tegra_host->pinctrl_state_3v3);
478+
if (ret < 0)
479+
dev_err(mmc_dev(host->mmc),
480+
"setting 3.3V failed, ret: %d\n", ret);
481+
}
482+
}
483+
484+
return ret;
485+
}
486+
414487
static void tegra_sdhci_pad_autocalib(struct sdhci_host *host)
415488
{
416489
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -437,6 +510,7 @@ static void tegra_sdhci_pad_autocalib(struct sdhci_host *host)
437510
pdpu = offsets.pull_down_3v3 << 8 | offsets.pull_up_3v3;
438511
}
439512

513+
/* Set initial offset before auto-calibration */
440514
tegra_sdhci_set_pad_autocal_offset(host, pdpu);
441515

442516
card_clk_enabled = tegra_sdhci_configure_card_clk(host, false);
@@ -460,19 +534,15 @@ static void tegra_sdhci_pad_autocalib(struct sdhci_host *host)
460534
if (ret) {
461535
dev_err(mmc_dev(host->mmc), "Pad autocal timed out\n");
462536

463-
if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180)
464-
pdpu = offsets.pull_down_1v8_timeout << 8 |
465-
offsets.pull_up_1v8_timeout;
466-
else
467-
pdpu = offsets.pull_down_3v3_timeout << 8 |
468-
offsets.pull_up_3v3_timeout;
469-
470-
/* Disable automatic calibration and use fixed offsets */
537+
/* Disable automatic cal and use fixed Drive Strengths */
471538
reg = sdhci_readl(host, SDHCI_TEGRA_AUTO_CAL_CONFIG);
472539
reg &= ~SDHCI_AUTO_CAL_ENABLE;
473540
sdhci_writel(host, reg, SDHCI_TEGRA_AUTO_CAL_CONFIG);
474541

475-
tegra_sdhci_set_pad_autocal_offset(host, pdpu);
542+
ret = tegra_sdhci_set_padctrl(host, ios->signal_voltage, false);
543+
if (ret < 0)
544+
dev_err(mmc_dev(host->mmc),
545+
"Setting drive strengths failed: %d\n", ret);
476546
}
477547
}
478548

@@ -511,26 +581,46 @@ static void tegra_sdhci_parse_pad_autocal_dt(struct sdhci_host *host)
511581
err = device_property_read_u32(host->mmc->parent,
512582
"nvidia,pad-autocal-pull-up-offset-3v3-timeout",
513583
&autocal->pull_up_3v3_timeout);
514-
if (err)
584+
if (err) {
585+
if (!IS_ERR(tegra_host->pinctrl_state_3v3) &&
586+
(tegra_host->pinctrl_state_3v3_drv == NULL))
587+
pr_warn("%s: Missing autocal timeout 3v3-pad drvs\n",
588+
mmc_hostname(host->mmc));
515589
autocal->pull_up_3v3_timeout = 0;
590+
}
516591

517592
err = device_property_read_u32(host->mmc->parent,
518593
"nvidia,pad-autocal-pull-down-offset-3v3-timeout",
519594
&autocal->pull_down_3v3_timeout);
520-
if (err)
595+
if (err) {
596+
if (!IS_ERR(tegra_host->pinctrl_state_3v3) &&
597+
(tegra_host->pinctrl_state_3v3_drv == NULL))
598+
pr_warn("%s: Missing autocal timeout 3v3-pad drvs\n",
599+
mmc_hostname(host->mmc));
521600
autocal->pull_down_3v3_timeout = 0;
601+
}
522602

523603
err = device_property_read_u32(host->mmc->parent,
524604
"nvidia,pad-autocal-pull-up-offset-1v8-timeout",
525605
&autocal->pull_up_1v8_timeout);
526-
if (err)
606+
if (err) {
607+
if (!IS_ERR(tegra_host->pinctrl_state_1v8) &&
608+
(tegra_host->pinctrl_state_1v8_drv == NULL))
609+
pr_warn("%s: Missing autocal timeout 1v8-pad drvs\n",
610+
mmc_hostname(host->mmc));
527611
autocal->pull_up_1v8_timeout = 0;
612+
}
528613

529614
err = device_property_read_u32(host->mmc->parent,
530615
"nvidia,pad-autocal-pull-down-offset-1v8-timeout",
531616
&autocal->pull_down_1v8_timeout);
532-
if (err)
617+
if (err) {
618+
if (!IS_ERR(tegra_host->pinctrl_state_1v8) &&
619+
(tegra_host->pinctrl_state_1v8_drv == NULL))
620+
pr_warn("%s: Missing autocal timeout 1v8-pad drvs\n",
621+
mmc_hostname(host->mmc));
533622
autocal->pull_down_1v8_timeout = 0;
623+
}
534624

535625
err = device_property_read_u32(host->mmc->parent,
536626
"nvidia,pad-autocal-pull-up-offset-sdr104",
@@ -743,32 +833,6 @@ static int tegra_sdhci_execute_tuning(struct sdhci_host *host, u32 opcode)
743833
return mmc_send_tuning(host->mmc, opcode, NULL);
744834
}
745835

746-
static int tegra_sdhci_set_padctrl(struct sdhci_host *host, int voltage)
747-
{
748-
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
749-
struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host);
750-
int ret;
751-
752-
if (!tegra_host->pad_control_available)
753-
return 0;
754-
755-
if (voltage == MMC_SIGNAL_VOLTAGE_180) {
756-
ret = pinctrl_select_state(tegra_host->pinctrl_sdmmc,
757-
tegra_host->pinctrl_state_1v8);
758-
if (ret < 0)
759-
dev_err(mmc_dev(host->mmc),
760-
"setting 1.8V failed, ret: %d\n", ret);
761-
} else {
762-
ret = pinctrl_select_state(tegra_host->pinctrl_sdmmc,
763-
tegra_host->pinctrl_state_3v3);
764-
if (ret < 0)
765-
dev_err(mmc_dev(host->mmc),
766-
"setting 3.3V failed, ret: %d\n", ret);
767-
}
768-
769-
return ret;
770-
}
771-
772836
static int sdhci_tegra_start_signal_voltage_switch(struct mmc_host *mmc,
773837
struct mmc_ios *ios)
774838
{
@@ -778,15 +842,15 @@ static int sdhci_tegra_start_signal_voltage_switch(struct mmc_host *mmc,
778842
int ret = 0;
779843

780844
if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
781-
ret = tegra_sdhci_set_padctrl(host, ios->signal_voltage);
845+
ret = tegra_sdhci_set_padctrl(host, ios->signal_voltage, true);
782846
if (ret < 0)
783847
return ret;
784848
ret = sdhci_start_signal_voltage_switch(mmc, ios);
785849
} else if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
786850
ret = sdhci_start_signal_voltage_switch(mmc, ios);
787851
if (ret < 0)
788852
return ret;
789-
ret = tegra_sdhci_set_padctrl(host, ios->signal_voltage);
853+
ret = tegra_sdhci_set_padctrl(host, ios->signal_voltage, true);
790854
}
791855

792856
if (tegra_host->pad_calib_required)
@@ -805,6 +869,20 @@ static int tegra_sdhci_init_pinctrl_info(struct device *dev,
805869
return -1;
806870
}
807871

872+
tegra_host->pinctrl_state_1v8_drv = pinctrl_lookup_state(
873+
tegra_host->pinctrl_sdmmc, "sdmmc-1v8-drv");
874+
if (IS_ERR(tegra_host->pinctrl_state_1v8_drv)) {
875+
if (PTR_ERR(tegra_host->pinctrl_state_1v8_drv) == -ENODEV)
876+
tegra_host->pinctrl_state_1v8_drv = NULL;
877+
}
878+
879+
tegra_host->pinctrl_state_3v3_drv = pinctrl_lookup_state(
880+
tegra_host->pinctrl_sdmmc, "sdmmc-3v3-drv");
881+
if (IS_ERR(tegra_host->pinctrl_state_3v3_drv)) {
882+
if (PTR_ERR(tegra_host->pinctrl_state_3v3_drv) == -ENODEV)
883+
tegra_host->pinctrl_state_3v3_drv = NULL;
884+
}
885+
808886
tegra_host->pinctrl_state_3v3 =
809887
pinctrl_lookup_state(tegra_host->pinctrl_sdmmc, "sdmmc-3v3");
810888
if (IS_ERR(tegra_host->pinctrl_state_3v3)) {

0 commit comments

Comments
 (0)