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

Commit d425ff3d authored by Vipin Deep Kaur's avatar Vipin Deep Kaur
Browse files

i2c: i2c-msm-geni: Propagate missing changes from 4.19 to 5.4



Propagate following changes from 4.19 to 5.4 for I2C and GSI driver.
'commit 22cec88da571 ("i2c: i2c-qcom-geni: Add lock and unlock tre
support in I2C GSI mode")',
'commit 3adda53e090d ("i2c: i2c-qcom-geni: Enable shared flag in GSI
mode only")',
'commit 6f84a3f8ca30 ("i2c: i2c-qcom-geni: Enhance IPC logging debug
infra in I2C")',
'commit d06ac0169fb7 ("i2c: i2c-qcom-geni: Correct the IEOB/IEOT
sequence for I2C GSI tres")'.

Change-Id: I8ab0b4d580b16041b751f0be3de717d32238a374
Signed-off-by: default avatarVipin Deep Kaur <vkaur@codeaurora.org>
parent 492d9b26
Loading
Loading
Loading
Loading
+109 −35
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
 */

#include <linux/atomic.h>
@@ -447,7 +447,8 @@ struct gpi_dev {
	struct dentry *dentry;
};

static struct gpi_dev *gpi_dev_dbg;
static struct gpi_dev *gpi_dev_dbg[5];
static int arr_idx;

