/*
 * This driver is for IPS MIP LCD SAT101BO30I42R18-45143M048IN-1.8V which is 720x1280 display. 
 * Display ic is ICNL9707 10.1 inch panel
;合力泰 HLT090WSB60I031_D  30pin  mipi 720*1280 屏驱IC：88577
110_lcd_driver_name     = "id110_hlt090wsb60i031_d"
110_lcd_backlight       = 197
110_lcd_if              = 4
110_lcd_dsi_if          = 0
110_lcd_dsi_lane        = 4
110_lcd_dsi_format      = 0
110_lcd_dsi_te          = 0
110_lcd_dsi_eotp        = 0
110_lcd_x               = 720
110_lcd_y               = 1280
110_lcd_width           =
110_lcd_height          =
110_lcd_dclk_freq       = 79
110_lcd_pwm_used        = 1
110_lcd_pwm_ch          = 0
110_lcd_pwm_freq        = 50000
110_lcd_pwm_pol         = 1
110_lcd_hbp             = 60
110_lcd_ht              = 960
110_lcd_hspw            = 20
110_lcd_vbp             = 16
110_lcd_vt              = 1330
110_lcd_vspw            = 8
110_lcd_lvds_if         = 0
110_lcd_lvds_colordepth = 0
110_lcd_lvds_mode       = 0
110_lcd_frm             = 1
110_lcd_hv_clk_phase    = 0
110_lcd_hv_sync_polarity= 0
110_lcd_gamma_en        = 0
110_lcd_cmap_en         = 0
110_lcdgamma4iep        = 22
110_fast_carback_enable = 0
110_reverse_rotation    = 1
110_lcd_gpio_0          = port:PA8<1><0><default><1>
110_lcd_info            = " M_HLT_8857_0_000_01_N110_1_20231206"
 */

#include "panels.h"


static void LCD_power_on(u32 sel);
static void LCD_power_off(u32 sel);
static void LCD_bl_open(u32 sel);
static void LCD_bl_close(u32 sel);

static void LCD_panel_init(u32 sel);
static void LCD_panel_exit(u32 sel);

#define panel_reset(val) set_lcd_reset_state(val)
#define power_en(val)  
//#define power_en(val)  sunxi_lcd_gpio_set_value(sel, 1, val)

#define DATA_SIZE_MAX 8
#define CMD_LINE_END 0xFFFF
#define PRINT_PANEL_ID 0
#define PANEL_NAME "id110_hlt090wsb60i031_d"
struct mipi_init_code_line{
	u8 cmd_type;
	u8 data[DATA_SIZE_MAX];
	u32 data_len;
};

static struct mipi_init_code_line MIPI_INIT_CODE[] = \
{	
	
	{0xee,{0x50},1},		// page 1
	{0xea,{0x85,0x55},2},    // 
	{0x30,{0x00},1},        // bist
	{0x24,{0xa0},1},        // rgb  TE	
	{0x56,{0x83},1},  		// autolane	
	{0x79,{0x08},1},        // zigzag
	{0x7a,{0x20},1},        // 
	{0x7d,{0x00},1},        // 
	{0x80,{0x10},1},        // te v width
	{0x90,{0x25,0x40},2},   // ss_tp
	{0x93,{0xf8},1},   // 
	{0x95,{0x74},1},      //inv 
	{0x97,{0x08},1},   //   smart gip
	{0x99,{0x10},1},        // ss_delay
	{0xee,{0x60},1},
	{0x21,{0x00},1},	
	{0x27,{0x62},1},				// vddd
	{0x2c,{0xf9},1},
	{0x29,{0x8a},1}, 
	{0x30,{0x01},1},
/*	{0x31,{0xAF},1},
	{0x32,{0xdb},1},				// vrs_tldo
	{0x33,{0xF3},1},				// dsi_rts<1:0>=10  
	{0x34,{0x3f},1}, */
	{ 0x31,{0x0f},1},
        { 0x32,{0xd9},1},
        { 0x33,{0xc0},1},
        { 0x34,{0x1f},1},
	{ 0x35,{0x10},1},
      { 0x36,{0x00},1},
        { 0x37,{0x00},1}, 
	{0x3a,{0x24},1},				// gas off
	{0x3b,{0x00},1},				// gip_s3s
	{0x3C,{0x3C},1},				// VCOM  -1.209V 
	{0x3d,{0x03,0x84},2},		
	{0x42,{0x69,0x69},2},	    //5.1v
	{0x44,{0x08},1},         //vgh=14.95v
	{0x46,{0xE8},1},		//vgl=-12.98v
	{0x86,{0x20},1},
	{0x89,{0x00},1},
	{0x8a,{0xAA},1},
	{0x90,{0x00},1},
	{0x91,{0x44},1},
	{0x92,{0x33},1},
	{0x93,{0x9B},1},              // vcsw1=1 vcsw2=0
	{0x9a,{0x05},1},				// 720
	{0x9b,{0x02,0x80},2},			// 1280
	{0x47,{0x00,0x0c,0x28,0x33,0x40},5},	//gamma P0.4.8.12.20
	{0x5a,{0x00,0x0c,0x28,0x33,0x40},5},	//gamma n 0.4.8.12.20
	{0x4c,{0x4b,0x44,0x56,0x39,0x3b},5},	//28.44.64.96.128. 
	{0x5f,{0x4b,0x44,0x56,0x39,0x3b},5},	//28.44.64.96.128. 
	{0x51,{0x3d,0x25,0x3a,0x35,0x43},5},	//159.191.211.227.235 
	{0x64,{0x3d,0x25,0x3a,0x35,0x43},5},	//159.191.211.227.235  
	{0x56,{0x45,0x51,0x61,0x7F},4},	//243.247.251.255
	{0x69,{0x45,0x51,0x61,0x7F},4},	//243.247.251.255
	{0xee,{0x70},1},  
	{0x00,{0x00,0x06,0x00,0x01},4},  //stv0
	{0x04,{0x0C,0x12,0x55,0x01},4},  //stv2
	{0x0c,{0x05,0x05},2},
	
