Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 09d44748 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "mmc: sdhci-msm: Add hs400 enhanced strobe mode support to host"

parents 02af2598 a852fd70
Loading
Loading
Loading
Loading
+49 −7
Original line number Original line Diff line number Diff line
@@ -652,6 +652,11 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
	}
	}


	if (card->ext_csd.rev >= 7) {
	if (card->ext_csd.rev >= 7) {
		/* Enhance Strobe is supported since v5.1 which rev should be
		 * 8 but some eMMC devices can support it with rev 7. So handle
		 * Enhance Strobe here.
		 */
		card->ext_csd.strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT];
		card->ext_csd.cmdq_support = ext_csd[EXT_CSD_CMDQ_SUPPORT];
		card->ext_csd.cmdq_support = ext_csd[EXT_CSD_CMDQ_SUPPORT];
		if (card->ext_csd.cmdq_support) {
		if (card->ext_csd.cmdq_support) {
			/*
			/*
@@ -1100,13 +1105,33 @@ static int mmc_select_hs400(struct mmc_card *card)
{
{
	struct mmc_host *host = card->host;
	struct mmc_host *host = card->host;
	int err = 0;
	int err = 0;
	u8 val;


	/*
	/*
	 * HS400 mode requires 8-bit bus width
	 * HS400 mode requires 8-bit bus width
	 */
	 */
	if (card->ext_csd.strobe_support) {
		if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
		    host->caps & MMC_CAP_8_BIT_DATA))
			return 0;

		/* For Enhance Strobe flow. For non Enhance Strobe, signal
		 * voltage will not be set.
		 */
		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
			err = __mmc_set_signal_voltage(host,
					MMC_SIGNAL_VOLTAGE_120);

		if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
			err = __mmc_set_signal_voltage(host,
					MMC_SIGNAL_VOLTAGE_180);
		if (err)
			return err;
	} else {
		if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
		if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
		    host->ios.bus_width == MMC_BUS_WIDTH_8))
		    host->ios.bus_width == MMC_BUS_WIDTH_8))
			return 0;
			return 0;
	}


	/*
	/*
	 * Before switching to dual data rate operation for HS400,
	 * Before switching to dual data rate operation for HS400,
@@ -1125,9 +1150,16 @@ static int mmc_select_hs400(struct mmc_card *card)
		return err;
		return err;
	}
	}


	val = EXT_CSD_DDR_BUS_WIDTH_8;
	if (card->ext_csd.strobe_support) {
		err = mmc_select_bus_width(card);
		if (IS_ERR_VALUE(err))
			return err;
		val |= EXT_CSD_BUS_WIDTH_STROBE;
	}
	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
			 EXT_CSD_BUS_WIDTH,
			 EXT_CSD_BUS_WIDTH,
			 EXT_CSD_DDR_BUS_WIDTH_8,
			 val,
			 card->ext_csd.generic_cmd6_time);
			 card->ext_csd.generic_cmd6_time);
	if (err) {
	if (err) {
		pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
		pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
@@ -1148,7 +1180,12 @@ static int mmc_select_hs400(struct mmc_card *card)
	mmc_set_timing(host, MMC_TIMING_MMC_HS400);
	mmc_set_timing(host, MMC_TIMING_MMC_HS400);
	mmc_set_bus_speed(card);
	mmc_set_bus_speed(card);


	if ((host->caps2 & MMC_CAP2_HS400_POST_TUNING) && host->ops->execute_tuning) {
	if (host->ops->enhanced_strobe) {
		mmc_host_clk_hold(host);
		err = host->ops->enhanced_strobe(host);
		mmc_host_clk_release(host);
	} else if ((host->caps2 & MMC_CAP2_HS400_POST_TUNING) &&
			host->ops->execute_tuning) {
		mmc_host_clk_hold(host);
		mmc_host_clk_hold(host);
		err = host->ops->execute_tuning(host,
		err = host->ops->execute_tuning(host,
				MMC_SEND_TUNING_BLOCK_HS200);
				MMC_SEND_TUNING_BLOCK_HS200);
@@ -1159,7 +1196,7 @@ static int mmc_select_hs400(struct mmc_card *card)
				mmc_hostname(host));
				mmc_hostname(host));
	}
	}


	return 0;
	return err;
}
}


/*
/*
@@ -1225,7 +1262,12 @@ static int mmc_select_timing(struct mmc_card *card)
	if (!mmc_can_ext_csd(card))
	if (!mmc_can_ext_csd(card))
		goto bus_speed;
		goto bus_speed;


	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
	/* For Enhance Strobe HS400 flow */
	if (card->ext_csd.strobe_support &&
	    card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
	    card->host->caps & MMC_CAP_8_BIT_DATA)
		err = mmc_select_hs400(card);
	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
		err = mmc_select_hs200(card);
		err = mmc_select_hs200(card);
	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
		err = mmc_select_hs(card);
		err = mmc_select_hs(card);
