blob: 3462f0884480e3727bd0ff5e216bb6b9e778c4b5 [file] [log] [blame]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <linux/init.h>
#include <linux/version.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/reset.h>
#include "lcd_common.h"
#include "lcd_reg.h"
#include "lcd_tcon.h"
static void lcd_tcon_core_reg_pre_od(struct lcd_tcon_config_s *tcon_conf,
struct tcon_mem_map_table_s *mm_table)
{
struct tcon_rmem_s *tcon_rmem = get_lcd_tcon_rmem();
unsigned char *table8;
unsigned int *table32;
unsigned int reg, bit, en = 0;
if (!mm_table || !mm_table->core_reg_table) {
LCDERR("%s: table is NULL\n", __func__);
return;
}
if (tcon_conf->reg_core_od == REG_LCD_TCON_MAX)
return;
reg = tcon_conf->reg_core_od;
bit = tcon_conf->bit_od_en;
if (tcon_conf->core_reg_width == 8) {
table8 = mm_table->core_reg_table;
if (((table8[reg] >> bit) & 1) == 0)
return;
if (!tcon_rmem) {
en = 0;
} else {
if (tcon_rmem->flag == 0)
en = 0;
else
en = 1;
}
if (en == 0) {
table8[reg] &= ~(1 << bit);
LCDPR("%s: invalid buf, disable od function\n",
__func__);
}
} else {
table32 = (unsigned int *)mm_table->core_reg_table;
if (((table32[reg] >> bit) & 1) == 0)
return;
if (!tcon_rmem) {
en = 0;
} else {
if (tcon_rmem->flag == 0)
en = 0;
else
en = 1;
}
if (en == 0) {
table32[reg] &= ~(1 << bit);
LCDPR("%s: invalid buf, disable od function\n",
__func__);
}
}
}
static void lcd_tcon_core_reg_pre_dis_od(struct lcd_tcon_config_s *tcon_conf,
struct tcon_mem_map_table_s *mm_table)
{
unsigned char *table8;
unsigned int *table32;
unsigned int reg, bit;
if (!mm_table || !mm_table->core_reg_table) {
LCDERR("%s: table is NULL\n", __func__);
return;
}
if (tcon_conf->reg_core_od == REG_LCD_TCON_MAX)
return;
reg = tcon_conf->reg_core_od;
bit = tcon_conf->bit_od_en;
if (tcon_conf->core_reg_width == 8) {
table8 = mm_table->core_reg_table;
table8[reg] &= ~(1 << bit);
} else {
table32 = (unsigned int *)mm_table->core_reg_table;
table32[reg] &= ~(1 << bit);
}
}
void lcd_tcon_core_reg_set(struct aml_lcd_drv_s *pdrv,
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, ret;
ret = lcd_tcon_valid_check();
if (ret)
return;
if (!mm_table || !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;
for (i = offset; i < len; i++)
lcd_tcon_write_byte(pdrv, i, table8[i]);
} else {
if (tcon_conf->reg_table_width == 32) {
table32 = (unsigned int *)mm_table->core_reg_table;
len /= 4;
for (i = offset; i < len; i++)
lcd_tcon_write(pdrv, i, table32[i]);
} else {
table8 = mm_table->core_reg_table;
for (i = offset; i < len; i++)
lcd_tcon_write(pdrv, i, table8[i]);
}
}
LCDPR("%s\n", __func__);
}
static void lcd_tcon_axi_rmem_set(struct aml_lcd_drv_s *pdrv,
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(pdrv, tcon_conf->axi_reg[i], paddr);
if (lcd_debug_print_flag & LCD_DBG_PR_NORMAL) {
LCDPR("set tcon axi_mem[%d] reg: 0x%08x, paddr: 0x%08x\n",
i, tcon_conf->axi_reg[i], paddr);
}
}
}
static void lcd_tcon_vac_set_tl1(struct aml_lcd_drv_s *pdrv, unsigned int demura_valid)
{
struct tcon_rmem_s *tcon_rmem = get_lcd_tcon_rmem();
int len, i, j, n;
unsigned int d0, d1, temp, set0, set1, set2;
unsigned char *buf = NULL;
if (!tcon_rmem)
return;
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;
set0 = buf[n];
set1 = 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", set0, set1, set2);
lcd_tcon_write_byte(pdrv, 0x0267, lcd_tcon_read_byte(pdrv, 0x0267) | 0xa0);
/*vac_cntl, 12pipe delay temp for pre_dt*/
lcd_tcon_write(pdrv, 0x2800, 0x807);
if (demura_valid)
lcd_tcon_write(pdrv, 0x2817, (0x1e | ((set1 & 0xff) << 8)));
else
lcd_tcon_write(pdrv, 0x2817, (0x1e | ((set0 & 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(pdrv, 0xa100 + i, buf[n + i * 2]);
for (i = 0; i < len; i++)
lcd_tcon_write_byte(pdrv, 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(pdrv, 0xa300 + i, buf[n + i * 2]);
for (i = 0; i < len; i++)
lcd_tcon_write_byte(pdrv, 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(pdrv, 0xbc00 + i);
if (lcd_debug_print_flag & LCD_DBG_PR_ADV)
LCDPR("%s: start write vac_ramt3\n", __func__);
/*write vac_ramt3_1~6: 16bit({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(pdrv, (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(pdrv, 0x2900 + i);
lcd_tcon_write(pdrv, 0x2801, 0x0f000870); /* vac_size */
lcd_tcon_write(pdrv, 0x2802, (0x58e00d00 | (set2 & 0xff)));
lcd_tcon_write(pdrv, 0x2803, 0x80400058);
lcd_tcon_write(pdrv, 0x2804, 0x58804000);
lcd_tcon_write(pdrv, 0x2805, 0x80400000);
lcd_tcon_write(pdrv, 0x2806, 0xf080a032);
lcd_tcon_write(pdrv, 0x2807, 0x4c08a864);
lcd_tcon_write(pdrv, 0x2808, 0x10200000);
lcd_tcon_write(pdrv, 0x2809, 0x18200000);
lcd_tcon_write(pdrv, 0x280a, 0x18000004);
lcd_tcon_write(pdrv, 0x280b, 0x735244c2);
lcd_tcon_write(pdrv, 0x280c, 0x9682383d);
lcd_tcon_write(pdrv, 0x280d, 0x96469449);
lcd_tcon_write(pdrv, 0x280e, 0xaf363ce7);
lcd_tcon_write(pdrv, 0x280f, 0xc71fbb56);
lcd_tcon_write(pdrv, 0x2810, 0x953885a1);
lcd_tcon_write(pdrv, 0x2811, 0x7a7a7900);
lcd_tcon_write(pdrv, 0x2812, 0xc4640708);
lcd_tcon_write(pdrv, 0x2813, 0x4b14b08a);
lcd_tcon_write(pdrv, 0x2814, 0x4004b12c);
lcd_tcon_write(pdrv, 0x2815, 0x0);
/*vac_cntl,always read*/
lcd_tcon_write(pdrv, 0x2800, 0x381f);
LCDPR("tcon vac finish\n");
}
static int lcd_tcon_demura_set_tl1(struct aml_lcd_drv_s *pdrv)
{
struct tcon_rmem_s *tcon_rmem = get_lcd_tcon_rmem();
unsigned char *data_buf;
unsigned int data_cnt, i;
if (!tcon_rmem || !tcon_rmem->demura_set_rmem.mem_vaddr) {
LCDERR("%s: demura_set_mem_vaddr is null\n", __func__);
return -1;
}
if (lcd_tcon_getb_byte(pdrv, 0x23d, 0, 1) == 0) {
if (lcd_debug_print_flag & LCD_DBG_PR_ADV)
LCDPR("%s: demura function disabled\n", __func__);
return 0;
}
if (lcd_debug_print_flag & LCD_DBG_PR_ADV) {
for (i = 0; i < 30; i++)
LCDPR("demura_set data[%d]: 0x%x\n",
i, tcon_rmem->demura_set_rmem.mem_vaddr[i]);
}
/*demura_setting:
* 8byte chk_data + demura_set_data: 161byte
*/
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(pdrv, 0x186, data_buf[i]);
LCDPR("tcon demura_set cnt %d\n", data_cnt);
return 0;
}
static int lcd_tcon_demura_lut_tl1(struct aml_lcd_drv_s *pdrv)
{
struct tcon_rmem_s *tcon_rmem = get_lcd_tcon_rmem();
unsigned char *data_buf;
unsigned int data_cnt, i;
if (!tcon_rmem || !tcon_rmem->demura_lut_rmem.mem_vaddr) {
LCDERR("%s: demura_lut_mem_vaddr is null\n", __func__);
return -1;
}
if (lcd_tcon_getb_byte(pdrv, 0x23d, 0, 1) == 0) {
if (lcd_debug_print_flag & LCD_DBG_PR_ADV)
LCDPR("%s: demura function disabled\n", __func__);
return 0;
}
/*disable demura when load lut data*/
lcd_tcon_setb_byte(pdrv, 0x23d, 0, 0, 1);
lcd_tcon_setb_byte(pdrv, 0x181, 1, 0, 1);
lcd_tcon_write_byte(pdrv, 0x182, 0x01);
lcd_tcon_write_byte(pdrv, 0x183, 0x86);
lcd_tcon_write_byte(pdrv, 0x184, 0x01);
lcd_tcon_write_byte(pdrv, 0x185, 0x87);
if (lcd_debug_print_flag & LCD_DBG_PR_ADV) {
for (i = 0; i < 30; i++)
LCDPR("demura_lut data[%d]: 0x%x\n",
i, tcon_rmem->demura_lut_rmem.mem_vaddr[i]);
}
/*demura_lut is
*chk_data: 8byte + demura_lut_data: 391053byte
*/
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(pdrv, 0x187, 0);
lcd_tcon_write_byte(pdrv, 0x187, 0);
for (i = 0; i < data_cnt; i++)
lcd_tcon_write_byte(pdrv, 0x187, data_buf[i]);
/*enable demura when load lut data finished*/
lcd_tcon_setb_byte(pdrv, 0x23d, 1, 0, 1);
LCDPR("tcon demura_lut cnt %d\n", data_cnt);
LCDPR("lcd_tcon 0x23d = 0x%02x\n", lcd_tcon_read_byte(pdrv, 0x23d));
return 0;
}
static int lcd_tcon_acc_lut_tl1(struct aml_lcd_drv_s *pdrv)
{
struct tcon_rmem_s *tcon_rmem = get_lcd_tcon_rmem();
unsigned char *data_buf;
unsigned int data_cnt, i;
if (!tcon_rmem || !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(pdrv, 0x262, 0x2, 0, 2);
/* write gamma lut */
/*acc_lut is
*chk_data: 8byte + acc_lut_data: 1158byte
*/
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(pdrv, (0xb50 + i), data_buf[i]);
/* enable gamma */
lcd_tcon_setb_byte(pdrv, 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();
unsigned char *p;
unsigned int span = 0, remain = 0, count = 0;
unsigned long paddr, phys;
void *vaddr = NULL;
unsigned int highmem_flag = 0;
int i;
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;
}
paddr = tcon_rmem->axi_rmem[index].mem_paddr;
highmem_flag = PageHighMem(phys_to_page(paddr));
if (highmem_flag == 0) {
vaddr = phys_to_virt(paddr);
if (!vaddr)
goto lcd_tcon_axi_rmem_lut_load_err;
memcpy(vaddr, buf, size);
} else {
span = SZ_1M;
count = size / PAGE_ALIGN(span);
remain = size % PAGE_ALIGN(span);
for (i = 0; i < count; i++) {
phys = paddr + i * span;
vaddr = lcd_vmap(phys, span);
if (!vaddr)
goto lcd_tcon_axi_rmem_lut_load_err;
p = buf + i * span;
memcpy(vaddr, p, span);
lcd_unmap_phyaddr(vaddr);
}
if (remain) {
phys = paddr + count * span;
vaddr = lcd_vmap(phys, remain);
if (!vaddr)
goto lcd_tcon_axi_rmem_lut_load_err;
p = buf + count * span;
memcpy(vaddr, p, remain);
lcd_unmap_phyaddr(vaddr);
}
}
return;
lcd_tcon_axi_rmem_lut_load_err:
LCDERR("tcon axi_rmem[%d] mapping failed: 0x%lx\n", index, paddr);
}
static int lcd_tcon_wr_n_data_write(struct aml_lcd_drv_s *pdrv,
struct lcd_tcon_data_part_wr_n_s *wr_n,
unsigned char *p,
unsigned int n,
unsigned int reg)
{
unsigned int k, data, d;
if (wr_n->reg_inc) {
for (k = 0; k < wr_n->data_cnt; k++) {
data = 0;
for (d = 0; d < wr_n->reg_data_byte; d++)
data |= (p[n + d] << (d * 8));
if (wr_n->reg_data_byte == 1)
lcd_tcon_write_byte(pdrv, (reg + k), data);
else
lcd_tcon_write(pdrv, (reg + k), data);
if (lcd_debug_print_flag & LCD_DBG_PR_ADV) {
LCDPR("%s: write reg 0x%x=0x%x\n",
__func__, (reg + k), data);
}
n += wr_n->reg_data_byte;
}
} else {
for (k = 0; k < wr_n->data_cnt; k++) {
data = 0;
for (d = 0; d < wr_n->reg_data_byte; d++)
data |= (p[n + d] << (d * 8));
if (wr_n->reg_data_byte == 1)
lcd_tcon_write_byte(pdrv, reg, data);
else
lcd_tcon_write(pdrv, reg, data);
if (lcd_debug_print_flag & LCD_DBG_PR_ADV) {
LCDPR("%s: write reg 0x%x=0x%x\n",
__func__, (reg + k), data);
}
n += wr_n->reg_data_byte;
}
}
return 0;
}
int lcd_tcon_data_common_parse_set(struct aml_lcd_drv_s *pdrv,
unsigned char *data_buf, int init_flag)
{
struct lcd_tcon_config_s *tcon_conf = get_lcd_tcon_config();
struct lcd_tcon_data_block_header_s *block_header;
struct lcd_tcon_data_block_ext_header_s *ext_header;
unsigned char *p;
unsigned short part_cnt;
unsigned char part_type;
unsigned int size, reg, data, mask, temp, reg_base = 0;
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;
unsigned short block_ctrl_flag, ctrl_data_flag, ctrl_sub_type;
int ret;
if (tcon_conf)
reg_base = tcon_conf->core_reg_start;
block_header = (struct lcd_tcon_data_block_header_s *)data_buf;
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);
block_ctrl_flag = block_header->block_ctrl;
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_CONTROL:
block_ctrl_flag = 0;
data_part.ctrl = (struct lcd_tcon_data_part_ctrl_s *)p;
offset = LCD_TCON_DATA_PART_CTRL_SIZE_PRE;
size = offset + (data_part.ctrl->data_cnt *
data_part.ctrl->data_byte_width);
if ((size + data_offset) > block_header->block_size)
goto lcd_tcon_data_common_parse_set_err_size;
if (block_header->block_ctrl == 0)
break;
ctrl_data_flag = data_part.ctrl->ctrl_data_flag;
ctrl_sub_type = data_part.ctrl->ctrl_sub_type;
if (init_flag) {
if (ctrl_sub_type != LCD_TCON_DATA_CTRL_DEFAULT)
goto lcd_tcon_data_common_parse_set_exit;
}
if (ctrl_data_flag == LCD_TCON_DATA_CTRL_FLAG_MULTI) {
ret = 0;
} else {
ret = -1;
LCDERR("%s: ctrl_data_flag 0x%x not support\n",
__func__, ctrl_data_flag);
}
if (ret)
goto lcd_tcon_data_common_parse_set_exit;
break;
case LCD_TCON_DATA_PART_TYPE_WR_N:
if (block_ctrl_flag)
goto lcd_tcon_data_common_parse_set_ctrl_err;
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*/
/*for data*/
n = m + (reg_cnt * reg_byte);
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;
lcd_tcon_wr_n_data_write(pdrv, data_part.wr_n,
p, n, reg);
m += reg_byte;
}
break;
case LCD_TCON_DATA_PART_TYPE_WR_DDR:
if (block_ctrl_flag)
goto lcd_tcon_data_common_parse_set_ctrl_err;
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:
if (block_ctrl_flag)
goto lcd_tcon_data_common_parse_set_ctrl_err;
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 */
/* for data */
n = m + reg_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;
data = 0;
for (d = 0; d < data_byte; d++)
data |= (p[n + d] << (d * 8));
if (data_byte == 1)
lcd_tcon_update_bits_byte(pdrv, reg, mask, data);
else
lcd_tcon_update_bits(pdrv, reg, mask, data);
if (lcd_debug_print_flag & LCD_DBG_PR_ADV) {
LCDPR("%s: write reg 0x%x, data=0x%x, mask=0x%x\n",
__func__, reg, mask, data);
}
break;
case LCD_TCON_DATA_PART_TYPE_RD_MASK:
if (block_ctrl_flag)
goto lcd_tcon_data_common_parse_set_ctrl_err;
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 */
/* for data */
n = m + reg_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));
if (data_byte == 1) {
data = lcd_tcon_read_byte(pdrv, 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(pdrv, 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);
}
break;
case LCD_TCON_DATA_PART_TYPE_CHK_WR_MASK:
if (block_ctrl_flag)
goto lcd_tcon_data_common_parse_set_ctrl_err;
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;
size = offset + data_part.chk_wr_mask->reg_chk_addr_byte +
//include mask
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 +
//include mask, default
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(pdrv, reg) & mask;
else
temp = lcd_tcon_read(pdrv, 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, temp, 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(pdrv, reg, mask, data);
else
lcd_tcon_update_bits(pdrv, reg, mask, data);
if (lcd_debug_print_flag & LCD_DBG_PR_ADV) {
LCDPR("%s: write reg 0x%x, data=0x%x, mask=0x%x\n",
__func__, reg, mask, data);
}
break;
case LCD_TCON_DATA_PART_TYPE_CHK_EXIT:
if (block_ctrl_flag)
goto lcd_tcon_data_common_parse_set_ctrl_err;
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 */
/* for data */
n = m + reg_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;
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(pdrv, reg, mask, data);
else
ret = lcd_tcon_check_bits(pdrv, 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:
if (block_ctrl_flag)
goto lcd_tcon_data_common_parse_set_ctrl_err;
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 (init_flag == 0) /* calling by vsync isr */
break;
if (data_part.delay->delay_us > 20000) {
m = data_part.delay->delay_us / 1000;
n = data_part.delay->delay_us % 1000;
msleep(m);
if (n > 20)
usleep_range(n, n + 1);
else if (n > 0)
udelay(n);
} else {
n = data_part.delay->delay_us;
if (n > 20)
usleep_range(n, n + 1);
else if (n > 0)
udelay(n);
}
break;
case LCD_TCON_DATA_PART_TYPE_PARAM:
if (block_ctrl_flag)
goto lcd_tcon_data_common_parse_set_ctrl_err;
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:
if (block_ctrl_flag)
goto lcd_tcon_data_common_parse_set_ctrl_err;
LCDERR("%s: unsupport dat 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_exit:
if (lcd_debug_print_flag)
LCDPR("%s: block %s control exit\n", __func__, block_header->name);
return -1;
lcd_tcon_data_common_parse_set_ctrl_err:
LCDERR("%s: block %s need control part\n", __func__, block_header->name);
return -1;
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 aml_lcd_drv_s *pdrv,
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;
unsigned int i, index, chk_size;
if (!mm_table->data_mem_vaddr) {
LCDERR("%s: data_mem error\n", __func__);
return -1;
}
if (!mm_table->data_priority) {
LCDERR("%s: data_priority is null\n", __func__);
return -1;
}
for (i = 0; i < mm_table->block_cnt; i++) {
index = mm_table->data_priority[i].index;
if (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[index];
block_header = (struct lcd_tcon_data_block_header_s *)data_buf;
chk_size = block_header->block_size - 4;
temp_crc32 = cal_crc32(0, &data_buf[4], chk_size);
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, priority %d: size=0x%x, type=0x%02x, ctrl=0x%x\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->block_ctrl);
}
/* add data multi list */
if (block_header->block_ctrl & LCD_TCON_DATA_CTRL_FLAG_MULTI)
lcd_tcon_data_multi_add(mm_table, block_header, index);
/* apply data */
lcd_tcon_data_common_parse_set(pdrv, data_buf, 1);
}
LCDPR("%s finish\n", __func__);
return 0;
}
static int lcd_tcon_top_set_tl1(struct aml_lcd_drv_s *pdrv)
{
struct lcd_config_s *pconf = &pdrv->config;
struct tcon_rmem_s *tcon_rmem = get_lcd_tcon_rmem();
unsigned int axi_reg[3] = {
TCON_AXI_OFST0, TCON_AXI_OFST1, TCON_AXI_OFST2
};
unsigned int paddr, p2p_type;
int i;
if (lcd_debug_print_flag & LCD_DBG_PR_NORMAL)
LCDPR("lcd tcon top set\n");
if (tcon_rmem && 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(pdrv, axi_reg[i], paddr);
LCDPR("set tcon axi_mem paddr[%d]: 0x%08x\n",
i, paddr);
}
}
} else {
LCDERR("%s: invalid axi_mem\n", __func__);
}
lcd_tcon_write(pdrv, TCON_CLK_CTRL, 0x001f);
if (pconf->basic.lcd_type == LCD_P2P) {
p2p_type = pconf->control.p2p_cfg.p2p_type & 0x1f;
switch (p2p_type) {
case P2P_CHPI:
case P2P_USIT:
lcd_tcon_write(pdrv, TCON_TOP_CTRL, 0x8199);
break;
default:
lcd_tcon_write(pdrv, TCON_TOP_CTRL, 0x8999);
break;
}
} else {
lcd_tcon_write(pdrv, TCON_TOP_CTRL, 0x8999);
}
lcd_tcon_write(pdrv, TCON_PLLLOCK_CNTL, 0x0037);
lcd_tcon_write(pdrv, TCON_RST_CTRL, 0x003f);
lcd_tcon_write(pdrv, TCON_RST_CTRL, 0x0000);
lcd_tcon_write(pdrv, TCON_DDRIF_CTRL0, 0x33fff000);
lcd_tcon_write(pdrv, TCON_DDRIF_CTRL1, 0x300300);
return 0;
}
static int lcd_tcon_top_set_t5(struct aml_lcd_drv_s *pdrv)
{
struct lcd_config_s *pconf = &pdrv->config;
unsigned int p2p_type;
if (lcd_debug_print_flag & LCD_DBG_PR_NORMAL)
LCDPR("lcd tcon top set\n");
lcd_tcon_write(pdrv, TCON_CLK_CTRL, 0x001f);
if (pconf->basic.lcd_type == LCD_P2P) {
p2p_type = pconf->control.p2p_cfg.p2p_type & 0x1f;
switch (p2p_type) {
case P2P_CHPI:
case P2P_USIT:
lcd_tcon_write(pdrv, TCON_TOP_CTRL, 0x8399);
break;
default:
lcd_tcon_write(pdrv, TCON_TOP_CTRL, 0x8b99);
break;
}
} else {
lcd_tcon_write(pdrv, TCON_TOP_CTRL, 0x8b99);
}
lcd_tcon_write(pdrv, TCON_PLLLOCK_CNTL, 0x0037);
lcd_tcon_write(pdrv, TCON_RST_CTRL, 0x003f);
lcd_tcon_write(pdrv, TCON_RST_CTRL, 0x0000);
lcd_tcon_write(pdrv, TCON_DDRIF_CTRL0, 0x33fff000);
lcd_tcon_write(pdrv, TCON_DDRIF_CTRL1, 0x300300);
return 0;
}
void lcd_tcon_global_reset_t5(struct aml_lcd_drv_s *pdrv)
{
/* global reset tcon */
lcd_reset_setb(pdrv, RESET1_MASK_T5, 0, 4, 1);
lcd_reset_setb(pdrv, RESET1_LEVEL_T5, 0, 4, 1);
udelay(1);
lcd_reset_setb(pdrv, RESET1_LEVEL_T5, 1, 4, 1);
udelay(2);
}
void lcd_tcon_global_reset_t3(struct aml_lcd_drv_s *pdrv)
{
/* global reset tcon */
lcd_reset_setb(pdrv, RESETCTRL_RESET2_MASK, 0, 5, 1);
lcd_reset_setb(pdrv, RESETCTRL_RESET2_LEVEL, 0, 5, 1);
udelay(1);
lcd_reset_setb(pdrv, RESETCTRL_RESET2_LEVEL, 1, 5, 1);
udelay(2);
}
int lcd_tcon_gamma_pattern_tl1(struct aml_lcd_drv_s *pdrv,
unsigned int bit_width, unsigned int gamma_r,
unsigned int gamma_g, unsigned int gamma_b)
{
unsigned int val_r = 0, val_g = 0, val_b = 0, reg;
unsigned char temp[3];
int i;
switch (bit_width) {
case 12:
val_r = gamma_r;
val_g = gamma_g;
val_b = gamma_b;
break;
case 10:
val_r = (gamma_r << 2);
val_g = (gamma_g << 2);
val_b = (gamma_b << 2);
break;
case 8:
val_r = (gamma_r << 4);
val_g = (gamma_g << 4);
val_b = (gamma_b << 4);
break;
default:
LCDERR("gamam_set: invalid bit_width %d\n", bit_width);
return -1;
}
/* enable lut access, disable gamma en*/
lcd_tcon_setb_byte(pdrv, 0x262, 0x2, 0, 2);
/* gamma_r */
/*2 data splice 3 bytes*/
temp[0] = val_r & 0xff;
temp[1] = ((val_r >> 8) & 0xf) | ((val_r & 0xf) << 4);
temp[2] = (val_r >> 4) & 0xff;
reg = 0xb50;
for (i = 0; i < 384; i += 3) { /* 256 * 1.5 */
lcd_tcon_write_byte(pdrv, (reg + i), temp[0]);
lcd_tcon_write_byte(pdrv, (reg + i + 1), temp[1]);
lcd_tcon_write_byte(pdrv, (reg + i + 2), temp[2]);
}
temp[0] = val_r & 0xff;
temp[1] = ((val_r >> 8) & 0xf);
temp[2] = 0;
reg += 384;
lcd_tcon_write_byte(pdrv, (reg), temp[0]);
lcd_tcon_write_byte(pdrv, (reg + 1), temp[1]);
lcd_tcon_write_byte(pdrv, (reg + 2), temp[2]);
/* gamma_g */
/*2 data splice 3 bytes*/
temp[0] = val_g & 0xff;
temp[1] = ((val_g >> 8) & 0xf) | ((val_g & 0xf) << 4);
temp[2] = (val_g >> 4) & 0xff;
reg += 3;
for (i = 0; i < 384; i += 3) { /* 256 * 1.5 */
lcd_tcon_write_byte(pdrv, (reg + i), temp[0]);
lcd_tcon_write_byte(pdrv, (reg + i + 1), temp[1]);
lcd_tcon_write_byte(pdrv, (reg + i + 2), temp[2]);
}
temp[0] = val_g & 0xff;
temp[1] = ((val_g >> 8) & 0xf);
temp[2] = 0;
reg += 384;
lcd_tcon_write_byte(pdrv, (reg), temp[0]);
lcd_tcon_write_byte(pdrv, (reg + 1), temp[1]);
lcd_tcon_write_byte(pdrv, (reg + 2), temp[2]);
/* gamma_b */
/*2 data splice 3 bytes*/
temp[0] = val_b & 0xff;
temp[1] = ((val_b >> 8) & 0xf) | ((val_b & 0xf) << 4);
temp[2] = (val_b >> 4) & 0xff;
reg += 3;
for (i = 0; i < 384; i += 3) { /* 256 * 1.5 */
lcd_tcon_write_byte(pdrv, (reg + i), temp[0]);
lcd_tcon_write_byte(pdrv, (reg + i + 1), temp[1]);
lcd_tcon_write_byte(pdrv, (reg + i + 2), temp[2]);
}
temp[0] = val_b & 0xff;
temp[1] = ((val_b >> 8) & 0xf);
temp[2] = 0;
reg += 384;
lcd_tcon_write_byte(pdrv, (reg), temp[0]);
lcd_tcon_write_byte(pdrv, (reg + 1), temp[1]);
lcd_tcon_write_byte(pdrv, (reg + 2), temp[2]);
/* enable gamma */
lcd_tcon_setb_byte(pdrv, 0x262, 0x3, 0, 2);
return 0;
}
int lcd_tcon_gamma_pattern_t5(struct aml_lcd_drv_s *pdrv,
unsigned int bit_width, unsigned int gamma_r,
unsigned int gamma_g, unsigned int gamma_b)
{
unsigned int val_r = 0, val_g = 0, val_b = 0;
unsigned int temp;
switch (bit_width) {
case 10:
val_r = gamma_r & 0x3ff;
val_g = gamma_g & 0x3ff;
val_b = gamma_b & 0x3ff;
break;
case 8:
val_r = (gamma_r << 2) & 0x3ff;
val_g = (gamma_g << 2) & 0x3ff;
val_b = (gamma_b << 2) & 0x3ff;
break;
default:
LCDERR("gamam_set: invalid bit_width %d\n", bit_width);
return -1;
}
/* gamma calibrate mode */
lcd_tcon_setb(pdrv, 0x222, 1, 13, 1);
lcd_tcon_setb(pdrv, 0x222, 0, 12, 1);
lcd_tcon_setb(pdrv, 0x222, 0, 8, 2);
lcd_tcon_setb(pdrv, 0x201, 1, 31, 1); //test pattern enable
/* gamma pattern */
lcd_tcon_setb(pdrv, 0x201, 0, 26, 4);
temp = (val_r << 0) | (val_g << 10) | (val_b << 20);
lcd_tcon_setb(pdrv, 0x204, temp, 0, 30);
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();
unsigned int p2p_type;
int ret, flag;
ret = lcd_tcon_valid_check();
if (ret)
return -1;
if (!tcon_conf)
return -1;
if (!mm_table)
return -1;
if (mm_table->tcon_data_flag == 0)
lcd_tcon_data_load();
/* step 1: tcon top */
lcd_tcon_top_set_tl1(pdrv);
/* step 2: tcon_core_reg_update */
lcd_tcon_core_reg_pre_od(tcon_conf, mm_table);
lcd_tcon_core_reg_set(pdrv, tcon_conf, mm_table);
if (pconf->basic.lcd_type == LCD_P2P) {
p2p_type = pconf->control.p2p_cfg.p2p_type & 0x1f;
switch (p2p_type) {
case P2P_CHPI:
lcd_phy_tcon_chpi_bbc_init_tl1(pconf);
break;
default:
break;
}
}
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)
flag = 1;
else
flag = 0;
lcd_tcon_vac_set_tl1(pdrv, flag);
}
if (mm_table->valid_flag & LCD_TCON_DATA_VALID_DEMURA) {
lcd_tcon_demura_set_tl1(pdrv);
lcd_tcon_demura_lut_tl1(pdrv);
}
if (mm_table->valid_flag & LCD_TCON_DATA_VALID_ACC)
lcd_tcon_acc_lut_tl1(pdrv);
} else {
lcd_tcon_data_set(pdrv, mm_table);
}
/* step 3: tcon_top_output_set */
lcd_tcon_write(pdrv, TCON_OUT_CH_SEL0, 0x76543210);
lcd_tcon_write(pdrv, TCON_OUT_CH_SEL1, 0xba98);
/* step 4: tcon_intr_mask */
lcd_tcon_write(pdrv, TCON_INTR_MASKN, TCON_INTR_MASKN_VAL);
return 0;
}
int lcd_tcon_disable_tl1(struct aml_lcd_drv_s *pdrv)
{
struct lcd_tcon_config_s *tcon_conf = get_lcd_tcon_config();
unsigned int reg, i, cnt, offset, bit;
if (!tcon_conf)
return 0;
/* disable tcon intr */
lcd_tcon_write(pdrv, TCON_INTR_MASKN, 0);
/* disable over_drive */
if (tcon_conf->reg_core_od != REG_LCD_TCON_MAX) {
reg = tcon_conf->reg_core_od;
bit = tcon_conf->bit_od_en;
if (tcon_conf->core_reg_width == 8)
lcd_tcon_setb_byte(pdrv, reg, 0, bit, 1);
else
lcd_tcon_setb(pdrv, reg, 0, bit, 1);
msleep(100);
}
/* disable all ctrl signal */
if (tcon_conf->reg_ctrl_timing_base == REG_LCD_TCON_MAX)
goto lcd_tcon_disable_tl1_next;
reg = tcon_conf->reg_ctrl_timing_base;
offset = tcon_conf->ctrl_timing_offset;
cnt = tcon_conf->ctrl_timing_cnt;
for (i = 0; i < cnt; i++) {
if (tcon_conf->core_reg_width == 8)
lcd_tcon_setb_byte(pdrv, (reg + (i * offset)), 1, 3, 1);
else
lcd_tcon_setb(pdrv, (reg + (i * offset)), 1, 3, 1);
}
/* disable top */
lcd_tcon_disable_tl1_next:
if (tcon_conf->reg_top_ctrl != REG_LCD_TCON_MAX) {
reg = tcon_conf->reg_top_ctrl;
bit = tcon_conf->bit_en;
lcd_tcon_setb(pdrv, reg, 0, bit, 1);
}
return 0;
}
int lcd_tcon_enable_t5(struct aml_lcd_drv_s *pdrv)
{
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;
if (mm_table->tcon_data_flag == 0)
lcd_tcon_data_load();
lcd_vcbus_write(ENCL_VIDEO_EN, 0);
/* step 1: tcon top */
lcd_tcon_top_set_t5(pdrv);
/* step 2: tcon_core_reg_update */
lcd_tcon_core_reg_pre_dis_od(tcon_conf, mm_table);
lcd_tcon_core_reg_set(pdrv, tcon_conf, mm_table);
/* step 3: set axi rmem, must before tcon data */
lcd_tcon_axi_rmem_set(pdrv, tcon_conf);
/* step 4: tcon data set */
if (mm_table->version)
lcd_tcon_data_set(pdrv, mm_table);
/* step 5: tcon_top_output_set */
lcd_tcon_write(pdrv, TCON_OUT_CH_SEL0, 0x76543210);
lcd_tcon_write(pdrv, TCON_OUT_CH_SEL1, 0xba98);
/* step 6: tcon_intr_mask */
lcd_tcon_write(pdrv, TCON_INTR_MASKN, TCON_INTR_MASKN_VAL);
lcd_vcbus_write(ENCL_VIDEO_EN, 1);
return 0;
}
int lcd_tcon_disable_t5(struct aml_lcd_drv_s *pdrv)
{
/* disable tcon intr */
lcd_tcon_write(pdrv, TCON_INTR_MASKN, 0);
/* disable od ddr_if */
lcd_tcon_setb(pdrv, 0x263, 0, 31, 1);
msleep(100);
/* top reset */
lcd_tcon_write(pdrv, TCON_RST_CTRL, 0x003f);
lcd_tcon_global_reset_t5(pdrv);
return 0;
}
int lcd_tcon_disable_t3(struct aml_lcd_drv_s *pdrv)
{
/* disable tcon intr */
lcd_tcon_write(pdrv, TCON_INTR_MASKN, 0);
/* disable od ddr_if */
lcd_tcon_setb(pdrv, 0x263, 0, 31, 1);
msleep(100);
/* top reset */
lcd_tcon_write(pdrv, TCON_RST_CTRL, 0x003f);
lcd_tcon_global_reset_t3(pdrv);
return 0;
}