struct reg_info {
	char *name;
@@ -581,6 +582,7 @@ struct gpii {
	struct gpi_reg_table dbg_reg_table;
	bool reg_table_dump;
	u32 dbg_gpi_irq_cnt;
	bool unlock_tre_set;
};

struct gpi_desc {
@@ -1447,6 +1449,22 @@ static void gpi_process_qup_notif_event(struct gpii_chan *gpii_chan,
			      client_info->cb_param);
}

/* free gpi_desc for the specified channel */
static void gpi_free_chan_desc(struct gpii_chan *gpii_chan)
{
	struct virt_dma_desc *vd;
	struct gpi_desc *gpi_desc;
	unsigned long flags;

	spin_lock_irqsave(&gpii_chan->vc.lock, flags);
	vd = vchan_next_desc(&gpii_chan->vc);
	gpi_desc = to_gpi_desc(vd);
	list_del(&vd->node);
	spin_unlock_irqrestore(&gpii_chan->vc.lock, flags);
	kfree(gpi_desc);
	gpi_desc = NULL;
}

/* process DMA Immediate completion data events */
static void gpi_process_imed_data_event(struct gpii_chan *gpii_chan,
					struct immediate_data_event *imed_event)
@@ -1459,6 +1477,8 @@ static void gpi_process_imed_data_event(struct gpii_chan *gpii_chan,
		(ch_ring->el_size * imed_event->tre_index);
	struct msm_gpi_dma_async_tx_cb_param *tx_cb_param;
	unsigned long flags;
	u32 chid;
	struct gpii_chan *gpii_tx_chan = &gpii->gpii_chan[GPI_TX_CHAN];

	/*
	 * If channel not active don't process event but let
@@ -1496,20 +1516,6 @@ static void gpi_process_imed_data_event(struct gpii_chan *gpii_chan,
		return;
	}
	gpi_desc = to_gpi_desc(vd);

	/* Event TR RP gen. don't match descriptor TR */
	if (gpi_desc->wp != tre) {
		spin_unlock_irqrestore(&gpii_chan->vc.lock, flags);
		GPII_ERR(gpii, gpii_chan->chid,
			 "EOT/EOB received for wrong TRE 0x%0llx != 0x%0llx\n",
			 to_physical(ch_ring, gpi_desc->wp),
			 to_physical(ch_ring, tre));
		gpi_generate_cb_event(gpii_chan, MSM_GPI_QUP_EOT_DESC_MISMATCH,
				      __LINE__);
		return;
	}

	list_del(&vd->node);
	spin_unlock_irqrestore(&gpii_chan->vc.lock, flags);


@@ -1525,6 +1531,35 @@ static void gpi_process_imed_data_event(struct gpii_chan *gpii_chan,
	/* make sure rp updates are immediately visible to all cores */
	smp_wmb();

	/*
	 * If unlock tre is present, don't send transfer callback on
	 * on IEOT, wait for unlock IEOB. Free the respective channel
	 * descriptors.
	 * If unlock is not present, IEOB indicates freeing the descriptor
	 * and IEOT indicates channel transfer completion.
	 */
	chid = imed_event->chid;
	if (gpii->unlock_tre_set) {
		if (chid == GPI_RX_CHAN) {
			if (imed_event->code == MSM_GPI_TCE_EOT)
				goto gpi_free_desc;
			else if (imed_event->code == MSM_GPI_TCE_UNEXP_ERR)
				/*
				 * In case of an error in a read transfer on a
				 * shared se, unlock tre will not be processed
				 * as channels go to bad state so tx desc should
				 * be freed manually.
				 */
				gpi_free_chan_desc(gpii_tx_chan);
			else
				return;
		} else if (imed_event->code == MSM_GPI_TCE_EOT) {
			return;
		}
	} else if (imed_event->code == MSM_GPI_TCE_EOB) {
		goto gpi_free_desc;
	}

	tx_cb_param = vd->tx.callback_param;
	if (vd->tx.callback && tx_cb_param) {
		struct msm_gpi_tre *imed_tre = &tx_cb_param->imed_tre;
@@ -1540,7 +1575,9 @@ static void gpi_process_imed_data_event(struct gpii_chan *gpii_chan,
		tx_cb_param->status = imed_event->status;
		vd->tx.callback(tx_cb_param);
	}
	kfree(gpi_desc);

gpi_free_desc:
	gpi_free_chan_desc(gpii_chan);
}

/* processing transfer completion events */
@@ -1554,6 +1591,8 @@ static void gpi_process_xfer_compl_event(struct gpii_chan *gpii_chan,
	struct msm_gpi_dma_async_tx_cb_param *tx_cb_param;
	struct gpi_desc *gpi_desc;
	unsigned long flags;
	u32 chid;
	struct gpii_chan *gpii_tx_chan = &gpii->gpii_chan[GPI_TX_CHAN];

	/* only process events on active channel */
	if (unlikely(gpii_chan->pm_state != ACTIVE_STATE)) {
@@ -1583,20 +1622,6 @@ static void gpi_process_xfer_compl_event(struct gpii_chan *gpii_chan,
	}

	gpi_desc = to_gpi_desc(vd);

	/* TRE Event generated didn't match descriptor's TRE */
	if (gpi_desc->wp != ev_rp) {
		spin_unlock_irqrestore(&gpii_chan->vc.lock, flags);
		GPII_ERR(gpii, gpii_chan->chid,
			 "EOT\EOB received for wrong TRE 0x%0llx != 0x%0llx\n",
			 to_physical(ch_ring, gpi_desc->wp),
			 to_physical(ch_ring, ev_rp));
		gpi_generate_cb_event(gpii_chan, MSM_GPI_QUP_EOT_DESC_MISMATCH,
				      __LINE__);
		return;
	}

	list_del(&vd->node);
	spin_unlock_irqrestore(&gpii_chan->vc.lock, flags);


@@ -1612,6 +1637,35 @@ static void gpi_process_xfer_compl_event(struct gpii_chan *gpii_chan,
	/* update must be visible to other cores */
	smp_wmb();

	/*
	 * If unlock tre is present, don't send transfer callback on
	 * on IEOT, wait for unlock IEOB. Free the respective channel
	 * descriptors.
	 * If unlock is not present, IEOB indicates freeing the descriptor
	 * and IEOT indicates channel transfer completion.
	 */
	chid = compl_event->chid;
	if (gpii->unlock_tre_set) {
		if (chid == GPI_RX_CHAN) {
			if (compl_event->code == MSM_GPI_TCE_EOT)
				goto gpi_free_desc;
			else if (compl_event->code == MSM_GPI_TCE_UNEXP_ERR)
				/*
				 * In case of an error in a read transfer on a
				 * shared se, unlock tre will not be processed
				 * as channels go to bad state so tx desc should
				 * be freed manually.
				 */
				gpi_free_chan_desc(gpii_tx_chan);
			else
				return;
		} else if (compl_event->code == MSM_GPI_TCE_EOT) {
			return;
		}
	} else if (compl_event->code == MSM_GPI_TCE_EOB) {
		goto gpi_free_desc;
	}

	tx_cb_param = vd->tx.callback_param;
	if (vd->tx.callback && tx_cb_param) {
		GPII_VERB(gpii, gpii_chan->chid,
@@ -1623,7 +1677,10 @@ static void gpi_process_xfer_compl_event(struct gpii_chan *gpii_chan,
		tx_cb_param->status = compl_event->status;
		vd->tx.callback(tx_cb_param);
	}
	kfree(gpi_desc);

gpi_free_desc:
	gpi_free_chan_desc(gpii_chan);

}

/* process all events */
@@ -2299,6 +2356,7 @@ void gpi_desc_free(struct virt_dma_desc *vd)
	struct gpi_desc *gpi_desc = to_gpi_desc(vd);

	kfree(gpi_desc);
	gpi_desc = NULL;
}

/* copy tre into transfer ring */
@@ -2319,6 +2377,7 @@ struct dma_async_tx_descriptor *gpi_prep_slave_sg(struct dma_chan *chan,
	void *tre, *wp = NULL;
	const gfp_t gfp = GFP_ATOMIC;
	struct gpi_desc *gpi_desc;
	u32 tre_type;

	GPII_VERB(gpii, gpii_chan->chid, "enter\n");

@@ -2352,10 +2411,21 @@ struct dma_async_tx_descriptor *gpi_prep_slave_sg(struct dma_chan *chan,
	}

	/* copy each tre into transfer ring */
	for_each_sg(sgl, sg, sg_len, i)
		for (j = 0, tre = sg_virt(sg); j < sg->length;
	for_each_sg(sgl, sg, sg_len, i) {
		tre = sg_virt(sg);

		/* Check if last tre is an unlock tre */
		if (i == sg_len - 1) {
			tre_type =
			MSM_GPI_TRE_TYPE(((struct msm_gpi_tre *)tre));
			gpii->unlock_tre_set =
			tre_type == MSM_GPI_TRE_UNLOCK ? true : false;
		}

		for (j = 0; j < sg->length;
		     j += ch_ring->el_size, tre += ch_ring->el_size)
			gpi_queue_xfer(gpii, gpii_chan, tre, &wp);
	}

	/* set up the descriptor */
	gpi_desc->db = ch_ring->wp;
@@ -2807,7 +2877,7 @@ static int gpi_probe(struct platform_device *pdev)
		return -ENOMEM;

	/* debug purpose */
	gpi_dev_dbg = gpi_dev;
	gpi_dev_dbg[arr_idx++] = gpi_dev;

	gpi_dev->dev = &pdev->dev;
	gpi_dev->klog_lvl = DEFAULT_KLOG_LVL;
@@ -3018,6 +3088,10 @@ static int gpi_remove(struct platform_device *pdev)
			ipc_log_context_destroy(gpii->ilctxt);
	}

	for (i = 0; i < arr_idx; i++)
		gpi_dev_dbg[i] = NULL;
	arr_idx = 0;

	if (gpi_dev->ilctxt)
		ipc_log_context_destroy(gpi_dev->ilctxt);

+174 −44
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include <linux/msm_gpi.h>
#include <linux/ioctl.h>
#include <linux/pinctrl/consumer.h>
#include <linux/slab.h>

#define SE_I2C_TX_TRANS_LEN		(0x26C)
#define SE_I2C_RX_TRANS_LEN		(0x270)
@@ -73,12 +74,19 @@

#define I2C_TIMEOUT_MIN_USEC	500000

#define MAX_SE	20

enum i2c_se_mode {
	UNINITIALIZED,
	FIFO_SE_DMA,
	GSI_ONLY,
};

struct dbg_buf_ctxt {
	void *virt_buf;
	void *map_buf;
};

struct geni_i2c_dev {
	struct device *dev;
	void __iomem *base;
@@ -97,6 +105,8 @@ struct geni_i2c_dev {
	int clk_fld_idx;
	struct dma_chan *tx_c;
	struct dma_chan *rx_c;
	struct msm_gpi_tre lock_t;
	struct msm_gpi_tre unlock_t;
	struct msm_gpi_tre cfg0_t;
	struct msm_gpi_tre go_t;
	struct msm_gpi_tre tx_t;
@@ -115,9 +125,14 @@ struct geni_i2c_dev {
	enum i2c_se_mode se_mode;
	bool cmd_done;
	bool is_shared;
	u32 dbg_num;
	struct dbg_buf_ctxt *dbg_buf_ptr;
	bool is_le_vm;
};

static struct geni_i2c_dev *gi2c_dev_dbg[MAX_SE];
static int arr_idx;

struct geni_i2c_err_log {
	int err;
	const char *msg;
@@ -207,12 +222,6 @@ static inline void qcom_geni_i2c_calc_timeout(struct geni_i2c_dev *gi2c)

static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err)
{
	if (gi2c->cur)
		GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
			"len:%d, slv-addr:0x%x, RD/WR:%d timeout:%u\n",
			gi2c->cur->len, gi2c->cur->addr, gi2c->cur->flags,
			gi2c->xfer_timeout);

	if (err == I2C_NACK || err == GENI_ABORT_DONE) {
		GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n",
			     gi2c_log[err].msg);
@@ -221,8 +230,6 @@ static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err)
		GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "%s\n",
			     gi2c_log[err].msg);
	}
	GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s: se-mode:%d\n", __func__,
							gi2c->se_mode);
	geni_se_dump_dbg_regs(&gi2c->i2c_rsc, gi2c->base, gi2c->ipcl);
err_ret:
	gi2c->err = gi2c_log[err].err;
@@ -275,7 +282,13 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev)
	u32 dma = readl_relaxed(gi2c->base + SE_GENI_DMA_MODE_EN);
	struct i2c_msg *cur = gi2c->cur;

	if (!cur || (m_stat & M_CMD_FAILURE_EN) ||
	if (!cur) {
		geni_se_dump_dbg_regs(&gi2c->i2c_rsc, gi2c->base, gi2c->ipcl);
		GENI_SE_ERR(gi2c->ipcl, false, gi2c->dev, "Spurious irq\n");
		goto irqret;
	}

	if ((m_stat & M_CMD_FAILURE_EN) ||
		    (dm_rx_st & (DM_I2C_CB_ERR)) ||
		    (m_stat & M_CMD_CANCEL_EN) ||
		    (m_stat & M_CMD_ABORT_EN)) {
@@ -302,12 +315,6 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev)
		goto irqret;
	}

	if (dma) {
		dev_dbg(gi2c->dev, "i2c dma tx:0x%x, dma rx:0x%x\n", dm_tx_st,
			dm_rx_st);
		goto irqret;
	}

	if (((m_stat & M_RX_FIFO_WATERMARK_EN) ||
		(m_stat & M_RX_FIFO_LAST_EN)) && (cur->flags & I2C_M_RD)) {
		u32 rxcnt = rx_st & RX_FIFO_WC_MSK;
@@ -434,11 +441,9 @@ static void gi2c_gsi_tx_cb(void *ptr)
	struct msm_gpi_dma_async_tx_cb_param *tx_cb = ptr;
	struct geni_i2c_dev *gi2c = tx_cb->userdata;

	if (!(gi2c->cur->flags & I2C_M_RD)) {
	gi2c_gsi_cb_err(tx_cb, "TX");
	complete(&gi2c->xfer);
}
}

static void gi2c_gsi_rx_cb(void *ptr)
{
@@ -476,6 +481,7 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
			goto geni_i2c_gsi_xfer_out;
		}
	}

	if (!gi2c->rx_c) {
		gi2c->rx_c = dma_request_slave_channel(gi2c->dev, "rx");
		if (!gi2c->rx_c) {
@@ -496,6 +502,23 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
		}
	}

	if (gi2c->is_shared) {
		struct msm_gpi_tre *lock_t = &gi2c->lock_t;
		struct msm_gpi_tre *unlock_t = &gi2c->unlock_t;

		/* lock */
		lock_t->dword[0] = MSM_GPI_LOCK_TRE_DWORD0;
		lock_t->dword[1] = MSM_GPI_LOCK_TRE_DWORD1;
		lock_t->dword[2] = MSM_GPI_LOCK_TRE_DWORD2;
		lock_t->dword[3] = MSM_GPI_LOCK_TRE_DWORD3(0, 0, 0, 0, 1);

		/* unlock tre: ieob set */
		unlock_t->dword[0] = MSM_GPI_UNLOCK_TRE_DWORD0;
		unlock_t->dword[1] = MSM_GPI_UNLOCK_TRE_DWORD1;
		unlock_t->dword[2] = MSM_GPI_UNLOCK_TRE_DWORD2;
		unlock_t->dword[3] = MSM_GPI_UNLOCK_TRE_DWORD3(0, 0, 0, 1, 0);
	}

	if (!gi2c->cfg_sent) {
		struct geni_i2c_clk_fld *itr = geni_i2c_clk_map +
							gi2c->clk_fld_idx;
@@ -535,26 +558,47 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
		}

		qcom_geni_i2c_calc_timeout(gi2c);
		if (!gi2c->cfg_sent) {

		if (!gi2c->cfg_sent)
			segs++;
		if (gi2c->is_shared && (i == 0 || i == num-1)) {
			segs++;
			if (num == 1)
				segs++;
			sg_init_table(gi2c->tx_sg, segs);
			sg_set_buf(gi2c->tx_sg, &gi2c->cfg0_t,
						sizeof(gi2c->cfg0_t));
			gi2c->cfg_sent = 1;
			index++;
			if (i == 0)
				/* Send lock tre for first transfer in a msg */
				sg_set_buf(&gi2c->tx_sg[index++], &gi2c->lock_t,
					sizeof(gi2c->lock_t));
		} else {
			sg_init_table(gi2c->tx_sg, segs);
		}

		/* Send cfg tre when cfg not sent already */
		if (!gi2c->cfg_sent) {
			sg_set_buf(&gi2c->tx_sg[index++], &gi2c->cfg0_t,
						sizeof(gi2c->cfg0_t));
			gi2c->cfg_sent = 1;
		}

		go_t->dword[0] = MSM_GPI_I2C_GO_TRE_DWORD0((stretch << 2),
							   msgs[i].addr, op);
		go_t->dword[1] = MSM_GPI_I2C_GO_TRE_DWORD1;

		if (msgs[i].flags & I2C_M_RD) {
			go_t->dword[2] = MSM_GPI_I2C_GO_TRE_DWORD2(msgs[i].len);
			go_t->dword[3] = MSM_GPI_I2C_GO_TRE_DWORD3(1, 0, 0, 1,
									0);
			/*
			 * For Rx Go tre: Set ieob for non-shared se and for all
			 * but last transfer in shared se
			 */
			if (!gi2c->is_shared || (gi2c->is_shared && i != num-1))
				go_t->dword[3] = MSM_GPI_I2C_GO_TRE_DWORD3(1, 0,
								0, 1, 0);
			else
				go_t->dword[3] = MSM_GPI_I2C_GO_TRE_DWORD3(1, 0,
								0, 0, 0);
		} else {
			/* For Tx Go tre: ieob is not set, chain bit is set */
			go_t->dword[2] = MSM_GPI_I2C_GO_TRE_DWORD2(0);
			go_t->dword[3] = MSM_GPI_I2C_GO_TRE_DWORD3(0, 0, 0, 0,
									1);
@@ -564,6 +608,8 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
						  sizeof(gi2c->go_t));

		if (msgs[i].flags & I2C_M_RD) {
			GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
				"msg[%d].len:%d R\n", i, gi2c->cur->len);
			sg_init_table(&gi2c->rx_sg, 1);
			ret = geni_se_iommu_map_buf(rx_dev, &gi2c->rx_ph,
						dma_buf, msgs[i].len,
@@ -576,6 +622,11 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
								false);
				goto geni_i2c_gsi_xfer_out;

			} else if (gi2c->dbg_buf_ptr) {
				gi2c->dbg_buf_ptr[i].virt_buf =
							(void *)dma_buf;
				gi2c->dbg_buf_ptr[i].map_buf =
							(void *)&gi2c->rx_ph;
			}
			gi2c->rx_t.dword[0] =
				MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(gi2c->rx_ph);
@@ -583,6 +634,7 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
				MSM_GPI_DMA_W_BUFFER_TRE_DWORD1(gi2c->rx_ph);
			gi2c->rx_t.dword[2] =
				MSM_GPI_DMA_W_BUFFER_TRE_DWORD2(msgs[i].len);
			/* Set ieot for all Rx/Tx DMA tres */
			gi2c->rx_t.dword[3] =
				MSM_GPI_DMA_W_BUFFER_TRE_DWORD3(0, 0, 1, 0, 0);

@@ -606,6 +658,8 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
			rx_cookie = dmaengine_submit(gi2c->rx_desc);
			dma_async_issue_pending(gi2c->rx_c);
		} else {
			GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
				"msg[%d].len:%d W\n", i, gi2c->cur->len);
			ret = geni_se_iommu_map_buf(tx_dev, &gi2c->tx_ph,
						dma_buf, msgs[i].len,
						DMA_TO_DEVICE);
@@ -617,13 +671,27 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
								false);
				goto geni_i2c_gsi_xfer_out;

			} else if (gi2c->dbg_buf_ptr) {
				gi2c->dbg_buf_ptr[i].virt_buf =
							(void *)dma_buf;
				gi2c->dbg_buf_ptr[i].map_buf =
							(void *)&gi2c->tx_ph;
			}

			gi2c->tx_t.dword[0] =
				MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(gi2c->tx_ph);
			gi2c->tx_t.dword[1] =
				MSM_GPI_DMA_W_BUFFER_TRE_DWORD1(gi2c->tx_ph);
			gi2c->tx_t.dword[2] =
				MSM_GPI_DMA_W_BUFFER_TRE_DWORD2(msgs[i].len);
			if (gi2c->is_shared && i == num-1)
				/*
				 * For Tx: unlock tre is send for last transfer
				 * so set chain bit for last transfer DMA tre.
				 */
				gi2c->tx_t.dword[3] =
				MSM_GPI_DMA_W_BUFFER_TRE_DWORD3(0, 0, 1, 0, 1);
			else
				gi2c->tx_t.dword[3] =
				MSM_GPI_DMA_W_BUFFER_TRE_DWORD3(0, 0, 1, 0, 0);

