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

Commit 6222ca47 authored by Padmanabhan Komanduru's avatar Padmanabhan Komanduru Committed by Veera Sundaram Sankaran
Browse files

msm: mdss: add support for DMA TPG for sending panel commands



Currently, the DSI controller fetches DMA commands through the
MDP VBIF interface. The DMA data is fetched from memory only
when software triggers command DMA. The latency might be long
between fetches. A FIFO is present in the DSI controller to
bypass the VBIF interface from DSI rev 1.3.0. The user can
pre-fill the DMA data in the FIFO via the AHB bus before
triggering the command DMA operation. Add support for this.

CRs-fixed: 873962
Change-Id: Ieff7575fa4483c87e3b3665149f313828d9b09a7
Signed-off-by: default avatarPadmanabhan Komanduru <pkomandu@codeaurora.org>
[veeras@codeaurora.org: Resolve conflicts in mdss_dsi_host.c]
Signed-off-by: default avatarVeera Sundaram Sankaran <veeras@codeaurora.org>
parent f9c04f16
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -503,10 +503,10 @@ int dsi_panel_device_register(struct platform_device *ctrl_pdev,
	struct device_node *pan_node, struct mdss_dsi_ctrl_pdata *ctrl_pdata);

int mdss_dsi_cmds_tx(struct mdss_dsi_ctrl_pdata *ctrl,
		struct dsi_cmd_desc *cmds, int cnt);
		struct dsi_cmd_desc *cmds, int cnt, int use_dma_tpg);

int mdss_dsi_cmds_rx(struct mdss_dsi_ctrl_pdata *ctrl,
			struct dsi_cmd_desc *cmds, int rlen);
			struct dsi_cmd_desc *cmds, int rlen, int use_dma_tpg);

