diff --git a/drivers/media/vout/lcd/lcd_tcon.c b/drivers/media/vout/lcd/lcd_tcon.c index f0b33d78a..8dbc4e25b 100644 --- a/drivers/media/vout/lcd/lcd_tcon.c +++ b/drivers/media/vout/lcd/lcd_tcon.c @@ -2969,6 +2969,26 @@ lcd_tcon_load_init_data_new_err: return -1; } +static int lcd_tcon_dccd_flow_check(struct aml_lcd_drv_s *pdrv) +{ + struct lcd_tcon_fw_s *fw = aml_lcd_tcon_get_fw(); + + if (pdrv->boot_ctrl->dccd_flag && fw && fw->valid) { + //step 1. wait fw alg handle dccd flow + LCDPR("Wait fw alg to handle...\n"); + wait_for_completion(&fw->alg_comp); + + //step 2. update core reg from fw alg + LCDPR("fw alg handle done, update core reg\n"); + memcpy(tcon_mm_table.core_reg_header, fw->config->core_reg_header, + tcon_mm_table.core_reg_header->header_size); + memcpy(tcon_mm_table.core_reg_table, fw->config->core_reg_table, + tcon_mm_table.core_reg_table_size); + } + + return 0; +} + static int lcd_tcon_get_config(struct aml_lcd_drv_s *pdrv) { tcon_mm_table.data_init = NULL; @@ -2994,6 +3014,8 @@ static int lcd_tcon_get_config(struct aml_lcd_drv_s *pdrv) lcd_tcon_debug_file_add(pdrv, &tcon_local_cfg); + lcd_tcon_dccd_flow_check(pdrv); + return 0; } diff --git a/drivers/media/vout/lcd/lcd_tcon_debug.c b/drivers/media/vout/lcd/lcd_tcon_debug.c index 09b85009e..01452f7cc 100644 --- a/drivers/media/vout/lcd/lcd_tcon_debug.c +++ b/drivers/media/vout/lcd/lcd_tcon_debug.c @@ -1228,18 +1228,22 @@ long lcd_tcon_ioctl_handler(struct aml_lcd_drv_s *pdrv, int mcd_nr, unsigned lon struct aml_lcd_tcon_bin_s lcd_tcon_buff; struct tcon_rmem_s *tcon_rmem = get_lcd_tcon_rmem(); struct tcon_mem_map_table_s *mm_table = get_lcd_tcon_mm_table(); + struct lcd_tcon_fw_s *tcon_fw = aml_lcd_tcon_get_fw(); struct lcd_tcon_data_block_header_s block_header, block_header_old; + struct aml_lcd_dccd_config_s dccd_config; unsigned int size = 0, old_size, temp, m = 0, header_size = 0; struct device *dev; phys_addr_t paddr = 0, paddr_old = 0; unsigned char *mem_vaddr = NULL, *vaddr = NULL, *vaddr_old = NULL; char *str = NULL; + unsigned char *buf = NULL; int index = 0; int ret = 0; if (!pdrv) return -EFAULT; + memset(&dccd_config, 0, sizeof(dccd_config)); argp = (void __user *)arg; switch (mcd_nr) { case LCD_IOC_GET_TCON_BIN_MAX_CNT_INFO: @@ -1373,6 +1377,77 @@ set_tcon_bin_error_break: kfree(vaddr); ret = -EFAULT; break; + case TCON_IOC_SET_DCCD: + ret = -EINVAL; + if (copy_from_user(&dccd_config, argp, sizeof(dccd_config))) + goto __dccd_set_exit; + if (dccd_config.size < 4 || dccd_config.size > 0x10000) + goto __dccd_set_exit; + + argp = (void __user *)dccd_config.data.ptr; + buf = kzalloc(dccd_config.size, GFP_KERNEL); + if (unlikely(!buf)) { + LCDERR("Alloc dccd size=%d fail\n", dccd_config.size); + goto __dccd_set_exit; + } + + if (copy_from_user(buf, argp, dccd_config.size)) { + LCDERR("Copy ptr size=%d fail\n", dccd_config.size); + goto __dccd_set_exit; + } + dccd_config.data.ptr = buf; + tcon_fw->buf_table_in = (void *)&dccd_config; + if (tcon_fw->tcon_alg) + ret = tcon_fw->tcon_alg(tcon_fw, 0); +__dccd_set_exit: + kfree(buf); + if (!ret) + complete_all(&tcon_fw->alg_comp); + break; + case TCON_IOC_SET_QUICK_REG: + ret = -EINVAL; + if (!copy_from_user(&temp, argp, sizeof(temp))) { + if (tcon_fw->cmd_handler) { + ret = tcon_fw->cmd_handler(tcon_fw, + FWCMD_AUTOCALC_SET_QK_REG, &temp); + } + } + break; + case TCON_IOC_GET_DCCD_FLG: + temp = !!(tcon_fw->flag & (1 << 8)); + if (!copy_to_user(argp, &temp, sizeof(temp))) + ret = 0; + LCDPR("Get dccd flag(%d) %s!\n", temp, !ret ? "ok" : "error"); + break; + case TCON_IOC_GET_CALC_STATUS: + temp = 0; + ret = -EINVAL; + if (tcon_fw->cmd_handler) { + ret = tcon_fw->cmd_handler(tcon_fw, + FWCMD_AUTOCALC_GET_RDY_FLG, &temp); + } + if (!ret && !copy_to_user(argp, &temp, sizeof(temp))) + ret = 0; + LCDPR("Get dccd status(%d) %s!\n", temp, !ret ? "ok" : "error"); + break; + case TCON_IOC_GET_CALC_BUF: + if (!tcon_fw->config || !tcon_fw->config->core_reg) + goto __tcon_get_calc_exit; + if (copy_from_user(&dccd_config, argp, sizeof(dccd_config))) + goto __tcon_get_calc_exit; + + dccd_config.size = tcon_fw->config->core_reg_size; + if (copy_to_user(argp, &dccd_config, sizeof(dccd_config))) + goto __tcon_get_calc_exit; + + argp = (void __user *)dccd_config.data.ptr; + if (copy_to_user(argp, tcon_fw->config->core_reg, dccd_config.size)) + goto __tcon_get_calc_exit; + ret = 0; + +__tcon_get_calc_exit: + LCDPR("Get tcon calc buf %s\n", ret ? "fail" : "ok"); + break; default: LCDERR("tcon: don't support ioctl cmd_nr: 0x%x\n", mcd_nr); ret = -EINVAL; @@ -1424,7 +1499,12 @@ static long lcd_tcon_ioctl(struct file *file, unsigned int cmd, unsigned long ar case LCD_IOC_SET_TCON_DATA_INDEX_INFO: case LCD_IOC_GET_TCON_BIN_PATH_INFO: case LCD_IOC_SET_TCON_BIN_DATA_INFO: - lcd_tcon_ioctl_handler(pdrv, mcd_nr, arg); + case TCON_IOC_SET_DCCD: + case TCON_IOC_SET_QUICK_REG: + case TCON_IOC_GET_DCCD_FLG: + case TCON_IOC_GET_CALC_BUF: + case TCON_IOC_GET_CALC_STATUS: + ret = lcd_tcon_ioctl_handler(pdrv, mcd_nr, arg); break; default: LCDERR("tcon: don't support ioctl cmd_nr: 0x%x\n", mcd_nr); diff --git a/drivers/media/vout/lcd/lcd_tcon_fw_param.c b/drivers/media/vout/lcd/lcd_tcon_fw_param.c index 32a416bd7..9ddb2402b 100644 --- a/drivers/media/vout/lcd/lcd_tcon_fw_param.c +++ b/drivers/media/vout/lcd/lcd_tcon_fw_param.c @@ -143,6 +143,10 @@ static struct tcon_fw_config_s lcd_tcon_fw_config = { .if_type = TCON_IF_TYPE_MAX, .axi_cnt = 0, .axi_rmem = NULL, + .core_reg = NULL, + .core_reg_size = 0, + .core_reg_header = NULL, + .core_reg_table = NULL, }; static struct tcon_fw_base_timing_s lcd_tcon_fw_base_timing; @@ -305,6 +309,32 @@ void lcd_tcon_fw_prepare(struct aml_lcd_drv_s *pdrv, struct lcd_tcon_config_s *t lcd_tcon_fw.config->axi_rmem[i].mem_size = tcon_rmem->axi_rmem[i].mem_size; } + if (!mm_table->core_reg_table || !mm_table->core_reg_header) { + LCDERR("Invalid core reg table\n"); + kfree(lcd_tcon_fw.config->axi_rmem); + lcd_tcon_fw.config->axi_rmem = NULL; + lcd_tcon_fw.config->axi_cnt = 0; + return; + } + + if (pdrv->boot_ctrl->dccd_flag) { + lcd_tcon_fw.config->core_reg_size = mm_table->core_reg_header->header_size + + mm_table->core_reg_table_size; + lcd_tcon_fw.config->core_reg = + kzalloc(lcd_tcon_fw.config->core_reg_size, GFP_KERNEL); + if (lcd_tcon_fw.config->core_reg) { + memmove(lcd_tcon_fw.config->core_reg, mm_table->core_reg_header, + mm_table->core_reg_header->header_size); + memmove(lcd_tcon_fw.config->core_reg + + mm_table->core_reg_header->header_size, + mm_table->core_reg_table, mm_table->core_reg_table_size); + lcd_tcon_fw.config->core_reg_header = + (struct lcd_tcon_init_block_header_s *)lcd_tcon_fw.config->core_reg; + lcd_tcon_fw.config->core_reg_table = lcd_tcon_fw.config->core_reg + + lcd_tcon_fw.config->core_reg_header->header_size; + } + } + if (pdrv->status & LCD_STATUS_IF_ON) lcd_tcon_fw.tcon_state |= TCON_FW_STATE_TCON_EN; if (mm_table->lut_valid_flag & LCD_TCON_DATA_VALID_VAC) @@ -321,9 +351,11 @@ void lcd_tcon_fw_prepare(struct aml_lcd_drv_s *pdrv, struct lcd_tcon_config_s *t lcd_tcon_fw.tcon_state |= TCON_FW_STATE_LOD_VALID; lcd_tcon_fw_base_timing_update(pdrv); + init_completion(&lcd_tcon_fw.alg_comp); lcd_tcon_fw.drvdat = (void *)pdrv; lcd_tcon_fw.dev = pdrv->dev; + lcd_tcon_fw.flag |= (((unsigned int)pdrv->boot_ctrl->dccd_flag) << 8); lcd_tcon_fw.valid = 1; diff --git a/drivers/media/vout/lcd/lcd_vout.c b/drivers/media/vout/lcd/lcd_vout.c index 371ae6d4e..4d7229b6d 100644 --- a/drivers/media/vout/lcd/lcd_vout.c +++ b/drivers/media/vout/lcd/lcd_vout.c @@ -1530,7 +1530,12 @@ static long lcd_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case LCD_IOC_SET_TCON_DATA_INDEX_INFO: case LCD_IOC_GET_TCON_BIN_PATH_INFO: case LCD_IOC_SET_TCON_BIN_DATA_INFO: - lcd_tcon_ioctl_handler(pdrv, mcd_nr, arg); + case TCON_IOC_SET_DCCD: + case TCON_IOC_SET_QUICK_REG: + case TCON_IOC_GET_DCCD_FLG: + case TCON_IOC_GET_CALC_BUF: + case TCON_IOC_GET_CALC_STATUS: + ret = lcd_tcon_ioctl_handler(pdrv, mcd_nr, arg); break; case LCD_IOC_POWER_CTRL: if (copy_from_user((void *)&temp, argp, sizeof(unsigned int))) { @@ -2081,6 +2086,11 @@ static void lcd_config_default(struct aml_lcd_drv_s *pdrv) pdrv->config.timing.dft_timing.v_period = pdrv->config.timing.act_timing.v_period; if (init_state) { + if (pdrv->boot_ctrl->dccd_flag) { + pdrv->boot_ctrl->init_level = LCD_INIT_LEVEL_KERNEL_ON; + LCDPR("DCCD flow detected!\n"); + } + switch (pdrv->boot_ctrl->init_level) { case LCD_INIT_LEVEL_NORMAL: pdrv->status = (LCD_STATUS_ON | LCD_STATUS_PREPARE | LCD_STATUS_POWER); @@ -2735,6 +2745,7 @@ static int lcd_boot_ctrl_setup(char *str) boot_ctrl->lcd_bits = (data32 >> 4) & 0xf; boot_ctrl->advanced_flag = (data32 >> 8) & 0xff; boot_ctrl->custom_pinmux = (data32 >> 16) & 0x1; + boot_ctrl->dccd_flag = (data32 >> 17) & 0x1; boot_ctrl->init_level = (data32 >> 18) & 0x3; boot_ctrl->ppc = (data32 >> 20) & 0x3; boot_ctrl->clk_mode = (data32 >> 22) & 0x3; @@ -2762,6 +2773,7 @@ static int lcd1_boot_ctrl_setup(char *str) boot_ctrl->lcd_bits = (data32 >> 4) & 0xf; boot_ctrl->advanced_flag = (data32 >> 8) & 0xff; boot_ctrl->custom_pinmux = (data32 >> 16) & 0x1; + boot_ctrl->dccd_flag = (data32 >> 17) & 0x1; boot_ctrl->init_level = (data32 >> 18) & 0x3; boot_ctrl->ppc = (data32 >> 20) & 0x3; boot_ctrl->clk_mode = (data32 >> 22) & 0x3; @@ -2789,6 +2801,7 @@ static int lcd2_boot_ctrl_setup(char *str) boot_ctrl->lcd_bits = (data32 >> 4) & 0xf; boot_ctrl->advanced_flag = (data32 >> 8) & 0xff; boot_ctrl->custom_pinmux = (data32 >> 16) & 0x1; + boot_ctrl->dccd_flag = (data32 >> 17) & 0x1; boot_ctrl->init_level = (data32 >> 18) & 0x3; boot_ctrl->ppc = (data32 >> 20) & 0x3; boot_ctrl->clk_mode = (data32 >> 22) & 0x3; diff --git a/include/linux/amlogic/media/vout/lcd/lcd_tcon_data.h b/include/linux/amlogic/media/vout/lcd/lcd_tcon_data.h index ea43b8214..b10a0f134 100644 --- a/include/linux/amlogic/media/vout/lcd/lcd_tcon_data.h +++ b/include/linux/amlogic/media/vout/lcd/lcd_tcon_data.h @@ -87,7 +87,9 @@ struct lcd_tcon_init_block_header_s { unsigned short ext_header_size; unsigned short block_type; unsigned short block_ctrl; - unsigned char reserved2[5]; + unsigned char dccd_flag; + unsigned char dccd_crc; + unsigned char reserved2[3]; unsigned char data_byte_width; unsigned short chipid; unsigned char name[LCD_TCON_INIT_BIN_NAME_SIZE]; diff --git a/include/linux/amlogic/media/vout/lcd/lcd_tcon_fw.h b/include/linux/amlogic/media/vout/lcd/lcd_tcon_fw.h index 03ec331d9..499191958 100644 --- a/include/linux/amlogic/media/vout/lcd/lcd_tcon_fw.h +++ b/include/linux/amlogic/media/vout/lcd/lcd_tcon_fw.h @@ -7,8 +7,9 @@ #define _INC_AML_LCD_TCON_FW_H #include #include +#include -#define TCON_FW_PARA_VER 2 +#define TCON_FW_PARA_VER 3 enum tcon_fw_chip_e { TCON_CHIP_TL1 = 0, @@ -40,6 +41,11 @@ struct tcon_fw_config_s { unsigned int if_type; unsigned char axi_cnt; struct tcon_fw_axi_rmem_s *axi_rmem; + + unsigned char *core_reg; //full tcon bin + unsigned int core_reg_size; //size of tcon bin + struct lcd_tcon_init_block_header_s *core_reg_header; //tcon bin header + unsigned char *core_reg_table; //tcon bin register map }; struct tcon_fw_base_timing_s { @@ -96,13 +102,19 @@ struct tcon_fw_data_header_s { #define TCON_FW_STATE_OD_VALID 0x00010000 #define TCON_FW_STATE_LOD_VALID 0x00100000 +#define FWCMD_AUTOCALC_SET_QK_REG 0x1 +#define FWCMD_AUTOCALC_GET_RDY_FLG 0x2 + struct lcd_tcon_fw_s { /* init by driver */ unsigned int para_ver; unsigned int para_size; unsigned char valid; + + // bit[8]: dccd flag, indicate running dccd flow unsigned int flag; //for some state update unsigned int tcon_state; + struct completion alg_comp; //indicate alg handle done /* init by fw */ char fw_ver[20]; @@ -142,6 +154,7 @@ struct lcd_tcon_fw_s { int (*tcon_alg)(struct lcd_tcon_fw_s *fw, unsigned int flag); ssize_t (*debug_show)(struct lcd_tcon_fw_s *fw, char *buf); ssize_t (*debug_store)(struct lcd_tcon_fw_s *fw, const char *buf, size_t count); + int (*cmd_handler)(struct lcd_tcon_fw_s *fw, unsigned int cmd, void *data); }; struct lcd_tcon_fw_s *aml_lcd_tcon_get_fw(void); diff --git a/include/linux/amlogic/media/vout/lcd/lcd_vout.h b/include/linux/amlogic/media/vout/lcd/lcd_vout.h index 3df0d9269..4f08daf3b 100644 --- a/include/linux/amlogic/media/vout/lcd/lcd_vout.h +++ b/include/linux/amlogic/media/vout/lcd/lcd_vout.h @@ -608,20 +608,21 @@ struct lcd_config_s { #define LCD_VENC_4PPC 2 /* - *bit[31:24]: base frame rate - *bit[23:22]: clk mode - *bit[21:20]: ppc - *bit[19:18]: lcd_init_level - *bit[17]: reserved - *bit[16]: custom pinmux flag - *bit[15:8]: advanced flag(p2p_type when lcd_type=p2p) - *bit[7:4]: lcd bits - *bit[3:0]: lcd_type + * bit[31:24] : base frame rate + * bit[23:22] : clk mode + * bit[21:20] : ppc + * bit[19:18] : lcd_init_level + * bit[17] : dccd flag + * bit[16] : custom pinmux flag + * bit[15:8] : advanced flag(p2p_type when lcd_type=p2p) + * bit[7:4] : lcd bits + * bit[3:0] : lcd_type */ struct lcd_boot_ctrl_s { unsigned char lcd_type; unsigned char lcd_bits; unsigned char advanced_flag; + unsigned char dccd_flag; unsigned char custom_pinmux; unsigned char init_level; unsigned char ppc; diff --git a/include/uapi/amlogic/lcd.h b/include/uapi/amlogic/lcd.h index 3b41522fc..643b0e3ad 100644 --- a/include/uapi/amlogic/lcd.h +++ b/include/uapi/amlogic/lcd.h @@ -80,6 +80,14 @@ struct aml_lcd_ss_ctl_s { unsigned int mode; }; +struct aml_lcd_dccd_config_s { + unsigned int size; + union { + void *ptr; + unsigned long long unuse; + } data; +}; + #define LCD_IOC_TYPE 'C' #define LCD_IOC_NR_GET_HDR_INFO 0x0 #define LCD_IOC_NR_SET_HDR_INFO 0x1 @@ -96,6 +104,15 @@ struct aml_lcd_ss_ctl_s { #define LCD_IOC_SET_SS 0xc #define LCD_IOC_GET_SS 0xd +/* + * tcon use 0x20~0x2f + */ +#define TCON_IOC_SET_DCCD 0x20 +#define TCON_IOC_SET_QUICK_REG 0x21 +#define TCON_IOC_GET_DCCD_FLG 0x22 +#define TCON_IOC_GET_CALC_BUF 0x23 +#define TCON_IOC_GET_CALC_STATUS 0x24 + #define LCD_IOC_CMD_GET_HDR_INFO \ _IOR(LCD_IOC_TYPE, LCD_IOC_NR_GET_HDR_INFO, struct lcd_optical_info_s) #define LCD_IOC_CMD_SET_HDR_INFO \ @@ -122,5 +139,16 @@ struct aml_lcd_ss_ctl_s { #define LCD_IOC_CMD_GET_SS \ _IOR(LCD_IOC_TYPE, LCD_IOC_GET_SS, struct aml_lcd_ss_ctl_s) +#define TCON_IOC_CMD_SET_DCCD \ + _IOW(LCD_IOC_TYPE, TCON_IOC_SET_DCCD, struct aml_lcd_dccd_config_s) +#define TCON_IOC_CMD_SET_QUICK_REG \ + _IOW(LCD_IOC_TYPE, TCON_IOC_SET_QUICK_REG, unsigned int) +#define TCON_IOC_CMD_GET_DCCD_FLG \ + _IOR(LCD_IOC_TYPE, TCON_IOC_GET_DCCD_FLG, unsigned int) +#define TCON_IOC_CMD_GET_CALC_BUF \ + _IOR(LCD_IOC_TYPE, TCON_IOC_GET_CALC_BUF, struct aml_lcd_dccd_config_s) +#define TCON_IOC_CMD_GET_CALC_STATUS \ + _IOR(LCD_IOC_TYPE, TCON_IOC_GET_CALC_STATUS, unsigned int) + #endif