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

Commit 32473be6 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "mmc: core: Add partial initialization support"

parents 2ae503d7 87592d6f
Loading
Loading
Loading
Loading
+155 −9
Original line number Diff line number Diff line
@@ -2111,7 +2111,18 @@ static int mmc_can_sleep(struct mmc_card *card)
	return (card && card->ext_csd.rev >= 3);
}

static int mmc_sleep(struct mmc_host *host)
static int mmc_can_sleepawake(struct mmc_host *host)
{
#if defined(CONFIG_SDC_QTI)
	return host && (host->caps2 & MMC_CAP2_SLEEP_AWAKE) && host->card &&
		(host->card->ext_csd.rev >= 3);
#else
	return host && host->card && (host->card->ext_csd.rev >= 3);
#endif

}

static int mmc_sleepawake(struct mmc_host *host, bool sleep)
{
	struct mmc_command cmd = {};
	struct mmc_card *card = host->card;
@@ -2121,12 +2132,15 @@ static int mmc_sleep(struct mmc_host *host)
	/* Re-tuning can't be done once the card is deselected */
	mmc_retune_hold(host);

	if (sleep) {
		err = mmc_deselect_cards(host);
		if (err)
			goto out_release;
	}

	cmd.opcode = MMC_SLEEP_AWAKE;
	cmd.arg = card->rca << 16;
	if (sleep)
		cmd.arg |= 1 << 15;

	/*
@@ -2158,6 +2172,9 @@ static int mmc_sleep(struct mmc_host *host)
	if (!cmd.busy_timeout || !(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
		mmc_delay(timeout_ms);

	if (!sleep)
		err = mmc_select_card(card);

out_release:
	mmc_retune_release(host);
	return err;
@@ -2238,6 +2255,71 @@ static void mmc_detect(struct mmc_host *host)
	}
}

static int mmc_cache_card_ext_csd(struct mmc_host *host)
{
	int err;
	u8 *ext_csd;
	struct mmc_card *card = host->card;

	err = mmc_get_ext_csd(card, &ext_csd);
	if (err || !ext_csd) {
		pr_err("%s: %s: mmc_get_ext_csd failed (%d)\n",
			mmc_hostname(host), __func__, err);
		return err;
	}
	/* only cache read/write fields that the sw changes */
#if defined(CONFIG_SDC_QTI)
	card->ext_csd.raw_ext_csd_cmdq = ext_csd[EXT_CSD_CMDQ_MODE_EN];
	card->ext_csd.raw_ext_csd_cache_ctrl = ext_csd[EXT_CSD_CACHE_CTRL];
	card->ext_csd.raw_ext_csd_bus_width = ext_csd[EXT_CSD_BUS_WIDTH];
	card->ext_csd.raw_ext_csd_hs_timing = ext_csd[EXT_CSD_HS_TIMING];
#endif

	kfree(ext_csd);

	return 0;
}

static int mmc_test_awake_ext_csd(struct mmc_host *host)
{
	int err;
	u8 *ext_csd;
	struct mmc_card *card = host->card;

	err = mmc_get_ext_csd(card, &ext_csd);
	if (err) {
		pr_err("%s: %s: mmc_get_ext_csd failed (%d)\n",
			mmc_hostname(host), __func__, err);
		return err;
	}

	/* only compare read/write fields that the sw changes */
#if defined(CONFIG_SDC_QTI)
	pr_debug("%s: %s: type(cached:current) cmdq(%d:%d) cache_ctrl(%d:%d) bus_width (%d:%d) timing(%d:%d)\n",
		mmc_hostname(host), __func__,
		card->ext_csd.raw_ext_csd_cmdq,
		ext_csd[EXT_CSD_CMDQ_MODE_EN],
		card->ext_csd.raw_ext_csd_cache_ctrl,
		ext_csd[EXT_CSD_CACHE_CTRL],
		card->ext_csd.raw_ext_csd_bus_width,
		ext_csd[EXT_CSD_BUS_WIDTH],
		card->ext_csd.raw_ext_csd_hs_timing,
		ext_csd[EXT_CSD_HS_TIMING]);
	err = !((card->ext_csd.raw_ext_csd_cmdq ==
			ext_csd[EXT_CSD_CMDQ_MODE_EN]) &&
		(card->ext_csd.raw_ext_csd_cache_ctrl ==
			ext_csd[EXT_CSD_CACHE_CTRL]) &&
		(card->ext_csd.raw_ext_csd_bus_width ==
			ext_csd[EXT_CSD_BUS_WIDTH]) &&
		(card->ext_csd.raw_ext_csd_hs_timing ==
			ext_csd[EXT_CSD_HS_TIMING]));
#endif

	kfree(ext_csd);

	return err;
}

static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
{
	int err = 0;
@@ -2264,8 +2346,14 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
	if (mmc_can_poweroff_notify(host->card) &&
		((host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) || !is_suspend))
		err = mmc_poweroff_notify(host->card, notify_type);
	else if (mmc_can_sleep(host->card))
		err = mmc_sleep(host);
	if (mmc_can_sleepawake(host)) {
#if defined(CONFIG_SDC_QTI)
		memcpy(&host->cached_ios, &host->ios, sizeof(host->cached_ios));
#endif
		mmc_cache_card_ext_csd(host);
	}
	if (mmc_can_sleep(host->card))
		err = mmc_sleepawake(host, true);
	else if (!mmc_host_is_spi(host))
		err = mmc_deselect_cards(host);

@@ -2284,6 +2372,52 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
	return err;
}

