static int sdhci_msm_cm_dll_sdc4_calibration(struct sdhci_host *host) { struct mmc_host *mmc = host->mmc; u32 dll_status, config; int ret; pr_debug("%s: %s: Enter\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); if (mmc->ios.enhanced_strobe) { config = readl_relaxed(host->ioaddr + CORE_DDR_200_CFG); config |= CORE_CMDIN_RCLK_EN; writel_relaxed(config, host->ioaddr + CORE_DDR_200_CFG); } config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2); config |= CORE_DDR_CAL_EN; writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG_2); ret = readl_relaxed_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; } config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC3); config |= CORE_PWRSAVE_DLL; writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC3); /* * Drain writebuffer to ensure above DLL calibration * and PWRSAVE DLL is enabled. */ wmb(); out: pr_debug("%s: %s: Exit, ret %d\n", mmc_hostname(host->mmc), __func__, ret); return ret; }
static int meson_nfc_wait_cmd_finish(struct meson_nfc *nfc, unsigned int timeout_ms) { u32 cmd_size = 0; int ret; /* wait cmd fifo is empty */ ret = readl_relaxed_poll_timeout(nfc->reg_base + NFC_REG_CMD, cmd_size, !NFC_CMD_GET_SIZE(cmd_size), 10, timeout_ms * 1000); if (ret) dev_err(nfc->dev, "wait for empty CMD FIFO time out\n"); return ret; }
static void msm_hc_select_hs400(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); struct mmc_ios ios = host->mmc->ios; u32 config, dll_lock; int rc; /* Select the divided clock (free running MCLK/2) */ config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); config &= ~CORE_HC_MCLK_SEL_MASK; config |= CORE_HC_MCLK_SEL_HS400; writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC); /* * Select HS400 mode using the HC_SELECT_IN from VENDOR SPEC * register */ if ((msm_host->tuning_done || ios.enhanced_strobe) && !msm_host->calibration_done) { config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); config |= CORE_HC_SELECT_IN_HS400; config |= CORE_HC_SELECT_IN_EN; writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC); } if (!msm_host->clk_rate && !msm_host->use_cdclp533) { /* * Poll on DLL_LOCK or DDR_DLL_LOCK bits in * CORE_DLL_STATUS to be set. This should get set * within 15 us at 200 MHz. */ rc = readl_relaxed_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); } /* * Make sure above writes impacting free running MCLK are completed * before changing the clk_rate at GCC. */ wmb(); }
static int stm32_iwdg_start(struct watchdog_device *wdd) { struct stm32_iwdg *wdt = watchdog_get_drvdata(wdd); u32 val = FLAG_PVU | FLAG_RVU; u32 reload; int ret; dev_dbg(wdd->parent, "%s\n", __func__); /* prescaler fixed to 256 */ reload = clamp_t(unsigned int, ((wdd->timeout * wdt->rate) / 256) - 1, RLR_MIN, RLR_MAX); /* enable write access */ reg_write(wdt->regs, IWDG_KR, KR_KEY_EWA); /* set prescaler & reload registers */ reg_write(wdt->regs, IWDG_PR, PR_256); /* prescaler fix to 256 */ reg_write(wdt->regs, IWDG_RLR, reload); reg_write(wdt->regs, IWDG_KR, KR_KEY_ENABLE); /* wait for the registers to be updated (max 100ms) */ ret = readl_relaxed_poll_timeout(wdt->regs + IWDG_SR, val, !(val & (FLAG_PVU | FLAG_RVU)), SLEEP_US, TIMEOUT_US); if (ret) { dev_err(wdd->parent, "Fail to set prescaler or reload registers\n"); return ret; } /* reload watchdog */ reg_write(wdt->regs, IWDG_KR, KR_KEY_RELOAD); return 0; }
/* sdhci_msm_set_clock - Called with (host->lock) spinlock held. */ 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 = sdhci_pltfm_priv(pltfm_host); struct mmc_ios curr_ios = host->mmc->ios; u32 config, dll_lock; int rc; if (!clock) { msm_host->clk_rate = clock; goto out; } spin_unlock_irq(&host->lock); /* * The SDHC requires internal clock frequency to be double the * actual clock that will be set for DDR mode. The controller * uses the faster clock(100/400MHz) for some of its parts and * send the actual required clock (50/200MHz) to the card. */ if (curr_ios.timing == MMC_TIMING_UHS_DDR50 || curr_ios.timing == MMC_TIMING_MMC_DDR52 || curr_ios.timing == MMC_TIMING_MMC_HS400) clock *= 2; /* * In general all timing modes are controlled via UHS mode select in * Host Control2 register. eMMC specific HS200/HS400 doesn't have * their respective modes defined here, hence we use these values. * * HS200 - SDR104 (Since they both are equivalent in functionality) * HS400 - This involves multiple configurations * Initially SDR104 - when tuning is required as HS200 * Then when switching to DDR @ 400MHz (HS400) we use * the vendor specific HC_SELECT_IN to control the mode. * * In addition to controlling the modes we also need to select the * correct input clock for DLL depending on the mode. * * HS400 - divided clock (free running MCLK/2) * All other modes - default (free running MCLK) */ if (curr_ios.timing == MMC_TIMING_MMC_HS400) { /* Select the divided clock (free running MCLK/2) */ config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); config &= ~CORE_HC_MCLK_SEL_MASK; config |= CORE_HC_MCLK_SEL_HS400; writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC); /* * Select HS400 mode using the HC_SELECT_IN from VENDOR SPEC * register */ if (msm_host->tuning_done && !msm_host->calibration_done) { /* * Write 0x6 to HC_SELECT_IN and 1 to HC_SELECT_IN_EN * field in VENDOR_SPEC_FUNC */ config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); config |= CORE_HC_SELECT_IN_HS400; config |= CORE_HC_SELECT_IN_EN; writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC); } if (!msm_host->clk_rate && !msm_host->use_cdclp533) { /* * Poll on DLL_LOCK or DDR_DLL_LOCK bits in * CORE_DLL_STATUS to be set. This should get set * within 15 us at 200 MHz. */ rc = readl_relaxed_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) { config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC3); config &= ~CORE_PWRSAVE_DLL; writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC3); } config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); config &= ~CORE_HC_MCLK_SEL_MASK; config |= CORE_HC_MCLK_SEL_DFLT; writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC); /* * Disable HC_SELECT_IN to be able to use the UHS mode select * configuration from Host Control2 register for all other * modes. * Write 0 to HC_SELECT_IN and HC_SELECT_IN_EN field * in VENDOR_SPEC_FUNC */ config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); config &= ~CORE_HC_SELECT_IN_EN; config &= ~CORE_HC_SELECT_IN_MASK; writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC); } /* * Make sure above writes impacting free running MCLK are completed * before changing the clk_rate at GCC. */ wmb(); rc = clk_set_rate(msm_host->clk, clock); if (rc) { pr_err("%s: Failed to set clock at rate %u at timing %d\n", mmc_hostname(host->mmc), clock, curr_ios.timing); goto out_lock; } msm_host->clk_rate = clock; pr_debug("%s: Setting clock at rate %lu at timing %d\n", mmc_hostname(host->mmc), clk_get_rate(msm_host->clk), curr_ios.timing); out_lock: spin_lock_irq(&host->lock); out: __sdhci_msm_set_clock(host, clock); }
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; }