"dsi_meas",
"mipi_enable_gate",
"mipi_bandgap_gate";
- reg = <0x0 0xffd06000 0x0 0x400
- 0x0 0xff640000 0x0 0x100>;
+ reg = <0x0 0xffd06000 0x0 0x400 /* dsi_host */
+ 0x0 0xff640000 0x0 0x100>; /* dsi_phy */
+ interrupts = <0 3 1>;
+ interrupt-names = "vsync";
pinctrl_version = <1>; /* for uboot */
/* power type:
"dsi_meas",
"encl_top_gate",
"encl_int_gate";
- reg = <0x0 0xffd07000 0x0 0x400 /* dsi_host */
- 0x0 0xff644000 0x0 0x2000>; /* dsi_phy */
+ reg = <0x0 0xffd07000 0x0 0x400 /* dsi_host */
+ 0x0 0xff644000 0x0 0x200>; /* dsi_phy */
+ interrupts = <0 3 1>;
+ interrupt-names = "vsync";
pinctrl_version = <2>; /* for uboot */
/* power type:
"dsi_meas",
"encl_top_gate",
"encl_int_gate";
- reg = <0x0 0xffd07000 0x0 0x400 /* dsi_host */
- 0x0 0xff644000 0x0 0x2000>; /* dsi_phy */
+ reg = <0x0 0xffd07000 0x0 0x400 /* dsi_host */
+ 0x0 0xff644000 0x0 0x200>; /* dsi_phy */
+ interrupts = <0 3 1>;
+ interrupt-names = "vsync";
pinctrl_version = <2>; /* for uboot */
/* power type:
* "vencl_int_gate";
*/
reg = <0x0 0xc8834400 0x0 0x100>;
+ interrupts = <0 3 1>;
+ interrupt-names = "vsync";
pinctrl_version = <1>; /* for uboot */
/* power type:
* "vencl_int_gate";
*/
reg = <0x0 0xc8834400 0x0 0x100>;
+ interrupts = <0 3 1>;
+ interrupt-names = "vsync";
pinctrl_version = <1>; /* for uboot */
pinctrl-names = "ttl_6bit_hvsync_de_on","ttl_6bit_hvsync_on",
"ttl_6bit_de_on","ttl_8bit_hvsync_de_on",
/* 20180425: tvconfig suuport */
/* 20180620: fix coverity errors */
/* 20180626: txl suuport */
-#define LCD_DRV_VERSION "20180626"
+/* 20180718: mute: wait vsync for display shadow */
+#define LCD_DRV_VERSION "20180718"
#define VPP_OUT_SATURATE (1 << 0)
extern void lcd_if_enable_retry(struct lcd_config_s *pconf);
/* lcd debug */
+extern void lcd_debug_test(unsigned int num);
extern void lcd_mute_setting(unsigned char flag);
extern int lcd_class_creat(void);
extern int lcd_class_remove(void);
return len;
}
+static struct work_struct lcd_test_check_work;
+static void lcd_test_pattern_check(struct work_struct *p_work)
+{
+ struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver();
+ int flag;
+
+ flag = (lcd_drv->lcd_test_state > 0) ? 1 : 0;
+ aml_lcd_notifier_call_chain(LCD_EVENT_TEST_PATTERN, &flag);
+}
+
#define LCD_ENC_TST_NUM_MAX 9
static char *lcd_enc_tst_str[] = {
"0-None", /* 0 */
{0, 0x0, 0x0, 0x0, 1, 0, 3}, /* 8 */
};
-static void lcd_debug_test(unsigned int num)
+void lcd_debug_test(unsigned int num)
{
unsigned int h_active, video_on_pixel;
struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver();
- int flag;
num = (num >= LCD_ENC_TST_NUM_MAX) ? 0 : num;
- flag = (num > 0) ? 1 : 0;
- aml_lcd_notifier_call_chain(LCD_EVENT_TEST_PATTERN, &flag);
+
+ if (lcd_drv->workqueue)
+ queue_work(lcd_drv->workqueue, &lcd_test_check_work);
+ else
+ schedule_work(&lcd_test_check_work);
h_active = lcd_drv->lcd_config->lcd_basic.h_active;
video_on_pixel = lcd_drv->lcd_config->lcd_timing.video_on_pixel;
void lcd_mute_setting(unsigned char flag)
{
- LCDPR("set lcd mute: %d\n", flag);
if (flag) {
lcd_vcbus_write(ENCL_VIDEO_RGBIN_CTRL, 3);
lcd_vcbus_write(ENCL_TST_MDSEL, 0);
unsigned int h_active, video_on_pixel;
struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver();
unsigned int num;
- int flag;
-
- lcd_drv->lcd_mute = 0;
num = lcd_drv->lcd_test_flag;
num = (num >= LCD_ENC_TST_NUM_MAX) ? 0 : num;
- flag = (num > 0) ? 1 : 0;
- aml_lcd_notifier_call_chain(LCD_EVENT_TEST_PATTERN, &flag);
+
+ if (lcd_drv->workqueue)
+ queue_work(lcd_drv->workqueue, &lcd_test_check_work);
+ else
+ schedule_work(&lcd_test_check_work);
h_active = lcd_drv->lcd_config->lcd_basic.h_active;
video_on_pixel = lcd_drv->lcd_config->lcd_timing.video_on_pixel;
case 't': /* test */
ret = sscanf(buf, "test %d", &temp);
if (ret == 1) {
- lcd_drv->lcd_test_flag = (unsigned char)temp;
- lcd_debug_test(temp);
+ lcd_drv->lcd_test_flag =
+ (unsigned char)(temp | LCD_TEST_UPDATE);
} else {
LCDERR("invalid data\n");
return -EINVAL;
{
struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver();
- return sprintf(buf, "test pattern: %d\n", lcd_drv->lcd_test_flag);
+ return sprintf(buf, "test pattern: %d\n", lcd_drv->lcd_test_state);
}
static ssize_t lcd_debug_test_store(struct class *class,
struct class_attribute *attr, const char *buf, size_t count)
{
int ret = 0;
- unsigned int temp = 0;
+ unsigned int temp = 0, i = 0;
struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver();
ret = kstrtouint(buf, 10, &temp);
pr_info("invalid data\n");
return -EINVAL;
}
- lcd_drv->lcd_test_flag = (unsigned char)temp;
- lcd_debug_test(temp);
+ temp = (temp >= LCD_ENC_TST_NUM_MAX) ? 0 : temp;
+ lcd_drv->lcd_test_flag = (unsigned char)(temp | LCD_TEST_UPDATE);
+ while (i++ < 5000) {
+ if (lcd_drv->lcd_test_state == temp)
+ break;
+ udelay(20);
+ }
return count;
}
{
struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver();
- return sprintf(buf, "get lcd mute state: %d\n", lcd_drv->lcd_mute);
+ return sprintf(buf, "get lcd mute state: %d\n",
+ lcd_drv->lcd_mute_state);
}
static ssize_t lcd_debug_mute_store(struct class *class,
struct class_attribute *attr, const char *buf, size_t count)
{
int ret = 0;
- unsigned int temp = 0;
+ unsigned int temp = 0, i = 0;
struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver();
ret = kstrtouint(buf, 10, &temp);
pr_info("invalid data\n");
return -EINVAL;
}
- lcd_drv->lcd_mute = (unsigned char)temp;
- lcd_mute_setting(lcd_drv->lcd_mute);
+ temp = temp ? 1 : 0;
+ lcd_drv->lcd_mute_flag = (unsigned char)(temp | LCD_MUTE_UPDATE);
+ while (i++ < 5000) {
+ if (lcd_drv->lcd_mute_state == temp)
+ break;
+ udelay(20);
+ }
return count;
}
lcd_drv->lcd_screen_restore = lcd_screen_restore;
lcd_drv->lcd_screen_black = lcd_screen_black;
+ INIT_WORK(&lcd_test_check_work, lcd_test_pattern_check);
+
lcd_drv->lcd_debug_class = class_create(THIS_MODULE, "lcd");
if (IS_ERR(lcd_drv->lcd_debug_class)) {
LCDERR("create lcd debug class fail\n");
lcd_vcbus_write(ENCL_VIDEO_VSO_ELINE, pconf->lcd_timing.vs_ve_addr);
lcd_vcbus_write(ENCL_VIDEO_RGBIN_CTRL, 3);
+ /* default black pattern */
+ lcd_vcbus_write(ENCL_TST_MDSEL, 0);
+ lcd_vcbus_write(ENCL_TST_Y, 0);
+ lcd_vcbus_write(ENCL_TST_CB, 0);
+ lcd_vcbus_write(ENCL_TST_CR, 0);
+ lcd_vcbus_write(ENCL_TST_EN, 1);
+ lcd_vcbus_setb(ENCL_VIDEO_MODE_ADV, 0, 3, 1);
+
lcd_vcbus_write(ENCL_VIDEO_EN, 1);
aml_lcd_notifier_call_chain(LCD_EVENT_BACKLIGHT_UPDATE, NULL);
lcd_clk_set(pconf);
lcd_venc_set(pconf);
lcd_encl_tcon_set(pconf);
- lcd_mute_setting(1);
+ lcd_drv->lcd_mute_state = 1;
lcd_vcbus_write(VENC_INTCTRL, 0x200);
lcd_vcbus_write(ENCL_VIDEO_RGBIN_CTRL, 3);
+ /* default black pattern */
+ lcd_vcbus_write(ENCL_TST_MDSEL, 0);
+ lcd_vcbus_write(ENCL_TST_Y, 0);
+ lcd_vcbus_write(ENCL_TST_CB, 0);
+ lcd_vcbus_write(ENCL_TST_CR, 0);
+ lcd_vcbus_write(ENCL_TST_EN, 1);
+ lcd_vcbus_setb(ENCL_VIDEO_MODE_ADV, 0, 3, 1);
+
lcd_vcbus_write(ENCL_VIDEO_EN, 1);
aml_lcd_notifier_call_chain(LCD_EVENT_BACKLIGHT_UPDATE, NULL);
lcd_clk_set(pconf);
lcd_venc_set(pconf);
lcd_encl_tcon_set(pconf);
- lcd_mute_setting(1);
+ lcd_drv->lcd_mute_state = 1;
lcd_vcbus_write(VENC_INTCTRL, 0x200);
{
mutex_lock(&lcd_vout_mutex);
- lcd_driver->lcd_screen_black();
+ lcd_driver->lcd_mute_flag = (unsigned char)(1 | LCD_MUTE_UPDATE);
+ LCDPR("set mute\n");
mutex_unlock(&lcd_vout_mutex);
}
{
mutex_lock(&lcd_vout_mutex);
- lcd_driver->lcd_screen_restore();
+ lcd_driver->lcd_mute_flag = (unsigned char)(0 | LCD_MUTE_UPDATE);
+ LCDPR("clear mute\n");
mutex_unlock(&lcd_vout_mutex);
}
mutex_unlock(&lcd_driver->power_mutex);
}
+static irqreturn_t lcd_vsync_isr(int irq, void *dev_id)
+{
+ int flag;
+
+ if ((lcd_driver->lcd_status & LCD_STATUS_ENCL_ON) == 0)
+ return IRQ_HANDLED;
+
+ if (lcd_driver->lcd_mute_flag & LCD_MUTE_UPDATE) {
+ flag = lcd_driver->lcd_mute_flag & 0x1;
+ if (flag) {
+ if (lcd_driver->lcd_mute_state == 0) {
+ lcd_driver->lcd_mute_state = 1;
+ lcd_driver->lcd_screen_black();
+ }
+ } else {
+ if (lcd_driver->lcd_mute_state) {
+ lcd_driver->lcd_mute_state = 0;
+ lcd_driver->lcd_screen_restore();
+ }
+ }
+ lcd_driver->lcd_mute_flag &= ~(LCD_MUTE_UPDATE);
+ }
+
+ if (lcd_driver->lcd_test_flag & LCD_TEST_UPDATE) {
+ flag = lcd_driver->lcd_test_flag & 0xf;
+ if (flag != lcd_driver->lcd_test_state) {
+ lcd_driver->lcd_test_state = (unsigned char)flag;
+ lcd_debug_test(flag);
+ }
+ lcd_driver->lcd_test_flag &= ~(LCD_TEST_UPDATE);
+ }
+
+ return IRQ_HANDLED;
+}
+
/* ****************************************
* lcd notify
* ****************************************
lcd_driver->lcd_info = &lcd_vinfo;
lcd_driver->lcd_config = &lcd_config_dft;
+ lcd_driver->lcd_test_state = 0;
lcd_driver->lcd_test_flag = 0;
+ lcd_driver->lcd_mute_state = 0;
+ lcd_driver->lcd_mute_flag = 0;
lcd_driver->lcd_resume_type = 1; /* default workqueue */
lcd_driver->power_ctrl = lcd_power_ctrl;
lcd_driver->module_reset = lcd_module_reset;
return 0;
}
+static int lcd_vsync_irq_init(void)
+{
+ if (!lcd_driver->res_vsync_irq) {
+ LCDERR("res_vsync_irq is null\n");
+ return -1;
+ }
+
+ if (request_irq(lcd_driver->res_vsync_irq->start, lcd_vsync_isr,
+ IRQF_SHARED, "lcd_vsync", (void *)"lcd_vsync"))
+ LCDERR("can't request lcd_vsync_irq\n");
+ else
+ LCDPR("request lcd_vsync_irq successful\n");
+
+ return 0;
+}
+
+static void lcd_vsync_irq_remove(void)
+{
+ if (lcd_driver->res_vsync_irq)
+ free_irq(lcd_driver->res_vsync_irq->start, (void *)"lcd_vsync");
+}
+
#ifdef CONFIG_OF
static struct lcd_data_s lcd_data_gxtvbb = {
lcd_ioremap(pdev);
ret = lcd_config_probe(pdev);
+ lcd_vsync_irq_init();
LCDPR("%s %s\n", __func__, (ret ? "failed" : "ok"));
return 0;
destroy_workqueue(lcd_driver->workqueue);
if (lcd_driver) {
+ lcd_vsync_irq_remove();
lcd_fops_remove();
lcd_class_remove();
lcd_config_remove(lcd_driver->dev);
#define LCD_STATUS_VMODE_ACTIVE (1 << 2)
#define LCD_STATUS_ON (LCD_STATUS_IF_ON | LCD_STATUS_ENCL_ON)
+#define LCD_MUTE_UPDATE (1 << 4)
+#define LCD_TEST_UPDATE (1 << 4)
struct aml_lcd_drv_s {
char version[20];
struct lcd_data_s *data;
unsigned char lcd_key_valid;
unsigned char lcd_clk_path; /* 0=hpll, 1=gp0_pll */
unsigned char lcd_config_load;
- unsigned char lcd_test_flag;
unsigned char lcd_resume_type; /* 0=directly, 1=workqueue */
- unsigned char lcd_mute;
+ unsigned char lcd_test_state;
+ unsigned char lcd_test_flag;
+ unsigned char lcd_mute_state;
+ unsigned char lcd_mute_flag;
unsigned char clk_gate_state;
struct clk *encl_top_gate;