@@ -631,6 +699,12 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
							  sizeof(gi2c->tx_t));
		}

		if (gi2c->is_shared && i == num-1) {
			/* Send unlock tre at the end of last transfer */
			sg_set_buf(&gi2c->tx_sg[index++],
				&gi2c->unlock_t, sizeof(gi2c->unlock_t));
		}

		gi2c->tx_desc = dmaengine_prep_slave_sg(gi2c->tx_c, gi2c->tx_sg,
						segs, DMA_MEM_TO_DEV,
						(DMA_PREP_INTERRUPT |
@@ -652,8 +726,9 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
						gi2c->xfer_timeout);
		if (!timeout) {
			GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
				    "GSI Txn timed out: %u len: %d\n",
					gi2c->xfer_timeout, gi2c->cur->len);
				"I2C gsi xfer timeout:%u flags:%d addr:0x%x\n",
				gi2c->xfer_timeout, gi2c->cur->flags,
				gi2c->cur->addr);
			geni_se_dump_dbg_regs(&gi2c->i2c_rsc, gi2c->base,
						gi2c->ipcl);
			gi2c->err = -ETIMEDOUT;
@@ -663,6 +738,10 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
			dmaengine_terminate_all(gi2c->tx_c);
			gi2c->cfg_sent = 0;
		}
		if (gi2c->is_shared)
			/* Resend cfg tre for every new message on shared se */
			gi2c->cfg_sent = 0;

		if (msgs[i].flags & I2C_M_RD)
			geni_se_iommu_unmap_buf(rx_dev, &gi2c->rx_ph,
				msgs[i].len, DMA_FROM_DEVICE);
