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

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

Merge "mmc: sdhci: Skip interrupt clear in case of err"

parents a9013b58 64a4807b
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -1506,7 +1506,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);
}
+7 −0
Original line number Diff line number Diff line
@@ -2306,6 +2306,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;

@@ -2909,6 +2911,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 {
+238 −3
Original line number Diff line number Diff line
@@ -1210,6 +1210,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;
@@ -1244,6 +1316,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__);

@@ -1437,6 +1510,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;
@@ -2020,6 +2094,23 @@ static int sdhci_msm_parse_regulator_info(struct device *dev,
	return -EINVAL;
}

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,
@@ -2037,6 +2128,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)
@@ -2173,6 +2265,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:
@@ -2263,11 +2358,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;
}

@@ -3273,7 +3378,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 +
@@ -3337,8 +3443,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);
@@ -3995,6 +4102,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);
@@ -4052,6 +4226,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.
@@ -4743,6 +4925,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,
@@ -4770,6 +5000,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,
@@ -5411,6 +5644,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;
+65 −0
Original line number Diff line number Diff line
@@ -9,8 +9,70 @@

#include <linux/mmc/mmc.h>
#include <linux/pm_qos.h>
#include <linux/reset.h>
#include "sdhci-pltfm.h"

/* check IP CATALOG version */
#define SDCC_IP_CATALOG 0x328

/* DBG register offsets */
#define SDCC_TESTBUS_CONFIG 0x32C
#define SDCC_DEBUG_EN_DIS_REG 0x390
#define SDCC_DEBUG_FEATURE_CFG_REG 0x394
#define SDCC_DEBUG_FSM_TRACE_CFG_REG 0x398
#define SDCC_DEBUG_FSM_TRACE_RD_REG 0x39C
#define SDCC_DEBUG_FSM_TRACE_FIFO_FLUSH_REG 0x3A0
#define SDCC_DEBUG_PANIC_ERROR_EN_REG 0x3A4
#define SDCC_DEBUG_ERROR_STATE_EXIT_REG 0x3B8
#define SDCC_CURR_DESC_ADDR 0x3EC
#define SDCC_CURR_DESC_INFO 0x3F0
#define SDCC_PROC_DESC0_ADDR 0x3E4
#define SDCC_PROC_DESC0_INFO 0x3E8
#define SDCC_PROC_DESC1_ADDR 0x3DC
#define SDCC_PROC_DESC1_INFO 0x3E0
#define SDCC_DEBUG_IIB_REG 0x980
#define SDCC_DEBUG_MASK_PATTERN_REG 0x3C0
#define SDCC_DEBUG_MATCH_PATTERN_REG 0x3C4
#define SDCC_DEBUG_MM_TB_CFG_REG 0x3BC

#define ENABLE_DBG 0x35350000
#define DISABLE_DBG 0x26260000

#define DUMMY 0x1 /* value doesn't matter */

/* Panic on Err */
#define BOOT_ACK_REC_EN BIT(0)
#define BOOT_ACK_ERR_EN BIT(1)
#define BOOT_TIMEOUT_EN BIT(2)
#define AUTO_CMD19_TOUT_EN BIT(3)
#define STBITE_EN BIT(4)
#define CTOUT_EN BIT(5)
#define CCRCF_EN BIT(6)
#define CMD_END_BIT_ERR_EN BIT(7)
#define CMD_INDEX_ERR_EN BIT(8)
#define DTOUT_EN BIT(9)
#define DCRCF_EN BIT(10)
#define DATA_END_BIT_ERR_EN BIT(11)
#define CMDQ_HALT_ACK_INT_EN BIT(16)
#define CMDQ_TASK_COMPLETED_INT_EN BIT(17)
#define CMDQ_RESP_ERR_INT_EN BIT(18)
#define CMDQ_TASK_CLEARED_INT_EN BIT(19)
#define CMDQ_GENERAL_CRYPTO_ERROR_EN BIT(20)
#define CMDQ_INVALID_CRYPTO_CFG_ERROR_EN BIT(21)
#define CMDQ_DEVICE_EXCEPTION_INT_EN BIT(22)
#define ADMA_ERROR_EXT_EN BIT(23)
#define HC_NONCQ_ICE_INT_STATUS_MASKED_EN BIT(24)

/* Select debug Feature */
#define FSM_HISTORY BIT(0)
#define PANIC_ALERT BIT(1)
#define AUTO_RECOVERY_DISABLE BIT(2)
#define MM_TRIGGER_DISABLE BIT(3)
#define DESC_HISTORY BIT(4)
#define IIB_EN BIT(6)

#define TESTBUS_EN BIT(31)

/* This structure keeps information per regulator */
struct sdhci_msm_reg_data {
	/* voltage regulator handle */
@@ -267,6 +329,9 @@ struct sdhci_msm_host {
	struct sdhci_msm_dll_hsr *dll_hsr;
	struct sdhci_msm_ice_data ice;
	u32 ice_clk_rate;
	bool debug_mode_enabled;
	bool reg_store;
	struct reset_control *core_reset;
};

extern char *saved_command_line;
Loading