static int mmc_partial_init(struct mmc_host *host)
{
	int err = 0;
	struct mmc_card *card = host->card;

#if defined(CONFIG_SDC_QTI)
	mmc_set_bus_width(host, host->cached_ios.bus_width);
	mmc_set_timing(host, host->cached_ios.timing);
	if (host->cached_ios.enhanced_strobe) {
#endif
		host->ios.enhanced_strobe = true;
		if (host->ops->hs400_enhanced_strobe)
			host->ops->hs400_enhanced_strobe(host, &host->ios);
#if defined(CONFIG_SDC_QTI)
	}
	mmc_set_clock(host, host->cached_ios.clock);
	mmc_set_bus_mode(host, host->cached_ios.bus_mode);
#endif

	if (!mmc_card_hs400es(card) &&
			(mmc_card_hs200(card) || mmc_card_hs400(card))) {
		err = mmc_execute_tuning(card);
		if (err) {
			pr_err("%s: %s: Tuning failed (%d)\n",
				mmc_hostname(host), __func__, err);
			goto out;
		}
	}
	/*
	 * The ext_csd is read to make sure the card did not went through
	 * Power-failure during sleep period.
	 * A subset of the W/E_P, W/C_P register will be tested. In case
	 * these registers values are different from the values that were
	 * cached during suspend, we will conclude that a Power-failure occurred
	 * and will do full initialization sequence.
	 */
	err = mmc_test_awake_ext_csd(host);
	if (err) {
		pr_debug("%s: %s: fail on ext_csd read (%d)\n",
			mmc_hostname(host), __func__, err);
		goto out;
	}
out:
	return err;
}

/*
 * Suspend callback
 */
@@ -2306,7 +2440,7 @@ static int mmc_suspend(struct mmc_host *host)
 */
static int _mmc_resume(struct mmc_host *host)
{
	int err = 0;
	int err = -EINVAL;

	mmc_claim_host(host);

@@ -2323,7 +2457,19 @@ static int _mmc_resume(struct mmc_host *host)

	mmc_log_string(host, "Enter\n");
	mmc_power_up(host, host->card->ocr);

	if (mmc_can_sleepawake(host)) {
		err = mmc_sleepawake(host, false);
		if (!err)
			err = mmc_partial_init(host);
		else
			pr_err("%s: %s: awake failed (%d), fallback to full init\n",
				mmc_hostname(host), __func__, err);
	}

	if (err)
		err = mmc_init_card(host, host->card->ocr, host->card);

	mmc_card_clr_suspended(host->card);

#if !defined(CONFIG_SDC_QTI)
+10 −0
Original line number Diff line number Diff line
@@ -85,6 +85,10 @@ struct mmc_ext_csd {
	unsigned int            data_tag_unit_size;     /* DATA TAG UNIT size */
	unsigned int		boot_ro_lock;		/* ro lock support */
	bool			boot_ro_lockable;
#if defined(CONFIG_SDC_QTI)
	u8			raw_ext_csd_cmdq;	/* 15 */
	u8			raw_ext_csd_cache_ctrl;	/* 33 */
#endif
	bool			ffu_capable;	/* Firmware upgrade support */
	bool			cmdq_en;	/* Command Queue enabled */
	bool			cmdq_support;	/* Command Queue supported */
@@ -95,7 +99,13 @@ struct mmc_ext_csd {
	u8			raw_partition_support;	/* 160 */
	u8			raw_rpmb_size_mult;	/* 168 */
	u8			raw_erased_mem_count;	/* 181 */
#if defined(CONFIG_SDC_QTI)
	u8			raw_ext_csd_bus_width;	/* 183 */
#endif
	u8			strobe_support;		/* 184 */
#if defined(CONFIG_SDC_QTI)
	u8			raw_ext_csd_hs_timing;	/* 185 */
#endif
	u8			raw_ext_csd_structure;	/* 194 */
	u8			raw_card_type;		/* 196 */
	u8			raw_driver_strength;	/* 197 */
+4 −0
Original line number Diff line number Diff line
@@ -479,6 +479,7 @@ struct mmc_host {
#define MMC_CAP2_CRYPTO		(1 << 27)	/* Host supports inline encryption */
#if defined(CONFIG_SDC_QTI)
#define MMC_CAP2_CLK_SCALE      (1 << 28)       /* Allow dynamic clk scaling */
#define MMC_CAP2_SLEEP_AWAKE	(1 << 29)	/* Use Sleep/Awake (CMD5) */
#endif

	int			fixed_drv_type;	/* fixed driver type for non-removable media */
@@ -498,6 +499,9 @@ struct mmc_host {
	spinlock_t		lock;		/* lock for claim and bus ops */

	struct mmc_ios		ios;		/* current io bus settings */
#if defined(CONFIG_SDC_QTI)
	struct mmc_ios		cached_ios;
#endif

	/* group bitfields together to minimize padding */
	unsigned int		use_spi_crc:1;