blob: a17650c213c37bd96d776f36aac173d249f35bd0 [file] [log] [blame]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <common.h>
#include <malloc.h>
#include <asm/arch/io.h>
#include <amlogic/media/vout/lcd/aml_lcd.h>
#include "lcd_reg.h"
#include "lcd_common.h"
#include "lcd_tcon.h"
#define PR_BUF_MAX 200
#define TCON_IRQ_TIMEOUT_MAX BIT(17)
static struct lcd_tcon_config_s *lcd_tcon_conf;
static struct tcon_rmem_s tcon_rmem;
static struct tcon_mem_map_table_s tcon_mm_table;
int lcd_tcon_valid_check(void)
{
if (!lcd_tcon_conf) {
LCDERR("invalid tcon data\n");
return -1;
}
if (lcd_tcon_conf->tcon_valid == 0) {
LCDERR("invalid tcon\n");
return -1;
}
return 0;
}
struct lcd_tcon_config_s *get_lcd_tcon_config(void)
{
int ret;
ret = lcd_tcon_valid_check();
if (ret)
return NULL;
return lcd_tcon_conf;
}
struct tcon_rmem_s *get_lcd_tcon_rmem(void)
{
int ret;
ret = lcd_tcon_valid_check();
if (ret)
return NULL;
return &tcon_rmem;
}
struct tcon_mem_map_table_s *get_lcd_tcon_mm_table(void)
{
int ret;
ret = lcd_tcon_valid_check();
if (ret)
return NULL;
return &tcon_mm_table;
}
unsigned int lcd_tcon_data_size_align(unsigned int size)
{
unsigned int new_size;
/* ready for burst 128bit */
new_size = ((size + 15) / 16) * 16;
return new_size;
}
unsigned char lcd_tcon_checksum(unsigned char *buf, unsigned int len)
{
unsigned int temp = 0;
unsigned int i;
if (!buf)
return 0;
if (len == 0)
return 0;
for (i = 0; i < len; i++)
temp += buf[i];
return (unsigned char)(temp & 0xff);
}
unsigned char lcd_tcon_lrc(unsigned char *buf, unsigned int len)
{
unsigned char temp = 0;
unsigned int i;
if (!buf)
return 0xff;
if (len == 0)
return 0xff;
temp = buf[0];
for (i = 1; i < len; i++)
temp = temp ^ buf[i];
return temp;
}
/* **********************************
* tcon function api
* **********************************
*/
static unsigned int lcd_tcon_reg_read(unsigned int addr, unsigned int flag)
{
unsigned int val;
int ret;
ret = lcd_tcon_valid_check();
if (ret)
return 0;
if (flag)
val = lcd_tcon_read_byte(addr);
else
val = lcd_tcon_read(addr);
return val;
}
static void lcd_tcon_reg_write(unsigned int addr, unsigned int val,
unsigned int flag)
{
unsigned char temp;
int ret;
ret = lcd_tcon_valid_check();
if (ret)
return;
if (flag) {
temp = (unsigned char)val;
lcd_tcon_write_byte(addr, temp);
} else {
lcd_tcon_write(addr, val);
}
}
static void lcd_tcon_reg_table_print(void)
{
int i, j, cnt;
int ret;
ret = lcd_tcon_valid_check();
if (ret)
return;
if (!tcon_mm_table.core_reg_table) {
LCDERR("%s: reg_table is null\n", __func__);
return;
}
LCDPR("%s:\n", __func__);
cnt = tcon_mm_table.core_reg_table_size;
for (i = 0; i < cnt; i += 16) {
printf("%04x: ", i);
for (j = 0; j < 16; j++) {
if ((i + j) >= cnt)
break;
printf(" %02x", tcon_mm_table.core_reg_table[i + j]);
}
printf("\n");
}
}
static void lcd_tcon_reg_readback_print(void)
{
unsigned int i, j, cnt, offset;
int ret;
ret = lcd_tcon_valid_check();
if (ret)
return;
LCDPR("%s:\n", __func__);
cnt = tcon_mm_table.core_reg_table_size;
offset = lcd_tcon_conf->core_reg_start;
if (lcd_tcon_conf->core_reg_width == 8) {
for (i = offset; i < cnt; i += 16) {
printf("%04x: ", i);
for (j = 0; j < 16; j++) {
if ((i + j) >= cnt)
break;
printf(" %02x", lcd_tcon_read_byte(i + j));
}
printf("\n");
}
} else {
if (lcd_tcon_conf->reg_table_width == 32) {
cnt /= 4;
for (i = offset; i < cnt; i += 4) {
printf("%04x: ", i);
for (j = 0; j < 4; j++) {
if ((i + j) >= cnt)
break;
printf(" %08x", lcd_tcon_read(i + j));
}
printf("\n");
}
} else {
for (i = offset; i < cnt; i += 16) {
printf("%04x: ", i);
for (j = 0; j < 16; j++) {
if ((i + j) >= cnt)
break;
printf(" %02x", lcd_tcon_read(i + j));
}
printf("\n");
}
}
}
}
static unsigned int lcd_tcon_table_read(unsigned int addr)
{
unsigned char *table8;
unsigned int *table32, size = 0, val = 0;
int ret;
ret = lcd_tcon_valid_check();
if (ret)
return 0;
if (!tcon_mm_table.core_reg_table) {
LCDERR("tcon reg_table is null\n");
return 0;
}
if (lcd_tcon_conf->core_reg_width == 8)
size = tcon_mm_table.core_reg_table_size;
else
size = tcon_mm_table.core_reg_table_size / 4;
if (addr >= size) {
LCDERR("invalid tcon reg_table addr: 0x%04x\n", addr);
return 0;
}
if (lcd_tcon_conf->core_reg_width == 8) {
table8 = tcon_mm_table.core_reg_table;
val = table8[addr];
} else {
table32 = (unsigned int *)tcon_mm_table.core_reg_table;
val = table32[addr];
}
return val;
}
static unsigned int lcd_tcon_table_write(unsigned int addr, unsigned int val)
{
unsigned char *table8;
unsigned int *table32, size = 0, read_val = 0;
int ret;
ret = lcd_tcon_valid_check();
if (ret)
return 0;
if (!tcon_mm_table.core_reg_table) {
LCDERR("tcon reg_table is null\n");
return 0;
}
if (lcd_tcon_conf->core_reg_width == 8)
size = tcon_mm_table.core_reg_table_size;
else
size = tcon_mm_table.core_reg_table_size / 4;
if (addr >= size) {
LCDERR("invalid tcon reg_table addr: 0x%04x\n", addr);
return 0;
}
if (lcd_tcon_conf->core_reg_width == 8) {
table8 = tcon_mm_table.core_reg_table;
table8[addr] = (unsigned char)(val & 0xff);
read_val = table8[addr];
} else {
table32 = (unsigned int *)tcon_mm_table.core_reg_table;
table32[addr] = val;
read_val = table32[addr];
}
return read_val;
}
static void lcd_tcon_vac_print(void)
{
int i, j, n, size;
char *buf;
int ret;
ret = lcd_tcon_valid_check();
if (ret)
return;
if (tcon_mm_table.version) {
LCDERR("%s: mem map version invalid\n", __func__);
return;
}
if ((tcon_mm_table.valid_flag & LCD_TCON_DATA_VALID_VAC) == 0) {
LCDERR("%s: vac invalid\n", __func__);
return;
}
buf = (char *)malloc(PR_BUF_MAX * sizeof(char));
if (buf == NULL) {
LCDERR("%s: buf malloc error\n", __func__);
return;
}
printf("%s:\n", __func__);
size = tcon_rmem.vac_rmem.mem_vaddr[0] |
(tcon_rmem.vac_rmem.mem_vaddr[1] << 8) |
(tcon_rmem.vac_rmem.mem_vaddr[2] << 16) |
(tcon_rmem.vac_rmem.mem_vaddr[3] << 24);
size += 8; /* header for data_cnt & crc */
for (i = 0; i < size; i += 16) {
n = snprintf(buf, PR_BUF_MAX, "0x%04x: ", i);
for (j = 0; j < 16; j++) {
if ((i + j) >= size)
break;
n += snprintf(buf + n, PR_BUF_MAX, " %02x",
tcon_rmem.vac_rmem.mem_vaddr[i + j]);
}
buf[n] = '\0';
printf("%s\n", buf);
}
free(buf);
}
static void lcd_tcon_demura_print(void)
{
int i, j, n, size;
char *buf;
int ret;
ret = lcd_tcon_valid_check();
if (ret)
return;
if (tcon_mm_table.version) {
LCDERR("%s: mem map version invalid\n", __func__);
return;
}
if ((tcon_mm_table.valid_flag & LCD_TCON_DATA_VALID_DEMURA) == 0) {
LCDERR("%s: demura invalid\n", __func__);
return;
}
buf = (char *)malloc(PR_BUF_MAX * sizeof(char));
if (buf == NULL) {
LCDERR("%s: buf malloc error\n", __func__);
return;
}
printf("%s: demura_set:\n", __func__);
size = tcon_rmem.demura_set_rmem.mem_vaddr[0] |
(tcon_rmem.demura_set_rmem.mem_vaddr[1] << 8) |
(tcon_rmem.demura_set_rmem.mem_vaddr[2] << 16) |
(tcon_rmem.demura_set_rmem.mem_vaddr[3] << 24);
size += 8; /* header for data_cnt & crc */
for (i = 0; i < size; i += 16) {
n = snprintf(buf, PR_BUF_MAX, "0x%04x: ", i);
for (j = 0; j < 16; j++) {
if ((i + j) >= size)
break;
n += snprintf
(buf + n, PR_BUF_MAX, " %02x",
tcon_rmem.demura_set_rmem.mem_vaddr[i + j]);
}
buf[n] = '\0';
printf("%s\n", buf);
}
printf("\n%s: demura_lut:\n", __func__);
size = tcon_rmem.demura_lut_rmem.mem_vaddr[0] |
(tcon_rmem.demura_lut_rmem.mem_vaddr[1] << 8) |
(tcon_rmem.demura_lut_rmem.mem_vaddr[2] << 16) |
(tcon_rmem.demura_lut_rmem.mem_vaddr[3] << 24);
size += 8; /* header for data_cnt & crc */
for (i = 0; i < size; i += 16) {
n = snprintf(buf, PR_BUF_MAX, "0x%04x: ", i);
for (j = 0; j < 16; j++) {
if ((i + j) >= size)
break;
n += snprintf
(buf + n, PR_BUF_MAX, " %02x",
tcon_rmem.demura_lut_rmem.mem_vaddr[i + j]);
}
buf[n] = '\0';
printf("%s\n", buf);
}
free(buf);
}
static void lcd_tcon_acc_print(void)
{
int i, j, n, size;
char *buf;
int ret;
ret = lcd_tcon_valid_check();
if (ret)
return;
if (tcon_mm_table.version) {
LCDERR("%s: mem map version invalid\n", __func__);
return;
}
if ((tcon_mm_table.valid_flag & LCD_TCON_DATA_VALID_ACC) == 0) {
LCDERR("%s: acc_lut invalid\n", __func__);
return;
}
buf = (char *)malloc(PR_BUF_MAX * sizeof(char));
if (!buf) {
LCDERR("%s: buf malloc error\n", __func__);
return;
}
LCDPR("%s\n", __func__);
size = tcon_rmem.acc_lut_rmem.mem_vaddr[0] |
(tcon_rmem.acc_lut_rmem.mem_vaddr[1] << 8) |
(tcon_rmem.acc_lut_rmem.mem_vaddr[2] << 16) |
(tcon_rmem.acc_lut_rmem.mem_vaddr[3] << 24);
size += 8; /* header for data_cnt & crc */
for (i = 0; i < size; i += 16) {
n = snprintf(buf, PR_BUF_MAX, "0x%04x: ", i);
for (j = 0; j < 16; j++) {
if ((i + j) >= size)
break;
n += snprintf
(buf + n, PR_BUF_MAX, " %02x",
tcon_rmem.acc_lut_rmem.mem_vaddr[i + j]);
}
buf[n] = '\0';
printf("%s\n", buf);
}
free(buf);
}
static void lcd_tcon_data_block_print(char *buf, unsigned char *data_mem)
{
int i, j, n, size;
size = data_mem[8] |
(data_mem[9] << 8) |
(data_mem[10] << 16) |
(data_mem[11] << 24);
for (i = 0; i < size; i += 16) {
n = snprintf(buf, PR_BUF_MAX, "0x%04x: ", i);
for (j = 0; j < 16; j++) {
if ((i + j) >= size)
break;
n += snprintf(buf + n, PR_BUF_MAX, " %02x",
data_mem[i + j]);
}
buf[n] = '\0';
printf("%s\n", buf);
}
}
static void lcd_tcon_data_print(unsigned char index)
{
int i;
char *buf;
int ret;
ret = lcd_tcon_valid_check();
if (ret)
return;
if (tcon_mm_table.version == 0) {
LCDERR("%s: mem map version invalid\n", __func__);
return;
}
buf = (char *)malloc(PR_BUF_MAX * sizeof(char));
if (!buf) {
LCDERR("%s: buf malloc error\n", __func__);
return;
}
if (index == 0xff) {
for (i = 0; i < tcon_mm_table.block_cnt; i++) {
if (!tcon_mm_table.data_mem_vaddr[i])
continue;
printf("tcon data[%d] print:\n", i);
lcd_tcon_data_block_print
(buf, tcon_mm_table.data_mem_vaddr[i]);
}
} else {
if (index >= tcon_mm_table.block_cnt) {
LCDERR("%s: invalid index %d\n", __func__, index);
free(buf);
return;
}
if (!tcon_mm_table.data_mem_vaddr[index]) {
LCDERR("%s: invalid data_mem buf\n", __func__);
free(buf);
return;
}
printf("tcon data[%d] print:\n", index);
lcd_tcon_data_block_print
(buf, tcon_mm_table.data_mem_vaddr[index]);
}
free(buf);
}
void lcd_tcon_info_print(void)
{
unsigned int size, cnt, file_size, n;
char *str;
int i, ret;
ret = lcd_tcon_valid_check();
if (ret)
return;
LCDPR("%s:\n", __func__);
printf("core_reg_width: %d\n"
"reg_table_len: %d\n"
"tcon_rmem_flag: %d\n"
"rsv_mem addr: 0x%08x\n"
"rsv_mem size: 0x%08x\n\n",
lcd_tcon_conf->core_reg_width,
lcd_tcon_conf->reg_table_len,
tcon_rmem.flag,
tcon_rmem.rsv_mem_paddr,
tcon_rmem.rsv_mem_size);
if (tcon_rmem.flag) {
for (i = 0; i < lcd_tcon_conf->axi_bank; i++) {
printf("axi_mem[%d]_paddr: 0x%lx\n"
"axi_mem[%d]_vaddr: 0x%p\n"
"axi_mem[%d]_size: 0x%x\n",
i,
(unsigned long)tcon_rmem.axi_rmem[i].mem_paddr,
i, tcon_rmem.axi_rmem[i].mem_vaddr,
i, tcon_rmem.axi_rmem[i].mem_size);
}
}
if (tcon_rmem.bin_path_rmem.mem_size) {
printf("bin_path_mem paddr: 0x%08x\n"
"bin_path_mem vaddr: 0x%p\n"
"bin_path_mem size: 0x%08x\n\n",
tcon_rmem.bin_path_rmem.mem_paddr,
tcon_rmem.bin_path_rmem.mem_vaddr,
tcon_rmem.bin_path_rmem.mem_size);
}
if (tcon_mm_table.version == 0) {
if (tcon_rmem.vac_rmem.mem_size) {
printf("vac_mem vaddr: 0x%p\n"
"vac_mem size: 0x%08x\n",
tcon_rmem.vac_rmem.mem_vaddr,
tcon_rmem.vac_rmem.mem_size);
}
if (tcon_rmem.demura_set_rmem.mem_size) {
printf("demura_set_mem vaddr: 0x%p\n"
"demura_set_mem size: 0x%08x\n",
tcon_rmem.demura_set_rmem.mem_vaddr,
tcon_rmem.demura_set_rmem.mem_size);
}
if (tcon_rmem.demura_lut_rmem.mem_size) {
printf("demura_lut_mem vaddr: 0x%p\n"
"demura_lut_mem size: 0x%08x\n",
tcon_rmem.demura_lut_rmem.mem_vaddr,
tcon_rmem.demura_lut_rmem.mem_size);
}
if (tcon_rmem.acc_lut_rmem.mem_size) {
printf("acc_lut_mem vaddr: 0x%p\n"
"acc_lut_mem size: 0x%08x\n",
tcon_rmem.acc_lut_rmem.mem_vaddr,
tcon_rmem.acc_lut_rmem.mem_size);
}
} else {
printf("data_mem_block_cnt: %d\n",
tcon_mm_table.block_cnt);
for (i = 0; i < tcon_mm_table.block_cnt; i++) {
if (tcon_mm_table.data_mem_vaddr[i]) {
size = tcon_mm_table.data_mem_vaddr[i][8] |
(tcon_mm_table.data_mem_vaddr[i][9] << 8) |
(tcon_mm_table.data_mem_vaddr[i][10] << 16) |
(tcon_mm_table.data_mem_vaddr[i][11] << 24);
printf("data_mem[%d] vaddr: 0x%p\n"
"data_mem[%d] size: 0x%08x\n",
i, tcon_mm_table.data_mem_vaddr[i],
i, size);
}
}
}
if (tcon_rmem.bin_path_rmem.mem_vaddr) {
size = tcon_rmem.bin_path_rmem.mem_vaddr[4] |
(tcon_rmem.bin_path_rmem.mem_vaddr[5] << 8) |
(tcon_rmem.bin_path_rmem.mem_vaddr[6] << 16) |
(tcon_rmem.bin_path_rmem.mem_vaddr[7] << 24);
cnt = tcon_rmem.bin_path_rmem.mem_vaddr[16] |
(tcon_rmem.bin_path_rmem.mem_vaddr[17] << 8) |
(tcon_rmem.bin_path_rmem.mem_vaddr[18] << 16) |
(tcon_rmem.bin_path_rmem.mem_vaddr[19] << 24);
if (size < (32 + 256 * cnt))
return;
printf("\n");
for (i = 0; i < cnt; i++) {
n = 32 + 256 * i;
file_size = tcon_rmem.bin_path_rmem.mem_vaddr[n] |
(tcon_rmem.bin_path_rmem.mem_vaddr[n + 1] << 8) |
(tcon_rmem.bin_path_rmem.mem_vaddr[n + 2] << 16) |
(tcon_rmem.bin_path_rmem.mem_vaddr[n + 3] << 24);
str = (char *)&tcon_rmem.bin_path_rmem.mem_vaddr[n + 4];
printf("tcon_path[%d]: size: 0x%x, %s\n", i,
file_size, str);
}
}
printf("\n");
}
#ifdef CONFIG_CMD_INI
static int lcd_tcon_bin_path_resv_mem_set(void)
{
unsigned char *buf, *mem_vaddr;
unsigned int data_size, block_size, temp_crc, n, i;
if (tcon_rmem.flag == 0)
return 0;
buf = handle_tcon_path_mem_get(tcon_rmem.bin_path_rmem.mem_size);
if (!buf) {
LCDERR("%s: bin_path buf invalid\n", __func__);
return -1;
}
data_size = buf[4] | (buf[5] << 8) | (buf[6] << 16) | (buf[7] << 24);
if (tcon_mm_table.data_size) {
for (i = 0; i < tcon_mm_table.block_cnt; i++) {
block_size = tcon_mm_table.data_size[i];
if (block_size == 0)
continue;
n = 32 + (i * 256);
buf[n] = block_size & 0xff;
buf[n + 1] = (block_size >> 8) & 0xff;
buf[n + 2] = (block_size >> 16) & 0xff;
buf[n + 3] = (block_size >> 24) & 0xff;
}
/* update data check */
temp_crc = crc32(0, &buf[4], (data_size - 4));
buf[0] = temp_crc & 0xff;
buf[1] = (temp_crc >> 8) & 0xff;
buf[2] = (temp_crc >> 16) & 0xff;
buf[3] = (temp_crc >> 24) & 0xff;
}
mem_vaddr = (unsigned char *)
(unsigned long)(tcon_rmem.bin_path_rmem.mem_paddr);
memcpy(mem_vaddr, buf, data_size);
return 0;
}
#endif
int lcd_tcon_enable(struct aml_lcd_drv_s *pdrv)
{
int ret;
ret = lcd_tcon_valid_check();
if (ret)
return -1;
if (lcd_tcon_conf->tcon_enable)
lcd_tcon_conf->tcon_enable(pdrv);
#ifdef CONFIG_CMD_INI
lcd_tcon_bin_path_resv_mem_set();
#endif
return 0;
}
void lcd_tcon_disable(struct aml_lcd_drv_s *pdrv)
{
unsigned int reg, i, cnt, offset, bit;
int ret;
ret = lcd_tcon_valid_check();
if (ret)
return;
LCDPR("%s\n", __func__);
/* disable over_drive */
if (lcd_tcon_conf->reg_core_od != REG_LCD_TCON_MAX) {
reg = lcd_tcon_conf->reg_core_od;
bit = lcd_tcon_conf->bit_od_en;
if (lcd_tcon_conf->core_reg_width == 8)
lcd_tcon_setb_byte(reg, 0, bit, 1);
else
lcd_tcon_setb(reg, 0, bit, 1);
mdelay(100);
}
/* disable all ctrl signal */
if (lcd_tcon_conf->reg_ctrl_timing_base != REG_LCD_TCON_MAX) {
reg = lcd_tcon_conf->reg_ctrl_timing_base;
offset = lcd_tcon_conf->ctrl_timing_offset;
cnt = lcd_tcon_conf->ctrl_timing_cnt;
for (i = 0; i < cnt; i++) {
if (lcd_tcon_conf->core_reg_width == 8)
lcd_tcon_setb_byte((reg + (i * offset)),
1, 3, 1);
else
lcd_tcon_setb((reg + (i * offset)), 1, 3, 1);
}
}
/* disable top */
if (lcd_tcon_conf->reg_top_ctrl != REG_LCD_TCON_MAX) {
reg = lcd_tcon_conf->reg_top_ctrl;
bit = lcd_tcon_conf->bit_en;
lcd_tcon_setb(reg, 0, bit, 1);
}
}
/* **********************************
* tcon config
* **********************************
*/
static int lcd_tcon_vac_load(void)
{
unsigned char *buff = tcon_rmem.vac_rmem.mem_vaddr;
#ifdef CONFIG_CMD_INI
unsigned int i, data_cnt = 0;
unsigned char data_checksum, data_lrc, temp_checksum, temp_lrc;
#endif
int ret = -1;
if (tcon_rmem.vac_rmem.mem_size == 0 || !buff)
return -1;
#ifdef CONFIG_CMD_INI
ret = handle_tcon_vac(buff, tcon_rmem.vac_rmem.mem_size);
if (ret) {
LCDPR("%s: no vac data\n", __func__);
return -1;
}
data_cnt = (buff[0] |
(buff[1] << 8) |
(buff[2] << 16) |
(buff[3] << 24));
if (data_cnt == 0) {
LCDERR("%s: vac_data data_cnt error\n", __func__);
return -1;
}
data_checksum = buff[4];
data_lrc = buff[5];
temp_checksum = lcd_tcon_checksum(&buff[8], data_cnt);
temp_lrc = lcd_tcon_lrc(&buff[8], data_cnt);
if (data_checksum != temp_checksum) {
LCDERR("%s: vac_data checksum error\n", __func__);
return -1;
}
if (data_lrc != temp_lrc) {
LCDERR("%s: vac_data lrc error\n", __func__);
return -1;
}
if (buff[6] != 0x55 || buff[7] != 0xaa) {
LCDERR("%s: vac_data pattern error\n", __func__);
return -1;
}
if (lcd_debug_print_flag & LCD_DBG_PR_ADV) {
for (i = 0; i < 30; i++)
LCDPR("vac_data[%d]: 0x%02x\n", i, buff[i * 1]);
}
#endif
return ret;
}
static int lcd_tcon_demura_set_load(void)
{
unsigned char *buff = tcon_rmem.demura_set_rmem.mem_vaddr;
#ifdef CONFIG_CMD_INI
unsigned int i, data_cnt = 0;
unsigned char data_checksum, data_lrc, temp_checksum, temp_lrc;
#endif
int ret = -1;
if (tcon_rmem.demura_set_rmem.mem_size == 0 || !buff)
return -1;
#ifdef CONFIG_CMD_INI
ret = handle_tcon_demura_set(buff, tcon_rmem.demura_set_rmem.mem_size);
if (ret) {
LCDPR("%s: no demura_set data\n", __func__);
return -1;
}
data_cnt = (buff[0] |
(buff[1] << 8) |
(buff[2] << 16) |
(buff[3] << 24));
if (data_cnt == 0) {
LCDERR("%s: demura_set data_cnt error\n", __func__);
return -1;
}
data_checksum = buff[4];
data_lrc = buff[5];
temp_checksum = lcd_tcon_checksum(&buff[8], data_cnt);
temp_lrc = lcd_tcon_lrc(&buff[8], data_cnt);
if (data_checksum != temp_checksum) {
LCDERR("%s: demura_set checksum error\n", __func__);
return -1;
}
if (data_lrc != temp_lrc) {
LCDERR("%s: demura_set lrc error\n", __func__);
return -1;
}
if (buff[6] != 0x55 || buff[7] != 0xaa) {
LCDERR("%s: demura_set pattern error\n", __func__);
return -1;
}
if (lcd_debug_print_flag & LCD_DBG_PR_ADV) {
for (i = 0; i < 100; i++)
LCDPR("demura_set[%d]: 0x%x\n", i, buff[i]);
}
#endif
return ret;
}
static int lcd_tcon_demura_lut_load(void)
{
unsigned char *buff = tcon_rmem.demura_lut_rmem.mem_vaddr;
#ifdef CONFIG_CMD_INI
unsigned int i, data_cnt = 0;
unsigned char data_checksum, data_lrc, temp_checksum, temp_lrc;
#endif
int ret = -1;
if (tcon_rmem.demura_lut_rmem.mem_size == 0 || !buff)
return -1;
#ifdef CONFIG_CMD_INI
ret = handle_tcon_demura_lut(buff, tcon_rmem.demura_lut_rmem.mem_size);
if (ret) {
LCDPR("%s: no demura_lut data\n", __func__);
return -1;
}
data_cnt = (buff[0] |
(buff[1] << 8) |
(buff[2] << 16) |
(buff[3] << 24));
if (data_cnt == 0) {
LCDERR("%s: demura_lut data_cnt error\n", __func__);
return -1;
}
data_checksum = buff[4];
data_lrc = buff[5];
temp_checksum = lcd_tcon_checksum(&buff[8], data_cnt);
temp_lrc = lcd_tcon_lrc(&buff[8], data_cnt);
if (data_checksum != temp_checksum) {
LCDERR("%s: demura_lut checksum error\n", __func__);
return -1;
}
if (data_lrc != temp_lrc) {
LCDERR("%s: demura_lut lrc error\n", __func__);
return -1;
}
if ((buff[6] != 0x55) || (buff[7] != 0xaa)) {
LCDERR("%s: demura_lut pattern error\n", __func__);
return -1;
}
if (lcd_debug_print_flag & LCD_DBG_PR_ADV) {
for (i = 0; i < 100; i++)
LCDPR("demura_lut[%d]: 0x%02x\n", i, buff[i]);
}
#endif
return ret;
}
static int lcd_tcon_acc_lut_load(void)
{
unsigned char *buff = tcon_rmem.acc_lut_rmem.mem_vaddr;
#ifdef CONFIG_CMD_INI
unsigned int i, data_cnt = 0;
unsigned char data_checksum, data_lrc, temp_checksum, temp_lrc;
#endif
int ret = -1;
if (tcon_rmem.acc_lut_rmem.mem_size == 0 || !buff)
return -1;
#ifdef CONFIG_CMD_INI
ret = handle_tcon_acc_lut(buff, tcon_rmem.acc_lut_rmem.mem_size);
if (ret) {
LCDPR("%s: no acc_lut data\n", __func__);
return -1;
}
data_cnt = (buff[0] |
(buff[1] << 8) |
(buff[2] << 16) |
(buff[3] << 24));
if (data_cnt == 0) {
LCDERR("%s: acc_lut data_cnt error\n", __func__);
return -1;
}
data_checksum = buff[4];
data_lrc = buff[5];
temp_checksum = lcd_tcon_checksum(&buff[8], data_cnt);
temp_lrc = lcd_tcon_lrc(&buff[8], data_cnt);
if (data_checksum != temp_checksum) {
LCDERR("%s: acc_lut checksum error\n", __func__);
return -1;
}
if (data_lrc != temp_lrc) {
LCDERR("%s: acc_lut lrc error\n", __func__);
return -1;
}
if (buff[6] != 0x55 || buff[7] != 0xaa) {
LCDERR("%s: acc_lut pattern error\n", __func__);
return -1;
}
if (lcd_debug_print_flag & LCD_DBG_PR_ADV) {
for (i = 0; i < 100; i++)
LCDPR("acc_lut[%d]: 0x%02x\n", i, buff[i]);
}
#endif
return ret;
}
static int lcd_tcon_data_load(struct aml_lcd_drv_s *pdrv)
{
unsigned char *table;
#ifdef CONFIG_CMD_INI
struct lcd_tcon_data_block_header_s block_header;
struct tcon_data_priority_s *data_prio;
unsigned int i, j, priority, demura_cnt = 0;
#endif
int ret;
ret = lcd_tcon_valid_check();
if (ret)
return -1;
table = tcon_mm_table.core_reg_table;
if (!table)
return 0;
if (tcon_mm_table.version == 0) {
if (pdrv->data->chip_type == LCD_CHIP_TL1 ||
pdrv->data->chip_type == LCD_CHIP_TM2) {
ret = lcd_tcon_vac_load();
if (ret == 0)
tcon_mm_table.valid_flag |= LCD_TCON_DATA_VALID_VAC;
ret = lcd_tcon_demura_set_load();
if (ret) {
table[0x178] = 0x38;
table[0x17c] = 0x20;
table[0x181] = 0x00;
table[0x23d] &= ~(1 << 0);
} else {
ret = lcd_tcon_demura_lut_load();
if (ret) {
table[0x178] = 0x38;
table[0x17c] = 0x20;
table[0x181] = 0x00;
table[0x23d] &= ~(1 << 0);
} else {
tcon_mm_table.valid_flag |=
LCD_TCON_DATA_VALID_DEMURA;
}
}
}
ret = lcd_tcon_acc_lut_load();
if (ret == 0)
tcon_mm_table.valid_flag |= LCD_TCON_DATA_VALID_ACC;
} else {
if (!tcon_mm_table.data_mem_vaddr) {
LCDERR("%s: data_mem error\n", __func__);
return -1;
}
if (!tcon_mm_table.data_priority) {
LCDERR("%s: data_priority error\n", __func__);
return -1;
}
if (!tcon_mm_table.data_size) {
LCDERR("%s: data_size error\n", __func__);
return -1;
}
#ifdef CONFIG_CMD_INI
data_prio = tcon_mm_table.data_priority;
for (i = 0; i < tcon_mm_table.block_cnt; i++) {
ret = handle_tcon_data_load
(tcon_mm_table.data_mem_vaddr, i);
if (ret)
continue;
memcpy(&block_header, tcon_mm_table.data_mem_vaddr[i],
LCD_TCON_DATA_BLOCK_HEADER_SIZE);
tcon_mm_table.valid_flag |= block_header.block_flag;
if (block_header.block_flag ==
LCD_TCON_DATA_VALID_DEMURA)
demura_cnt++;
/* insertion sort for block data init_priority */
data_prio[i].index = i;
//data_prio[i].priority = block_header.init_priority;
/* update init_priority by index */
priority = i;
data_prio[i].priority = priority;
if (i > 0) {
j = i - 1;
while (j >= 0) {
if (priority > data_prio[j].priority)
break;
if (priority == data_prio[j].priority) {
LCDERR
("%s: block %d init_priority same as block %d\n",
__func__,
data_prio[i].index,
data_prio[j].index);
return -1;
}
data_prio[j + 1].index =
data_prio[j].index;
data_prio[j + 1].priority =
data_prio[j].priority;
j--;
}
data_prio[j + 1].index = i;
data_prio[j + 1].priority = priority;
}
tcon_mm_table.data_size[i] = block_header.block_size;
if (lcd_debug_print_flag & LCD_DBG_PR_NORMAL) {
LCDPR("%s %d: block size=0x%x, type=0x%02x, name=%s, init_priority=%d\n",
__func__, i,
block_header.block_size,
block_header.block_type,
block_header.name, priority);
}
}
/* specially check demura setting */
if (pdrv->data->chip_type == LCD_CHIP_TL1 ||
pdrv->data->chip_type == LCD_CHIP_TM2) {
if (demura_cnt < 2) {
tcon_mm_table.valid_flag &=
~LCD_TCON_DATA_VALID_DEMURA;
/* disable demura */
table[0x178] = 0x38;
table[0x17c] = 0x20;
table[0x181] = 0x00;
table[0x23d] &= ~(1 << 0);
}
}
#endif
}
return 0;
}
static int lcd_tcon_bin_path_update(unsigned int size)
{
#ifdef CONFIG_CMD_INI
unsigned char *mem_vaddr;
unsigned int data_size;
unsigned int data_crc32, temp_crc32;
/* notice: different with kernel flow: mem_vaddr is not mapping to mem_paddr */
tcon_rmem.bin_path_rmem.mem_vaddr = handle_tcon_path_mem_get(size);
if (!tcon_rmem.bin_path_rmem.mem_vaddr) {
LCDERR("%s: get mem error\n", __func__);
return -1;
}
mem_vaddr = tcon_rmem.bin_path_rmem.mem_vaddr;
data_size = mem_vaddr[4] |
(mem_vaddr[5] << 8) |
(mem_vaddr[6] << 16) |
(mem_vaddr[7] << 24);
if (data_size < 4) {
LCDERR("%s: tcon_bin_path data_size error\n", __func__);
return -1;
}
data_crc32 = mem_vaddr[0] |
(mem_vaddr[1] << 8) |
(mem_vaddr[2] << 16) |
(mem_vaddr[3] << 24);
temp_crc32 = crc32(0, &mem_vaddr[4], (data_size - 4));
if (data_crc32 != temp_crc32) {
LCDERR("%s: tcon_bin_path data crc error\n", __func__);
return -1;
}
tcon_mm_table.version = mem_vaddr[8] |
(mem_vaddr[9] << 8) |
(mem_vaddr[10] << 16) |
(mem_vaddr[11] << 24);
tcon_mm_table.data_load_level = mem_vaddr[12] |
(mem_vaddr[13] << 8) |
(mem_vaddr[14] << 16) |
(mem_vaddr[15] << 24);
tcon_mm_table.block_cnt = mem_vaddr[16] |
(mem_vaddr[17] << 8) |
(mem_vaddr[18] << 16) |
(mem_vaddr[19] << 24);
#endif
return 0;
}
static int lcd_tcon_mm_table_config_v0(void)
{
unsigned int max_size;
/* reserved memory */
max_size = lcd_tcon_conf->axi_size +
lcd_tcon_conf->bin_path_size +
lcd_tcon_conf->vac_size +
lcd_tcon_conf->demura_set_size +
lcd_tcon_conf->demura_lut_size +
lcd_tcon_conf->acc_lut_size;
if (tcon_rmem.rsv_mem_size < max_size) {
LCDERR("%s: tcon mem size 0x%x is not enough, need 0x%x\n",
__func__, tcon_rmem.rsv_mem_size, max_size);
return -1;
}
if (tcon_mm_table.block_cnt != 4) {
LCDERR("%s: tcon data block_cnt %d invalid\n",
__func__, tcon_mm_table.block_cnt);
return -1;
}
tcon_rmem.vac_rmem.mem_size = lcd_tcon_conf->vac_size;
tcon_rmem.vac_rmem.mem_paddr =
tcon_rmem.bin_path_rmem.mem_paddr +
tcon_rmem.bin_path_rmem.mem_size;
tcon_rmem.vac_rmem.mem_vaddr =
(unsigned char *)(unsigned long)(tcon_rmem.vac_rmem.mem_paddr);
if ((lcd_debug_print_flag & LCD_DBG_PR_NORMAL) && tcon_rmem.vac_rmem.mem_size > 0)
LCDPR("tcon vac paddr: 0x%08x, size: 0x%x\n",
tcon_rmem.vac_rmem.mem_paddr,
tcon_rmem.vac_rmem.mem_size);
tcon_rmem.demura_set_rmem.mem_size = lcd_tcon_conf->demura_set_size;
tcon_rmem.demura_set_rmem.mem_paddr =
tcon_rmem.vac_rmem.mem_paddr + tcon_rmem.vac_rmem.mem_size;
tcon_rmem.demura_set_rmem.mem_vaddr = (unsigned char *)
(unsigned long)(tcon_rmem.demura_set_rmem.mem_paddr);
if ((lcd_debug_print_flag & LCD_DBG_PR_NORMAL) && tcon_rmem.demura_set_rmem.mem_size > 0)
LCDPR("tcon demura set_paddr: 0x%08x, size: 0x%x\n",
tcon_rmem.demura_set_rmem.mem_paddr,
tcon_rmem.demura_set_rmem.mem_size);
tcon_rmem.demura_lut_rmem.mem_size = lcd_tcon_conf->demura_lut_size;
tcon_rmem.demura_lut_rmem.mem_paddr =
tcon_rmem.demura_set_rmem.mem_paddr +
tcon_rmem.demura_set_rmem.mem_size;
tcon_rmem.demura_lut_rmem.mem_vaddr = (unsigned char *)
(unsigned long)(tcon_rmem.demura_lut_rmem.mem_paddr);
if ((lcd_debug_print_flag & LCD_DBG_PR_NORMAL) && tcon_rmem.demura_lut_rmem.mem_size > 0)
LCDPR("tcon demura lut_paddr: 0x%08x, size: 0x%x\n",
tcon_rmem.demura_lut_rmem.mem_paddr,
tcon_rmem.demura_lut_rmem.mem_size);
tcon_rmem.acc_lut_rmem.mem_size = lcd_tcon_conf->acc_lut_size;
tcon_rmem.acc_lut_rmem.mem_paddr =
tcon_rmem.demura_lut_rmem.mem_paddr +
tcon_rmem.demura_lut_rmem.mem_size;
tcon_rmem.acc_lut_rmem.mem_vaddr = (unsigned char *)
(unsigned long)(tcon_rmem.acc_lut_rmem.mem_paddr);
if ((lcd_debug_print_flag & LCD_DBG_PR_NORMAL) && tcon_rmem.acc_lut_rmem.mem_size > 0)
LCDPR("tcon acc lut_paddr: 0x%08x, size: 0x%x\n",
tcon_rmem.acc_lut_rmem.mem_paddr,
tcon_rmem.acc_lut_rmem.mem_size);
return 0;
}
static int lcd_tcon_mm_table_config_v1(void)
{
if (tcon_mm_table.block_cnt > 32) {
LCDERR("%s: tcon data block_cnt %d invalid\n",
__func__, tcon_mm_table.block_cnt);
return -1;
}
if (tcon_mm_table.data_mem_vaddr)
return 0;
if (tcon_mm_table.block_cnt == 0) {
if (lcd_debug_print_flag & LCD_DBG_PR_NORMAL)
LCDPR("%s: block_cnt is zero\n", __func__);
return 0;
}
tcon_mm_table.data_mem_vaddr = (unsigned char **)malloc
(tcon_mm_table.block_cnt * sizeof(unsigned char *));
if (!tcon_mm_table.data_mem_vaddr) {
LCDERR("%s: Not enough memory\n", __func__);
return -1;
}
memset(tcon_mm_table.data_mem_vaddr, 0,
tcon_mm_table.block_cnt * sizeof(unsigned char *));
tcon_mm_table.data_priority = (struct tcon_data_priority_s *)malloc
(tcon_mm_table.block_cnt * sizeof(struct tcon_data_priority_s));
if (!tcon_mm_table.data_priority) {
LCDERR("%s: Not enough memory\n", __func__);
return -1;
}
memset(tcon_mm_table.data_priority, 0xff,
tcon_mm_table.block_cnt * sizeof(struct tcon_data_priority_s));
tcon_mm_table.data_size = (unsigned int *)malloc
(tcon_mm_table.block_cnt * sizeof(unsigned int));
if (!tcon_mm_table.data_size) {
LCDERR("%s: Not enough memory\n", __func__);
return -1;
}
memset(tcon_mm_table.data_size, 0,
tcon_mm_table.block_cnt * sizeof(unsigned int));
return 0;
}
static void lcd_tcon_axi_mem_config_tl1(void)
{
unsigned int size[3] = {4162560, 4162560, 1960440};
unsigned int total_size = 0, temp_size = 0;
int i;
for (i = 0; i < lcd_tcon_conf->axi_bank; i++)
total_size += size[i];
if (total_size > tcon_rmem.axi_mem_size) {
LCDERR("%s: tcon axi_mem size 0x%x is not enough, need 0x%x\n",
__func__, tcon_rmem.axi_mem_size, total_size);
return;
}
tcon_rmem.axi_rmem = (struct tcon_rmem_config_s *)
malloc(lcd_tcon_conf->axi_bank * sizeof(struct tcon_rmem_config_s));
if (!tcon_rmem.axi_rmem)
return;
memset(tcon_rmem.axi_rmem, 0,
lcd_tcon_conf->axi_bank * sizeof(struct tcon_rmem_config_s));
for (i = 0; i < lcd_tcon_conf->axi_bank; i++) {
tcon_rmem.axi_rmem[i].mem_paddr = tcon_rmem.axi_mem_paddr +
temp_size;
tcon_rmem.axi_rmem[i].mem_vaddr = (unsigned char *)
(unsigned long)tcon_rmem.axi_rmem[i].mem_paddr;
tcon_rmem.axi_rmem[i].mem_size = size[i];
temp_size += size[i];
}
}
static void lcd_tcon_axi_mem_config_t5(void)
{
unsigned int size[2] = {0x00800000, 0x100000};
unsigned int reg[2] = {0x261, 0x1a9};
unsigned int total_size = 0, temp_size = 0;
int i;
for (i = 0; i < lcd_tcon_conf->axi_bank; i++)
total_size += size[i];
if (total_size > tcon_rmem.axi_mem_size) {
LCDERR("%s: tcon axi_mem size 0x%x is not enough, need 0x%x\n",
__func__, tcon_rmem.axi_mem_size, total_size);
return;
}
temp_size = lcd_tcon_conf->axi_bank * sizeof(struct tcon_rmem_config_s);
tcon_rmem.axi_rmem = (struct tcon_rmem_config_s *)malloc(temp_size);
if (!tcon_rmem.axi_rmem)
return;
memset(tcon_rmem.axi_rmem, 0, temp_size);
temp_size = lcd_tcon_conf->axi_bank * sizeof(unsigned int);
lcd_tcon_conf->axi_reg = (unsigned int *)malloc(temp_size);
if (!lcd_tcon_conf->axi_reg) {
free(tcon_rmem.axi_rmem);
return;
}
memset(lcd_tcon_conf->axi_reg, 0, temp_size);
temp_size = 0;
for (i = 0; i < lcd_tcon_conf->axi_bank; i++) {
tcon_rmem.axi_rmem[i].mem_paddr = tcon_rmem.axi_mem_paddr + temp_size;
tcon_rmem.axi_rmem[i].mem_vaddr = (unsigned char *)
(unsigned long)tcon_rmem.axi_rmem[i].mem_paddr;
tcon_rmem.axi_rmem[i].mem_size = size[i];
temp_size += size[i];
lcd_tcon_conf->axi_reg[i] = reg[i];
}
}
static int lcd_tcon_mem_config(void)
{
unsigned char *mem_vaddr;
unsigned int max_size;
int ret;
/* reserved memory */
max_size = lcd_tcon_conf->axi_size + lcd_tcon_conf->bin_path_size;
if (tcon_rmem.rsv_mem_size < max_size) {
LCDERR("%s: tcon mem size 0x%x is not enough, need 0x%x\n",
__func__, tcon_rmem.rsv_mem_size, max_size);
return -1;
}
tcon_rmem.axi_mem_size = lcd_tcon_conf->axi_size;
tcon_rmem.axi_mem_paddr = tcon_rmem.rsv_mem_paddr;
if (lcd_debug_print_flag & LCD_DBG_PR_NORMAL)
LCDPR("tcon axi_mem paddr: 0x%08x, size: 0x%x\n",
tcon_rmem.axi_mem_paddr, tcon_rmem.axi_mem_size);
lcd_tcon_conf->tcon_axi_mem_config();
tcon_rmem.bin_path_rmem.mem_size = lcd_tcon_conf->bin_path_size;
tcon_rmem.bin_path_rmem.mem_paddr =
tcon_rmem.axi_mem_paddr + tcon_rmem.axi_mem_size;
/* don't set bin_path_rmem.mem_vaddr here */
if ((lcd_debug_print_flag & LCD_DBG_PR_NORMAL) && tcon_rmem.bin_path_rmem.mem_size > 0)
LCDPR("tcon bin_path paddr: 0x%08x, size: 0x%x\n",
tcon_rmem.bin_path_rmem.mem_paddr,
tcon_rmem.bin_path_rmem.mem_size);
/* default clear tcon rmem */
mem_vaddr = (unsigned char *)(unsigned long)(tcon_rmem.rsv_mem_paddr);
memset(mem_vaddr, 0, tcon_rmem.rsv_mem_size);
ret = lcd_tcon_bin_path_update(tcon_rmem.bin_path_rmem.mem_size);
if (ret)
return -1;
/* allocated memory, memory map table config */
if (lcd_debug_print_flag & LCD_DBG_PR_NORMAL)
LCDPR("tcon mm_table version: %d\n", tcon_mm_table.version);
if (tcon_mm_table.version == 0)
ret = lcd_tcon_mm_table_config_v0();
else
ret = lcd_tcon_mm_table_config_v1();
return ret;
}
static void lcd_tcon_config_axi_offset_default(void)
{
tcon_rmem.rsv_mem_paddr = env_get_ulong("tcon_mem_addr", 16, 0);
if (tcon_rmem.rsv_mem_paddr) {
tcon_rmem.rsv_mem_size = lcd_tcon_conf->rsv_mem_size;
LCDPR("get lcd_tcon mem_addr from default\n");
} else {
LCDERR("can't find env tcon_mem_addr\n");
}
}
static int lcd_tcon_load_init_data_from_unifykey(void)
{
int key_len, data_len, ret;
data_len = tcon_mm_table.core_reg_table_size;
if (!tcon_mm_table.core_reg_table) {
tcon_mm_table.core_reg_table = (unsigned char *)malloc
(sizeof(unsigned char) * data_len);
if (!tcon_mm_table.core_reg_table)
return -1;
}
memset(tcon_mm_table.core_reg_table, 0, (sizeof(unsigned char) * data_len));
key_len = data_len;
ret = lcd_unifykey_get_no_header("lcd_tcon",
tcon_mm_table.core_reg_table,
&key_len);
if (ret)
goto lcd_tcon_load_init_data_err;
if (key_len != data_len)
goto lcd_tcon_load_init_data_err;
LCDPR("tcon: load init data len: %d\n", data_len);
return 0;
lcd_tcon_load_init_data_err:
free(tcon_mm_table.core_reg_table);
tcon_mm_table.core_reg_table = NULL;
LCDERR("%s: !!!!!!tcon unifykey load error!!!!!!\n", __func__);
return -1;
}
static int lcd_tcon_load_init_data_from_unifykey_new(void)
{
int key_len, data_len;
unsigned char *buf, *p;
struct lcd_tcon_init_block_header_s *data_header;
int ret;
data_len = tcon_mm_table.core_reg_table_size + LCD_TCON_DATA_BLOCK_HEADER_SIZE;
buf = (unsigned char *)malloc(data_len * sizeof(unsigned char));
if (!buf)
return -1;
key_len = data_len;
ret = lcd_unifykey_get_tcon("lcd_tcon", buf, &key_len);
if (ret)
goto lcd_tcon_load_init_data_new_err;
if (key_len != data_len)
goto lcd_tcon_load_init_data_new_err;
data_header = (struct lcd_tcon_init_block_header_s *)buf;
if (lcd_debug_print_flag & LCD_DBG_PR_NORMAL) {
LCDPR("unifykey header:\n");
LCDPR("crc32 = 0x%08x\n", data_header->crc32);
LCDPR("block_size = %d\n", data_header->block_size);
LCDPR("chipid = %d\n", data_header->chipid);
LCDPR("name = %s\n", data_header->name);
}
data_len = tcon_mm_table.core_reg_table_size;
if (!tcon_mm_table.core_reg_table) {
tcon_mm_table.core_reg_table = (unsigned char *)
malloc(data_len * sizeof(unsigned char));
if (!tcon_mm_table.core_reg_table)
goto lcd_tcon_load_init_data_new_err;
memset(tcon_mm_table.core_reg_table, 0,
(sizeof(unsigned char) * data_len));
}
p = buf + LCD_TCON_DATA_BLOCK_HEADER_SIZE;
memcpy(tcon_mm_table.core_reg_table, p, data_len);
free(buf);
LCDPR("tcon: load init data len: %d\n", data_len);
return 0;
lcd_tcon_load_init_data_new_err:
free(buf);
LCDERR("%s: !!!!!!tcon unifykey load error!!!!!!\n", __func__);
return -1;
}
static int lcd_tcon_get_config(char *dt_addr, struct aml_lcd_drv_s *pdrv,
int load_id)
{
struct lcd_config_s *pconf = &pdrv->config;
int parent_offset, size;
char *propdata;
unsigned int mem_size;
if (load_id & 0x1) {
parent_offset = fdt_path_offset(dt_addr, "/reserved-memory");
size = fdt_address_cells(dt_addr, parent_offset);
parent_offset = fdt_path_offset(dt_addr, "/reserved-memory/linux,lcd_tcon");
if (parent_offset < 0) {
LCDERR("can't find node: /reserved-memory/linux,lcd_tcon\n");
} else {
propdata = (char *)fdt_getprop(dt_addr, parent_offset,
"alloc-ranges", NULL);
if (!propdata) {
LCDERR("failed to get lcd_tcon reserved-memory from dts\n");
lcd_tcon_config_axi_offset_default();
} else {
if (size == 2)
tcon_rmem.rsv_mem_paddr =
be32_to_cpup((((u32 *)propdata) + 1));
else
tcon_rmem.rsv_mem_paddr =
be32_to_cpup(((u32 *)propdata));
}
propdata = (char *)fdt_getprop(dt_addr, parent_offset,
"size", NULL);
if (!propdata) {
LCDERR("failed to get tcon size from dts\n");
lcd_tcon_config_axi_offset_default();
} else {
if (size == 2)
mem_size = be32_to_cpup((((u32 *)propdata) + 1));
else
mem_size = be32_to_cpup(((u32 *)propdata));
if (mem_size < lcd_tcon_conf->rsv_mem_size) {
LCDERR("tcon mem_size is not enough\n");
tcon_rmem.rsv_mem_paddr = 0;
tcon_rmem.flag = 0;
} else {
tcon_rmem.rsv_mem_size =
lcd_tcon_conf->rsv_mem_size;
}
}
}
} else {
lcd_tcon_config_axi_offset_default();
}
if (tcon_rmem.rsv_mem_paddr) {
tcon_rmem.flag = 1;
lcd_tcon_mem_config();
LCDPR("tcon: rsv_mem addr: 0x%x\n", tcon_rmem.rsv_mem_paddr);
}
tcon_mm_table.core_reg_table_size = lcd_tcon_conf->reg_table_len;
if (lcd_tcon_conf->core_reg_ver)
lcd_tcon_load_init_data_from_unifykey_new();
else
lcd_tcon_load_init_data_from_unifykey();
lcd_tcon_data_load(pdrv);
return 0;
}
static int lcd_tcon_core_flag(enum lcd_chip_e chip_type)
{
int ret = 0;
switch (chip_type) {
case LCD_CHIP_TL1:
case LCD_CHIP_TM2:
ret = (readl(TCON_CORE_FLAG_LIC2) >> 17) & 0x1;
break;
default:
break;
}
if (lcd_debug_print_flag & LCD_DBG_PR_NORMAL) {
if (ret)
LCDPR("%s: tcon invalid\n", __func__);
}
return ret;
}
/* **********************************
* tcon match data
* **********************************
*/
static struct lcd_tcon_config_s tcon_data_tl1 = {
.tcon_valid = 0,
.core_reg_ver = 0,
.core_reg_width = LCD_TCON_CORE_REG_WIDTH_TL1,
.reg_table_width = LCD_TCON_TABLE_WIDTH_TL1,
.reg_table_len = LCD_TCON_TABLE_LEN_TL1,
.core_reg_start = TCON_CORE_REG_START_TL1,
.reg_top_ctrl = TCON_TOP_CTRL,
.bit_en = BIT_TOP_EN_TL1,
.reg_core_od = REG_CORE_OD_TL1,
.bit_od_en = BIT_OD_EN_TL1,
.reg_ctrl_timing_base = REG_LCD_TCON_MAX,
.ctrl_timing_offset = CTRL_TIMING_OFFSET_TL1,
.ctrl_timing_cnt = CTRL_TIMING_CNT_TL1,
.axi_bank = LCD_TCON_AXI_BANK_TL1,
.rsv_mem_size = 0x00c00000, /* 12M */
.axi_size = 0x00a00000, /* 10M */
.bin_path_size = 0x00002800, /* 10K */
.vac_size = 0x00002000, /* 8K */
.demura_set_size = 0x00001000, /* 4K */
.demura_lut_size = 0x00120000, /* 1152K */
.acc_lut_size = 0x00001000, /* 4K */
.axi_reg = NULL,
.tcon_axi_mem_config = lcd_tcon_axi_mem_config_tl1,
.tcon_enable = lcd_tcon_enable_tl1,
};
static struct lcd_tcon_config_s tcon_data_t5 = {
.tcon_valid = 0,
.core_reg_ver = 1, /* new version with header */
.core_reg_width = LCD_TCON_CORE_REG_WIDTH_T5,
.reg_table_width = LCD_TCON_TABLE_WIDTH_T5,
.reg_table_len = LCD_TCON_TABLE_LEN_T5,
.core_reg_start = TCON_CORE_REG_START_T5,
.reg_top_ctrl = REG_LCD_TCON_MAX,
.bit_en = BIT_TOP_EN_T5,
.reg_core_od = REG_LCD_TCON_MAX,
.bit_od_en = BIT_OD_EN_T5,
.reg_ctrl_timing_base = REG_LCD_TCON_MAX,
.ctrl_timing_offset = CTRL_TIMING_OFFSET_T5,
.ctrl_timing_cnt = CTRL_TIMING_CNT_T5,
.axi_bank = LCD_TCON_AXI_BANK_T5,
.rsv_mem_size = 0x00c00000, /* 12M */
.axi_size = 0x00a00000, /* 9M */
.bin_path_size = 0x00002800, /* 10K */
.vac_size = 0,
.demura_set_size = 0,
.demura_lut_size = 0,
.acc_lut_size = 0,
.axi_reg = NULL,
.tcon_axi_mem_config = lcd_tcon_axi_mem_config_t5,
.tcon_enable = lcd_tcon_enable_t5,
};
static struct lcd_tcon_config_s tcon_data_t5d = {
.tcon_valid = 0,
.core_reg_ver = 1, /* new version with header */
.core_reg_width = LCD_TCON_CORE_REG_WIDTH_T5,
.reg_table_len = LCD_TCON_TABLE_LEN_T5,
.core_reg_start = TCON_CORE_REG_START_T5,
.reg_top_ctrl = REG_LCD_TCON_MAX,
.bit_en = BIT_TOP_EN_T5,
.reg_core_od = REG_LCD_TCON_MAX,
.bit_od_en = BIT_OD_EN_T5,
.reg_ctrl_timing_base = REG_LCD_TCON_MAX,
.ctrl_timing_offset = CTRL_TIMING_OFFSET_T5,
.ctrl_timing_cnt = CTRL_TIMING_CNT_T5,
.axi_bank = LCD_TCON_AXI_BANK_T5,
.rsv_mem_size = 0x00c00000, /* 12M */
.axi_size = 0x00a00000, /* 10M */
.bin_path_size = 0x00002800, /* 10K */
.vac_size = 0,
.demura_set_size = 0,
.demura_lut_size = 0,
.acc_lut_size = 0,
.tcon_axi_mem_config = lcd_tcon_axi_mem_config_t5,
.tcon_enable = lcd_tcon_enable_t5,
};
int lcd_tcon_probe(char *dt_addr, struct aml_lcd_drv_s *pdrv, int load_id)
{
int ret = 0;
struct lcd_config_s *pconf = &pdrv->config;
lcd_tcon_conf = NULL;
switch (pdrv->data->chip_type) {
case LCD_CHIP_TL1:
case LCD_CHIP_TM2:
if (lcd_tcon_core_flag(pdrv->data->chip_type) == 0)
lcd_tcon_conf = &tcon_data_tl1;
break;
case LCD_CHIP_T5:
case LCD_CHIP_T7:
lcd_tcon_conf = &tcon_data_t5;
break;
case LCD_CHIP_T5D:
lcd_tcon_conf = &tcon_data_t5d;
break;
default:
break;
}
if (!lcd_tcon_conf)
return 0;
switch (pconf->basic.lcd_type) {
case LCD_MLVDS:
lcd_tcon_conf->tcon_valid = 1;
break;
case LCD_P2P:
if (pdrv->data->chip_type == LCD_CHIP_T5D)
lcd_tcon_conf->tcon_valid = 0;
else
lcd_tcon_conf->tcon_valid = 1;
break;
default:
break;
}
if (lcd_tcon_conf->tcon_valid == 0)
return 0;
if (lcd_debug_print_flag & LCD_DBG_PR_NORMAL)
LCDPR("%s\n", __func__);
memset(&tcon_rmem, 0, sizeof(struct tcon_rmem_s));
memset(&tcon_mm_table, 0, sizeof(struct tcon_mem_map_table_s));
/*must before tcon_config, for memory alloc*/
lcd_tcon_spi_data_probe(pdrv);
ret = lcd_tcon_get_config(dt_addr, pdrv, load_id);
pdrv->tcon_reg_print = lcd_tcon_reg_readback_print;
pdrv->tcon_table_print = lcd_tcon_reg_table_print;
pdrv->tcon_vac_print = lcd_tcon_vac_print;
pdrv->tcon_demura_print = lcd_tcon_demura_print;
pdrv->tcon_acc_print = lcd_tcon_acc_print;
pdrv->tcon_data_print = lcd_tcon_data_print;
pdrv->tcon_reg_read = lcd_tcon_reg_read;
pdrv->tcon_reg_write = lcd_tcon_reg_write;
pdrv->tcon_table_read = lcd_tcon_table_read;
pdrv->tcon_table_write = lcd_tcon_table_write;
return ret;
}