void mdss_dsi_host_init(struct mdss_panel_data *pdata);
void mdss_dsi_op_mode_config(int mode,
+1 −0
Original line number Diff line number Diff line
@@ -100,6 +100,7 @@ struct dsi_cmd_desc {
#define CMD_REQ_COMMIT  0x0002
#define CMD_CLK_CTRL    0x0004
#define CMD_REQ_UNICAST 0x0008
#define CMD_REQ_DMA_TPG 0x0040
#define CMD_REQ_NO_MAX_PKT_SIZE 0x0008
#define CMD_REQ_LP_MODE 0x0010
#define CMD_REQ_HS_MODE 0x0020
+155 −34
Original line number Diff line number Diff line
@@ -30,6 +30,8 @@
#include "mdss_smmu.h"

#define VSYNC_PERIOD 17
#define DMA_TX_TIMEOUT 200
#define DMA_TPG_FIFO_LEN 64

struct mdss_dsi_ctrl_pdata *ctrl_list[DSI_CTRL_MAX];

@@ -1290,8 +1292,107 @@ static int mdss_dsi_cmd_dma_tx(struct mdss_dsi_ctrl_pdata *ctrl,
static int mdss_dsi_cmd_dma_rx(struct mdss_dsi_ctrl_pdata *ctrl,
			struct dsi_buf *rp, int rlen);

static int mdss_dsi_cmd_dma_tpg_tx(struct mdss_dsi_ctrl_pdata *ctrl,
					struct dsi_buf *tp)
{
	int len, i, ret = 0, data = 0;
	u32 *bp, ctrl_rev;
	struct mdss_dsi_ctrl_pdata *mctrl = NULL;

	if (tp->len > DMA_TPG_FIFO_LEN) {
		pr_debug("command length more than FIFO length\n");
		return -EINVAL;
	}

	ctrl_rev = MIPI_INP(ctrl->ctrl_base);

	if (ctrl_rev < MDSS_DSI_HW_REV_103) {
		pr_err("CMD DMA TPG not supported for this DSI version\n");
		return -EINVAL;
	}

	bp = (u32 *)tp->data;
	len = ALIGN(tp->len, 4);

	reinit_completion(&ctrl->dma_comp);

	if (mdss_dsi_sync_wait_trigger(ctrl))
		mctrl = mdss_dsi_get_other_ctrl(ctrl);

	data = BIT(16) | BIT(17);	/* select CMD_DMA_PATTERN_SEL to 3 */
	data |= BIT(2);			/* select CMD_DMA_FIFO_MODE to 1 */
	data |= BIT(1);			/* enable CMD_DMA_TPG */

	MIPI_OUTP(ctrl->ctrl_base + 0x15c, data);
	if (mctrl)
		MIPI_OUTP(mctrl->ctrl_base + 0x15c, data);

	/*
	 * The DMA command parameters need to be programmed to the DMA_INIT_VAL
	 * register in the proper order. The 'len' value will be a multiple
	 * of 4, the padding bytes to make sure of this will be taken care of in
	 * mdss_dsi_cmd_dma_add API.
	 */
	for (i = 0; i < len; i += 4) {
		MIPI_OUTP(ctrl->ctrl_base + 0x17c, *bp);
		if (mctrl)
			MIPI_OUTP(mctrl->ctrl_base + 0x17c, *bp);
		wmb(); /* make sure write happens before writing next command */
		bp++;
	}

	/*
	 * The number of writes to the DMA_INIT_VAL register should be an even
	 * number of dwords (32 bits). In case 'len' is not a multiple of 8,
	 * we need to do make an extra write to the register with 0x00 to
	 * satisfy this condition.
	 */
	if ((len % 8) != 0) {
		MIPI_OUTP(ctrl->ctrl_base + 0x17c, 0x00);
		if (mctrl)
			MIPI_OUTP(mctrl->ctrl_base + 0x17c, 0x00);
	}

	if (mctrl) {
		MIPI_OUTP(mctrl->ctrl_base + 0x04c, len);
		MIPI_OUTP(mctrl->ctrl_base + 0x090, 0x01); /* trigger */
	}
	MIPI_OUTP(ctrl->ctrl_base + 0x04c, len);
	wmb(); /* make sure DMA length is programmed */

	MIPI_OUTP(ctrl->ctrl_base + 0x090, 0x01); /* trigger */
	wmb(); /* make sure DMA trigger happens */

	ret = wait_for_completion_timeout(&ctrl->dma_comp,
				msecs_to_jiffies(DMA_TX_TIMEOUT));
	if (ret == 0)
		ret = -ETIMEDOUT;
	else
		ret = tp->len;

	/* Reset the DMA TPG FIFO */
	MIPI_OUTP(ctrl->ctrl_base + 0x1ec, 0x1);
	wmb(); /* make sure FIFO reset happens */
	MIPI_OUTP(ctrl->ctrl_base + 0x1ec, 0x0);
	wmb(); /* make sure FIFO reset happens */
	/* Disable CMD_DMA_TPG */
	MIPI_OUTP(ctrl->ctrl_base + 0x15c, 0x0);

	if (mctrl) {
		/* Reset the DMA TPG FIFO */
		MIPI_OUTP(mctrl->ctrl_base + 0x1ec, 0x1);
		wmb(); /* make sure FIFO reset happens */
		MIPI_OUTP(mctrl->ctrl_base + 0x1ec, 0x0);
		wmb(); /* make sure FIFO reset happens */
		/* Disable CMD_DMA_TPG */
		MIPI_OUTP(mctrl->ctrl_base + 0x15c, 0x0);
	}

	return ret;
}

static int mdss_dsi_cmds2buf_tx(struct mdss_dsi_ctrl_pdata *ctrl,
			struct dsi_cmd_desc *cmds, int cnt)
			struct dsi_cmd_desc *cmds, int cnt, int use_dma_tpg)
{
	struct dsi_buf *tp;
	struct dsi_cmd_desc *cm;
@@ -1318,6 +1419,9 @@ static int mdss_dsi_cmds2buf_tx(struct mdss_dsi_ctrl_pdata *ctrl,
			wait = mdss_dsi_wait4video_eng_busy(ctrl);

			mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM);
			if (use_dma_tpg)
				len = mdss_dsi_cmd_dma_tpg_tx(ctrl, tp);
			else
				len = mdss_dsi_cmd_dma_tx(ctrl, tp);
			if (IS_ERR_VALUE(len)) {
				mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM);
@@ -1378,7 +1482,7 @@ static inline bool __mdss_dsi_cmd_mode_config(
 * thread context only
 */
int mdss_dsi_cmds_tx(struct mdss_dsi_ctrl_pdata *ctrl,
		struct dsi_cmd_desc *cmds, int cnt)
		struct dsi_cmd_desc *cmds, int cnt, int use_dma_tpg)
{
	int len = 0;
	struct mdss_dsi_ctrl_pdata *mctrl = NULL;
@@ -1413,7 +1517,7 @@ int mdss_dsi_cmds_tx(struct mdss_dsi_ctrl_pdata *ctrl,
do_send:
	ctrl->cmd_cfg_restore = __mdss_dsi_cmd_mode_config(ctrl, 1);

	len = mdss_dsi_cmds2buf_tx(ctrl, cmds, cnt);
	len = mdss_dsi_cmds2buf_tx(ctrl, cmds, cnt, use_dma_tpg);
	if (!len)
		pr_err("%s: failed to call\n", __func__);

@@ -1454,7 +1558,7 @@ static struct dsi_cmd_desc pkt_size_cmd = {
 *
 */
int mdss_dsi_cmds_rx(struct mdss_dsi_ctrl_pdata *ctrl,
			struct dsi_cmd_desc *cmds, int rlen)
			struct dsi_cmd_desc *cmds, int rlen, int use_dma_tpg)
{
	int data_byte, rx_byte, dlen, end;
	int short_response, diff, pkt_size, ret = 0;
@@ -1536,6 +1640,9 @@ do_send:
		mdss_dsi_wait4video_eng_busy(ctrl);

		mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM);
		if (use_dma_tpg)
			ret = mdss_dsi_cmd_dma_tpg_tx(ctrl, tp);
		else
			ret = mdss_dsi_cmd_dma_tx(ctrl, tp);
		if (IS_ERR_VALUE(ret)) {
			mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM);
@@ -1569,6 +1676,9 @@ do_send:
		mdss_dsi_wait4video_eng_busy(ctrl);	/* video mode only */
		mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM);
		/* transmit read comamnd to client */
		if (use_dma_tpg)
			ret = mdss_dsi_cmd_dma_tpg_tx(ctrl, tp);
		else
			ret = mdss_dsi_cmd_dma_tx(ctrl, tp);
		if (IS_ERR_VALUE(ret)) {
			mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM);
@@ -1670,8 +1780,6 @@ end:
	return rp->read_cnt;
}

#define DMA_TX_TIMEOUT 200

static int mdss_dsi_cmd_dma_tx(struct mdss_dsi_ctrl_pdata *ctrl,
					struct dsi_buf *tp)
{
@@ -2101,7 +2209,8 @@ int mdss_dsi_cmdlist_tx(struct mdss_dsi_ctrl_pdata *ctrl,
			ctrl->do_unicast = true;
	}

	len = mdss_dsi_cmds_tx(ctrl, req->cmds, req->cmds_cnt);
	len = mdss_dsi_cmds_tx(ctrl, req->cmds, req->cmds_cnt,
				(req->flags & CMD_REQ_DMA_TPG));

	if (req->cb)
		req->cb(len);
@@ -2117,7 +2226,8 @@ int mdss_dsi_cmdlist_rx(struct mdss_dsi_ctrl_pdata *ctrl,

	if (req->rbuf) {
		rp = &ctrl->rx_buf;
		len = mdss_dsi_cmds_rx(ctrl, req->cmds, req->rlen);
		len = mdss_dsi_cmds_rx(ctrl, req->cmds, req->rlen,
				(req->flags & CMD_REQ_DMA_TPG));
		memcpy(req->rbuf, rp->data, rp->len);
		ctrl->rx_len = len;
	} else {
@@ -2138,6 +2248,7 @@ int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
	int ret = -EINVAL;
	int rc = 0;
	bool hs_req = false;
	u32 ctrl_rev;

	if (mdss_get_sd_client_cnt())
		return -EPERM;
@@ -2160,6 +2271,12 @@ int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
	/* make sure dsi_cmd_mdp is idle */
	mdss_dsi_cmd_mdp_busy(ctrl);

	ctrl_rev = MIPI_INP(ctrl->ctrl_base);

	/* For DSI versions less than 1.3.0, CMD DMA TPG is not supported */
	if (req && (ctrl_rev < MDSS_DSI_HW_REV_103))
		req->flags &= ~CMD_REQ_DMA_TPG;

	pr_debug("%s: ctrl=%d from_mdp=%d pid=%d\n", __func__,
				ctrl->ndx, from_mdp, current->pid);

@@ -2186,6 +2303,9 @@ int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)

	MDSS_XLOG(ctrl->ndx, req->flags, req->cmds_cnt, from_mdp, current->pid);

	pr_debug("%s:  from_mdp=%d pid=%d\n", __func__, from_mdp, current->pid);

	if (!(req->flags & CMD_REQ_DMA_TPG)) {
		/*
		* mdss interrupt is generated in mdp core clock domain
		* mdp clock need to be enabled to receive dsi interrupt
@@ -2200,8 +2320,6 @@ int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
			return rc;
		}

	pr_debug("%s:  from_mdp=%d pid=%d\n", __func__, from_mdp, current->pid);

		if (ctrl->mdss_util->iommu_ctrl) {
			rc = ctrl->mdss_util->iommu_ctrl(1);
			if (IS_ERR_VALUE(rc)) {
@@ -2210,6 +2328,7 @@ int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
				return rc;
			}
		}
	}

	mdss_dsi_clk_ctrl(ctrl, ctrl->dsi_clk_handle, MDSS_DSI_ALL_CLKS,
			  MDSS_DSI_CLK_ON);
@@ -2225,13 +2344,15 @@ int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
	if (req->flags & CMD_REQ_HS_MODE)
		mdss_dsi_set_tx_power_mode(1, &ctrl->panel_data);

	if (!(req->flags & CMD_REQ_DMA_TPG)) {
		if (ctrl->mdss_util->iommu_ctrl)
			ctrl->mdss_util->iommu_ctrl(0);

		(void)mdss_dsi_bus_bandwidth_vote(ctrl->shared_data, false);
		mdss_dsi_clk_ctrl(ctrl, ctrl->dsi_clk_handle, MDSS_DSI_ALL_CLKS,
			  MDSS_DSI_CLK_OFF);
	}

	(void)mdss_dsi_bus_bandwidth_vote(ctrl->shared_data, false);
need_lock:

	MDSS_XLOG(ctrl->ndx, from_mdp, ctrl->mdp_busy, current->pid,