| /* |
| * drivers/display/lcd/aml_lcd_tcon.c |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the named License, |
| * or any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| */ |
| |
| #include <common.h> |
| #include <malloc.h> |
| #include <asm/arch/io.h> |
| #include <amlogic/aml_lcd.h> |
| #ifdef CONFIG_AMLOGIC_TEE |
| #include <../../aml_tee/tee_aml.h> |
| #endif |
| #include "aml_lcd_reg.h" |
| #include "aml_lcd_common.h" |
| #include "aml_lcd_tcon.h" |
| |
| #define PR_BUF_MAX 200 |
| |
| #define TCON_IRQ_TIMEOUT_MAX (1 << 17) |
| //static unsigned int tcon_irq_timeout; |
| //static unsigned int tcon_irq_cnt; |
| //static void lcd_tcon_p2p_chpi_irq(void); |
| |
| 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; |
| static struct lcd_tcon_local_cfg_s tcon_local_cfg; |
| |
| 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; |
| } |
| |
| struct lcd_tcon_local_cfg_s *get_lcd_tcon_local_cfg(void) |
| { |
| int ret; |
| |
| ret = lcd_tcon_valid_check(); |
| if (ret) |
| return NULL; |
| |
| return &tcon_local_cfg; |
| } |
| |
| 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 == NULL) { |
| 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 == NULL) { |
| 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, sec_protect, sec_handle, *data; |
| char *str, sec_cfg[30]; |
| 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_bin_ver: %s\n" |
| "tcon_rmem_flag: %d\n" |
| "rsv_mem paddr: 0x%08x\n" |
| "rsv_mem size: 0x%08x\n", |
| lcd_tcon_conf->core_reg_width, |
| lcd_tcon_conf->reg_table_len, |
| tcon_local_cfg.bin_ver, |
| tcon_rmem.flag, |
| tcon_rmem.rsv_mem_paddr, |
| tcon_rmem.rsv_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", |
| tcon_rmem.bin_path_rmem.mem_paddr, |
| tcon_rmem.bin_path_rmem.mem_vaddr, |
| tcon_rmem.bin_path_rmem.mem_size); |
| } |
| printf("\n"); |
| |
| if (tcon_rmem.flag) { |
| for (i = 0; i < lcd_tcon_conf->axi_bank; i++) { |
| memset(sec_cfg, 0, 30); |
| if (tcon_rmem.axi_rmem[i].sec_protect) { |
| sprintf(sec_cfg, "protect, handle:%d", |
| tcon_rmem.axi_rmem[i].sec_handle); |
| } else { |
| sprintf(sec_cfg, "unprotect"); |
| } |
| printf("axi_mem[%d] paddr: 0x%lx (%s)\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, sec_cfg, |
| i, tcon_rmem.axi_rmem[i].mem_vaddr, |
| i, tcon_rmem.axi_rmem[i].mem_size); |
| } |
| printf("\n"); |
| |
| 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 = *(unsigned int *)&tcon_mm_table.data_mem_vaddr[i][8]; |
| 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 = *(unsigned int *)&tcon_rmem.bin_path_rmem.mem_vaddr[4]; |
| cnt = *(unsigned int *)&tcon_rmem.bin_path_rmem.mem_vaddr[16]; |
| if (size < (32 + 256 * cnt)) |
| return; |
| if (cnt > 32) |
| return; |
| printf("\nbin_path: cnt: %d\n" |
| "init_load: %d\n" |
| "data_flag: %d\n", |
| cnt, tcon_mm_table.init_load, |
| tcon_mm_table.tcon_data_flag); |
| for (i = 0; i < cnt; i++) { |
| n = 32 + 256 * i; |
| file_size = *(unsigned int *)&tcon_rmem.bin_path_rmem.mem_vaddr[n]; |
| str = (char *)&tcon_rmem.bin_path_rmem.mem_vaddr[n + 4]; |
| printf("bin[%d]: size: 0x%x, %s\n", i, file_size, str); |
| } |
| } |
| |
| if (tcon_rmem.secure_cfg_rmem.mem_vaddr) { |
| data = (unsigned int *)tcon_rmem.secure_cfg_rmem.mem_vaddr; |
| cnt = lcd_tcon_conf->axi_bank; |
| printf("\nsecure_cfg rsv_mem:\n" |
| "mem_paddr: 0x%08x\n" |
| "mem_vaddr: 0x%p\n" |
| "mem_size: 0x%08x\n", |
| tcon_rmem.secure_cfg_rmem.mem_paddr, |
| tcon_rmem.secure_cfg_rmem.mem_vaddr, |
| tcon_rmem.secure_cfg_rmem.mem_size); |
| for (i = 0; i < cnt; i++) { |
| n = 2 * i; |
| sec_protect = *(data + n); |
| sec_handle = *(data + n + 1); |
| printf(" [%d]: protect: %d, handle: %d\n", |
| i, sec_protect, sec_handle); |
| } |
| } |
| 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_resv_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 lcd_config_s *pconf) |
| { |
| int ret; |
| |
| ret = lcd_tcon_valid_check(); |
| if (ret) |
| return -1; |
| |
| if (lcd_tcon_conf->tcon_enable) |
| lcd_tcon_conf->tcon_enable(pconf); |
| |
| #ifdef CONFIG_CMD_INI |
| lcd_tcon_bin_path_resv_mem_set(); |
| #endif |
| |
| return 0; |
| } |
| |
| void lcd_tcon_disable(struct lcd_config_s *pconf) |
| { |
| int ret; |
| |
| ret = lcd_tcon_valid_check(); |
| if (ret) |
| return; |
| |
| LCDPR("%s\n", __func__); |
| |
| if (lcd_tcon_conf->tcon_disable) |
| lcd_tcon_conf->tcon_disable(pconf); |
| } |
| |
| static int lcd_tcon_forbidden_check(void) |
| { |
| int ret; |
| |
| ret = lcd_tcon_valid_check(); |
| if (ret) |
| return -1; |
| |
| if (lcd_tcon_conf->tcon_forbidden_check) |
| ret = lcd_tcon_conf->tcon_forbidden_check(); |
| else |
| ret = 0; |
| |
| return ret; |
| } |
| |
| static int lcd_tcon_data_multi_match_policy_check(struct aml_lcd_drv_s *lcd_drv, |
| struct lcd_tcon_data_part_ctrl_s *ctrl_part, unsigned char *p) |
| { |
| struct bl_config_s *bconf; |
| struct bl_pwm_config_s *bl_pwm = NULL; |
| unsigned int data_byte, data_cnt, data, min, max; |
| unsigned int sync_num, sync_den, temp; |
| unsigned int j, k; |
| |
| if (!ctrl_part) |
| return -1; |
| if (ctrl_part->ctrl_data_flag != LCD_TCON_DATA_CTRL_FLAG_MULTI) |
| return -1; |
| |
| data_byte = ctrl_part->data_byte_width; |
| data_cnt = ctrl_part->data_cnt; |
| |
| k = 0; |
| data = 0; |
| min = 0; |
| max = 0; |
| |
| switch (ctrl_part->ctrl_method) { |
| case LCD_TCON_DATA_CTRL_MULTI_VFREQ: |
| if (data_cnt != 2) |
| goto lcd_tcon_data_multi_match_check_err_data_cnt; |
| sync_num = lcd_drv->lcd_config->lcd_timing.sync_duration_num; |
| sync_den = lcd_drv->lcd_config->lcd_timing.sync_duration_den; |
| temp = sync_num / sync_den; |
| |
| for (j = 0; j < data_byte; j++) |
| min |= (p[k + j] << (j * 8)); |
| k += data_byte; |
| for (j = 0; j < data_byte; j++) |
| max |= (p[k + j] << (j * 8)); |
| if (temp < min || temp > max) |
| goto lcd_tcon_data_multi_match_check_exit; |
| break; |
| case LCD_TCON_DATA_CTRL_MULTI_BL_LEVEL: |
| bconf = lcd_drv->bl_config; |
| if (!bconf) |
| goto lcd_tcon_data_multi_match_check_err_type; |
| temp = bconf->level; |
| |
| if (data_cnt != 2) |
| goto lcd_tcon_data_multi_match_check_err_data_cnt; |
| for (j = 0; j < data_byte; j++) |
| min |= (p[k + j] << (j * 8)); |
| k += data_byte; |
| for (j = 0; j < data_byte; j++) |
| max |= (p[k + j] << (j * 8)); |
| if (temp < min || temp > max) |
| goto lcd_tcon_data_multi_match_check_exit; |
| break; |
| case LCD_TCON_DATA_CTRL_MULTI_BL_PWM_DUTY: |
| bconf = lcd_drv->bl_config; |
| if (!bconf) |
| goto lcd_tcon_data_multi_match_check_err_type; |
| |
| if (data_cnt != 3) |
| goto lcd_tcon_data_multi_match_check_err_data_cnt; |
| for (j = 0; j < data_byte; j++) |
| data |= (p[k + j] << (j * 8)); |
| k += data_byte; |
| for (j = 0; j < data_byte; j++) |
| min |= (p[k + j] << (j * 8)); |
| k += data_byte; |
| for (j = 0; j < data_byte; j++) |
| max |= (p[k + j] << (j * 8)); |
| |
| switch (bconf->method) { |
| case BL_CTRL_PWM: |
| bl_pwm = bconf->bl_pwm; |
| break; |
| case BL_CTRL_PWM_COMBO: |
| if (data == 0) |
| bl_pwm = bconf->bl_pwm_combo0; |
| else |
| bl_pwm = bconf->bl_pwm_combo1; |
| break; |
| default: |
| break; |
| } |
| if (!bl_pwm) |
| goto lcd_tcon_data_multi_match_check_err_type; |
| |
| temp = bl_pwm->pwm_duty; |
| if (temp < min || temp > max) |
| goto lcd_tcon_data_multi_match_check_exit; |
| break; |
| case LCD_TCON_DATA_CTRL_DEFAULT: |
| return 1; |
| default: |
| return -1; |
| } |
| |
| return 0; |
| |
| lcd_tcon_data_multi_match_check_exit: |
| return -1; |
| |
| lcd_tcon_data_multi_match_check_err_data_cnt: |
| LCDERR("%s: ctrl_part %s data_cnt error\n", __func__, ctrl_part->name); |
| return -1; |
| |
| lcd_tcon_data_multi_match_check_err_type: |
| LCDERR("%s: ctrl_part %s type invalid\n", __func__, ctrl_part->name); |
| return -1; |
| } |
| |
| /* return: |
| * 0: matched |
| * 1: dft list |
| * -1: not match |
| */ |
| int lcd_tcon_data_multi_match_find(unsigned char *data_buf) |
| { |
| struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver(); |
| struct lcd_tcon_data_block_header_s *block_header; |
| struct lcd_tcon_data_block_ext_header_s *ext_header; |
| struct lcd_tcon_data_part_ctrl_s *ctrl_part; |
| unsigned char *p, part_type; |
| unsigned int size, data_offset, offset, i; |
| unsigned short part_cnt; |
| int ret; |
| |
| 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; |
| |
| 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]; |
| |
| switch (part_type) { |
| case LCD_TCON_DATA_PART_TYPE_CONTROL: |
| offset = LCD_TCON_DATA_PART_CTRL_SIZE_PRE; |
| ctrl_part = (struct lcd_tcon_data_part_ctrl_s *)p; |
| size = offset + (ctrl_part->data_cnt * |
| ctrl_part->data_byte_width); |
| if (ctrl_part->ctrl_data_flag != LCD_TCON_DATA_CTRL_FLAG_MULTI) |
| break; |
| ret = lcd_tcon_data_multi_match_policy_check(lcd_drv, |
| ctrl_part, (p + offset)); |
| if (ret == 0) |
| return 0; |
| if (ret == 1) |
| return 1; |
| break; |
| default: |
| return -1; |
| } |
| data_offset += size; |
| } |
| |
| return -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 == 3) { |
| 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 == 3) { |
| 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 == 3) { |
| 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 == 3) { |
| for (i = 0; i < 100; i++) |
| LCDPR("acc_lut[%d]: 0x%02x\n", i, buff[i]); |
| } |
| #endif |
| return ret; |
| } |
| |
| #ifdef CONFIG_CMD_INI |
| static void lcd_tcon_data_complete_check(struct aml_lcd_drv_s *lcd_drv, int index) |
| { |
| unsigned char *table = tcon_mm_table.core_reg_table; |
| int i, n = 0; |
| |
| if (tcon_mm_table.tcon_data_flag) |
| return; |
| |
| if (lcd_debug_print_flag) |
| LCDPR("%s: index %d\n", __func__, index); |
| |
| tcon_mm_table.block_bit_flag |= (1 << index); |
| for (i = 0; i < tcon_mm_table.block_cnt; i++) { |
| if (tcon_mm_table.block_bit_flag & (1 << i)) |
| n++; |
| } |
| if (n < tcon_mm_table.block_cnt) |
| return; |
| |
| tcon_mm_table.tcon_data_flag = 1; |
| LCDPR("%s: tcon_data_flag: %d\n", __func__, tcon_mm_table.tcon_data_flag); |
| |
| /* specially check demura setting */ |
| if (lcd_drv->chip_type == LCD_CHIP_TL1 || |
| lcd_drv->chip_type == LCD_CHIP_TM2) { |
| if (tcon_mm_table.demura_cnt < 2) { |
| tcon_mm_table.valid_flag &= ~LCD_TCON_DATA_VALID_DEMURA; |
| if (table) { |
| /* disable demura */ |
| table[0x178] = 0x38; |
| table[0x17c] = 0x20; |
| table[0x181] = 0x00; |
| table[0x23d] &= ~(1 << 0); |
| } |
| } |
| } |
| } |
| |
| static int lcd_tcon_data_load(struct aml_lcd_drv_s *lcd_drv, unsigned char *data_buf, int index) |
| { |
| struct lcd_tcon_data_block_header_s *block_header; |
| struct tcon_data_priority_s *data_prio; |
| unsigned int priority; |
| int j; |
| |
| if (!data_buf) { |
| LCDERR("%s: data_buf is null\n", __func__); |
| return -1; |
| } |
| if (!tcon_mm_table.data_size) { |
| LCDERR("%s: data_size buf error\n", __func__); |
| return -1; |
| } |
| if (!tcon_mm_table.data_priority) { |
| LCDERR("%s: data_priority buf error\n", __func__); |
| return -1; |
| } |
| |
| data_prio = tcon_mm_table.data_priority; |
| block_header = (struct lcd_tcon_data_block_header_s *)data_buf; |
| if (block_header->block_size < sizeof(struct lcd_tcon_data_block_header_s)) { |
| LCDERR("%s: block[%d] size 0x%x error\n", |
| __func__, index, block_header->block_size); |
| return -1; |
| } |
| |
| if (block_header->block_type != LCD_TCON_DATA_BLOCK_TYPE_BASIC_INIT) { |
| tcon_mm_table.valid_flag |= block_header->block_flag; |
| if (block_header->block_flag == LCD_TCON_DATA_VALID_DEMURA) |
| tcon_mm_table.demura_cnt++; |
| } |
| |
| /* insertion sort for block data init_priority */ |
| data_prio[index].index = index; |
| /*data_prio[i].priority = block_header->init_priority;*/ |
| /* update init_priority by index */ |
| priority = index; |
| data_prio[index].priority = priority; |
| if (index > 0) { |
| for (j = index - 1; j >= 0; j--) { |
| if (priority > data_prio[j].priority) |
| break; |
| if (priority == data_prio[j].priority) { |
| LCDERR("%s: block %d init_prio same as block %d\n", |
| __func__, data_prio[index].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; |
| } |
| data_prio[j + 1].index = index; |
| data_prio[j + 1].priority = priority; |
| } |
| tcon_mm_table.data_size[index] = block_header->block_size; |
| |
| if (lcd_debug_print_flag) { |
| LCDPR("%s %d: block size=0x%x, type=0x%02x, name=%s, init_priority=%d\n", |
| __func__, index, |
| block_header->block_size, |
| block_header->block_type, |
| block_header->name, |
| priority); |
| } |
| |
| lcd_tcon_data_complete_check(lcd_drv, index); |
| |
| return 0; |
| } |
| #endif |
| |
| static int lcd_tcon_bin_load(void) |
| { |
| unsigned char *table; |
| struct aml_lcd_drv_s *lcd_drv = aml_lcd_get_driver(); |
| #ifdef CONFIG_CMD_INI |
| unsigned int i; |
| #endif |
| int ret; |
| |
| LCDPR("%s\n", __func__); |
| ret = lcd_tcon_valid_check(); |
| if (ret) |
| return -1; |
| |
| if (tcon_mm_table.version == 0) { |
| table = tcon_mm_table.core_reg_table; |
| if (!table) |
| return 0; |
| if ((lcd_drv->chip_type == LCD_CHIP_TL1) || |
| (lcd_drv->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; |
| tcon_mm_table.tcon_data_flag = 1; |
| } else { |
| if (!tcon_mm_table.data_mem_vaddr) { |
| LCDERR("%s: data_mem error\n", __func__); |
| return -1; |
| } |
| if (!tcon_mm_table.data_size) { |
| LCDERR("%s: data_size error\n", __func__); |
| return -1; |
| } |
| #ifdef CONFIG_CMD_INI |
| 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; |
| |
| if (!tcon_mm_table.data_mem_vaddr[i]) |
| continue; |
| lcd_tcon_data_load(lcd_drv, tcon_mm_table.data_mem_vaddr[i], i); |
| } |
| #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, block_cnt; |
| 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 < 32) { /* header size */ |
| LCDERR("%s: tcon_bin_path data_size error\n", __func__); |
| return -1; |
| } |
| block_cnt = mem_vaddr[16] | |
| (mem_vaddr[17] << 8) | |
| (mem_vaddr[18] << 16) | |
| (mem_vaddr[19] << 24); |
| if (block_cnt > 32) { |
| LCDERR("%s: tcon_bin_path block_cnt 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 = block_cnt; |
| tcon_mm_table.init_load = mem_vaddr[20]; |
| LCDPR("%s: init_load: %d\n", __func__, tcon_mm_table.init_load); |
| #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 && (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 && (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 && (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 && (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) |
| 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_txhd(void) |
| { |
| unsigned int size = 0x1fe000; |
| |
| if (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, size); |
| return; |
| } |
| |
| tcon_rmem.axi_rmem = (struct tcon_rmem_config_s *) |
| malloc(sizeof(struct tcon_rmem_config_s)); |
| if (!tcon_rmem.axi_rmem) |
| return; |
| memset(tcon_rmem.axi_rmem, 0, sizeof(struct tcon_rmem_config_s)); |
| |
| tcon_rmem.axi_rmem->mem_paddr = tcon_rmem.axi_mem_paddr; |
| tcon_rmem.axi_rmem->mem_vaddr = |
| (unsigned char *)(unsigned long)tcon_rmem.axi_rmem->mem_paddr; |
| tcon_rmem.axi_rmem->mem_size = size; |
| } |
| |
| 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 void lcd_tcon_axi_rmem_update_t5(unsigned int *table) |
| { |
| unsigned int reg, paddr, i; |
| |
| if (tcon_rmem.flag == 0 || !tcon_rmem.axi_rmem) { |
| LCDERR("%s: invalid axi_mem\n", __func__); |
| return; |
| } |
| |
| for (i = 0; i < lcd_tcon_conf->axi_bank; i++) { |
| reg = lcd_tcon_conf->axi_reg[i]; |
| paddr = tcon_rmem.axi_rmem[i].mem_paddr; |
| table[reg] = paddr; |
| if (lcd_debug_print_flag) { |
| LCDPR("%s: axi[%d] reg: 0x%08x, paddr: 0x%08x\n", |
| __func__, i, reg, paddr); |
| } |
| } |
| } |
| |
| static void lcd_tcon_axi_mem_config_t5d(void) |
| { |
| unsigned int size = 0x00500000; |
| unsigned int reg = 0x261; |
| unsigned int temp_size = 0; |
| |
| if (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, size); |
| return; |
| } |
| |
| temp_size = 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 = 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); |
| |
| tcon_rmem.axi_rmem->mem_paddr = tcon_rmem.axi_mem_paddr; |
| tcon_rmem.axi_rmem->mem_vaddr = |
| (unsigned char *)(unsigned long)tcon_rmem.axi_rmem->mem_paddr; |
| tcon_rmem.axi_rmem->mem_size = size; |
| |
| *lcd_tcon_conf->axi_reg = reg; |
| } |
| |
| static void lcd_tcon_axi_rmem_update_t5d(unsigned int *table) |
| { |
| unsigned int reg, paddr; |
| |
| if (tcon_rmem.flag == 0 || !tcon_rmem.axi_rmem) { |
| LCDERR("%s: invalid axi_mem\n", __func__); |
| return; |
| } |
| |
| reg = *lcd_tcon_conf->axi_reg; |
| paddr = tcon_rmem.axi_rmem->mem_paddr; |
| table[reg] = paddr; |
| if (lcd_debug_print_flag) { |
| LCDPR("%s: axi reg: 0x%08x, paddr: 0x%08x\n", |
| __func__, reg, paddr); |
| } |
| } |
| |
| static void lcd_tcon_axi_mem_secure_tl1(void) |
| { |
| #ifdef CONFIG_AMLOGIC_TEE |
| unsigned int sec_handle = 0; |
| int i, ret; |
| |
| if (!tcon_rmem.axi_rmem) |
| return; |
| |
| tcon_rmem.axi_rmem[0].sec_handle = 0; |
| ret = tee_protect_mem_by_type(TEE_MEM_TYPE_TCON, |
| tcon_rmem.axi_mem_paddr, |
| tcon_rmem.axi_mem_size, |
| &sec_handle); |
| if (ret) { |
| for (i = 0; i < lcd_tcon_conf->axi_bank; i++) |
| tcon_rmem.axi_rmem[i].sec_protect = 0; |
| LCDERR("%s: protect failed! mem start: 0x%08x, size: 0x%x, ret: %d\n", |
| __func__, tcon_rmem.axi_mem_paddr, |
| tcon_rmem.axi_mem_size, ret); |
| return; |
| } |
| for (i = 0; i < lcd_tcon_conf->axi_bank; i++) { |
| tcon_rmem.axi_rmem[i].sec_protect = 1; |
| tcon_rmem.axi_rmem[i].sec_handle = sec_handle; |
| } |
| LCDPR("%s: protect OK. mem start: 0x%08x, size: 0x%x\n", |
| __func__, tcon_rmem.axi_mem_paddr, tcon_rmem.axi_mem_size); |
| #endif |
| } |
| |
| static void lcd_tcon_axi_mem_secure_t5(void) |
| { |
| /* only protect od mem */ |
| #ifdef CONFIG_AMLOGIC_TEE |
| lcd_tcon_mem_tee_protect(0, 1); |
| #endif |
| } |
| |
| #ifdef CONFIG_AMLOGIC_TEE |
| int lcd_tcon_mem_tee_protect(int mem_flag, int protect_en) |
| { |
| unsigned char *secure_cfg_vaddr; |
| unsigned int *data, sec_protect, sec_handle; |
| int ret; |
| |
| if (!tcon_rmem.axi_rmem) { |
| LCDERR("%s: axi_rmem is null\n", __func__); |
| return -1; |
| } |
| |
| if (mem_flag > lcd_tcon_conf->axi_bank) { |
| LCDPR("no need protect\n"); |
| return 0; |
| } |
| |
| /* mem_flag: 0 = od secure mem(default secure) |
| * 1 = demura_lut mem(default unsecure) |
| */ |
| secure_cfg_vaddr = tcon_rmem.secure_cfg_rmem.mem_vaddr; |
| if (!secure_cfg_vaddr) { |
| LCDERR("%s: secure_cfg_vaddr is null\n", __func__); |
| return 0; |
| } |
| data = (unsigned int *)secure_cfg_vaddr; |
| |
| if (protect_en) { |
| if (tcon_rmem.axi_rmem[mem_flag].sec_protect) |
| return 0; |
| |
| ret = tee_protect_mem_by_type(TEE_MEM_TYPE_TCON, |
| tcon_rmem.axi_rmem[mem_flag].mem_paddr, |
| tcon_rmem.axi_rmem[mem_flag].mem_size, |
| &tcon_rmem.axi_rmem[mem_flag].sec_handle); |
| |
| if (ret) { |
| LCDERR("%s: protect failed! mem[%d], start: 0x%08x, size: 0x%x, ret: %d\n", |
| __func__, mem_flag, |
| tcon_rmem.axi_rmem[mem_flag].mem_paddr, |
| tcon_rmem.axi_rmem[mem_flag].mem_size, ret); |
| return -1; |
| } |
| tcon_rmem.axi_rmem[mem_flag].sec_protect = 1; |
| LCDPR("%s: protect OK. mem[%d], start: 0x%08x, size: 0x%x\n", |
| __func__, mem_flag, |
| tcon_rmem.axi_rmem[mem_flag].mem_paddr, |
| tcon_rmem.axi_rmem[mem_flag].mem_size); |
| } else { |
| if (!tcon_rmem.axi_rmem[mem_flag].sec_protect) |
| return 0; |
| tee_unprotect_mem(tcon_rmem.axi_rmem[mem_flag].sec_handle); |
| tcon_rmem.axi_rmem[mem_flag].sec_protect = 0; |
| tcon_rmem.axi_rmem[mem_flag].sec_handle = 0; |
| LCDPR("%s: unprotect OK. mem[%d], start: 0x%08x, size: 0x%x\n", |
| __func__, mem_flag, |
| tcon_rmem.axi_rmem[mem_flag].mem_paddr, |
| tcon_rmem.axi_rmem[mem_flag].mem_size); |
| } |
| //update secure_cfg_vaddr |
| *data = tcon_rmem.axi_rmem[mem_flag].sec_protect; |
| *(data + 1) = tcon_rmem.axi_rmem[mem_flag].sec_handle; |
| if (lcd_debug_print_flag == 2) { |
| sec_protect = secure_cfg_vaddr[0 + mem_flag * 8] | |
| (secure_cfg_vaddr[1 + mem_flag * 8] << 8) | |
| (secure_cfg_vaddr[2 + mem_flag * 8] << 16) | |
| (secure_cfg_vaddr[3 + mem_flag * 8] << 24); |
| sec_handle = secure_cfg_vaddr[4 + mem_flag * 8] | |
| (secure_cfg_vaddr[5 + mem_flag * 8] << 8) | |
| (secure_cfg_vaddr[6 + mem_flag * 8] << 16) | |
| (secure_cfg_vaddr[7 + mem_flag * 8] << 24); |
| LCDPR("mem[%d] sec_handle: %d, secure_cfg_rmem protect: %d, handle: %d\n", |
| mem_flag, tcon_rmem.axi_rmem[mem_flag].sec_handle, |
| sec_protect, sec_handle); |
| } |
| |
| return 0; |
| } |
| #endif |
| |
| static int lcd_tcon_mem_config(void) |
| { |
| unsigned char *mem_vaddr; |
| unsigned int max_size; |
| int ret; |
| |
| if (tcon_rmem.flag == 0) |
| return -1; |
| |
| /* reserved memory */ |
| max_size = lcd_tcon_conf->axi_size + lcd_tcon_conf->bin_path_size + |
| lcd_tcon_conf->secure_cfg_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) |
| LCDPR("tcon axi_mem paddr: 0x%08x, size: 0x%x\n", |
| tcon_rmem.axi_mem_paddr, tcon_rmem.axi_mem_size); |
| if (lcd_tcon_conf->tcon_axi_mem_config) |
| 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 && (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); |
| |
| tcon_rmem.secure_cfg_rmem.mem_size = lcd_tcon_conf->secure_cfg_size; |
| tcon_rmem.secure_cfg_rmem.mem_paddr = |
| tcon_rmem.axi_mem_paddr + tcon_rmem.axi_mem_size + lcd_tcon_conf->bin_path_size; |
| if (tcon_rmem.secure_cfg_rmem.mem_size > 0) { |
| tcon_rmem.secure_cfg_rmem.mem_vaddr = |
| (unsigned char *)(unsigned long)(tcon_rmem.secure_cfg_rmem.mem_paddr); |
| if (lcd_debug_print_flag) { |
| LCDPR("tcon secure_cfg_rmem paddr: 0x%08x, vaddr: 0x%p, size: 0x%x\n", |
| tcon_rmem.secure_cfg_rmem.mem_paddr, |
| tcon_rmem.secure_cfg_rmem.mem_vaddr, |
| tcon_rmem.secure_cfg_rmem.mem_size); |
| } |
| } else { |
| tcon_rmem.secure_cfg_rmem.mem_vaddr = NULL; |
| } |
| |
| /* 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) |
| 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_reserved_memory_init_default(void) |
| { |
| |
| tcon_rmem.rsv_mem_paddr = getenv_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 tcon rsv_mem addr 0x%x from env tcon_mem_addr\n", |
| tcon_rmem.rsv_mem_paddr); |
| } 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 = aml_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; |
| |
| memset(tcon_local_cfg.bin_ver, 0, TCON_BIN_VER_LEN); |
| 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; |
| } |
| |
| void lcd_tcon_init_data_version_update(char *data_buf) |
| { |
| if (!data_buf) |
| return; |
| |
| memcpy(tcon_local_cfg.bin_ver, data_buf, LCD_TCON_INIT_BIN_VERSION_SIZE); |
| tcon_local_cfg.bin_ver[TCON_BIN_VER_LEN - 1] = '\0'; |
| } |
| |
| 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; |
| |
| data_header = malloc(LCD_TCON_DATA_BLOCK_HEADER_SIZE); |
| if (!data_header) { |
| free(buf); |
| return -1; |
| } |
| memset(data_header, 0, LCD_TCON_DATA_BLOCK_HEADER_SIZE); |
| tcon_mm_table.core_reg_header = data_header; |
| |
| key_len = data_len; |
| ret = aml_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; |
| |
| memcpy(data_header, buf, LCD_TCON_DATA_BLOCK_HEADER_SIZE); |
| if (lcd_debug_print_flag) { |
| 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("resolution = %dx%d\n", |
| data_header->h_active, data_header->v_active); |
| LCDPR("block_ctrl = 0x%x\n", data_header->block_ctrl); |
| LCDPR("name = %s\n", data_header->name); |
| } |
| lcd_tcon_init_data_version_update(data_header->version); |
| |
| 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, ver: %s\n", |
| data_len, tcon_local_cfg.bin_ver); |
| 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_reserved_memory_init_dts(char *dt_addr) |
| { |
| int parent_offset, cell_size; |
| char *propdata; |
| |
| parent_offset = fdt_path_offset(dt_addr, "/reserved-memory"); |
| if (parent_offset < 0) { |
| LCDERR("can't find node: /reserved-memory\n"); |
| return -1; |
| } |
| cell_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"); |
| return -1; |
| } |
| |
| propdata = (char *)fdt_getprop(dt_addr, parent_offset, "alloc-ranges", NULL); |
| if (propdata) { |
| if (cell_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 rsv_mem size from dts\n"); |
| return -1; |
| } |
| if (cell_size == 2) |
| tcon_rmem.rsv_mem_size = be32_to_cpup((((u32 *)propdata) + 1)); |
| else |
| tcon_rmem.rsv_mem_size = be32_to_cpup(((u32 *)propdata)); |
| } else { |
| propdata = (char *)fdt_getprop(dt_addr, parent_offset, "reg", NULL); |
| if (!propdata) { |
| LCDERR("failed to get lcd_tcon reserved-memory from dts\n"); |
| return -1; |
| } |
| if (cell_size == 2) { |
| tcon_rmem.rsv_mem_paddr = be32_to_cpup((((u32 *)propdata) + 1)); |
| tcon_rmem.rsv_mem_size = be32_to_cpup((((u32 *)propdata) + 3)); |
| } else { |
| tcon_rmem.rsv_mem_paddr = be32_to_cpup(((u32 *)propdata)); |
| tcon_rmem.rsv_mem_size = be32_to_cpup((((u32 *)propdata) + 1)); |
| } |
| } |
| |
| return 0; |
| } |
| |
| static int lcd_tcon_get_config(char *dt_addr, struct lcd_config_s *pconf, int load_id) |
| { |
| int ret; |
| |
| if (load_id & 0x1) { |
| ret = lcd_tcon_reserved_memory_init_dts(dt_addr); |
| if (ret) |
| lcd_tcon_reserved_memory_init_default(); |
| } else { |
| lcd_tcon_reserved_memory_init_default(); |
| } |
| |
| if (tcon_rmem.rsv_mem_paddr) { |
| if (tcon_rmem.rsv_mem_size < lcd_tcon_conf->rsv_mem_size) { |
| LCDERR("tcon rsv_mem size 0x%x is not enough, need 0x%x\n", |
| tcon_rmem.rsv_mem_size, lcd_tcon_conf->rsv_mem_size); |
| tcon_rmem.rsv_mem_paddr = 0; |
| tcon_rmem.rsv_mem_size = 0; |
| tcon_rmem.flag = 0; |
| } else { |
| tcon_rmem.flag = 1; |
| LCDPR("tcon: rsv_mem addr:0x%x, size:0x%x\n", |
| tcon_rmem.rsv_mem_paddr, tcon_rmem.rsv_mem_size); |
| lcd_tcon_mem_config(); |
| } |
| } |
| |
| 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_bin_load(); |
| |
| #ifdef CONFIG_CMD_INI |
| lcd_tcon_bin_path_resv_mem_set(); |
| #endif |
| |
| 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) { |
| if (ret) |
| LCDPR("%s: tcon invalid\n", __func__); |
| } |
| |
| return ret; |
| } |
| |
| /* ********************************** |
| * tcon match data |
| * ********************************** |
| */ |
| static struct lcd_tcon_config_s tcon_data_txhd = { |
| .tcon_valid = 0, |
| |
| .core_reg_ver = 0, |
| .core_reg_width = LCD_TCON_CORE_REG_WIDTH_TXHD, |
| .reg_table_width = LCD_TCON_TABLE_WIDTH_TXHD, |
| .reg_table_len = LCD_TCON_TABLE_LEN_TXHD, |
| .core_reg_start = TCON_CORE_REG_START_TXHD, |
| |
| .reg_top_ctrl = TCON_TOP_CTRL, |
| .bit_en = BIT_TOP_EN_TXHD, |
| |
| .reg_core_od = REG_CORE_OD_TXHD, |
| .bit_od_en = BIT_OD_EN_TXHD, |
| |
| .reg_ctrl_timing_base = REG_CTRL_TIMING_BASE_TXHD, |
| .ctrl_timing_offset = CTRL_TIMING_OFFSET_TXHD, |
| .ctrl_timing_cnt = CTRL_TIMING_CNT_TXHD, |
| |
| .axi_bank = LCD_TCON_AXI_BANK_TXHD, |
| |
| .rsv_mem_size = 0x00210000, //0x00400000 |
| .axi_size = 0x001fe000, |
| .bin_path_size = 0x00002800, /* 10K */ |
| .secure_cfg_size = 0, |
| .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_txhd, |
| .tcon_axi_mem_secure = NULL, |
| .tcon_axi_mem_update = NULL, |
| .tcon_enable = lcd_tcon_enable_txhd, |
| .tcon_disable = lcd_tcon_disable_tl1, |
| .tcon_forbidden_check = NULL, |
| }; |
| |
| 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 */ |
| .secure_cfg_size = 0, |
| .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_axi_mem_secure = lcd_tcon_axi_mem_secure_tl1, |
| .tcon_axi_mem_update = NULL, |
| .tcon_enable = lcd_tcon_enable_tl1, |
| .tcon_disable = lcd_tcon_disable_tl1, |
| .tcon_forbidden_check = NULL, |
| }; |
| |
| 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_CORE_OD_T5, |
| .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 */ |
| .secure_cfg_size = 0x00000040, /* 64byte */ |
| .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_axi_mem_secure = lcd_tcon_axi_mem_secure_t5, |
| .tcon_axi_mem_update = lcd_tcon_axi_rmem_update_t5, |
| .tcon_enable = lcd_tcon_enable_t5, |
| .tcon_disable = lcd_tcon_disable_t5, |
| .tcon_forbidden_check = lcd_tcon_forbidden_check_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_T5D, |
| .reg_table_width = LCD_TCON_TABLE_WIDTH_T5D, |
| .reg_table_len = LCD_TCON_TABLE_LEN_T5D, |
| .core_reg_start = TCON_CORE_REG_START_T5D, |
| |
| .reg_top_ctrl = REG_LCD_TCON_MAX, |
| .bit_en = BIT_TOP_EN_T5D, |
| |
| .reg_core_od = REG_CORE_OD_T5D, |
| .bit_od_en = BIT_OD_EN_T5D, |
| |
| .reg_ctrl_timing_base = REG_LCD_TCON_MAX, |
| .ctrl_timing_offset = CTRL_TIMING_OFFSET_T5D, |
| .ctrl_timing_cnt = CTRL_TIMING_CNT_T5D, |
| |
| .axi_bank = LCD_TCON_AXI_BANK_T5D, |
| |
| .rsv_mem_size = 0x00800000, /* 8M */ |
| .axi_size = 0x00500000, /* 5M */ |
| .bin_path_size = 0x00002800, /* 10K */ |
| .secure_cfg_size = 0x00000040, /* 64byte */ |
| .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_t5d, |
| .tcon_axi_mem_secure = lcd_tcon_axi_mem_secure_t5, |
| .tcon_axi_mem_update = lcd_tcon_axi_rmem_update_t5d, |
| .tcon_enable = lcd_tcon_enable_t5, |
| .tcon_disable = lcd_tcon_disable_t5, |
| .tcon_forbidden_check = lcd_tcon_forbidden_check_t5d, |
| }; |
| |
| int lcd_tcon_probe(char *dt_addr, struct aml_lcd_drv_s *lcd_drv, int load_id) |
| { |
| int ret = 0; |
| struct lcd_config_s *pconf = lcd_drv->lcd_config; |
| |
| lcd_tcon_conf = NULL; |
| switch (lcd_drv->chip_type) { |
| case LCD_CHIP_TXHD: |
| lcd_tcon_conf = &tcon_data_txhd; |
| break; |
| case LCD_CHIP_TL1: |
| case LCD_CHIP_TM2: |
| if (lcd_tcon_core_flag(lcd_drv->chip_type) == 0) |
| lcd_tcon_conf = &tcon_data_tl1; |
| break; |
| case LCD_CHIP_T5: |
| lcd_tcon_conf = &tcon_data_t5; |
| break; |
| case LCD_CHIP_T5D: |
| lcd_tcon_conf = &tcon_data_t5d; |
| break; |
| case LCD_CHIP_T5W: |
| lcd_tcon_conf = &tcon_data_t5; |
| break; |
| default: |
| break; |
| } |
| if (!lcd_tcon_conf) |
| return 0; |
| |
| lcd_tcon_conf->tcon_valid = 0; |
| switch (pconf->lcd_basic.lcd_type) { |
| case LCD_MLVDS: |
| lcd_tcon_conf->tcon_valid = 1; |
| break; |
| case LCD_P2P: |
| if ((lcd_drv->chip_type == LCD_CHIP_TXHD) || |
| (lcd_drv->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) |
| 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)); |
| lcd_tcon_spi_data_probe(lcd_drv);/*must before tcon_config, for memory alloc*/ |
| ret = lcd_tcon_get_config(dt_addr, pconf, load_id); |
| |
| lcd_drv->lcd_tcon_reg_print = lcd_tcon_reg_readback_print; |
| lcd_drv->lcd_tcon_table_print = lcd_tcon_reg_table_print; |
| lcd_drv->lcd_tcon_vac_print = lcd_tcon_vac_print; |
| lcd_drv->lcd_tcon_demura_print = lcd_tcon_demura_print; |
| lcd_drv->lcd_tcon_acc_print = lcd_tcon_acc_print; |
| lcd_drv->lcd_tcon_data_print = lcd_tcon_data_print; |
| lcd_drv->lcd_tcon_reg_read = lcd_tcon_reg_read; |
| lcd_drv->lcd_tcon_reg_write = lcd_tcon_reg_write; |
| lcd_drv->lcd_tcon_table_read = lcd_tcon_table_read; |
| lcd_drv->lcd_tcon_table_write = lcd_tcon_table_write; |
| #ifdef CONFIG_AMLOGIC_TEE |
| lcd_drv->tcon_mem_tee_protect = lcd_tcon_mem_tee_protect; |
| #else |
| lcd_drv->tcon_mem_tee_protect = NULL; |
| #endif |
| lcd_drv->tcon_forbidden_check = lcd_tcon_forbidden_check; |
| |
| return ret; |
| } |