	// CYC0 cyc1
	{0x10,{0x02,0x05,0x00,0x00,0x00},5}, 
	{0x15,{0x00,0x08,0x0d,0x08},4},   
	{0x29,{0x65,0x02},2},//d9   02 d0

	//gip-flm0						
	{0x30,{0x0E,0x0f,0x55,0x05,0x05},5},  						
	{0x35,{0x02,0x0f,0x0E,0x55,0x05},5}, 						
	{0x3a,{0x05,0x02},2}, 	


	//gip0-gip21=gipL1-gipL22 (forward scan)
	{0x60,{0x01,0x00,0x20,0x21,0x3c},5},
	{0x65,{0x13,0x12,0x11,0x10,0x17},5},
	{0x6a,{0x16,0x15,0x14,0x05,0x3f},5},
	{0x6f,{0x04,0x05,0x3c,0x3c,0x3c},5},
	{0x74,{0x3c,0x3c},2},
	{0x80,{0x01,0x00,0x20,0x21,0x3c},5},
	{0x85,{0x13,0x12,0x11,0x10,0x17},5},
	{0x8a,{0x16,0x15,0x14,0x05,0x3f},5},
	{0x8f,{0x04,0x05,0x3c,0x3c,0x3c},5},
	{0x94,{0x3c,0x3c},2},
	{0xee,{0x80},1},		// page 4
	{0x23,{0x85,0x55,0x01,0x00},4}, //  8555V01
	{0xea,{0x00,0x00},2},    // write enable
	{0xee,{0x00},1},		// ENTER PAGE0


		{ 0xff,{},CMD_LINE_END},
};
extern s32 dsi_dcs_wr(u32 sel,u8 cmd,u8* para_p,u32 para_num);
static void mipi_dsi_cmd_data_write(u32 sel, u8 cmd, u8* para, u32 para_len)
{
#if 1
	dsi_dcs_wr(0, cmd, para, para_len);
#else
	dsi_gen_wr(0, cmd, para, para_len);
#endif
}
#if PRINT_PANEL_ID
extern s32 dsi_dcs_rd(u32 sel, u8 cmd, u8* para_p, u32* num_p);
static s32 mipi_dsi_cmd_data_read(u32 sel, u8 cmd, u8* para, u32 *para_len)
{
#if 1
	return dsi_dcs_rd(0, cmd, para, para_len);
#endif
}

