From: Weiming Liu Date: Thu, 14 Sep 2017 05:12:42 +0000 (+0800) Subject: lcd: synchronous lcd driver from linux3.14 X-Git-Tag: khadas-vims-v0.9.6-release~2826 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1e0437fabf2838dedb9244d5227cb228d1063e5e;p=platform%2Fkernel%2Flinux-amlogic.git lcd: synchronous lcd driver from linux3.14 PD#150981: synchronous lcd driver linux3.14 to linux4.9 1.add bl_level bootargs parameter 2.repair unifykey bl_level error 3.update the mechanism of 50/60hz switch 4.add pwm & enable sequence reverse support 5.add vbyone special control adjust support Change-Id: I63136af6b96d793691eed23c064e7515e1d50aff Signed-off-by: Weiming Liu --- diff --git a/arch/arm64/boot/dts/amlogic/mesonaxg_s400-panel.dtsi b/arch/arm64/boot/dts/amlogic/mesonaxg_s400-panel.dtsi index ce1ff28..cfe878d 100644 --- a/arch/arm64/boot/dts/amlogic/mesonaxg_s400-panel.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesonaxg_s400-panel.dtsi @@ -230,6 +230,7 @@ * pwm_on_delay(ms), pwm_off_delay(ms) */ bl_pwm_power = <0 0 10 10>; + bl_pwm_en_sequence_reverse = <0>; /* 1 for reverse */ }; backlight_1{ index = <1>; @@ -245,6 +246,7 @@ * on_delay(ms), off_delay(ms) */ bl_power_attr = <1 1 0 200 200>; + bl_pwm_en_sequence_reverse = <0>; /* 1 for reverse */ bl_extern_index = <1>; }; }; diff --git a/drivers/amlogic/media/vout/backlight/aml_bl.c b/drivers/amlogic/media/vout/backlight/aml_bl.c index b219f05..6238404 100644 --- a/drivers/amlogic/media/vout/backlight/aml_bl.c +++ b/drivers/amlogic/media/vout/backlight/aml_bl.c @@ -62,6 +62,10 @@ static unsigned int bl_off_policy; module_param(bl_off_policy, uint, 0664); MODULE_PARM_DESC(bl_off_policy, "bl_off_policy"); +static unsigned int bl_level; +module_param(bl_level, uint, 0664); +MODULE_PARM_DESC(bl_level, "bl_level"); + static unsigned int bl_level_uboot; static unsigned int brightness_bypass; module_param(brightness_bypass, uint, 0664); @@ -644,21 +648,40 @@ static void bl_power_on(void) bl_power_en_ctrl(bconf, 1); break; case BL_CTRL_PWM: - /* step 1: power on pwm */ - bl_pwm_ctrl(bconf->bl_pwm, 1); - if (bconf->pwm_on_delay > 0) - mdelay(bconf->pwm_on_delay); - /* step 2: power on enable */ - bl_power_en_ctrl(bconf, 1); + if (bconf->pwm_en_sequence_reverse) { + /* step 1: power on enable */ + bl_power_en_ctrl(bconf, 1); + if (bconf->pwm_on_delay > 0) + msleep(bconf->pwm_on_delay); + /* step 2: power on pwm */ + bl_pwm_ctrl(bconf->bl_pwm, 1); + } else { + /* step 1: power on pwm */ + bl_pwm_ctrl(bconf->bl_pwm, 1); + if (bconf->pwm_on_delay > 0) + msleep(bconf->pwm_on_delay); + /* step 2: power on enable */ + bl_power_en_ctrl(bconf, 1); + } break; case BL_CTRL_PWM_COMBO: - /* step 1: power on pwm_combo */ - bl_pwm_ctrl(bconf->bl_pwm_combo0, 1); - bl_pwm_ctrl(bconf->bl_pwm_combo1, 1); - if (bconf->pwm_on_delay > 0) - mdelay(bconf->pwm_on_delay); - /* step 2: power on enable */ - bl_power_en_ctrl(bconf, 1); + if (bconf->pwm_en_sequence_reverse) { + /* step 1: power on enable */ + bl_power_en_ctrl(bconf, 1); + if (bconf->pwm_on_delay > 0) + msleep(bconf->pwm_on_delay); + /* step 2: power on pwm_combo */ + bl_pwm_ctrl(bconf->bl_pwm_combo0, 1); + bl_pwm_ctrl(bconf->bl_pwm_combo1, 1); + } else { + /* step 1: power on pwm_combo */ + bl_pwm_ctrl(bconf->bl_pwm_combo0, 1); + bl_pwm_ctrl(bconf->bl_pwm_combo1, 1); + if (bconf->pwm_on_delay > 0) + msleep(bconf->pwm_on_delay); + /* step 2: power on enable */ + bl_power_en_ctrl(bconf, 1); + } break; #ifdef CONFIG_AMLOGIC_LOCAL_DIMMING case BL_CTRL_LOCAL_DIMING: @@ -739,21 +762,40 @@ static void bl_power_off(void) bl_power_en_ctrl(bconf, 0); break; case BL_CTRL_PWM: - /* step 1: power off enable */ - bl_power_en_ctrl(bconf, 0); - /* step 2: power off pwm */ - if (bconf->pwm_off_delay > 0) - mdelay(bconf->pwm_off_delay); - bl_pwm_ctrl(bconf->bl_pwm, 0); + if (bconf->pwm_en_sequence_reverse) { + /* step 1: power off pwm */ + bl_pwm_ctrl(bconf->bl_pwm, 0); + if (bconf->pwm_off_delay > 0) + msleep(bconf->pwm_off_delay); + /* step 2: power off enable */ + bl_power_en_ctrl(bconf, 0); + } else { + /* step 1: power off enable */ + bl_power_en_ctrl(bconf, 0); + /* step 2: power off pwm */ + if (bconf->pwm_off_delay > 0) + msleep(bconf->pwm_off_delay); + bl_pwm_ctrl(bconf->bl_pwm, 0); + } break; case BL_CTRL_PWM_COMBO: - /* step 1: power off enable */ - bl_power_en_ctrl(bconf, 0); - /* step 2: power off pwm_combo */ - if (bconf->pwm_off_delay > 0) - mdelay(bconf->pwm_off_delay); - bl_pwm_ctrl(bconf->bl_pwm_combo0, 0); - bl_pwm_ctrl(bconf->bl_pwm_combo1, 0); + if (bconf->pwm_en_sequence_reverse) { + /* step 1: power off pwm_combo */ + bl_pwm_ctrl(bconf->bl_pwm_combo0, 0); + bl_pwm_ctrl(bconf->bl_pwm_combo1, 0); + if (bconf->pwm_off_delay > 0) + msleep(bconf->pwm_off_delay); + /* step 2: power off enable */ + bl_power_en_ctrl(bconf, 0); + } else { + /* step 1: power off enable */ + bl_power_en_ctrl(bconf, 0); + /* step 2: power off pwm_combo */ + if (bconf->pwm_off_delay > 0) + msleep(bconf->pwm_off_delay); + bl_pwm_ctrl(bconf->bl_pwm_combo0, 0); + bl_pwm_ctrl(bconf->bl_pwm_combo1, 0); + } break; #ifdef CONFIG_AMLOGIC_LOCAL_DIMMING case BL_CTRL_LOCAL_DIMING: @@ -798,7 +840,7 @@ static void bl_power_off(void) break; } if (bconf->power_off_delay > 0) - mdelay(bconf->power_off_delay); + msleep(bconf->power_off_delay); bl_drv->state &= ~BL_STATE_BL_ON; BLPR("backlight power off\n"); @@ -1149,6 +1191,8 @@ static void aml_bl_config_print(struct bl_config_s *bconf) case BL_CTRL_PWM: BLPR("pwm_on_delay = %dms\n", bconf->pwm_on_delay); BLPR("pwm_off_delay = %dms\n", bconf->pwm_off_delay); + BLPR("pwm_en_sequence_reverse = %d\n", + bconf->pwm_en_sequence_reverse); if (bconf->bl_pwm) { bl_pwm = bconf->bl_pwm; BLPR("pwm_index = %d\n", bl_pwm->index); @@ -1176,6 +1220,8 @@ static void aml_bl_config_print(struct bl_config_s *bconf) case BL_CTRL_PWM_COMBO: BLPR("pwm_on_delay = %dms\n", bconf->pwm_on_delay); BLPR("pwm_off_delay = %dms\n", bconf->pwm_off_delay); + BLPR("pwm_en_sequence_reverse = %d\n", + bconf->pwm_en_sequence_reverse); /* pwm_combo_0 */ if (bconf->bl_pwm_combo0) { bl_pwm = bconf->bl_pwm_combo0; @@ -1277,8 +1323,8 @@ static int aml_bl_config_load_from_dts(struct bl_config_s *bconf, /* ensure string ending */ bconf->name[BL_NAME_MAX-1] = '\0'; - ret = of_property_read_u32_array(child, "bl_level_default_uboot_kernel", - &bl_para[0], 2); + ret = of_property_read_u32_array(child, + "bl_level_default_uboot_kernel", &bl_para[0], 2); if (ret) { BLERR("failed to get bl_level_default_uboot_kernel\n"); bl_level_uboot = BL_LEVEL_DEFAULT; @@ -1287,6 +1333,7 @@ static int aml_bl_config_load_from_dts(struct bl_config_s *bconf, bl_level_uboot = bl_para[0]; bconf->level_default = bl_para[1]; } + ret = of_property_read_u32_array(child, "bl_level_attr", &bl_para[0], 4); if (ret) { @@ -1397,6 +1444,13 @@ static int aml_bl_config_load_from_dts(struct bl_config_s *bconf, bconf->pwm_on_delay = bl_para[2]; bconf->pwm_off_delay = bl_para[3]; } + ret = of_property_read_u32(child, + "bl_pwm_en_sequence_reverse", &val); + if (ret) { + BLPR("don't find bl_pwm_en_sequence_reverse\n"); + bconf->pwm_en_sequence_reverse = 0; + } else + bconf->pwm_en_sequence_reverse = val; bl_pwm->pwm_duty = bl_pwm->pwm_duty_min; /* init pwm config */ @@ -1517,6 +1571,13 @@ static int aml_bl_config_load_from_dts(struct bl_config_s *bconf, bconf->pwm_on_delay = bl_para[4]; bconf->pwm_off_delay = bl_para[5]; } + ret = of_property_read_u32(child, + "bl_pwm_en_sequence_reverse", &val); + if (ret) { + BLPR("don't find bl_pwm_en_sequence_reverse\n"); + bconf->pwm_en_sequence_reverse = 0; + } else + bconf->pwm_en_sequence_reverse = val; pwm_combo0->pwm_duty = pwm_combo0->pwm_duty_min; pwm_combo1->pwm_duty = pwm_combo1->pwm_duty_min; @@ -1544,7 +1605,7 @@ static int aml_bl_config_load_from_dts(struct bl_config_s *bconf, break; } - return ret; + return 0; } #endif @@ -1574,25 +1635,40 @@ static int aml_bl_config_load_from_unifykey(struct bl_config_s *bconf) return -1; } - /* check backlight unifykey length */ - len = 10 + 30 + 12 + 8 + 32; + /* step 1: check header */ + len = LCD_UKEY_HEAD_SIZE; ret = lcd_unifykey_len_check(key_len, len); if (ret < 0) { - BLERR("unifykey length is not correct\n"); + BLERR("unifykey header length is incorrect\n"); kfree(para); return -1; } - /* header: 10byte */ lcd_unifykey_header_check(para, &bl_header); + BLPR("unifykey version: 0x%04x\n", bl_header.version); + switch (bl_header.version) { + case 2: + len = 10 + 30 + 12 + 8 + 32 + 10; + break; + default: + len = 10 + 30 + 12 + 8 + 32; + break; + } if (bl_debug_print_flag) { BLPR("unifykey header:\n"); BLPR("crc32 = 0x%08x\n", bl_header.crc32); BLPR("data_len = %d\n", bl_header.data_len); - BLPR("version = 0x%04x\n", bl_header.version); BLPR("reserved = 0x%04x\n", bl_header.reserved); } + /* step 2: check backlight parameters */ + ret = lcd_unifykey_len_check(key_len, len); + if (ret < 0) { + BLERR("unifykey length is incorrect\n"); + kfree(para); + return -1; + } + /* basic: 30byte */ p = para + LCD_UKEY_HEAD_SIZE; str = (const char *)p; @@ -1605,7 +1681,7 @@ static int aml_bl_config_load_from_unifykey(struct bl_config_s *bconf) bl_level_uboot = (*p | ((*(p + 1)) << 8)); p += LCD_UKEY_BL_LEVEL_UBOOT; bconf->level_default = (*p | ((*(p + 1)) << 8)); - p += LCD_UKEY_BL_LEVEL_KERNEL; /* dummy pointer */ + p += LCD_UKEY_BL_LEVEL_KERNEL; bconf->level_max = (*p | ((*(p + 1)) << 8)); p += LCD_UKEY_BL_LEVEL_MAX; bconf->level_min = (*p | ((*(p + 1)) << 8)); @@ -1690,6 +1766,18 @@ static int aml_bl_config_load_from_unifykey(struct bl_config_s *bconf) p += LCD_UKEY_BL_PWM_GPIO; p += LCD_UKEY_BL_PWM_GPIO_OFF; + if (bl_header.version == 2) { + bconf->pwm_en_sequence_reverse = + (*p | ((*(p + 1)) << 8)); + p += LCD_UKEY_BL_CUST_VAL_0; + /* dummy pointer */ + p += LCD_UKEY_BL_CUST_VAL_1; + p += LCD_UKEY_BL_CUST_VAL_2; + p += LCD_UKEY_BL_CUST_VAL_3; + p += LCD_UKEY_BL_CUST_VAL_4; + } else + bconf->pwm_en_sequence_reverse = 0; + bl_pwm->pwm_duty = bl_pwm->pwm_duty_min; bl_pwm_config_init(bl_pwm); break; @@ -1781,6 +1869,18 @@ static int aml_bl_config_load_from_unifykey(struct bl_config_s *bconf) pwm_combo1->level_min = (*p | ((*(p + 1)) << 8)); p += LCD_UKEY_BL_PWM2_LEVEL_MIN; + if (bl_header.version == 2) { + bconf->pwm_en_sequence_reverse = + (*p | ((*(p + 1)) << 8)); + p += LCD_UKEY_BL_CUST_VAL_0; + /* dummy pointer */ + p += LCD_UKEY_BL_CUST_VAL_1; + p += LCD_UKEY_BL_CUST_VAL_2; + p += LCD_UKEY_BL_CUST_VAL_3; + p += LCD_UKEY_BL_CUST_VAL_4; + } else + bconf->pwm_en_sequence_reverse = 0; + pwm_combo0->pwm_duty = pwm_combo0->pwm_duty_min; pwm_combo1->pwm_duty = pwm_combo1->pwm_duty_min; bl_pwm_config_init(pwm_combo0); @@ -1909,7 +2009,10 @@ static int aml_bl_config_load(struct bl_config_s *bconf, ret = aml_bl_config_load_from_dts(bconf, pdev); #endif } - + if (bl_level) { + bl_level_uboot = bl_level; + bconf->level_default = bl_level; + } aml_bl_config_print(bconf); switch (bconf->method) { @@ -1987,9 +2090,8 @@ static int aml_bl_on_notifier(struct notifier_block *nb, msleep(bconf->power_on_delay); aml_bl_on_function(); } - } else { + } else BLERR("wrong backlight control method\n"); - } return NOTIFY_OK; } @@ -2010,9 +2112,8 @@ static int aml_bl_off_notifier(struct notifier_block *nb, if (brightness_bypass) { if (bl_drv->state & BL_STATE_BL_ON) bl_power_off(); - } else { + } else aml_bl_update_status(bl_drv->bldev); - } return NOTIFY_OK; } @@ -2207,10 +2308,12 @@ static ssize_t bl_status_read(struct class *class, "pwm_duty_max: %d\n" "pwm_duty_min: %d\n" "pwm_on_delay: %d\n" - "pwm_off_delay: %d\n\n", + "pwm_off_delay: %d\n" + "pwm_en_sequence_reverse: %d\n\n", bl_pwm->pwm_method, bl_pwm->pwm_port, bl_pwm->pwm_freq, bl_pwm->pwm_duty_max, bl_pwm->pwm_duty_min, - bconf->pwm_on_delay, bconf->pwm_off_delay); + bconf->pwm_on_delay, bconf->pwm_off_delay, + bconf->pwm_en_sequence_reverse); break; case BL_CTRL_PWM_COMBO: pwm_combo0 = bconf->bl_pwm_combo0; @@ -2231,7 +2334,8 @@ static ssize_t bl_status_read(struct class *class, "pwm_1_duty_max: %d\n" "pwm_1_duty_min: %d\n" "pwm_on_delay: %d\n" - "pwm_off_delay: %d\n\n", + "pwm_off_delay: %d\n" + "pwm_en_sequence_reverse: %d\n\n", pwm_combo0->level_max, pwm_combo0->level_min, pwm_combo0->pwm_method, pwm_combo0->pwm_port, pwm_combo0->pwm_freq, @@ -2240,7 +2344,8 @@ static ssize_t bl_status_read(struct class *class, pwm_combo1->pwm_method, pwm_combo1->pwm_port, pwm_combo1->pwm_freq, pwm_combo1->pwm_duty_max, pwm_combo1->pwm_duty_min, - bconf->pwm_on_delay, bconf->pwm_off_delay); + bconf->pwm_on_delay, bconf->pwm_off_delay, + bconf->pwm_en_sequence_reverse); break; #ifdef CONFIG_AMLOGIC_LOCAL_DIMMING case BL_CTRL_LOCAL_DIMING: @@ -2985,6 +3090,20 @@ static int __init aml_bl_boot_para_setup(char *s) } __setup("bl_off=", aml_bl_boot_para_setup); +static int __init aml_bl_level_setup(char *str) +{ + int ret = 0; + + if (str != NULL) { + ret = kstrtouint(str, 10, &bl_level); + BLPR("bl_level: %d\n", bl_level); + } + + return ret; +} +__setup("bl_level=", aml_bl_level_setup); + + MODULE_DESCRIPTION("AML Backlight Driver"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Amlogic, Inc."); diff --git a/drivers/amlogic/media/vout/lcd/lcd_debug.c b/drivers/amlogic/media/vout/lcd/lcd_debug.c index bee979e..9461e44 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_debug.c +++ b/drivers/amlogic/media/vout/lcd/lcd_debug.c @@ -157,6 +157,7 @@ static void lcd_info_print(void) unsigned int lcd_clk, sync_duration; struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver(); struct lcd_config_s *pconf; + struct vbyone_config_s *vx1_conf; pconf = lcd_drv->lcd_config; lcd_clk = (pconf->lcd_timing.lcd_clk / 1000); @@ -242,6 +243,7 @@ static void lcd_info_print(void) pconf->lcd_control.lvds_config->phy_clk_preem); break; case LCD_VBYONE: + vx1_conf = pconf->lcd_control.vbyone_config; pr_info("lane_count %u\n" "region_num %u\n" "byte_mode %u\n" @@ -250,7 +252,8 @@ static void lcd_info_print(void) "phy_vswing 0x%x\n" "phy_preemphasis 0x%x\n" "intr_en %u\n" - "vsync_intr_en %u\n\n", + "vsync_intr_en %u\n" + "ctrl_flag 0x%x\n\n", pconf->lcd_control.vbyone_config->lane_count, pconf->lcd_control.vbyone_config->region_num, pconf->lcd_control.vbyone_config->byte_mode, @@ -259,7 +262,26 @@ static void lcd_info_print(void) pconf->lcd_control.vbyone_config->phy_vswing, pconf->lcd_control.vbyone_config->phy_preem, pconf->lcd_control.vbyone_config->intr_en, - pconf->lcd_control.vbyone_config->vsync_intr_en); + pconf->lcd_control.vbyone_config->vsync_intr_en, + pconf->lcd_control.vbyone_config->ctrl_flag); + if (vx1_conf->ctrl_flag & 0x1) { + pr_info("power_on_reset_en %u\n" + "power_on_reset_delay %ums\n\n", + (vx1_conf->ctrl_flag & 0x1), + vx1_conf->power_on_reset_delay); + } + if (vx1_conf->ctrl_flag & 0x2) { + pr_info("hpd_data_delay_en %u\n" + "hpd_data_delay %ums\n\n", + ((vx1_conf->ctrl_flag >> 1) & 0x1), + vx1_conf->hpd_data_delay); + } + if (vx1_conf->ctrl_flag & 0x4) { + pr_info("cdr_training_hold_en %u\n" + "cdr_training_hold %ums\n\n", + ((vx1_conf->ctrl_flag >> 2) & 0x1), + vx1_conf->cdr_training_hold); + } break; case LCD_MIPI: #ifdef CONFIG_AMLOGIC_LCD_TABLET @@ -1677,6 +1699,11 @@ static const char *lcd_vbyone_debug_usage_str = { "data format:\n" " : 0=disable vsync monitor intr, 1=enable vsync monitor intr\n" "\n" +" echo ctrl > vbyone; set ctrl adjust\n" +"data format:\n" +" : bit[0]:power_on_reset_en, bit[1]:hpd_data_delay_en, bit[2]:cdr_training_hold_en\n" +" others : unit in ms\n" +"\n" }; static const char *lcd_mipi_debug_usage_str = { @@ -1800,7 +1827,7 @@ static ssize_t lcd_vx1_debug_store(struct class *class, struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver(); struct vbyone_config_s *vx1_conf; #ifdef CONFIG_AMLOGIC_LCD_TV - int val[2]; + int val[5]; #endif vx1_conf = lcd_drv->lcd_config->lcd_control.vbyone_config; @@ -1841,6 +1868,34 @@ static ssize_t lcd_vx1_debug_store(struct class *class, #else return -EINVAL; #endif + } else if (buf[0] == 'c') { /* ctrl */ +#ifdef CONFIG_AMLOGIC_LCD_TV + ret = sscanf(buf, "ctrl %x %d %d %d", + &val[0], &val[1], &val[2], &val[3]); + if (ret == 4) { + pr_info("set vbyone ctrl_flag: 0x%x\n", val[0]); + pr_info("power_on_reset_delay: %dms\n", val[1]); + pr_info("hpd_data_delay: %dms\n", val[2]); + pr_info("cdr_training_hold: %dms\n", val[3]); + vx1_conf->ctrl_flag = val[0]; + vx1_conf->power_on_reset_delay = val[1]; + vx1_conf->hpd_data_delay = val[2]; + vx1_conf->cdr_training_hold = val[3]; + lcd_debug_config_update(); + } else { + pr_info("set vbyone ctrl_flag: 0x%x\n", + vx1_conf->ctrl_flag); + pr_info("power_on_reset_delay: %dms\n", + vx1_conf->power_on_reset_delay); + pr_info("hpd_data_delay: %dms\n", + vx1_conf->hpd_data_delay); + pr_info("cdr_training_hold: %dms\n", + vx1_conf->cdr_training_hold); + return -EINVAL; + } +#else + return -EINVAL; +#endif } else { ret = sscanf(buf, "%d %d %d", &vx1_conf->lane_count, &vx1_conf->region_num, &vx1_conf->byte_mode); diff --git a/drivers/amlogic/media/vout/lcd/lcd_tablet/lcd_drv.c b/drivers/amlogic/media/vout/lcd/lcd_tablet/lcd_drv.c index b70241e..3e4a666 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_tablet/lcd_drv.c +++ b/drivers/amlogic/media/vout/lcd/lcd_tablet/lcd_drv.c @@ -419,7 +419,7 @@ static void lcd_venc_set(struct lcd_config_s *pconf) lcd_vcbus_write(ENCL_VIDEO_EN, 0); lcd_vcbus_write(VPU_VIU_VENC_MUX_CTRL, ((0 << 0) | (0 << 2))); - lcd_vcbus_write(ENCL_VIDEO_MODE, 0); + lcd_vcbus_write(ENCL_VIDEO_MODE, 0x8000);/*bit[15] shadown en*/ lcd_vcbus_write(ENCL_VIDEO_MODE_ADV, 0x0418); /* Sampling rate: 1 */ lcd_vcbus_write(ENCL_VIDEO_FILT_CTRL, 0x1000); /* bypass filter */ diff --git a/drivers/amlogic/media/vout/lcd/lcd_tv/lcd_drv.c b/drivers/amlogic/media/vout/lcd/lcd_tv/lcd_drv.c index 9a33c53..f92ab99 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_tv/lcd_drv.c +++ b/drivers/amlogic/media/vout/lcd/lcd_tv/lcd_drv.c @@ -451,6 +451,18 @@ static void lcd_vbyone_wait_timing_stable(void) mdelay(2); } +static void lcd_vbyone_cdr_training_hold(struct vbyone_config_s *vx1_conf, + int flag) +{ + if (flag) { + LCDPR("ctrl_flag for cdr_training_hold\n"); + lcd_vcbus_setb(VBO_FSM_HOLDER_H, 0xffff, 0, 16); + } else { + msleep(vx1_conf->cdr_training_hold); + lcd_vcbus_setb(VBO_FSM_HOLDER_H, 0, 0, 16); + } +} + static void lcd_vbyone_control_set(struct lcd_config_s *pconf) { int lane_count, byte_mode, region_num, hsize, vsize, color_fmt; @@ -542,6 +554,12 @@ static void lcd_vbyone_control_set(struct lcd_config_s *pconf) lcd_vbyone_wait_timing_stable(); lcd_vbyone_sw_reset(); + + /* training hold */ + if ((pconf->lcd_control.vbyone_config->ctrl_flag) & 0x4) { + lcd_vbyone_cdr_training_hold( + pconf->lcd_control.vbyone_config, 1); + } } static void lcd_vbyone_disable(void) @@ -599,8 +617,19 @@ void lcd_vbyone_interrupt_enable(int flag) } } -static void lcd_vbyone_interrupt_init(void) +static void lcd_vbyone_interrupt_init(struct aml_lcd_drv_s *lcd_drv) { + /* release sw filter ctrl in uboot */ + switch (lcd_drv->chip_type) { + case LCD_CHIP_TXL: + case LCD_CHIP_TXLX: + lcd_vcbus_setb(VBO_INSGN_CTRL, 0, 2, 1); + lcd_vcbus_setb(VBO_INSGN_CTRL, 0, 0, 1); + break; + default: + break; + } + /* set hold in FSM_ACQ */ lcd_vcbus_setb(VBO_FSM_HOLDER_L, 0xffff, 0, 16); /* set hold in FSM_CDR */ @@ -622,16 +651,57 @@ static void lcd_vbyone_interrupt_init(void) LCDPR("%s\n", __func__); } +#define VX1_LOCKN_WAIT_TIMEOUT 5000 /* 250ms */ void lcd_vbyone_wait_stable(void) { - int i = 5000; + int i = VX1_LOCKN_WAIT_TIMEOUT; while (((lcd_vcbus_read(VBO_STATUS_L) & 0x3f) != 0x20) && (i > 0)) { udelay(50); i--; } LCDPR("%s status: 0x%x, i=%d\n", - __func__, lcd_vcbus_read(VBO_STATUS_L), (5000 - i)); + __func__, lcd_vcbus_read(VBO_STATUS_L), + (VX1_LOCKN_WAIT_TIMEOUT - i)); + vx1_training_wait_cnt = 0; + vx1_training_stable_cnt = 0; + vx1_fsm_acq_st = 0; + lcd_vbyone_interrupt_enable(1); +} + +static void lcd_vbyone_power_on_wait_stable(struct lcd_config_s *pconf) +{ + int i = VX1_LOCKN_WAIT_TIMEOUT; + + /* training hold release */ + if ((pconf->lcd_control.vbyone_config->ctrl_flag) & 0x4) { + lcd_vbyone_cdr_training_hold( + pconf->lcd_control.vbyone_config, 0); + } + while (((lcd_vcbus_read(VBO_STATUS_L) & 0x3f) != 0x20) && (i > 0)) { + udelay(50); + i--; + } + LCDPR("%s status: 0x%x, i=%d\n", + __func__, lcd_vcbus_read(VBO_STATUS_L), + (VX1_LOCKN_WAIT_TIMEOUT - i)); + + /* power on reset */ + if ((pconf->lcd_control.vbyone_config->ctrl_flag) & 0x1) { + LCDPR("ctrl_flag for power on reset\n"); + msleep(pconf->lcd_control.vbyone_config->power_on_reset_delay); + lcd_vbyone_sw_reset(); + i = VX1_LOCKN_WAIT_TIMEOUT; + while (((lcd_vcbus_read(VBO_STATUS_L) & 0x3f) != 0x20) && + (i > 0)) { + udelay(50); + i--; + } + LCDPR("%s status: 0x%x, i=%d\n", + __func__, lcd_vcbus_read(VBO_STATUS_L), + (VX1_LOCKN_WAIT_TIMEOUT - i)); + } + vx1_training_wait_cnt = 0; vx1_training_stable_cnt = 0; vx1_fsm_acq_st = 0; @@ -641,13 +711,15 @@ void lcd_vbyone_wait_stable(void) #define LCD_VX1_WAIT_STABLE_DELAY 300 /* ms */ static void lcd_vx1_wait_stable_delayed(struct work_struct *work) { + struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver(); + if (lcd_vx1_intr_request == 0) return; - lcd_vbyone_wait_stable(); + lcd_vbyone_power_on_wait_stable(lcd_drv->lcd_config); } -static void lcd_vx1_wait_hpd(void) +static void lcd_vbyone_wait_hpd(struct lcd_config_s *pconf) { int i = 0; @@ -659,13 +731,20 @@ static void lcd_vx1_wait_hpd(void) break; udelay(50); } - mdelay(10); /* add 10ms delay for compatibility */ - if (lcd_vcbus_read(VBO_STATUS_L) & 0x40) + if (lcd_vcbus_read(VBO_STATUS_L) & 0x40) { LCDPR("%s: hpd=%d\n", __func__, ((lcd_vcbus_read(VBO_STATUS_L) >> 6) & 0x1)); - else + } else { LCDPR("%s: hpd=%d, i=%d\n", __func__, ((lcd_vcbus_read(VBO_STATUS_L) >> 6) & 0x1), i); + } + + if ((pconf->lcd_control.vbyone_config->ctrl_flag) & 0x2) { + LCDPR("ctrl_flag for hpd_data delay\n"); + msleep(pconf->lcd_control.vbyone_config->hpd_data_delay); + } else + usleep_range(10000, 10500); + /* add 10ms delay for compatibility */ } #define LCD_PCLK_TOLERANCE 2000000 /* 2M */ @@ -826,7 +905,7 @@ static irqreturn_t lcd_vbyone_vsync_isr(int irq, void *dev_id) return IRQ_HANDLED; } -#define VX1_LOCKN_WAIT_TIMEOUT 50 +#define VX1_LOCKN_WAIT_CNT_MAX 50 static int vx1_lockn_wait_cnt; #define VX1_FSM_ACQ_NEXT_STEP_CONTINUE 0 @@ -877,7 +956,7 @@ static irqreturn_t lcd_vbyone_interrupt_handler(int irq, void *dev_id) LCDPR("vx1 lockn fall occurred\n"); vx1_fsm_acq_st = 0; lcd_vcbus_setb(VBO_INTR_STATE_CTRL, 0, 15, 1); - if (vx1_lockn_wait_cnt++ > VX1_LOCKN_WAIT_TIMEOUT) { + if (vx1_lockn_wait_cnt++ > VX1_LOCKN_WAIT_CNT_MAX) { #if 0 LCDPR("vx1 sw reset for lockn timeout\n"); /* force PHY to 0 */ @@ -1004,7 +1083,7 @@ static void lcd_venc_set(struct lcd_config_s *pconf) /* Enable Hsync and equalization pulse switch in center; * bit[14] cfg_de_v = 1 */ - lcd_vcbus_write(ENCL_VIDEO_MODE, 40); + lcd_vcbus_write(ENCL_VIDEO_MODE, 0x8000);/*bit[15] shadown en*/ lcd_vcbus_write(ENCL_VIDEO_MODE_ADV, 0x18); /* Sampling rate: 1 */ /* bypass filter */ @@ -1195,7 +1274,7 @@ int lcd_tv_driver_init(void) case LCD_VBYONE: lcd_vbyone_pinmux_set(1); lcd_vbyone_control_set(pconf); - lcd_vx1_wait_hpd(); + lcd_vbyone_wait_hpd(pconf); lcd_vbyone_phy_set(pconf, 1); lcd_vx1_intr_request = 1; queue_delayed_work(lcd_drv->workqueue, @@ -1328,9 +1407,9 @@ void lcd_tv_driver_tiny_enable(void) case LCD_VBYONE: lcd_vbyone_pinmux_set(1); lcd_vbyone_control_set(pconf); - lcd_vx1_wait_hpd(); + lcd_vbyone_wait_hpd(pconf); lcd_vbyone_phy_set(pconf, 1); - lcd_vbyone_wait_stable(); + lcd_vbyone_power_on_wait_stable(pconf); break; default: break; @@ -1373,7 +1452,7 @@ void lcd_vbyone_interrupt_up(void) { struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver(); - lcd_vbyone_interrupt_init(); + lcd_vbyone_interrupt_init(lcd_drv); vx1_lockn_wait_cnt = 0; vx1_training_wait_cnt = 0; vx1_timeout_reset_flag = 0; diff --git a/drivers/amlogic/media/vout/lcd/lcd_tv/lcd_tv.c b/drivers/amlogic/media/vout/lcd/lcd_tv/lcd_tv.c index 383e70a..89a6467 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_tv/lcd_tv.c +++ b/drivers/amlogic/media/vout/lcd/lcd_tv/lcd_tv.c @@ -703,9 +703,10 @@ static int lcd_config_load_from_dts(struct lcd_config_s *pconf, { int ret = 0; const char *str; - unsigned int para[10]; + unsigned int para[10], val; struct device_node *child; struct lvds_config_s *lvdsconf; + struct vbyone_config_s *vx1_conf; child = of_get_child_by_name(dev->of_node, pconf->lcd_propname); if (child == NULL) { @@ -845,24 +846,24 @@ static int lcd_config_load_from_dts(struct lcd_config_s *pconf, } break; case LCD_VBYONE: + vx1_conf = pconf->lcd_control.vbyone_config; ret = of_property_read_u32_array(child, "vbyone_attr", ¶[0], 4); if (ret) { LCDERR("failed to get vbyone_attr\n"); } else { - pconf->lcd_control.vbyone_config->lane_count = para[0]; - pconf->lcd_control.vbyone_config->region_num = para[1]; - pconf->lcd_control.vbyone_config->byte_mode = para[2]; - pconf->lcd_control.vbyone_config->color_fmt = para[3]; + vx1_conf->lane_count = para[0]; + vx1_conf->region_num = para[1]; + vx1_conf->byte_mode = para[2]; + vx1_conf->color_fmt = para[3]; } ret = of_property_read_u32_array(child, "vbyone_intr_enable", ¶[0], 2); if (ret) { LCDERR("failed to get vbyone_intr_enable\n"); } else { - pconf->lcd_control.vbyone_config->intr_en = para[0]; - pconf->lcd_control.vbyone_config->vsync_intr_en = - para[1]; + vx1_conf->intr_en = para[0]; + vx1_conf->vsync_intr_en = para[1]; } ret = of_property_read_u32_array(child, "phy_attr", ¶[0], 2); @@ -870,12 +871,38 @@ static int lcd_config_load_from_dts(struct lcd_config_s *pconf, if (lcd_debug_print_flag) LCDPR("failed to get phy_attr\n"); } else { - pconf->lcd_control.vbyone_config->phy_vswing = para[0]; - pconf->lcd_control.vbyone_config->phy_preem = para[1]; + vx1_conf->phy_vswing = para[0]; + vx1_conf->phy_preem = para[1]; if (lcd_debug_print_flag) { LCDPR("phy vswing=0x%x, preemphasis=0x%x\n", - pconf->lcd_control.vbyone_config->phy_vswing, - pconf->lcd_control.vbyone_config->phy_preem); + vx1_conf->phy_vswing, vx1_conf->phy_preem); + } + } + ret = of_property_read_u32(child, "vbyone_ctrl_flag", &val); + if (ret) { + if (lcd_debug_print_flag) + LCDPR("failed to get vbyone_ctrl_flag\n"); + } else { + vx1_conf->ctrl_flag = val; + LCDPR("vbyone ctrl_flag=0x%x\n", vx1_conf->ctrl_flag); + } + if (vx1_conf->ctrl_flag & 0x7) { + ret = of_property_read_u32_array(child, + "vbyone_ctrl_timing", ¶[0], 3); + if (ret) + LCDPR("failed to get vbyone_ctrl_timing\n"); + else { + vx1_conf->power_on_reset_delay = para[0]; + vx1_conf->hpd_data_delay = para[1]; + vx1_conf->cdr_training_hold = para[2]; + } + if (lcd_debug_print_flag) { + LCDPR("power_on_reset_delay: %d\n", + vx1_conf->power_on_reset_delay); + LCDPR("hpd_data_delay: %d\n", + vx1_conf->hpd_data_delay); + LCDPR("cdr_training_hold: %d\n", + vx1_conf->cdr_training_hold); } } break; @@ -1118,27 +1145,59 @@ static int lcd_config_load_from_unifykey(struct lcd_config_s *pconf) if (lcd_header.version == 2) { /* ctrl: 44byte */ /* v2 */ - p += LCD_UKEY_CTRL_FLAG; - p += LCD_UKEY_CTRL_ATTR_0; - p += LCD_UKEY_CTRL_ATTR_1; - p += LCD_UKEY_CTRL_ATTR_2; - p += LCD_UKEY_CTRL_ATTR_3; - p += LCD_UKEY_CTRL_ATTR_4; - p += LCD_UKEY_CTRL_ATTR_5; - p += LCD_UKEY_CTRL_ATTR_6; - p += LCD_UKEY_CTRL_ATTR_7; - p += LCD_UKEY_CTRL_ATTR_8; - p += LCD_UKEY_CTRL_ATTR_9; - p += LCD_UKEY_CTRL_ATTR_10; - p += LCD_UKEY_CTRL_ATTR_11; - p += LCD_UKEY_CTRL_ATTR_12; - p += LCD_UKEY_CTRL_ATTR_13; - p += LCD_UKEY_CTRL_ATTR_14; - p += LCD_UKEY_CTRL_ATTR_15; - p += LCD_UKEY_CTRL_ATTR_16; - p += LCD_UKEY_CTRL_ATTR_17; - p += LCD_UKEY_CTRL_ATTR_18; - p += LCD_UKEY_CTRL_ATTR_19; + if (pconf->lcd_basic.lcd_type == LCD_VBYONE) { + vx1_conf->ctrl_flag = (*p | ((*(p + 1)) << 8) | + ((*(p + 2)) << 16) | ((*(p + 3)) << 24)); + p += LCD_UKEY_CTRL_FLAG; + vx1_conf->power_on_reset_delay = + (*p | ((*(p + 1)) << 8)); + p += LCD_UKEY_CTRL_ATTR_0; + vx1_conf->hpd_data_delay = (*p | ((*(p + 1)) << 8)); + p += LCD_UKEY_CTRL_ATTR_1; + vx1_conf->cdr_training_hold = (*p | ((*(p + 1)) << 8)); + p += LCD_UKEY_CTRL_ATTR_2; + /* dummy pointer */ + p += LCD_UKEY_CTRL_ATTR_3; + p += LCD_UKEY_CTRL_ATTR_4; + p += LCD_UKEY_CTRL_ATTR_5; + p += LCD_UKEY_CTRL_ATTR_6; + p += LCD_UKEY_CTRL_ATTR_7; + p += LCD_UKEY_CTRL_ATTR_8; + p += LCD_UKEY_CTRL_ATTR_9; + p += LCD_UKEY_CTRL_ATTR_10; + p += LCD_UKEY_CTRL_ATTR_11; + p += LCD_UKEY_CTRL_ATTR_12; + p += LCD_UKEY_CTRL_ATTR_13; + /* dummy pointer */ + p += LCD_UKEY_CTRL_ATTR_14; + p += LCD_UKEY_CTRL_ATTR_15; + p += LCD_UKEY_CTRL_ATTR_16; + p += LCD_UKEY_CTRL_ATTR_17; + p += LCD_UKEY_CTRL_ATTR_18; + p += LCD_UKEY_CTRL_ATTR_19; + } else { + p += LCD_UKEY_CTRL_FLAG; + p += LCD_UKEY_CTRL_ATTR_0; + p += LCD_UKEY_CTRL_ATTR_1; + p += LCD_UKEY_CTRL_ATTR_2; + p += LCD_UKEY_CTRL_ATTR_3; + p += LCD_UKEY_CTRL_ATTR_4; + p += LCD_UKEY_CTRL_ATTR_5; + p += LCD_UKEY_CTRL_ATTR_6; + p += LCD_UKEY_CTRL_ATTR_7; + p += LCD_UKEY_CTRL_ATTR_8; + p += LCD_UKEY_CTRL_ATTR_9; + p += LCD_UKEY_CTRL_ATTR_10; + p += LCD_UKEY_CTRL_ATTR_11; + p += LCD_UKEY_CTRL_ATTR_12; + p += LCD_UKEY_CTRL_ATTR_13; + p += LCD_UKEY_CTRL_ATTR_14; + p += LCD_UKEY_CTRL_ATTR_15; + p += LCD_UKEY_CTRL_ATTR_16; + p += LCD_UKEY_CTRL_ATTR_17; + p += LCD_UKEY_CTRL_ATTR_18; + p += LCD_UKEY_CTRL_ATTR_19; + } /* phy: 10byte */ /* v2 */ if (pconf->lcd_basic.lcd_type == LCD_VBYONE) { diff --git a/drivers/amlogic/media/vout/lcd/lcd_vout.c b/drivers/amlogic/media/vout/lcd/lcd_vout.c index 967612f..19b7dd7 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_vout.c +++ b/drivers/amlogic/media/vout/lcd/lcd_vout.c @@ -100,6 +100,11 @@ static struct vbyone_config_s lcd_vbyone_config = { .phy_preem = VX1_PHY_PREEM_DFT, .intr_en = 1, .vsync_intr_en = 1, + + .ctrl_flag = 0, + .power_on_reset_delay = VX1_PWR_ON_RESET_DLY_DFT, + .hpd_data_delay = VX1_HPD_DATA_DELAY_DFT, + .cdr_training_hold = VX1_CDR_TRAINING_HOLD_DFT, }; static unsigned char dsi_init_on_table[DSI_INIT_ON_MAX] = {0xff, 0xff}; diff --git a/include/linux/amlogic/media/vout/lcd/aml_bl.h b/include/linux/amlogic/media/vout/lcd/aml_bl.h index c9fc189..1aa8652 100644 --- a/include/linux/amlogic/media/vout/lcd/aml_bl.h +++ b/include/linux/amlogic/media/vout/lcd/aml_bl.h @@ -146,6 +146,7 @@ struct bl_config_s { struct bl_pwm_config_s *bl_pwm_combo1; unsigned int pwm_on_delay; unsigned int pwm_off_delay; + unsigned int pwm_en_sequence_reverse; struct bl_gpio_s bl_gpio[BL_GPIO_NUM_MAX]; struct pinctrl *pin; diff --git a/include/linux/amlogic/media/vout/lcd/lcd_vout.h b/include/linux/amlogic/media/vout/lcd/lcd_vout.h index 350b4a9..80973ee 100644 --- a/include/linux/amlogic/media/vout/lcd/lcd_vout.h +++ b/include/linux/amlogic/media/vout/lcd/lcd_vout.h @@ -224,8 +224,13 @@ struct lvds_config_s { unsigned int phy_clk_preem; }; -#define VX1_PHY_VSWING_DFT 3 -#define VX1_PHY_PREEM_DFT 0 +#define VX1_PHY_VSWING_DFT 3 +#define VX1_PHY_PREEM_DFT 0 + +#define VX1_PWR_ON_RESET_DLY_DFT 500 /* 500ms */ +#define VX1_HPD_DATA_DELAY_DFT 10 /* 10ms */ +#define VX1_CDR_TRAINING_HOLD_DFT 200 /* 200ms */ + struct vbyone_config_s { unsigned int lane_count; unsigned int region_num; @@ -237,6 +242,24 @@ struct vbyone_config_s { unsigned int phy_preem; unsigned int intr_en; unsigned int vsync_intr_en; + + unsigned int ctrl_flag; + /* bit[0]:power_on_reset_en + * bit[1]:hpd_data_delay_en + * bit[2]:cdr_training_hold_en + * bit[3]:hw_filter_en + * bit[5:4]:sw_filter + */ + + /* ctrl timing */ + unsigned int power_on_reset_delay; /* ms */ + unsigned int hpd_data_delay; /* ms */ + unsigned int cdr_training_hold; /* ms */ + /* hw filter */ + unsigned int hpd_hw_filter_time; /* ms */ + unsigned int hpd_hw_filter_cnt; + unsigned int lockn_hw_filter_time; /* ms */ + unsigned int lockn_hw_filter_cnt; }; /* mipi-dsi config */