+50 −2
Original line number Original line Diff line number Diff line
@@ -151,7 +151,9 @@


#define CORE_DDR_200_CFG		0x184
#define CORE_DDR_200_CFG		0x184
#define CORE_CDC_T4_DLY_SEL		(1 << 0)
#define CORE_CDC_T4_DLY_SEL		(1 << 0)
#define CORE_CMDIN_RCLK_EN		(1 << 1)
#define CORE_START_CDC_TRAFFIC		(1 << 6)
#define CORE_START_CDC_TRAFFIC		(1 << 6)

#define CORE_VENDOR_SPEC3	0x1B0
#define CORE_VENDOR_SPEC3	0x1B0
#define CORE_PWRSAVE_DLL	(1 << 3)
#define CORE_PWRSAVE_DLL	(1 << 3)


@@ -771,6 +773,11 @@ static int sdhci_msm_cm_dll_sdc4_calibration(struct sdhci_host *host)
	 */
	 */
	writel_relaxed(DDR_CONFIG_POR_VAL, host->ioaddr + CORE_DDR_CONFIG);
	writel_relaxed(DDR_CONFIG_POR_VAL, host->ioaddr + CORE_DDR_CONFIG);


	if (msm_host->enhanced_strobe)
		writel_relaxed((readl_relaxed(host->ioaddr + CORE_DDR_200_CFG)
				| CORE_CMDIN_RCLK_EN),
				host->ioaddr + CORE_DDR_200_CFG);

	/* Write 1 to DDR_CAL_EN field in CORE_DLL_CONFIG_2 */
	/* Write 1 to DDR_CAL_EN field in CORE_DLL_CONFIG_2 */
	writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2)
	writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2)
			| CORE_DDR_CAL_EN),
			| CORE_DDR_CAL_EN),
@@ -805,6 +812,42 @@ out:
	return ret;
	return ret;
}
}


static int sdhci_msm_enhanced_strobe(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;
	struct mmc_host *mmc = host->mmc;

	pr_debug("%s: Enter %s\n", mmc_hostname(host->mmc), __func__);

	if (!msm_host->enhanced_strobe) {
		pr_debug("%s: host does not support hs400 enhanced strobe\n",
				mmc_hostname(mmc));
		return -EINVAL;
	}

	if (msm_host->calibration_done ||
		!(mmc->ios.timing == MMC_TIMING_MMC_HS400)) {
		return 0;
	}

	/*
	 * Reset the tuning block.
	 */
	ret = msm_init_cm_dll(host);
	if (ret)
		goto out;

	ret = sdhci_msm_cm_dll_sdc4_calibration(host);
out:
	if (!ret)
		msm_host->calibration_done = true;
	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)