@@ -688,8 +767,15 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
	int i, ret = 0, timeout = 0;

	gi2c->err = 0;
	gi2c->cur = &msgs[0];
	reinit_completion(&gi2c->xfer);

	/* Client to respect system suspend */
	if (!pm_runtime_enabled(gi2c->dev)) {
		GENI_SE_ERR(gi2c->ipcl, false, gi2c->dev,
			"%s: System suspended\n", __func__);
		return -EACCES;
	}

	ret = pm_runtime_get_sync(gi2c->dev);
	if (ret < 0) {
		GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
@@ -709,14 +795,25 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
		}
	}

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

	gi2c->dbg_num = num;
	kfree(gi2c->dbg_buf_ptr);
	gi2c->dbg_buf_ptr =
		kcalloc(num, sizeof(struct dbg_buf_ctxt), GFP_KERNEL);
	if (!gi2c->dbg_buf_ptr)
		GENI_SE_ERR(gi2c->ipcl, false, gi2c->dev,
			"Buf logging pointer not available\n");

	if (gi2c->se_mode == GSI_ONLY) {
		ret = geni_i2c_gsi_xfer(adap, msgs, num);
		goto geni_i2c_txn_ret;
	} else {
		/* Don't set shared flag in non-GSI mode */
		gi2c->is_shared = false;
	}

	qcom_geni_i2c_conf(gi2c, 0);
	dev_dbg(gi2c->dev, "i2c xfer:num:%d, msgs:len:%d,flg:%d\n",
				num, msgs[0].len, msgs[0].flags);
	for (i = 0; i < num; i++) {
		int stretch = (i < (num - 1));
		u32 m_param = 0;
@@ -751,9 +848,8 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
		}

		if (msgs[i].flags & I2C_M_RD) {
			dev_dbg(gi2c->dev,
				"READ,n:%d,i:%d len:%d, stretch:%d\n",
					num, i, msgs[i].len, stretch);
			GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
				"msgs[%d].len:%d R\n", i, msgs[i].len);
			geni_write_reg(msgs[i].len,
				       gi2c->base, SE_I2C_RX_TRANS_LEN);
			m_cmd = I2C_READ;
