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

sdhci: sdhci-msm: update dll configuration

The newer msm sdhci's cores use a different DLL hardware for HS400.
Update the configuration and calibration of the newer DLL block.

The HS400 DLL block used previously is CDC LP 533 and requires
programming multiple registers and waiting for configuration to
complete and then enable it. It has about 18 register writes and
two register reads.

The newer HS400 DLL block is SDC4 DLL and requires two register
writes for configuration and one register read to confirm that it
is initialized. There is an additional register write to enable
the power save mode for SDC4 DLL block.

Signed-off-by: Ritesh Harjani <riteshh@codeaurora.org>
Signed-off-by: Krishna Konda <kkonda@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
02e4293d cc392c58

+123 -2
+123 -2
drivers/mmc/host/sdhci-msm.c
··· 52 52 #define INT_MASK 0xf 53 53 #define MAX_PHASES 16 54 54 #define CORE_DLL_LOCK BIT(7) 55 + #define CORE_DDR_DLL_LOCK BIT(11) 55 56 #define CORE_DLL_EN BIT(16) 56 57 #define CORE_CDR_EN BIT(17) 57 58 #define CORE_CK_OUT_EN BIT(18) ··· 64 63 #define CORE_DLL_STATUS 0x108 65 64 66 65 #define CORE_DLL_CONFIG_2 0x1b4 66 + #define CORE_DDR_CAL_EN BIT(0) 67 67 #define CORE_FLL_CYCLE_CNT BIT(18) 68 68 #define CORE_DLL_CLOCK_DISABLE BIT(21) 69 69 ··· 103 101 #define CORE_DDR_200_CFG 0x184 104 102 #define CORE_CDC_T4_DLY_SEL BIT(0) 105 103 #define CORE_START_CDC_TRAFFIC BIT(6) 104 + #define CORE_VENDOR_SPEC3 0x1b0 105 + #define CORE_PWRSAVE_DLL BIT(3) 106 + 107 + #define CORE_DDR_CONFIG 0x1b8 108 + #define DDR_CONFIG_POR_VAL 0x80040853 106 109 107 110 #define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c 108 111 ··· 135 128 bool tuning_done; 136 129 bool calibration_done; 137 130 u8 saved_tuning_phase; 131 + bool use_cdclp533; 138 132 }; 139 133 140 134 /* Platform specific tuning */ ··· 577 569 return ret; 578 570 } 579 571 572 + static int sdhci_msm_cm_dll_sdc4_calibration(struct sdhci_host *host) 573 + { 574 + u32 dll_status, config; 575 + int ret; 576 + 577 + pr_debug("%s: %s: Enter\n", mmc_hostname(host->mmc), __func__); 578 + 579 + /* 580 + * Currently the CORE_DDR_CONFIG register defaults to desired 581 + * configuration on reset. Currently reprogramming the power on 582 + * reset (POR) value in case it might have been modified by 583 + * bootloaders. In the future, if this changes, then the desired 584 + * values will need to be programmed appropriately. 585 + */ 586 + writel_relaxed(DDR_CONFIG_POR_VAL, host->ioaddr + CORE_DDR_CONFIG); 587 + 588 + config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2); 589 + config |= CORE_DDR_CAL_EN; 590 + writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG_2); 591 + 592 + ret = readl_relaxed_poll_timeout(host->ioaddr + CORE_DLL_STATUS, 593 + dll_status, 594 + (dll_status & CORE_DDR_DLL_LOCK), 595 + 10, 1000); 596 + 597 + if (ret == -ETIMEDOUT) { 598 + pr_err("%s: %s: CM_DLL_SDC4 calibration was not completed\n", 599 + mmc_hostname(host->mmc), __func__); 600 + goto out; 601 + } 602 + 603 + config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC3); 604 + config |= CORE_PWRSAVE_DLL; 605 + writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC3); 606 + 607 + /* 608 + * Drain writebuffer to ensure above DLL calibration 609 + * and PWRSAVE DLL is enabled. 610 + */ 611 + wmb(); 612 + out: 613 + pr_debug("%s: %s: Exit, ret %d\n", mmc_hostname(host->mmc), 614 + __func__, ret); 615 + return ret; 616 + } 617 + 618 + static int sdhci_msm_hs400_dll_calibration(struct sdhci_host *host) 619 + { 620 + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 621 + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 622 + int ret; 623 + u32 config; 624 + 625 + pr_debug("%s: %s: Enter\n", mmc_hostname(host->mmc), __func__); 626 + 627 + /* 628 + * Retuning in HS400 (DDR mode) will fail, just reset the 629 + * tuning block and restore the saved tuning phase. 630 + */ 631 + ret = msm_init_cm_dll(host); 632 + if (ret) 633 + goto out; 634 + 635 + /* Set the selected phase in delay line hw block */ 636 + ret = msm_config_cm_dll_phase(host, msm_host->saved_tuning_phase); 637 + if (ret) 638 + goto out; 639 + 640 + config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); 641 + config |= CORE_CMD_DAT_TRACK_SEL; 642 + writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); 643 + if (msm_host->use_cdclp533) 644 + ret = sdhci_msm_cdclp533_calibration(host); 645 + else 646 + ret = sdhci_msm_cm_dll_sdc4_calibration(host); 647 + out: 648 + pr_debug("%s: %s: Exit, ret %d\n", mmc_hostname(host->mmc), 649 + __func__, ret); 650 + return ret; 651 + } 652 + 580 653 static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode) 581 654 { 582 655 int tuning_seq_cnt = 3; ··· 804 715 if (host->clock > CORE_FREQ_100MHZ && 805 716 msm_host->tuning_done && !msm_host->calibration_done && 806 717 mmc->ios.timing == MMC_TIMING_MMC_HS400) 807 - if (!sdhci_msm_cdclp533_calibration(host)) 718 + if (!sdhci_msm_hs400_dll_calibration(host)) 808 719 msm_host->calibration_done = true; 809 720 spin_lock_irq(&host->lock); 810 721 } ··· 894 805 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 895 806 struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); 896 807 struct mmc_ios curr_ios = host->mmc->ios; 897 - u32 config; 808 + u32 config, dll_lock; 898 809 int rc; 899 810 900 811 if (!clock) { ··· 951 862 config |= CORE_HC_SELECT_IN_EN; 952 863 writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC); 953 864 } 865 + if (!msm_host->clk_rate && !msm_host->use_cdclp533) { 866 + /* 867 + * Poll on DLL_LOCK or DDR_DLL_LOCK bits in 868 + * CORE_DLL_STATUS to be set. This should get set 869 + * within 15 us at 200 MHz. 870 + */ 871 + rc = readl_relaxed_poll_timeout(host->ioaddr + 872 + CORE_DLL_STATUS, 873 + dll_lock, 874 + (dll_lock & 875 + (CORE_DLL_LOCK | 876 + CORE_DDR_DLL_LOCK)), 10, 877 + 1000); 878 + if (rc == -ETIMEDOUT) 879 + pr_err("%s: Unable to get DLL_LOCK/DDR_DLL_LOCK, dll_status: 0x%08x\n", 880 + mmc_hostname(host->mmc), dll_lock); 881 + } 954 882 } else { 883 + if (!msm_host->use_cdclp533) { 884 + config = readl_relaxed(host->ioaddr + 885 + CORE_VENDOR_SPEC3); 886 + config &= ~CORE_PWRSAVE_DLL; 887 + writel_relaxed(config, host->ioaddr + 888 + CORE_VENDOR_SPEC3); 889 + } 890 + 955 891 config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); 956 892 config &= ~CORE_HC_MCLK_SEL_MASK; 957 893 config |= CORE_HC_MCLK_SEL_DFLT; ··· 1167 1053 1168 1054 if (core_major == 1 && core_minor >= 0x42) 1169 1055 msm_host->use_14lpp_dll_reset = true; 1056 + 1057 + /* 1058 + * SDCC 5 controller with major version 1, minor version 0x34 and later 1059 + * with HS 400 mode support will use CM DLL instead of CDC LP 533 DLL. 1060 + */ 1061 + if (core_major == 1 && core_minor < 0x34) 1062 + msm_host->use_cdclp533 = true; 1170 1063 1171 1064 /* 1172 1065 * Support for some capabilities is not advertised by newer