Loading drivers/mmc/host/sdhci-msm.c +123 −35 Original line number Diff line number Diff line Loading @@ -90,6 +90,7 @@ #define CORE_DLL_STATUS 0x108 #define CORE_DLL_LOCK (1 << 7) #define CORE_DDR_DLL_LOCK (1 << 11) #define CORE_VENDOR_SPEC 0x10C #define CORE_CLK_PWRSAVE (1 << 1) Loading Loading @@ -138,6 +139,15 @@ #define CORE_DDR_200_CFG 0x184 #define CORE_CDC_T4_DLY_SEL (1 << 0) #define CORE_START_CDC_TRAFFIC (1 << 6) #define CORE_VENDOR_SPEC3 0x1B0 #define CORE_PWRSAVE_DLL (1 << 3) #define CORE_DLL_CONFIG_2 0x1B4 #define CORE_DDR_CAL_EN (1 << 0) #define CORE_DDR_CONFIG 0x1B8 #define DDR_CONFIG_POR_VAL 0x80040853 #define CORE_MCI_DATA_CNT 0x30 #define CORE_MCI_STATUS 0x34 Loading Loading @@ -301,6 +311,7 @@ struct sdhci_msm_host { bool en_auto_cmd21; struct device_attribute auto_cmd21_attr; atomic_t controller_clock; bool use_cdclp533; }; enum vdd_io_level { Loading Loading @@ -715,32 +726,12 @@ static int msm_init_cm_dll(struct sdhci_host *host) static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host) { u32 wait_cnt; u32 calib_done; int ret = 0; int cdc_err = 0; struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; pr_debug("%s: Enter %s\n", mmc_hostname(host->mmc), __func__); /* * Retuning in HS400 (DDR mode) will fail, just reset the * tuning block and restore the saved tuning phase. */ ret = msm_init_cm_dll(host); if (ret) goto out; /* Set the selected phase in delay line hw block */ ret = msm_config_cm_dll_phase(host, msm_host->saved_tuning_phase); if (ret) goto out; /* Write 1 to CMD_DAT_TRACK_SEL field in DLL_CONFIG */ writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) | CORE_CMD_DAT_TRACK_SEL), host->ioaddr + CORE_DLL_CONFIG); /* Write 0 to CDC_T4_DLY_SEL field in VENDOR_SPEC_DDR200_CFG */ writel_relaxed((readl_relaxed(host->ioaddr + CORE_DDR_200_CFG) & ~CORE_CDC_T4_DLY_SEL), Loading Loading @@ -810,19 +801,14 @@ static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host) mb(); /* Poll on CALIBRATION_DONE field in CORE_CSR_CDC_STATUS0 to be 1 */ wait_cnt = 50; while (!(readl_relaxed(host->ioaddr + CORE_CSR_CDC_STATUS0) & CORE_CALIBRATION_DONE)) { /* max. wait for 50us sec for CALIBRATION_DONE bit to be set */ if (--wait_cnt == 0) { ret = readl_poll_timeout(host->ioaddr + CORE_CSR_CDC_STATUS0, calib_done, (calib_done & CORE_CALIBRATION_DONE), 1, 50); if (ret == -ETIMEDOUT) { pr_err("%s: %s: CDC Calibration was not completed\n", mmc_hostname(host->mmc), __func__); ret = -ETIMEDOUT; goto out; } /* wait for 1us before polling again */ udelay(1); } /* Verify CDC_ERROR_CODE field in CORE_CSR_CDC_STATUS0 is 0 */ cdc_err = readl_relaxed(host->ioaddr + CORE_CSR_CDC_STATUS0) Loading @@ -844,6 +830,81 @@ static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host) return ret; } static int sdhci_msm_cm_dll_sdc4_calibration(struct sdhci_host *host) { u32 dll_status; int ret = 0; pr_debug("%s: Enter %s\n", mmc_hostname(host->mmc), __func__); /* * Currently the CORE_DDR_CONFIG register defaults to desired * configuration on reset. Currently reprogramming the power on * reset (POR) value in case it might have been modified by * bootloaders. In the future, if this changes, then the desired * values will need to be programmed appropriately. */ writel_relaxed(DDR_CONFIG_POR_VAL, host->ioaddr + CORE_DDR_CONFIG); /* Write 1 to DDR_CAL_EN field in CORE_DLL_CONFIG_2 */ writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2) | CORE_DDR_CAL_EN), host->ioaddr + CORE_DLL_CONFIG_2); /* Poll on DDR_DLL_LOCK bit in CORE_DLL_STATUS to be set */ ret = readl_poll_timeout(host->ioaddr + CORE_DLL_STATUS, dll_status, (dll_status & CORE_DDR_DLL_LOCK), 10, 1000); if (ret == -ETIMEDOUT) { pr_err("%s: %s: CM_DLL_SDC4 Calibration was not completed\n", mmc_hostname(host->mmc), __func__); goto out; } /* set CORE_PWRSAVE_DLL bit in CORE_VENDOR_SPEC3 */ writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC3) | CORE_PWRSAVE_DLL), host->ioaddr + CORE_VENDOR_SPEC3); mb(); out: pr_debug("%s: Exit %s, ret:%d\n", mmc_hostname(host->mmc), __func__, ret); return ret; } static int sdhci_msm_hs400_dll_calibration(struct sdhci_host *host) { int ret = 0; struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; pr_debug("%s: Enter %s\n", mmc_hostname(host->mmc), __func__); /* * Retuning in HS400 (DDR mode) will fail, just reset the * tuning block and restore the saved tuning phase. */ ret = msm_init_cm_dll(host); if (ret) goto out; /* Set the selected phase in delay line hw block */ ret = msm_config_cm_dll_phase(host, msm_host->saved_tuning_phase); if (ret) goto out; if (msm_host->use_cdclp533) /* Calibrate CDCLP533 DLL HW */ ret = sdhci_msm_cdclp533_calibration(host); else /* Calibrate CM_DLL_SDC4 HW */ ret = sdhci_msm_cm_dll_sdc4_calibration(host); out: pr_debug("%s: Exit %s, ret:%d\n", mmc_hostname(host->mmc), __func__, ret); return ret; } static void sdhci_msm_set_mmc_drv_type(struct sdhci_host *host, u32 opcode, u8 drv_type) { Loading Loading @@ -901,10 +962,10 @@ int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode) pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__); /* CDCLP533 HW calibration is only required for HS400 mode*/ /* CDC/SDC4 DLL HW calibration is only required for HS400 mode*/ if (msm_host->tuning_done && !msm_host->calibration_done && (mmc->ios.timing == MMC_TIMING_MMC_HS400)) { rc = sdhci_msm_cdclp533_calibration(host); rc = sdhci_msm_hs400_dll_calibration(host); spin_lock_irqsave(&host->lock, flags); if (!rc) msm_host->calibration_done = true; Loading Loading @@ -2382,7 +2443,7 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock) struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; struct mmc_ios curr_ios = host->mmc->ios; u32 sup_clock, ddr_clock; u32 sup_clock, ddr_clock, dll_lock; bool curr_pwrsave; if (!clock) { Loading Loading @@ -2469,7 +2530,27 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock) | CORE_HC_SELECT_IN_EN), host->ioaddr + CORE_VENDOR_SPEC); } if (!host->mmc->ios.old_rate && !msm_host->use_cdclp533) { /* * Poll on DLL_LOCK and DDR_DLL_LOCK bits in * CORE_DLL_STATUS to be set. This should get set * with in 15 us at 200 MHz. */ rc = readl_poll_timeout(host->ioaddr + CORE_DLL_STATUS, dll_lock, (dll_lock & (CORE_DLL_LOCK | CORE_DDR_DLL_LOCK)), 10, 1000); if (rc == -ETIMEDOUT) pr_err("%s: Unable to get DLL_LOCK/DDR_DLL_LOCK, dll_status: 0x%08x\n", mmc_hostname(host->mmc), dll_lock); } } else { if (!msm_host->use_cdclp533) /* set CORE_PWRSAVE_DLL bit in CORE_VENDOR_SPEC3 */ writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC3) & ~CORE_PWRSAVE_DLL), host->ioaddr + CORE_VENDOR_SPEC3); /* Select the default clock (free running MCLK) */ writel_relaxed(((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) & ~CORE_HC_MCLK_SEL_MASK) Loading Loading @@ -2671,6 +2752,13 @@ static void sdhci_set_default_hw_caps(struct sdhci_msm_host *msm_host, (readl_relaxed(host->ioaddr + SDHCI_CAPABILITIES) | caps), host->ioaddr + CORE_VENDOR_SPEC_CAPABILITIES0); } /* * SDCC 5 controller with major version 1, minor version 0x34 and later * with HS 400 mode support will use CM DLL instead of CDC LP 533 DLL. */ if ((major == 1) && (minor < 0x34)) msm_host->use_cdclp533 = true; } static int sdhci_msm_probe(struct platform_device *pdev) Loading include/linux/mmc/host.h +1 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ struct mmc_ios { unsigned int clock; /* clock rate */ unsigned int old_rate; /* saved clock rate */ unsigned short vdd; /* vdd stores the bit number of the selected voltage range from below. */ Loading Loading
drivers/mmc/host/sdhci-msm.c +123 −35 Original line number Diff line number Diff line Loading @@ -90,6 +90,7 @@ #define CORE_DLL_STATUS 0x108 #define CORE_DLL_LOCK (1 << 7) #define CORE_DDR_DLL_LOCK (1 << 11) #define CORE_VENDOR_SPEC 0x10C #define CORE_CLK_PWRSAVE (1 << 1) Loading Loading @@ -138,6 +139,15 @@ #define CORE_DDR_200_CFG 0x184 #define CORE_CDC_T4_DLY_SEL (1 << 0) #define CORE_START_CDC_TRAFFIC (1 << 6) #define CORE_VENDOR_SPEC3 0x1B0 #define CORE_PWRSAVE_DLL (1 << 3) #define CORE_DLL_CONFIG_2 0x1B4 #define CORE_DDR_CAL_EN (1 << 0) #define CORE_DDR_CONFIG 0x1B8 #define DDR_CONFIG_POR_VAL 0x80040853 #define CORE_MCI_DATA_CNT 0x30 #define CORE_MCI_STATUS 0x34 Loading Loading @@ -301,6 +311,7 @@ struct sdhci_msm_host { bool en_auto_cmd21; struct device_attribute auto_cmd21_attr; atomic_t controller_clock; bool use_cdclp533; }; enum vdd_io_level { Loading Loading @@ -715,32 +726,12 @@ static int msm_init_cm_dll(struct sdhci_host *host) static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host) { u32 wait_cnt; u32 calib_done; int ret = 0; int cdc_err = 0; struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; pr_debug("%s: Enter %s\n", mmc_hostname(host->mmc), __func__); /* * Retuning in HS400 (DDR mode) will fail, just reset the * tuning block and restore the saved tuning phase. */ ret = msm_init_cm_dll(host); if (ret) goto out; /* Set the selected phase in delay line hw block */ ret = msm_config_cm_dll_phase(host, msm_host->saved_tuning_phase); if (ret) goto out; /* Write 1 to CMD_DAT_TRACK_SEL field in DLL_CONFIG */ writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) | CORE_CMD_DAT_TRACK_SEL), host->ioaddr + CORE_DLL_CONFIG); /* Write 0 to CDC_T4_DLY_SEL field in VENDOR_SPEC_DDR200_CFG */ writel_relaxed((readl_relaxed(host->ioaddr + CORE_DDR_200_CFG) & ~CORE_CDC_T4_DLY_SEL), Loading Loading @@ -810,19 +801,14 @@ static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host) mb(); /* Poll on CALIBRATION_DONE field in CORE_CSR_CDC_STATUS0 to be 1 */ wait_cnt = 50; while (!(readl_relaxed(host->ioaddr + CORE_CSR_CDC_STATUS0) & CORE_CALIBRATION_DONE)) { /* max. wait for 50us sec for CALIBRATION_DONE bit to be set */ if (--wait_cnt == 0) { ret = readl_poll_timeout(host->ioaddr + CORE_CSR_CDC_STATUS0, calib_done, (calib_done & CORE_CALIBRATION_DONE), 1, 50); if (ret == -ETIMEDOUT) { pr_err("%s: %s: CDC Calibration was not completed\n", mmc_hostname(host->mmc), __func__); ret = -ETIMEDOUT; goto out; } /* wait for 1us before polling again */ udelay(1); } /* Verify CDC_ERROR_CODE field in CORE_CSR_CDC_STATUS0 is 0 */ cdc_err = readl_relaxed(host->ioaddr + CORE_CSR_CDC_STATUS0) Loading @@ -844,6 +830,81 @@ static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host) return ret; } static int sdhci_msm_cm_dll_sdc4_calibration(struct sdhci_host *host) { u32 dll_status; int ret = 0; pr_debug("%s: Enter %s\n", mmc_hostname(host->mmc), __func__); /* * Currently the CORE_DDR_CONFIG register defaults to desired * configuration on reset. Currently reprogramming the power on * reset (POR) value in case it might have been modified by * bootloaders. In the future, if this changes, then the desired * values will need to be programmed appropriately. */ writel_relaxed(DDR_CONFIG_POR_VAL, host->ioaddr + CORE_DDR_CONFIG); /* Write 1 to DDR_CAL_EN field in CORE_DLL_CONFIG_2 */ writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2) | CORE_DDR_CAL_EN), host->ioaddr + CORE_DLL_CONFIG_2); /* Poll on DDR_DLL_LOCK bit in CORE_DLL_STATUS to be set */ ret = readl_poll_timeout(host->ioaddr + CORE_DLL_STATUS, dll_status, (dll_status & CORE_DDR_DLL_LOCK), 10, 1000); if (ret == -ETIMEDOUT) { pr_err("%s: %s: CM_DLL_SDC4 Calibration was not completed\n", mmc_hostname(host->mmc), __func__); goto out; } /* set CORE_PWRSAVE_DLL bit in CORE_VENDOR_SPEC3 */ writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC3) | CORE_PWRSAVE_DLL), host->ioaddr + CORE_VENDOR_SPEC3); mb(); out: pr_debug("%s: Exit %s, ret:%d\n", mmc_hostname(host->mmc), __func__, ret); return ret; } static int sdhci_msm_hs400_dll_calibration(struct sdhci_host *host) { int ret = 0; struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; pr_debug("%s: Enter %s\n", mmc_hostname(host->mmc), __func__); /* * Retuning in HS400 (DDR mode) will fail, just reset the * tuning block and restore the saved tuning phase. */ ret = msm_init_cm_dll(host); if (ret) goto out; /* Set the selected phase in delay line hw block */ ret = msm_config_cm_dll_phase(host, msm_host->saved_tuning_phase); if (ret) goto out; if (msm_host->use_cdclp533) /* Calibrate CDCLP533 DLL HW */ ret = sdhci_msm_cdclp533_calibration(host); else /* Calibrate CM_DLL_SDC4 HW */ ret = sdhci_msm_cm_dll_sdc4_calibration(host); out: pr_debug("%s: Exit %s, ret:%d\n", mmc_hostname(host->mmc), __func__, ret); return ret; } static void sdhci_msm_set_mmc_drv_type(struct sdhci_host *host, u32 opcode, u8 drv_type) { Loading Loading @@ -901,10 +962,10 @@ int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode) pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__); /* CDCLP533 HW calibration is only required for HS400 mode*/ /* CDC/SDC4 DLL HW calibration is only required for HS400 mode*/ if (msm_host->tuning_done && !msm_host->calibration_done && (mmc->ios.timing == MMC_TIMING_MMC_HS400)) { rc = sdhci_msm_cdclp533_calibration(host); rc = sdhci_msm_hs400_dll_calibration(host); spin_lock_irqsave(&host->lock, flags); if (!rc) msm_host->calibration_done = true; Loading Loading @@ -2382,7 +2443,7 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock) struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; struct mmc_ios curr_ios = host->mmc->ios; u32 sup_clock, ddr_clock; u32 sup_clock, ddr_clock, dll_lock; bool curr_pwrsave; if (!clock) { Loading Loading @@ -2469,7 +2530,27 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock) | CORE_HC_SELECT_IN_EN), host->ioaddr + CORE_VENDOR_SPEC); } if (!host->mmc->ios.old_rate && !msm_host->use_cdclp533) { /* * Poll on DLL_LOCK and DDR_DLL_LOCK bits in * CORE_DLL_STATUS to be set. This should get set * with in 15 us at 200 MHz. */ rc = readl_poll_timeout(host->ioaddr + CORE_DLL_STATUS, dll_lock, (dll_lock & (CORE_DLL_LOCK | CORE_DDR_DLL_LOCK)), 10, 1000); if (rc == -ETIMEDOUT) pr_err("%s: Unable to get DLL_LOCK/DDR_DLL_LOCK, dll_status: 0x%08x\n", mmc_hostname(host->mmc), dll_lock); } } else { if (!msm_host->use_cdclp533) /* set CORE_PWRSAVE_DLL bit in CORE_VENDOR_SPEC3 */ writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC3) & ~CORE_PWRSAVE_DLL), host->ioaddr + CORE_VENDOR_SPEC3); /* Select the default clock (free running MCLK) */ writel_relaxed(((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) & ~CORE_HC_MCLK_SEL_MASK) Loading Loading @@ -2671,6 +2752,13 @@ static void sdhci_set_default_hw_caps(struct sdhci_msm_host *msm_host, (readl_relaxed(host->ioaddr + SDHCI_CAPABILITIES) | caps), host->ioaddr + CORE_VENDOR_SPEC_CAPABILITIES0); } /* * SDCC 5 controller with major version 1, minor version 0x34 and later * with HS 400 mode support will use CM DLL instead of CDC LP 533 DLL. */ if ((major == 1) && (minor < 0x34)) msm_host->use_cdclp533 = true; } static int sdhci_msm_probe(struct platform_device *pdev) Loading
include/linux/mmc/host.h +1 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ struct mmc_ios { unsigned int clock; /* clock rate */ unsigned int old_rate; /* saved clock rate */ unsigned short vdd; /* vdd stores the bit number of the selected voltage range from below. */ Loading