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

Commit 6f84a3f8 authored by Vipin Deep Kaur's avatar Vipin Deep Kaur
Browse files

i2c: i2c-qcom-geni: Enhance IPC logging debug infra in I2C



Add additional logs with extra parameters which can help track
previous transfer parameters and status in I2C geni driver.

Change-Id: Id8cf640163a554e1cddbb233fd8ea59b5cfc59f1
Signed-off-by: default avatarVipin Deep Kaur <vkaur@codeaurora.org>
parent 9a711d9c
Loading
Loading
Loading
Loading
+111 −41
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)
@@ -74,12 +75,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;
@@ -118,8 +126,13 @@ 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;
};

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

struct geni_i2c_err_log {
	int err;
	const char *msg;
@@ -209,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);
@@ -223,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;
@@ -241,7 +246,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)) {
@@ -268,12 +279,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;
@@ -444,6 +449,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) {
@@ -559,6 +565,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,
@@ -571,6 +579,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);
@@ -601,6 +614,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);
@@ -612,7 +627,13 @@ 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] =
@@ -656,9 +677,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 slv:addr: 0x%x R/W: %d\n",
					gi2c->xfer_timeout, gi2c->cur->len,
					gi2c->cur->addr, gi2c->cur->flags);
				"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;
@@ -693,8 +714,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,
@@ -704,6 +732,18 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
		pm_runtime_set_suspended(gi2c->dev);
		return ret;
	}

	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;
@@ -712,9 +752,6 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
		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;
@@ -748,9 +785,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;
@@ -765,12 +801,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;
@@ -785,6 +825,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 */
@@ -795,19 +840,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) {
			if (gi2c->err) {
				reinit_completion(&gi2c->xfer);
@@ -825,9 +874,11 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
					      msgs[i].len);
			i2c_put_dma_safe_msg_buf(dma_buf, &msgs[i], !gi2c->err);
		}

		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;
		}
	}
@@ -837,9 +888,12 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,

	pm_runtime_mark_last_busy(gi2c->dev);
	pm_runtime_put_autosuspend(gi2c->dev);
	gi2c->cur_wr = 0;
	gi2c->cur_rd = 0;
	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;
}

@@ -865,6 +919,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);
@@ -901,14 +959,12 @@ static int geni_i2c_probe(struct platform_device *pdev)
		dev_err(&pdev->dev, "Err getting SE Core clk %d\n", ret);
		return ret;
	}

	gi2c->i2c_rsc.m_ahb_clk = devm_clk_get(&pdev->dev, "m-ahb");
	if (IS_ERR(gi2c->i2c_rsc.m_ahb_clk)) {
		ret = PTR_ERR(gi2c->i2c_rsc.m_ahb_clk);
		dev_err(&pdev->dev, "Err getting M AHB clk %d\n", ret);
		return ret;
	}

	gi2c->i2c_rsc.s_ahb_clk = devm_clk_get(&pdev->dev, "s-ahb");
	if (IS_ERR(gi2c->i2c_rsc.s_ahb_clk)) {
		ret = PTR_ERR(gi2c->i2c_rsc.s_ahb_clk);
@@ -987,6 +1043,7 @@ static int geni_i2c_probe(struct platform_device *pdev)
				   gi2c->irq, ret);
		return ret;
	}

	disable_irq(gi2c->irq);
	i2c_set_adapdata(&gi2c->adap, gi2c);
	gi2c->adap.dev.parent = gi2c->dev;
@@ -998,7 +1055,11 @@ static int geni_i2c_probe(struct platform_device *pdev)
	pm_runtime_set_autosuspend_delay(gi2c->dev, I2C_AUTO_SUSPEND_DELAY);
	pm_runtime_use_autosuspend(gi2c->dev);
	pm_runtime_enable(gi2c->dev);
	i2c_add_adapter(&gi2c->adap);
	ret = i2c_add_adapter(&gi2c->adap);
	if (ret) {
		dev_err(gi2c->dev, "Add adapter failed\n");
		return ret;
	}

	dev_dbg(gi2c->dev, "I2C probed\n");
	return 0;
@@ -1017,6 +1078,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;
}

@@ -1034,6 +1098,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;
}

@@ -1050,7 +1115,6 @@ static int geni_i2c_runtime_resume(struct device *dev)
	}

	ret = se_geni_resources_on(&gi2c->i2c_rsc);

	if (ret)
		return ret;

@@ -1070,23 +1134,27 @@ static int geni_i2c_runtime_resume(struct device *dev)
			gi2c->se_mode = GSI_ONLY;
			geni_se_select_mode(gi2c->base, GSI_DMA);
			GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
				    "i2c in GSI ONLY mode\n");
					"i2c GSI mode\n");
		} else {
			int gi2c_tx_depth = get_tx_fifo_depth(gi2c->base);

			gi2c->se_mode = FIFO_SE_DMA;

			gi2c->tx_wm = gi2c_tx_depth - 1;
			geni_se_init(gi2c->base, gi2c->tx_wm, gi2c_tx_depth);
			se_config_packing(gi2c->base, 8, 4, true);
			qcom_geni_i2c_conf(gi2c, 0);
			GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
				    "i2c fifo/se-dma mode. fifo depth:%d\n",
				    gi2c_tx_depth);
		}
		GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "i2c-%d: %s\n",
			gi2c->adap.nr, dev_name(gi2c->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;
}

@@ -1103,6 +1171,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);