@@ -768,12 +864,16 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
					mode = FIFO_MODE;
					ret = geni_se_select_mode(gi2c->base,
								  mode);
				} else if (gi2c->dbg_buf_ptr) {
					gi2c->dbg_buf_ptr[i].virt_buf =
								(void *)dma_buf;
					gi2c->dbg_buf_ptr[i].map_buf =
								(void *)&rx_dma;
				}
			}
		} else {
			dev_dbg(gi2c->dev,
				"WRITE:n:%d,i:%d len:%d, stretch:%d, m_param:0x%x\n",
					num, i, msgs[i].len, stretch, m_param);
			GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
				"msgs[%d].len:%d W\n", i, msgs[i].len);
			geni_write_reg(msgs[i].len, gi2c->base,
						SE_I2C_TX_TRANS_LEN);
			m_cmd = I2C_WRITE;
@@ -788,6 +888,11 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
					mode = FIFO_MODE;
					ret = geni_se_select_mode(gi2c->base,
								  mode);
				} else if (gi2c->dbg_buf_ptr) {
					gi2c->dbg_buf_ptr[i].virt_buf =
								(void *)dma_buf;
					gi2c->dbg_buf_ptr[i].map_buf =
								(void *)&tx_dma;
				}
			}
			if (mode == FIFO_MODE) /* Get FIFO IRQ */
