/* * drivers/display/lcd/aml_lcd.c * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the named License, * or any later version. * * 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 #include #include #include #include #ifdef CONFIG_OF_LIBFDT #include #endif #include #include #ifdef CONFIG_AML_LCD_EXTERN #include #endif #include "aml_lcd_reg.h" #include "aml_lcd_common.h" #include "aml_lcd_clk_config.h" #ifdef CONFIG_AML_LCD_TABLET #include "lcd_tablet/mipi_dsi_util.h" #endif #include #define PANEL_NAME "panel" unsigned int lcd_debug_print_flag; unsigned int lcd_debug_test; static struct aml_lcd_drv_s aml_lcd_driver; static struct lcd_boot_ctrl_s boot_ctrl; static struct lcd_debug_ctrl_s debug_ctrl; static void lcd_update_boot_ctrl_bootargs(void); #define PANEL_PARAM_MEM_RSVD_SIZE (0x80000) #define PANEL_PARAM_KEY_NUM_MAX (64 - 1) #define PANEL_PARAM_KEY_SIZE (64) #define PANEL_PARAM_HEAD_SIZE PANEL_PARAM_KEY_SIZE #define PANEL_PARAM_KEY_NAME_SIZE (PANEL_PARAM_KEY_SIZE - 8) #define PANEL_PARAM_KEY_MEM_OFST (PANEL_PARAM_KEY_NUM_MAX * PANEL_PARAM_KEY_SIZE +\ PANEL_PARAM_HEAD_SIZE) struct panel_param_key_s { unsigned int size; unsigned int mem_pos; char name[PANEL_PARAM_KEY_NAME_SIZE]; }; struct panel_param_head_s { unsigned int _crc32; unsigned int size; unsigned short key_cnt; unsigned short ukey_exist; unsigned char rsvd[PANEL_PARAM_HEAD_SIZE - 12]; }; struct panel_param_mem_s { unsigned int key_mem_pos; struct panel_param_head_s *head; unsigned char *mem; unsigned char *key_mem; struct panel_param_key_s *keys; }; static struct panel_param_mem_s panel_param_mem = {0, NULL, NULL, NULL, NULL}; void mem_dump(unsigned char *addr, int size) { int i = 0, j = 0, len = 0; char buf[128]; for (j = 0; j < (size >> 4); j++) { for (i = 0, len = 0; i < 16; i++) len += sprintf(buf + len, "%02x ", (unsigned int)addr[j * 16 + i]); printf("0x%04x: %s\n", j * 16, buf); } if (size & 0xf) { for (i = 0, len = 0; i < (size & 0xf); i++) len += sprintf(buf + len, "%02x ", (unsigned int)addr[j * 16 + i]); printf("0x%04x: %s\n", j * 16, buf); } } void panel_param_mem_dump(const char *key_name) { int i = 0; struct panel_param_key_s *key; unsigned char *p; if (!panel_param_mem.mem || !panel_param_mem.head->key_cnt) return; if (!key_name) { printf("\npanel param dump: key_cnt:%d\n", panel_param_mem.head->key_cnt); for (i = 0; i < panel_param_mem.head->key_cnt; i++) { key = &panel_param_mem.keys[i]; p = panel_param_mem.key_mem + key->mem_pos; printf("[%02d]: size:0x%x, mem_ofst:0x%x, vaddr:0x%p, name:%s\n", i, key->size, key->mem_pos, p, key->name); } printf("\n"); return; } for (i = 0; i < panel_param_mem.head->key_cnt; i++) { key = &panel_param_mem.keys[i]; if (strcmp(key_name, key->name) == 0) { p = panel_param_mem.key_mem + key->mem_pos; printf("[%02d]: size:0x%x, mem_ofst:0x%x, vaddr:0x%p, name:%s\n", i, key->size, key->mem_pos, p, key->name); mem_dump(p, key->size); printf("\n"); } } } int is_panel_param_mem_ok(void) { return (panel_param_mem.mem && panel_param_mem.head->key_cnt) ? 1 : 0; } int is_ukey_in_param_mem(void) { return (panel_param_mem.head && panel_param_mem.head->ukey_exist) ? 1 : 0; } void panel_param_mem_set_ukey_flag(void) { panel_param_mem.head->ukey_exist = 1; } /*head(64byte)|keys(64 * N)......|key_mems......*/ int panel_param_mem_put(unsigned char *mem, const char *name, u32 len) { struct panel_param_key_s *key; if (!panel_param_mem.mem) { panel_param_mem.mem = (unsigned char *)malloc(PANEL_PARAM_MEM_RSVD_SIZE); if (panel_param_mem.mem) { memset(panel_param_mem.mem, 0, PANEL_PARAM_MEM_RSVD_SIZE); panel_param_mem.head = (struct panel_param_head_s *)panel_param_mem.mem; panel_param_mem.keys = (struct panel_param_key_s *)(panel_param_mem.mem + PANEL_PARAM_HEAD_SIZE); panel_param_mem.key_mem = (unsigned char *)(panel_param_mem.mem + PANEL_PARAM_KEY_MEM_OFST); panel_param_mem.head->size = PANEL_PARAM_KEY_MEM_OFST; panel_param_mem.key_mem_pos = 0; } else { printf("%s, no memory alloc\n", __func__); return -1; } } key = &panel_param_mem.keys[panel_param_mem.head->key_cnt]; key->size = len; key->mem_pos = panel_param_mem.key_mem_pos; if (key->mem_pos + key->size > PANEL_PARAM_MEM_RSVD_SIZE - PANEL_PARAM_KEY_MEM_OFST) { printf("%s, memory not enough\n", __func__); return -1; } strncpy(key->name, name, sizeof(key->name)); memcpy(panel_param_mem.key_mem + key->mem_pos, mem, len); panel_param_mem.key_mem_pos += len; panel_param_mem.key_mem_pos = ALIGN(panel_param_mem.key_mem_pos, 16); panel_param_mem.head->key_cnt++; panel_param_mem.head->size = panel_param_mem.key_mem_pos + PANEL_PARAM_KEY_MEM_OFST; return 0; } unsigned char *panel_param_mem_get(const char *name, u32 *len) { int i = 0; struct panel_param_key_s *key; if (!panel_param_mem.key_mem || !panel_param_mem.head->key_cnt) return NULL; for (i = 0; i < panel_param_mem.head->key_cnt; i++) { key = &panel_param_mem.keys[i]; if (strncmp(key->name, name, sizeof(key->name)) == 0) { *len = key->size; return panel_param_mem.key_mem + key->mem_pos; } } return NULL; } int panel_param_mem_modify(unsigned char *mem, const char *name, u32 len) { struct panel_param_key_s *key; unsigned int _crc32; int ret = 0, i = 0; if (!mem || !panel_param_mem.mem || !panel_param_mem.head->key_cnt) return -1; for (i = 0; i < panel_param_mem.head->key_cnt; i++) { key = &panel_param_mem.keys[i]; if (strncmp(key->name, name, sizeof(key->name)) == 0) { if (len <= key->size) { memset(panel_param_mem.key_mem + key->mem_pos, 0, key->size); memcpy(panel_param_mem.key_mem + key->mem_pos, mem, len); key->size = len; } else { //once for all, we don't care about this memory memset(panel_param_mem.key_mem + key->mem_pos, 0, key->size); memset(key, 0, PANEL_PARAM_KEY_SIZE); ret = panel_param_mem_put(mem, name, len); } if (ret == 0) { _crc32 = CalCRC32(0, panel_param_mem.mem + 4, panel_param_mem.head->size - 4); panel_param_mem.head->_crc32 = _crc32; } return ret; } } ret = panel_param_mem_put(mem, name, len); if (ret == 0) { _crc32 = CalCRC32(0, panel_param_mem.mem + 4, panel_param_mem.head->size - 4); panel_param_mem.head->_crc32 = _crc32; } return ret; } static void panel_param_mem_update_to_lrm(void) { unsigned int size = 0, key_size = 0, key_mem_size = 0; phys_addr_t paddr; unsigned char *panel_rsvd; struct panel_param_head_s { unsigned int _crc32, size; unsigned short key_cnt, ukey_exist; unsigned char rsvd[PANEL_PARAM_HEAD_SIZE - 12]; } *head; if (!panel_param_mem.mem || !panel_param_mem.head->key_cnt) return; head = (struct panel_param_head_s *)panel_param_mem.mem; if (!head->key_cnt) { LCDPR("error panel_param header\n"); return; } key_size = head->key_cnt * PANEL_PARAM_KEY_SIZE + PANEL_PARAM_HEAD_SIZE; key_mem_size = head->size - PANEL_PARAM_KEY_MEM_OFST; size = key_size + key_mem_size; panel_rsvd = (unsigned char *)lrm_alloc_tail(size, &paddr, "panel_config"); if (!panel_rsvd) { LCDPR("no rsvd mem to save panel_config\n"); return; } memcpy(panel_rsvd, panel_param_mem.mem, key_size); memcpy(panel_rsvd + key_size, panel_param_mem.mem + PANEL_PARAM_KEY_MEM_OFST, key_mem_size); head = (struct panel_param_head_s *)panel_rsvd; head->size = size; head->_crc32 = CalCRC32(0, panel_rsvd + 4, size - 4); if (lcd_debug_print_flag) { LCDPR("%s, paddr:0x%llx crc:0x%x, size:%d, key_cnt:%d, ukey_exist:%d\n", __func__, (u64)paddr, head->_crc32, head->size, head->key_cnt, head->ukey_exist); } } void update_panel_param_to_kernel(void) { u64 pa; u32 size; if (!lrm_exist()) return; if (lrm_get_by_name("panel_config", &pa, &size)) { panel_param_mem_update_to_lrm(); //new return; } //exist lrm_phys_free(pa); panel_param_mem_update_to_lrm(); } void lcd_panel_param_test(char *name) { struct panel_param_mem_s local_param_mem; unsigned char *mem, *p; u64 pa; unsigned int size, _crc32; struct panel_param_head_s *head; struct panel_param_key_s *key; int i; if (lrm_get_by_name("panel_config", &pa, &size)) { LCDERR("panel_config get fail\n"); return; } mem = lrm_phys_to_virt(pa, size); if (!mem) { LCDERR("panel_config get fail\n"); return; } head = (struct panel_param_head_s *)mem; _crc32 = CalCRC32(0, mem + 4, head->size - 4); if (_crc32 != head->_crc32) { LCDERR("panel_config crc check fail:cal:0x%x-ori:0x%x\n", _crc32, head->_crc32); return; } local_param_mem.mem = mem; local_param_mem.head = (struct panel_param_head_s *)mem; local_param_mem.keys = (struct panel_param_key_s *)(local_param_mem.mem + PANEL_PARAM_HEAD_SIZE); head = local_param_mem.head; size = head->key_cnt * PANEL_PARAM_KEY_SIZE + PANEL_PARAM_HEAD_SIZE; local_param_mem.key_mem = local_param_mem.mem + size; if (!name) { LCDPR("local_param_mem: paddr:0x%llx, size:0x%x, key_cnt:%d, ukey_exist:%d\n", pa, head->size, head->key_cnt, head->ukey_exist); for (i = 0; i < head->key_cnt; i++) { key = &local_param_mem.keys[i]; p = local_param_mem.key_mem + key->mem_pos; printf("[%02d]: size:0x%x, mem_ofst:0x%x, vaddr:0x%p, name:%s\n", i, key->size, key->mem_pos, p, key->name); } printf("\n"); return; } for (i = 0; i < head->key_cnt; i++) { key = &local_param_mem.keys[i]; if (strcmp(name, key->name)) continue; p = local_param_mem.key_mem + key->mem_pos; printf("[%02d]: size:0x%x, mem_ofst:0x%x, vaddr:0x%p, name:%s\n", i, key->size, key->mem_pos, p, key->name); mem_dump(p, key->size); printf("\n"); } } int save_panel_file_to_param(void) { char *file_name, *p; unsigned char *buf; int size, ret = -1; if (!lrm_exist()) return -1; file_name = getenv("model_panel"); if (!file_name) { LCDPR("%s, warn: model_panel path fail!\n", __func__); return -1; } buf = model_read_file_to_buffer(file_name, &size); if (!buf) return -1; p = strrchr(file_name, '.'); if (p && (!strncmp(p + 1, "ini", 3) || !strncmp(p + 1, "INI", 3))) ret = panel_param_mem_put(buf, "panel0_ini_file", size); free(buf); return ret; } static void lcd_chip_detect(void) { #if 1 unsigned int cpu_type; unsigned int rev_type; cpu_type = get_cpu_id().family_id; rev_type = get_cpu_id().chip_rev; switch (cpu_type) { case MESON_CPU_MAJOR_ID_GXTVBB: aml_lcd_driver.chip_type = LCD_CHIP_GXTVBB; break; case MESON_CPU_MAJOR_ID_GXL: aml_lcd_driver.chip_type = LCD_CHIP_GXL; break; case MESON_CPU_MAJOR_ID_GXM: aml_lcd_driver.chip_type = LCD_CHIP_GXM; break; case MESON_CPU_MAJOR_ID_TXL: aml_lcd_driver.chip_type = LCD_CHIP_TXL; break; case MESON_CPU_MAJOR_ID_TXLX: aml_lcd_driver.chip_type = LCD_CHIP_TXLX; break; case MESON_CPU_MAJOR_ID_AXG: aml_lcd_driver.chip_type = LCD_CHIP_AXG; break; case MESON_CPU_MAJOR_ID_TXHD: aml_lcd_driver.chip_type = LCD_CHIP_TXHD; break; case MESON_CPU_MAJOR_ID_G12A: aml_lcd_driver.chip_type = LCD_CHIP_G12A; break; case MESON_CPU_MAJOR_ID_G12B: aml_lcd_driver.chip_type = LCD_CHIP_G12B; break; case MESON_CPU_MAJOR_ID_TL1: aml_lcd_driver.chip_type = LCD_CHIP_TL1; aml_lcd_driver.rev_type = rev_type; break; case MESON_CPU_MAJOR_ID_SM1: aml_lcd_driver.chip_type = LCD_CHIP_SM1; break; case MESON_CPU_MAJOR_ID_TM2: aml_lcd_driver.chip_type = LCD_CHIP_TM2; aml_lcd_driver.rev_type = rev_type; break; case MESON_CPU_MAJOR_ID_T5: aml_lcd_driver.chip_type = LCD_CHIP_T5; aml_lcd_driver.rev_type = rev_type; break; case MESON_CPU_MAJOR_ID_T5D: aml_lcd_driver.chip_type = LCD_CHIP_T5D; aml_lcd_driver.rev_type = rev_type; break; case MESON_CPU_MAJOR_ID_T5W: aml_lcd_driver.chip_type = LCD_CHIP_T5W; aml_lcd_driver.rev_type = rev_type; break; default: aml_lcd_driver.chip_type = LCD_CHIP_T5W; //aml_lcd_driver.chip_type = LCD_CHIP_MAX; break; } #else aml_lcd_driver.chip_type = LCD_CHIP_TM2; #endif lcd_pinmux_probe(aml_lcd_driver.chip_type); if (lcd_debug_print_flag) LCDPR("check chip: %d\n", aml_lcd_driver.chip_type); } static int lcd_check_valid(void) { if (aml_lcd_driver.probe_done == 0) { LCDERR("invalid lcd config\n"); return -1; } return 0; } static void lcd_power_ctrl(int status) { struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver(); struct lcd_power_ctrl_s *lcd_power; struct lcd_power_step_s *power_step; char *str; unsigned int i, wait, gpio, delay; int value = LCD_PMU_GPIO_NUM_MAX; #ifdef CONFIG_AML_LCD_EXTERN struct aml_lcd_extern_driver_s *ext_drv; #endif i = 0; lcd_power = lcd_drv->lcd_config->lcd_power; if (status) { /* check if factory test */ if (lcd_drv->factory_lcd_power_on_step) { LCDPR("%s: factory test power_on_step!\n", __func__); power_step = lcd_drv->factory_lcd_power_on_step; } else { power_step = &lcd_power->power_on_step[0]; } } else { power_step = &lcd_power->power_off_step[0]; } while (i < LCD_PWR_STEP_MAX) { if (power_step->type >= LCD_POWER_TYPE_MAX) break; if (lcd_debug_print_flag) { LCDPR("power_ctrl: %d, step %d: type=%d, index=%d, value=%d, delay=%d\n", status, i, power_step->type, power_step->index, power_step->value, power_step->delay); } delay = power_step[i].delay; switch (power_step->type) { case LCD_POWER_TYPE_CPU: if (power_step->index < LCD_CPU_GPIO_NUM_MAX) { str = lcd_power->cpu_gpio[power_step->index]; gpio = aml_lcd_gpio_name_map_num(str); aml_lcd_gpio_set(gpio, power_step->value); } else { LCDERR("cpu_gpio index: %d\n", power_step->index); } break; case LCD_POWER_TYPE_SIGNAL: if (status) lcd_drv->driver_init(); else lcd_drv->driver_disable(); break; #ifdef CONFIG_AML_LCD_EXTERN case LCD_POWER_TYPE_EXTERN: ext_drv = aml_lcd_extern_get_driver(power_step->index); if (ext_drv) { if (status) { if (ext_drv->power_on) ext_drv->power_on(); else LCDERR("no ext power on\n"); } else { if (ext_drv->power_off) ext_drv->power_off(); else LCDERR("no ext power off\n"); } if (ext_drv->exit_break) return; } break; #endif case LCD_POWER_TYPE_WAIT_GPIO: delay = 0; if (power_step->index < LCD_CPU_GPIO_NUM_MAX) { str = lcd_power->cpu_gpio[power_step->index]; gpio = aml_lcd_gpio_name_map_num(str); aml_lcd_gpio_set(gpio, LCD_GPIO_INPUT); } else { LCDERR( "wait_gpio index: %d\n", power_step->index); break; } LCDPR("lcd_power_type_wait_gpio wait\n"); for (wait = 0; wait < power_step->delay; wait++) { value = aml_lcd_gpio_input_get(gpio); if (value == power_step->value) { LCDPR( "get value: %d, wait ok\n", value); break; } mdelay(1); } if (wait == power_step->delay) LCDERR( "get value: %d, wait timeout!\n", value); break; case LCD_POWER_TYPE_CLK_SS: delay = 0; break; #ifdef CONFIG_AML_LCD_TCON case LCD_POWER_TYPE_TCON_SPI_DATA_LOAD: if (lcd_drv->lcd_tcon_spi_data_load) lcd_drv->lcd_tcon_spi_data_load(); break; #endif case LCD_POWER_TYPE_OFF_DELAY: break; default: break; } if (delay > 0) mdelay(delay); i++; power_step++; } if (lcd_debug_print_flag) LCDPR("%s: %d\n", __func__, status); } static void lcd_gamma_init(void) { lcd_wait_vsync(); vpp_disable_lcd_gamma_table(); vpp_init_lcd_gamma_table(); lcd_wait_vsync(); vpp_enable_lcd_gamma_table(); } static void lcd_encl_on(void) { struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver(); int ret; if (lcd_drv->config_check_en == 0) { if (lcd_debug_print_flag) LCDPR("config_check disabled\n"); } else { ret = lcd_config_timing_check(&lcd_drv->lcd_config->lcd_timing.act_timing); if (ret & 0x55) { LCDERR("%s: config timing check fatal error!\n", __func__); return; } } lcd_drv->driver_init_pre(); if (lcd_debug_test) aml_lcd_debug_test(lcd_debug_test); lcd_gamma_init(); lcd_vcbus_write(VENC_INTCTRL, 0x200); lcd_drv->lcd_status |= LCD_STATUS_ENCL_ON; } static void lcd_interface_on(void) { struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver(); struct lcd_config_s *pconf = lcd_drv->lcd_config; lcd_power_ctrl(1); pconf->retry_enable_cnt = 0; while (pconf->retry_enable_flag) { if (pconf->retry_enable_cnt++ >= LCD_ENABLE_RETRY_MAX) break; LCDPR("retry enable...%d\n", pconf->retry_enable_cnt); lcd_power_ctrl(0); mdelay(1000); lcd_power_ctrl(1); } pconf->retry_enable_cnt = 0; lcd_drv->lcd_status |= LCD_STATUS_IF_ON; } static void lcd_module_enable(char *mode, unsigned int frac) { unsigned int sync_duration; struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver(); struct lcd_config_s *pconf = lcd_drv->lcd_config; int ret; if (!mode) return; ret = lcd_drv->config_valid(mode); if (ret) { LCDERR("init exit\n"); return; } sync_duration = pconf->lcd_timing.act_timing.sync_duration_num; sync_duration = (sync_duration * 100 / pconf->lcd_timing.act_timing.sync_duration_den); LCDPR("enable: %s, %s, %ux%u@%u.%2uHz\n", pconf->lcd_basic.model_name, lcd_type_type_to_str(pconf->lcd_basic.lcd_type), pconf->lcd_timing.act_timing.h_active, pconf->lcd_timing.act_timing.v_active, (sync_duration / 100), (sync_duration % 100)); if ((lcd_drv->lcd_status & LCD_STATUS_ENCL_ON) == 0) lcd_encl_on(); if ((lcd_drv->lcd_status & LCD_STATUS_ENCL_ON) == 0) { LCDERR("%s: encl_on failed!\n", __func__); return; } if ((lcd_drv->lcd_status & LCD_STATUS_IF_ON) == 0) { if (boot_ctrl.init_level == LCD_INIT_LEVEL_NORMAL) { lcd_interface_on(); aml_bl_lcd_on_ctrl(); } else { LCDPR("bypass interface for init_level %d\n", boot_ctrl.init_level); } } lcd_update_boot_ctrl_bootargs(); } static void lcd_module_disable(void) { struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver(); LCDPR("disable: %s\n", lcd_drv->lcd_config->lcd_basic.model_name); if (lcd_drv->lcd_status & LCD_STATUS_IF_ON) { aml_bl_lcd_off_ctrl(); lcd_power_ctrl(0); } lcd_vcbus_write(ENCL_VIDEO_EN, 0); lcd_clk_disable(); lcd_drv->lcd_status = 0; } static void lcd_module_prepare(char *mode, unsigned int frac) { struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver(); int ret; if (!mode) return; ret = lcd_drv->config_valid(mode); if (ret) { LCDERR("prepare exit\n"); return; } if ((lcd_drv->lcd_status & LCD_STATUS_ENCL_ON) == 0) lcd_encl_on(); lcd_update_boot_ctrl_bootargs(); } static void lcd_vbyone_filter_flag_print(struct lcd_config_s *pconf) { struct vbyone_config_s *vx1_conf = pconf->lcd_control.vbyone_config; switch (aml_lcd_driver.chip_type) { case LCD_CHIP_TXL: case LCD_CHIP_TXLX: LCDPR("vx1_sw_filter_en: %d\n", vx1_conf->vx1_sw_filter_en); LCDPR("vx1_sw_filter_time: %d\n", vx1_conf->vx1_sw_filter_time); LCDPR("vx1_sw_filter_cnt: %d\n", vx1_conf->vx1_sw_filter_cnt); LCDPR("vx1_sw_filter_retry_cnt: %d\n", vx1_conf->vx1_sw_filter_retry_cnt); LCDPR("vx1_sw_filter_retry_delay: %d\n", vx1_conf->vx1_sw_filter_retry_delay); LCDPR("vx1_sw_cdr_detect_time: %d\n", vx1_conf->vx1_sw_cdr_detect_time); LCDPR("vx1_sw_cdr_detect_cnt: %d\n", vx1_conf->vx1_sw_cdr_detect_cnt); LCDPR("vx1_sw_cdr_timeout_cnt: %d\n", vx1_conf->vx1_sw_cdr_timeout_cnt); break; default: break; } } static void lcd_vbyone_filter_env_init(struct lcd_config_s *pconf) { struct vbyone_config_s *vx1_conf = pconf->lcd_control.vbyone_config; unsigned int temp = 0; temp = getenv_ulong("lcd_debug_vx1_sw_filter", 10, 0); if (!temp) return; LCDPR("%s\n", __func__); temp = getenv_ulong("vx1_sw_filter_en", 10, 0xffff); if (temp != 0xffff) { vx1_conf->vx1_sw_filter_en = temp; LCDPR("vx1_sw_filter_en: %d\n", vx1_conf->vx1_sw_filter_en); } /* 100us */ temp = getenv_ulong("vx1_sw_filter_time", 10, 0xffff); if (temp != 0xffff) { vx1_conf->vx1_sw_filter_time = temp; LCDPR("vx1_sw_filter_time: %d\n", vx1_conf->vx1_sw_filter_time); } temp = getenv_ulong("vx1_sw_filter_cnt", 10, 0xffff); if (temp != 0xffff) { vx1_conf->vx1_sw_filter_cnt = temp; LCDPR("vx1_sw_filter_cnt: %d\n", vx1_conf->vx1_sw_filter_cnt); } temp = getenv_ulong("vx1_sw_filter_retry_cnt", 10, 0xffff); if (temp != 0xffff) { vx1_conf->vx1_sw_filter_cnt = temp; LCDPR("vx1_sw_filter_retry_cnt: %d\n", vx1_conf->vx1_sw_filter_retry_cnt); } /* ms */ temp = getenv_ulong("vx1_sw_filter_retry_delay", 10, 0xffff); if (temp != 0xffff) { vx1_conf->vx1_sw_filter_retry_delay = temp; LCDPR("vx1_sw_filter_retry_delay: %d\n", vx1_conf->vx1_sw_filter_retry_delay); } /* us * 100 */ temp = getenv_ulong("vx1_sw_cdr_detect_time", 10, 0xffff); if (temp != 0xffff) { vx1_conf->vx1_sw_filter_cnt = temp; LCDPR("vx1_sw_cdr_detect_time: %d\n", vx1_conf->vx1_sw_cdr_detect_time); } temp = getenv_ulong("vx1_sw_cdr_detect_cnt", 10, 0xffff); if (temp != 0xffff) { vx1_conf->vx1_sw_cdr_detect_cnt = temp; LCDPR("vx1_sw_cdr_detect_cnt: %d\n", vx1_conf->vx1_sw_cdr_detect_cnt); } temp = getenv_ulong("vx1_sw_cdr_timeout_cnt", 10, 0xffff); if (temp != 0xffff) { vx1_conf->vx1_sw_cdr_timeout_cnt = temp; LCDPR("vx1_sw_cdr_timeout_cnt: %d\n", vx1_conf->vx1_sw_cdr_timeout_cnt); } } #ifdef CONFIG_AML_LCD_EXTERN static int lcd_extern_load_config(char *dt_addr, struct lcd_config_s *pconf) { struct lcd_power_step_s *power_step; int index, i = 0; aml_lcd_extern_init(); /* mipi extern_init is special */ if (pconf->lcd_basic.lcd_type == LCD_MIPI) { index = pconf->lcd_control.mipi_config->extern_init; if (index < LCD_EXTERN_INDEX_INVALID) aml_lcd_extern_probe(dt_addr, index); } while (i < LCD_PWR_STEP_MAX) { power_step = &pconf->lcd_power->power_on_step[i]; if (power_step->type >= LCD_POWER_TYPE_MAX) break; if (power_step->type == LCD_POWER_TYPE_EXTERN) { if (lcd_debug_print_flag) { LCDPR("power_on: step %d: type=%d, index=%d\n", i, power_step->type, power_step->index); } index = power_step->index; if (index < LCD_EXTERN_INDEX_INVALID) aml_lcd_extern_probe(dt_addr, index); } i++; } return 0; } #endif #ifdef CONFIG_OF_LIBFDT static int lcd_init_load_from_dts(char *dt_addr) { struct lcd_config_s *pconf = aml_lcd_driver.lcd_config; int parent_offset; char *propdata, *p; const char *str; int i, j, temp; if (!dt_addr) { LCDERR("%s: dt_addr is null\n", __func__); return -1; } /* check bl_key_valid */ parent_offset = fdt_path_offset(dt_addr, "/backlight"); if (parent_offset < 0) { LCDERR("not find /backlight node: %s\n", fdt_strerror(parent_offset)); aml_lcd_driver.bl_config->bl_key_valid = 0; } propdata = (char *)fdt_getprop(dt_addr, parent_offset, "key_valid", NULL); if (propdata == NULL) { LCDERR("failed to get key_valid\n"); aml_lcd_driver.bl_config->bl_key_valid = 0; } else { aml_lcd_driver.bl_config->bl_key_valid = (unsigned char)(be32_to_cpup((u32*)propdata)); } parent_offset = fdt_path_offset(dt_addr, "/lcd"); if (parent_offset < 0) { LCDERR("not find /lcd node: %s\n", fdt_strerror(parent_offset)); return -1; } /* check lcd_mode & lcd_key_valid */ propdata = (char *)fdt_getprop(dt_addr, parent_offset, "mode", NULL); if (propdata == NULL) { LCDERR("failed to get mode\n"); return -1; } else { pconf->lcd_mode = lcd_mode_str_to_mode(propdata); } str = propdata; propdata = (char *)fdt_getprop(dt_addr, parent_offset, "key_valid", NULL); if (propdata == NULL) { LCDERR("failed to get key_valid\n"); pconf->lcd_key_valid = 0; } else { pconf->lcd_key_valid = (unsigned char)(be32_to_cpup((u32*)propdata)); } LCDPR("detect mode: %s, key_valid: %d\n", str, pconf->lcd_key_valid); /* check lcd_clk_path */ propdata = (char *)fdt_getprop(dt_addr, parent_offset, "clk_path", NULL); if (propdata == NULL) { if (lcd_debug_print_flag) LCDPR("failed to get clk_path\n"); pconf->lcd_clk_path = 0; } else { pconf->lcd_clk_path = (unsigned char)(be32_to_cpup((u32*)propdata)); LCDPR("detect lcd_clk_path: %d\n", pconf->lcd_clk_path); } temp = getenv_ulong("lcd_clk_path", 10, 0xffff); if (temp != 0xffff) { if (temp) pconf->lcd_clk_path = 1; else pconf->lcd_clk_path = 0; LCDPR("lcd_clk_path flag set clk_path: %d\n", pconf->lcd_clk_path); } i = 0; propdata = (char *)fdt_getprop(dt_addr, parent_offset, "lcd_cpu_gpio_names", NULL); if (propdata == NULL) { LCDPR("failed to get lcd_cpu_gpio_names\n"); } else { p = propdata; while (i < LCD_CPU_GPIO_NUM_MAX) { str = p; if (strlen(str) == 0) break; strcpy(pconf->lcd_power->cpu_gpio[i], str); if (lcd_debug_print_flag) { LCDPR("i=%d, gpio=%s\n", i, pconf->lcd_power->cpu_gpio[i]); } p += strlen(p) + 1; i++; } } for (j = i; j < LCD_CPU_GPIO_NUM_MAX; j++) strcpy(pconf->lcd_power->cpu_gpio[j], "invalid"); propdata = (char *)fdt_getprop(dt_addr, parent_offset, "config_check_glb", NULL); if (!propdata) { aml_lcd_driver.config_check_glb = 0; } else { aml_lcd_driver.config_check_glb = be32_to_cpup((u32 *)propdata); if (lcd_debug_print_flag) { LCDPR("find config_check_glb: %d\n", aml_lcd_driver.config_check_glb); } } propdata = (char *)fdt_getprop(dt_addr, parent_offset, "display_timing_req_min", NULL); if (!propdata) { aml_lcd_driver.disp_req.alert_level = 0; aml_lcd_driver.disp_req.hswbp_vid = 0; aml_lcd_driver.disp_req.hfp_vid = 0; aml_lcd_driver.disp_req.vswbp_vid = 0; aml_lcd_driver.disp_req.vfp_vid = 0; } else { aml_lcd_driver.disp_req.alert_level = be32_to_cpup((u32 *)propdata); aml_lcd_driver.disp_req.hswbp_vid = be32_to_cpup((((u32 *)propdata) + 1)); aml_lcd_driver.disp_req.hfp_vid = be32_to_cpup((((u32 *)propdata) + 2)); aml_lcd_driver.disp_req.vswbp_vid = be32_to_cpup((((u32 *)propdata) + 3)); aml_lcd_driver.disp_req.vfp_vid = be32_to_cpup((((u32 *)propdata) + 4)); if (lcd_debug_print_flag) { LCDPR("find display_timing_req_min: alert_level:%d\n" "hswbp:%d, hfp:%d, vswbp:%d, vfp:%d\n", aml_lcd_driver.disp_req.alert_level, aml_lcd_driver.disp_req.hswbp_vid, aml_lcd_driver.disp_req.hfp_vid, aml_lcd_driver.disp_req.vswbp_vid, aml_lcd_driver.disp_req.vfp_vid); } } return 0; } #endif static int lcd_init_load_from_bsp(void) { struct lcd_config_s *pconf = aml_lcd_driver.lcd_config; int i, j, temp; /*pconf->lcd_key_valid = 0; aml_lcd_driver.bl_config->bl_key_valid = 0;*/ LCDPR("detect mode: %s, key_valid: %d\n", lcd_mode_mode_to_str(pconf->lcd_mode), pconf->lcd_key_valid); i = 0; while (i < LCD_CPU_GPIO_NUM_MAX) { if (strcmp(pconf->lcd_power->cpu_gpio[i], "invalid") == 0) break; i++; } for (j = i; j < LCD_CPU_GPIO_NUM_MAX; j++) { strcpy(pconf->lcd_power->cpu_gpio[j], "invalid"); } temp = getenv_ulong("lcd_clk_path", 10, 0); if (temp) pconf->lcd_clk_path = 1; else pconf->lcd_clk_path = 0; LCDPR("lcd_clk_path flag set clk_path: %d\n", pconf->lcd_clk_path); return 0; } static int lcd_config_load_id_check(char *dt_addr) { int load_id = 0, ret; #ifdef CONFIG_OF_LIBFDT int parent_offset; if (dt_addr) { if (fdt_check_header(dt_addr) < 0) { LCDERR("check dts: %s, load default lcd parameters\n", fdt_strerror(fdt_check_header(dt_addr))); } else { parent_offset = fdt_path_offset(dt_addr, "/lcd"); if (parent_offset < 0) { LCDERR("not find /lcd node: %s\n", fdt_strerror(parent_offset)); load_id = 0x0; } else { load_id = 0x1; } } } else { load_id = 0x0; } #endif switch (debug_ctrl.debug_para_source) { case 1: LCDPR("lcd_debug_para: 1,dts\n"); load_id = 0x1; break; case 2: LCDPR("lcd_debug_para: 2,unifykey\n"); break; case 3: LCDPR("lcd_debug_para: 3,bsp\n"); load_id = 0x0; break; default: break; } if (load_id & 0x1) { #ifdef CONFIG_OF_LIBFDT ret = lcd_init_load_from_dts(dt_addr); if (ret) return -1; #endif } else { ret = lcd_init_load_from_bsp(); if (ret) return -1; } if (debug_ctrl.debug_para_source == 1) { aml_lcd_driver.bl_config->bl_key_valid = 0; aml_lcd_driver.lcd_config->lcd_key_valid = 0; } else if (debug_ctrl.debug_para_source == 2) { aml_lcd_driver.bl_config->bl_key_valid = 1; aml_lcd_driver.lcd_config->lcd_key_valid = 1; } if (aml_lcd_driver.unifykey_test_flag) { aml_lcd_driver.bl_config->bl_key_valid = 1; aml_lcd_driver.lcd_config->lcd_key_valid = 1; LCDPR("force bl_key_valid & lcd_key_valid to 1\n"); } if (aml_lcd_driver.lcd_config->lcd_key_valid) { ret = aml_lcd_unifykey_check("lcd"); if (ret == 0) { LCDPR("load lcd_config from unifykey\n"); load_id |= 0x10; return load_id; } } if (load_id & 0x1) LCDPR("load config from dts\n"); else LCDPR("load config from bsp\n"); return load_id; } static int lcd_mode_probe(char *dt_addr, int load_id) { int dbg_chk, ret = 0; switch (debug_ctrl.debug_lcd_mode) { case 1: LCDPR("lcd_debug_mode: 1,tv\n"); aml_lcd_driver.lcd_config->lcd_mode = LCD_MODE_TV; break; case 2: LCDPR("lcd_debug_mode: 2,tablet\n"); aml_lcd_driver.lcd_config->lcd_mode = LCD_MODE_TABLET; break; default: break; } /* load lcd config */ switch (aml_lcd_driver.lcd_config->lcd_mode) { case LCD_MODE_TV: #ifdef CONFIG_AML_LCD_TV ret = get_lcd_tv_config(dt_addr, load_id); #endif break; case LCD_MODE_TABLET: #ifdef CONFIG_AML_LCD_TABLET ret = get_lcd_tablet_config(dt_addr, load_id); #endif break; default: ret = -1; LCDERR("invalid lcd mode: %d\n", aml_lcd_driver.lcd_config->lcd_mode); break; } if (ret) { aml_lcd_driver.probe_done = 0; LCDERR("invalid lcd config\n"); return -1; } if (aml_lcd_driver.lcd_config->lcd_basic.lcd_type == LCD_VBYONE) lcd_vbyone_filter_env_init(aml_lcd_driver.lcd_config); #ifdef CONFIG_AML_LCD_TCON lcd_tcon_probe(dt_addr, &aml_lcd_driver, load_id); #endif dbg_chk = getenv_ulong("lcd_debug_check", 10, 0xff); if (dbg_chk == 0xff) { if (aml_lcd_driver.lcd_config->lcd_basic.config_check & 0x2) { aml_lcd_driver.config_check_en = aml_lcd_driver.lcd_config->lcd_basic.config_check & 0x1; } else { aml_lcd_driver.config_check_en = aml_lcd_driver.config_check_glb; } } else { LCDPR("lcd_debug_check: %d\n", dbg_chk); aml_lcd_driver.config_check_en = dbg_chk; } #ifdef CONFIG_AML_LCD_EXTERN lcd_extern_load_config(dt_addr, aml_lcd_driver.lcd_config); #endif /* load bl config */ if (aml_lcd_driver.bl_config->bl_key_valid) { ret = aml_lcd_unifykey_check("backlight"); if (ret == 0) { LCDPR("load backlight_config from unifykey\n"); load_id |= 0x10; } else { load_id &= ~(0x10); } } else { load_id &= ~(0x10); } aml_bl_config_load(dt_addr, load_id); if (lcd_debug_print_flag) { if (aml_lcd_driver.lcd_config->lcd_basic.lcd_type == LCD_VBYONE) lcd_vbyone_filter_flag_print(aml_lcd_driver.lcd_config); } return 0; } static int lcd_config_probe(void) { int load_id = 0; char *dt_addr; unsigned long dtb_mem; dtb_mem = getenv_ulong("dtb_mem_addr", 16, 0); if (dtb_mem) { dt_addr = (char *)dtb_mem; } else { LCDPR("no dtb_mem_addr\n"); #ifdef CONFIG_DTB_MEM_ADDR dt_addr = (char *)CONFIG_DTB_MEM_ADDR; #endif } load_id = lcd_config_load_id_check(dt_addr); /* default setting */ aml_lcd_driver.lcd_config->retry_enable_flag = 0; aml_lcd_driver.lcd_config->retry_enable_cnt = 0; strncpy(aml_lcd_driver.lcd_config->cus_pinmux_name, "null", CUS_PINMUX_NAME_MAX - 1); lcd_reserved_memory_init(dt_addr); lcd_phy_probe(); lcd_clk_config_probe(); lcd_mode_probe(dt_addr, load_id); aml_lcd_debug_probe(&aml_lcd_driver); return 0; } static void lcd_update_boot_ctrl_bootargs(void) { struct lcd_config_s *pconf = aml_lcd_driver.lcd_config; unsigned int value = 0; char env_str[16], ctrl_str[48], *type_str; boot_ctrl.lcd_type = pconf->lcd_basic.lcd_type; boot_ctrl.lcd_bits = pconf->lcd_basic.lcd_bits; boot_ctrl.frame_rate = pconf->lcd_timing.base_timing.frame_rate; switch (pconf->lcd_basic.lcd_type) { case LCD_TTL: boot_ctrl.advanced_flag = pconf->lcd_control.ttl_config->sync_valid; break; case LCD_P2P: boot_ctrl.advanced_flag = pconf->lcd_control.p2p_config->p2p_type; break; default: break; } /*create new env "lcd_ctrl", define as below: *bit[3:0]: lcd_type *bit[7:4]: lcd bits *bit[15:8]: advanced flag(p2p_type when lcd_type=p2p) *bit[17]: reserved *bit[16]: reserved *bit[19:18]: lcd_init_level *bit[23:20]: reserved *bit[31:24]: frame rate */ value |= (boot_ctrl.lcd_type & 0xf); value |= (boot_ctrl.lcd_bits & 0xf) << 4; value |= (boot_ctrl.advanced_flag & 0xff) << 8; value |= (boot_ctrl.init_level & 0x3) << 18; value |= (boot_ctrl.frame_rate & 0xff) << 24; lcd_venc_save_bootctrl_to_regs(&boot_ctrl); if (lcd_debug_print_flag) { LCDPR("%s: base_fr=%d, bootctrl val=0x%x\n", __func__, pconf->lcd_timing.base_timing.frame_rate, value); } sprintf(ctrl_str, "0x%08x", value); setenv("lcd_ctrl", ctrl_str); setenv("panel_name", pconf->cus_pinmux_name); type_str = getenv("panel_type"); sprintf(env_str, "lcd0_attr"); sprintf(ctrl_str, "0x%08x,%s,%s", value, strcmp(pconf->cus_pinmux_name, "null") ? pconf->cus_pinmux_name : "", pconf->lcd_key_valid ? "" : (type_str ? type_str : "")); setenv(env_str, ctrl_str); //================================ //debug bootargs //================================ value = 0; memset(ctrl_str, 0, 20); debug_ctrl.debug_print_flag = lcd_debug_print_flag; debug_ctrl.debug_test_pattern = lcd_debug_test; /* *bit[31:30]: lcd mode(0=normal, 1=tv; 2=tablet, 3=TBD) *bit[29:28]: lcd debug para source(0=normal, 1=dts, 2=unifykey, * 3=bsp for uboot) *bit[27:20]: reserved *bit[19:16]: lcd test pattern *bit[15:0]: lcd debug print flag */ value |= (debug_ctrl.debug_print_flag & 0xffff); value |= (debug_ctrl.debug_test_pattern & 0xff) << 16; value |= (debug_ctrl.debug_para_source & 0x3) << 28; value |= (debug_ctrl.debug_lcd_mode & 0x3) << 30; sprintf(ctrl_str, "0x%08x", value); setenv("lcd_debug", ctrl_str); } static struct phy_config_s lcd_phy_cfg = { .flag = 0, .vswing = 0, .vcm = 0, .ref_bias = 0, .odt = 0, .cv_mode = 0, }; int lcd_probe(void) { int ret = 0; lcd_debug_print_flag = getenv_ulong("lcd_debug_print", 10, 0); LCDPR("lcd_debug_print flag: %d\n", lcd_debug_print_flag); lcd_debug_test = getenv_ulong("lcd_debug_test", 10, 0); debug_ctrl.debug_para_source = getenv_ulong("lcd_debug_para", 10, 0); debug_ctrl.debug_lcd_mode = getenv_ulong("lcd_debug_mode", 10, 0); if (getenv("lcd_debug_init")) boot_ctrl.init_level = getenv_ulong("lcd_debug_init", 10, 0); else boot_ctrl.init_level = getenv_ulong("lcd_init_level", 10, 0); lcd_chip_detect(); lcd_config_bsp_init(); aml_lcd_driver.lcd_config->lcd_control.phy_cfg = &lcd_phy_cfg; ret = lcd_config_probe(); if (ret) return 0; save_panel_file_to_param(); panel_param_mem_update_to_lrm(); lcd_update_boot_ctrl_bootargs(); lrm_handle_mem_info_to_kernel(); mdelay(10); return 0; } int lcd_remove(void) { #ifdef CONFIG_AML_LCD_EXTERN aml_lcd_extern_remove(); #endif return 0; } #define LCD_WAIT_VSYNC_TIMEOUT 50000 void lcd_wait_vsync(void) { struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver(); int reg, line_cnt, line_cnt_previous; int i = 0; if (lcd_drv->chip_type == LCD_CHIP_T5W) reg = VPU_VENCP_STAT; else reg = ENCL_INFO_READ; line_cnt = 0x1fff; line_cnt_previous = lcd_vcbus_getb(reg, 16, 13); while (i++ < LCD_WAIT_VSYNC_TIMEOUT) { line_cnt = lcd_vcbus_getb(reg, 16, 13); if (line_cnt < line_cnt_previous) break; line_cnt_previous = line_cnt; udelay(2); } /*LCDPR("line_cnt=%d, line_cnt_previous=%d, i=%d\n", * line_cnt, line_cnt_previous, i); */ } int aml_lcd_get_state(void) { if (aml_lcd_driver.lcd_status & LCD_STATUS_IF_ON) return 1; return 0; } /* ********************************************** * lcd driver API * ********************************************** */ static int lcd_outputmode_check(char *mode, unsigned int frac) { if (aml_lcd_driver.outputmode_check) return aml_lcd_driver.outputmode_check(mode); LCDERR("invalid lcd config\n"); return -1; } static void lcd_prepare(char *mode, unsigned int frac) { if (lcd_check_valid()) return; if (aml_lcd_driver.lcd_status & LCD_STATUS_ENCL_ON) LCDPR("already enabled\n"); else lcd_module_prepare(mode, frac); } static void lcd_enable(char *mode, unsigned int frac) { if (lcd_check_valid()) return; if (aml_lcd_driver.lcd_status & LCD_STATUS_IF_ON) LCDPR("already enabled\n"); else lcd_module_enable(mode, frac); } static void lcd_disable(void) { if (lcd_check_valid()) return; if (aml_lcd_driver.lcd_status & LCD_STATUS_ENCL_ON) lcd_module_disable(); else LCDPR("already disabled\n"); } static void aml_lcd_set_ss(unsigned int level, unsigned int freq, unsigned int mode) { struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver(); int ret; if (lcd_check_valid()) return; if (aml_lcd_driver.lcd_status) { ret = lcd_set_ss(level, freq, mode); if (ret == 0) { if (level < 0xff) lcd_drv->lcd_config->lcd_timing.ss_level = level; if (freq < 0xff) lcd_drv->lcd_config->lcd_timing.ss_freq = freq; if (mode < 0xff) lcd_drv->lcd_config->lcd_timing.ss_mode = mode; } } else { LCDPR("already disabled\n"); } } static void aml_lcd_get_ss(void) { if (lcd_check_valid()) return; if (aml_lcd_driver.lcd_status) lcd_get_ss(); else LCDPR("already disabled\n"); } static void aml_lcd_test(int num) { if (lcd_check_valid()) return; if (aml_lcd_driver.lcd_status) aml_lcd_debug_test(num); else LCDPR("already disabled\n"); } static void aml_lcd_config_check(void) { int ret; if (lcd_check_valid()) return; ret = lcd_config_timing_check(&aml_lcd_driver.lcd_config->lcd_timing.act_timing); if (ret == 0) printf("lcd_config_check: PASS\n"); printf("disp_tmg_min_req:\n" " alert_lvl %d\n" " hswbp %d\n" " hfp %d\n" " vswbp %d\n" " vfp %d\n\n", aml_lcd_driver.disp_req.alert_level, aml_lcd_driver.disp_req.hswbp_vid, aml_lcd_driver.disp_req.hfp_vid, aml_lcd_driver.disp_req.vswbp_vid, aml_lcd_driver.disp_req.vfp_vid); #ifdef CONFIG_AML_LCD_TCON if (aml_lcd_driver.lcd_config->lcd_basic.lcd_type == LCD_MLVDS || aml_lcd_driver.lcd_config->lcd_basic.lcd_type == LCD_P2P) { lcd_tcon_dbg_check(&aml_lcd_driver.lcd_config->lcd_timing.act_timing); } #endif printf("config_check_glb: %d, config_check: 0x%x, config_check_en: %d\n\n", aml_lcd_driver.config_check_glb, aml_lcd_driver.lcd_config->lcd_basic.config_check, aml_lcd_driver.config_check_en); } static void aml_lcd_clk(void) { if (lcd_check_valid()) return; lcd_clk_config_print(); } static void aml_lcd_info(void) { if (lcd_check_valid()) return; aml_lcd_info_print(); } static void aml_lcd_reg(void) { if (lcd_check_valid()) return; aml_lcd_reg_print(); } static void lcd_vbyone_rst(void) { if (lcd_check_valid()) return; aml_lcd_vbyone_rst(); } int lcd_vbyone_cdr(void) { if (lcd_check_valid()) return -1; return aml_lcd_vbyone_cdr(); } int lcd_vbyone_lock(void) { if (lcd_check_valid()) return -1; return aml_lcd_vbyone_lock(); } static void aml_set_backlight_level(int level) { aml_bl_set_level(level); } static int aml_get_backlight_level(void) { return aml_bl_get_level(); } static void aml_backlight_power_on(void) { aml_bl_lcd_on_ctrl(); } static void aml_backlight_power_off(void) { aml_bl_lcd_off_ctrl(); } static void aml_lcd_key_dump(unsigned int flag) { unsigned int key_flag = LCD_UKEY_DEBUG_NORMAL; if (flag & (1 << 0)) { key_flag = LCD_UKEY_DEBUG_NORMAL; } else if (flag & (1 << 1)) { #ifdef CONFIG_AML_LCD_TCON switch (aml_lcd_driver.chip_type) { case LCD_CHIP_TXHD: key_flag = (LCD_UKEY_DEBUG_TCON | LCD_UKEY_TCON_SIZE); break; case LCD_CHIP_TL1: case LCD_CHIP_TM2: key_flag = (LCD_UKEY_DEBUG_TCON | LCD_UKEY_TCON_SIZE_NEW); break; default: break; } #endif } aml_lcd_unifykey_dump(key_flag); } static void aml_lcd_debug_print_set(unsigned int flag) { char str[5]; lcd_debug_print_flag = flag; sprintf(str, "%d", flag); setenv("lcd_debug_print", str); LCDPR("set debug_print_flag: %d\n", flag); } static struct aml_lcd_drv_s aml_lcd_driver = { .probe_done = 0, .lcd_status = 0, .lcd_config = &lcd_config_dft, .bl_config = &bl_config_dft, .config_valid = NULL, .lcd_probe = lcd_probe, .lcd_outputmode_check = lcd_outputmode_check, .lcd_prepare = lcd_prepare, .lcd_enable = lcd_enable, .lcd_disable = lcd_disable, .lcd_set_ss = aml_lcd_set_ss, .lcd_get_ss = aml_lcd_get_ss, .lcd_test = aml_lcd_test, .lcd_config_check = aml_lcd_config_check, .lcd_prbs = aml_lcd_prbs_test, .lcd_clk = aml_lcd_clk, .lcd_info = aml_lcd_info, .lcd_reg = aml_lcd_reg, #ifdef CONFIG_AML_LCD_TCON .lcd_tcon_reg_print = NULL, .lcd_tcon_table_print = NULL, .lcd_tcon_vac_print = NULL, .lcd_tcon_demura_print = NULL, .lcd_tcon_acc_print = NULL, .lcd_tcon_data_print = NULL, .lcd_tcon_spi_print = NULL, .lcd_tcon_spi_data_load = NULL, .lcd_tcon_reg_read = NULL, .lcd_tcon_reg_write = NULL, #endif .lcd_vbyone_rst = lcd_vbyone_rst, .lcd_vbyone_cdr = lcd_vbyone_cdr, .lcd_vbyone_lock = lcd_vbyone_lock, .bl_on = aml_backlight_power_on, .bl_off = aml_backlight_power_off, .set_bl_level = aml_set_backlight_level, .get_bl_level = aml_get_backlight_level, .bl_config_print = aml_bl_config_print, .unifykey_test_flag = 0, /* default disable unifykey test */ .unifykey_dump = aml_lcd_key_dump, .debug_print_set = aml_lcd_debug_print_set, /* for factory test */ .factory_lcd_power_on_step = NULL, .factory_bl_power_on_delay = -1, }; struct aml_lcd_drv_s *aml_lcd_get_driver(void) { return &aml_lcd_driver; }