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

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

Merge "i2c: i2c-msm-geni: WAR to halt cancel if IOS not in good state"

parents 12d07c9e 052480e3
Loading
Loading
Loading
Loading
+69 −15
Original line number Diff line number Diff line
@@ -134,6 +134,7 @@ struct geni_i2c_dev {
	bool first_resume;
	bool gpi_reset;
	bool disable_dma_mode;
	bool prev_cancel_pending; //Halt cancel till IOS in good state
};

static struct geni_i2c_dev *gi2c_dev_dbg[MAX_SE];
@@ -241,10 +242,45 @@ static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err)
	gi2c->err = gi2c_log[err].err;
}

static int geni_i2c_prepare(struct geni_i2c_dev *gi2c)
static int do_pending_cancel(struct geni_i2c_dev *gi2c)
{
	int timeout = 0;
	u32 geni_ios = 0;

	geni_ios = geni_read_reg_nolog(gi2c->base, SE_GENI_IOS);
	if ((geni_ios & 0x3) != 0x3) {
		GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
			"%s: Can't do pending cancel, IOS bad state: 0x%x\n",
			__func__, geni_ios);
		return -EINVAL;
	}

	if (gi2c->se_mode == GSI_ONLY) {
		dmaengine_terminate_all(gi2c->tx_c);
		gi2c->cfg_sent = 0;
	} else {
		reinit_completion(&gi2c->xfer);
		geni_cancel_m_cmd(gi2c->base);
		timeout = wait_for_completion_timeout(&gi2c->xfer, HZ);
		if (!timeout) {
			GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
				"%s:Pending Cancel failed\n", __func__);
			reinit_completion(&gi2c->xfer);
			geni_abort_m_cmd(gi2c->base);
			timeout = wait_for_completion_timeout(&gi2c->xfer, HZ);
			if (!timeout)
				GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
				"%s:Abort failed\n", __func__);
		}
	}
	gi2c->prev_cancel_pending = false;
	GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
			"%s: Pending Cancel done\n", __func__);
	return timeout;
}

static int geni_i2c_prepare(struct geni_i2c_dev *gi2c)
{
	if (gi2c->se_mode == UNINITIALIZED) {
		int proto = get_se_proto(gi2c->base);
		u32 se_mode;
@@ -256,16 +292,6 @@ static int geni_i2c_prepare(struct geni_i2c_dev *gi2c)
			return -ENXIO;
		}

		geni_ios = geni_read_reg_nolog(gi2c->base, SE_GENI_IOS);
		if ((geni_ios & 0x3) != 0x3) { //SCL:b'1, SDA:b'0
			GENI_SE_DBG(gi2c->ipcl, true, gi2c->dev,
			"IO lines not in good state, Check power to slave\n");

			if (!gi2c->is_le_vm)
				se_geni_resources_off(&gi2c->i2c_rsc);
			return -ENXIO;
		}

		se_mode = readl_relaxed(gi2c->base +
					GENI_IF_FIFO_DISABLE_RO);
		if (se_mode) {
@@ -933,6 +959,8 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
		timeout = wait_for_completion_timeout(&gi2c->xfer,
						gi2c->xfer_timeout);
		if (!timeout) {
			u32 geni_ios = 0;

			GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
				"I2C gsi xfer timeout:%u flags:%d addr:0x%x\n",
				gi2c->xfer_timeout, gi2c->cur->flags,
@@ -940,6 +968,15 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
			geni_se_dump_dbg_regs(&gi2c->i2c_rsc, gi2c->base,
						gi2c->ipcl);
			gi2c->err = -ETIMEDOUT;

			/* WAR: Set flag to mark cancel pending if IOS stuck */
			geni_ios = geni_read_reg_nolog(gi2c->base, SE_GENI_IOS);
			if ((geni_ios & 0x3) != 0x3) { //SCL:b'1, SDA:b'0
				GENI_SE_DBG(gi2c->ipcl, true, gi2c->dev,
					"%s: IO lines not in good state\n", __func__);
				gi2c->prev_cancel_pending = true;
				goto geni_i2c_gsi_cancel_pending;
			}
		}
geni_i2c_err_prep_sg:
		if (gi2c->err) {
@@ -962,6 +999,7 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
			/* Resend cfg tre for every new message on shared se */
			gi2c->cfg_sent = 0;

geni_i2c_gsi_cancel_pending:
		if (msgs[i].flags & I2C_M_RD)
			geni_se_iommu_unmap_buf(rx_dev, &gi2c->rx_ph,
				msgs[i].len, DMA_FROM_DEVICE);
@@ -1007,6 +1045,13 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
		}
	}

	// WAR : Complete previous pending cancel cmd
	if (gi2c->prev_cancel_pending) {
		ret = do_pending_cancel(gi2c);
		if (ret)
			return ret; //Don't perform xfer is cancel failed
	}

	GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
		"n:%d addr:0x%x\n", num, msgs[0].addr);

@@ -1124,9 +1169,20 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
		timeout = wait_for_completion_timeout(&gi2c->xfer,
						gi2c->xfer_timeout);
		if (!timeout) {
			u32 geni_ios = 0;

			GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
				"I2C xfer timeout: %d\n", gi2c->xfer_timeout);
			geni_i2c_err(gi2c, GENI_TIMEOUT);

			/* WAR: Set flag to mark cancel pending if IOS bad */
			geni_ios = geni_read_reg_nolog(gi2c->base, SE_GENI_IOS);
			if ((geni_ios & 0x3) != 0x3) { //SCL:b'1, SDA:b'0
				GENI_SE_DBG(gi2c->ipcl, true, gi2c->dev,
					"%s: IO lines not in good state\n", __func__);
				gi2c->prev_cancel_pending = true;
				goto geni_i2c_txn_ret;
			}
		}

		if (gi2c->err) {
@@ -1453,19 +1509,17 @@ static int geni_i2c_runtime_resume(struct device *dev)
	if (!gi2c->is_le_vm) {
		/* Do not control clk/gpio/icb for LE-VM */
		ret = se_geni_resources_on(&gi2c->i2c_rsc);

		if (ret)
			return ret;

		ret = geni_i2c_prepare(gi2c);
		if (ret) {
			dev_err(gi2c->dev, "I2C prepare failed\n");
			dev_err(gi2c->dev, "I2C prepare failed: %d\n", ret);
			return ret;
		}

		if (gi2c->se_mode == FIFO_SE_DMA)
			enable_irq(gi2c->irq);

	} else if (!gi2c->first_resume) {
		/*
		 * For first resume call in le, do nothing, and in
@@ -1475,7 +1529,7 @@ static int geni_i2c_runtime_resume(struct device *dev)
		 */
		ret = geni_i2c_prepare(gi2c);
		if (ret) {
			dev_err(gi2c->dev, "I2C prepare failed\n");
			dev_err(gi2c->dev, "I2C prepare failed:%d\n", ret);
			return ret;
		}