blob: 635f72e160f414edb92829b92bce1dd0ebf5808f [file] [log] [blame]
/*
* drivers/amlogic/media/vout/lcd/aml_lcd_tcon.c
*
* Copyright (C) 2015 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#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 struct lcd_tcon_data_s *lcd_tcon_data;
static int lcd_tcon_valid_check(void)
{
if (lcd_tcon_data == NULL) {
LCDERR("invalid tcon data\n");
return -1;
}
if (lcd_tcon_data->tcon_valid == 0) {
LCDERR("invalid tcon\n");
return -1;
}
return 0;
}
static void lcd_tcon_config_axi_offset_default(void)
{
char *str;
str = env_get("tcon_fb_addr");
if (str) {
lcd_tcon_data->axi_offset_addr = simple_strtoul(str, NULL, 16);
} else {
LCDERR("can't find env tcon_fb_addr\n");
lcd_tcon_data->axi_offset_addr = 0;
}
}
static int lcd_tcon_config(const void *dt_blob, struct lcd_config_s *pconf, int load_id)
{
int key_len, reg_len;
int parent_offset;
char *propdata;
int ret;
if (load_id & 0x1) {
parent_offset = fdt_path_offset(dt_blob, "/lcd");
if (parent_offset < 0) {
LCDERR("can't find /lcd node: %s\n", fdt_strerror(parent_offset));
lcd_tcon_config_axi_offset_default();
} else {
propdata = (char *)fdt_getprop(dt_blob,
parent_offset, "tcon_fb_addr", NULL);
if (propdata == NULL) {
LCDERR("failed to get tcon_fb_addr from dts\n");
lcd_tcon_config_axi_offset_default();
} else {
lcd_tcon_data->axi_offset_addr =
be32_to_cpup(((u32*)propdata));
}
}
} else {
lcd_tcon_config_axi_offset_default();
}
/* get reg table from unifykey */
reg_len = lcd_tcon_data->reg_table_len;
if (lcd_tcon_data->reg_table == NULL) {
lcd_tcon_data->reg_table =
(unsigned char *)malloc(sizeof(unsigned char) * reg_len);
if (!lcd_tcon_data->reg_table) {
LCDERR("%s: Not enough memory\n", __func__);
return -1;
}
}
memset(lcd_tcon_data->reg_table, 0, (sizeof(unsigned char) * reg_len));
key_len = reg_len;
ret = aml_lcd_unifykey_get_no_header("lcd_tcon",
lcd_tcon_data->reg_table, &key_len);
if (ret) {
free(lcd_tcon_data->reg_table);
lcd_tcon_data->reg_table = NULL;
LCDERR("%s: !!!!!!!!tcon unifykey load error!!!!!!!!\n", __func__);
return -1;
}
if (key_len != reg_len) {
free(lcd_tcon_data->reg_table);
lcd_tcon_data->reg_table = NULL;
LCDERR("%s: !!!!!!!!tcon unifykey load length error!!!!!!!!\n", __func__);
return -1;
}
LCDPR("tcon: load key len: %d\n", key_len);
return 0;
}
/* **********************************
* tcon function api
* **********************************
*/
#define PR_BUF_MAX 200
void lcd_tcon_reg_table_print(void)
{
int i, j, n, cnt;
char *buf;
int ret;
ret = lcd_tcon_valid_check();
if (ret)
return;
if (lcd_tcon_data->reg_table == NULL) {
LCDERR("%s: reg_table is null\n", __func__);
return;
}
buf = (char *)malloc(PR_BUF_MAX * sizeof(char));
if (buf == NULL) {
LCDERR("%s: buf malloc error\n", __func__);
return;
}
LCDPR("%s:\n", __func__);
cnt = lcd_tcon_data->reg_table_len;
for (i = 0; i < cnt; i += 16) {
n = snprintf(buf, PR_BUF_MAX, "0x%04x: ", i);
for (j = 0; j < 16; j++) {
if ((i + j) >= cnt)
break;
n += snprintf(buf+n, PR_BUF_MAX, " 0x%02x",
lcd_tcon_data->reg_table[i+j]);
}
buf[n] = '\0';
printf("%s\n", buf);
}
free(buf);
}
void lcd_tcon_reg_readback_print(void)
{
int i, j, n, cnt;
char *buf;
int ret;
ret = lcd_tcon_valid_check();
if (ret)
return;
buf = (char *)malloc(PR_BUF_MAX * sizeof(char));
if (buf == NULL) {
LCDERR("%s: buf malloc error\n", __func__);
return;
}
LCDPR("%s:\n", __func__);
cnt = lcd_tcon_data->reg_table_len;
for (i = 0; i < cnt; i += 16) {
n = snprintf(buf, PR_BUF_MAX, "0x%04x: ", i);
for (j = 0; j < 16; j++) {
if ((i + j) >= cnt)
break;
if (lcd_tcon_data->core_reg_width == 8) {
n += snprintf(buf+n, PR_BUF_MAX, " 0x%02x",
lcd_tcon_read_byte(i+j));
} else {
n += snprintf(buf+n, PR_BUF_MAX, " 0x%02x",
lcd_tcon_read(i+j));
}
}
buf[n] = '\0';
printf("%s\n", buf);
}
free(buf);
}
void lcd_tcon_info_print(void)
{
int ret;
ret = lcd_tcon_valid_check();
if (ret)
return;
LCDPR("%s:\n", __func__);
printf("core_reg_width: %d\n", lcd_tcon_data->core_reg_width);
printf("reg_table_len: %d\n", lcd_tcon_data->reg_table_len);
printf("axi_offset_addr: 0x%08x\n", lcd_tcon_data->axi_offset_addr);
}
int lcd_tcon_enable(struct lcd_config_s *pconf)
{
int ret;
ret = lcd_tcon_valid_check();
if (ret)
return -1;
if (lcd_tcon_data->tcon_enable)
lcd_tcon_data->tcon_enable(pconf);
return 0;
}
void lcd_tcon_disable(void)
{
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_data->reg_core_od != REG_LCD_TCON_MAX) {
reg = lcd_tcon_data->reg_core_od + TCON_CORE_REG_START;
if (lcd_tcon_data->core_reg_width == 8)
lcd_tcon_write_byte(reg, 0);
else
lcd_tcon_write(reg, 0);
mdelay(100);
}
/* disable all ctrl signal */
if (lcd_tcon_data->reg_core_ctrl_timing_base != REG_LCD_TCON_MAX) {
reg = lcd_tcon_data->reg_core_ctrl_timing_base + TCON_CORE_REG_START;
offset = lcd_tcon_data->ctrl_timing_offset;
cnt = lcd_tcon_data->ctrl_timing_cnt;
for (i = 0; i < cnt; i++) {
if (lcd_tcon_data->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_data->reg_top_ctrl != REG_LCD_TCON_MAX) {
reg = lcd_tcon_data->reg_top_ctrl;
bit = lcd_tcon_data->bit_en;
lcd_tcon_setb(reg, 0, bit, 1);
}
}
/* **********************************
* tcon match data
* **********************************
*/
int lcd_tcon_probe(const void *dt_blob, struct aml_lcd_drv_s *lcd_drv, int load_id)
{
int ret = 0;
struct lcd_config_s *pconf = lcd_drv->lcd_config;
LCDPR("%s\n", __func__);
switch (lcd_drv->chip_type) {
default:
lcd_tcon_data = NULL;
break;
}
ret = lcd_tcon_valid_check();
if (ret)
return -1;
ret = lcd_tcon_config(dt_blob, pconf, load_id);
return ret;
}