lcd: synchronous lcd driver from linux3.14
authorWeiming Liu <weiming.liu@amlogic.com>
Thu, 14 Sep 2017 05:12:42 +0000 (13:12 +0800)
committerJianxin Pan <jianxin.pan@amlogic.com>
Wed, 20 Sep 2017 04:32:15 +0000 (21:32 -0700)
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 <weiming.liu@amlogic.com>
arch/arm64/boot/dts/amlogic/mesonaxg_s400-panel.dtsi
drivers/amlogic/media/vout/backlight/aml_bl.c
drivers/amlogic/media/vout/lcd/lcd_debug.c
drivers/amlogic/media/vout/lcd/lcd_tablet/lcd_drv.c
drivers/amlogic/media/vout/lcd/lcd_tv/lcd_drv.c
drivers/amlogic/media/vout/lcd/lcd_tv/lcd_tv.c
drivers/amlogic/media/vout/lcd/lcd_vout.c
include/linux/amlogic/media/vout/lcd/aml_bl.h
include/linux/amlogic/media/vout/lcd/lcd_vout.h

index ce1ff28..cfe878d 100644 (file)
                                 * 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>;
                                 * 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>;
                };
        };
index b219f05..6238404 100644 (file)
@@ -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.");
index bee979e..9461e44 100644 (file)
@@ -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"
 "    <en>    : 0=disable vsync monitor intr, 1=enable vsync monitor intr\n"
 "\n"
+"    echo ctrl <ctrl_flag> <power_on_reset_delay> <hpd_data_delay> <cdr_training_hold> > vbyone; set ctrl adjust\n"
+"data format:\n"
+"    <ctrl_flag>    : 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);
index b70241e..3e4a666 100644 (file)
@@ -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 */
index 9a33c53..f92ab99 100644 (file)
@@ -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;
index 383e70a..89a6467 100644 (file)
@@ -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",
                        &para[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",
                        &para[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",
                        &para[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", &para[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) {
index 967612f..19b7dd7 100644 (file)
@@ -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};
index c9fc189..1aa8652 100644 (file)
@@ -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;
index 350b4a9..80973ee 100644 (file)
@@ -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 */