static void print_MIPI_LCD_ID(void)
{
	u8 param[] = {0xF0,0x5A,0x59};
	u8 read_data[70] = {0};
	u32 read_num = 0;
	s32 ret;

	mipi_dsi_cmd_data_write(0,0xB9,param,3);
	ret = mipi_dsi_cmd_data_read(0,0xDA,&read_data[0],&read_num);
	if(ret){
		printk("%s-%d: do mipi_dsi_cmd_data_read error!\n",__func__,__LINE__);
	}
	ret = mipi_dsi_cmd_data_read(0,0xDB,&read_data[1],&read_num);
	if(ret){
		printk("%s-%d: do mipi_dsi_cmd_data_read error!\n",__func__,__LINE__);
	}
	ret = mipi_dsi_cmd_data_read(0,0xDC,&read_data[2],&read_num);
	if(ret){
		printk("%s-%d: do mipi_dsi_cmd_data_read error!\n",__func__,__LINE__);
	}
	printk("%s: read_num =%d, read id 0xda,0xdb,0xdc is 0x%x,0x%x,0x%x!\n",__func__,read_num,read_data[0],read_data[1],read_data[2]);
}
#endif
static void LCD_cfg_panel_info(panel_extend_para * info)
{
	u32 i = 0, j=0;
	u32 items;
	u8 lcd_gamma_tbl[][2] =
	{
		//{input value, corrected value}
		{0, 0},
		{15, 15},
		{30, 30},
		{45, 45},
		{60, 60},
		{75, 75},
		{90, 90},
		{105, 105},
		{120, 120},
		{135, 135},
		{150, 150},
		{165, 165},
		{180, 180},
		{195, 195}, 
		{210, 210},
		{225, 225},
		{240, 240},
		{255, 255},
	};

	u32 lcd_cmap_tbl[2][3][4] = {
		{
			{LCD_CMAP_G0,LCD_CMAP_B1,LCD_CMAP_G2,LCD_CMAP_B3},
			{LCD_CMAP_B0,LCD_CMAP_R1,LCD_CMAP_B2,LCD_CMAP_R3},
			{LCD_CMAP_R0,LCD_CMAP_G1,LCD_CMAP_R2,LCD_CMAP_G3},
		},
		{
			{LCD_CMAP_B3,LCD_CMAP_G2,LCD_CMAP_B1,LCD_CMAP_G0},
			{LCD_CMAP_R3,LCD_CMAP_B2,LCD_CMAP_R1,LCD_CMAP_B0},
			{LCD_CMAP_G3,LCD_CMAP_R2,LCD_CMAP_G1,LCD_CMAP_R0},
		},
	};

	items = sizeof(lcd_gamma_tbl)/2;
	for(i=0; i<items-1; i++) {
		u32 num = lcd_gamma_tbl[i+1][0] - lcd_gamma_tbl[i][0];

		for(j=0; j<num; j++) {
			u32 value = 0;

			value = lcd_gamma_tbl[i][1] + ((lcd_gamma_tbl[i+1][1] - lcd_gamma_tbl[i][1]) * j)/num;
			info->lcd_gamma_tbl[lcd_gamma_tbl[i][0] + j] = (value<<16) + (value<<8) + value;
		}
	}
	info->lcd_gamma_tbl[255] = (lcd_gamma_tbl[items-1][1]<<16) + (lcd_gamma_tbl[items-1][1]<<8) + lcd_gamma_tbl[items-1][1];

	memcpy(info->lcd_cmap_tbl, lcd_cmap_tbl, sizeof(lcd_cmap_tbl));

}

static s32 LCD_open_flow(u32 sel)
{
	LCD_OPEN_FUNC(sel, LCD_power_on, 50);   //open lcd power, and delay 50ms
	LCD_OPEN_FUNC(sel, LCD_panel_init, 100);   //open lcd power, than delay 200ms
	LCD_OPEN_FUNC(sel, sunxi_lcd_tcon_enable, 50);     //open lcd controller, and delay 100ms
	LCD_OPEN_FUNC(sel, LCD_bl_open, 0);     //open lcd backlight, and delay 0ms
	return 0;
}

static s32 LCD_close_flow(u32 sel)
{
	LCD_CLOSE_FUNC(sel, LCD_bl_close, 0);       //close lcd backlight, and delay 0ms
	LCD_CLOSE_FUNC(sel, sunxi_lcd_tcon_disable, 0);         //close lcd controller, and delay 0ms
	LCD_CLOSE_FUNC(sel, LCD_panel_exit,	200);   //open lcd power, than delay 200ms
	LCD_CLOSE_FUNC(sel, LCD_power_off, 50);   //close lcd power, and delay 500ms
	return 0;
}

