From 077fbb3a8f830ddb3472ee26166e4c2ebaf9d46e Mon Sep 17 00:00:00 2001 From: Nanxin Qin Date: Wed, 18 Apr 2018 20:24:41 +0800 Subject: [PATCH] fw: update and optimize the fw driver. PD#165763: 1. optimized some codes for fw and package parse. 2. adds a feature that the fw which the best match will be loaded. 3. adds the control of the ver for parsing of fw package. Change-Id: Ia17474df3ff90c6abbe5b617699cfca227f5ea9d Signed-off-by: Nanxin Qin --- .../common/firmware/firmware_cfg.h | 22 +- .../common/firmware/firmware_drv.c | 652 ++++++++++-------- .../common/firmware/firmware_priv.h | 50 +- .../common/firmware/firmware_type.c | 115 +-- .../common/firmware/firmware_type.h | 105 +-- .../frame_provider/decoder/avs/avs.c | 4 +- .../frame_provider/decoder/h264/vh264_mvc.c | 13 +- .../decoder/h264_multi/vmh264.c | 13 +- .../frame_provider/decoder/h265/vh265.c | 47 +- .../frame_provider/decoder/utils/amvdec.c | 71 +- .../frame_provider/decoder/utils/firmware.h | 4 +- .../frame_provider/decoder/vc1/vvc1.c | 20 +- .../frame_provider/decoder/vp9/vvp9.c | 9 +- .../stream_input/amports/amstream.c | 2 +- firmware/video/video_ucode.bin | Bin 739328 -> 768768 bytes 15 files changed, 629 insertions(+), 498 deletions(-) diff --git a/drivers/amlogic/media_modules/common/firmware/firmware_cfg.h b/drivers/amlogic/media_modules/common/firmware/firmware_cfg.h index c98ceef675cb..720b99277038 100644 --- a/drivers/amlogic/media_modules/common/firmware/firmware_cfg.h +++ b/drivers/amlogic/media_modules/common/firmware/firmware_cfg.h @@ -16,27 +16,17 @@ */ /*all firmwares in one bin.*/ -{MESON_CPU_MAJOR_ID_GXBB, VIDEO_PACKAGE, "video_ucode.bin"}, -{MESON_CPU_MAJOR_ID_GXTVBB, VIDEO_PACKAGE, "video_ucode.bin"}, -{MESON_CPU_MAJOR_ID_GXL, VIDEO_PACKAGE, "video_ucode.bin"}, -{MESON_CPU_MAJOR_ID_GXM, VIDEO_PACKAGE, "video_ucode.bin"}, -{MESON_CPU_MAJOR_ID_TXL, VIDEO_PACKAGE, "video_ucode.bin"}, -{MESON_CPU_MAJOR_ID_TXLX, VIDEO_PACKAGE, "video_ucode.bin"}, -{MESON_CPU_MAJOR_ID_G12A, VIDEO_PACKAGE, "video_ucode.bin"}, +{VIDEO_MISC, VIDEO_PACKAGE, "video_ucode.bin"}, /* Note: if the addition of new package has the same name */ /* as the firmware in the video_ucode.bin, the firmware */ /* in the video_ucode.bin will be ignored yet, because the */ /* video_ucode.bin will always be processed in the end */ -{MESON_CPU_MAJOR_ID_GXM, VIDEO_PACKAGE, "h264_enc.bin"}, -{MESON_CPU_MAJOR_ID_GXL, VIDEO_PACKAGE, "h264_enc.bin"}, -{MESON_CPU_MAJOR_ID_TXLX, VIDEO_PACKAGE, "h264_enc.bin"}, -{MESON_CPU_MAJOR_ID_TXL, VIDEO_PACKAGE, "h264_enc.bin"}, -{MESON_CPU_MAJOR_ID_G12A, VIDEO_PACKAGE, "h264_enc.bin"}, +{VIDEO_ENCODE, VIDEO_FW_FILE, "h264_enc.bin"}, + /*firmware for a special format, to replace the format in the package.*/ -{MESON_CPU_MAJOR_ID_GXL, VIDEO_DEC_HEVC, "h265.bin"}, -{MESON_CPU_MAJOR_ID_GXL, VIDEO_DEC_H264, "h264.bin"}, -{MESON_CPU_MAJOR_ID_GXL, VIDEO_DEC_H264_MULTI, "h264_multi.bin"}, - +{VIDEO_DECODE, VIDEO_FW_FILE, "h265.bin"}, +{VIDEO_DECODE, VIDEO_FW_FILE, "h264.bin"}, +{VIDEO_DECODE, VIDEO_FW_FILE, "h264_multi.bin"}, diff --git a/drivers/amlogic/media_modules/common/firmware/firmware_drv.c b/drivers/amlogic/media_modules/common/firmware/firmware_drv.c index 6827bd897f31..3b65de085403 100644 --- a/drivers/amlogic/media_modules/common/firmware/firmware_drv.c +++ b/drivers/amlogic/media_modules/common/firmware/firmware_drv.c @@ -39,6 +39,9 @@ #include #include +/* major.minor.revision */ +#define PACK_VERS "v0.0.1" + #define CLASS_NAME "firmware_codec" #define DEV_NAME "firmware_vdec" #define DIR "video" @@ -56,28 +59,29 @@ static DEFINE_MUTEX(mutex); -static struct ucode_info_s ucode_info[] = { +static struct ucode_file_info_s ucode_info[] = { #include "firmware_cfg.h" }; -static const struct file_operations firmware_fops = { +static const struct file_operations fw_fops = { .owner = THIS_MODULE }; -struct firmware_mgr_s *g_mgr; -struct firmware_dev_s *g_dev; +struct fw_mgr_s *g_mgr; +struct fw_dev_s *g_dev; static u32 debug; +static u32 detail; -int get_firmware_data(enum firmware_type_e type, char *buf) +int get_firmware_data(unsigned int format, char *buf) { int data_len, ret = -1; - struct firmware_mgr_s *mgr = g_mgr; - struct firmware_info_s *info; + struct fw_mgr_s *mgr = g_mgr; + struct fw_info_s *info; if (tee_enabled()) { - pr_info ("tee load firmware type= %d\n",(u32)type); - ret = tee_load_video_fw((u32)type, 0); + pr_info ("tee load firmware fomat = %d\n",(u32)format); + ret = tee_load_video_fw((u32)format, 0); if (ret == 0) ret = 1; else @@ -87,16 +91,16 @@ int get_firmware_data(enum firmware_type_e type, char *buf) mutex_lock(&mutex); - if (list_empty(&mgr->head)) { + if (list_empty(&mgr->fw_head)) { pr_info("the info list is empty.\n"); goto out; } - list_for_each_entry(info, &mgr->head, node) { - if (type != info->type) + list_for_each_entry(info, &mgr->fw_head, node) { + if (format != info->format) continue; - data_len = info->data->header.data_size; + data_len = info->data->head.data_size; memcpy(buf, info->data->data, data_len); ret = data_len; @@ -112,28 +116,28 @@ EXPORT_SYMBOL(get_firmware_data); int get_data_from_name(const char *name, char *buf) { int data_len, ret = -1; - struct firmware_mgr_s *mgr = g_mgr; - struct firmware_info_s *info; - char *firmware_name = __getname(); + struct fw_mgr_s *mgr = g_mgr; + struct fw_info_s *info; + char *fw_name = __getname(); - if (IS_ERR_OR_NULL(firmware_name)) + if (IS_ERR_OR_NULL(fw_name)) return -ENOMEM; - strcat(firmware_name, name); - strcat(firmware_name, ".bin"); + strcat(fw_name, name); + strcat(fw_name, ".bin"); mutex_lock(&mutex); - if (list_empty(&mgr->head)) { + if (list_empty(&mgr->fw_head)) { pr_info("the info list is empty.\n"); goto out; } - list_for_each_entry(info, &mgr->head, node) { - if (strcmp(firmware_name, info->name)) + list_for_each_entry(info, &mgr->fw_head, node) { + if (strcmp(fw_name, info->name)) continue; - data_len = info->data->header.data_size; + data_len = info->data->head.data_size; memcpy(buf, info->data->data, data_len); ret = data_len; @@ -142,13 +146,13 @@ int get_data_from_name(const char *name, char *buf) out: mutex_unlock(&mutex); - __putname(firmware_name); + __putname(fw_name); return ret; } EXPORT_SYMBOL(get_data_from_name); -static int firmware_probe(char *buf) +static int fw_probe(char *buf) { int magic = 0; @@ -160,31 +164,31 @@ static int request_firmware_from_sys(const char *file_name, char *buf, int size) { int ret = -1; - const struct firmware *firmware; + const struct firmware *fw; int magic, offset = 0; - pr_info("Try load %s ...\n", file_name); + pr_info("Try to load %s ...\n", file_name); - ret = request_firmware(&firmware, file_name, g_dev->dev); + ret = request_firmware(&fw, file_name, g_dev->dev); if (ret < 0) { pr_info("Error : %d can't load the %s.\n", ret, file_name); goto err; } - if (firmware->size > size) { + if (fw->size > size) { pr_info("Not enough memory size for ucode.\n"); ret = -ENOMEM; goto release; } - magic = firmware_probe((char *)firmware->data); + magic = fw_probe((char *)fw->data); if (magic != PACK && magic != CODE) { - if (firmware->size < SEC_OFFSET) { + if (fw->size < SEC_OFFSET) { pr_info("This is an invalid firmware file.\n"); goto release; } - magic = firmware_probe((char *)firmware->data + SEC_OFFSET); + magic = fw_probe((char *)fw->data + SEC_OFFSET); if (magic != PACK) { pr_info("The firmware file is not packet.\n"); goto release; @@ -193,18 +197,18 @@ static int request_firmware_from_sys(const char *file_name, offset = SEC_OFFSET; } - memcpy(buf, (char *)firmware->data + offset, firmware->size - offset); + memcpy(buf, (char *)fw->data + offset, fw->size - offset); pr_info("load firmware size : %zd, Name : %s.\n", - firmware->size, file_name); - ret = firmware->size; + fw->size, file_name); + ret = fw->size; release: - release_firmware(firmware); + release_firmware(fw); err: return ret; } -int request_decoder_firmware_on_sys(enum vformat_e type, +int request_decoder_firmware_on_sys(enum vformat_e format, const char *file_name, char *buf, int size) { int ret; @@ -220,21 +224,21 @@ int request_decoder_firmware_on_sys(enum vformat_e type, return ret; } -int get_decoder_firmware_data(enum vformat_e type, +int get_decoder_firmware_data(enum vformat_e format, const char *file_name, char *buf, int size) { int ret; - ret = request_decoder_firmware_on_sys(type, file_name, buf, size); + ret = request_decoder_firmware_on_sys(format, file_name, buf, size); if (ret < 0) pr_info("get_decoder_firmware_data %s for format %d failed!\n", - file_name, type); + file_name, format); return ret; } EXPORT_SYMBOL(get_decoder_firmware_data); -static unsigned long firmware_mgr_lock(struct firmware_mgr_s *mgr) +static unsigned long fw_mgr_lock(struct fw_mgr_s *mgr) { unsigned long flags; @@ -242,98 +246,120 @@ static unsigned long firmware_mgr_lock(struct firmware_mgr_s *mgr) return flags; } -static void firmware_mgr_unlock(struct firmware_mgr_s *mgr, unsigned long flags) +static void fw_mgr_unlock(struct fw_mgr_s *mgr, unsigned long flags) { spin_unlock_irqrestore(&mgr->lock, flags); } -static void add_info(struct firmware_info_s *info) +static void fw_add_info(struct fw_info_s *info) { unsigned long flags; - struct firmware_mgr_s *mgr = g_mgr; + struct fw_mgr_s *mgr = g_mgr; - flags = firmware_mgr_lock(mgr); - list_add(&info->node, &mgr->head); - firmware_mgr_unlock(mgr, flags); + flags = fw_mgr_lock(mgr); + list_add(&info->node, &mgr->fw_head); + fw_mgr_unlock(mgr, flags); } -static void del_info(struct firmware_info_s *info) +static void fw_del_info(struct fw_info_s *info) { unsigned long flags; - struct firmware_mgr_s *mgr = g_mgr; + struct fw_mgr_s *mgr = g_mgr; - flags = firmware_mgr_lock(mgr); + flags = fw_mgr_lock(mgr); list_del(&info->node); - firmware_mgr_unlock(mgr, flags); + kfree(info); + fw_mgr_unlock(mgr, flags); } -static void walk_firmware_info(void) +static void fw_info_walk(void) { - struct firmware_mgr_s *mgr = g_mgr; - struct firmware_info_s *info; + struct fw_mgr_s *mgr = g_mgr; + struct fw_info_s *info; - mutex_lock(&mutex); - - if (list_empty(&mgr->head)) { + if (list_empty(&mgr->fw_head)) { pr_info("the info list is empty.\n"); return; } - list_for_each_entry(info, &mgr->head, node) { + list_for_each_entry(info, &mgr->fw_head, node) { if (IS_ERR_OR_NULL(info->data)) continue; - pr_info("path : %s.\n", info->path); pr_info("name : %s.\n", info->name); - pr_info("version : %s.\n", - info->data->header.version); - pr_info("checksum : 0x%x.\n", - info->data->header.checksum); - pr_info("data size : %d.\n", - info->data->header.data_size); - pr_info("author : %s.\n", - info->data->header.author); - pr_info("date : %s.\n", - info->data->header.date); - pr_info("commit : %s.\n\n", - info->data->header.commit); + pr_info("ver : %s.\n", + info->data->head.version); + pr_info("crc : 0x%x.\n", + info->data->head.checksum); + pr_info("size : %d.\n", + info->data->head.data_size); + pr_info("maker: %s.\n", + info->data->head.maker); + pr_info("from : %s.\n", info->src_from); + pr_info("date : %s.\n\n", + info->data->head.date); + } +} + +static void fw_files_info_walk(void) +{ + struct fw_mgr_s *mgr = g_mgr; + struct fw_files_s *files; + + if (list_empty(&mgr->files_head)) { + pr_info("the file list is empty.\n"); + return; } - mutex_unlock(&mutex); + list_for_each_entry(files, &mgr->files_head, node) { + pr_info("type : %s.\n", !files->fw_type ? + "VIDEO_DECODE" : files->fw_type == 1 ? + "VIDEO_ENCODE" : "VIDEO_MISC"); + pr_info("from : %s.\n", !files->file_type ? + "VIDEO_PACKAGE" : "VIDEO_FW_FILE"); + pr_info("path : %s.\n", files->path); + pr_info("name : %s.\n\n", files->name); + } } static ssize_t info_show(struct class *class, struct class_attribute *attr, char *buf) { char *pbuf = buf; - struct firmware_mgr_s *mgr = g_mgr; - struct firmware_info_s *info; + struct fw_mgr_s *mgr = g_mgr; + struct fw_info_s *info; mutex_lock(&mutex); - if (list_empty(&mgr->head)) { + if (list_empty(&mgr->fw_head)) { pbuf += sprintf(pbuf, "No firmware.\n"); goto out; } - list_for_each_entry(info, &mgr->head, node) { + list_for_each_entry(info, &mgr->fw_head, node) { if (IS_ERR_OR_NULL(info->data)) continue; - pr_info("%10s : %s\n", "from", info->src_from); - pr_info("%10s : %s\n", "name", info->name); - pr_info("%10s : %d\n", "size", - info->data->header.data_size); - pr_info("%10s : %s\n", "ver", - info->data->header.version); - pr_info("%10s : 0x%x\n", "sum", - info->data->header.checksum); - pr_info("%10s : %s\n", "commit", - info->data->header.commit); - pr_info("%10s : %s\n", "author", - info->data->header.author); - pr_info("%10s : %s\n\n", "date", - info->data->header.date); + if (detail) { + pr_info("%-5s: %s\n", "name", info->name); + pr_info("%-5s: %s\n", "ver", + info->data->head.version); + pr_info("%-5s: 0x%x\n", "sum", + info->data->head.checksum); + pr_info("%-5s: %d\n", "size", + info->data->head.data_size); + pr_info("%-5s: %s\n", "maker", + info->data->head.maker); + pr_info("%-5s: %s\n", "from", + info->src_from); + pr_info("%-5s: %s\n\n", "date", + info->data->head.date); + continue; + } + + pr_info("fmt: %-16s, crc: 0x%-8x, size: %-5d, file: %s\n", + info->data->head.format, info->data->head.checksum, + info->data->head.data_size, info->data->head.name); } out: mutex_unlock(&mutex); @@ -341,12 +367,12 @@ out: return pbuf - buf; } -static int set_firmware_info(void) +static int fw_info_fill(void) { int ret = 0, i, len; - struct firmware_info_s *info; + struct fw_mgr_s *mgr = g_mgr; + struct fw_files_s *files; int info_size = ARRAY_SIZE(ucode_info); - int cpu = get_cpu_type(); char *path = __getname(); const char *name; @@ -354,9 +380,6 @@ static int set_firmware_info(void) return -ENOMEM; for (i = 0; i < info_size; i++) { - if (cpu != ucode_info[i].cpu) - continue; - name = ucode_info[i].name; if (IS_ERR_OR_NULL(name)) break; @@ -366,70 +389,127 @@ static int set_firmware_info(void) if (len >= PATH_MAX) continue; - info = kzalloc(sizeof(struct firmware_info_s), GFP_KERNEL); - if (IS_ERR_OR_NULL(info)) { + files = kzalloc(sizeof(struct fw_files_s), GFP_KERNEL); + if (IS_ERR_OR_NULL(files)) { __putname(path); return -ENOMEM; } - strcpy(info->path, path); - strcpy(info->name, name); - strcpy(info->src_from, name); - info->type = ucode_info[i].type; - info->data = NULL; + files->file_type = ucode_info[i].file_type; + files->fw_type = ucode_info[i].fw_type; + strncpy(files->path, path, sizeof(files->path)); + strncpy(files->name, name, sizeof(files->name)); - add_info(info); + list_add(&files->node, &mgr->files_head); } __putname(path); + if (debug) + fw_files_info_walk(); + return ret; } -static int checksum(struct firmware_s *firmware) +static int fw_data_check_sum(struct firmware_s *fw) { unsigned int crc; - crc = crc32_le(~0U, firmware->data, firmware->header.data_size); + crc = crc32_le(~0U, fw->data, fw->head.data_size); - if (debug) - pr_info("firmware crc result : 0x%x\n", crc ^ ~0U); + /*pr_info("firmware crc result : 0x%x\n", crc ^ ~0U);*/ - return firmware->header.checksum != (crc ^ ~0U) ? 0 : 1; + return fw->head.checksum != (crc ^ ~0U) ? 0 : 1; } -static int check_repeat(struct firmware_s *data, enum firmware_type_e type) +static int fw_data_filter(struct firmware_s *fw, + struct fw_info_s *fw_info) { - struct firmware_mgr_s *mgr = g_mgr; - struct firmware_info_s *info; + struct fw_mgr_s *mgr = g_mgr; + struct fw_info_s *info, *tmp; + int cpu = fw_get_cpu(fw->head.cpu); - if (list_empty(&mgr->head)) { - pr_info("the info list is empty.\n"); + if (mgr->cur_cpu < cpu) { + pr_info("the fw %s is not match.\n", fw_info->name); + kfree(fw_info); + kfree(fw); return -1; } - if (type == FIRMWARE_MAX) + /* the encode fw need to ignoring filtering rules. */ + if (fw_info->format == FIRMWARE_MAX) return 0; - list_for_each_entry(info, &mgr->head, node) { - if (info->type != type) + list_for_each_entry_safe(info, tmp, &mgr->fw_head, node) { + if (info->format != fw_info->format) continue; - if (IS_ERR_OR_NULL(info->data)) - info->data = data; + if (IS_ERR_OR_NULL(info->data)) { + fw_del_info(info); + return 0; + } - return 1; + /* high priority of VIDEO_FW_FILE */ + if (info->file_type == VIDEO_FW_FILE) { + pr_info("the %s need to priority proc.\n",info->name); + kfree(fw_info); + kfree(fw); + return 1; + } + + /* the cpu ver is lower and needs to be filtered */ + if (cpu < fw_get_cpu(info->data->head.cpu)) { + pr_info("the fw %s is not match.\n", + fw_info->name); + kfree(fw_info); + kfree(fw); + return 1; + } + + /* removes not match fw from info list */ + pr_info("the fw %s is not match.\n", info->name); + kfree(info->data); + fw_del_info(info); } return 0; } -static int firmware_parse_package(struct firmware_info_s *fw_info, +static int fw_check_pack_version(char *buf) +{ + struct package_s *pack = NULL; + int major, minor, rev, ver = 0; + + pack = (struct package_s *) buf; + sscanf(PACK_VERS, "v%x.%x.%x", &major, &minor, &rev); + ver = (major << 24 | minor << 16 | rev); + + pr_info("the package has %d fws totally.\n", pack->head.total); + + major = pack->head.version >> 24; + minor = (pack->head.version >> 16) & 0xf; + rev = pack->head.version & 0xff; + + if (ver < pack->head.version) { + pr_info("the pack ver v%d.%d.%d too higher to unsupport.\n", + major, minor, rev); + return -1; + } + + if (ver != pack->head.version) { + pr_info("the fw pack ver v%d.%d.%d is too lower.\n", major, minor, rev); + pr_info("it may work abnormally so need to be update in time.\n"); + } + + return 0; +} + +static int fw_package_parse(struct fw_files_s *files, char *buf, int size) { int ret = 0; struct package_info_s *pack_info; - struct firmware_info_s *info; + struct fw_info_s *info; struct firmware_s *data; char *pack_data; int info_len, len; @@ -444,15 +524,15 @@ static int firmware_parse_package(struct firmware_info_s *fw_info, info_len = sizeof(struct package_info_s); do { - if (!pack_info->header.length) + if (!pack_info->head.length) break; len = snprintf(path, PATH_MAX, "%s/%s", DIR, - pack_info->header.name); + pack_info->head.name); if (len >= PATH_MAX) continue; - info = kzalloc(sizeof(struct firmware_info_s), GFP_KERNEL); + info = kzalloc(sizeof(struct fw_info_s), GFP_KERNEL); if (IS_ERR_OR_NULL(info)) { ret = -ENOMEM; goto out; @@ -465,39 +545,34 @@ static int firmware_parse_package(struct firmware_info_s *fw_info, goto out; } - strcpy(info->path, path); - strcpy(info->name, pack_info->header.name); - strcpy(info->src_from, fw_info->src_from); - info->type = get_firmware_type(pack_info->header.format); + info->file_type = files->file_type; + strncpy(info->src_from, files->name, + sizeof(info->src_from)); + strncpy(info->name, pack_info->head.name, + sizeof(info->name)); + info->format = get_fw_format(pack_info->head.format); - len = pack_info->header.length; + len = pack_info->head.length; memcpy(data, pack_info->data, len); - pack_data += (pack_info->header.length + info_len); + pack_data += (pack_info->head.length + info_len); pack_info = (struct package_info_s *)pack_data; - ret = checksum(data); - if (!ret) { + if (!fw_data_check_sum(data)) { pr_info("check sum fail !\n"); kfree(data); kfree(info); goto out; } - ret = check_repeat(data, info->type); - if (ret < 0) { - kfree(data); - kfree(info); - goto out; - } - - if (ret) { - kfree(info); + if (fw_data_filter(data, info)) continue; - } + + if (debug) + pr_info("adds %s to the fw list.\n", info->name); info->data = data; - add_info(info); + fw_add_info(info); } while (try_cnt--); out: __putname(path); @@ -505,24 +580,35 @@ out: return ret; } -static int firmware_parse_code(struct firmware_info_s *info, +static int fw_code_parse(struct fw_files_s *files, char *buf, int size) { - if (!IS_ERR_OR_NULL(info->data)) - kfree(info->data); + struct fw_info_s *info; + + info = kzalloc(sizeof(struct fw_info_s), GFP_KERNEL); + if (IS_ERR_OR_NULL(info)) + return -ENOMEM; info->data = kzalloc(FRIMWARE_SIZE, GFP_KERNEL); if (IS_ERR_OR_NULL(info->data)) return -ENOMEM; + info->file_type = files->file_type; + strncpy(info->src_from, files->name, + sizeof(info->src_from)); memcpy(info->data, buf, size); - if (!checksum(info->data)) { + if (!fw_data_check_sum(info->data)) { pr_info("check sum fail !\n"); kfree(info->data); return -1; } + if (debug) + pr_info("adds %s to the fw list.\n", info->name); + + fw_add_info(info); + return 0; } @@ -538,89 +624,141 @@ static int get_firmware_from_sys(const char *path, return len; } -static int set_firmware_data(void) +static int fw_data_binding(void) { int ret = 0, magic = 0; - struct firmware_mgr_s *mgr = g_mgr; - struct firmware_info_s *info, *temp; - char *buf = NULL; + struct fw_mgr_s *mgr = g_mgr; + struct fw_files_s *files, *tmp; + char *buf = vmalloc(BUFF_SIZE); int size; - if (list_empty(&mgr->head)) { - pr_info("the info list is empty.\n"); + if (list_empty(&mgr->files_head)) { + pr_info("the file list is empty.\n"); return 0; } - buf = vmalloc(BUFF_SIZE); if (IS_ERR_OR_NULL(buf)) return -ENOMEM; memset(buf, 0, BUFF_SIZE); - list_for_each_entry_safe(info, temp, &mgr->head, node) { - size = get_firmware_from_sys(info->path, buf, BUFF_SIZE); - magic = firmware_probe(buf); + list_for_each_entry_safe(files, tmp, &mgr->files_head, node) { + size = get_firmware_from_sys(files->path, buf, BUFF_SIZE); + magic = fw_probe(buf); - switch (magic) { - case PACK: - ret = firmware_parse_package(info, buf, size); + if (files->file_type == VIDEO_PACKAGE && magic == PACK) { + pr_info("start to parse fw package.\n"); - del_info(info); - kfree(info); - break; + if (!fw_check_pack_version(buf)) + ret = fw_package_parse(files, buf, size); + } else if (files->file_type == VIDEO_FW_FILE && magic == CODE) { + pr_info("start to parse fw code.\n"); - case CODE: - ret = firmware_parse_code(info, buf, size); - break; - - default: - del_info(info); - kfree(info); - pr_info("invaild type.\n"); + ret = fw_code_parse(files, buf, size); + } else { + list_del(&files->node); + kfree(files); + pr_info("invaild file type.\n"); } memset(buf, 0, BUFF_SIZE); } if (debug) - walk_firmware_info(); + fw_info_walk(); vfree(buf); return ret; } -static int firmware_pre_load(void) +static int fw_pre_load(void) { - int ret = -1; - - ret = set_firmware_info(); - if (ret < 0) { + if (fw_info_fill() < 0) { pr_info("Get path fail.\n"); - goto err; + return -1; } - ret = set_firmware_data(); - if (ret < 0) { + if (fw_data_binding() < 0) { pr_info("Set data fail.\n"); - goto err; + return -1; } -err: - return ret; + + return 0; } -static int firmware_mgr_init(void) +static int fw_mgr_init(void) { - g_mgr = kzalloc(sizeof(struct firmware_mgr_s), GFP_KERNEL); + g_mgr = kzalloc(sizeof(struct fw_mgr_s), GFP_KERNEL); if (IS_ERR_OR_NULL(g_mgr)) return -ENOMEM; - INIT_LIST_HEAD(&g_mgr->head); + g_mgr->cur_cpu = get_cpu_type(); + INIT_LIST_HEAD(&g_mgr->files_head); + INIT_LIST_HEAD(&g_mgr->fw_head); spin_lock_init(&g_mgr->lock); return 0; } +static void fw_ctx_clean(void) +{ + struct fw_mgr_s *mgr = g_mgr; + struct fw_files_s *files; + struct fw_info_s *info; + unsigned long flags; + + flags = fw_mgr_lock(mgr); + while (!list_empty(&mgr->files_head)) { + files = list_entry(mgr->files_head.next, + struct fw_files_s, node); + list_del(&files->node); + kfree(files); + } + + while (!list_empty(&mgr->fw_head)) { + info = list_entry(mgr->fw_head.next, + struct fw_info_s, node); + list_del(&info->node); + kfree(info->data); + kfree(info); + } + fw_mgr_unlock(mgr, flags); +} + +int video_fw_reload(int mode) +{ + int ret = 0; + struct fw_mgr_s *mgr = g_mgr; + + if (tee_enabled()) + return 0; + + mutex_lock(&mutex); + + if (mode & FW_LOAD_FORCE) { + fw_ctx_clean(); + + ret = fw_pre_load(); + if (ret < 0) + pr_err("The fw reload fail.\n"); + } else if (mode & FW_LOAD_TRY) { + if (!list_empty(&mgr->fw_head)) { + pr_info("The fw has been loaded.\n"); + goto out; + } + + ret = fw_pre_load(); + if (ret < 0) + pr_err("The fw try to reload fail.\n"); + } +out: + mutex_unlock(&mutex); + + return ret; +} +EXPORT_SYMBOL(video_fw_reload); + static ssize_t reload_show(struct class *class, struct class_attribute *attr, char *buf) { @@ -633,46 +771,6 @@ static ssize_t reload_show(struct class *class, return pbuf - buf; } -int firmware_reload(int mode) -{ - int ret = 0; - struct firmware_mgr_s *mgr = g_mgr; - struct firmware_info_s *info = NULL; - - if (tee_enabled()) - return 0; - - mutex_lock(&mutex); - - if (mode & FW_LOAD_FORCE) { - while (!list_empty(&mgr->head)) { - info = list_entry(mgr->head.next, - struct firmware_info_s, node); - list_del(&info->node); - kfree(info->data); - kfree(info); - } - - ret = firmware_pre_load(); - if (ret < 0) - pr_err("The fw reload fail.\n"); - } else if (mode & FW_LOAD_TRY) { - if (!list_empty(&mgr->head)) { - pr_info("The fw has been loaded.\n"); - goto out; - } - - ret = firmware_pre_load(); - if (ret < 0) - pr_err("The fw try to reload fail.\n"); - } -out: - mutex_unlock(&mutex); - - return ret; -} -EXPORT_SYMBOL(firmware_reload); - static ssize_t reload_store(struct class *class, struct class_attribute *attr, const char *buf, size_t size) @@ -684,29 +782,61 @@ static ssize_t reload_store(struct class *class, if (ret != 0) return -EINVAL; - ret = firmware_reload(val); + ret = video_fw_reload(val); if (ret < 0) pr_err("fw reload fail.\n"); return size; } -static struct class_attribute firmware_class_attrs[] = { +static ssize_t debug_show(struct class *cls, + struct class_attribute *attr, char *buf) +{ + return sprintf(buf, "%x\n", debug); +} + +static ssize_t debug_store(struct class *cls, + struct class_attribute *attr, const char *buf, size_t count) +{ + if (kstrtoint(buf, 0, &debug) < 0) + return -EINVAL; + + return count; +} + +static ssize_t detail_show(struct class *cls, + struct class_attribute *attr, char *buf) +{ + return sprintf(buf, "%x\n", detail); +} + +static ssize_t detail_store(struct class *cls, + struct class_attribute *attr, const char *buf, size_t count) +{ + if (kstrtoint(buf, 0, &detail) < 0) + return -EINVAL; + + return count; +} + +static struct class_attribute fw_class_attrs[] = { __ATTR_RO(info), __ATTR(reload, 0664, reload_show, reload_store), + __ATTR(debug, 0664, debug_show, debug_store), + __ATTR(detail, 0664, detail_show, detail_store), __ATTR_NULL }; -static struct class firmware_class = { +static struct class fw_class = { .name = CLASS_NAME, - .class_attrs = firmware_class_attrs, + .class_attrs = fw_class_attrs, }; -static int firmware_driver_init(void) +static int fw_driver_init(void) { int ret = -1; - g_dev = kzalloc(sizeof(struct firmware_dev_s), GFP_KERNEL); + g_dev = kzalloc(sizeof(struct fw_dev_s), GFP_KERNEL); if (IS_ERR_OR_NULL(g_dev)) return -ENOMEM; @@ -718,7 +848,7 @@ static int firmware_driver_init(void) goto err; } - cdev_init(&g_dev->cdev, &firmware_fops); + cdev_init(&g_dev->cdev, &fw_fops); g_dev->cdev.owner = THIS_MODULE; ret = cdev_add(&g_dev->cdev, g_dev->dev_no, 1); @@ -727,13 +857,13 @@ static int firmware_driver_init(void) goto err; } - ret = class_register(&firmware_class); + ret = class_register(&fw_class); if (ret < 0) { pr_info("Failed in creating class.\n"); goto err; } - g_dev->dev = device_create(&firmware_class, NULL, + g_dev->dev = device_create(&fw_class, NULL, g_dev->dev_no, NULL, DEV_NAME); if (IS_ERR_OR_NULL(g_dev->dev)) { pr_info("Create device failed.\n"); @@ -746,51 +876,33 @@ err: return ret; } -static void firmware_info_clean(void) +static void fw_driver_exit(void) { - struct firmware_mgr_s *mgr = g_mgr; - struct firmware_info_s *info; - unsigned long flags; - - flags = firmware_mgr_lock(mgr); - while (!list_empty(&mgr->head)) { - info = list_entry(mgr->head.next, - struct firmware_info_s, node); - list_del(&info->node); - kfree(info->data); - kfree(info); - } - firmware_mgr_unlock(mgr, flags); - + cdev_del(&g_dev->cdev); + device_destroy(&fw_class, g_dev->dev_no); + class_unregister(&fw_class); + unregister_chrdev_region(g_dev->dev_no, 1); + kfree(g_dev); kfree(g_mgr); } -static void firmware_driver_exit(void) -{ - cdev_del(&g_dev->cdev); - device_destroy(&firmware_class, g_dev->dev_no); - class_unregister(&firmware_class); - unregister_chrdev_region(g_dev->dev_no, 1); - kfree(g_dev); -} - -static int __init firmware_module_init(void) +static int __init fw_module_init(void) { int ret = -1; - ret = firmware_driver_init(); + ret = fw_driver_init(); if (ret) { pr_info("Error %d firmware driver init fail.\n", ret); goto err; } - ret = firmware_mgr_init(); + ret = fw_mgr_init(); if (ret) { pr_info("Error %d firmware mgr init fail.\n", ret); goto err; } - ret = firmware_pre_load(); + ret = fw_pre_load(); if (ret) { pr_info("Error %d firmware pre load fail.\n", ret); goto err; @@ -799,17 +911,15 @@ err: return ret; } -static void __exit firmware_module_exit(void) +static void __exit fw_module_exit(void) { - firmware_info_clean(); - firmware_driver_exit(); + fw_ctx_clean(); + fw_driver_exit(); pr_info("Firmware driver cleaned up.\n"); } -module_param(debug, uint, 0664); - -module_init(firmware_module_init); -module_exit(firmware_module_exit); +module_init(fw_module_init); +module_exit(fw_module_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Nanxin Qin "); diff --git a/drivers/amlogic/media_modules/common/firmware/firmware_priv.h b/drivers/amlogic/media_modules/common/firmware/firmware_priv.h index 4b03fd8e9b0a..811fdc6e0159 100644 --- a/drivers/amlogic/media_modules/common/firmware/firmware_priv.h +++ b/drivers/amlogic/media_modules/common/firmware/firmware_priv.h @@ -15,42 +15,52 @@ * */ -#ifndef __VIDEO_FIRMWARE_PRIV_HEADER_ -#define __VIDEO_FIRMWARE_PRIV_HEADER_ +#ifndef __VIDEO_FIRMWARE_PRIV_HEAD_ +#define __VIDEO_FIRMWARE_PRIV_HEAD_ #include #include #include #include #include "firmware_type.h" -struct firmware_mgr_s { - struct list_head head; +struct fw_mgr_s { + struct list_head fw_head; + struct list_head files_head; spinlock_t lock; + int cur_cpu; }; -struct firmware_info_s { +struct fw_files_s { struct list_head node; + int fw_type; + int file_type; char name[32]; char path[64]; - char src_from[32]; - enum firmware_type_e type; - struct firmware_s *data; }; -struct ucode_info_s { - int cpu; - enum firmware_type_e type; +struct ucode_file_info_s { + int fw_type; + int file_type; const char *name; }; -struct firmware_header_s { +struct fw_info_s { + struct list_head node; + char name[32]; + char src_from[32]; + int file_type; + unsigned int format; + struct firmware_s *data; +}; + +struct fw_head_s { int magic; int checksum; char name[32]; char cpu[16]; char format[32]; char version[32]; - char author[32]; + char maker[32]; char date[32]; char commit[16]; int data_size; @@ -60,28 +70,30 @@ struct firmware_header_s { struct firmware_s { union { - struct firmware_header_s header; + struct fw_head_s head; char buf[512]; }; char data[0]; }; -struct package_header_s { +struct package_head_s { int magic; int size; int checksum; + int total; + int version; char reserved[128]; }; struct package_s { union { - struct package_header_s header; + struct package_head_s head; char buf[256]; }; char data[0]; }; -struct info_header_s { +struct info_head_s { char name[32]; char format[32]; char cpu[32]; @@ -90,13 +102,13 @@ struct info_header_s { struct package_info_s { union { - struct info_header_s header; + struct info_head_s head; char buf[256]; }; char data[0]; }; -struct firmware_dev_s { +struct fw_dev_s { struct cdev cdev; struct device *dev; dev_t dev_no; diff --git a/drivers/amlogic/media_modules/common/firmware/firmware_type.c b/drivers/amlogic/media_modules/common/firmware/firmware_type.c index 5975c733c259..b2d9f17d6572 100644 --- a/drivers/amlogic/media_modules/common/firmware/firmware_type.c +++ b/drivers/amlogic/media_modules/common/firmware/firmware_type.c @@ -1,67 +1,92 @@ #include "firmware_type.h" +#include -static const struct type_name_s type_name[] = { - {VIDEO_DEC_MPEG12, "mpeg12"}, - {VIDEO_DEC_MPEG4_3, "divx311"}, - {VIDEO_DEC_MPEG4_4, "divx4x"}, - {VIDEO_DEC_MPEG4_5, "xvid"}, - {VIDEO_DEC_H263, "h263"}, - {VIDEO_DEC_MJPEG, "mjpeg"}, - {VIDEO_DEC_MJPEG_MULTI, "mjpeg_multi"}, - {VIDEO_DEC_REAL_V8, "real_v8"}, - {VIDEO_DEC_REAL_V9, "real_v9"}, - {VIDEO_DEC_VC1, "vc1"}, - {VIDEO_DEC_VC1_G12A, "vc1_g12a"}, - {VIDEO_DEC_AVS, "avs"}, - {VIDEO_DEC_AVS_GXM, "avs_gxm"}, - {VIDEO_DEC_AVS_NOCABAC, "avs_no_cabac"}, - {VIDEO_DEC_H264, "h264"}, - {VIDEO_DEC_H264_4k2K, "h264_4k2k"}, - {VIDEO_DEC_H264_4k2K_SINGLE, "h264_4k2k_single"}, - {VIDEO_DEC_H264_MVC, "h264_mvc"}, - {VIDEO_DEC_H264_MVC_GXM, "h264_mvc_gxm"}, - {VIDEO_DEC_H264_MULTI, "h264_multi"}, - {VIDEO_DEC_H264_MULTI_MMU, "h264_multi_mmu"}, - {VIDEO_DEC_H264_MULTI_GXM, "h264_multi_gxm"}, - {VIDEO_DEC_HEVC, "hevc"}, - {VIDEO_DEC_HEVC_MMU, "hevc_mmu"}, - {VIDEO_DEC_HEVC_G12A, "hevc_g12a"}, - {VIDEO_DEC_VP9, "vp9"}, - {VIDEO_DEC_VP9_MMU, "vp9_mmu"}, - {VIDEO_DEC_VP9_G12A, "vp9_g12a"}, - {VIDEO_DEC_AVS2, "avs2"}, - {VIDEO_DEC_AVS2_MMU, "avs2_mmu"}, - {VIDEO_ENC_H264, "h264_enc"}, - {VIDEO_ENC_JPEG, "jpeg_enc"}, - {FIRMWARE_MAX, "unknown"}, +static const struct format_name_s format_name[] = { + {VIDEO_DEC_MPEG12, "mpeg12"}, + {VIDEO_DEC_MPEG12_MULTI, "mpeg12_multi"}, + {VIDEO_DEC_MPEG4_3, "divx311"}, + {VIDEO_DEC_MPEG4_4, "divx4x"}, + {VIDEO_DEC_MPEG4_4_MULTI, "divx4x_multi"}, + {VIDEO_DEC_MPEG4_5, "xvid"}, + {VIDEO_DEC_MPEG4_5_MULTI, "xvid_multi"}, + {VIDEO_DEC_H263, "h263"}, + {VIDEO_DEC_H263_MULTI, "h263_multi"}, + {VIDEO_DEC_MJPEG, "mjpeg"}, + {VIDEO_DEC_MJPEG_MULTI, "mjpeg_multi"}, + {VIDEO_DEC_REAL_V8, "real_v8"}, + {VIDEO_DEC_REAL_V9, "real_v9"}, + {VIDEO_DEC_VC1, "vc1"}, + {VIDEO_DEC_VC1_G12A, "vc1_g12a"}, + {VIDEO_DEC_AVS, "avs"}, + {VIDEO_DEC_AVS_GXM, "avs_gxm"}, + {VIDEO_DEC_AVS_NOCABAC, "avs_no_cabac"}, + {VIDEO_DEC_H264, "h264"}, + {VIDEO_DEC_H264_4k2K, "h264_4k2k"}, + {VIDEO_DEC_H264_4k2K_SINGLE, "h264_4k2k_single"}, + {VIDEO_DEC_H264_MVC, "h264_mvc"}, + {VIDEO_DEC_H264_MVC_GXM, "h264_mvc_gxm"}, + {VIDEO_DEC_H264_MULTI, "h264_multi"}, + {VIDEO_DEC_H264_MULTI_MMU, "h264_multi_mmu"}, + {VIDEO_DEC_H264_MULTI_GXM, "h264_multi_gxm"}, + {VIDEO_DEC_HEVC, "hevc"}, + {VIDEO_DEC_HEVC_MMU, "hevc_mmu"}, + {VIDEO_DEC_HEVC_G12A, "hevc_g12a"}, + {VIDEO_DEC_VP9, "vp9"}, + {VIDEO_DEC_VP9_MMU, "vp9_mmu"}, + {VIDEO_DEC_VP9_G12A, "vp9_g12a"}, + {VIDEO_DEC_AVS2, "avs2"}, + {VIDEO_DEC_AVS2_MMU, "avs2_mmu"}, + {VIDEO_ENC_H264, "h264_enc"}, + {VIDEO_ENC_JPEG, "jpeg_enc"}, + {FIRMWARE_MAX, "unknown"}, }; +static const struct cpu_type_s cpu_type[] = { + {MESON_CPU_MAJOR_ID_GXL, "gxl"}, + {MESON_CPU_MAJOR_ID_GXM, "gxm"}, + {MESON_CPU_MAJOR_ID_G12A, "g12a"}, + {MESON_CPU_MAJOR_ID_G12B, "g12b"}, +}; -const char *get_firmware_type_name(enum firmware_type_e type) +const char *get_fw_format_name(unsigned int format) { const char *name = "unknown"; - int i, size = ARRAY_SIZE(type_name); + int i, size = ARRAY_SIZE(format_name); for (i = 0; i < size; i++) { - if (type == type_name[i].type) - name = type_name[i].name; + if (format == format_name[i].format) + name = format_name[i].name; } return name; } -EXPORT_SYMBOL(get_firmware_type_name); +EXPORT_SYMBOL(get_fw_format_name); -enum firmware_type_e get_firmware_type(const char *name) +unsigned int get_fw_format(const char *name) { - enum firmware_type_e type = FIRMWARE_MAX; - int i, size = ARRAY_SIZE(type_name); + unsigned int format = FIRMWARE_MAX; + int i, size = ARRAY_SIZE(format_name); for (i = 0; i < size; i++) { - if (!strcmp(name, type_name[i].name)) - type = type_name[i].type; + if (!strcmp(name, format_name[i].name)) + format = format_name[i].format; + } + + return format; +} +EXPORT_SYMBOL(get_fw_format); + +int fw_get_cpu(const char *name) +{ + int type = 0; + int i, size = ARRAY_SIZE(cpu_type); + + for (i = 0; i < size; i++) { + if (!strcmp(name, cpu_type[i].name)) + type = cpu_type[i].type; } return type; } -EXPORT_SYMBOL(get_firmware_type); +EXPORT_SYMBOL(fw_get_cpu); diff --git a/drivers/amlogic/media_modules/common/firmware/firmware_type.h b/drivers/amlogic/media_modules/common/firmware/firmware_type.h index 94c5a9a0f1fd..f51956bbf561 100644 --- a/drivers/amlogic/media_modules/common/firmware/firmware_type.h +++ b/drivers/amlogic/media_modules/common/firmware/firmware_type.h @@ -3,49 +3,74 @@ #include -enum firmware_type_e { - VIDEO_DEC_MPEG12, - VIDEO_DEC_MPEG4_3, - VIDEO_DEC_MPEG4_4, - VIDEO_DEC_MPEG4_5, - VIDEO_DEC_H263, - VIDEO_DEC_MJPEG, - VIDEO_DEC_MJPEG_MULTI, - VIDEO_DEC_REAL_V8, - VIDEO_DEC_REAL_V9, - VIDEO_DEC_VC1, - VIDEO_DEC_AVS, - VIDEO_DEC_H264, - VIDEO_DEC_H264_4k2K, - VIDEO_DEC_H264_4k2K_SINGLE, - VIDEO_DEC_H264_MVC, - VIDEO_DEC_H264_MULTI, - VIDEO_DEC_HEVC, - VIDEO_DEC_HEVC_MMU, - VIDEO_DEC_VP9, - VIDEO_DEC_VP9_MMU, - VIDEO_ENC_H264, - VIDEO_ENC_JPEG, - VIDEO_PACKAGE, - VIDEO_DEC_H264_MULTI_MMU, - VIDEO_DEC_HEVC_G12A, - VIDEO_DEC_VP9_G12A, - VIDEO_DEC_AVS2, - VIDEO_DEC_AVS2_MMU, - VIDEO_DEC_AVS_GXM, - VIDEO_DEC_AVS_NOCABAC, - VIDEO_DEC_H264_MULTI_GXM, - VIDEO_DEC_H264_MVC_GXM, - VIDEO_DEC_VC1_G12A, - FIRMWARE_MAX -}; +/* example: #define VIDEO_DEC_AV1 TAG('A', 'V', '1', '-')*/ +#define TAG(a, b, c, d)\ + ((a << 24) | (b << 16) | (c << 8) | d) -struct type_name_s { - enum firmware_type_e type; +/* fws define */ +#define VIDEO_DEC_MPEG12 (0) +#define VIDEO_DEC_MPEG4_3 (1) +#define VIDEO_DEC_MPEG4_4 (2) +#define VIDEO_DEC_MPEG4_5 (3) +#define VIDEO_DEC_H263 (4) +#define VIDEO_DEC_MJPEG (5) +#define VIDEO_DEC_MJPEG_MULTI (6) +#define VIDEO_DEC_REAL_V8 (7) +#define VIDEO_DEC_REAL_V9 (8) +#define VIDEO_DEC_VC1 (9) +#define VIDEO_DEC_AVS (10) +#define VIDEO_DEC_H264 (11) +#define VIDEO_DEC_H264_4k2K (12) +#define VIDEO_DEC_H264_4k2K_SINGLE (13) +#define VIDEO_DEC_H264_MVC (14) +#define VIDEO_DEC_H264_MULTI (15) +#define VIDEO_DEC_HEVC (16) +#define VIDEO_DEC_HEVC_MMU (17) +#define VIDEO_DEC_VP9 (18) +#define VIDEO_DEC_VP9_MMU (19) +#define VIDEO_ENC_H264 (20) +#define VIDEO_ENC_JPEG (21) +#define VIDEO_DEC_H264_MULTI_MMU (23) +#define VIDEO_DEC_HEVC_G12A (24) +#define VIDEO_DEC_VP9_G12A (25) +#define VIDEO_DEC_AVS2 (26) +#define VIDEO_DEC_AVS2_MMU (27) +#define VIDEO_DEC_AVS_GXM (28) +#define VIDEO_DEC_AVS_NOCABAC (29) +#define VIDEO_DEC_H264_MULTI_GXM (30) +#define VIDEO_DEC_H264_MVC_GXM (31) +#define VIDEO_DEC_VC1_G12A (32) +#define VIDEO_DEC_MPEG12_MULTI TAG('M', '1', '2', 'M') +#define VIDEO_DEC_MPEG4_4_MULTI TAG('M', '4', '4', 'M') +#define VIDEO_DEC_MPEG4_5_MULTI TAG('M', '4', '5', 'M') +#define VIDEO_DEC_H263_MULTI TAG('2', '6', '3', 'M') + +/* ... */ +#define FIRMWARE_MAX (UINT_MAX) + +#define VIDEO_PACKAGE (0) +#define VIDEO_FW_FILE (1) + +#define VIDEO_DECODE (0) +#define VIDEO_ENCODE (1) +#define VIDEO_MISC (2) + +#define OPTEE_VDEC_LEGENCY (0) +#define OPTEE_VDEC (1) +#define OPTEE_VDEC_HEVC (2) + +struct format_name_s { + unsigned int format; const char *name; }; -const char *get_firmware_type_name(enum firmware_type_e type); -enum firmware_type_e get_firmware_type(const char *name); +struct cpu_type_s { + int type; + const char *name; +}; + +const char *get_firmware_type_name(unsigned int format); +unsigned int get_fw_format(const char *name); +int fw_get_cpu(const char *name); #endif diff --git a/drivers/amlogic/media_modules/frame_provider/decoder/avs/avs.c b/drivers/amlogic/media_modules/frame_provider/decoder/avs/avs.c index 8620fde2526f..f01bedd4a986 100644 --- a/drivers/amlogic/media_modules/frame_provider/decoder/avs/avs.c +++ b/drivers/amlogic/media_modules/frame_provider/decoder/avs/avs.c @@ -1505,7 +1505,7 @@ static s32 vavs_init(void) vavs_local_init(); if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXM) - size = get_firmware_data(VIDEO_DEC_AVS_GXM, buf); + size = get_firmware_data(VIDEO_DEC_AVS, buf); else { if (firmware_sel == 1) size = get_firmware_data(VIDEO_DEC_AVS_NOCABAC, buf); @@ -1528,7 +1528,7 @@ static s32 vavs_init(void) pr_info("tee load ok\n"); if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXM) - size = amvdec_loadmc_ex(VFORMAT_AVS, "avs_gxm", buf); + size = amvdec_loadmc_ex(VFORMAT_AVS, NULL, buf); else if (firmware_sel == 1) size = amvdec_loadmc_ex(VFORMAT_AVS, "avs_no_cabac", buf); else diff --git a/drivers/amlogic/media_modules/frame_provider/decoder/h264/vh264_mvc.c b/drivers/amlogic/media_modules/frame_provider/decoder/h264/vh264_mvc.c index 8a2b6b68675d..9ca073f99326 100644 --- a/drivers/amlogic/media_modules/frame_provider/decoder/h264/vh264_mvc.c +++ b/drivers/amlogic/media_modules/frame_provider/decoder/h264/vh264_mvc.c @@ -1425,12 +1425,7 @@ static s32 vh264mvc_init(void) if (tee_enabled()) { pr_info("the video fw from the teeload.\n"); - - if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXM) - ret = tee_load_video_fw((u32)VIDEO_DEC_H264_MVC_GXM, 0); - else - ret = tee_load_video_fw((u32)VIDEO_DEC_H264_MVC, 0); - + ret = tee_load_video_fw((u32)VIDEO_DEC_H264_MVC, 0); if (ret != 0) { amvdec_disable(); return -1; @@ -1448,11 +1443,7 @@ static s32 vh264mvc_init(void) WRITE_VREG(UCODE_START_ADDR, mc_dma_handle); - if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXM) - size = get_firmware_data(VIDEO_DEC_H264_MVC_GXM, buf); - else - size = get_firmware_data(VIDEO_DEC_H264_MVC, buf); - + size = get_firmware_data(VIDEO_DEC_H264_MVC, buf); if (size < 0) { pr_err("get firmware fail."); vfree(buf); diff --git a/drivers/amlogic/media_modules/frame_provider/decoder/h264_multi/vmh264.c b/drivers/amlogic/media_modules/frame_provider/decoder/h264_multi/vmh264.c index e9b936781ab3..23ab742a04e6 100644 --- a/drivers/amlogic/media_modules/frame_provider/decoder/h264_multi/vmh264.c +++ b/drivers/amlogic/media_modules/frame_provider/decoder/h264_multi/vmh264.c @@ -5063,11 +5063,7 @@ static s32 vh264_init(struct vdec_h264_hw_s *hw) if (IS_ERR_OR_NULL(fw)) return -ENOMEM; - if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXM) - size = get_firmware_data(VIDEO_DEC_H264_MULTI_GXM, fw->data); - else - size = get_firmware_data(VIDEO_DEC_H264_MULTI, fw->data); - + size = get_firmware_data(VIDEO_DEC_H264_MULTI, fw->data); if (size < 0) { pr_err("get firmware fail.\n"); vfree(fw); @@ -6354,12 +6350,7 @@ static void run(struct vdec_s *vdec, unsigned long mask, start_process_time(hw); if (tee_enabled()) { - unsigned int fw_type = VIDEO_DEC_H264_MULTI; - - if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXM) - fw_type = VIDEO_DEC_H264_MULTI_GXM; - - if (tee_load_video_fw(fw_type, 0) != 0) { + if (tee_load_video_fw(VIDEO_DEC_H264_MULTI, 0) != 0) { amvdec_enable_flag = false; amvdec_disable(); pr_err("id: %d, %s: Error amvdec_vdec_loadmc fail\n", diff --git a/drivers/amlogic/media_modules/frame_provider/decoder/h265/vh265.c b/drivers/amlogic/media_modules/frame_provider/decoder/h265/vh265.c index 73f56dd6bf0a..4b20e0739a4a 100644 --- a/drivers/amlogic/media_modules/frame_provider/decoder/h265/vh265.c +++ b/drivers/amlogic/media_modules/frame_provider/decoder/h265/vh265.c @@ -8802,16 +8802,20 @@ static s32 vh265_init(struct hevc_state_s *hevc) size = 1; else #endif - if (get_cpu_type() >= MESON_CPU_MAJOR_ID_G12A) { - size = get_firmware_data(VIDEO_DEC_HEVC_G12A, fw->data); - hevc_print(hevc, 0, "vh265 g12a ucode loaded!\n"); - } else if (mmu_enable && (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXL)) { - size = get_firmware_data(VIDEO_DEC_HEVC_MMU, fw->data); - hevc_print(hevc, 0, "vh265 mmu ucode loaded!\n"); + + if (mmu_enable) { + if (get_cpu_type() >= MESON_CPU_MAJOR_ID_G12A) { + size = get_firmware_data(VIDEO_DEC_HEVC, fw->data); + hevc_print(hevc, 0, "vh265 ucode loaded!\n"); + } else { + size = get_firmware_data(VIDEO_DEC_HEVC_MMU, fw->data); + hevc_print(hevc, 0, "vh265 mmu ucode loaded!\n"); + } } else { size = get_firmware_data(VIDEO_DEC_HEVC, fw->data); hevc_print(hevc, 0, "vh265 ucode loaded!\n"); } + if (size < 0) { pr_err("get firmware fail.\n"); vfree(fw); @@ -8845,12 +8849,13 @@ static s32 vh265_init(struct hevc_state_s *hevc) if (size == 1) { pr_info ("tee load ok"); - if (get_cpu_type() >= MESON_CPU_MAJOR_ID_G12A) - ret = tee_load_video_fw((u32)VIDEO_DEC_HEVC_G12A, 2); - else if (hevc->mmu_enable && - (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXL)) - ret = tee_load_video_fw((u32)VIDEO_DEC_HEVC_MMU, 0); - else + + if (hevc->mmu_enable) { + if (get_cpu_type() >= MESON_CPU_MAJOR_ID_G12A) + ret = tee_load_video_fw((u32)VIDEO_DEC_HEVC, 0); + else + ret = tee_load_video_fw((u32)VIDEO_DEC_HEVC_MMU, 0); + } else ret = tee_load_video_fw((u32)VIDEO_DEC_HEVC, 0); } else ret = amhevc_loadmc_ex(VFORMAT_HEVC, NULL, fw->data); @@ -9618,7 +9623,7 @@ static void run(struct vdec_s *vdec, unsigned long mask, { struct hevc_state_s *hevc = (struct hevc_state_s *)vdec->private; - int r, loadr; + int r, loadr = 0; unsigned char check_sum = 0; run_count[hevc->index]++; @@ -9682,14 +9687,14 @@ static void run(struct vdec_s *vdec, unsigned long mask, } } - if (get_cpu_type() >= MESON_CPU_MAJOR_ID_G12A) - loadr = amhevc_vdec_loadmc_ex(vdec, - "vh265_mc_g12a", hevc->fw->data); - else if (hevc->mmu_enable && - (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXL)) - loadr = amhevc_vdec_loadmc_ex(vdec, - "vh265_mc_mmu", hevc->fw->data); - else + if (hevc->mmu_enable) { + if (get_cpu_type() >= MESON_CPU_MAJOR_ID_G12A) + loadr = amhevc_vdec_loadmc_ex(vdec, + "vh265_mc", hevc->fw->data); + else + loadr = amhevc_vdec_loadmc_ex(vdec, + "vh265_mc_mmu", hevc->fw->data); + } else loadr = amhevc_vdec_loadmc_ex(vdec, "vh265_mc", hevc->fw->data); diff --git a/drivers/amlogic/media_modules/frame_provider/decoder/utils/amvdec.c b/drivers/amlogic/media_modules/frame_provider/decoder/utils/amvdec.c index 0a0aa6365395..7289fece7d21 100644 --- a/drivers/amlogic/media_modules/frame_provider/decoder/utils/amvdec.c +++ b/drivers/amlogic/media_modules/frame_provider/decoder/utils/amvdec.c @@ -375,96 +375,85 @@ static s32 amvdec_loadmc(const u32 *p) s32 optee_load_fw(enum vformat_e type, const char *fw_name) { - s32 ret = 0; + s32 ret = -1; + unsigned int format = FIRMWARE_MAX; + unsigned int vdec = OPTEE_VDEC_LEGENCY; char *name = __getname(); sprintf(name, "%s", fw_name ? fw_name : "null"); switch ((u32)type) { case VFORMAT_VC1: - ret = tee_load_video_fw((u32)VIDEO_DEC_VC1, 0); + format = VIDEO_DEC_VC1; break; case VFORMAT_AVS: - if (!strcmp(name, "avs_gxm")) - ret = tee_load_video_fw((u32)VIDEO_DEC_AVS_GXM, 0); - else if (!strcmp(name, "avs_no_cabac")) - ret = tee_load_video_fw((u32)VIDEO_DEC_AVS_NOCABAC, 0); + if (!strcmp(name, "avs_no_cabac")) + format = VIDEO_DEC_AVS_NOCABAC; else - ret = tee_load_video_fw((u32)VIDEO_DEC_AVS, 0); + format = VIDEO_DEC_AVS; break; case VFORMAT_MPEG12: - ret = tee_load_video_fw((u32)VIDEO_DEC_MPEG12, 0); + format = VIDEO_DEC_MPEG12; break; case VFORMAT_MJPEG: - ret = tee_load_video_fw((u32)VIDEO_DEC_MJPEG, 0); + format = VIDEO_DEC_MJPEG; break; case VFORMAT_VP9: - if (!strcmp(name, "vp9_mc_g12a")) - ret = tee_load_video_fw((u32)VIDEO_DEC_VP9_G12A, 2); + if (!strcmp(name, "vp9_mc")) + format = VIDEO_DEC_VP9; else - ret = tee_load_video_fw((u32)VIDEO_DEC_VP9_MMU, 0); + format = VIDEO_DEC_VP9_MMU; break; case VFORMAT_AVS2: - ret = tee_load_video_fw((u32)VIDEO_DEC_AVS2_MMU, 2); + format = VIDEO_DEC_AVS2_MMU; + vdec = OPTEE_VDEC_HEVC; break; case VFORMAT_HEVC: if (!strcmp(name, "vh265_mc")) - ret = tee_load_video_fw((u32)VIDEO_DEC_HEVC, 0); - else if (!strcmp(name, "vh265_mc_mmu")) - ret = tee_load_video_fw((u32)VIDEO_DEC_HEVC_MMU, 0); - else if (!strcmp(name, "vh265_mc_g12a")) - ret = tee_load_video_fw((u32)VIDEO_DEC_HEVC_G12A, 2); + format = VIDEO_DEC_HEVC; + else + format = VIDEO_DEC_HEVC_MMU; break; case VFORMAT_REAL: if (!strcmp(name, "vreal_mc_8")) - ret = tee_load_video_fw((u32)VIDEO_DEC_REAL_V8, 0); + format = VIDEO_DEC_REAL_V8; else if (!strcmp(name, "vreal_mc_9")) - ret = tee_load_video_fw((u32)VIDEO_DEC_REAL_V9, 0); + format = VIDEO_DEC_REAL_V9; break; case VFORMAT_MPEG4: if (!strcmp(name, "vmpeg4_mc_311")) - ret = tee_load_video_fw((u32)VIDEO_DEC_MPEG4_3, 0); + format = VIDEO_DEC_MPEG4_3; else if (!strcmp(name, "vmpeg4_mc_4")) - ret = tee_load_video_fw((u32)VIDEO_DEC_MPEG4_4, 0); + format = VIDEO_DEC_MPEG4_4; else if (!strcmp(name, "vmpeg4_mc_5")) - ret = tee_load_video_fw((u32)VIDEO_DEC_MPEG4_5, 0); + format = VIDEO_DEC_MPEG4_5; else if (!strcmp(name, "h263_mc")) - ret = tee_load_video_fw((u32)VIDEO_DEC_FORMAT_H263, 0); + format = VIDEO_DEC_FORMAT_H263; break; + default: if (!strcmp(name, "vh265_mc")) - ret = tee_load_video_fw((u32)VIDEO_DEC_HEVC, 0); + format = VIDEO_DEC_HEVC; else if (!strcmp(name, "vh265_mc_mmu")) - ret = tee_load_video_fw((u32)VIDEO_DEC_HEVC_MMU, 0); - else if (!strcmp(name, "vmpeg4_mc_311")) - ret = tee_load_video_fw((u32)VIDEO_DEC_MPEG4_3, 0); - else if (!strcmp(name, "vmpeg4_mc_4")) - ret = tee_load_video_fw((u32)VIDEO_DEC_MPEG4_4, 0); - else if (!strcmp(name, "vmpeg4_mc_5")) - ret = tee_load_video_fw((u32)VIDEO_DEC_MPEG4_5, 0); - else if (!strcmp(name, "h263_mc")) - ret = tee_load_video_fw((u32)VIDEO_DEC_FORMAT_H263, 0); - else if (!strcmp(name, "vreal_mc_8")) - ret = tee_load_video_fw((u32)VIDEO_DEC_REAL_V8, 0); - else if (!strcmp(name, "vreal_mc_9")) - ret = tee_load_video_fw((u32)VIDEO_DEC_REAL_V9, 0); + format = VIDEO_DEC_HEVC_MMU; else if (!strcmp(name, "vmmjpeg_mc")) - ret = tee_load_video_fw((u32)VIDEO_DEC_MJPEG_MULTI, 0); - else if (!strcmp(name, "vh265_mc_g12a")) - ret = tee_load_video_fw((u32)VIDEO_DEC_HEVC_G12A, 2); + format = VIDEO_DEC_MJPEG_MULTI; else pr_info("unknow dec format\n"); break; } + if (format < FIRMWARE_MAX) + ret = tee_load_video_fw(format, vdec); + __putname(name); return ret; diff --git a/drivers/amlogic/media_modules/frame_provider/decoder/utils/firmware.h b/drivers/amlogic/media_modules/frame_provider/decoder/utils/firmware.h index a2fd138d5077..17f64e430b72 100644 --- a/drivers/amlogic/media_modules/frame_provider/decoder/utils/firmware.h +++ b/drivers/amlogic/media_modules/frame_provider/decoder/utils/firmware.h @@ -15,7 +15,7 @@ struct firmware_s { extern int get_decoder_firmware_data(enum vformat_e type, const char *file_name, char *buf, int size); extern int get_data_from_name(const char *name, char *buf); -extern int get_firmware_data(enum firmware_type_e type, char *buf); -extern int firmware_reload(int mode); +extern int get_firmware_data(unsigned int foramt, char *buf); +extern int video_fw_reload(int mode); #endif diff --git a/drivers/amlogic/media_modules/frame_provider/decoder/vc1/vvc1.c b/drivers/amlogic/media_modules/frame_provider/decoder/vc1/vvc1.c index 72e88495715a..49517eebf562 100644 --- a/drivers/amlogic/media_modules/frame_provider/decoder/vc1/vvc1.c +++ b/drivers/amlogic/media_modules/frame_provider/decoder/vc1/vvc1.c @@ -1056,20 +1056,12 @@ static s32 vvc1_init(void) } else pr_info("not supported VC1 format\n"); - if (get_cpu_type() >= MESON_CPU_MAJOR_ID_G12A) - fw_type = VIDEO_DEC_VC1_G12A; - - if (get_cpu_type() >= MESON_CPU_MAJOR_ID_G12A && tee_enabled()) { - ret = tee_load_video_fw((u32)fw_type, 1); - size = 1; - } else { - size = get_firmware_data(fw_type, buf); - if (size < 0) { - amvdec_disable(); - pr_err("get firmware fail."); - vfree(buf); - return -1; - } + size = get_firmware_data(fw_type, buf); + if (size < 0) { + amvdec_disable(); + pr_err("get firmware fail."); + vfree(buf); + return -1; } if (size == 1) diff --git a/drivers/amlogic/media_modules/frame_provider/decoder/vp9/vvp9.c b/drivers/amlogic/media_modules/frame_provider/decoder/vp9/vvp9.c index 9a1e88f94988..66a12a92f227 100644 --- a/drivers/amlogic/media_modules/frame_provider/decoder/vp9/vvp9.c +++ b/drivers/amlogic/media_modules/frame_provider/decoder/vp9/vvp9.c @@ -8057,10 +8057,12 @@ static s32 vvp9_init(struct VP9Decoder_s *pbi) pr_debug ("laod\n"); } else #endif + if (get_cpu_type() >= MESON_CPU_MAJOR_ID_G12A) - size = get_firmware_data(VIDEO_DEC_VP9_G12A, fw->data); + size = get_firmware_data(VIDEO_DEC_VP9, fw->data); else size = get_firmware_data(VIDEO_DEC_VP9_MMU, fw->data); + if (size < 0) { pr_err("get firmware fail.\n"); vfree(fw); @@ -8096,7 +8098,7 @@ static s32 vvp9_init(struct VP9Decoder_s *pbi) if (size == 1) { pr_info ("tee load ok\n"); if (get_cpu_type() >= MESON_CPU_MAJOR_ID_G12A) - ret = tee_load_video_fw((u32)VIDEO_DEC_VP9_G12A, 2); + ret = tee_load_video_fw((u32)VIDEO_DEC_VP9, 0); else ret = tee_load_video_fw((u32)VIDEO_DEC_VP9_MMU, 0); } else @@ -8824,8 +8826,7 @@ static void run_front(struct vdec_s *vdec) } if (get_cpu_type() >= MESON_CPU_MAJOR_ID_G12A) - ret = amhevc_loadmc_ex(VFORMAT_VP9, - "vp9_mc_g12a", pbi->fw->data); + ret = amhevc_loadmc_ex(VFORMAT_VP9, "vp9_mc", pbi->fw->data); else ret = amhevc_loadmc_ex(VFORMAT_VP9, NULL, pbi->fw->data); diff --git a/drivers/amlogic/media_modules/stream_input/amports/amstream.c b/drivers/amlogic/media_modules/stream_input/amports/amstream.c index 4614af242f61..91285e5e460e 100644 --- a/drivers/amlogic/media_modules/stream_input/amports/amstream.c +++ b/drivers/amlogic/media_modules/stream_input/amports/amstream.c @@ -885,7 +885,7 @@ static int amstream_port_init(struct port_priv_s *priv) } /* try to reload the fw.*/ - r = firmware_reload(FW_LOAD_TRY); + r = video_fw_reload(FW_LOAD_TRY); if (r) pr_err("the firmware reload fail.\n"); diff --git a/firmware/video/video_ucode.bin b/firmware/video/video_ucode.bin index 4f47fb851b5bb2dbff3e991925fc32809b49a89a..e5cfacd945b4fd00525ba3737e2844265c9a40c0 100644 GIT binary patch delta 6244 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 delta 4987 zcmcgvdsGxv7{B+S(HXHZy?Vzl$+e3b7MA+n{ozv7%~i9veX}WQZ_z8d?;=uT z=6v~h?A5)WkURZ$e;c@0PI3f%wb{(v{6Z{ttbV=Zs`ud?sdv_o2#sBky(M`~@#~^W=%ule5&GeR zyxa`)+nI}VGZfK3F0mlXlwd0`Sz}DmmNAyNF&1@TjRRd@*RS0o0Nwz6TzU32c_$6W z!@54V+xph&(JXCk*m`VOphJgj;cuj6M#qj!%UStGVOCm3agKROR&I|^z1AdQWj{%1 zZSbEO<2OE|`1${&z(2!P6+@B5Y%yzzi@VRow2dpWjZVw3MlU8tFUpUYGB}zDThRd3 zJMWjK76z!^x#>v4EpJ+#ap`&3#rlVAYQCn-a6_Ozo1<+qUCPe)AT{dOu+S#Mdi_Fe zjR?K@SO2*_H9=FLEN1hkQxadul)+$x{(W;=3bN~@DP($CcYi(y#s`OTIF{N8g zd!o2IxK43UrhRFRBWZU-!JpRK>F#XtC8io$r)EJA5o+iLV_n4XO|E24FIxI6r+ifu zbeZauOI3Ru++AEvadw%jp=WDLHg_X?Xxh#dEww&7r5~+Iu8Kf}M%dszX#We0t90~M z>MR}IirORLo)MGuNRUxGw?JDY+>9L3LqUe;Fa_zE$G46uKZi}~AxYdXI84)Qw7K!{ zJl;m5q#N?~%ecTOc?XX~;1S7Q%qL@Tk1@c(22Q*$Z4aJ5zh=lJYFDckdEN2bsHO7inSUgUSE#u>Z zg;AYzCn80b1v|02E<|?DiE$(_oxe8Rxt1|t;AFt7#fFn(ovce&?9>Hf&z|6b)Dap0 zOG*54ej*a4k?eao838LfdJivwPI=&cJXdjMKG~GXzlT6BdGaqVf=-hE00$vZOg25h z*}RZn;&Kw?Fw%~hVL>3CG4R3xh80A1YKomAK@V^0@EZsVlH|2DSpu(2&`dBn3F97B2zZR z$%;CP6DG^2p5jj-1oBGA`$9@=DUtH3lcA4vta>o?A{~eiL{2ZMBWj&oMe&(oNH|S! zIR6K79+UqG=N&8({Nx%dztCUjs-nbri3=dXeW<}wIMr90fe!Ic&R<^9RbySNQv59+ z66ZyEkZI-KR09$mMcThj)8t4K#j}{qqY*Ank<%7P|ix@etlD`I0TNM-< zYY|V$_E73Bs~3g=mllxMhf|XvavI4G!>RaKXCGiN8vtDkMb_N(G0stTS|JR^kx*n> znyT?s8$R+P<-iezPxh0Y$Mo>ecKyo6e0EHZlM^MNtB~XjXAM07-U4i*qUb06KeXWliZw0@U8MfAtAVqw6v5>d1TkA_K}+z*0?uzOSqcD*z_NEu^aIK