static int sdhci_msm_hs400_dll_calibration(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); int ret; u32 config; pr_debug("%s: %s: Enter\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; config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); config |= CORE_CMD_DAT_TRACK_SEL; writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); if (msm_host->use_cdclp533) ret = sdhci_msm_cdclp533_calibration(host); else ret = sdhci_msm_cm_dll_sdc4_calibration(host); out: pr_debug("%s: %s: Exit, ret %d\n", mmc_hostname(host->mmc), __func__, ret); return ret; }
static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode) { int tuning_seq_cnt = 3; u8 phase, tuned_phases[16], tuned_phase_cnt = 0; int rc; struct mmc_host *mmc = host->mmc; struct mmc_ios ios = host->mmc->ios; struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); /* * Tuning is required for SDR104, HS200 and HS400 cards and * if clock frequency is greater than 100MHz in these modes. */ if (host->clock <= CORE_FREQ_100MHZ || !(ios.timing == MMC_TIMING_MMC_HS400 || ios.timing == MMC_TIMING_MMC_HS200 || ios.timing == MMC_TIMING_UHS_SDR104)) return 0; retry: /* First of all reset the tuning block */ rc = msm_init_cm_dll(host); if (rc) return rc; phase = 0; do { /* Set the phase in delay line hw block */ rc = msm_config_cm_dll_phase(host, phase); if (rc) return rc; msm_host->saved_tuning_phase = phase; rc = mmc_send_tuning(mmc, opcode, NULL); if (!rc) { /* Tuning is successful at this tuning point */ tuned_phases[tuned_phase_cnt++] = phase; dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n", mmc_hostname(mmc), phase); } } while (++phase < ARRAY_SIZE(tuned_phases)); if (tuned_phase_cnt) { rc = msm_find_most_appropriate_phase(host, tuned_phases, tuned_phase_cnt); if (rc < 0) return rc; else phase = rc; /* * Finally set the selected phase in delay * line hw block. */ rc = msm_config_cm_dll_phase(host, phase); if (rc) return rc; dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n", mmc_hostname(mmc), phase); } else { if (--tuning_seq_cnt) goto retry; /* Tuning failed */ dev_dbg(mmc_dev(mmc), "%s: No tuning point found\n", mmc_hostname(mmc)); rc = -EIO; } if (!rc) msm_host->tuning_done = true; return rc; }
static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); u32 config, calib_done; int ret; pr_debug("%s: %s: Enter\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; config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); config |= CORE_CMD_DAT_TRACK_SEL; writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); config = readl_relaxed(host->ioaddr + CORE_DDR_200_CFG); config &= ~CORE_CDC_T4_DLY_SEL; writel_relaxed(config, host->ioaddr + CORE_DDR_200_CFG); config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_GEN_CFG); config &= ~CORE_CDC_SWITCH_BYPASS_OFF; writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_GEN_CFG); config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_GEN_CFG); config |= CORE_CDC_SWITCH_RC_EN; writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_GEN_CFG); config = readl_relaxed(host->ioaddr + CORE_DDR_200_CFG); config &= ~CORE_START_CDC_TRAFFIC; writel_relaxed(config, host->ioaddr + CORE_DDR_200_CFG); /* * Perform CDC Register Initialization Sequence * * CORE_CSR_CDC_CTLR_CFG0 0x11800EC * CORE_CSR_CDC_CTLR_CFG1 0x3011111 * CORE_CSR_CDC_CAL_TIMER_CFG0 0x1201000 * CORE_CSR_CDC_CAL_TIMER_CFG1 0x4 * CORE_CSR_CDC_REFCOUNT_CFG 0xCB732020 * CORE_CSR_CDC_COARSE_CAL_CFG 0xB19 * CORE_CSR_CDC_DELAY_CFG 0x3AC * CORE_CDC_OFFSET_CFG 0x0 * CORE_CDC_SLAVE_DDA_CFG 0x16334 */ writel_relaxed(0x11800EC, host->ioaddr + CORE_CSR_CDC_CTLR_CFG0); writel_relaxed(0x3011111, host->ioaddr + CORE_CSR_CDC_CTLR_CFG1); writel_relaxed(0x1201000, host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG0); writel_relaxed(0x4, host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG1); writel_relaxed(0xCB732020, host->ioaddr + CORE_CSR_CDC_REFCOUNT_CFG); writel_relaxed(0xB19, host->ioaddr + CORE_CSR_CDC_COARSE_CAL_CFG); writel_relaxed(0x3AC, host->ioaddr + CORE_CSR_CDC_DELAY_CFG); writel_relaxed(0x0, host->ioaddr + CORE_CDC_OFFSET_CFG); writel_relaxed(0x16334, host->ioaddr + CORE_CDC_SLAVE_DDA_CFG); /* CDC HW Calibration */ config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_CTLR_CFG0); config |= CORE_SW_TRIG_FULL_CALIB; writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_CTLR_CFG0); config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_CTLR_CFG0); config &= ~CORE_SW_TRIG_FULL_CALIB; writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_CTLR_CFG0); config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_CTLR_CFG0); config |= CORE_HW_AUTOCAL_ENA; writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_CTLR_CFG0); config = readl_relaxed(host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG0); config |= CORE_TIMER_ENA; writel_relaxed(config, host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG0); ret = readl_relaxed_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__); goto out; } ret = readl_relaxed(host->ioaddr + CORE_CSR_CDC_STATUS0) & CORE_CDC_ERROR_CODE_MASK; if (ret) { pr_err("%s: %s: CDC error code %d\n", mmc_hostname(host->mmc), __func__, ret); ret = -EINVAL; goto out; } config = readl_relaxed(host->ioaddr + CORE_DDR_200_CFG); config |= CORE_START_CDC_TRAFFIC; writel_relaxed(config, host->ioaddr + CORE_DDR_200_CFG); out: pr_debug("%s: %s: Exit, ret %d\n", mmc_hostname(host->mmc), __func__, ret); return ret; }
static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode) { int tuning_seq_cnt = 3; u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0; const u32 *tuning_block_pattern = tuning_block_64; int size = sizeof(tuning_block_64); /* Pattern size in bytes */ int rc; struct mmc_host *mmc = host->mmc; struct mmc_ios ios = host->mmc->ios; /* * Tuning is required for SDR104, HS200 and HS400 cards and * if clock frequency is greater than 100MHz in these modes. */ if (host->clock <= 100 * 1000 * 1000 || !((ios.timing == MMC_TIMING_MMC_HS200) || (ios.timing == MMC_TIMING_UHS_SDR104))) return 0; if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) && (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) { tuning_block_pattern = tuning_block_128; size = sizeof(tuning_block_128); } data_buf = kmalloc(size, GFP_KERNEL); if (!data_buf) return -ENOMEM; retry: /* First of all reset the tuning block */ rc = msm_init_cm_dll(host); if (rc) goto out; phase = 0; do { struct mmc_command cmd = { 0 }; struct mmc_data data = { 0 }; struct mmc_request mrq = { .cmd = &cmd, .data = &data }; struct scatterlist sg; /* Set the phase in delay line hw block */ rc = msm_config_cm_dll_phase(host, phase); if (rc) goto out; cmd.opcode = opcode; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; data.blksz = size; data.blocks = 1; data.flags = MMC_DATA_READ; data.timeout_ns = NSEC_PER_SEC; /* 1 second */ data.sg = &sg; data.sg_len = 1; sg_init_one(&sg, data_buf, size); memset(data_buf, 0, size); mmc_wait_for_req(mmc, &mrq); if (!cmd.error && !data.error && !memcmp(data_buf, tuning_block_pattern, size)) { /* Tuning is successful at this tuning point */ tuned_phases[tuned_phase_cnt++] = phase; dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n", mmc_hostname(mmc), phase); } } while (++phase < ARRAY_SIZE(tuned_phases)); if (tuned_phase_cnt) { rc = msm_find_most_appropriate_phase(host, tuned_phases, tuned_phase_cnt); if (rc < 0) goto out; else phase = rc; /* * Finally set the selected phase in delay * line hw block. */ rc = msm_config_cm_dll_phase(host, phase); if (rc) goto out; dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n", mmc_hostname(mmc), phase); } else { if (--tuning_seq_cnt) goto retry; /* Tuning failed */ dev_dbg(mmc_dev(mmc), "%s: No tuning point found\n", mmc_hostname(mmc)); rc = -EIO; } out: kfree(data_buf); return rc; }