static int sdhci_msm_hs400_dll_calibration(struct sdhci_host *host)
{
{
	int ret = 0;
	int ret = 0;
@@ -2543,7 +2586,8 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
		 * Select HS400 mode using the HC_SELECT_IN from VENDOR SPEC
		 * Select HS400 mode using the HC_SELECT_IN from VENDOR SPEC
		 * register
		 * register
		 */
		 */
		if (msm_host->tuning_done && !msm_host->calibration_done) {
		if ((msm_host->tuning_done || msm_host->enhanced_strobe) &&
			!msm_host->calibration_done) {
			/*
			/*
			 * Write 0x6 to HC_SELECT_IN and 1 to HC_SELECT_IN_EN
			 * Write 0x6 to HC_SELECT_IN and 1 to HC_SELECT_IN_EN
			 * field in VENDOR_SPEC_FUNC
			 * field in VENDOR_SPEC_FUNC
@@ -2772,6 +2816,7 @@ static struct sdhci_ops sdhci_msm_ops = {
	.set_uhs_signaling = sdhci_msm_set_uhs_signaling,
	.set_uhs_signaling = sdhci_msm_set_uhs_signaling,
	.check_power_status = sdhci_msm_check_power_status,
	.check_power_status = sdhci_msm_check_power_status,
	.platform_execute_tuning = sdhci_msm_execute_tuning,
	.platform_execute_tuning = sdhci_msm_execute_tuning,
	.enhanced_strobe = sdhci_msm_enhanced_strobe,
	.toggle_cdr = sdhci_msm_toggle_cdr,
	.toggle_cdr = sdhci_msm_toggle_cdr,
	.get_max_segments = sdhci_msm_max_segs,
	.get_max_segments = sdhci_msm_max_segs,
	.set_clock = sdhci_msm_set_clock,
	.set_clock = sdhci_msm_set_clock,
@@ -2829,9 +2874,12 @@ static void sdhci_set_default_hw_caps(struct sdhci_msm_host *msm_host,
	/*
	/*
	 * SDCC 5 controller with major version 1, minor version 0x42 and later
	 * SDCC 5 controller with major version 1, minor version 0x42 and later
	 * will require additional steps when resetting DLL.
	 * will require additional steps when resetting DLL.
	 * It also supports HS400 enhanced strobe mode.
	 */
	 */
	if ((major == 1) && (minor >= 0x42))
	if ((major == 1) && (minor >= 0x42)) {
		msm_host->use_updated_dll_reset = true;
		msm_host->use_updated_dll_reset = true;
		msm_host->enhanced_strobe = true;
	}


	/*
	/*
	 * SDCC 5 controller with major version 1 and minor version 0x42,
	 * SDCC 5 controller with major version 1 and minor version 0x42,
+1 −0
Original line number Original line Diff line number Diff line
@@ -154,6 +154,7 @@ struct sdhci_msm_host {
	bool use_cdclp533;
	bool use_cdclp533;
	bool use_updated_dll_reset;
	bool use_updated_dll_reset;
	bool use_14lpp_dll;
	bool use_14lpp_dll;
	bool enhanced_strobe;
	u32 caps_0;
	u32 caps_0;
	struct sdhci_msm_ice_data ice;
	struct sdhci_msm_ice_data ice;
	u32 ice_clk_rate;
	u32 ice_clk_rate;
+15 −0
Original line number Original line Diff line number Diff line
@@ -60,6 +60,7 @@ static void sdhci_finish_data(struct sdhci_host *);


static void sdhci_finish_command(struct sdhci_host *);
static void sdhci_finish_command(struct sdhci_host *);
static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
static int sdhci_enhanced_strobe(struct mmc_host *mmc);
static void sdhci_tuning_timer(unsigned long data);
static void sdhci_tuning_timer(unsigned long data);
static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
static void sdhci_show_adma_error(struct sdhci_host *host);
static void sdhci_show_adma_error(struct sdhci_host *host);
@@ -2274,6 +2275,19 @@ static int sdhci_card_busy(struct mmc_host *mmc)
	return !(present_state & SDHCI_DATA_LVL_MASK);
	return !(present_state & SDHCI_DATA_LVL_MASK);
}
}


static int sdhci_enhanced_strobe(struct mmc_host *mmc)
{
	struct sdhci_host *host = mmc_priv(mmc);
	int err = 0;

	sdhci_runtime_pm_get(host);
	if (host->ops->enhanced_strobe)
		err = host->ops->enhanced_strobe(host);
	sdhci_runtime_pm_put(host);

	return err;
}

static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
{
{
	struct sdhci_host *host = mmc_priv(mmc);
	struct sdhci_host *host = mmc_priv(mmc);
@@ -2539,6 +2553,7 @@ static const struct mmc_host_ops sdhci_ops = {
	.enable_sdio_irq = sdhci_enable_sdio_irq,
	.enable_sdio_irq = sdhci_enable_sdio_irq,
	.start_signal_voltage_switch	= sdhci_start_signal_voltage_switch,
	.start_signal_voltage_switch	= sdhci_start_signal_voltage_switch,
	.execute_tuning			= sdhci_execute_tuning,
	.execute_tuning			= sdhci_execute_tuning,
	.enhanced_strobe		= sdhci_enhanced_strobe,
	.card_event			= sdhci_card_event,
	.card_event			= sdhci_card_event,
	.card_busy	= sdhci_card_busy,
	.card_busy	= sdhci_card_busy,
	.enable		= sdhci_enable,
	.enable		= sdhci_enable,
+1 −0
Original line number Original line Diff line number Diff line
@@ -320,6 +320,7 @@ struct sdhci_ops {
#define REQ_IO_LOW	(1 << 2)
#define REQ_IO_LOW	(1 << 2)
#define REQ_IO_HIGH	(1 << 3)
#define REQ_IO_HIGH	(1 << 3)
	void    (*card_event)(struct sdhci_host *host);
	void    (*card_event)(struct sdhci_host *host);
	int	(*enhanced_strobe)(struct sdhci_host *host);
	void	(*platform_bus_voting)(struct sdhci_host *host, u32 enable);
	void	(*platform_bus_voting)(struct sdhci_host *host, u32 enable);
	void	(*dump_vendor_regs)(struct sdhci_host *host);
	void	(*dump_vendor_regs)(struct sdhci_host *host);
	int	(*config_auto_tuning_cmd)(struct sdhci_host *host,
	int	(*config_auto_tuning_cmd)(struct sdhci_host *host,
Loading