@@ -798,17 +903,23 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
		mb();
		timeout = wait_for_completion_timeout(&gi2c->xfer,
						gi2c->xfer_timeout);
		if (!timeout)
		if (!timeout) {
			GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
				"I2C xfer timeout: %d\n", gi2c->xfer_timeout);
			geni_i2c_err(gi2c, GENI_TIMEOUT);
		}

		if (gi2c->err) {
			reinit_completion(&gi2c->xfer);
			gi2c->cur = NULL;
			geni_cancel_m_cmd(gi2c->base);
			timeout = wait_for_completion_timeout(&gi2c->xfer, HZ);
			if (!timeout)
			if (!timeout) {
				GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
					"Abort\n");
				geni_abort_m_cmd(gi2c->base);
			}
		}
		gi2c->cur_wr = 0;
		gi2c->cur_rd = 0;
		if (mode == SE_DMA) {
@@ -830,7 +941,8 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
		}
		ret = gi2c->err;
		if (gi2c->err) {
			dev_err(gi2c->dev, "i2c error :%d\n", gi2c->err);
			GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
				"i2c error :%d\n", gi2c->err);
			break;
		}
	}
@@ -842,7 +954,8 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
	pm_runtime_put_autosuspend(gi2c->dev);
	gi2c->cur = NULL;
	gi2c->err = 0;
	dev_dbg(gi2c->dev, "i2c txn ret:%d\n", ret);
	GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
			"i2c txn ret:%d\n", ret);
	return ret;
}

