1634 lines
41 KiB
C
1634 lines
41 KiB
C
/*
|
|
* 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 <common.h>
|
|
#include <malloc.h>
|
|
#include <asm/cpu_id.h>
|
|
#include <asm/arch/gpio.h>
|
|
#include <vpp.h>
|
|
#ifdef CONFIG_OF_LIBFDT
|
|
#include <libfdt.h>
|
|
#endif
|
|
#include <amlogic/keyunify.h>
|
|
#include <amlogic/aml_lcd.h>
|
|
#ifdef CONFIG_AML_LCD_EXTERN
|
|
#include <amlogic/aml_lcd_extern.h>
|
|
#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 <amlogic/aml_lcd_memory.h>
|
|
|
|
#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;
|
|
}
|