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

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

Merge "mmc: core: Set reset done after hw reset"

parents 8112827a 29fc96a5
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -1543,7 +1543,6 @@ void mmc_blk_cqe_recovery(struct mmc_queue *mq)
	err = mmc_cqe_recovery(host);
	if (err)
		mmc_blk_reset(mq->blkdata, host, MMC_BLK_CQE_RECOVERY);
	else
	mmc_blk_reset_success(mq->blkdata, MMC_BLK_CQE_RECOVERY);

	pr_debug("%s: CQE recovery done\n", mmc_hostname(host));
+2 −0
Original line number Diff line number Diff line
@@ -420,6 +420,8 @@ void mmc_remove_card(struct mmc_card *card)
		device_del(&card->dev);
		of_node_put(card->dev.of_node);
	}
	if (host->ops->exit_dbg_mode)
		host->ops->exit_dbg_mode(host);

	put_device(&card->dev);
}
+9 −2
Original line number Diff line number Diff line
@@ -2304,6 +2304,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,

	if (!oldcard)
		host->card = card;
	if (host->ops->enter_dbg_mode)
		host->ops->enter_dbg_mode(host);

	return 0;

@@ -2907,6 +2909,11 @@ static int _mmc_hw_reset(struct mmc_host *host)
		/* If the card accept RST_n signal, send it. */
		mmc_set_clock(host, host->f_init);
		host->ops->hw_reset(host);
		/*
		 * Do a brute force power cycle as some controller do not
		 * have gpio support to power cycle card
		 */
		mmc_power_cycle(host, card->ocr);
		/* Set initial state and call mmc_set_ios */
		mmc_set_initial_state(host);
	} else {
@@ -2933,9 +2940,9 @@ static int _mmc_hw_reset(struct mmc_host *host)
		return ret;
	}

	ret = mmc_suspend_clk_scaling(host);
	ret = mmc_resume_clk_scaling(host);
	if (ret) {
		pr_err("%s: %s: fail to suspend clock scaling (%d)\n",
		pr_err("%s: %s: fail to resume clock scaling (%d)\n",
				mmc_hostname(host), __func__, ret);
	}
	return ret;
+9 −2
Original line number Diff line number Diff line
@@ -901,14 +901,21 @@ irqreturn_t cqhci_irq(struct mmc_host *mmc, u32 intmask, int cmd_error,
	struct cqhci_host *cq_host = mmc->cqe_private;

	status = cqhci_readl(cq_host, CQHCI_IS);
	cqhci_writel(cq_host, status, CQHCI_IS);

	pr_debug("%s: cqhci: IRQ status: 0x%08x\n", mmc_hostname(mmc), status);
	mmc_log_string(mmc, "CQIS: 0x%x cmd_error : %d data_err: %d\n",
		status, cmd_error, data_error);

	if ((status & CQHCI_IS_RED) || cmd_error || data_error)
	if ((status & CQHCI_IS_RED) || cmd_error || data_error) {
		pr_err("%s: cqhci: error IRQ status: 0x%08x cmd error %d data error %d\n",
			mmc_hostname(mmc), status, cmd_error, data_error);
		cqhci_dumpregs(cq_host);
		cqhci_writel(cq_host, status, CQHCI_IS);
		cqhci_error_irq(mmc, status, cmd_error, data_error);
	} else {
		/* Clear interrupt */
		cqhci_writel(cq_host, status, CQHCI_IS);
	}

	if (status & CQHCI_IS_TCC) {
		/* read TCN and complete the request */
+238 −3
Original line number Diff line number Diff line
@@ -1206,6 +1206,78 @@ static void sdhci_msm_set_mmc_drv_type(struct sdhci_host *host, u32 opcode,
			drv_type);
}

#define IPCAT_MINOR_MASK(val) ((val & 0x0fff0000) >> 0x10)

/* Enter sdcc debug mode */
void sdhci_msm_enter_dbg_mode(struct sdhci_host *host)
{
	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
	struct sdhci_msm_host *msm_host = pltfm_host->priv;
	struct platform_device *pdev = msm_host->pdev;
	u32 enable_dbg_feature = 0;
	u32 minor;

	minor = IPCAT_MINOR_MASK(readl_relaxed(host->ioaddr +
				SDCC_IP_CATALOG));
	if (minor < 2 || msm_host->debug_mode_enabled)
		return;

	/* Enable debug mode */
	writel_relaxed(ENABLE_DBG,
			host->ioaddr + SDCC_TESTBUS_CONFIG);
	writel_relaxed(DUMMY,
			host->ioaddr + SDCC_DEBUG_EN_DIS_REG);
	writel_relaxed((readl_relaxed(host->ioaddr +
			SDCC_TESTBUS_CONFIG) | TESTBUS_EN),
			host->ioaddr + SDCC_TESTBUS_CONFIG);

	if (minor >= 2)
		enable_dbg_feature |= FSM_HISTORY |
			AUTO_RECOVERY_DISABLE |
			MM_TRIGGER_DISABLE |
			IIB_EN;

	/* Enable particular feature */
	writel_relaxed((readl_relaxed(host->ioaddr +
			SDCC_DEBUG_FEATURE_CFG_REG) | enable_dbg_feature),
			host->ioaddr + SDCC_DEBUG_FEATURE_CFG_REG);

	/* Read back to ensure write went through */
	readl_relaxed(host->ioaddr +
			SDCC_DEBUG_FEATURE_CFG_REG);
	msm_host->debug_mode_enabled = true;

	dev_info(&pdev->dev, "Debug feature enabled 0x%08x\n",
			readl_relaxed(host->ioaddr +
			SDCC_DEBUG_FEATURE_CFG_REG));
}

/* Exit sdcc debug mode */
void sdhci_msm_exit_dbg_mode(struct sdhci_host *host)
{
	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
	struct sdhci_msm_host *msm_host = pltfm_host->priv;
	struct platform_device *pdev = msm_host->pdev;
	u32 minor;

	minor = IPCAT_MINOR_MASK(readl_relaxed(host->ioaddr +
				SDCC_IP_CATALOG));
	if (minor < 2 || !msm_host->debug_mode_enabled)
		return;

	/* Exit debug mode */
	writel_relaxed(DISABLE_DBG,
			host->ioaddr + SDCC_TESTBUS_CONFIG);
	writel_relaxed(DUMMY,
			host->ioaddr + SDCC_DEBUG_EN_DIS_REG);

	msm_host->debug_mode_enabled = false;

	dev_dbg(&pdev->dev, "Debug feature disabled 0x%08x\n",
			readl_relaxed(host->ioaddr +
			SDCC_DEBUG_FEATURE_CFG_REG));
}

int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
{
	unsigned long flags;
@@ -1240,6 +1312,7 @@ int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
	 */
	if (msm_host->tuning_in_progress)
		return 0;
	sdhci_msm_exit_dbg_mode(host);
	msm_host->tuning_in_progress = true;
	pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);

@@ -1433,6 +1506,7 @@ int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
kfree:
	kfree(data_buf);
out:
	sdhci_msm_enter_dbg_mode(host);
	spin_lock_irqsave(&host->lock, flags);
	if (!rc)
		msm_host->tuning_done = true;
@@ -1980,6 +2054,23 @@ static int sdhci_msm_dt_parse_hsr_info(struct device *dev,
	return ret;
}

int sdhci_msm_parse_reset_data(struct device *dev,
			struct sdhci_msm_host *msm_host)
{
	int ret = 0;

	msm_host->core_reset = devm_reset_control_get(dev,
					"core_reset");
	if (IS_ERR(msm_host->core_reset)) {
		ret = PTR_ERR(msm_host->core_reset);
		dev_err(dev, "core_reset unavailable,err = %d\n",
				ret);
		msm_host->core_reset = NULL;
	}

	return ret;
}

/* Parse platform data */
static
struct sdhci_msm_pltfm_data *sdhci_msm_populate_pdata(struct device *dev,
@@ -1997,6 +2088,7 @@ struct sdhci_msm_pltfm_data *sdhci_msm_populate_pdata(struct device *dev,
	enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
	int bus_clk_table_len;
	u32 *bus_clk_table = NULL;
	int ret = 0;

	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
	if (!pdata)
@@ -2150,6 +2242,9 @@ struct sdhci_msm_pltfm_data *sdhci_msm_populate_pdata(struct device *dev,

	if (sdhci_msm_dt_parse_hsr_info(dev, msm_host))
		goto out;
	ret = sdhci_msm_parse_reset_data(dev, msm_host);
	if (ret)
		dev_err(dev, "Reset data parsing error\n");

	return pdata;
out:
@@ -2240,11 +2335,21 @@ static u32 sdhci_msm_cqe_irq(struct sdhci_host *host, u32 intmask)
{
	int cmd_error = 0;
	int data_error = 0;
	u32 mask;

	if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error))
		return intmask;

	cqhci_irq(host->mmc, intmask, cmd_error, data_error);

	/*
	 * Clear selected interrupts in err case.
	 * as earlier driver skipped
	 */
	if (data_error || cmd_error) {
		mask = intmask & host->cqe_ier;
		sdhci_writel(host, mask, SDHCI_INT_STATUS);
	}
	return 0;
}

@@ -3235,7 +3340,8 @@ static void sdhci_msm_registers_save(struct sdhci_host *host)
	const struct sdhci_msm_offset *msm_host_offset =
					msm_host->offset;

	if (!msm_host->regs_restore.is_supported)
	if (!msm_host->regs_restore.is_supported &&
			!msm_host->reg_store)
		return;

	msm_host->regs_restore.vendor_func = readl_relaxed(host->ioaddr +
@@ -3299,8 +3405,9 @@ static void sdhci_msm_registers_restore(struct sdhci_host *host)
					msm_host->offset;
	struct mmc_ios ios = host->mmc->ios;

	if (!msm_host->regs_restore.is_supported ||
		!msm_host->regs_restore.is_valid)
	if ((!msm_host->regs_restore.is_supported ||
		!msm_host->regs_restore.is_valid) &&
		!msm_host->reg_store)
		return;

	writel_relaxed(0, host->ioaddr + msm_host_offset->CORE_PWRCTL_MASK);
@@ -3957,6 +4064,73 @@ static void sdhci_msm_cqe_dump_debug_ram(struct sdhci_host *host)
	pr_err("-------------------------\n");
}

#define DUMP_FSM readl_relaxed(host->ioaddr + SDCC_DEBUG_FSM_TRACE_RD_REG)
#define MAX_FSM 16

void sdhci_msm_dump_fsm_history(struct sdhci_host *host)
{
	u32 sel_fsm;

	pr_err("----------- FSM REGISTER DUMP -----------\n");
	/* select fsm to dump */
	for (sel_fsm = 0; sel_fsm <= MAX_FSM; sel_fsm++) {
		writel_relaxed(sel_fsm, host->ioaddr +
				SDCC_DEBUG_FSM_TRACE_CFG_REG);
		pr_err(": selected fsm is 0x%08x\n",
				readl_relaxed(host->ioaddr +
				SDCC_DEBUG_FSM_TRACE_CFG_REG));
		/* dump selected fsm history */
		pr_err("0x%08x 0x%08x 0x%08x 0x%08x\n",
				readl_relaxed(host->ioaddr +
					SDCC_DEBUG_FSM_TRACE_RD_REG),
				readl_relaxed(host->ioaddr +
					SDCC_DEBUG_FSM_TRACE_RD_REG),
				readl_relaxed(host->ioaddr +
					SDCC_DEBUG_FSM_TRACE_RD_REG),
				readl_relaxed(host->ioaddr +
					SDCC_DEBUG_FSM_TRACE_RD_REG));
		pr_err("0x%08x 0x%08x 0x%08x\n",
				readl_relaxed(host->ioaddr +
					SDCC_DEBUG_FSM_TRACE_RD_REG),
				readl_relaxed(host->ioaddr +
					SDCC_DEBUG_FSM_TRACE_RD_REG),
				readl_relaxed(host->ioaddr +
					SDCC_DEBUG_FSM_TRACE_RD_REG));
	}
	/* Flush all fsm history */
	writel_relaxed(DUMMY, host->ioaddr +
			SDCC_DEBUG_FSM_TRACE_FIFO_FLUSH_REG);

	/* Exit from Auto recovery disable to move FSMs to idle state */
	writel_relaxed(DUMMY, host->ioaddr +
			SDCC_DEBUG_ERROR_STATE_EXIT_REG);

}

void sdhci_msm_dump_desc_history(struct sdhci_host *host)
{
	pr_err("----------- DESC HISTORY DUMP -----------\n");
	pr_err("Current Desc Addr: 0x%08x | Info: 0x%08x\n",
			readl_relaxed(host->ioaddr + SDCC_CURR_DESC_ADDR),
			readl_relaxed(host->ioaddr + SDCC_CURR_DESC_INFO));
	pr_err("Processed Desc1 Addr: 0x%08x | Info: 0x%08x\n",
			readl_relaxed(host->ioaddr + SDCC_PROC_DESC0_ADDR),
			readl_relaxed(host->ioaddr + SDCC_PROC_DESC0_INFO));
	pr_err("Processed Desc2 Addr: 0x%08x | Info: 0x%08x\n",
			readl_relaxed(host->ioaddr + SDCC_PROC_DESC1_ADDR),
			readl_relaxed(host->ioaddr + SDCC_PROC_DESC1_INFO));
}

void sdhci_msm_dump_iib(struct sdhci_host *host)
{
	u32 iter;

	pr_err("----------- IIB HISTORY DUMP -----------\n");
	for (iter = 0; iter < 8; iter++)
		pr_err("0x%08x\n", readl_relaxed(host->ioaddr +
			SDCC_DEBUG_IIB_REG + (iter * 4)));
}

void sdhci_msm_dump_vendor_regs(struct sdhci_host *host)
{
	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -4014,6 +4188,14 @@ void sdhci_msm_dump_vendor_regs(struct sdhci_host *host)
			msm_host_offset->CORE_VENDOR_SPEC_FUNC2),
		readl_relaxed(host->ioaddr +
			msm_host_offset->CORE_VENDOR_SPEC3));

	if (msm_host->debug_mode_enabled) {
		sdhci_msm_dump_fsm_history(host);
		sdhci_msm_dump_desc_history(host);
	}
	/* Debug feature enable not must for iib */
	sdhci_msm_dump_iib(host);

	/*
	 * tbsel indicates [2:0] bits and tbsel2 indicates [7:4] bits
	 * of CORE_TESTBUS_CONFIG register.
@@ -4705,6 +4887,54 @@ static int sdhci_msm_notify_load(struct sdhci_host *host, enum mmc_load state)
	return 0;
}

static void sdhci_msm_hw_reset(struct sdhci_host *host)
{
	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
	struct sdhci_msm_host *msm_host = pltfm_host->priv;
	struct platform_device *pdev = msm_host->pdev;
	int ret = -ENOTSUPP;

	if (!msm_host->core_reset) {
		dev_err(&pdev->dev, "%s: failed, err = %d\n", __func__,
				ret);
		return;
	}

	if (!msm_host->debug_mode_enabled)
		return;
	msm_host->reg_store = true;
	sdhci_msm_exit_dbg_mode(host);
	sdhci_msm_registers_save(host);
	if (host->mmc->caps2 & MMC_CAP2_CQE) {
		host->mmc->cqe_ops->cqe_disable(host->mmc);
		host->mmc->cqe_enabled = false;
	}

	ret = reset_control_assert(msm_host->core_reset);
	if (ret) {
		dev_err(&pdev->dev, "%s: core_reset assert failed, err = %d\n",
				__func__, ret);
		goto out;
	}

	/*
	 * The hardware requirement for delay between assert/deassert
	 * is at least 3-4 sleep clock (32.7KHz) cycles, which comes to
	 * ~125us (4/32768). To be on the safe side add 200us delay.
	 */
	usleep_range(200, 210);

	ret = reset_control_deassert(msm_host->core_reset);
	if (ret)
		dev_err(&pdev->dev, "%s: core_reset deassert failed, err = %d\n",
				__func__, ret);

	sdhci_msm_registers_restore(host);
	msm_host->reg_store = false;
out:
	return;
}

static struct sdhci_ops sdhci_msm_ops = {
	.crypto_engine_cfg = sdhci_msm_ice_cfg,
	.crypto_engine_cfg_end = sdhci_msm_ice_cfg_end,
@@ -4732,6 +4962,9 @@ static struct sdhci_ops sdhci_msm_ops = {
	.get_current_limit = sdhci_msm_get_current_limit,
	.notify_load = sdhci_msm_notify_load,
	.irq = sdhci_msm_cqe_irq,
	.enter_dbg_mode = sdhci_msm_enter_dbg_mode,
	.exit_dbg_mode = sdhci_msm_exit_dbg_mode,
	.hw_reset = sdhci_msm_hw_reset,
};

static void sdhci_set_default_hw_caps(struct sdhci_msm_host *msm_host,
@@ -5311,6 +5544,8 @@ static int sdhci_msm_probe(struct platform_device *pdev)
	msm_host->mmc->caps2 |= MMC_CAP2_MAX_DISCARD_SIZE;
	msm_host->mmc->caps2 |= MMC_CAP2_SLEEP_AWAKE;
	msm_host->mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
	if (msm_host->core_reset)
		msm_host->mmc->caps |= MMC_CAP_HW_RESET;

	if (msm_host->pdata->nonremovable)
		msm_host->mmc->caps |= MMC_CAP_NONREMOVABLE;
Loading