/* * drivers/video/sunxi/disp2/disp/de/disp_lcd/disp_lcd.c * * Copyright (c) 2007-2019 Allwinnertech Co., Ltd. * Author: zhengxiaobin * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #include "disp_lcd.h" #include struct disp_lcd_private_data { disp_lcd_flow open_flow; disp_lcd_flow close_flow; disp_panel_para panel_info; panel_extend_para panel_extend_info; disp_lcd_cfg lcd_cfg; disp_lcd_panel_fun lcd_panel_fun; bool enabling; bool disabling; bool bl_enabled; u32 irq_no; u32 irq_no_dsi; u32 irq_no_edp; u32 enabled; u32 power_enabled; u32 bl_need_enabled; u32 frame_per_sec; u32 usec_per_line; u32 judge_line; u32 tri_finish_fail; struct { uintptr_t dev; u32 channel; u32 polarity; u32 period_ns; u32 duty_ns; u32 enabled; }pwm_info; struct clk *clk; struct clk *lvds_clk; struct clk *dsi_clk[CLK_DSI_NUM]; struct clk *edp_clk; struct clk *clk_parent; }; __attribute__((unused)) static spinlock_t lcd_data_lock; static struct disp_device *lcds = NULL; static struct disp_lcd_private_data *lcd_private; s32 disp_lcd_set_bright(struct disp_device *lcd, u32 bright); s32 disp_lcd_get_bright(struct disp_device *lcd); struct disp_device* disp_get_lcd(u32 disp) { u32 num_screens; num_screens = bsp_disp_feat_get_num_screens(); if (disp >= num_screens || !bsp_disp_feat_is_supported_output_types(disp, DISP_OUTPUT_TYPE_LCD)) { DE_INF("disp %d not support lcd output\n", disp); return NULL; } return &lcds[disp]; } static struct disp_lcd_private_data *disp_lcd_get_priv(struct disp_device *lcd) { if (NULL == lcd) { DE_WRN("param is NULL!\n"); return NULL; } return (struct disp_lcd_private_data *)lcd->priv_data; } static s32 disp_lcd_is_used(struct disp_device* lcd) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); s32 ret = 0; if ((NULL == lcd) || (NULL == lcdp)) { ret = 0; } else { ret = (s32)lcdp->lcd_cfg.lcd_used; } return ret; } static s32 lcd_parse_panel_para(u32 disp, disp_panel_para * info) { s32 ret = 0; char primary_key[25]; s32 value = 0; sprintf(primary_key, "lcd%d", disp); memset(info, 0, sizeof(disp_panel_para)); ret = disp_sys_script_get_item(primary_key, "lcd_x", &value, 1); if (ret == 1) { info->lcd_x = value; } ret = disp_sys_script_get_item(primary_key, "lcd_y", &value, 1); if (ret == 1) { info->lcd_y = value; } ret = disp_sys_script_get_item(primary_key, "lcd_width", &value, 1); if (ret == 1) { info->lcd_width = value; } ret = disp_sys_script_get_item(primary_key, "lcd_height", &value, 1); if (ret == 1) { info->lcd_height = value; } ret = disp_sys_script_get_item(primary_key, "lcd_dclk_freq", &value, 1); if (ret == 1) { info->lcd_dclk_freq = value; } ret = disp_sys_script_get_item(primary_key, "lcd_pwm_used", &value, 1); if (ret == 1) { info->lcd_pwm_used = value; } ret = disp_sys_script_get_item(primary_key, "lcd_pwm_ch", &value, 1); if (ret == 1) { info->lcd_pwm_ch = value; } ret = disp_sys_script_get_item(primary_key, "lcd_pwm_freq", &value, 1); if (ret == 1) { info->lcd_pwm_freq = value; } ret = disp_sys_script_get_item(primary_key, "lcd_pwm_pol", &value, 1); if (ret == 1) { info->lcd_pwm_pol = value; } ret = disp_sys_script_get_item(primary_key, "lcd_if", &value, 1); if (ret == 1) { info->lcd_if = value; } ret = disp_sys_script_get_item(primary_key, "lcd_hbp", &value, 1); if (ret == 1) { info->lcd_hbp = value; } ret = disp_sys_script_get_item(primary_key, "lcd_ht", &value, 1); if (ret == 1) { info->lcd_ht = value; } ret = disp_sys_script_get_item(primary_key, "lcd_vbp", &value, 1); if (ret == 1) { info->lcd_vbp = value; } ret = disp_sys_script_get_item(primary_key, "lcd_vt", &value, 1); if (ret == 1) { info->lcd_vt = value; } ret = disp_sys_script_get_item(primary_key, "lcd_hv_if", &value, 1); if (ret == 1) { info->lcd_hv_if = value; } ret = disp_sys_script_get_item(primary_key, "lcd_vspw", &value, 1); if (ret == 1) { info->lcd_vspw = value; } ret = disp_sys_script_get_item(primary_key, "lcd_hspw", &value, 1); if (ret == 1) { info->lcd_hspw = value; } ret = disp_sys_script_get_item(primary_key, "lcd_lvds_if", &value, 1); if (ret == 1) { info->lcd_lvds_if = value; } ret = disp_sys_script_get_item(primary_key, "lcd_lvds_mode", &value, 1); if (ret == 1) { info->lcd_lvds_mode = value; } ret = disp_sys_script_get_item(primary_key, "lcd_lvds_colordepth", &value, 1); if (ret == 1) { info->lcd_lvds_colordepth= value; } ret = disp_sys_script_get_item(primary_key, "lcd_lvds_io_polarity", &value, 1); if (ret == 1) { info->lcd_lvds_io_polarity = value; } ret = disp_sys_script_get_item(primary_key, "lcd_cpu_if", &value, 1); if (ret == 1) { info->lcd_cpu_if = value; } ret = disp_sys_script_get_item(primary_key, "lcd_cpu_te", &value, 1); if (ret == 1) { info->lcd_cpu_te = value; } ret = disp_sys_script_get_item(primary_key, "lcd_cpu_mode", &value, 1); if (ret == 1) info->lcd_cpu_mode = value; ret = disp_sys_script_get_item(primary_key, "lcd_frm", &value, 1); if (ret == 1) { info->lcd_frm = value; } ret = disp_sys_script_get_item(primary_key, "lcd_dsi_if", &value, 1); if (ret == 1) { info->lcd_dsi_if = value; } ret = disp_sys_script_get_item(primary_key, "lcd_dsi_lane", &value, 1); if (ret == 1) { info->lcd_dsi_lane = value; } ret = disp_sys_script_get_item(primary_key, "lcd_dsi_format", &value, 1); if (ret == 1) { info->lcd_dsi_format = value; } ret = disp_sys_script_get_item(primary_key, "lcd_dsi_eotp", &value, 1); if (ret == 1) { info->lcd_dsi_eotp = value; } ret = disp_sys_script_get_item(primary_key, "lcd_dsi_te", &value, 1); if (ret == 1) { info->lcd_dsi_te = value; } ret = disp_sys_script_get_item(primary_key, "lcd_dsi_port_num", &value, 1); if (ret == 1) info->lcd_dsi_port_num = value; ret = disp_sys_script_get_item(primary_key, "lcd_tcon_mode", &value, 1); if (ret == 1) info->lcd_tcon_mode = value; ret = disp_sys_script_get_item(primary_key, "lcd_slave_tcon_num", &value, 1); if (ret == 1) info->lcd_slave_tcon_num = value; ret = disp_sys_script_get_item(primary_key, "lcd_slave_stop_pos", &value, 1); if (ret == 1) info->lcd_slave_stop_pos = value; ret = disp_sys_script_get_item(primary_key, "lcd_sync_pixel_num", &value, 1); if (ret == 1) info->lcd_sync_pixel_num = value; ret = disp_sys_script_get_item(primary_key, "lcd_sync_line_num", &value, 1); if (ret == 1) info->lcd_sync_line_num = value; ret = disp_sys_script_get_item(primary_key, "lcd_tcon_en_odd_even_div", &value, 1); if (ret == 1) info->lcd_tcon_en_odd_even = value; ret = disp_sys_script_get_item(primary_key, "lcd_fsync_en", &value, 1); if (ret == 1) info->lcd_fsync_en = value; ret = disp_sys_script_get_item(primary_key, "lcd_fsync_act_time", &value, 1); if (ret == 1) info->lcd_fsync_act_time = value; ret = disp_sys_script_get_item(primary_key, "lcd_fsync_dis_time", &value, 1); if (ret == 1) info->lcd_fsync_dis_time = value; ret = disp_sys_script_get_item(primary_key, "lcd_fsync_pol", &value, 1); if (ret == 1) info->lcd_fsync_pol = value; ret = disp_sys_script_get_item(primary_key, "lcd_hv_clk_phase", &value, 1); if (ret == 1) { info->lcd_hv_clk_phase = value; } ret = disp_sys_script_get_item(primary_key, "lcd_hv_sync_polarity", &value, 1); if (ret == 1) { info->lcd_hv_sync_polarity = value; } ret = disp_sys_script_get_item(primary_key, "lcd_hv_data_polarity", &value, 1); if (ret == 1) info->lcd_hv_data_polarity = value; ret = disp_sys_script_get_item(primary_key, "lcd_hv_srgb_seq", &value, 1); if (ret == 1) { info->lcd_hv_srgb_seq = value; } ret = disp_sys_script_get_item(primary_key, "lcd_rb_swap", &value, 1); if (ret == 1) { info->lcd_rb_swap = value; } ret = disp_sys_script_get_item(primary_key, "lcd_hv_syuv_seq", &value, 1); if (ret == 1) { info->lcd_hv_syuv_seq = value; } ret = disp_sys_script_get_item(primary_key, "lcd_hv_syuv_fdly", &value, 1); if (ret == 1) { info->lcd_hv_syuv_fdly = value; } ret = disp_sys_script_get_item(primary_key, "lcd_gamma_en", &value, 1); if (ret == 1) { info->lcd_gamma_en = value; } ret = disp_sys_script_get_item(primary_key, "lcd_cmap_en", &value, 1); if (ret == 1) { info->lcd_cmap_en = value; } ret = disp_sys_script_get_item(primary_key, "lcd_xtal_freq", &value, 1); if (ret == 1) { info->lcd_xtal_freq = value; } ret = disp_sys_script_get_item(primary_key, "lcd_size", (int*)info->lcd_size, 2); ret = disp_sys_script_get_item(primary_key, "lcd_model_name", (int*)info->lcd_model_name, 2); return 0; } #if 0 static void lcd_panel_parameter_check(u32 disp, struct disp_device* lcd) { disp_panel_para* info; u32 cycle_num = 1; u32 Lcd_Panel_Err_Flag = 0; u32 Lcd_Panel_Wrn_Flag = 0; u32 Disp_Driver_Bug_Flag = 0; u32 lcd_fclk_frq; u32 lcd_clk_div; s32 ret = 0; char primary_key[20]; s32 value = 0; struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return ; } if (!disp_al_query_lcd_mod(lcd->hwdev_index)) return; sprintf(primary_key, "lcd%d", lcd->disp); ret = disp_sys_script_get_item(primary_key, "lcd_used", &value, 1); if (ret != 0 ) { DE_WRN("get lcd%dpara lcd_used fail\n", lcd->disp); return; } else { if (value != 1) { DE_WRN("lcd%dpara is not used\n", lcd->disp); return; } } info = &(lcdp->panel_info); if (NULL == info) { DE_WRN("NULL hdl!\n"); return; } if (info->lcd_if == 0 && info->lcd_hv_if == 8) cycle_num = 3; else if (info->lcd_if == 0 && info->lcd_hv_if == 10) cycle_num = 3; else if (info->lcd_if == 0 && info->lcd_hv_if == 11) cycle_num = 4; else if (info->lcd_if == 0 && info->lcd_hv_if == 12) cycle_num = 4; else if (info->lcd_if == 1 && info->lcd_cpu_if == 2) cycle_num = 3; else if (info->lcd_if == 1 && info->lcd_cpu_if == 4) cycle_num = 2; else if (info->lcd_if == 1 && info->lcd_cpu_if == 6) cycle_num = 2; else if (info->lcd_if == 1 && info->lcd_cpu_if == 10) cycle_num = 2; else if (info->lcd_if == 1 && info->lcd_cpu_if == 12) cycle_num = 3; else if (info->lcd_if == 1 && info->lcd_cpu_if == 14) cycle_num = 2; else cycle_num = 1; if (info->lcd_hbp > info->lcd_hspw) { ; } else { Lcd_Panel_Err_Flag |= BIT0; } if (info->lcd_vbp > info->lcd_vspw) { ; } else { Lcd_Panel_Err_Flag |= BIT1; } if (info->lcd_ht >= (info->lcd_hbp+info->lcd_x*cycle_num+4)) { ; } else { Lcd_Panel_Err_Flag |= BIT2; } if ((info->lcd_vt) >= (info->lcd_vbp+info->lcd_y + 2)) { ; } else { Lcd_Panel_Err_Flag |= BIT3; } lcd_clk_div = disp_al_lcd_get_clk_div(disp); if (lcd_clk_div >= 6) { ; } else if (lcd_clk_div >=2) { if ((info->lcd_hv_clk_phase == 1) && (info->lcd_hv_clk_phase == 3)) { Lcd_Panel_Err_Flag |= BIT10; } } else { Disp_Driver_Bug_Flag |= 1; } if ((info->lcd_if == 1 && info->lcd_cpu_if == 0) || (info->lcd_if == 1 && info->lcd_cpu_if == 10) || (info->lcd_if == 1 && info->lcd_cpu_if == 12) ||(info->lcd_if == 3 && info->lcd_lvds_colordepth == 1)) { if (info->lcd_frm != 1) Lcd_Panel_Wrn_Flag |= BIT0; } else if (info->lcd_if == 1 && ((info->lcd_cpu_if == 2) || (info->lcd_cpu_if == 4) || (info->lcd_cpu_if == 6) || (info->lcd_cpu_if == 8) || (info->lcd_cpu_if == 14))) { if (info->lcd_frm != 2) Lcd_Panel_Wrn_Flag |= BIT1; } lcd_fclk_frq = (info->lcd_dclk_freq * 1000 * 1000) / ((info->lcd_vt) * info->lcd_ht); if (lcd_fclk_frq < 50 || lcd_fclk_frq > 70) { Lcd_Panel_Wrn_Flag |= BIT2; } if (Lcd_Panel_Err_Flag != 0 || Lcd_Panel_Wrn_Flag != 0) { if (Lcd_Panel_Err_Flag != 0) { u32 i; for (i = 0; i < 200; i++) { //OSAL_PRINTF("*** Lcd in danger...\n"); } } OSAL_PRINTF("*****************************************************************\n"); OSAL_PRINTF("***\n"); OSAL_PRINTF("*** LCD Panel Parameter Check\n"); OSAL_PRINTF("***\n"); OSAL_PRINTF("*** by guozhenjie\n"); OSAL_PRINTF("***\n"); OSAL_PRINTF("*****************************************************************\n"); OSAL_PRINTF("*** \n"); OSAL_PRINTF("*** Interface:"); if (info->lcd_if == 0 && info->lcd_hv_if == 0) {OSAL_PRINTF("*** Parallel HV Panel\n");} else if (info->lcd_if == 0 && info->lcd_hv_if == 8) {OSAL_PRINTF("*** Serial HV Panel\n");} else if (info->lcd_if == 0 && info->lcd_hv_if == 10) {OSAL_PRINTF("*** Dummy RGB HV Panel\n");} else if (info->lcd_if == 0 && info->lcd_hv_if == 11) {OSAL_PRINTF("*** RGB Dummy HV Panel\n");} else if (info->lcd_if == 0 && info->lcd_hv_if == 12) {OSAL_PRINTF("*** Serial YUV Panel\n");} else if (info->lcd_if == 3 && info->lcd_lvds_colordepth== 0) {OSAL_PRINTF("*** 24Bit LVDS Panel\n");} else if (info->lcd_if == 3 && info->lcd_lvds_colordepth== 1) {OSAL_PRINTF("*** 18Bit LVDS Panel\n");} else if ((info->lcd_if == 1) && (info->lcd_cpu_if == 0 || info->lcd_cpu_if == 10 || info->lcd_cpu_if == 12)) {OSAL_PRINTF("*** 18Bit CPU Panel\n");} else if ((info->lcd_if == 1) && (info->lcd_cpu_if == 2 || info->lcd_cpu_if == 4 || info->lcd_cpu_if == 6 || info->lcd_cpu_if == 8 || info->lcd_cpu_if == 14)) {OSAL_PRINTF("*** 16Bit CPU Panel\n");} else { OSAL_PRINTF("\n"); OSAL_PRINTF("*** lcd_if: %d\n",info->lcd_if); OSAL_PRINTF("*** lcd_hv_if: %d\n",info->lcd_hv_if); OSAL_PRINTF("*** lcd_cpu_if: %d\n",info->lcd_cpu_if); } if (info->lcd_frm == 0) {OSAL_PRINTF("*** Lcd Frm Disable\n");} else if (info->lcd_frm == 1) {OSAL_PRINTF("*** Lcd Frm to RGB666\n");} else if (info->lcd_frm == 2) {OSAL_PRINTF("*** Lcd Frm to RGB565\n");} OSAL_PRINTF("*** \n"); OSAL_PRINTF("*** Timing:\n"); OSAL_PRINTF("*** lcd_x: %d\n", info->lcd_x); OSAL_PRINTF("*** lcd_y: %d\n", info->lcd_y); OSAL_PRINTF("*** lcd_ht: %d\n", info->lcd_ht); OSAL_PRINTF("*** lcd_hbp: %d\n", info->lcd_hbp); OSAL_PRINTF("*** lcd_vt: %d\n", info->lcd_vt); OSAL_PRINTF("*** lcd_vbp: %d\n", info->lcd_vbp); OSAL_PRINTF("*** lcd_hspw: %d\n", info->lcd_hspw); OSAL_PRINTF("*** lcd_vspw: %d\n", info->lcd_vspw); OSAL_PRINTF("*** lcd_frame_frq: %dHz\n", lcd_fclk_frq); OSAL_PRINTF("*** \n"); if (Lcd_Panel_Err_Flag & BIT0) {OSAL_PRINTF("*** Err01: Violate \"lcd_hbp > lcd_hspw\"\n");} if (Lcd_Panel_Err_Flag & BIT1) {OSAL_PRINTF("*** Err02: Violate \"lcd_vbp > lcd_vspw\"\n");} if (Lcd_Panel_Err_Flag & BIT2) {OSAL_PRINTF("*** Err03: Violate \"lcd_ht >= (lcd_hbp+lcd_x*%d+4)\"\n", cycle_num);} if (Lcd_Panel_Err_Flag & BIT3) {OSAL_PRINTF("*** Err04: Violate \"(lcd_vt) >= (lcd_vbp+lcd_y+2)\"\n");} if (Lcd_Panel_Err_Flag & BIT10) {OSAL_PRINTF("*** Err10: Violate \"lcd_hv_clk_phase\",use \"0\" or \"2\"");} if (Lcd_Panel_Wrn_Flag & BIT0) {OSAL_PRINTF("*** WRN01: Recommend \"lcd_frm = 1\"\n");} if (Lcd_Panel_Wrn_Flag & BIT1) {OSAL_PRINTF("*** WRN02: Recommend \"lcd_frm = 2\"\n");} if (Lcd_Panel_Wrn_Flag & BIT2) {OSAL_PRINTF("*** WRN03: Recommend \"lcd_dclk_frq = %d\"\n", ((info->lcd_vt) * info->lcd_ht) * 60 / (1000 * 1000));} OSAL_PRINTF("*** \n"); if (Lcd_Panel_Err_Flag != 0) { u32 image_base_addr; u32 reg_value = 0; image_base_addr = DE_Get_Reg_Base(disp); sys_put_wvalue(image_base_addr+0x804, 0xffff00ff);//set background color reg_value = sys_get_wvalue(image_base_addr + 0x800); sys_put_wvalue(image_base_addr+0x800, reg_value & 0xfffff0ff);//close all layer mdelay(2000); sys_put_wvalue(image_base_addr + 0x804, 0x00000000);//set background color sys_put_wvalue(image_base_addr + 0x800, reg_value);//open layer OSAL_PRINTF("*** Try new parameters,you can make it pass!\n"); } OSAL_PRINTF("*** LCD Panel Parameter Check End\n"); OSAL_PRINTF("*****************************************************************\n"); } } #endif static void lcd_get_sys_config(u32 disp, disp_lcd_cfg *lcd_cfg) { disp_gpio_set_t *gpio_info; int value = 1; char primary_key[20], sub_name[25], str[10]; int i = 0; int ret; sprintf(primary_key, "lcd%d", disp); //lcd_used ret = disp_sys_script_get_item(primary_key, "status", (int *)str, 2); if (ret != 2 || strncmp(str, "okay", 10) != 0) { lcd_cfg->lcd_used = 0; return; } lcd_cfg->lcd_used = 1; //lcd_bl_en lcd_cfg->lcd_bl_en_used = 0; gpio_info = &(lcd_cfg->lcd_bl_en); ret = disp_sys_script_get_item(primary_key,"lcd_bl_en", (int *)gpio_info, 3); if (ret == 3) { lcd_cfg->lcd_bl_en_used = 1; } sprintf(sub_name, "lcd_bl_en_power"); ret = disp_sys_script_get_item(primary_key, sub_name, (int *)lcd_cfg->lcd_bl_en_power, 2); //lcd fix power for (i=0; ilcd_power_used[i] = 0; ret = disp_sys_script_get_item(primary_key,sub_name, (int *)(lcd_cfg->lcd_fix_power[i]), 2); if (ret == 2) { /* str */ lcd_cfg->lcd_fix_power_used[i] = 1; } } //lcd_power for (i=0; ilcd_power_used[i] = 0; ret = disp_sys_script_get_item(primary_key,sub_name, (int *)(lcd_cfg->lcd_power[i]), 2); if (ret == 2) { /* str */ lcd_cfg->lcd_power_used[i] = 1; } } //lcd_gpio for (i = 0; i < (LCD_GPIO_NUM - 2); i++) { sprintf(sub_name, "lcd_gpio_%d", i); gpio_info = &(lcd_cfg->lcd_gpio[i]); ret = disp_sys_script_get_item(primary_key,sub_name, (int *)gpio_info, 3); if (ret == 3) { lcd_cfg->lcd_gpio_used[i]= 1; } } //lcd_gpio_scl,lcd_gpio_sda gpio_info = &(lcd_cfg->lcd_gpio[LCD_GPIO_SCL]); ret = disp_sys_script_get_item(primary_key,"lcd_gpio_scl", (int *)gpio_info, 3); if (ret == 3) { lcd_cfg->lcd_gpio_used[LCD_GPIO_SCL]= 1; } gpio_info = &(lcd_cfg->lcd_gpio[LCD_GPIO_SDA]); ret = disp_sys_script_get_item(primary_key,"lcd_gpio_sda", (int *)gpio_info, 3); if (ret == 3) { lcd_cfg->lcd_gpio_used[LCD_GPIO_SDA]= 1; } for (i = 0; i < LCD_GPIO_REGU_NUM; i++) { sprintf(sub_name, "lcd_gpio_power%d", i); ret = disp_sys_script_get_item(primary_key, sub_name, (int *)lcd_cfg->lcd_gpio_power[i], 2); } for (i=0; ilcd_pin_power[i], 2); } sprintf(sub_name, "lcd_pwm_max_limit"); ret = disp_sys_script_get_item(primary_key, sub_name, &value, 1); if (ret == 1) { lcd_cfg->lcd_pwm_max_limit = value; } else { lcd_cfg->lcd_pwm_max_limit = 255; } #ifdef __LINUX_PLAT__ //backlight adjust for (i = 0; i < 101; i++) { sprintf(sub_name, "lcd_bl_%d_percent", i); lcd_cfg->backlight_curve_adjust[i] = 0; if (i == 100) lcd_cfg->backlight_curve_adjust[i] = lcd_cfg->lcd_pwm_max_limit; ret = disp_sys_script_get_item(primary_key, sub_name, &value, 1); if (ret == 1) { value = (value > 100)? 100:value; value = value * lcd_cfg->lcd_pwm_max_limit / 100; lcd_cfg->backlight_curve_adjust[i] = value; } } #endif sprintf(sub_name, "lcd_backlight"); ret = disp_sys_script_get_item(primary_key, sub_name, &value, 1); if (ret == 1) { value = (value > lcd_cfg->lcd_pwm_max_limit)? lcd_cfg->lcd_pwm_max_limit:value; lcd_cfg->backlight_bright = value; } else { lcd_cfg->backlight_bright = 197; } } static s32 lcd_clk_init(struct disp_device* lcd) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return -1; } DE_INF("lcd %d clk init\n", lcd->disp); lcdp->clk_parent = clk_get_parent(lcdp->clk); return DIS_SUCCESS; } static s32 lcd_clk_exit(struct disp_device* lcd) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return -1; } if (lcdp->clk_parent) clk_put(lcdp->clk_parent); return DIS_SUCCESS; } static s32 lcd_clk_config(struct disp_device* lcd) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); struct lcd_clk_info clk_info; unsigned long pll_rate = 297000000, lcd_rate = 33000000, dclk_rate = 33000000, dsi_rate = 0;//hz unsigned long pll_rate_set = 297000000, lcd_rate_set = 33000000, dclk_rate_set = 33000000, dsi_rate_set = 0;//hz u32 i = 0, j = 0; u32 dsi_num = 0; if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return -1; } memset(&clk_info, 0, sizeof(struct lcd_clk_info)); disp_al_lcd_get_clk_info(lcd->hwdev_index, &clk_info, &lcdp->panel_info); dclk_rate = lcdp->panel_info.lcd_dclk_freq * 1000000;//Mhz -> hz if (LCD_IF_DSI == lcdp->panel_info.lcd_if) { lcd_rate = dclk_rate * clk_info.dsi_div; pll_rate = lcd_rate * clk_info.lcd_div; } else { lcd_rate = dclk_rate * clk_info.tcon_div; pll_rate = lcd_rate * clk_info.lcd_div; } dsi_rate = pll_rate / clk_info.dsi_div; if (lcdp->clk_parent) { clk_set_rate(lcdp->clk_parent, pll_rate); pll_rate_set = clk_get_rate(lcdp->clk_parent); } if (clk_info.lcd_div) lcd_rate_set = pll_rate_set / clk_info.lcd_div; else lcd_rate_set = pll_rate_set; clk_set_rate(lcdp->clk, lcd_rate_set); lcd_rate_set = clk_get_rate(lcdp->clk); if (LCD_IF_DSI == lcdp->panel_info.lcd_if) { if (lcdp->panel_info.lcd_dsi_if == LCD_DSI_IF_COMMAND_MODE) dsi_rate_set = pll_rate_set; else dsi_rate_set = pll_rate_set / clk_info.dsi_div; dsi_rate_set = (0 == clk_info.dsi_rate)? dsi_rate_set:clk_info.dsi_rate; dsi_num = (lcdp->panel_info.lcd_tcon_mode == DISP_TCON_DUAL_DSI) ? 2 : 1; dsi_rate_set /= dsi_num; dsi_rate = dsi_rate_set; /* total number of dsi clk for current disp device*/ dsi_num *= CLK_NUM_PER_DSI; /* In the case of CLK_NUM_PER_DSI equal to 2 * even index mean hs clk which need to be seted * odd index mean lp clk which no need to be seted*/ for (i = dsi_num * lcd->disp, j = 0; i < CLK_DSI_NUM; i += CLK_NUM_PER_DSI) { if (lcdp->dsi_clk[i]) { clk_set_rate(lcdp->dsi_clk[i], dsi_rate_set); DE_INF( "clk_set_rate:dsi's %d th clk with %ld\n", i, dsi_rate_set); j += CLK_NUM_PER_DSI; dsi_rate_set = clk_get_rate(lcdp->dsi_clk[i]); } if (j == dsi_num) break; } /*FIXME, dsi clk0 = dsi clk1(rate)*/ /*disp_sys_clk_set_rate(lcdp->dsi_clk[1], dsi_rate_set);*/ } dclk_rate_set = lcd_rate_set / clk_info.tcon_div; if ((pll_rate_set != pll_rate) || (lcd_rate_set != lcd_rate) || (dclk_rate_set != dclk_rate)) { DE_WRN("disp %d, clk: pll(%ld),clk(%ld),dclk(%ld) dsi_rate(%ld)\n clk real:pll(%ld),clk(%ld),dclk(%ld) dsi_rate(%ld)\n", lcd->disp, pll_rate, lcd_rate, dclk_rate, dsi_rate, pll_rate_set, lcd_rate_set, dclk_rate_set, dsi_rate_set); } return 0; } static s32 lcd_clk_enable(struct disp_device* lcd) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); int ret = 0; u32 i = 0, j = 0; u32 dsi_num = 0; if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return -1; } lcd_clk_config(lcd); ret = clk_prepare_enable(lcdp->clk); if (0 != ret) { DE_WRN("fail enable lcd's clock!\n"); goto exit; } if (LCD_IF_LVDS == lcdp->panel_info.lcd_if) { if (lcdp->lvds_clk) ret = clk_prepare_enable(lcdp->lvds_clk); else ret = clk_prepare_enable(lcdp->clk); if (0 != ret) { DE_WRN("fail enable lvds's clock!\n"); goto exit; } #ifdef SUPPORT_COMBO_DPHY if (lcd->hwdev_index == 0) clk_prepare_enable(lcdp->dsi_clk[0]); #endif } else if (LCD_IF_DSI == lcdp->panel_info.lcd_if) { dsi_num = (lcdp->panel_info.lcd_tcon_mode == DISP_TCON_DUAL_DSI) ? 2 : 1; /*the num of dsi clk to use for current disp*/ dsi_num *= CLK_NUM_PER_DSI; for (i = dsi_num * lcd->disp, j = 0; i < CLK_DSI_NUM; ++i) { if (lcdp->dsi_clk[i]) { ret = clk_prepare_enable(lcdp->dsi_clk[i]); if (0 != ret) { DE_WRN("fail enable dsi's clock%d!\n", i); goto exit; } ++j; } else { DE_WRN("dsi's clock%d is NULL!\n", i); goto exit; } if (j == dsi_num) break; } } else if (LCD_IF_EDP == lcdp->panel_info.lcd_if) { ret = clk_prepare_enable(lcdp->edp_clk); if (0 != ret) { DE_WRN("fail enable edp's clock!\n"); goto exit; } } exit: return ret; } static s32 lcd_clk_disable(struct disp_device* lcd) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); u32 i = 0, j = 0; u32 dsi_num = 0; if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return -1; } if (LCD_IF_LVDS == lcdp->panel_info.lcd_if) { clk_disable(lcdp->lvds_clk); #ifdef SUPPORT_COMBO_DPHY if (lcd->hwdev_index == 0) clk_disable(lcdp->dsi_clk[0]); #endif } else if (LCD_IF_DSI == lcdp->panel_info.lcd_if) { dsi_num = (lcdp->panel_info.lcd_tcon_mode == DISP_TCON_DUAL_DSI) ? 2 : 1; /*the num of dsi clk to use for current disp*/ dsi_num *= CLK_NUM_PER_DSI; for (i = dsi_num * lcd->disp, j = 0; i < CLK_DSI_NUM; ++i) { if (lcdp->dsi_clk[i]) clk_disable(lcdp->dsi_clk[i]); ++j; if (j == dsi_num) break; } } else if (LCD_IF_EDP == lcdp->panel_info.lcd_if) { clk_disable(lcdp->edp_clk); } clk_disable(lcdp->clk); return DIS_SUCCESS; } static int lcd_calc_judge_line(struct disp_device *lcd) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return -1; } if (lcdp->usec_per_line == 0) { disp_panel_para *panel_info = &lcdp->panel_info; /* * usec_per_line = 1 / fps / vt * 1000000 * = 1 / (dclk * 1000000 / vt / ht) / vt * 1000000 * = ht / dclk(Mhz) */ lcdp->usec_per_line = panel_info->lcd_ht / panel_info->lcd_dclk_freq; } if (lcdp->judge_line == 0) { int start_delay = disp_al_lcd_get_start_delay(lcd->hwdev_index, &lcdp->panel_info); int usec_start_delay = start_delay * lcdp->usec_per_line; int usec_judge_point; if (usec_start_delay <= 200) usec_judge_point = usec_start_delay * 3 / 7; else if (usec_start_delay <= 400) usec_judge_point = usec_start_delay / 2; else usec_judge_point = 200; lcdp->judge_line = usec_judge_point / lcdp->usec_per_line; } return 0; } static s32 disp_lcd_speed_limit(disp_panel_para *panel, u32 *min_dclk, u32 *max_dclk) { #if defined(CONFIG_MACH_SUN50IW10) unsigned long markid = 0; unsigned int qa_val = 0; unsigned int ic_ver = 0; unsigned int display_cfg_flag = 0; /*init unlimit*/ *min_dclk = 0; *max_dclk = 9999; qa_val = readl(0x0300621c); qa_val = (qa_val >> 28) & 0x00000003; ic_ver = readl(0x03000024) & 0x00000007; markid = readl(0x03006200) & 0x0000ffff; display_cfg_flag = (readl(0x03006218) >> 12) & 0x00000001; /*B810 and bad ic not support DSI*/ if ((qa_val >= 2 && panel->lcd_if == LCD_IF_DSI) || (markid == 0x4000)) { /*bad IC not support DSI*/ *min_dclk = 9999; *max_dclk = 0; goto OUT; } switch (markid) { case 0x3c00: /*A53*/ { if (panel->lcd_if == LCD_IF_DSI) { if (qa_val == 0) *min_dclk = 40; /*1024*600@60*/ /* normal qa and B/C ic */ if (qa_val == 1 && ic_ver == 0) { *min_dclk = 64; /*1280*720@60*/ } /*ic version after e*/ if (ic_ver >= 4) *min_dclk = 0; } *max_dclk = 200; /*1280*720@60*/ } break; case 0x0400: /*A100*/ { if (panel->lcd_if == LCD_IF_DSI) { if (qa_val == 0) *min_dclk = 40; /*1024*600@60*/ /* normal qa and B/C ic */ if (qa_val == 1 && ic_ver == 0) { *min_dclk = 64; /*1280*720@60*/ } /*ic version after e*/ if (ic_ver >= 4) *min_dclk = 0; } *max_dclk = 85; /*1280*720@60*/ } break; case 0x1400: /*A133*/ { if (panel->lcd_if == LCD_IF_DSI) { if ((qa_val == 0 && ic_ver == 0) || (qa_val == 1 && ic_ver == 3)) { /*D 01 or B/C 00*/ *min_dclk = 40; } else if (qa_val == 1 && ic_ver == 0) { /*B/C 01*/ *min_dclk = 64; /*1280*720@60*/ } /*ic version after e*/ if (ic_ver >= 4) *min_dclk = 0; } *max_dclk = 200; /*1920*1200@60*/ } break; case 0x1000: /*R818/MR813*/ case 0x2000: { /*not bad ic*/ *max_dclk = 200; /*1920*1200@60*/ } break; case 0x0800: { /*T509*/ if (panel->lcd_if == LCD_IF_DSI) { if (qa_val == 0 && ic_ver == 0) *min_dclk = 40;/*1024*600@60*/ else *min_dclk = 0; } *max_dclk = 200; /*1920*1200@60*/ } break; default: break; } OUT: tick_printf( "soc ic_ver:0x%x, qa_val:0x%x, markid:0x%x dclk[%u-%u] display_cfg_flag:%d\n", ic_ver, qa_val, markid, *min_dclk, *max_dclk, display_cfg_flag); #endif /*unlimit */ return 0; } static s32 disp_lcd_tcon_enable(struct disp_device *lcd) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); u32 min_dclk = 0, max_dclk = 0; if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return -1; } disp_lcd_speed_limit(&lcdp->panel_info, &min_dclk, &max_dclk); if (lcdp->panel_info.lcd_dclk_freq < min_dclk || lcdp->panel_info.lcd_dclk_freq > max_dclk) { return 0; } return disp_al_lcd_enable(lcd->hwdev_index, &lcdp->panel_info); } static s32 disp_lcd_tcon_disable(struct disp_device *lcd) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return -1; } return disp_al_lcd_disable(lcd->hwdev_index, &lcdp->panel_info); } static s32 disp_lcd_pin_cfg(struct disp_device *lcd, u32 bon) { int i; struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); char dev_name[25]; if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return DIS_FAIL; } DE_INF("lcd %d pin config, state %s, %d\n", lcd->disp, (bon)? "on":"off", bon); //io-pad if (bon == 1) { for (i=0; ilcd_cfg.lcd_pin_power[i], "")) || (!strcmp(lcdp->lcd_cfg.lcd_pin_power[i], "none")))) disp_sys_power_enable(lcdp->lcd_cfg.lcd_pin_power[i]); } } sprintf(dev_name, "lcd%d", lcd->disp); disp_sys_pin_set_state(dev_name, (1==bon)? DISP_PIN_STATE_ACTIVE:DISP_PIN_STATE_SLEEP); disp_al_lcd_io_cfg(lcd->hwdev_index, bon, &lcdp->panel_info); if (bon == 0) { for (i=LCD_GPIO_REGU_NUM-1; i>=0; i--) { if (!((!strcmp(lcdp->lcd_cfg.lcd_pin_power[i], "")) || (!strcmp(lcdp->lcd_cfg.lcd_pin_power[i], "none")))) disp_sys_power_disable(lcdp->lcd_cfg.lcd_pin_power[i]); } } return DIS_SUCCESS; } static s32 disp_lcd_pwm_enable(struct disp_device *lcd) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return DIS_FAIL; } if (disp_lcd_is_used(lcd) && lcdp->pwm_info.dev) { return disp_sys_pwm_enable(lcdp->pwm_info.dev); } DE_WRN("pwm device hdl is NULL\n"); return DIS_FAIL; } static s32 disp_lcd_pwm_disable(struct disp_device *lcd) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return DIS_FAIL; } if (disp_lcd_is_used(lcd) && lcdp->pwm_info.dev) { return disp_sys_pwm_disable(lcdp->pwm_info.dev); } DE_WRN("pwm device hdl is NULL\n"); return DIS_FAIL; } static s32 disp_lcd_backlight_enable(struct disp_device *lcd) { disp_gpio_set_t gpio_info[1]; struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); unsigned long flags; if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return DIS_FAIL; } spin_lock_irqsave(&lcd_data_lock, flags); lcdp->bl_need_enabled = 1; spin_unlock_irqrestore(&lcd_data_lock, flags); if (disp_lcd_is_used(lcd)) { unsigned bl; if (lcdp->lcd_cfg.lcd_bl_en_used) { //io-pad if (!((!strcmp(lcdp->lcd_cfg.lcd_bl_en_power, "")) || (!strcmp(lcdp->lcd_cfg.lcd_bl_en_power, "none")))) disp_sys_power_enable(lcdp->lcd_cfg.lcd_bl_en_power); memcpy(gpio_info, &(lcdp->lcd_cfg.lcd_bl_en), sizeof(disp_gpio_set_t)); disp_sys_gpio_request_simple(gpio_info, 1); } bl = disp_lcd_get_bright(lcd); disp_lcd_set_bright(lcd, bl); } return 0; } static s32 disp_lcd_backlight_disable(struct disp_device *lcd) { disp_gpio_set_t gpio_info[1]; struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return DIS_FAIL; } if (disp_lcd_is_used(lcd)) { if (lcdp->lcd_cfg.lcd_bl_en_used) { memcpy(gpio_info, &(lcdp->lcd_cfg.lcd_bl_en), sizeof(disp_gpio_set_t)); gpio_info->data = (gpio_info->data==0)?1:0; gpio_info->mul_sel = 7; disp_sys_gpio_request_simple(gpio_info, 1); //io-pad if (!((!strcmp(lcdp->lcd_cfg.lcd_bl_en_power, "")) || (!strcmp(lcdp->lcd_cfg.lcd_bl_en_power, "none")))) disp_sys_power_disable(lcdp->lcd_cfg.lcd_bl_en_power); } } return 0; } static s32 disp_lcd_power_enable(struct disp_device *lcd, u32 power_id) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return DIS_FAIL; } if (disp_lcd_is_used(lcd)) { if (1 == lcdp->lcd_cfg.lcd_power_used[power_id]) { /* regulator type */ disp_sys_power_enable(lcdp->lcd_cfg.lcd_power[power_id]); } } return 0; } static s32 disp_lcd_power_disable(struct disp_device *lcd, u32 power_id) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return DIS_FAIL; } if (disp_lcd_is_used(lcd)) { if (1 == lcdp->lcd_cfg.lcd_power_used[power_id]) { /* regulator type */ disp_sys_power_disable(lcdp->lcd_cfg.lcd_power[power_id]); } } return 0; } static s32 disp_lcd_bright_get_adjust_value(struct disp_device *lcd, u32 bright) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return DIS_FAIL; } bright = (bright > 255)? 255:bright; return lcdp->panel_extend_info.lcd_bright_curve_tbl[bright]; } static s32 disp_lcd_bright_curve_init(struct disp_device *lcd) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); u32 i = 0, j=0; u32 items = 0; u32 lcd_bright_curve_tbl[101][2]; if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return DIS_FAIL; } for (i = 0; i < 101; i++) { if (lcdp->lcd_cfg.backlight_curve_adjust[i] == 0) { if (i == 0) { lcd_bright_curve_tbl[items][0] = 0; lcd_bright_curve_tbl[items][1] = 0; items++; } else if (i == 100) { lcd_bright_curve_tbl[items][0] = 255; lcd_bright_curve_tbl[items][1] = 255; items++; } } else { lcd_bright_curve_tbl[items][0] = 255 * i / 100; lcd_bright_curve_tbl[items][1] = lcdp->lcd_cfg.backlight_curve_adjust[i]; items++; } } for (i=0; ipanel_extend_info.lcd_bright_curve_tbl[lcd_bright_curve_tbl[i][0] + j] = value; } } lcdp->panel_extend_info.lcd_bright_curve_tbl[255] = lcd_bright_curve_tbl[items-1][1]; return 0; } s32 disp_lcd_set_bright(struct disp_device *lcd, u32 bright) { u32 duty_ns; __u64 backlight_bright = bright; __u64 backlight_dimming; __u64 period_ns; struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); unsigned long flags; bool bright_update = false; struct disp_manager *mgr = NULL; struct disp_smbl *smbl = NULL; if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return DIS_FAIL; } mgr = lcd->manager; if (NULL == mgr) { DE_WRN("NULL hdl!\n"); return DIS_FAIL; } smbl = mgr->smbl; spin_lock_irqsave(&lcd_data_lock, flags); backlight_bright = (backlight_bright > 255)? 255:backlight_bright; if (lcdp->lcd_cfg.backlight_bright != backlight_bright) { bright_update = true; lcdp->lcd_cfg.backlight_bright = backlight_bright; } spin_unlock_irqrestore(&lcd_data_lock, flags); if (bright_update && smbl) smbl->update_backlight(smbl, backlight_bright); if (lcdp->pwm_info.dev) { if (backlight_bright != 0) { backlight_bright += 1; } backlight_bright = disp_lcd_bright_get_adjust_value(lcd, backlight_bright); lcdp->lcd_cfg.backlight_dimming = (0 == lcdp->lcd_cfg.backlight_dimming)? 256:lcdp->lcd_cfg.backlight_dimming; backlight_dimming = lcdp->lcd_cfg.backlight_dimming; period_ns = lcdp->pwm_info.period_ns; duty_ns = (backlight_bright * backlight_dimming * period_ns/256 + 128) / 256; lcdp->pwm_info.duty_ns = duty_ns; disp_sys_pwm_config(lcdp->pwm_info.dev, duty_ns, period_ns); } if (lcdp->lcd_panel_fun.set_bright && lcdp->enabled) { lcdp->lcd_panel_fun.set_bright(lcd->disp,disp_lcd_bright_get_adjust_value(lcd,bright)); } return DIS_SUCCESS; } s32 disp_lcd_get_bright(struct disp_device *lcd) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return DIS_FAIL; } return lcdp->lcd_cfg.backlight_bright; } static s32 disp_lcd_set_bright_dimming(struct disp_device *lcd, u32 dimming) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); u32 bl = 0; if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return DIS_FAIL; } dimming = dimming > 256?256:dimming; lcdp->lcd_cfg.backlight_dimming = dimming; bl = disp_lcd_get_bright(lcd); disp_lcd_set_bright(lcd, bl); return DIS_SUCCESS; } static s32 disp_lcd_get_panel_info(struct disp_device *lcd, disp_panel_para* info) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return DIS_FAIL; } memcpy(info, (disp_panel_para*)(&(lcdp->panel_info)), sizeof(disp_panel_para)); return 0; } //FIXME extern void sync_event_proc(u32 disp, bool timeout); #if defined(__LINUX_PLAT__) static s32 disp_lcd_event_proc(int irq, void *parg) #else static s32 disp_lcd_event_proc(void *parg) #endif { struct disp_device *lcd = (struct disp_device*)parg; struct disp_lcd_private_data *lcdp = NULL; #if defined(SUPPORT_EINK) && defined(CONFIG_EINK_PANEL_USED) struct disp_eink_manager *eink_manager = NULL; #else struct disp_manager *mgr = NULL; u32 irq_flag = 0; #endif u32 hwdev_index; if (NULL == lcd) return DISP_IRQ_RETURN; hwdev_index = lcd->hwdev_index; lcdp = disp_lcd_get_priv(lcd); if (NULL == lcdp) return DISP_IRQ_RETURN; #if defined(SUPPORT_EINK) && defined(CONFIG_EINK_PANEL_USED) eink_manager = disp_get_eink_manager(0); if (NULL == eink_manager) return DISP_IRQ_RETURN; #endif if (disp_al_lcd_query_irq(hwdev_index, LCD_IRQ_TCON0_VBLK, &lcdp->panel_info)) { #if defined(SUPPORT_EINK) && defined(CONFIG_EINK_PANEL_USED) eink_display_one_frame(eink_manager); #else int cur_line = disp_al_lcd_get_cur_line(hwdev_index, &lcdp->panel_info); int start_delay = disp_al_lcd_get_start_delay(hwdev_index, &lcdp->panel_info); mgr = lcd->manager; if (NULL == mgr) return DISP_IRQ_RETURN; if (cur_line <= (start_delay - lcdp->judge_line)) { sync_event_proc(mgr->disp, false); } else { sync_event_proc(mgr->disp, true); } #endif } else { #if defined(SUPPORT_EINK) && defined(CONFIG_EINK_PANEL_USED) goto exit; #else irq_flag = disp_al_lcd_query_irq(hwdev_index, LCD_IRQ_TCON0_CNTR, &lcdp->panel_info); irq_flag |= disp_al_lcd_query_irq(hwdev_index, LCD_IRQ_TCON0_TRIF, &lcdp->panel_info); if (0 == irq_flag) goto exit; if (disp_al_lcd_tri_busy(hwdev_index, &lcdp->panel_info)) { /* if lcd is still busy when tri/cnt irq coming, * take it as failture, record failture times, * when it reach 2 times, clear counter */ lcdp->tri_finish_fail++; lcdp->tri_finish_fail = (2 == lcdp->tri_finish_fail) ? 0 : lcdp->tri_finish_fail; } else lcdp->tri_finish_fail = 0; mgr = lcd->manager; if (NULL == mgr) return DISP_IRQ_RETURN; if (0 == lcdp->tri_finish_fail) { sync_event_proc(mgr->disp, false); disp_al_lcd_tri_start(hwdev_index, &lcdp->panel_info); } else sync_event_proc(mgr->disp, true); #endif } exit: return DISP_IRQ_RETURN; } static s32 disp_lcd_cal_fps(struct disp_device *lcd) { s32 ret = -1; struct disp_lcd_private_data *lcdp = NULL; disp_panel_para *panel_info = NULL; if (!lcd) goto OUT; lcdp = disp_lcd_get_priv(lcd); if (!lcdp) goto OUT; panel_info = &lcdp->panel_info; lcdp->frame_per_sec = panel_info->lcd_dclk_freq * 1000000 / panel_info->lcd_ht / panel_info->lcd_vt * (panel_info->lcd_interlace + 1); ret = 0; OUT: return ret; } static s32 disp_lcd_pre_enable(struct disp_device* lcd) { unsigned long flags; struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); int i; struct disp_manager *mgr = NULL; int ret; if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return DIS_FAIL; } DE_INF("lcd %d\n", lcd->disp); mgr = lcd->manager; if ((NULL == mgr)) { DE_WRN("mgr is NULL!\n"); return DIS_FAIL; } if (1 == disp_lcd_is_enabled(lcd)) return 0; disp_lcd_cal_fps(lcd); if (mgr->enable) mgr->enable(mgr); /* init fix power */ for (i=0; ilcd_cfg.lcd_fix_power_used[i]) { disp_sys_power_enable(lcdp->lcd_cfg.lcd_fix_power[i]); } } #if defined(SUPPORT_DSI) && defined(DSI_VERSION_40) if ((LCD_IF_DSI == lcdp->panel_info.lcd_if) && (0 != lcdp->irq_no_dsi)) { if (lcdp->panel_info.lcd_dsi_if == LCD_DSI_IF_COMMAND_MODE) { disp_sys_register_irq(lcdp->irq_no, 0, disp_lcd_event_proc, (void *)lcd, 0, 0); disp_sys_enable_irq(lcdp->irq_no); } else { disp_sys_register_irq(lcdp->irq_no_dsi, 0, disp_lcd_event_proc, (void *)lcd, 0, 0); disp_sys_enable_irq(lcdp->irq_no_dsi); } } else #endif { disp_sys_register_irq(lcdp->irq_no,0,disp_lcd_event_proc,(void*)lcd,0,0); disp_sys_enable_irq(lcdp->irq_no); } spin_lock_irqsave(&lcd_data_lock, flags); lcdp->enabling = 1; lcdp->bl_need_enabled = 0; spin_unlock_irqrestore(&lcd_data_lock, flags); if (lcdp->lcd_panel_fun.cfg_panel_info) lcdp->lcd_panel_fun.cfg_panel_info(&lcdp->panel_extend_info); else DE_WRN("lcd_panel_fun[%d].cfg_panel_info is NULL\n", lcd->disp); lcdp->panel_extend_info.lcd_gamma_en = lcdp->panel_info.lcd_gamma_en; disp_lcd_gpio_init(lcd); ret = lcd_clk_enable(lcd); if (0 != ret) return DIS_FAIL; disp_al_lcd_cfg(lcd->hwdev_index, &lcdp->panel_info, &lcdp->panel_extend_info); return 0; } static s32 disp_lcd_post_enable(struct disp_device* lcd) { unsigned long flags; struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); unsigned bl; int ret = 0; if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return DIS_FAIL; } spin_lock_irqsave(&lcd_data_lock, flags); lcdp->enabled = 1; lcdp->enabling = 0; spin_unlock_irqrestore(&lcd_data_lock, flags); bl = disp_lcd_get_bright(lcd); disp_lcd_set_bright(lcd, bl); return ret; } static void disp_lcd_pre_enable_ex(unsigned int disp) { struct disp_device *lcd = NULL; lcd = disp_get_lcd(disp); if (lcd != NULL) disp_lcd_pre_enable(lcd); return ; } static void disp_lcd_post_enable_ex(unsigned int disp) { struct disp_device *lcd = NULL; lcd = disp_get_lcd(disp); if (lcd != NULL) disp_lcd_post_enable(lcd); return ; } static s32 __disp_lcd_enable(struct disp_device* lcd, bool fake) { unsigned long flags; struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); int i, flow_number; struct disp_manager *mgr = NULL; unsigned bl; int ret; if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return DIS_FAIL; } DE_INF("lcd %d\n", lcd->disp); mgr = lcd->manager; if ((NULL == mgr)) { DE_WRN("mgr is NULL!\n"); return DIS_FAIL; } if (1 == disp_lcd_is_enabled(lcd)) return 0; disp_lcd_cal_fps(lcd); if (mgr->enable) mgr->enable(mgr); /* init fix power */ for (i=0; ilcd_cfg.lcd_fix_power_used[i]) { disp_sys_power_enable(lcdp->lcd_cfg.lcd_fix_power[i]); } } #if defined(SUPPORT_DSI) && defined(DSI_VERSION_40) if ((LCD_IF_DSI == lcdp->panel_info.lcd_if) && (0 != lcdp->irq_no_dsi)) { if (lcdp->panel_info.lcd_dsi_if == LCD_DSI_IF_COMMAND_MODE) { disp_sys_register_irq(lcdp->irq_no, 0, disp_lcd_event_proc, (void *)lcd, 0, 0); disp_sys_enable_irq(lcdp->irq_no); } else { disp_sys_register_irq(lcdp->irq_no_dsi, 0, disp_lcd_event_proc, (void *)lcd, 0, 0); disp_sys_enable_irq(lcdp->irq_no_dsi); } } else #endif { disp_sys_register_irq(lcdp->irq_no,0,disp_lcd_event_proc,(void*)lcd,0,0); disp_sys_enable_irq(lcdp->irq_no); } spin_lock_irqsave(&lcd_data_lock, flags); lcdp->enabling = 1; lcdp->bl_need_enabled = 0; spin_unlock_irqrestore(&lcd_data_lock, flags); if (lcdp->lcd_panel_fun.cfg_panel_info) lcdp->lcd_panel_fun.cfg_panel_info(&lcdp->panel_extend_info); else DE_WRN("lcd_panel_fun[%d].cfg_panel_info is NULL\n", lcd->disp); lcdp->panel_extend_info.lcd_gamma_en = lcdp->panel_info.lcd_gamma_en; disp_lcd_gpio_init(lcd); ret = lcd_clk_enable(lcd); if (0 != ret) return DIS_FAIL; disp_al_lcd_cfg(lcd->hwdev_index, &lcdp->panel_info, &lcdp->panel_extend_info); lcd_calc_judge_line(lcd); lcdp->open_flow.func_num = 0; if (lcdp->lcd_panel_fun.cfg_open_flow) { lcdp->lcd_panel_fun.cfg_open_flow(lcd->disp); } else { DE_WRN("lcd_panel_fun[%d].cfg_open_flow is NULL\n", lcd->disp); } flow_number = (fake)? (lcdp->open_flow.func_num-1) : (lcdp->open_flow.func_num); for (i=0; iopen_flow.func[i].func) { lcdp->open_flow.func[i].func(lcd->disp); DE_INF("open flow:step %d finish, to delay %d\n", i, lcdp->open_flow.func[i].delay); if (0 != lcdp->open_flow.func[i].delay) disp_delay_ms(lcdp->open_flow.func[i].delay); } } spin_lock_irqsave(&lcd_data_lock, flags); lcdp->enabled = 1; lcdp->enabling = 0; spin_unlock_irqrestore(&lcd_data_lock, flags); bl = disp_lcd_get_bright(lcd); disp_lcd_set_bright(lcd, bl); return 0; } /* extern bool flush_work(struct work_struct *work); */ #if defined(SUPPORT_EINK) && defined(CONFIG_EINK_PANEL_USED) static s32 disp_lcd_enable(struct disp_device *lcd) { unsigned long flags; struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); struct disp_manager *mgr = NULL; int ret; int i; if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return DIS_FAIL; } /* flush_work(&lcd->close_eink_panel_work); */ DE_INF("lcd %d\n", lcd->disp); mgr = lcd->manager; if ((NULL == mgr)) { DE_WRN("mgr is NULL!\n"); return DIS_FAIL; } if (1 == disp_lcd_is_enabled(lcd)) return 0; disp_sys_register_irq(lcdp->irq_no, 0, disp_lcd_event_proc, (void *)lcd, 0, 0); disp_sys_enable_irq(lcdp->irq_no); spin_lock_irqsave(&lcd_data_lock, flags); lcdp->enabling = 1; lcdp->bl_need_enabled = 0; spin_unlock_irqrestore(&lcd_data_lock, flags); if (lcdp->lcd_panel_fun.cfg_panel_info) lcdp->lcd_panel_fun.cfg_panel_info(&lcdp->panel_extend_info); else DE_WRN("lcd_panel_fun[%d].cfg_panel_info is NULL\n", lcd->disp); disp_lcd_gpio_init(lcd); ret = lcd_clk_enable(lcd); if (0 != ret) return DIS_FAIL; disp_al_lcd_cfg(lcd->hwdev_index, &lcdp->panel_info, &lcdp->panel_extend_info); lcdp->open_flow.func_num = 0; if (lcdp->lcd_panel_fun.cfg_open_flow) lcdp->lcd_panel_fun.cfg_open_flow(lcd->disp); else DE_WRN("lcd_panel_fun[%d].cfg_open_flow is NULL\n", lcd->disp); for (i = 0; i < lcdp->open_flow.func_num; i++) { if (lcdp->open_flow.func[i].func) { lcdp->open_flow.func[i].func(lcd->disp); DE_INF("open flow:step %d finish, to delay %d\n", i, lcdp->open_flow.func[i].delay); if (0 != lcdp->open_flow.func[i].delay) disp_delay_ms(lcdp->open_flow.func[i].delay); } } spin_lock_irqsave(&lcd_data_lock, flags); lcdp->enabled = 1; lcdp->enabling = 0; spin_unlock_irqrestore(&lcd_data_lock, flags); return 0; } #else static s32 disp_lcd_enable(struct disp_device* lcd) { return __disp_lcd_enable(lcd, false); } #endif /* lcd enable except for backlight */ static s32 disp_lcd_fake_enable(struct disp_device* lcd) { return __disp_lcd_enable(lcd, true); } static s32 disp_lcd_pre_disable(struct disp_device* lcd) { unsigned long flags; struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return DIS_FAIL; } DE_INF("lcd %d\n", lcd->disp); if (0 == disp_lcd_is_enabled(lcd)) return 0; spin_lock_irqsave(&lcd_data_lock, flags); lcdp->enabled = 0; spin_unlock_irqrestore(&lcd_data_lock, flags); return 0; } static s32 disp_lcd_post_disable(struct disp_device* lcd) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); struct disp_manager *mgr = NULL; int i; if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return DIS_FAIL; } DE_INF("lcd %d\n", lcd->disp); mgr = lcd->manager; if ((NULL == mgr)) { DE_WRN("mgr is NULL!\n"); return DIS_FAIL; } disp_lcd_gpio_exit(lcd); lcd_clk_disable(lcd); if ((LCD_IF_DSI == lcdp->panel_info.lcd_if) && (0 != lcdp->irq_no_dsi)) { if (lcdp->panel_info.lcd_dsi_if == LCD_DSI_IF_COMMAND_MODE) { disp_sys_disable_irq(lcdp->irq_no); disp_sys_unregister_irq( lcdp->irq_no, disp_lcd_event_proc, (void *)lcd); } else { disp_sys_disable_irq(lcdp->irq_no_dsi); disp_sys_unregister_irq( lcdp->irq_no_dsi, disp_lcd_event_proc, (void *)lcd); } } else { disp_sys_disable_irq(lcdp->irq_no); disp_sys_unregister_irq(lcdp->irq_no, disp_lcd_event_proc,(void*)lcd); } /* disable fix power */ for (i=LCD_POWER_NUM -1; i>=0; i--) { if (1 == lcdp->lcd_cfg.lcd_fix_power_used[i]) { disp_sys_power_disable(lcdp->lcd_cfg.lcd_fix_power[i]); } } if (mgr->disable) mgr->disable(mgr); return 0; } static void disp_lcd_pre_disable_ex(unsigned int disp) { struct disp_device *lcd = NULL; lcd = disp_get_lcd(disp); if (lcd != NULL) disp_lcd_pre_disable(lcd); return ; } static void disp_lcd_post_disable_ex(unsigned int disp) { struct disp_device *lcd = NULL; lcd = disp_get_lcd(disp); if (lcd != NULL) disp_lcd_post_disable(lcd); return ; } #if defined(SUPPORT_EINK) && defined(CONFIG_EINK_PANEL_USED) s32 disp_lcd_disable(struct disp_device *lcd) { unsigned long flags; struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); struct disp_manager *mgr = NULL; int i; if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return DIS_FAIL; } DE_INF("lcd %d\n", lcd->disp); mgr = lcd->manager; if ((NULL == mgr)) { DE_WRN("mgr is NULL!\n"); return DIS_FAIL; } if (0 == disp_lcd_is_enabled(lcd)) return 0; spin_lock_irqsave(&lcd_data_lock, flags); lcdp->enabled = 0; spin_unlock_irqrestore(&lcd_data_lock, flags); lcdp->bl_need_enabled = 0; lcdp->close_flow.func_num = 0; if (lcdp->lcd_panel_fun.cfg_close_flow) lcdp->lcd_panel_fun.cfg_close_flow(lcd->disp); else DE_WRN("lcd_panel_fun[%d].cfg_close_flow is NULL\n", lcd->disp); for (i = 0; i < lcdp->close_flow.func_num; i++) { if (lcdp->close_flow.func[i].func) { lcdp->close_flow.func[i].func(lcd->disp); DE_INF("close flow:step %d finish, to delay %d\n", i, lcdp->close_flow.func[i].delay); if (0 != lcdp->close_flow.func[i].delay) disp_delay_ms(lcdp->close_flow.func[i].delay); } } lcd_clk_disable(lcd); disp_lcd_gpio_exit(lcd); disp_sys_disable_irq(lcdp->irq_no); disp_sys_unregister_irq(lcdp->irq_no, disp_lcd_event_proc, (void *)lcd); return 0; } #else static s32 disp_lcd_disable(struct disp_device* lcd) { unsigned long flags; struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); struct disp_manager *mgr = NULL; int i; if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return DIS_FAIL; } DE_INF("lcd %d\n", lcd->disp); mgr = lcd->manager; if ((NULL == mgr)) { DE_WRN("mgr is NULL!\n"); return DIS_FAIL; } if (0 == disp_lcd_is_enabled(lcd)) return 0; spin_lock_irqsave(&lcd_data_lock, flags); lcdp->enabled = 0; spin_unlock_irqrestore(&lcd_data_lock, flags); lcdp->bl_need_enabled = 0; lcdp->close_flow.func_num = 0; if (lcdp->lcd_panel_fun.cfg_close_flow) { lcdp->lcd_panel_fun.cfg_close_flow(lcd->disp); } else { DE_WRN("lcd_panel_fun[%d].cfg_close_flow is NULL\n", lcd->disp); } for (i=0; iclose_flow.func_num; i++) { if (lcdp->close_flow.func[i].func) { lcdp->close_flow.func[i].func(lcd->disp); DE_INF("close flow:step %d finish, to delay %d\n", i, lcdp->close_flow.func[i].delay); if (0 != lcdp->close_flow.func[i].delay) disp_delay_ms(lcdp->close_flow.func[i].delay); } } disp_lcd_gpio_exit(lcd); lcd_clk_disable(lcd); if ((LCD_IF_DSI == lcdp->panel_info.lcd_if) && (0 != lcdp->irq_no_dsi)) { if (lcdp->panel_info.lcd_dsi_if == LCD_DSI_IF_COMMAND_MODE) { disp_sys_disable_irq(lcdp->irq_no); disp_sys_unregister_irq( lcdp->irq_no, disp_lcd_event_proc, (void *)lcd); } else { disp_sys_disable_irq(lcdp->irq_no_dsi); disp_sys_unregister_irq( lcdp->irq_no_dsi, disp_lcd_event_proc, (void *)lcd); } } else { disp_sys_disable_irq(lcdp->irq_no); disp_sys_unregister_irq(lcdp->irq_no, disp_lcd_event_proc,(void*)lcd); } /* disable fix power */ for (i=LCD_POWER_NUM -1; i>=0; i--) { if (1 == lcdp->lcd_cfg.lcd_fix_power_used[i]) { disp_sys_power_disable(lcdp->lcd_cfg.lcd_fix_power[i]); } } if (mgr->disable) mgr->disable(mgr); return 0; } #endif static s32 disp_lcd_sw_enable(struct disp_device* lcd) { unsigned long flags; struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); int i; struct disp_manager *mgr = NULL; disp_gpio_set_t gpio_info[1]; if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return DIS_FAIL; } mgr = lcd->manager; if ((NULL == mgr)) { DE_WRN("mgr is NULL!\n"); return DIS_FAIL; } if (mgr->sw_enable) mgr->sw_enable(mgr); /* init fix power */ for (i=0; ilcd_cfg.lcd_fix_power_used[i]) { disp_sys_power_enable(lcdp->lcd_cfg.lcd_fix_power[i]); } } /* init lcd power */ for (i=0; ilcd_cfg.lcd_power_used[i]) { disp_sys_power_enable(lcdp->lcd_cfg.lcd_power[i]); } } /* init gpio */ for (i = 0; i < LCD_GPIO_REGU_NUM; i++) { if (!((!strcmp(lcdp->lcd_cfg.lcd_gpio_power[i], "")) || (!strcmp(lcdp->lcd_cfg.lcd_gpio_power[i], "none")))) disp_sys_power_enable(lcdp->lcd_cfg.lcd_gpio_power[i]); } for (i=0; ilcd_cfg.gpio_hdl[i] = 0; if (lcdp->lcd_cfg.lcd_gpio_used[i]) { memcpy(gpio_info, &(lcdp->lcd_cfg.lcd_gpio[i]), sizeof(disp_gpio_set_t)); lcdp->lcd_cfg.gpio_hdl[i] = disp_sys_gpio_request_simple(gpio_info, 1); } } /* init lcd pin */ for (i=0; ilcd_cfg.lcd_pin_power[i], "")) || (!strcmp(lcdp->lcd_cfg.lcd_pin_power[i], "none")))) disp_sys_power_enable(lcdp->lcd_cfg.lcd_pin_power[i]); } /* init bl */ if (lcdp->lcd_cfg.lcd_bl_en_used) { //io-pad if (!((!strcmp(lcdp->lcd_cfg.lcd_bl_en_power, "")) || (!strcmp(lcdp->lcd_cfg.lcd_bl_en_power, "none")))) disp_sys_power_enable(lcdp->lcd_cfg.lcd_bl_en_power); } spin_lock_irqsave(&lcd_data_lock, flags); lcdp->enabled = 1; lcdp->enabling = 0; lcdp->bl_need_enabled = 1; spin_unlock_irqrestore(&lcd_data_lock, flags); lcd_calc_judge_line(lcd); disp_al_lcd_disable_irq(lcd->hwdev_index, LCD_IRQ_TCON0_VBLK, &lcdp->panel_info); #if defined(SUPPORT_DSI) && defined(DSI_VERSION_40) if ((LCD_IF_DSI == lcdp->panel_info.lcd_if) && (0 != lcdp->irq_no_dsi)) { if (lcdp->panel_info.lcd_dsi_if == LCD_DSI_IF_COMMAND_MODE) { disp_sys_register_irq(lcdp->irq_no, 0, disp_lcd_event_proc, (void *)lcd, 0, 0); disp_sys_enable_irq(lcdp->irq_no); } else { disp_sys_register_irq(lcdp->irq_no_dsi, 0, disp_lcd_event_proc, (void *)lcd, 0, 0); disp_sys_enable_irq(lcdp->irq_no_dsi); } } else #endif { disp_sys_register_irq(lcdp->irq_no,0,disp_lcd_event_proc,(void*)lcd,0,0); disp_sys_enable_irq(lcdp->irq_no); } disp_al_lcd_enable_irq(lcd->hwdev_index, LCD_IRQ_TCON0_VBLK, &lcdp->panel_info); return 0; } s32 disp_lcd_is_enabled(struct disp_device* lcd) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return DIS_FAIL; } return (s32)lcdp->enabled; } static s32 disp_lcd_set_open_func(struct disp_device* lcd, LCD_FUNC func, u32 delay) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return -1; } if (func) { lcdp->open_flow.func[lcdp->open_flow.func_num].func = func; lcdp->open_flow.func[lcdp->open_flow.func_num].delay = delay; lcdp->open_flow.func_num ++; } return DIS_SUCCESS; } static s32 disp_lcd_set_close_func(struct disp_device* lcd, LCD_FUNC func, u32 delay) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return -1; } if (func) { lcdp->close_flow.func[lcdp->close_flow.func_num].func = func; lcdp->close_flow.func[lcdp->close_flow.func_num].delay = delay; lcdp->close_flow.func_num ++; } return DIS_SUCCESS; } static disp_lcd_flow * disp_lcd_get_open_flow(struct disp_device* lcd) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); if((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return NULL; } lcdp->open_flow.func_num = 0; if (!disp_lcd_is_used(lcd)) goto exit; lcdp->open_flow.func[lcdp->open_flow.func_num].func = disp_lcd_pre_enable_ex; lcdp->open_flow.func[lcdp->open_flow.func_num].delay = 0; lcdp->open_flow.func_num ++; if(lcdp->lcd_panel_fun.cfg_open_flow) { lcdp->lcd_panel_fun.cfg_open_flow(lcd->disp); } else { DE_WRN("lcd_panel_fun[%d].cfg_open_flow is NULL\n", lcd->disp); } lcdp->open_flow.func[lcdp->open_flow.func_num].func = disp_lcd_post_enable_ex; lcdp->open_flow.func[lcdp->open_flow.func_num].delay = 0; lcdp->open_flow.func_num ++; exit: return &(lcdp->open_flow); } static disp_lcd_flow * disp_lcd_get_close_flow(struct disp_device* lcd) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); if((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return NULL; } lcdp->close_flow.func_num = 0; if (!disp_lcd_is_used(lcd)) goto exit; lcdp->close_flow.func[lcdp->close_flow.func_num].func = disp_lcd_pre_disable_ex; lcdp->close_flow.func[lcdp->close_flow.func_num].delay = 0; lcdp->close_flow.func_num ++; if(lcdp->lcd_panel_fun.cfg_close_flow) { lcdp->lcd_panel_fun.cfg_close_flow(lcd->disp); } else { DE_WRN("lcd_panel_fun[%d].cfg_close_flow is NULL\n", lcd->disp); } lcdp->close_flow.func[lcdp->close_flow.func_num].func = disp_lcd_post_disable_ex; lcdp->close_flow.func[lcdp->close_flow.func_num].delay = 0; lcdp->close_flow.func_num ++; exit: return &(lcdp->close_flow); } static s32 disp_lcd_set_panel_funs(struct disp_device* lcd, char *name, disp_lcd_panel_fun * lcd_cfg) { char primary_key[20], drv_name[32]; s32 ret; struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return DIS_FAIL; } sprintf(primary_key, "lcd%d", lcd->disp); ret = disp_sys_script_get_item(primary_key, "lcd_driver_name", (int*)drv_name, 2); DE_INF("lcd %d, driver_name %s, panel_name %s\n", lcd->disp, drv_name, name); if ((2==ret) && !strcmp(drv_name, name)) { memset(&lcdp->lcd_panel_fun, 0, sizeof(disp_lcd_panel_fun)); lcdp->lcd_panel_fun.cfg_panel_info= lcd_cfg->cfg_panel_info; lcdp->lcd_panel_fun.cfg_open_flow = lcd_cfg->cfg_open_flow; lcdp->lcd_panel_fun.cfg_close_flow = lcd_cfg->cfg_close_flow; lcdp->lcd_panel_fun.lcd_user_defined_func = lcd_cfg->lcd_user_defined_func; lcdp->lcd_panel_fun.set_bright = lcd_cfg->set_bright; return 0; } return -1; } s32 disp_lcd_gpio_init(struct disp_device* lcd) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); int i = 0; if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return DIS_FAIL; } //io-pad for (i = 0; i < LCD_GPIO_REGU_NUM; i++) { if (!((!strcmp(lcdp->lcd_cfg.lcd_gpio_power[i], "")) || (!strcmp(lcdp->lcd_cfg.lcd_gpio_power[i], "none")))) disp_sys_power_enable(lcdp->lcd_cfg.lcd_gpio_power[i]); } for (i=0; ilcd_cfg.gpio_hdl[i] = 0; if (lcdp->lcd_cfg.lcd_gpio_used[i]) { disp_gpio_set_t gpio_info[1]; memcpy(gpio_info, &(lcdp->lcd_cfg.lcd_gpio[i]), sizeof(disp_gpio_set_t)); lcdp->lcd_cfg.gpio_hdl[i] = disp_sys_gpio_request(gpio_info, 1); } } return 0; } s32 disp_lcd_gpio_exit(struct disp_device* lcd) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); int i = 0; if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return DIS_FAIL; } for (i=0; ilcd_cfg.gpio_hdl[i]) { disp_gpio_set_t gpio_info[1]; disp_sys_gpio_release(lcdp->lcd_cfg.gpio_hdl[i], 2); memcpy(gpio_info, &(lcdp->lcd_cfg.lcd_gpio[i]), sizeof(disp_gpio_set_t)); gpio_info->mul_sel = 7; lcdp->lcd_cfg.gpio_hdl[i] = disp_sys_gpio_request(gpio_info, 1); disp_sys_gpio_release(lcdp->lcd_cfg.gpio_hdl[i], 2); lcdp->lcd_cfg.gpio_hdl[i] = 0; } } //io-pad for (i = LCD_GPIO_REGU_NUM-1; i>=0; i--) { if (!((!strcmp(lcdp->lcd_cfg.lcd_gpio_power[i], "")) || (!strcmp(lcdp->lcd_cfg.lcd_gpio_power[i], "none")))) disp_sys_power_disable(lcdp->lcd_cfg.lcd_gpio_power[i]); } return 0; } //direction: input(0), output(1) s32 disp_lcd_gpio_set_direction(struct disp_device* lcd, u32 io_index, u32 direction) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); char gpio_name[20]; if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return DIS_FAIL; } sprintf(gpio_name, "lcd_gpio_%d", io_index); return disp_sys_gpio_set_direction(lcdp->lcd_cfg.gpio_hdl[io_index], direction, gpio_name); } s32 disp_lcd_gpio_get_value(struct disp_device* lcd,u32 io_index) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); char gpio_name[20]; if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return DIS_FAIL; } sprintf(gpio_name, "lcd_gpio_%d", io_index); return disp_sys_gpio_get_value(lcdp->lcd_cfg.gpio_hdl[io_index], gpio_name); } s32 disp_lcd_gpio_set_value(struct disp_device* lcd, u32 io_index, u32 data) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); char gpio_name[20]; if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return DIS_FAIL; } sprintf(gpio_name, "lcd_gpio_%d", io_index); return disp_sys_gpio_set_value(lcdp->lcd_cfg.gpio_hdl[io_index], data, gpio_name); } static s32 disp_lcd_get_dimensions(struct disp_device *lcd, u32 *width, u32 *height) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return DIS_FAIL; } *width = lcdp->panel_info.lcd_width; *height = lcdp->panel_info.lcd_height; return 0; } static s32 disp_lcd_get_status(struct disp_device *lcd) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return 0; } return disp_al_device_get_status(lcd->hwdev_index); } static s32 disp_lcd_set_gamma_tbl(struct disp_device *lcd, unsigned int *gamma_table, unsigned int size) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); int ret; if ((NULL == lcd) || (NULL == lcdp) || (NULL == gamma_table)) { DE_WRN("NULL hdl!\n"); return 0; } size = (size > LCD_GAMMA_TABLE_SIZE) ? LCD_GAMMA_TABLE_SIZE : size; memcpy(lcdp->panel_extend_info.lcd_gamma_tbl, gamma_table, size); if (lcdp->panel_extend_info.lcd_gamma_en == 1) ret = disp_al_lcd_cfg_ext(lcd->disp, &lcdp->panel_extend_info); else ret = 0; return ret; } static s32 disp_lcd_enable_gamma(struct disp_device *lcd) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); int ret; if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return 0; } if (lcdp->panel_extend_info.lcd_gamma_en == 0) { lcdp->panel_extend_info.lcd_gamma_en = 1; ret = disp_al_lcd_cfg_ext(lcd->disp, &lcdp->panel_extend_info); } else { ret = 0; } return ret; } static s32 disp_lcd_disable_gamma(struct disp_device *lcd) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); int ret; if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return 0; } if (lcdp->panel_extend_info.lcd_gamma_en == 1) { lcdp->panel_extend_info.lcd_gamma_en = 0; ret = disp_al_lcd_cfg_ext(lcd->disp, &lcdp->panel_extend_info); } else { ret = 0; } return ret; } static s32 disp_lcd_get_fps(struct disp_device *lcd) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return 0; } return lcdp->frame_per_sec; } static s32 disp_lcd_init(struct disp_device* lcd) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return DIS_FAIL; } DE_INF("lcd %d\n", lcd->disp); lcd_get_sys_config(lcd->disp, &lcdp->lcd_cfg); if (disp_lcd_is_used(lcd)) { struct disp_video_timings *timmings; disp_panel_para *panel_info; lcd_parse_panel_para(lcd->disp, &lcdp->panel_info); if (lcdp->panel_info.lcd_if == LCD_IF_DSI && lcdp->panel_info.lcd_tcon_mode == DISP_TCON_DUAL_DSI && lcdp->panel_info.lcd_dsi_port_num == DISP_LCD_DSI_SINGLE_PORT) { lcdp->panel_info.lcd_ht *= 2; lcdp->panel_info.lcd_hspw *= 2; lcdp->panel_info.lcd_x *= 2; lcdp->panel_info.lcd_hbp *= 2; lcdp->panel_info.lcd_dclk_freq *= 2; } timmings = &lcd->timings; panel_info = &lcdp->panel_info; timmings->pixel_clk = panel_info->lcd_dclk_freq * 1000; timmings->x_res = panel_info->lcd_x; timmings->y_res = panel_info->lcd_y; timmings->hor_total_time= panel_info->lcd_ht; timmings->hor_sync_time= panel_info->lcd_hspw; timmings->hor_back_porch= panel_info->lcd_hbp-panel_info->lcd_hspw; timmings->hor_front_porch= panel_info->lcd_ht-panel_info->lcd_hbp - panel_info->lcd_x; timmings->ver_total_time= panel_info->lcd_vt; timmings->ver_sync_time= panel_info->lcd_vspw; timmings->ver_back_porch= panel_info->lcd_vbp-panel_info->lcd_vspw; timmings->ver_front_porch= panel_info->lcd_vt-panel_info->lcd_vbp -panel_info->lcd_y; } disp_lcd_bright_curve_init(lcd); if (disp_lcd_is_used(lcd)) { __u64 backlight_bright; __u64 period_ns, duty_ns; if (lcdp->panel_info.lcd_pwm_used) { lcdp->pwm_info.channel = lcdp->panel_info.lcd_pwm_ch; lcdp->pwm_info.polarity = lcdp->panel_info.lcd_pwm_pol; lcdp->pwm_info.dev = disp_sys_pwm_request(lcdp->panel_info.lcd_pwm_ch); if (lcdp->panel_info.lcd_pwm_freq != 0) { period_ns = 1000*1000*1000 / lcdp->panel_info.lcd_pwm_freq; } else { DE_WRN("lcd%d.lcd_pwm_freq is ZERO\n", lcd->disp); period_ns = 1000*1000*1000 / 1000; //default 1khz } backlight_bright = lcdp->lcd_cfg.backlight_bright; duty_ns = (backlight_bright * period_ns) / 256; //DE_DBG("[PWM]backlight_bright=%d,period_ns=%d,duty_ns=%d\n",(u32)backlight_bright,(u32)period_ns, (u32)duty_ns); disp_sys_pwm_set_polarity(lcdp->pwm_info.dev, lcdp->pwm_info.polarity); disp_sys_pwm_config(lcdp->pwm_info.dev, duty_ns, period_ns); lcdp->pwm_info.duty_ns = duty_ns; lcdp->pwm_info.period_ns = period_ns; } lcd_clk_init(lcd); } //lcd_panel_parameter_check(lcd->disp, lcd); return 0; } static bool disp_lcd_check_config_dirty(struct disp_device *lcd, struct disp_device_config *config) { bool ret = false; struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); if ((lcd == NULL) || (lcdp == NULL)) { DE_WRN("NULL hdl!\n"); goto exit; } if (lcdp->enabled == 0) ret = true; exit: return ret; } static s32 disp_lcd_set_static_config(struct disp_device *lcd, struct disp_device_config *config) { return 0; } static s32 disp_lcd_get_static_config(struct disp_device *lcd, struct disp_device_config *config) { int ret = 0; struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); if ((lcd == NULL) || (lcdp == NULL)) { DE_WRN("NULL hdl!\n"); ret = -1; goto exit; } config->type = lcd->type; config->format = DISP_CSC_TYPE_RGB; exit: return ret; } #if defined(SUPPORT_EINK) && defined(CONFIG_EINK_PANEL_USED) void disp_close_eink_panel(struct disp_eink_manager *manager) { struct disp_device *plcd = NULL; plcd = disp_device_find(0, DISP_OUTPUT_TYPE_LCD); plcd->disable(plcd); __eink_clk_disable(manager); disp_mgr_clk_disable(manager->mgr); diplay_finish_flag = 1; return; } #endif static s32 disp_lcd_exit(struct disp_device* lcd) { struct disp_lcd_private_data *lcdp = disp_lcd_get_priv(lcd); if ((NULL == lcd) || (NULL == lcdp)) { DE_WRN("NULL hdl!\n"); return DIS_FAIL; } lcd_clk_exit(lcd); return 0; } s32 disp_init_lcd(disp_bsp_init_para * para) { u32 num_devices; u32 disp = 0; struct disp_device *lcd; struct disp_lcd_private_data *lcdp; u32 hwdev_index = 0; u32 num_devices_support_lcd = 0; #if defined(SUPPORT_DSI) u32 i = 0; #endif char primary_key[20], str[10] = {0}; __attribute__((unused)) int ret = 0, value = 1; #if defined(CONFIG_MACH_SUN8IW17) s32 use_dsi_flag = 0; #endif DE_INF("disp_init_lcd\n"); #if defined(__LINUX_PLAT__) spin_lock_init(&lcd_data_lock); #endif num_devices = bsp_disp_feat_get_num_devices(); for (hwdev_index=0; hwdev_indexpriv_data = (void*)lcdp; sprintf(lcd->name, "lcd%d", disp); lcd->disp = disp; #if defined(CONFIG_MACH_SUN8IW17) value = 0; ret = disp_sys_script_get_item(primary_key, "lcd_if", &value, 1); if (value == 4) { lcd->hwdev_index = 1; use_dsi_flag = 1; } else lcd->hwdev_index = (use_dsi_flag == 1) ? 0 : hwdev_index; #else lcd->hwdev_index = hwdev_index; #endif lcd->type = DISP_OUTPUT_TYPE_LCD; lcdp->irq_no = para->irq_no[DISP_MOD_LCD0 + lcd->hwdev_index]; lcdp->clk = para->mclk[DISP_MOD_LCD0 + lcd->hwdev_index]; #if DEVICE_LVDS_NUM == 1 lcdp->lvds_clk = para->mclk[DISP_MOD_LVDS]; #else lcdp->lvds_clk = para->mclk[DISP_MOD_LVDS + lcd->hwdev_index]; #endif #if defined(SUPPORT_DSI) lcdp->irq_no_dsi = para->irq_no[DISP_MOD_DSI0 + disp]; for (i = 0; i < CLK_DSI_NUM; ++i) lcdp->dsi_clk[i] = para->mclk[DISP_MOD_DSI0 + i]; DE_INF("total number of clk in dsi:%d\n", CLK_DSI_NUM); #endif DE_INF("lcd %d, irq_no=%d, irq_no_dsi=%d\n", disp, lcdp->irq_no, lcdp->irq_no_dsi); lcd->set_manager = disp_device_set_manager; lcd->unset_manager = disp_device_unset_manager; lcd->get_resolution = disp_device_get_resolution; lcd->get_timings = disp_device_get_timings; lcd->enable = disp_lcd_enable; lcd->sw_enable = disp_lcd_sw_enable; lcd->fake_enable = disp_lcd_fake_enable; lcd->disable = disp_lcd_disable; lcd->is_enabled = disp_lcd_is_enabled; lcd->set_bright = disp_lcd_set_bright; lcd->get_bright = disp_lcd_get_bright; lcd->set_bright_dimming = disp_lcd_set_bright_dimming; lcd->get_panel_info = disp_lcd_get_panel_info; lcd->set_static_config = disp_lcd_set_static_config; lcd->get_static_config = disp_lcd_get_static_config; lcd->check_config_dirty = disp_lcd_check_config_dirty; lcd->set_panel_func = disp_lcd_set_panel_funs; lcd->set_open_func = disp_lcd_set_open_func; lcd->set_close_func = disp_lcd_set_close_func; lcd->backlight_enable = disp_lcd_backlight_enable; lcd->backlight_disable = disp_lcd_backlight_disable; lcd->pwm_enable = disp_lcd_pwm_enable; lcd->pwm_disable = disp_lcd_pwm_disable; lcd->power_enable = disp_lcd_power_enable; lcd->power_disable = disp_lcd_power_disable; lcd->pin_cfg = disp_lcd_pin_cfg; lcd->tcon_enable = disp_lcd_tcon_enable; lcd->tcon_disable = disp_lcd_tcon_disable; lcd->get_open_flow = disp_lcd_get_open_flow; lcd->get_close_flow = disp_lcd_get_close_flow; lcd->gpio_set_value = disp_lcd_gpio_set_value; lcd->gpio_set_direction = disp_lcd_gpio_set_direction; lcd->get_dimensions = disp_lcd_get_dimensions; lcd->get_status = disp_lcd_get_status; lcd->set_gamma_tbl = disp_lcd_set_gamma_tbl; lcd->enable_gamma = disp_lcd_enable_gamma; lcd->disable_gamma = disp_lcd_disable_gamma; lcd->get_fps = disp_lcd_get_fps; lcd->show_builtin_patten = disp_device_show_builtin_patten; lcd->init = disp_lcd_init; lcd->exit = disp_lcd_exit; lcd->init(lcd); disp_device_register(lcd); disp ++; } return 0; }