/*
 * mdss_dsi_cmds_tx:
 * thread context only
 */
int mdss_dsi_cmds_tx(struct mdss_dsi_ctrl_pdata *ctrl,
		struct dsi_cmd_desc *cmds, int cnt)
{
	struct dsi_buf *tp;
	struct dsi_cmd_desc *cm;
	struct dsi_ctrl_hdr *dchdr;
	u32 dsi_ctrl, data;
	int i, video_mode;
#ifdef CONFIG_OLED_SUPPORT
#ifdef LGE_HRTIMER_OLED_PATCH
#else
	struct timeval tv_start, tv_end;
	long tv_diff;
	int delay_count;
#endif
#endif

	if (ctrl->shared_pdata.broadcast_enable) {
		if (ctrl->ndx == DSI_CTRL_0) {
			pr_debug("%s: Broadcast mode. 1st ctrl\n",
				 __func__);
			return 0;
		}
	}

	if (ctrl->shared_pdata.broadcast_enable) {
		if ((ctrl->ndx == DSI_CTRL_1)
		  && (left_ctrl_pdata != NULL)) {
			dsi_ctrl = MIPI_INP(left_ctrl_pdata->ctrl_base
								+ 0x0004);
			video_mode = dsi_ctrl & 0x02; /* VIDEO_MODE_EN */
			if (video_mode) {
				data = dsi_ctrl | 0x04; /* CMD_MODE_EN */
				MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004,
						data);
			}
		}
	}

	/* turn on cmd mode
	* for video mode, do not send cmds more than
	* one pixel line, since it only transmit it
	* during BLLP.
	*/
	dsi_ctrl = MIPI_INP((ctrl->ctrl_base) + 0x0004);
	video_mode = dsi_ctrl & 0x02; /* VIDEO_MODE_EN */
	if (video_mode) {
		data = dsi_ctrl | 0x04; /* CMD_MODE_EN */
		MIPI_OUTP((ctrl->ctrl_base) + 0x0004, data);
	}

	tp = &ctrl->tx_buf;
	cm = cmds;
	for (i = 0; i < cnt; i++) {
		mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM);
		mdss_dsi_buf_init(tp);
		mdss_dsi_cmd_dma_add(tp, cm);
		mdss_dsi_cmd_dma_tx(ctrl, tp);
		dchdr = &cm->dchdr;
#ifdef CONFIG_OLED_SUPPORT
#ifdef LGE_HRTIMER_OLED_PATCH
	      if(dchdr->wait) {
		     printk("[Zee][OLED] mipi_dsi_tx(0x%X) start (target delay=%dms)\n", cm->payload[0], (int)dchdr->wait);

		     if(dchdr->wait > 5)
			    oled_hrtimer_delay(dchdr->wait);
		     else
			    mdelay(dchdr->wait);

		     printk("[Zee][OLED] mipi_dsi_tx(0x%X) finish (target delay=%dms)\n", cm->payload[0], (int)dchdr->wait);
	      }
#else
		if(dchdr->wait) {
			delay_count = 0;
			do_gettimeofday(&tv_start);
			do {
				mdelay(1);
				do_gettimeofday(&tv_end);
				tv_diff = ((tv_end.tv_sec - tv_start.tv_sec) * 1000000) // sec
						+ (tv_end.tv_usec - tv_start.tv_usec);			// usec
				delay_count++;
			} while(dchdr->wait * 1000 > tv_diff);
			pr_info("%s: 0x%X needs %d(ms) delay and real delay is %ld(us), delay_count(%d).\n", __func__, cm->payload[0], (int)dchdr->wait, tv_diff, delay_count);
		}
#endif
#else
		if (dchdr->wait)
			usleep(dchdr->wait * 1000);
#endif
		cm++;
	}

	if (video_mode)
		MIPI_OUTP((ctrl->ctrl_base) + 0x0004,
					dsi_ctrl); /* restore */
	return cnt;
}
static int mdss_dsi_cmds2buf_tx(struct mdss_dsi_ctrl_pdata *ctrl,
			struct dsi_cmd_desc *cmds, int cnt)
{
	struct dsi_buf *tp;
	struct dsi_cmd_desc *cm;
	struct dsi_ctrl_hdr *dchdr;
	int len, wait, tot = 0;

#ifdef CONFIG_OLED_SUPPORT
#ifdef LGE_HRTIMER_OLED_PATCH
#else
	struct timeval tv_start, tv_end;
	long tv_diff;
	int delay_count;
#endif
#endif

	tp = &ctrl->tx_buf;
	mdss_dsi_buf_init(tp);
	cm = cmds;
	len = 0;
	while (cnt--) {
		dchdr = &cm->dchdr;
		mdss_dsi_buf_reserve(tp, len);
		len = mdss_dsi_cmd_dma_add(tp, cm);
		if (!len) {
			pr_err("%s: failed to add cmd = 0x%x\n",
				__func__,  cm->payload[0]);
			return -EINVAL;
		}
		tot += len;
		if (dchdr->last) {
			tp->data = tp->start; /* begin of buf */

			wait = mdss_dsi_wait4video_eng_busy(ctrl);

			mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM);
			len = mdss_dsi_cmd_dma_tx(ctrl, tp);
			if (IS_ERR_VALUE(len)) {
				mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM);
				pr_err("%s: failed to call cmd_dma_tx for cmd = 0x%x\n",
					__func__,  cmds->payload[0]);
				return -EINVAL;
			}
#ifdef CONFIG_OLED_SUPPORT
#ifdef LGE_HRTIMER_OLED_PATCH
			if (!wait || dchdr->wait/* > VSYNC_PERIOD*/) {
				pr_info("[Zee][OLED] mipi_dsi_tx(0x%X) start (target delay=%dms)\n", cm->payload[0], (int)dchdr->wait);

				if (dchdr->wait > 5)
					oled_hrtimer_delay(dchdr->wait);
				else
					mdelay(dchdr->wait);

				pr_info("[Zee][OLED] mipi_dsi_tx(0x%X) finish (target delay=%dms)\n", cm->payload[0], (int)dchdr->wait);
			}
#else
			if (!wait || dchdr->wait/* > VSYNC_PERIOD*/) {
				delay_count = 0;
				do_gettimeofday(&tv_start);
				do {
					mdelay(1);
					do_gettimeofday(&tv_end);
					tv_diff = ((tv_end.tv_sec - tv_start.tv_sec) * 1000000) /* sec */
						+ (tv_end.tv_usec - tv_start.tv_usec);			/* usec */
					delay_count++;
				} while (dchdr->wait * 1000 > tv_diff);
				pr_info("%s: 0x%X needs %d(ms) delay and real delay is %ld(us), delay_count(%d).\n", __func__, cm->payload[0], (int)dchdr->wait, tv_diff, delay_count);
			}
#endif
#else
			if (!wait || dchdr->wait > VSYNC_PERIOD)
				usleep(dchdr->wait * 1000);
#endif

			mdss_dsi_buf_init(tp);
			len = 0;
		}
		cm++;
	}
	return tot;
}