diff --git a/drivers/amlogic/media/vout/lcd/lcd_clk_config.c b/drivers/amlogic/media/vout/lcd/lcd_clk_config.c index fef8229a804d..5e82489db67a 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_clk_config.c +++ b/drivers/amlogic/media/vout/lcd/lcd_clk_config.c @@ -632,6 +632,165 @@ set_pll_retry_tl1: } } +static void lcd_prbs_set_pll_vx1_tl1(void) +{ + int cnt = 0, ret; + + LCDPR("%s\n", __func__); + +lcd_prbs_retry_pll_vx1_tl1: + lcd_hiu_write(HHI_TCON_PLL_CNTL0, 0x000f04f7); + usleep_range(10, 12); + lcd_hiu_setb(HHI_TCON_PLL_CNTL0, 1, LCD_PLL_RST_TL1, 1); + usleep_range(10, 12); + lcd_hiu_setb(HHI_TCON_PLL_CNTL0, 1, LCD_PLL_EN_TL1, 1); + usleep_range(10, 12); + lcd_hiu_write(HHI_TCON_PLL_CNTL1, 0x10110000); + usleep_range(10, 12); + lcd_hiu_write(HHI_TCON_PLL_CNTL2, 0x0000110c); + usleep_range(10, 12); + lcd_hiu_write(HHI_TCON_PLL_CNTL3, 0x10051400); + usleep_range(10, 12); + lcd_hiu_write(HHI_TCON_PLL_CNTL4, 0x000100c0); + usleep_range(10, 12); + lcd_hiu_write(HHI_TCON_PLL_CNTL4, 0x008300c0); + usleep_range(10, 12); + lcd_hiu_setb(HHI_TCON_PLL_CNTL0, 1, 26, 1); + usleep_range(10, 12); + lcd_hiu_setb(HHI_TCON_PLL_CNTL0, 0, LCD_PLL_RST_TL1, 1); + usleep_range(10, 12); + lcd_hiu_write(HHI_TCON_PLL_CNTL2, 0x0000300c); + usleep_range(10, 12); + + ret = lcd_pll_wait_lock(HHI_TCON_PLL_CNTL0, LCD_PLL_LOCK_TL1); + if (ret) { + if (cnt++ < PLL_RETRY_MAX) + goto lcd_prbs_retry_pll_vx1_tl1; + LCDERR("hpll lock failed\n"); + } + lcd_hiu_write(HHI_TCON_PLL_CNTL2, 0x0000302c); + + /* pll_div */ + lcd_hiu_setb(HHI_VIID_CLK_CNTL, 0, VCLK2_EN, 1); + usleep_range(5, 10); + + /* Disable the div output clock */ + lcd_hiu_setb(HHI_VID_PLL_CLK_DIV, 0, 19, 1); + lcd_hiu_setb(HHI_VID_PLL_CLK_DIV, 0, 15, 1); + + lcd_hiu_setb(HHI_VID_PLL_CLK_DIV, 0, 18, 1); + lcd_hiu_setb(HHI_VID_PLL_CLK_DIV, 0, 16, 2); + lcd_hiu_setb(HHI_VID_PLL_CLK_DIV, 0, 15, 1); + lcd_hiu_setb(HHI_VID_PLL_CLK_DIV, 0, 0, 14); + + lcd_hiu_setb(HHI_VID_PLL_CLK_DIV, 2, 16, 2); + lcd_hiu_setb(HHI_VID_PLL_CLK_DIV, 1, 15, 1); + lcd_hiu_setb(HHI_VID_PLL_CLK_DIV, 0x739c, 0, 15); + lcd_hiu_setb(HHI_VID_PLL_CLK_DIV, 0, 15, 1); + + /* Enable the final output clock */ + lcd_hiu_setb(HHI_VID_PLL_CLK_DIV, 1, 19, 1); +} + +static void lcd_prbs_set_pll_lvds_tl1(void) +{ + int cnt = 0, ret; + + LCDPR("%s\n", __func__); + +lcd_prbs_retry_pll_lvds_tl1: + lcd_hiu_write(HHI_TCON_PLL_CNTL0, 0x0006048d); + usleep_range(10, 12); + lcd_hiu_setb(HHI_TCON_PLL_CNTL0, 1, LCD_PLL_RST_TL1, 1); + usleep_range(10, 12); + lcd_hiu_setb(HHI_TCON_PLL_CNTL0, 1, LCD_PLL_EN_TL1, 1); + usleep_range(10, 12); + lcd_hiu_write(HHI_TCON_PLL_CNTL1, 0x10000000); + usleep_range(10, 12); + lcd_hiu_write(HHI_TCON_PLL_CNTL2, 0x00001102); + usleep_range(10, 12); + lcd_hiu_write(HHI_TCON_PLL_CNTL3, 0x10051400); + usleep_range(10, 12); + lcd_hiu_write(HHI_TCON_PLL_CNTL4, 0x010100c0); + usleep_range(10, 12); + lcd_hiu_write(HHI_TCON_PLL_CNTL4, 0x038300c0); + usleep_range(10, 12); + lcd_hiu_setb(HHI_TCON_PLL_CNTL0, 1, 26, 1); + usleep_range(10, 12); + lcd_hiu_write(HHI_TCON_PLL_CNTL0, 0x148e048d); + usleep_range(10, 12); + lcd_hiu_write(HHI_TCON_PLL_CNTL2, 0x00003008); + usleep_range(10, 12); + lcd_hiu_write(HHI_TCON_PLL_CNTL2, 0x00003022); + usleep_range(10, 12); + + ret = lcd_pll_wait_lock(HHI_TCON_PLL_CNTL0, LCD_PLL_LOCK_TL1); + if (ret) { + if (cnt++ < PLL_RETRY_MAX) + goto lcd_prbs_retry_pll_lvds_tl1; + LCDERR("hpll lock failed\n"); + } + + /* pll_div */ + lcd_hiu_setb(HHI_VIID_CLK_CNTL, 0, VCLK2_EN, 1); + usleep_range(5, 10); + + /* Disable the div output clock */ + lcd_hiu_setb(HHI_VID_PLL_CLK_DIV, 0, 19, 1); + lcd_hiu_setb(HHI_VID_PLL_CLK_DIV, 0, 15, 1); + + lcd_hiu_setb(HHI_VID_PLL_CLK_DIV, 0, 18, 1); + lcd_hiu_setb(HHI_VID_PLL_CLK_DIV, 0, 16, 2); + lcd_hiu_setb(HHI_VID_PLL_CLK_DIV, 0, 15, 1); + lcd_hiu_setb(HHI_VID_PLL_CLK_DIV, 0, 0, 14); + + lcd_hiu_setb(HHI_VID_PLL_CLK_DIV, 1, 16, 2); + lcd_hiu_setb(HHI_VID_PLL_CLK_DIV, 1, 15, 1); + lcd_hiu_setb(HHI_VID_PLL_CLK_DIV, 0x3c78, 0, 15); + lcd_hiu_setb(HHI_VID_PLL_CLK_DIV, 0, 15, 1); + + /* Enable the final output clock */ + lcd_hiu_setb(HHI_VID_PLL_CLK_DIV, 1, 19, 1); +} + +static void lcd_prbs_config_clk_tl1(unsigned int lcd_prbs_mode) +{ + if (lcd_prbs_mode == LCD_PRBS_MODE_VX1) { + lcd_prbs_set_pll_vx1_tl1(); + } else if (lcd_prbs_mode == LCD_PRBS_MODE_LVDS) { + lcd_prbs_set_pll_lvds_tl1(); + } else { + LCDERR("%s: unsupport lcd_prbs_mode %d\n", + __func__, lcd_prbs_mode); + return; + } + + lcd_hiu_setb(HHI_VIID_CLK_DIV, 0, VCLK2_XD, 8); + usleep_range(5, 10); + + /* select vid_pll_clk */ + lcd_hiu_setb(HHI_VIID_CLK_CNTL, 0, VCLK2_CLK_IN_SEL, 3); + lcd_hiu_setb(HHI_VIID_CLK_CNTL, 1, VCLK2_EN, 1); + usleep_range(5, 10); + + /* [15:12] encl_clk_sel, select vclk2_div1 */ + lcd_hiu_setb(HHI_VIID_CLK_DIV, 8, ENCL_CLK_SEL, 4); + /* release vclk2_div_reset and enable vclk2_div */ + lcd_hiu_setb(HHI_VIID_CLK_DIV, 1, VCLK2_XD_EN, 2); + usleep_range(5, 10); + + lcd_hiu_setb(HHI_VIID_CLK_CNTL, 1, VCLK2_DIV1_EN, 1); + lcd_hiu_setb(HHI_VIID_CLK_CNTL, 1, VCLK2_SOFT_RST, 1); + usleep_range(10, 12); + lcd_hiu_setb(HHI_VIID_CLK_CNTL, 0, VCLK2_SOFT_RST, 1); + usleep_range(5, 10); + + /* enable CTS_ENCL clk gate */ + lcd_hiu_setb(HHI_VID_CLK_CNTL2, 1, ENCL_GATE_VCLK, 1); + + LCDPR("%s ok\n", __func__); +} + static void lcd_set_vid_pll_div(struct lcd_clk_config_s *cconf) { unsigned int shift_val, shift_sel; @@ -2746,6 +2905,7 @@ static struct lcd_clk_data_s lcd_clk_data_gxl = { .clktree_remove = lcd_clktree_remove_dft, .clk_config_init_print = lcd_clk_config_init_print_dft, .clk_config_print = lcd_clk_config_print_dft, + .prbs_clk_config = NULL, }; static struct lcd_clk_data_s lcd_clk_data_txl = { @@ -2789,6 +2949,7 @@ static struct lcd_clk_data_s lcd_clk_data_txl = { .clktree_remove = lcd_clktree_remove_dft, .clk_config_init_print = lcd_clk_config_init_print_dft, .clk_config_print = lcd_clk_config_print_dft, + .prbs_clk_config = NULL, }; static struct lcd_clk_data_s lcd_clk_data_txlx = { @@ -2832,6 +2993,7 @@ static struct lcd_clk_data_s lcd_clk_data_txlx = { .clktree_remove = lcd_clktree_remove_dft, .clk_config_init_print = lcd_clk_config_init_print_dft, .clk_config_print = lcd_clk_config_print_dft, + .prbs_clk_config = NULL, }; static struct lcd_clk_data_s lcd_clk_data_axg = { @@ -2875,6 +3037,7 @@ static struct lcd_clk_data_s lcd_clk_data_axg = { .clktree_remove = lcd_clktree_remove_axg, .clk_config_init_print = lcd_clk_config_init_print_axg, .clk_config_print = lcd_clk_config_print_axg, + .prbs_clk_config = NULL, }; static struct lcd_clk_data_s lcd_clk_data_g12a_path0 = { @@ -2918,6 +3081,7 @@ static struct lcd_clk_data_s lcd_clk_data_g12a_path0 = { .clktree_remove = lcd_clktree_remove_g12a, .clk_config_init_print = lcd_clk_config_init_print_axg, .clk_config_print = lcd_clk_config_print_g12a, + .prbs_clk_config = NULL, }; static struct lcd_clk_data_s lcd_clk_data_g12a_path1 = { @@ -2961,6 +3125,7 @@ static struct lcd_clk_data_s lcd_clk_data_g12a_path1 = { .clktree_remove = lcd_clktree_remove_g12a, .clk_config_init_print = lcd_clk_config_init_print_axg, .clk_config_print = lcd_clk_config_print_g12a, + .prbs_clk_config = NULL, }; static struct lcd_clk_data_s lcd_clk_data_g12b_path0 = { @@ -3004,6 +3169,7 @@ static struct lcd_clk_data_s lcd_clk_data_g12b_path0 = { .clktree_remove = lcd_clktree_remove_g12a, .clk_config_init_print = lcd_clk_config_init_print_axg, .clk_config_print = lcd_clk_config_print_g12a, + .prbs_clk_config = NULL, }; static struct lcd_clk_data_s lcd_clk_data_g12b_path1 = { @@ -3047,6 +3213,7 @@ static struct lcd_clk_data_s lcd_clk_data_g12b_path1 = { .clktree_remove = lcd_clktree_remove_g12a, .clk_config_init_print = lcd_clk_config_init_print_axg, .clk_config_print = lcd_clk_config_print_g12a, + .prbs_clk_config = NULL, }; static struct lcd_clk_data_s lcd_clk_data_tl1 = { @@ -3090,6 +3257,7 @@ static struct lcd_clk_data_s lcd_clk_data_tl1 = { .clktree_remove = lcd_clktree_remove_tl1, .clk_config_init_print = lcd_clk_config_init_print_dft, .clk_config_print = lcd_clk_config_print_dft, + .prbs_clk_config = lcd_prbs_config_clk_tl1, }; static void lcd_clk_config_chip_init(struct lcd_clk_config_s *cconf) diff --git a/drivers/amlogic/media/vout/lcd/lcd_clk_config.h b/drivers/amlogic/media/vout/lcd/lcd_clk_config.h index 4c201c1c5790..1b6b55da882d 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_clk_config.h +++ b/drivers/amlogic/media/vout/lcd/lcd_clk_config.h @@ -45,6 +45,9 @@ struct lcd_clk_ctrl_s { unsigned int len; }; +#define LCD_PRBS_MODE_LVDS BIT(0) +#define LCD_PRBS_MODE_VX1 BIT(1) +#define LCD_PRBS_MODE_MAX 2 struct lcd_clk_data_s { /* clk path node parameters */ unsigned int pll_od_fb; @@ -87,6 +90,7 @@ struct lcd_clk_data_s { void (*clktree_probe)(void); void (*clktree_remove)(void); void (*clk_config_init_print)(void); + void (*prbs_clk_config)(unsigned int prbs_mode); int (*clk_config_print)(char *buf, int offset); }; diff --git a/drivers/amlogic/media/vout/lcd/lcd_debug.c b/drivers/amlogic/media/vout/lcd/lcd_debug.c index 1b26441ff39c..a3cf4f0cae45 100644 --- a/drivers/amlogic/media/vout/lcd/lcd_debug.c +++ b/drivers/amlogic/media/vout/lcd/lcd_debug.c @@ -1532,14 +1532,77 @@ static void lcd_screen_black(void) lcd_mute_setting(1); } -static unsigned int lcd_prbs_flag; -static unsigned int lcd_prbs_cnt; -static void aml_lcd_prbs_test(unsigned int s) +#define CLK_CHK_MAX 2000000 /*Hz*/ +static unsigned int lcd_prbs_performed; +static unsigned int lcd_prbs_flag, lcd_prbs_err, lcd_prbs_cnt; +static unsigned long lcd_clk9_check_std = 121000000; +static unsigned long lcd_clk55_check_std = 121000000; +static unsigned long lcd_clk129_check_std = 42000000; + +static unsigned long lcd_abs(unsigned long a, unsigned long b) +{ + unsigned long val; + + if (a >= b) + val = a - b; + else + val = b - a; + + return val; +} + +static int lcd_lvds_clk_check(unsigned int cnt) +{ + unsigned long clk_check, temp; + + clk_check = meson_clk_measure(9); + if (clk_check != lcd_clk9_check_std) { + temp = lcd_abs(clk_check, lcd_clk9_check_std); + if (temp >= CLK_CHK_MAX) { + if (lcd_debug_print_flag == 6) { + LCDERR("lcd encl clkmsr error %ld, cnt:%d\n", + clk_check, cnt); + } + return -1; + } + } + + clk_check = meson_clk_measure(55); + if (clk_check != lcd_clk55_check_std) { + temp = lcd_abs(clk_check, lcd_clk55_check_std); + if (temp >= CLK_CHK_MAX) { + if (lcd_debug_print_flag == 6) { + LCDERR("lcd vid_div clkmsr error %ld, cnt:%d\n", + clk_check, cnt); + } + return -1; + } + } + + clk_check = meson_clk_measure(129); + if (clk_check != lcd_clk129_check_std) { + temp = lcd_abs(clk_check, lcd_clk129_check_std); + if (temp >= CLK_CHK_MAX) { + if (lcd_debug_print_flag == 6) { + LCDERR("lcd fifo clkmsr error %ld, cnt:%d\n", + clk_check, cnt); + } + return -1; + } + } + + return 0; +} + +static void aml_lcd_prbs_test(unsigned int s, unsigned int mode_flag) { struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver(); + struct lcd_clk_config_s *cconf = get_lcd_clk_config(); + unsigned int lcd_prbs_mode; unsigned int reg0, reg1; - unsigned int val1, val2, cnt = 0, timeout; - int i, ret; + unsigned int val1, val2, timeout; + unsigned int clk_err_cnt = 0; + int i, j, ret; switch (lcd_drv->data->chip_type) { case LCD_CHIP_GXL: @@ -1548,8 +1611,8 @@ static void aml_lcd_prbs_test(unsigned int s) case LCD_CHIP_G12A: case LCD_CHIP_G12B: case LCD_CHIP_SM1: - LCDERR("not support\n"); - return; + LCDERR("%s: not support\n", __func__); + goto lcd_prbs_test_end; case LCD_CHIP_TXL: case LCD_CHIP_TXLX: reg0 = HHI_LVDS_TX_PHY_CNTL0; @@ -1561,52 +1624,123 @@ static void aml_lcd_prbs_test(unsigned int s) break; } - lcd_hiu_write(reg0, 0xfff20c4); - lcd_hiu_setb(reg0, 1, 12, 1); - val1 = lcd_hiu_getb(reg1, 12, 12); - s = (s > 1800) ? 1800 : s; timeout = s * 200; - while (lcd_prbs_flag) { - if (s > 1) { /* when s=1, means always run */ - if (cnt++ >= timeout) - break; + + for (i = 0; i < LCD_PRBS_MODE_MAX; i++) { + if ((mode_flag & (1 << i)) == 0) + continue; + + lcd_prbs_cnt = 0; + lcd_prbs_err = 0; + lcd_prbs_mode = (1 << i); + if (cconf->data->prbs_clk_config) { + cconf->data->prbs_clk_config(lcd_prbs_mode); + } else { + LCDERR("%s: prbs_clk_config is null\n", __func__); + goto lcd_prbs_test_end; } - usleep_range(5000, 5001); - ret = 1; - for (i = 0; i < 5; i++) { - val2 = lcd_hiu_getb(reg1, 12, 12); - if (val2 != val1) { - ret = 0; - break; + msleep(20); + + lcd_hiu_write(reg0, 0x000000c0); + lcd_hiu_setb(reg0, 0xfff, 16, 12); + lcd_hiu_setb(reg0, 1, 2, 1); + lcd_hiu_write(reg1, 0x41000000); + lcd_hiu_setb(reg1, 1, 31, 1); + + lcd_hiu_write(reg0, 0xfff20c4); + lcd_hiu_setb(reg0, 1, 12, 1); + val1 = lcd_hiu_getb(reg1, 12, 12); + + while (lcd_prbs_flag) { + if (s > 1) { /* when s=1, means always run */ + if (lcd_prbs_cnt++ >= timeout) + break; } + usleep_range(5000, 5001); + ret = 1; + for (j = 0; j < 5; j++) { + val2 = lcd_hiu_getb(reg1, 12, 12); + if (val2 != val1) { + ret = 0; + break; + } + } + if (ret) { + LCDERR( + "lcd prbs check error 1, val:0x%03x, cnt:%d\n", + val2, lcd_prbs_cnt); + goto lcd_prbs_test_err; + } + val1 = val2; + if (lcd_hiu_getb(reg1, 0, 12)) { + LCDERR("lcd prbs check error 2, cnt:%d\n", + lcd_prbs_cnt); + goto lcd_prbs_test_err; + } + + if (lcd_prbs_mode == LCD_PRBS_MODE_LVDS) { + if (lcd_lvds_clk_check(lcd_prbs_cnt)) + clk_err_cnt++; + else + clk_err_cnt = 0; + if (clk_err_cnt >= 10) { + LCDERR( + "lvds prbs check error 3(clkmsr), cnt: %d\n", + lcd_prbs_cnt); + goto lcd_prbs_test_err; + } + } + + if (lcd_prbs_cnt >= 0xffffffff) + lcd_prbs_cnt = 0; + else + lcd_prbs_cnt++; } - if (ret) { - LCDERR("lcd prbs check error 1, val:0x%03x, cnt:%d\n", - val2, lcd_prbs_cnt); - return; + + lcd_hiu_write(reg0, 0); + lcd_hiu_write(reg1, 0); + + if (lcd_prbs_mode == LCD_PRBS_MODE_LVDS) { + lcd_prbs_performed |= LCD_PRBS_MODE_LVDS; + lcd_prbs_err &= ~(LCD_PRBS_MODE_LVDS); + LCDPR("lcd lvds prbs check ok\n"); + } else if (lcd_prbs_mode == LCD_PRBS_MODE_VX1) { + lcd_prbs_performed |= LCD_PRBS_MODE_VX1; + lcd_prbs_err &= ~(LCD_PRBS_MODE_VX1); + LCDPR("lcd vx1 prbs check ok\n"); + } else { + LCDPR("lcd prbs check: unsupport mode\n"); } - val1 = val2; - if (lcd_hiu_getb(reg1, 0, 12)) { - LCDERR("lcd prbs check error 2, cnt:%d\n", - lcd_prbs_cnt); - return; + continue; + +lcd_prbs_test_err: + if (lcd_prbs_mode == LCD_PRBS_MODE_LVDS) { + lcd_prbs_performed |= LCD_PRBS_MODE_LVDS; + lcd_prbs_err |= LCD_PRBS_MODE_LVDS; + } else if (lcd_prbs_mode == LCD_PRBS_MODE_VX1) { + lcd_prbs_performed |= LCD_PRBS_MODE_VX1; + lcd_prbs_err |= LCD_PRBS_MODE_VX1; } - if (lcd_prbs_cnt >= 0xffffffff) - lcd_prbs_cnt = 0; - else - lcd_prbs_cnt++; } +lcd_prbs_test_end: lcd_prbs_cnt = 0; - LCDPR("lcd prbs check ok\n"); + lcd_prbs_flag = 0; } static ssize_t lcd_debug_prbs_show(struct class *class, struct class_attribute *attr, char *buf) { - return sprintf(buf, "lcd prbs flag: %d, cnt: %d\n", - lcd_prbs_flag, lcd_prbs_cnt); + return sprintf(buf, + "lvds prbs performed: %d, error: %d\n" + "vx1 prbs performed: %d, error: %d\n" + "lcd prbs flag: %d\n", + (lcd_prbs_performed & LCD_PRBS_MODE_LVDS) ? 1 : 0, + (lcd_prbs_err & LCD_PRBS_MODE_LVDS) ? 1 : 0, + (lcd_prbs_performed & LCD_PRBS_MODE_VX1) ? 1 : 0, + (lcd_prbs_err & LCD_PRBS_MODE_VX1) ? 1 : 0, + lcd_prbs_flag); } static ssize_t lcd_debug_prbs_store(struct class *class, @@ -1614,13 +1748,38 @@ static ssize_t lcd_debug_prbs_store(struct class *class, const char *buf, size_t count) { int ret = 0; - unsigned int temp = 1; + unsigned int temp; + unsigned int prbs_mode_flag; - ret = kstrtouint(buf, 10, &temp); - if (ret) { - LCDERR("invalid data\n"); - return -EINVAL; + switch (buf[0]) { + case 'v': /* vx1 */ + ret = sscanf(buf, "vx1 %d", &temp); + if (ret) { + prbs_mode_flag = LCD_PRBS_MODE_VX1; + } else { + LCDERR("invalid data\n"); + return -EINVAL; + } + break; + case 'l': /* lvds */ + ret = sscanf(buf, "lvds %d", &temp); + if (ret) { + prbs_mode_flag = LCD_PRBS_MODE_LVDS; + } else { + LCDERR("invalid data\n"); + return -EINVAL; + } + break; + default: + prbs_mode_flag = LCD_PRBS_MODE_LVDS | LCD_PRBS_MODE_VX1; + ret = kstrtouint(buf, 10, &temp); + if (ret) { + LCDERR("invalid data\n"); + return -EINVAL; + } + break; } + if (temp) { if (lcd_prbs_flag) { LCDPR("lcd prbs check is already running\n"); @@ -1628,7 +1787,7 @@ static ssize_t lcd_debug_prbs_store(struct class *class, } lcd_prbs_cnt = 0; lcd_prbs_flag = 1; - aml_lcd_prbs_test(temp); + aml_lcd_prbs_test(temp, prbs_mode_flag); } else { if (lcd_prbs_flag == 0) { LCDPR("lcd prbs check is already stopped\n");