extern void set_lcd_1v8_pwr_state(int val);
extern void set_lcd_rst(int val);
static void LCD_power_on(u32 sel)
{
	set_lcd_rst(0);
	panel_reset(0);
	sunxi_lcd_delay_ms(100);
	sunxi_lcd_pin_cfg(sel, 1);
	sunxi_lcd_delay_ms(200);
	set_lcd_rst(1);
	panel_reset(1);
	sunxi_lcd_delay_ms(100);
	set_lcd_rst(0);
	panel_reset(0);
	sunxi_lcd_delay_ms(100);
	set_lcd_rst(1);
	panel_reset(1);
	sunxi_lcd_delay_ms(50);
	//set_lcd_rst(1);
	sunxi_lcd_power_enable(sel, 0);//config lcd_power pin to open lcd power
	sunxi_lcd_delay_ms(5);
	sunxi_lcd_power_enable(sel, 1);//config lcd_power pin to open lcd power0
	sunxi_lcd_delay_ms(5);
	sunxi_lcd_power_enable(sel, 2);//config lcd_power pin to open lcd power2
	sunxi_lcd_delay_ms(5);
	power_en(1);
	//sunxi_lcd_delay_ms(50);
	//panel_reset(1);
	//sunxi_lcd_delay_ms(50);
	//panel_reset(0);
	//sunxi_lcd_delay_ms(50);
	//panel_reset(1);
	//sunxi_lcd_delay_ms(50);
	//set_lcd_1v8_pwr_state(1);
	sunxi_lcd_delay_ms(100);
	sunxi_lcd_pwm_enable(sel);
	sunxi_lcd_delay_ms(200);
}

static void LCD_power_off(u32 sel)
{
	sunxi_lcd_pin_cfg(sel, 0);
	power_en(0);
	sunxi_lcd_delay_ms(20);
	panel_reset(0);
	sunxi_lcd_delay_ms(5);
	sunxi_lcd_power_disable(sel, 2);//config lcd_power pin to close lcd power2
	sunxi_lcd_delay_ms(5);
	sunxi_lcd_power_disable(sel, 1);//config lcd_power pin to close lcd power1
	sunxi_lcd_delay_ms(5);
	sunxi_lcd_power_disable(sel, 0);//config lcd_power pin to close lcd power
}

static void LCD_bl_open(u32 sel)
{
	sunxi_lcd_delay_ms(100);
	sunxi_lcd_pwm_enable(sel);
	sunxi_lcd_backlight_enable(sel);//config lcd_bl_en pin to open lcd backlight
}

static void LCD_bl_close(u32 sel)
{
	sunxi_lcd_backlight_disable(sel);//config lcd_bl_en pin to close lcd backlight
	sunxi_lcd_pwm_disable(sel);
}

static void LCD_panel_init(u32 sel)
{
	int i=0;
#if PRINT_PANEL_ID
	sunxi_lcd_dsi_clk_enable(sel);
	sunxi_lcd_delay_ms(50);
	print_MIPI_LCD_ID();
#endif
	//sunxi_lcd_delay_ms(50);
	printk("LCD_panel_init: do init %s panel.\n",PANEL_NAME);
	sunxi_lcd_dsi_clk_enable(sel);
	sunxi_lcd_delay_ms(100);

	for(i=0;i<0xff;i++)
	{
		if(MIPI_INIT_CODE[i].data_len == CMD_LINE_END)
			break;
		mipi_dsi_cmd_data_write(sel, MIPI_INIT_CODE[i].cmd_type, MIPI_INIT_CODE[i].data, MIPI_INIT_CODE[i].data_len);
	}

	//SLP OUT
	//SSD_Number(0x01);
	sunxi_lcd_dsi_dcs_write_0para(sel,0x11);  	// SLPOUT
	//Delayms(120);
	sunxi_lcd_delay_ms(250);

	//DISP ON
	//SSD_Number(0x01);
	sunxi_lcd_dsi_dcs_write_0para(sel,0x29);  	// DSPON
	//Delayms(5);
	sunxi_lcd_delay_ms(50);

	return;
}

static void LCD_panel_exit(u32 sel)
{
	sunxi_lcd_dsi_dcs_write_0para(sel,DSI_DCS_SET_DISPLAY_OFF);
	sunxi_lcd_delay_ms(20);
	sunxi_lcd_dsi_dcs_write_0para(sel,DSI_DCS_ENTER_SLEEP_MODE);
	sunxi_lcd_delay_ms(120);
	return ;
}

//sel: 0:lcd0; 1:lcd1
static s32 LCD_user_defined_func(u32 sel, u32 para1, u32 para2, u32 para3)
{
	return 0;
}

__lcd_panel_t id110_hlt090wsb60i031_d_panel = {
	/* panel driver name, must mach the name of lcd_drv_name in sys_config.fex */
	.name = PANEL_NAME,
	.func = {
		.cfg_panel_info = LCD_cfg_panel_info,
		.cfg_open_flow = LCD_open_flow,
		.cfg_close_flow = LCD_close_flow,
		.lcd_user_defined_func = LCD_user_defined_func,
	},
};