@@ -868,6 +981,10 @@ static int geni_i2c_probe(struct platform_device *pdev)
	if (!gi2c)
		return -ENOMEM;

	if (arr_idx < MAX_SE)
		/* Debug purpose */
		gi2c_dev_dbg[arr_idx++] = gi2c;

	gi2c->dev = &pdev->dev;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1029,9 +1146,15 @@ static int geni_i2c_probe(struct platform_device *pdev)
static int geni_i2c_remove(struct platform_device *pdev)
{
	struct geni_i2c_dev *gi2c = platform_get_drvdata(pdev);
	int i;

	pm_runtime_disable(gi2c->dev);
	i2c_del_adapter(&gi2c->adap);

	for (i = 0; i < arr_idx; i++)
		gi2c_dev_dbg[i] = NULL;
	arr_idx = 0;

	if (gi2c->ipcl)
		ipc_log_context_destroy(gi2c->ipcl);
	return 0;
@@ -1039,6 +1162,9 @@ static int geni_i2c_remove(struct platform_device *pdev)

static int geni_i2c_resume_noirq(struct device *device)
{
	struct geni_i2c_dev *gi2c = dev_get_drvdata(device);

	GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n", __func__);
	return 0;
}

@@ -1059,6 +1185,7 @@ static int geni_i2c_runtime_suspend(struct device *dev)
	} else {
		se_geni_resources_off(&gi2c->i2c_rsc);
	}
	GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n", __func__);
	return 0;
}

