/*delete mdss_mdp_get_clk_rate() to avoid panic*/
void mdp_underrun_dsm_report(unsigned long num,unsigned long underrun_cnt)
{
	/* try to get permission to use the buffer */
	if(dsm_client_ocuppy(lcd_dclient))
	{
		/* buffer is busy */
		LCD_LOG_ERR("%s: buffer is busy!\n", __func__);
		return;
	}
	dsm_client_record(lcd_dclient, "Lcd underrun detected for ctl=%d,count=%d\n",num,underrun_cnt);
	dsm_client_notify(lcd_dclient, DSM_LCD_MDSS_UNDERRUN_ERROR_NO);
}
int mdss_record_dsm_err(u32 *dsi_status)
{
	if( NULL == lcd_dclient )
	{
		LCD_LOG_ERR("%s: there is no lcd_dclient!\n", __func__);
		return -1;
	}

	/* try to get permission to use the buffer */
	if(dsm_client_ocuppy(lcd_dclient))
	{
		/* buffer is busy */
		LCD_LOG_ERR("%s: buffer is busy!\n", __func__);
		return -1;
	}

	LCD_LOG_INFO("%s: entry!\n", __func__);
	if (dsi_status[0])
		dsm_client_record(lcd_dclient, "DSI_ACK_ERR_STATUS is wrong ,err number :%x\n", dsi_status[0]);

	if (dsi_status[1] & 0x0111)
		dsm_client_record(lcd_dclient, "DSI_TIMEOUT_STATUS is wrong ,err number :%x\n", dsi_status[1]);

	if (dsi_status[2] & 0x011111)
		dsm_client_record(lcd_dclient, "DSI_DLN0_PHY_ERR is wrong ,err number :%x\n", dsi_status[2]);

	if (dsi_status[3] & 0xcccc4489) 
		dsm_client_record(lcd_dclient, "DSI_FIFO_STATUS is wrong ,err number :%x\n", dsi_status[3]);

	if (dsi_status[4] & 0x80000000) 
		dsm_client_record(lcd_dclient, "DSI_STATUS is wrong ,err number :%x\n", dsi_status[4]);

	dsm_client_notify(lcd_dclient, DSM_LCD_MDSS_DSI_ISR_ERROR_NO);

	return 0;
}
static int fget_dtsi_style(unsigned char * buf, int max_num, int fd,off_t *fd_seek)
{
	int cur_seek=*fd_seek;
	unsigned char ch = '\0';
	unsigned char last_char = 'Z';
	int j =0;
	
	sys_lseek(fd, (off_t)0,0);

	while (j < max_num) {
		if ((unsigned)sys_read(fd, &ch, 1) != 1) {
			LCD_LOG_INFO("\n%s: its end of file %d : len = %d\n", __func__, __LINE__, j);
			return j;
		}
		else
		{
			if (!IS_VALID_CHAR(ch)) {
				last_char = 'Z';
				cur_seek++;
				sys_lseek(fd, (off_t)cur_seek,0);
				continue;
			}

			if (last_char != 'Z') {
				/*two char value is possible like F0, so make it a single char*/
				--j;
				buf[j] = (buf[j] * HEX_BASE) + hex_char_to_value(ch);
				last_char = 'Z';
			} else {
				buf[j]= hex_char_to_value(ch);
				last_char = buf[j];
			}

			j++;
			cur_seek++;
			sys_lseek(fd, (off_t)cur_seek,0);
		}
	}

	if (j >= max_num){
		LCD_LOG_ERR("%s:Buffer is not enough", __func__);
		j *= -1;
	}

	*fd_seek=cur_seek;
	return j;
}
/* set global ctrl_pdata pointer */
void lcd_dbg_set_dsi_ctrl_pdata(struct mdss_dsi_ctrl_pdata *ctrl)
{
	static char already_set = 0;  

	/* judge if already set or not*/
	if (already_set)
	{
		LCD_LOG_ERR("%s: already set\n", __func__);
	}
	else
	{
		g_lcd_dbg_dsi_ctrl_pdata = ctrl;
		already_set = 1;   
	}

	return;
}
bool lcd_debug_malloc_dtsi_para(void **para_table, uint32_t *para_num)
{
	int ret = 0 ;
	int fd = 0 ;
	void * table_tmp = NULL;
	int num_tmp =0 ;
	mm_segment_t fs;

	if(NULL==para_table){
		return FALSE;
	}

	fs = get_fs();     /* save previous value */
	set_fs (get_ds()); /* use kernel limit */

	fd = sys_open((const char __force *) HW_LCD_INIT_TEST_PARAM, O_RDONLY, 0);
	if (fd < 0) 
	{
		LCD_LOG_INFO("%s: %s file doesn't exsit\n", __func__, HW_LCD_INIT_TEST_PARAM);
		set_fs(fs);
		return FALSE;
	}

	LCD_LOG_INFO( "%s: Config file %s opened. \n", __func__, HW_LCD_INIT_TEST_PARAM);

	//resolve the config file
	ret = lcd_resolve_dtsi_config_file(fd, &table_tmp,&num_tmp);
	sys_close(fd);
	set_fs(fs);

	*para_table = table_tmp;
	*para_num = (uint32_t)num_tmp;

	if (FALSE == ret){
		LCD_LOG_ERR("%s failed to read the init code into memory\n",__func__);
		return FALSE;
	}
	*para_table = table_tmp;

	LCD_LOG_INFO("%s init code is copied into memory\n",__func__);
	return TRUE;
}
int lcd_report_dsm_err(int type, int err_value,int add_value)
{
    
	if ((DSM_LCD_MIPI_ERROR_NO == type && 0x51 == add_value)|| DSM_LCD_MDSS_DSI_ISR_ERROR_NO == type)
	{
		return 0;
	}

	LCD_LOG_INFO("%s: entry! type:%d\n", __func__, type);


	if( NULL == lcd_dclient )
	{
		LCD_LOG_ERR("%s: there is not lcd_dclient!\n", __func__);
		return -1;
	}

	/* try to get permission to use the buffer */
	if(dsm_client_ocuppy(lcd_dclient))
	{
		/* buffer is busy */
		LCD_LOG_ERR("%s: buffer is busy!\n", __func__);
		return -1;
	}

	/* lcd report err according to err type */
	switch(type)
	{
		case DSM_LCD_STATUS_ERROR_NO:
			dsm_client_record(lcd_dclient, "lcd register %x status wrong, value :%x\n",add_value, err_value);
			break;
		case DSM_LCD_MIPI_ERROR_NO:
			dsm_client_record(lcd_dclient, "mipi transmit register %x time out ,err number :%x\n", add_value, err_value );
			break;
		/* add for lcd esd */
		case DSM_LCD_ESD_STATUS_ERROR_NO:
			dsm_client_record(lcd_dclient, "LCD STATUS ERROR %x read data = %x\n", add_value, err_value );
			break;
		case DSM_LCD_ESD_REBOOT_ERROR_NO:
			dsm_client_record(lcd_dclient, "LCD RESET register %x read data =%x\n", add_value, err_value );
			break;
		case DSM_LCD_MDSS_IOMMU_ERROR_NO:
			dsm_client_record(lcd_dclient, "mdss iommu attach/detach or map memory fail (%d)\n", err_value);
			break;
		case DSM_LCD_MDSS_PIPE_ERROR_NO:
			dsm_client_record(lcd_dclient, "mdss pipe status error (%d)\n",err_value);
			break;
		case DSM_LCD_MDSS_PINGPONG_ERROR_NO:
			dsm_client_record(lcd_dclient, "mdss wait pingpong time out (%d)\n",err_value);
			break;
		case DSM_LCD_MDSS_VSP_ERROR_NO:
			dsm_client_record(lcd_dclient, "get vsp/vsn(%d) register fail (%d) \n", add_value, err_value);
			break;
		case DSM_LCD_MDSS_ROTATOR_ERROR_NO:
			dsm_client_record(lcd_dclient, "mdss rotator queue fail (%d) \n",err_value);
			break;
		case DSM_LCD_MDSS_FENCE_ERROR_NO:
			dsm_client_record(lcd_dclient, "mdss sync_fence_wait fail (%d) \n", err_value);
			break;
		case DSM_LCD_MDSS_CMD_STOP_ERROR_NO:
			dsm_client_record(lcd_dclient, "mdss stop cmd time out (%d) \n", err_value);
			break;
		case DSM_LCD_MDSS_VIDEO_DISPLAY_ERROR_NO:
			dsm_client_record(lcd_dclient, "mdss commit without wait! ctl=%d", err_value);
			break;
		case DSM_LCD_MDSS_MDP_CLK_ERROR_NO:
			dsm_client_record(lcd_dclient, "mdss mdp clk can't be turned off\n", err_value);
			break;
		case DSM_LCD_MDSS_MDP_BUSY_ERROR_NO:
			dsm_client_record(lcd_dclient, "mdss mdp dma tx time out (%d)\n", err_value);
			break;
		default:
			break;
	}

	dsm_client_notify(lcd_dclient, type);

	return 0;
}
/**********************************************************************************
*function:process read and write commands  for lcd reg debug
*op_type:	read or write
*reg:		lcd register
*cmd_type:	DCS or GEN
*param_num:	the count of prameters to tranfer
*param_buf:	prameters
*read_value:  value from lcd panel
*delay_ms:	delay time
*return: 0 - success, negative - fail
**********************************************************************************/
int lcd_dbg_mipi_prcess_ic_reg(int op_type,int reg, int cmd_type, int param_num, char *param_buf,int *read_value, int delay_ms)
{
	static struct dcs_cmd_req cmdreq;
	static struct dsi_cmd_desc dsi_cmd;                  // dsi cmd struct
	struct mdss_dsi_ctrl_pdata *ctrl = NULL;
#if LCD_MIPI_DEBUG_ON
	int i = 0;
#endif
	
	/* check if input legal */
	if (is_mipi_input_legal(op_type,reg, cmd_type, param_num,param_buf))
	{
		LCD_LOG_ERR("%s, input illegal.\n", __func__);
		return -1;
	}

	ctrl = lcd_dbg_get_dsi_ctrl_pdata();
	/* translate cmd_type from huawei to qcom's format */
	switch (param_num)
	{
		case 0:
		{
			if(OPER_READ == op_type)
			{
				/* DCS MODE */
				if (MIPI_DCS_COMMAND == cmd_type)
				{
					cmd_type = DTYPE_DCS_READ;
				}
				/* GEN MODE */
				else if (MIPI_GEN_COMMAND == cmd_type)
				{
					cmd_type = DTYPE_GEN_READ;
				}
			}
			else
			{
				/* DCS MODE */
				if (MIPI_DCS_COMMAND == cmd_type)
				{
					cmd_type = DTYPE_DCS_WRITE;
				}
				/* GEN MODE */
				else if (MIPI_GEN_COMMAND == cmd_type)
				{
					cmd_type = DTYPE_GEN_WRITE1;
				}
			}
			break;
		}

		case 1:
		{
			if(OPER_READ == op_type)
			{
				/* DCS MODE */
				if (MIPI_DCS_COMMAND == cmd_type)
				{
					LCD_LOG_ERR("%s ,not support this kind of dcs read! \n",__func__);
					return -1;
				}
				/* GEN MODE */
				else if (MIPI_GEN_COMMAND == cmd_type)
				{
					cmd_type = DTYPE_GEN_READ1;
				}
			}
			else
			{
				/* DCS MODE */
				if (MIPI_DCS_COMMAND == cmd_type)
				{
					cmd_type = DTYPE_DCS_WRITE1;
				}
				/* GEN MODE */
				else if (MIPI_GEN_COMMAND == cmd_type)
				{
					cmd_type = DTYPE_GEN_WRITE2;
				}
			}
			break;
		}

		default:
		{
			if(OPER_READ == op_type)
			{
				/* DCS MODE */
				if (MIPI_DCS_COMMAND == cmd_type)
				{
					LCD_LOG_ERR("%s ,not support this kind of dcs read! \n",__func__);
					return -1;
				}
				/* GEN MODE */
				else if (MIPI_GEN_COMMAND == cmd_type)
				{
					cmd_type = DTYPE_GEN_READ2;
				}
			}
			else
			{
				/* DCS MODE */
				if (MIPI_DCS_COMMAND == cmd_type)
				{
					cmd_type = DTYPE_DCS_LWRITE;
				}
				/* GEN MODE */
				else if (MIPI_GEN_COMMAND == cmd_type)
				{
					cmd_type = DTYPE_GEN_LWRITE;
				}
			}
			break;
		}
	}

	/* insert reg into param_buf's beginning */
	memmove(param_buf + 1, param_buf, param_num);
	param_buf[0] = reg;
	param_num++;

	/* debug begin */
#if LCD_MIPI_DEBUG_ON
	LCD_LOG_INFO("%s,op_type=%d, reg=0x%02x, cmd_type=0x%02x, param_num=0x%02x, delay_ms=0x%02x\n", __func__, op_type,reg, cmd_type, param_num, delay_ms);
	LCD_LOG_INFO("%s, print param_buf begin\n", __func__);
	for (i = 0; i < param_num; i++)
	{
		LCD_LOG_INFO("0x%02x ", param_buf[i]);
	}
	LCD_LOG_INFO("%s, print param_buf end\n", __func__);
#endif
	/* debug end */

	dsi_cmd.dchdr.dtype = cmd_type;
	dsi_cmd.dchdr.last =1;
	dsi_cmd.dchdr.vc = 0;
	dsi_cmd.dchdr.dlen = param_num;
	dsi_cmd.payload = param_buf;
	memset(&cmdreq, 0, sizeof(cmdreq));
	switch(op_type)
	{
		case OPER_READ:	
			dsi_cmd.dchdr.ack = 1;
			dsi_cmd.dchdr.wait = 5;//5 ms
			cmdreq.flags = CMD_REQ_RX | CMD_REQ_COMMIT;
			cmdreq.rbuf = (char*)read_value;
			break;
		case OPER_WRITE:
			dsi_cmd.dchdr.ack = 0;
			dsi_cmd.dchdr.wait = delay_ms;//5 ms
			cmdreq.flags = CMD_REQ_COMMIT;
			cmdreq.rbuf = NULL;
			break;
	}
	cmdreq.cmds = &dsi_cmd;
	cmdreq.cmds_cnt = 1;
	if (ctrl->long_read_flag)
	{
		cmdreq.rlen = 3;
	}else
	{
		cmdreq.rlen = 1;
	
	}
	cmdreq.cb = NULL; /* call back */
	mdss_dsi_cmdlist_put(ctrl, &cmdreq);
	if( op_type ==OPER_READ )
	{
		LCD_LOG_INFO("%s, read value is 0x%02x\n", __func__,cmdreq.rbuf[0]);
	}
	return 0;
}
/*
G730:
BOE:     ID[1:0]   {1:1} --->is is 5
tianma:  ID[1:0]   {0:0} --->id is 0
youda:   ID[1:0]   {1:0} --->id is 4
BYD:     ID[1:0]   {0:1} --->id is 1


BOE    IC     NT35517 
tianma IC     HX8389-B 
youda  IC     RM68190 
BYD    IC     NT35517 
*/
int hw_get_lcd_id(void)
{
	int ret = 0;
	int id0,id1;
	int gpio_id0,gpio_id1;
	int pullup_read,pulldown_read;
	static int lcd_id = GET_LCD_ID_FAIL;
	
	id0=0;
	id1=0;
	pullup_read = 0;
	pulldown_read = 0;
	gpio_id0 = LCD_ID_0_GPIO;
	gpio_id1 = LCD_ID_1_GPIO;

	
	if( (lcd_id >= 0x0) && (lcd_id <= 0xA) )//if lcd_id had read successfully,just return lcd_id.
		return lcd_id;

	if(gpio_id0 <= GET_GPIO_FAIL ||gpio_id1 <= GET_GPIO_FAIL)
		return GET_LCD_ID_FAIL;

    LCD_LOG_INFO("gpio_lcd_id0:%d gpio_lcd_id1:%d\n",gpio_id0,gpio_id1);

    ret = gpio_request(gpio_id0, "lcd_id0");
      if (ret) {
         LCD_LOG_ERR("lcd_id0 gpio[%d] request failed\n", gpio_id0);
         goto lcd_id0_req_fail;
          }

    ret = gpio_request(gpio_id1, "lcd_id1");
	if (ret) {
	     LCD_LOG_ERR("lcd_id1 gpio[%d] request failed\n", gpio_id1);
         goto lcd_id1_req_fail;
	}

	/*config id0 to pull down and read*/
	ret = gpio_tlmm_config(GPIO_CFG(gpio_id0,0,GPIO_CFG_INPUT,GPIO_CFG_PULL_DOWN,GPIO_CFG_2MA),GPIO_CFG_ENABLE);
	  if (ret) {
	     LCD_LOG_ERR("config id0 to pull down failed\n");
	     goto get_lcd_id_fail;
	    }
	udelay(10);
	pulldown_read = gpio_get_value(gpio_id0);

	/*config id0 to pull up and read*/
	ret = gpio_tlmm_config(GPIO_CFG(gpio_id0,0,GPIO_CFG_INPUT,GPIO_CFG_PULL_UP,GPIO_CFG_2MA),GPIO_CFG_ENABLE);
	if (ret) {
		LCD_LOG_ERR("config id0 to pull up failed\n");
		goto get_lcd_id_fail;
		}
	udelay(10);
	pullup_read = gpio_get_value(gpio_id0);
	if(pulldown_read != pullup_read)//float
	{
		id0 = BIT(1);
		gpio_tlmm_config(GPIO_CFG(gpio_id0,0,GPIO_CFG_INPUT,GPIO_CFG_PULL_DOWN,GPIO_CFG_2MA),GPIO_CFG_ENABLE);
	}
	else//connect 
	{
		id0 = pullup_read;//pullup_read==pulldown_read
		switch(id0)
		{
			case LCD_ID_PULL_DOWN:
			case LCD_ID_PULL_UP:
			default:
				gpio_tlmm_config(GPIO_CFG(gpio_id0,0,GPIO_CFG_INPUT,GPIO_CFG_NO_PULL,GPIO_CFG_2MA),GPIO_CFG_ENABLE);
				break;
		}

	}

	/*config id1 to pull down and read*/
	ret = gpio_tlmm_config(GPIO_CFG(gpio_id1,0,GPIO_CFG_INPUT,GPIO_CFG_PULL_DOWN,GPIO_CFG_2MA),GPIO_CFG_ENABLE);
	if (ret) {
		LCD_LOG_ERR("config id1 to pull down failed\n");
		goto get_lcd_id_fail;
		}
	udelay(10);
	pulldown_read = gpio_get_value(gpio_id1);

	/*config id1 to pull up and read*/
	ret = gpio_tlmm_config(GPIO_CFG(gpio_id1,0,GPIO_CFG_INPUT,GPIO_CFG_PULL_UP,GPIO_CFG_2MA),GPIO_CFG_ENABLE);
	if (ret) {
		LCD_LOG_ERR("config id1 to pull up failed\n");
		goto get_lcd_id_fail;
		}
	udelay(10);
	pullup_read = gpio_get_value(gpio_id1);
	if(pulldown_read != pullup_read)//float
	{
		id1 = BIT(1);
		gpio_tlmm_config(GPIO_CFG(gpio_id1,0,GPIO_CFG_INPUT,GPIO_CFG_PULL_DOWN,GPIO_CFG_2MA),GPIO_CFG_ENABLE);
	}
	else//connect
	{
		id1 = pullup_read;//pullup_read==pulldown_read
		switch(id1)
		{
			case LCD_ID_PULL_DOWN:
			case LCD_ID_PULL_UP:
			default:
				gpio_tlmm_config(GPIO_CFG(gpio_id1,0,GPIO_CFG_INPUT,GPIO_CFG_NO_PULL,GPIO_CFG_2MA),GPIO_CFG_ENABLE);
				break;
		}
	}

	gpio_free(gpio_id0);
	gpio_free(gpio_id1);

	lcd_id = (id1<<2) | id0;
	return lcd_id;
get_lcd_id_fail:
	gpio_free(gpio_id1);
lcd_id1_req_fail:
	gpio_free(gpio_id0);
lcd_id0_req_fail:
	return GET_LCD_ID_FAIL;
}
int hw_parse_dsi_cmds(struct dsi_panel_cmds *pcmds)
{
	int blen = 0, len = 0;
	char *buf = NULL, *bp = NULL;
	struct dsi_ctrl_hdr *dchdr;
	int i = 0, cnt = 0;

	memset(pcmds, sizeof(struct dsi_panel_cmds), 0);

	if (!lcd_debug_malloc_dtsi_para((void **)&buf, &blen)) {
		//LCD_LOG_ERR("%s: failed\n", __func__);
		return -ENOMEM;
	}

	/* scan dcs commands */
	bp = buf;
	len = blen;
	cnt = 0;
	while (len > sizeof(*dchdr)) {
		dchdr = (struct dsi_ctrl_hdr *)bp;
		dchdr->dlen = ntohs(dchdr->dlen);
		if (dchdr->dlen > len) {
			LCD_LOG_ERR("%s: dtsi cmd=%x error, len=%d",
				__func__, dchdr->dtype, dchdr->dlen);
			return -ENOMEM;
		}
		bp += sizeof(*dchdr);
		len -= sizeof(*dchdr);
		bp += dchdr->dlen;
		len -= dchdr->dlen;
		cnt++;
	}

	if (len != 0) {
		LCD_LOG_ERR("%s: dcs_cmd=%x len=%d error!",
				__func__, buf[0], blen);
		kfree(buf);
		return -ENOMEM;
	}

	pcmds->cmds = kzalloc(cnt * sizeof(struct dsi_cmd_desc),
						GFP_KERNEL);
	if (!pcmds->cmds){
		kfree(buf);
		return -ENOMEM;
	}

	pcmds->cmd_cnt = cnt;
	pcmds->buf = buf;
	pcmds->blen = blen;

	bp = buf;
	len = blen;
	for (i = 0; i < cnt; i++) {
		dchdr = (struct dsi_ctrl_hdr *)bp;
		len -= sizeof(*dchdr);
		bp += sizeof(*dchdr);
		pcmds->cmds[i].dchdr = *dchdr;
		pcmds->cmds[i].payload = bp;
		bp += dchdr->dlen;
		len -= dchdr->dlen;
	}

	print_cmds(pcmds->cmds, pcmds->cmd_cnt);

	LCD_LOG_INFO("%s: dcs_cmd=%x len=%d, cmd_cnt=%d\n", __func__,
		pcmds->buf[0], pcmds->blen, pcmds->cmd_cnt);

	return 0;
}