コード例 #1
0
ファイル: sdhci-msm.c プロジェクト: asmalldev/linux
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;
}
コード例 #2
0
ファイル: meson_nand.c プロジェクト: avagin/linux
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;
}
コード例 #3
0
ファイル: sdhci-msm.c プロジェクト: asmalldev/linux
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();
}
コード例 #4
0
ファイル: stm32_iwdg.c プロジェクト: SantoshShilimkar/linux
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;
}
コード例 #5
0
ファイル: sdhci-msm.c プロジェクト: forgivemyheart/linux
/* 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);
}
コード例 #6
0
ファイル: sdhci-msm.c プロジェクト: forgivemyheart/linux
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;
}