@@ -1070,7 +1197,7 @@ static int geni_i2c_runtime_resume(struct device *dev)
	if (!gi2c->ipcl) {
		char ipc_name[I2C_NAME_SIZE];

		snprintf(ipc_name, I2C_NAME_SIZE, "i2c-%d", gi2c->adap.nr);
		snprintf(ipc_name, I2C_NAME_SIZE, "%s", dev_name(gi2c->dev));
		gi2c->ipcl = ipc_log_context_create(2, ipc_name, 0);
	}

@@ -1096,6 +1223,7 @@ static int geni_i2c_runtime_resume(struct device *dev)
		if (gi2c->se_mode == FIFO_SE_DMA)
			enable_irq(gi2c->irq);
	}
	GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n", __func__);

	return 0;
}
@@ -1113,6 +1241,8 @@ static int geni_i2c_suspend_noirq(struct device *device)
		return -EBUSY;
	}
	if (!pm_runtime_status_suspended(device)) {
		GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
			"%s\n", __func__);
		geni_i2c_runtime_suspend(device);
		pm_runtime_disable(device);
		pm_runtime_set_suspended(device);
+17 −1
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
 */

#ifndef __MSM_GPI_H_
@@ -29,6 +29,22 @@ enum msm_gpi_tre_type {

#define MSM_GPI_TRE_TYPE(tre) ((tre->dword[3] >> 16) & 0xFF)

/* Lock TRE */
#define MSM_GPI_LOCK_TRE_DWORD0 (0)
#define MSM_GPI_LOCK_TRE_DWORD1 (0)
#define MSM_GPI_LOCK_TRE_DWORD2 (0)
#define MSM_GPI_LOCK_TRE_DWORD3(link_rx, bei, ieot, ieob, ch) \
	((0x3 << 20) | (0x0 << 16) | (link_rx << 11) | (bei << 10) | \
	(ieot << 9) | (ieob << 8) | ch)

/* Unlock TRE */
#define MSM_GPI_UNLOCK_TRE_DWORD0 (0)
#define MSM_GPI_UNLOCK_TRE_DWORD1 (0)
#define MSM_GPI_UNLOCK_TRE_DWORD2 (0)
#define MSM_GPI_UNLOCK_TRE_DWORD3(link_rx, bei, ieot, ieob, ch) \
	((0x3 << 20) | (0x1 << 16) | (link_rx << 11) | (bei << 10) | \
	(ieot << 9) | (ieob << 8) | ch)

/* DMA w. Buffer TRE */
#ifdef CONFIG_ARM64
#define MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(ptr) ((u32)ptr)