blob: faaffced6e6bed3d8ebe57ff4afeb0927c0cae8b [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"
static void lcd_tcon_od_check_byte(struct lcd_tcon_config_s *tcon_conf,
unsigned char *table)
{
struct tcon_rmem_s *tcon_rmem = get_lcd_tcon_rmem();
unsigned int reg, bit;
if (tcon_conf->reg_core_od == REG_LCD_TCON_MAX)
return;
reg = tcon_conf->reg_core_od;
bit = tcon_conf->bit_od_en;
if (((table[reg] >> bit) & 1) == 0)
return;
if (tcon_rmem->flag == 0) {
table[reg] &= ~(1 << bit);
LCDPR("%s: invalid memory, disable od function\n", __func__);
}
}
static inline void lcd_tcon_od_check(struct lcd_tcon_config_s *tcon_conf,
unsigned int *table)
{
struct tcon_rmem_s *tcon_rmem = get_lcd_tcon_rmem();
unsigned int reg, bit;
if (tcon_conf->reg_core_od == REG_LCD_TCON_MAX)
return;
reg = tcon_conf->reg_core_od;
bit = tcon_conf->bit_od_en;
if (((table[reg] >> bit) & 1) == 0)
return;
if (tcon_rmem->flag == 0) {
table[reg] &= ~(1 << bit);
LCDPR("%s: invalid buf, disable od function\n", __func__);
}
}
static void lcd_tcon_core_reg_update(struct lcd_tcon_config_s *tcon_conf,
struct tcon_mem_map_table_s *mm_table)
{
unsigned char *table8;
unsigned int *table32;
unsigned int len, offset;
int i;
if (!mm_table->core_reg_table) {
LCDERR("%s: table is NULL\n", __func__);
return;
}
len = mm_table->core_reg_table_size;
offset = tcon_conf->core_reg_start;
if (tcon_conf->core_reg_width == 8) {
table8 = mm_table->core_reg_table;
lcd_tcon_od_check_byte(tcon_conf, table8);
for (i = offset; i < len; i++)
lcd_tcon_write_byte(i, table8[i]);
} else {
if (tcon_conf->reg_table_width == 32) {
len /= 4;
table32 = (unsigned int *)mm_table->core_reg_table;
lcd_tcon_od_check(tcon_conf, table32);
for (i = offset; i < len; i++)
lcd_tcon_write(i, table32[i]);
} else {
table8 = mm_table->core_reg_table;
lcd_tcon_od_check_byte(tcon_conf, table8);
for (i = offset; i < len; i++)
lcd_tcon_write(i, table8[i]);
}
}
LCDPR("tcon core regs update\n");
}
static void lcd_tcon_axi_rmem_set(struct lcd_tcon_config_s *tcon_conf)
{
struct tcon_rmem_s *tcon_rmem = get_lcd_tcon_rmem();
unsigned int paddr, i;
if (!tcon_conf)
return;
if (!tcon_rmem)
return;
if (lcd_debug_print_flag & LCD_DBG_PR_NORMAL)
LCDPR("%s\n", __func__);
if (tcon_rmem->flag == 0 || !tcon_rmem->axi_rmem) {
LCDERR("%s: invalid axi_mem\n", __func__);
return;
}
for (i = 0; i < tcon_conf->axi_bank; i++) {
paddr = tcon_rmem->axi_rmem[i].mem_paddr;
lcd_tcon_write(tcon_conf->axi_reg[i], paddr);
if (lcd_debug_print_flag & LCD_DBG_PR_NORMAL)
LCDPR("set tcon axi_mem[%d] paddr: 0x%08x\n", i, paddr);
}
}
static void lcd_tcon_vac_set_tl1(unsigned int demura_valid)
{
struct tcon_rmem_s *tcon_rmem = get_lcd_tcon_rmem();
int len, i, j, n;
unsigned int d0, d1, temp, dly0, dly1, set2;
unsigned char *buf;
buf = tcon_rmem->vac_rmem.mem_vaddr;
if (!buf) {
LCDERR("%s: vac_mem_vaddr is null\n", __func__);
return;
}
n = 8;
len = TCON_VAC_SET_PARAM_NUM;
dly0 = buf[n];
dly1 = buf[n + 2];
set2 = buf[n + 4];
n += (len * 2);
if (lcd_debug_print_flag & LCD_DBG_PR_ADV)
LCDPR("vac_set:0x%x, 0x%x, 0x%x\n", dly0, dly1, set2);
lcd_tcon_write_byte(0x0267, lcd_tcon_read_byte(0x0267) | 0xa0);
/*vac_cntl, 12pipe delay temp for pre_dt*/
lcd_tcon_write(0x2800, 0x807);
if (demura_valid) /* vac delay with demura */
lcd_tcon_write(0x2817, (0x1e | ((dly1 & 0xff) << 8)));
else /* vac delay without demura */
lcd_tcon_write(0x2817, (0x1e | ((dly0 & 0xff) << 8)));
len = TCON_VAC_LUT_PARAM_NUM;
if (lcd_debug_print_flag & LCD_DBG_PR_ADV)
LCDPR("%s: start write vac_ramt1~2\n", __func__);
/*write vac_ramt1: 8bit, 256 regs*/
for (i = 0; i < len; i++)
lcd_tcon_write_byte(0xa100 + i, buf[n + i * 2]);
for (i = 0; i < len; i++)
lcd_tcon_write_byte(0xa200 + i, buf[n + i * 2]);
/*write vac_ramt2: 8bit, 256 regs*/
n += (len * 2);
for (i = 0; i < len; i++)
lcd_tcon_write_byte(0xa300 + i, buf[n + i * 2]);
for (i = 0; i < len; i++)
lcd_tcon_write_byte(0xbc00 + i, buf[n + i * 2]);
if (lcd_debug_print_flag & LCD_DBG_PR_ADV)
LCDPR("%s: write vac_ramt1~2 ok\n", __func__);
for (i = 0; i < len; i++)
lcd_tcon_read_byte(0xbc00 + i);
if (lcd_debug_print_flag & LCD_DBG_PR_ADV)
LCDPR("%s: start write vac_ramt3\n", __func__);
/*write vac_ramt3_1~6: 24bit({data0[11:0],data1[11:0]},128 regs)*/
for (j = 0; j < 6; j++) {
n += (len * 2);
for (i = 0; i < (len >> 1); i++) {
d0 = (buf[n + (i * 4)] |
(buf[n + (i * 4 + 1)] << 8)) & 0xfff;
d1 = (buf[n + (i * 4 + 2)] |
(buf[n + (i * 4 + 3)] << 8)) & 0xfff;
temp = ((d0 << 12) | d1);
lcd_tcon_write((0x2900 + i + (j * 128)), temp);
}
}
if (lcd_debug_print_flag & LCD_DBG_PR_ADV)
LCDPR("%s: write vac_ramt3 ok\n", __func__);
for (i = 0; i < ((len >> 1) * 6); i++)
lcd_tcon_read(0x2900 + i);
lcd_tcon_write(0x2801, 0x0f000870); /* vac_size */
lcd_tcon_write(0x2802, (0x58e00d00 | (set2 & 0xff)));
lcd_tcon_write(0x2803, 0x80400058);
lcd_tcon_write(0x2804, 0x58804000);
lcd_tcon_write(0x2805, 0x80400000);
lcd_tcon_write(0x2806, 0xf080a032);
lcd_tcon_write(0x2807, 0x4c08a864);
lcd_tcon_write(0x2808, 0x10200000);
lcd_tcon_write(0x2809, 0x18200000);
lcd_tcon_write(0x280a, 0x18000004);
lcd_tcon_write(0x280b, 0x735244c2);
lcd_tcon_write(0x280c, 0x9682383d);
lcd_tcon_write(0x280d, 0x96469449);
lcd_tcon_write(0x280e, 0xaf363ce7);
lcd_tcon_write(0x280f, 0xc71fbb56);
lcd_tcon_write(0x2810, 0x953885a1);
lcd_tcon_write(0x2811, 0x7a7a7900);
lcd_tcon_write(0x2812, 0xc4640708);
lcd_tcon_write(0x2813, 0x4b14b08a);
lcd_tcon_write(0x2814, 0x4004b12c);
lcd_tcon_write(0x2815, 0x0);
/*vac_cntl,always read*/
lcd_tcon_write(0x2800, 0x381f);
LCDPR("tcon vac finish\n");
}
static int lcd_tcon_demura_set_tl1(void)
{
struct tcon_rmem_s *tcon_rmem = get_lcd_tcon_rmem();
unsigned char *data_buf;
unsigned int data_cnt, i;
if (!tcon_rmem->demura_set_rmem.mem_vaddr) {
LCDERR("%s: demura_set_mem_vaddr is null\n", __func__);
return -1;
}
if (lcd_tcon_getb_byte(0x23d, 0, 1) == 0) {
if (lcd_debug_print_flag & LCD_DBG_PR_ADV)
LCDPR("%s: demura function disabled\n", __func__);
return 0;
}
data_cnt = (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));
data_buf = &tcon_rmem->demura_set_rmem.mem_vaddr[8];
for (i = 0; i < data_cnt; i++)
lcd_tcon_write_byte(0x186, data_buf[i]);
LCDPR("tcon demura_set cnt %d\n", data_cnt);
return 0;
}
static int lcd_tcon_demura_lut_tl1(void)
{
struct tcon_rmem_s *tcon_rmem = get_lcd_tcon_rmem();
unsigned char *data_buf;
unsigned int data_cnt, i;
if (!tcon_rmem->demura_lut_rmem.mem_vaddr) {
LCDERR("%s: demura_lut_mem_vaddr is null\n", __func__);
return -1;
}
if (lcd_tcon_getb_byte(0x23d, 0, 1) == 0)
return 0;
/*disable demura when load lut data*/
lcd_tcon_setb_byte(0x23d, 0, 0, 1);
lcd_tcon_setb_byte(0x181, 1, 0, 1);
lcd_tcon_write_byte(0x182, 0x01);
lcd_tcon_write_byte(0x183, 0x86);
lcd_tcon_write_byte(0x184, 0x01);
lcd_tcon_write_byte(0x185, 0x87);
data_cnt = (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));
data_buf = &tcon_rmem->demura_lut_rmem.mem_vaddr[8];
/* fixed 2 byte 0 for border */
lcd_tcon_write_byte(0x187, 0);
lcd_tcon_write_byte(0x187, 0);
for (i = 0; i < data_cnt; i++)
lcd_tcon_write_byte(0x187, data_buf[i]);
/*enable demura when load lut data finished*/
lcd_tcon_setb_byte(0x23d, 1, 0, 1);
LCDPR("tcon demura_lut cnt %d\n", data_cnt);
if (lcd_debug_print_flag & LCD_DBG_PR_ADV)
LCDPR("tcon demura 0x23d = 0x%02x\n",
lcd_tcon_read_byte(0x23d));
return 0;
}
static int lcd_tcon_acc_lut_tl1(void)
{
struct tcon_rmem_s *tcon_rmem = get_lcd_tcon_rmem();
unsigned char *data_buf;
unsigned int data_cnt, i;
if (!tcon_rmem->acc_lut_rmem.mem_vaddr) {
LCDERR("%s: acc_lut_mem_vaddr is null\n", __func__);
return -1;
}
/* enable lut access, disable gamma en*/
lcd_tcon_setb_byte(0x262, 0x2, 0, 2);
/* write gamma lut */
data_cnt = (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));
if (data_cnt > 1161) { /* 0xb50~0xfd8, 1161 */
LCDPR("%s: data_cnt %d is invalid, force to 1161\n",
__func__, data_cnt);
data_cnt = 1161;
}
data_buf = &tcon_rmem->acc_lut_rmem.mem_vaddr[8];
for (i = 0; i < data_cnt; i++)
lcd_tcon_write_byte((0xb50 + i), data_buf[i]);
/* enable gamma */
lcd_tcon_setb_byte(0x262, 0x3, 0, 2);
LCDPR("tcon acc_lut cnt %d\n", data_cnt);
return 0;
}
void lcd_tcon_axi_rmem_lut_load(unsigned int index, unsigned char *buf,
unsigned int size)
{
struct tcon_rmem_s *tcon_rmem = get_lcd_tcon_rmem();
struct lcd_tcon_config_s *tcon_conf = get_lcd_tcon_config();
if (!tcon_rmem || !tcon_rmem->axi_rmem) {
LCDERR("axi_rmem is NULL\n");
return;
}
if (!tcon_conf)
return;
if (index > tcon_conf->axi_bank) {
LCDERR("axi_rmem index %d invalid\n", index);
return;
}
if (tcon_rmem->axi_rmem[index].mem_size < size) {
LCDERR("axi_mem[%d] size 0x%x is not enough, need 0x%x\n",
index, tcon_rmem->axi_rmem[index].mem_size, size);
return;
}
memcpy(tcon_rmem->axi_rmem[index].mem_vaddr, buf, size);
}
static int lcd_tcon_data_common_parse_set(unsigned char *data_buf,
struct lcd_tcon_data_block_header_s *block_header)
{
unsigned char *p;
unsigned short part_cnt;
unsigned char part_type;
unsigned int size, reg, data, mask, temp, reg_base = 0;
struct lcd_tcon_config_s *tcon_conf = get_lcd_tcon_config();
struct lcd_tcon_data_block_ext_header_s *ext_header;
union lcd_tcon_data_part_u data_part;
unsigned int data_offset, offset, i, j, k, d, m, n, step = 0;
unsigned int reg_cnt, reg_byte, data_cnt, data_byte;
int ret;
if (tcon_conf)
reg_base = tcon_conf->core_reg_start;
p = data_buf + LCD_TCON_DATA_BLOCK_HEADER_SIZE;
ext_header = (struct lcd_tcon_data_block_ext_header_s *)p;
part_cnt = ext_header->part_cnt;
if (lcd_debug_print_flag & LCD_DBG_PR_NORMAL)
LCDPR("%s: part_cnt: %d\n", __func__, part_cnt);
data_offset = LCD_TCON_DATA_BLOCK_HEADER_SIZE +
block_header->ext_header_size;
size = 0;
for (i = 0; i < part_cnt; i++) {
p = data_buf + data_offset;
part_type = p[LCD_TCON_DATA_PART_NAME_SIZE + 3];
if (lcd_debug_print_flag & LCD_DBG_PR_ADV) {
LCDPR("%s: start step %d, %s, type=0x%02x\n",
__func__, step, p, part_type);
}
switch (part_type) {
case LCD_TCON_DATA_PART_TYPE_WR_N:
data_part.wr_n = (struct lcd_tcon_data_part_wr_n_s *)p;
offset = LCD_TCON_DATA_PART_WR_N_SIZE_PRE;
size = offset +
(data_part.wr_n->reg_cnt * data_part.wr_n->reg_addr_byte) +
(data_part.wr_n->data_cnt * data_part.wr_n->reg_data_byte);
if ((size + data_offset) > block_header->block_size)
goto lcd_tcon_data_common_parse_set_err_size;
reg_cnt = data_part.wr_n->reg_cnt;
reg_byte = data_part.wr_n->reg_addr_byte;
m = offset; /* for reg */
n = m + (reg_cnt * reg_byte); /* for data */
for (j = 0; j < reg_cnt; j++) {
reg = 0;
for (d = 0; d < reg_byte; d++)
reg |= (p[m + d] << (d * 8));
if (reg < reg_base)
goto
lcd_tcon_data_common_parse_set_err_reg;
if (data_part.wr_n->reg_inc) {
for (k = 0;
k < data_part.wr_n->data_cnt;
k++) {
data = 0;
for (d = 0;
d < data_part.wr_n->reg_data_byte;
d++)
data |= (p[n + d] << (d * 8));
if (data_part.wr_n->reg_data_byte == 1)
lcd_tcon_write_byte((reg + k),
data);
else
lcd_tcon_write((reg + k), data);
n += data_part.wr_n->reg_data_byte;
}
} else {
for (k = 0;
k < data_part.wr_n->data_cnt;
k++) {
data = 0;
for (d = 0;
d < data_part.wr_n->reg_data_byte;
d++)
data |= (p[n + d] << (d * 8));
if (data_part.wr_n->reg_data_byte == 1)
lcd_tcon_write_byte(reg, data);
else
lcd_tcon_write(reg, data);
n += data_part.wr_n->reg_data_byte;
}
}
m += reg_byte;
}
break;
case LCD_TCON_DATA_PART_TYPE_WR_DDR:
data_part.wr_ddr =
(struct lcd_tcon_data_part_wr_ddr_s *)p;
offset = LCD_TCON_DATA_PART_WR_DDR_SIZE_PRE;
m = data_part.wr_ddr->data_cnt *
data_part.wr_ddr->data_byte;
size = offset + m;
if ((size + data_offset) > block_header->block_size)
goto lcd_tcon_data_common_parse_set_err_size;
n = data_part.wr_ddr->axi_buf_id;
lcd_tcon_axi_rmem_lut_load(n, &p[offset], m);
break;
case LCD_TCON_DATA_PART_TYPE_WR_MASK:
data_part.wr_mask =
(struct lcd_tcon_data_part_wr_mask_s *)p;
offset = LCD_TCON_DATA_PART_WR_MASK_SIZE_PRE;
size = offset + data_part.wr_mask->reg_addr_byte +
(2 * data_part.wr_mask->reg_data_byte);
if ((size + data_offset) > block_header->block_size)
goto lcd_tcon_data_common_parse_set_err_size;
reg_byte = data_part.wr_mask->reg_addr_byte;
data_byte = data_part.wr_mask->reg_data_byte;
m = offset; /* for reg */
n = m + reg_byte; /* for data */
reg = 0;
for (d = 0; d < reg_byte; d++)
reg |= (p[m + d] << (d * 8));
if (reg < reg_base)
goto lcd_tcon_data_common_parse_set_err_reg;
mask = 0;
for (d = 0; d < data_byte; d++)
mask |= (p[n + d] << (d * 8));
n += data_byte;
data = 0;
for (d = 0; d < data_byte; d++)
data |= (p[n + d] << (d * 8));
if (data_byte == 1)
lcd_tcon_update_bits_byte(reg, mask, data);
else
lcd_tcon_update_bits(reg, mask, data);
break;
case LCD_TCON_DATA_PART_TYPE_RD_MASK:
data_part.rd_mask =
(struct lcd_tcon_data_part_rd_mask_s *)p;
offset = LCD_TCON_DATA_PART_RD_MASK_SIZE_PRE;
size = offset + data_part.rd_mask->reg_addr_byte +
data_part.rd_mask->reg_data_byte;
if ((size + data_offset) > block_header->block_size)
goto lcd_tcon_data_common_parse_set_err_size;
reg_byte = data_part.rd_mask->reg_addr_byte;
data_byte = data_part.rd_mask->reg_data_byte;
m = offset; /* for reg */
n = m + reg_byte; /* for data */
reg = 0;
for (d = 0; d < reg_byte; d++)
reg |= (p[m + d] << (d * 8));
if (reg < reg_base)
goto lcd_tcon_data_common_parse_set_err_reg;
mask = 0;
for (d = 0; d < data_byte; d++)
mask |= (p[n + d] << (d * 8));
if (data_byte == 1) {
data = lcd_tcon_read_byte(reg) & mask;
if (lcd_debug_print_flag & LCD_DBG_PR_ADV) {
LCDPR("%s: read reg 0x%04x = 0x%02x, mask = 0x%02x\n",
__func__, reg, data, mask);
}
} else {
data = lcd_tcon_read(reg) & mask;
if (lcd_debug_print_flag & LCD_DBG_PR_ADV) {
LCDPR("%s: read reg 0x%04x = 0x%08x, mask = 0x%08x\n",
__func__, reg, data, mask);
}
}
break;
case LCD_TCON_DATA_PART_TYPE_CHK_WR_MASK:
data_part.chk_wr_mask =
(struct lcd_tcon_data_part_chk_wr_mask_s *)p;
offset = LCD_TCON_DATA_PART_CHK_WR_MASK_SIZE_PRE;
//include mask
size = offset + data_part.chk_wr_mask->reg_chk_addr_byte +
data_part.chk_wr_mask->reg_chk_data_byte *
(data_part.chk_wr_mask->data_chk_cnt + 1) +
data_part.chk_wr_mask->reg_wr_addr_byte +
data_part.chk_wr_mask->reg_wr_data_byte *
(data_part.chk_wr_mask->data_chk_cnt + 2);
if ((size + data_offset) > block_header->block_size)
goto lcd_tcon_data_common_parse_set_err_size;
reg_byte = data_part.chk_wr_mask->reg_chk_addr_byte;
data_cnt = data_part.chk_wr_mask->data_chk_cnt;
data_byte = data_part.chk_wr_mask->reg_chk_data_byte;
m = offset; /* for reg */
n = m + reg_byte; /* for data */
reg = 0;
for (d = 0; d < reg_byte; d++)
reg |= (p[m + d] << (d * 8));
if (reg < reg_base)
goto lcd_tcon_data_common_parse_set_err_reg;
mask = 0;
for (d = 0; d < data_byte; d++)
mask |= (p[n + d] << (d * 8));
if (data_byte == 1)
temp = lcd_tcon_read_byte(reg) & mask;
else
temp = lcd_tcon_read(reg) & mask;
n += data_byte;
for (j = 0; j < data_cnt; j++) {
data = 0;
for (d = 0; d < data_byte; d++)
data |= (p[n + d] << (d * 8));
if ((data & mask) == temp)
break;
n += data_byte;
}
k = j;
/* for reg */
m = offset + reg_byte + data_byte * (data_cnt + 1);
/* for data */
n = m + data_part.chk_wr_mask->reg_wr_addr_byte;
reg_byte = data_part.chk_wr_mask->reg_wr_addr_byte;
data_byte = data_part.chk_wr_mask->reg_wr_data_byte;
reg = 0;
for (d = 0; d < reg_byte; d++)
reg |= (p[m + d] << (d * 8));
if (reg < reg_base)
goto lcd_tcon_data_common_parse_set_err_reg;
mask = 0;
for (d = 0; d < data_byte; d++)
mask |= (p[n + d] << (d * 8));
n += data_byte;
n += data_byte * k;
data = 0;
for (d = 0; d < data_byte; d++)
data |= (p[n + d] << (d * 8));
if (data_byte == 1)
lcd_tcon_update_bits_byte(reg, mask, data);
else
lcd_tcon_update_bits(reg, mask, data);
break;
case LCD_TCON_DATA_PART_TYPE_CHK_EXIT:
data_part.chk_exit =
(struct lcd_tcon_data_part_chk_exit_s *)p;
offset = LCD_TCON_DATA_PART_CHK_EXIT_SIZE_PRE;
size = offset + data_part.chk_exit->reg_addr_byte +
(2 * data_part.chk_exit->reg_data_byte);
if ((size + data_offset) > block_header->block_size)
goto lcd_tcon_data_common_parse_set_err_size;
reg_byte = data_part.chk_exit->reg_addr_byte;
data_byte = data_part.chk_exit->reg_data_byte;
m = offset; /* for reg */
n = m + reg_byte; /* for data */
reg = 0;
for (d = 0; d < reg_byte; d++)
reg |= (p[m + d] << (d * 8));
if (reg < reg_base)
goto lcd_tcon_data_common_parse_set_err_reg;
mask = 0;
for (d = 0; d < data_byte; d++)
mask |= (p[n + d] << (d * 8));
n += data_byte;
data = 0;
for (d = 0; d < data_byte; d++)
data |= (p[n + d] << (d * 8));
if (data_byte == 1)
ret = lcd_tcon_check_bits_byte(reg, mask, data);
else
ret = lcd_tcon_check_bits(reg, mask, data);
if (ret) {
LCDPR("%s: block %s data_part %d check exit\n",
__func__, block_header->name, i);
return 0;
}
break;
case LCD_TCON_DATA_PART_TYPE_DELAY:
data_part.delay = (struct lcd_tcon_data_part_delay_s *)p;
size = LCD_TCON_DATA_PART_DELAY_SIZE;
if ((size + data_offset) > block_header->block_size)
goto lcd_tcon_data_common_parse_set_err_size;
if (data_part.delay->delay_us > 1000) {
m = data_part.delay->delay_us / 1000;
n = data_part.delay->delay_us % 1000;
mdelay(m);
if (n)
udelay(n);
}
break;
case LCD_TCON_DATA_PART_TYPE_PARAM:
data_part.param =
(struct lcd_tcon_data_part_param_s *)p;
offset = LCD_TCON_DATA_PART_PARAM_SIZE_PRE;
size = offset + data_part.param->param_size;
if ((size + data_offset) > block_header->block_size)
goto lcd_tcon_data_common_parse_set_err_size;
break;
default:
LCDERR("%s: unsupport part type 0x%02x\n",
__func__, part_type);
break;
}
if (lcd_debug_print_flag & LCD_DBG_PR_ADV) {
LCDPR("%s: end step %d, %s, type=0x%02x, size=%d\n",
__func__, step, p, part_type, size);
}
data_offset += size;
step++;
}
return 0;
lcd_tcon_data_common_parse_set_err_reg:
LCDERR("%s: block %s step %d reg 0x%04x error\n",
__func__, block_header->name, step, reg);
return -1;
lcd_tcon_data_common_parse_set_err_size:
LCDERR("%s: block %s step %d size error\n",
__func__, block_header->name, step);
return -1;
}
static int lcd_tcon_data_set(struct tcon_mem_map_table_s *mm_table)
{
struct lcd_tcon_data_block_header_s block_header;
unsigned char *data_buf;
unsigned int temp_crc32;
int i;
if (!mm_table->data_mem_vaddr) {
if (lcd_debug_print_flag & LCD_DBG_PR_NORMAL)
LCDPR("%s: no data_mem, exit\n", __func__);
return 0;
}
if (!mm_table->data_priority) {
LCDERR("%s: data_priority is null\n", __func__);
return -1;
}
for (i = 0; i < mm_table->block_cnt; i++) {
if (mm_table->data_priority[i].index >= mm_table->block_cnt ||
mm_table->data_priority[i].priority == 0xff) {
LCDERR("%s: data index or priority is invalid\n",
__func__);
return -1;
}
data_buf =
mm_table->data_mem_vaddr[mm_table->data_priority[i].index];
if (!data_buf) {
LCDERR("%s: data %d buf is null\n",
__func__, mm_table->data_priority[i].index);
return -1;
}
memcpy(&block_header, data_buf,
LCD_TCON_DATA_BLOCK_HEADER_SIZE);
temp_crc32 = crc32(0, &data_buf[4],
(block_header.block_size - 4));
if (temp_crc32 != block_header.crc32) {
LCDERR("%s: block %d, %s data crc error\n",
__func__, mm_table->data_priority[i].index,
block_header.name);
continue;
}
if (lcd_debug_print_flag & LCD_DBG_PR_NORMAL) {
LCDPR("%s: block %d, %s, init_priority %d: block_size=0x%x, block_type=0x%02x(%s)\n",
__func__, mm_table->data_priority[i].index,
block_header.name,
mm_table->data_priority[i].priority,
block_header.block_size,
block_header.block_type,
block_header.name);
}
lcd_tcon_data_common_parse_set(data_buf, &block_header);
}
LCDPR("%s finish\n", __func__);
return 0;
}
static int lcd_tcon_top_set_tl1(struct lcd_config_s *pconf)
{
struct tcon_rmem_s *tcon_rmem = get_lcd_tcon_rmem();
unsigned int axi_reg[3] = {0x200c, 0x2013, 0x2014};
unsigned int paddr;
int i;
if (lcd_debug_print_flag & LCD_DBG_PR_NORMAL)
LCDPR("%s\n", __func__);
if (tcon_rmem->flag) {
if (!tcon_rmem->axi_rmem) {
LCDERR("%s: invalid axi_mem\n", __func__);
} else {
for (i = 0; i < 3; i++) {
paddr = tcon_rmem->axi_rmem[i].mem_paddr;
lcd_tcon_write(axi_reg[i], paddr);
LCDPR("set tcon axi_mem paddr[%d]: 0x%08x\n",
i, paddr);
}
}
}
lcd_tcon_write(TCON_CLK_CTRL, 0x001f);
if (pconf->basic.lcd_type == LCD_P2P) {
switch (pconf->control.p2p_cfg.p2p_type) {
case P2P_CHPI:
case P2P_USIT:
lcd_tcon_write(TCON_TOP_CTRL, 0x8199);
break;
default:
lcd_tcon_write(TCON_TOP_CTRL, 0x8999);
break;
}
} else {
lcd_tcon_write(TCON_TOP_CTRL, 0x8999);
}
lcd_tcon_write(TCON_PLLLOCK_CNTL, 0x0037);
lcd_tcon_write(TCON_RST_CTRL, 0x003f);
lcd_tcon_write(TCON_RST_CTRL, 0x0000);
lcd_tcon_write(TCON_DDRIF_CTRL0, 0x33fff000);
lcd_tcon_write(TCON_DDRIF_CTRL1, 0x300300);
return 0;
}
static int lcd_tcon_top_set_t5(struct lcd_config_s *pconf)
{
if (lcd_debug_print_flag & LCD_DBG_PR_NORMAL)
LCDPR("lcd tcon top set\n");
lcd_tcon_write(TCON_CLK_CTRL, 0x001f);
if (pconf->basic.lcd_type == LCD_P2P) {
switch (pconf->control.p2p_cfg.p2p_type) {
case P2P_CHPI:
case P2P_USIT:
lcd_tcon_write(TCON_TOP_CTRL, 0x8399);
break;
default:
lcd_tcon_write(TCON_TOP_CTRL, 0x8b99);
break;
}
} else {
lcd_tcon_write(TCON_TOP_CTRL, 0x8b99);
}
lcd_tcon_write(TCON_PLLLOCK_CNTL, 0x0037);
lcd_tcon_write(TCON_RST_CTRL, 0x003f);
lcd_tcon_write(TCON_RST_CTRL, 0x0000);
lcd_tcon_write(TCON_DDRIF_CTRL0, 0x33fff000);
lcd_tcon_write(TCON_DDRIF_CTRL1, 0x300300);
return 0;
}
int lcd_tcon_enable_tl1(struct aml_lcd_drv_s *pdrv)
{
struct lcd_config_s *pconf = &pdrv->config;
struct lcd_tcon_config_s *tcon_conf = get_lcd_tcon_config();
struct tcon_mem_map_table_s *mm_table = get_lcd_tcon_mm_table();
int ret;
ret = lcd_tcon_valid_check();
if (ret)
return -1;
/* step 1: tcon top */
lcd_tcon_top_set_tl1(pconf);
/* step 2: tcon_core_reg_update */
lcd_tcon_core_reg_update(tcon_conf, mm_table);
if (pconf->basic.lcd_type == LCD_P2P) {
switch (pconf->control.p2p_cfg.p2p_type) {
case P2P_CHPI:
lcd_phy_tcon_chpi_bbc_init_tl1(pconf);
break;
default:
break;
}
}
if (mm_table->valid_flag & LCD_TCON_DATA_VALID_DEMURA) {
if (!mm_table->valid_flag & LCD_TCON_DATA_VALID_VAC) {
/*enable gamma*/
lcd_tcon_setb_byte(0x262, 0x3, 0, 2);
}
} else {
/*enable gamma*/
lcd_tcon_setb_byte(0x262, 0x3, 0, 2);
}
if (mm_table->version == 0) {
if (mm_table->valid_flag & LCD_TCON_DATA_VALID_VAC) {
if (mm_table->valid_flag & LCD_TCON_DATA_VALID_DEMURA)
lcd_tcon_vac_set_tl1(1);
else
lcd_tcon_vac_set_tl1(0);
}
if (mm_table->valid_flag & LCD_TCON_DATA_VALID_DEMURA) {
lcd_tcon_demura_set_tl1();
lcd_tcon_demura_lut_tl1();
}
if (mm_table->valid_flag & LCD_TCON_DATA_VALID_ACC)
lcd_tcon_acc_lut_tl1();
} else {
lcd_tcon_data_set(mm_table);
}
/* step 3: tcon_top_output_set */
lcd_tcon_write(TCON_OUT_CH_SEL1, 0xba98); /* out swap for ch8~11 */
return 0;
}
int lcd_tcon_enable_t5(struct aml_lcd_drv_s *pdrv)
{
struct lcd_config_s *pconf = &pdrv->config;
struct lcd_tcon_config_s *tcon_conf = get_lcd_tcon_config();
struct tcon_mem_map_table_s *mm_table = get_lcd_tcon_mm_table();
int ret;
ret = lcd_tcon_valid_check();
if (ret)
return -1;
if (!tcon_conf)
return -1;
if (!mm_table)
return -1;
/* step 1: tcon top */
lcd_tcon_top_set_t5(pconf);
/* step 2: tcon_core_reg_update */
lcd_tcon_core_reg_update(tcon_conf, mm_table);
/* step 3: set axi rmem, must before tcon data */
lcd_tcon_axi_rmem_set(tcon_conf);
/* step 4: tcon data set */
if (mm_table->version)
lcd_tcon_data_set(mm_table);
/* step 5: tcon_top_output_set */
lcd_tcon_write(TCON_OUT_CH_SEL0, 0x76543210);
lcd_tcon_write(TCON_OUT_CH_SEL1, 0xba98);
return 0;
}