Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mmc: sdhci-msm: Add calibration tuning for CDCLP533 circuit

In HS400 mode a new RCLK is introduced on the interface for read data
transfers. The eMMC5.0 device transmits the read data to the host with
respect to rising and falling edges of RCLK. In order to ensure correct
operation of read data transfers in HS400 mode, the incoming RX data
needs to be sampled by delayed version of RCLK.

The CDCLP533 delay circuit shifts the RCLK by T/4. It needs to be
initialized, configured and enabled once during HS400 mode switch and
when operational voltage/clock is changed.

Signed-off-by: Venkat Gopalakrishnan <venkatg@codeaurora.org>
Signed-off-by: Ritesh Harjani <riteshh@codeaurora.org>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

authored by

Ritesh Harjani and committed by
Ulf Hansson
cc392c58 abf270e5

+151
+151
drivers/mmc/host/sdhci-msm.c
··· 20 20 #include <linux/mmc/mmc.h> 21 21 #include <linux/pm_runtime.h> 22 22 #include <linux/slab.h> 23 + #include <linux/iopoll.h> 23 24 24 25 #include "sdhci-pltfm.h" 25 26 ··· 59 58 #define CORE_DLL_PDN BIT(29) 60 59 #define CORE_DLL_RST BIT(30) 61 60 #define CORE_DLL_CONFIG 0x100 61 + #define CORE_CMD_DAT_TRACK_SEL BIT(0) 62 62 #define CORE_DLL_STATUS 0x108 63 63 64 64 #define CORE_DLL_CONFIG_2 0x1b4 ··· 74 72 #define CORE_HC_SELECT_IN_EN BIT(18) 75 73 #define CORE_HC_SELECT_IN_HS400 (6 << 19) 76 74 #define CORE_HC_SELECT_IN_MASK (7 << 19) 75 + 76 + #define CORE_CSR_CDC_CTLR_CFG0 0x130 77 + #define CORE_SW_TRIG_FULL_CALIB BIT(16) 78 + #define CORE_HW_AUTOCAL_ENA BIT(17) 79 + 80 + #define CORE_CSR_CDC_CTLR_CFG1 0x134 81 + #define CORE_CSR_CDC_CAL_TIMER_CFG0 0x138 82 + #define CORE_TIMER_ENA BIT(16) 83 + 84 + #define CORE_CSR_CDC_CAL_TIMER_CFG1 0x13C 85 + #define CORE_CSR_CDC_REFCOUNT_CFG 0x140 86 + #define CORE_CSR_CDC_COARSE_CAL_CFG 0x144 87 + #define CORE_CDC_OFFSET_CFG 0x14C 88 + #define CORE_CSR_CDC_DELAY_CFG 0x150 89 + #define CORE_CDC_SLAVE_DDA_CFG 0x160 90 + #define CORE_CSR_CDC_STATUS0 0x164 91 + #define CORE_CALIBRATION_DONE BIT(0) 92 + 93 + #define CORE_CDC_ERROR_CODE_MASK 0x7000000 94 + 95 + #define CORE_CSR_CDC_GEN_CFG 0x178 96 + #define CORE_CDC_SWITCH_BYPASS_OFF BIT(0) 97 + #define CORE_CDC_SWITCH_RC_EN BIT(1) 98 + 99 + #define CORE_DDR_200_CFG 0x184 100 + #define CORE_CDC_T4_DLY_SEL BIT(0) 101 + #define CORE_START_CDC_TRAFFIC BIT(6) 77 102 78 103 #define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c 79 104 ··· 456 427 return 0; 457 428 } 458 429 430 + static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host) 431 + { 432 + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 433 + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 434 + u32 config, calib_done; 435 + int ret; 436 + 437 + pr_debug("%s: %s: Enter\n", mmc_hostname(host->mmc), __func__); 438 + 439 + /* 440 + * Retuning in HS400 (DDR mode) will fail, just reset the 441 + * tuning block and restore the saved tuning phase. 442 + */ 443 + ret = msm_init_cm_dll(host); 444 + if (ret) 445 + goto out; 446 + 447 + /* Set the selected phase in delay line hw block */ 448 + ret = msm_config_cm_dll_phase(host, msm_host->saved_tuning_phase); 449 + if (ret) 450 + goto out; 451 + 452 + config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); 453 + config |= CORE_CMD_DAT_TRACK_SEL; 454 + writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); 455 + 456 + config = readl_relaxed(host->ioaddr + CORE_DDR_200_CFG); 457 + config &= ~CORE_CDC_T4_DLY_SEL; 458 + writel_relaxed(config, host->ioaddr + CORE_DDR_200_CFG); 459 + 460 + config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_GEN_CFG); 461 + config &= ~CORE_CDC_SWITCH_BYPASS_OFF; 462 + writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_GEN_CFG); 463 + 464 + config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_GEN_CFG); 465 + config |= CORE_CDC_SWITCH_RC_EN; 466 + writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_GEN_CFG); 467 + 468 + config = readl_relaxed(host->ioaddr + CORE_DDR_200_CFG); 469 + config &= ~CORE_START_CDC_TRAFFIC; 470 + writel_relaxed(config, host->ioaddr + CORE_DDR_200_CFG); 471 + 472 + /* 473 + * Perform CDC Register Initialization Sequence 474 + * 475 + * CORE_CSR_CDC_CTLR_CFG0 0x11800EC 476 + * CORE_CSR_CDC_CTLR_CFG1 0x3011111 477 + * CORE_CSR_CDC_CAL_TIMER_CFG0 0x1201000 478 + * CORE_CSR_CDC_CAL_TIMER_CFG1 0x4 479 + * CORE_CSR_CDC_REFCOUNT_CFG 0xCB732020 480 + * CORE_CSR_CDC_COARSE_CAL_CFG 0xB19 481 + * CORE_CSR_CDC_DELAY_CFG 0x3AC 482 + * CORE_CDC_OFFSET_CFG 0x0 483 + * CORE_CDC_SLAVE_DDA_CFG 0x16334 484 + */ 485 + 486 + writel_relaxed(0x11800EC, host->ioaddr + CORE_CSR_CDC_CTLR_CFG0); 487 + writel_relaxed(0x3011111, host->ioaddr + CORE_CSR_CDC_CTLR_CFG1); 488 + writel_relaxed(0x1201000, host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG0); 489 + writel_relaxed(0x4, host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG1); 490 + writel_relaxed(0xCB732020, host->ioaddr + CORE_CSR_CDC_REFCOUNT_CFG); 491 + writel_relaxed(0xB19, host->ioaddr + CORE_CSR_CDC_COARSE_CAL_CFG); 492 + writel_relaxed(0x3AC, host->ioaddr + CORE_CSR_CDC_DELAY_CFG); 493 + writel_relaxed(0x0, host->ioaddr + CORE_CDC_OFFSET_CFG); 494 + writel_relaxed(0x16334, host->ioaddr + CORE_CDC_SLAVE_DDA_CFG); 495 + 496 + /* CDC HW Calibration */ 497 + 498 + config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_CTLR_CFG0); 499 + config |= CORE_SW_TRIG_FULL_CALIB; 500 + writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_CTLR_CFG0); 501 + 502 + config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_CTLR_CFG0); 503 + config &= ~CORE_SW_TRIG_FULL_CALIB; 504 + writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_CTLR_CFG0); 505 + 506 + config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_CTLR_CFG0); 507 + config |= CORE_HW_AUTOCAL_ENA; 508 + writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_CTLR_CFG0); 509 + 510 + config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG0); 511 + config |= CORE_TIMER_ENA; 512 + writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG0); 513 + 514 + ret = readl_relaxed_poll_timeout(host->ioaddr + CORE_CSR_CDC_STATUS0, 515 + calib_done, 516 + (calib_done & CORE_CALIBRATION_DONE), 517 + 1, 50); 518 + 519 + if (ret == -ETIMEDOUT) { 520 + pr_err("%s: %s: CDC calibration was not completed\n", 521 + mmc_hostname(host->mmc), __func__); 522 + goto out; 523 + } 524 + 525 + ret = readl_relaxed(host->ioaddr + CORE_CSR_CDC_STATUS0) 526 + & CORE_CDC_ERROR_CODE_MASK; 527 + if (ret) { 528 + pr_err("%s: %s: CDC error code %d\n", 529 + mmc_hostname(host->mmc), __func__, ret); 530 + ret = -EINVAL; 531 + goto out; 532 + } 533 + 534 + config = readl_relaxed(host->ioaddr + CORE_DDR_200_CFG); 535 + config |= CORE_START_CDC_TRAFFIC; 536 + writel_relaxed(config, host->ioaddr + CORE_DDR_200_CFG); 537 + out: 538 + pr_debug("%s: %s: Exit, ret %d\n", mmc_hostname(host->mmc), 539 + __func__, ret); 540 + return ret; 541 + } 542 + 459 543 static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode) 460 544 { 461 545 int tuning_seq_cnt = 3; ··· 709 567 dev_dbg(mmc_dev(mmc), "%s: clock=%u uhs=%u ctrl_2=0x%x\n", 710 568 mmc_hostname(host->mmc), host->clock, uhs, ctrl_2); 711 569 sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); 570 + 571 + spin_unlock_irq(&host->lock); 572 + /* CDCLP533 HW calibration is only required for HS400 mode*/ 573 + if (host->clock > CORE_FREQ_100MHZ && 574 + msm_host->tuning_done && !msm_host->calibration_done && 575 + mmc->ios.timing == MMC_TIMING_MMC_HS400) 576 + if (!sdhci_msm_cdclp533_calibration(host)) 577 + msm_host->calibration_done = true; 578 + spin_lock_irq(&host->lock); 712 579 } 713 580 714 581 static void sdhci_msm_voltage_switch(struct sdhci_host *host)