1175 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2//3// aw88395_lib.c -- ACF bin parsing and check library file for aw883954//5// Copyright (c) 2022-2023 AWINIC Technology CO., LTD6//7// Author: Bruce zhao <zhaolei@awinic.com>8//9 10#include <linux/cleanup.h>11#include <linux/crc8.h>12#include <linux/i2c.h>13#include "aw88395_lib.h"14#include "aw88395_device.h"15 16#define AW88395_CRC8_POLYNOMIAL 0x8C17DECLARE_CRC8_TABLE(aw_crc8_table);18 19static char *profile_name[AW88395_PROFILE_MAX] = {20 "Music", "Voice", "Voip", "Ringtone",21 "Ringtone_hs", "Lowpower", "Bypass",22 "Mmi", "Fm", "Notification", "Receiver"23};24 25static int aw_parse_bin_header(struct aw_device *aw_dev, struct aw_bin *bin);26 27static int aw_check_sum(struct aw_device *aw_dev, struct aw_bin *bin, int bin_num)28{29 unsigned char *p_check_sum;30 unsigned int sum_data = 0;31 unsigned int check_sum;32 unsigned int i, len;33 34 p_check_sum = &(bin->info.data[(bin->header_info[bin_num].valid_data_addr -35 bin->header_info[bin_num].header_len)]);36 len = bin->header_info[bin_num].bin_data_len + bin->header_info[bin_num].header_len;37 check_sum = le32_to_cpup((void *)p_check_sum);38 39 for (i = 4; i < len; i++)40 sum_data += *(p_check_sum + i);41 42 dev_dbg(aw_dev->dev, "%s -- check_sum = %p, check_sum = 0x%x, sum_data = 0x%x",43 __func__, p_check_sum, check_sum, sum_data);44 if (sum_data != check_sum) {45 dev_err(aw_dev->dev, "%s. CheckSum Fail.bin_num=%d, CheckSum:0x%x, SumData:0x%x",46 __func__, bin_num, check_sum, sum_data);47 return -EINVAL;48 }49 50 return 0;51}52 53static int aw_check_data_version(struct aw_device *aw_dev, struct aw_bin *bin, int bin_num)54{55 if (bin->header_info[bin_num].bin_data_ver < DATA_VERSION_V1 ||56 bin->header_info[bin_num].bin_data_ver > DATA_VERSION_MAX) {57 dev_err(aw_dev->dev, "aw_bin_parse Unrecognized this bin data version\n");58 return -EINVAL;59 }60 61 return 0;62}63 64static int aw_check_register_num(struct aw_device *aw_dev, struct aw_bin *bin, int bin_num)65{66 struct bin_header_info temp_info = bin->header_info[bin_num];67 unsigned int check_register_num, parse_register_num;68 unsigned char *p_check_sum;69 70 p_check_sum = &(bin->info.data[(temp_info.valid_data_addr)]);71 72 parse_register_num = le32_to_cpup((void *)p_check_sum);73 check_register_num = (bin->header_info[bin_num].bin_data_len - CHECK_REGISTER_NUM_OFFSET) /74 (bin->header_info[bin_num].reg_byte_len +75 bin->header_info[bin_num].data_byte_len);76 dev_dbg(aw_dev->dev, "%s,parse_register_num = 0x%x,check_register_num = 0x%x\n",77 __func__, parse_register_num, check_register_num);78 if (parse_register_num != check_register_num) {79 dev_err(aw_dev->dev, "%s parse_register_num = 0x%x,check_register_num = 0x%x\n",80 __func__, parse_register_num, check_register_num);81 return -EINVAL;82 }83 84 bin->header_info[bin_num].reg_num = parse_register_num;85 bin->header_info[bin_num].valid_data_len = temp_info.bin_data_len - VALID_DATA_LEN;86 bin->header_info[bin_num].valid_data_addr = temp_info.valid_data_addr + VALID_DATA_ADDR;87 88 return 0;89}90 91static int aw_check_dsp_reg_num(struct aw_device *aw_dev, struct aw_bin *bin, int bin_num)92{93 struct bin_header_info temp_info = bin->header_info[bin_num];94 unsigned int check_dsp_reg_num, parse_dsp_reg_num;95 unsigned char *p_check_sum;96 97 p_check_sum = &(bin->info.data[(temp_info.valid_data_addr)]);98 99 parse_dsp_reg_num = le32_to_cpup((void *)(p_check_sum + PARSE_DSP_REG_NUM));100 bin->header_info[bin_num].reg_data_byte_len =101 le32_to_cpup((void *)(p_check_sum + REG_DATA_BYTP_LEN));102 check_dsp_reg_num = (bin->header_info[bin_num].bin_data_len - CHECK_DSP_REG_NUM) /103 bin->header_info[bin_num].reg_data_byte_len;104 dev_dbg(aw_dev->dev, "%s bin_num = %d, parse_dsp_reg_num = 0x%x, check_dsp_reg_num = 0x%x",105 __func__, bin_num, check_dsp_reg_num, check_dsp_reg_num);106 if (parse_dsp_reg_num != check_dsp_reg_num) {107 dev_err(aw_dev->dev, "aw_bin_parse check dsp reg num error\n");108 dev_err(aw_dev->dev, "%s parse_dsp_reg_num = 0x%x, check_dsp_reg_num = 0x%x",109 __func__, check_dsp_reg_num, check_dsp_reg_num);110 return -EINVAL;111 }112 113 bin->header_info[bin_num].download_addr = le32_to_cpup((void *)p_check_sum);114 bin->header_info[bin_num].reg_num = parse_dsp_reg_num;115 bin->header_info[bin_num].valid_data_len = temp_info.bin_data_len - DSP_VALID_DATA_LEN;116 bin->header_info[bin_num].valid_data_addr = temp_info.valid_data_addr +117 DSP_VALID_DATA_ADDR;118 119 return 0;120}121 122static int aw_check_soc_app_num(struct aw_device *aw_dev, struct aw_bin *bin, int bin_num)123{124 struct bin_header_info temp_info = bin->header_info[bin_num];125 unsigned int check_soc_app_num, parse_soc_app_num;126 unsigned char *p_check_sum;127 128 p_check_sum = &(bin->info.data[(temp_info.valid_data_addr)]);129 130 bin->header_info[bin_num].app_version = le32_to_cpup((void *)p_check_sum);131 parse_soc_app_num = le32_to_cpup((void *)(p_check_sum + PARSE_SOC_APP_NUM));132 check_soc_app_num = bin->header_info[bin_num].bin_data_len - CHECK_SOC_APP_NUM;133 dev_dbg(aw_dev->dev, "%s bin_num = %d, parse_soc_app_num=0x%x, check_soc_app_num = 0x%x\n",134 __func__, bin_num, parse_soc_app_num, check_soc_app_num);135 if (parse_soc_app_num != check_soc_app_num) {136 dev_err(aw_dev->dev, "%s parse_soc_app_num=0x%x, check_soc_app_num = 0x%x\n",137 __func__, parse_soc_app_num, check_soc_app_num);138 return -EINVAL;139 }140 141 bin->header_info[bin_num].reg_num = parse_soc_app_num;142 bin->header_info[bin_num].download_addr = le32_to_cpup((void *)(p_check_sum +143 APP_DOWNLOAD_ADDR));144 bin->header_info[bin_num].valid_data_len = temp_info.bin_data_len - APP_VALID_DATA_LEN;145 bin->header_info[bin_num].valid_data_addr = temp_info.valid_data_addr +146 APP_VALID_DATA_ADDR;147 148 return 0;149}150 151static void aw_get_single_bin_header(struct aw_bin *bin)152{153 memcpy((void *)&bin->header_info[bin->all_bin_parse_num], bin->p_addr, DATA_LEN);154 155 bin->header_info[bin->all_bin_parse_num].header_len = HEADER_LEN;156 bin->all_bin_parse_num += 1;157}158 159static int aw_parse_one_of_multi_bins(struct aw_device *aw_dev, unsigned int bin_num,160 int bin_serial_num, struct aw_bin *bin)161{162 struct bin_header_info aw_bin_header_info;163 unsigned int bin_start_addr;164 unsigned int valid_data_len;165 166 if (bin->info.len < sizeof(struct bin_header_info)) {167 dev_err(aw_dev->dev, "bin_header_info size[%d] overflow file size[%d]\n",168 (int)sizeof(struct bin_header_info), bin->info.len);169 return -EINVAL;170 }171 172 aw_bin_header_info = bin->header_info[bin->all_bin_parse_num - 1];173 if (!bin_serial_num) {174 bin_start_addr = le32_to_cpup((void *)(bin->p_addr + START_ADDR_OFFSET));175 bin->p_addr += (HEADER_LEN + bin_start_addr);176 bin->header_info[bin->all_bin_parse_num].valid_data_addr =177 aw_bin_header_info.valid_data_addr + VALID_DATA_ADDR + 8 * bin_num +178 VALID_DATA_ADDR_OFFSET;179 } else {180 valid_data_len = aw_bin_header_info.bin_data_len;181 bin->p_addr += (HDADER_LEN + valid_data_len);182 bin->header_info[bin->all_bin_parse_num].valid_data_addr =183 aw_bin_header_info.valid_data_addr + aw_bin_header_info.bin_data_len +184 VALID_DATA_ADDR_OFFSET;185 }186 187 return aw_parse_bin_header(aw_dev, bin);188}189 190static int aw_get_multi_bin_header(struct aw_device *aw_dev, struct aw_bin *bin)191{192 unsigned int bin_num, i;193 int ret;194 195 bin_num = le32_to_cpup((void *)(bin->p_addr + VALID_DATA_ADDR_OFFSET));196 if (bin->multi_bin_parse_num == 1)197 bin->header_info[bin->all_bin_parse_num].valid_data_addr =198 VALID_DATA_ADDR_OFFSET;199 200 aw_get_single_bin_header(bin);201 202 for (i = 0; i < bin_num; i++) {203 dev_dbg(aw_dev->dev, "aw_bin_parse enter multi bin for is %d\n", i);204 ret = aw_parse_one_of_multi_bins(aw_dev, bin_num, i, bin);205 if (ret < 0)206 return ret;207 }208 209 return 0;210}211 212static int aw_parse_bin_header(struct aw_device *aw_dev, struct aw_bin *bin)213{214 unsigned int bin_data_type;215 216 if (bin->info.len < sizeof(struct bin_header_info)) {217 dev_err(aw_dev->dev, "bin_header_info size[%d] overflow file size[%d]\n",218 (int)sizeof(struct bin_header_info), bin->info.len);219 return -EINVAL;220 }221 222 bin_data_type = le32_to_cpup((void *)(bin->p_addr + BIN_DATA_TYPE_OFFSET));223 dev_dbg(aw_dev->dev, "aw_bin_parse bin_data_type 0x%x\n", bin_data_type);224 switch (bin_data_type) {225 case DATA_TYPE_REGISTER:226 case DATA_TYPE_DSP_REG:227 case DATA_TYPE_SOC_APP:228 bin->single_bin_parse_num += 1;229 dev_dbg(aw_dev->dev, "%s bin->single_bin_parse_num is %d\n", __func__,230 bin->single_bin_parse_num);231 if (!bin->multi_bin_parse_num)232 bin->header_info[bin->all_bin_parse_num].valid_data_addr =233 VALID_DATA_ADDR_OFFSET;234 aw_get_single_bin_header(bin);235 return 0;236 case DATA_TYPE_MULTI_BINS:237 bin->multi_bin_parse_num += 1;238 dev_dbg(aw_dev->dev, "%s bin->multi_bin_parse_num is %d\n", __func__,239 bin->multi_bin_parse_num);240 return aw_get_multi_bin_header(aw_dev, bin);241 default:242 dev_dbg(aw_dev->dev, "%s There is no corresponding type\n", __func__);243 return 0;244 }245}246 247static int aw_check_bin_header_version(struct aw_device *aw_dev, struct aw_bin *bin)248{249 unsigned int header_version;250 251 header_version = le32_to_cpup((void *)(bin->p_addr + HEADER_VERSION_OFFSET));252 dev_dbg(aw_dev->dev, "aw_bin_parse header_version 0x%x\n", header_version);253 254 switch (header_version) {255 case HEADER_VERSION_V1:256 return aw_parse_bin_header(aw_dev, bin);257 default:258 dev_err(aw_dev->dev, "aw_bin_parse Unrecognized this bin header version\n");259 return -EINVAL;260 }261}262 263static int aw_parsing_bin_file(struct aw_device *aw_dev, struct aw_bin *bin)264{265 int ret = -EINVAL;266 int i;267 268 if (!bin) {269 dev_err(aw_dev->dev, "aw_bin_parse bin is NULL\n");270 return ret;271 }272 bin->p_addr = bin->info.data;273 bin->all_bin_parse_num = 0;274 bin->multi_bin_parse_num = 0;275 bin->single_bin_parse_num = 0;276 277 ret = aw_check_bin_header_version(aw_dev, bin);278 if (ret < 0) {279 dev_err(aw_dev->dev, "aw_bin_parse check bin header version error\n");280 return ret;281 }282 283 for (i = 0; i < bin->all_bin_parse_num; i++) {284 ret = aw_check_sum(aw_dev, bin, i);285 if (ret < 0) {286 dev_err(aw_dev->dev, "aw_bin_parse check sum data error\n");287 return ret;288 }289 ret = aw_check_data_version(aw_dev, bin, i);290 if (ret < 0) {291 dev_err(aw_dev->dev, "aw_bin_parse check data version error\n");292 return ret;293 }294 if (bin->header_info[i].bin_data_ver == DATA_VERSION_V1) {295 switch (bin->header_info[i].bin_data_type) {296 case DATA_TYPE_REGISTER:297 ret = aw_check_register_num(aw_dev, bin, i);298 break;299 case DATA_TYPE_DSP_REG:300 ret = aw_check_dsp_reg_num(aw_dev, bin, i);301 break;302 case DATA_TYPE_SOC_APP:303 ret = aw_check_soc_app_num(aw_dev, bin, i);304 break;305 default:306 bin->header_info[i].valid_data_len =307 bin->header_info[i].bin_data_len;308 ret = 0;309 break;310 }311 if (ret < 0)312 return ret;313 }314 }315 316 return 0;317}318 319static int aw_dev_parse_raw_reg(unsigned char *data, unsigned int data_len,320 struct aw_prof_desc *prof_desc)321{322 prof_desc->sec_desc[AW88395_DATA_TYPE_REG].data = data;323 prof_desc->sec_desc[AW88395_DATA_TYPE_REG].len = data_len;324 325 prof_desc->prof_st = AW88395_PROFILE_OK;326 327 return 0;328}329 330static int aw_dev_parse_raw_dsp_cfg(unsigned char *data, unsigned int data_len,331 struct aw_prof_desc *prof_desc)332{333 if (data_len & 0x01)334 return -EINVAL;335 336 swab16_array((u16 *)data, data_len >> 1);337 338 prof_desc->sec_desc[AW88395_DATA_TYPE_DSP_CFG].data = data;339 prof_desc->sec_desc[AW88395_DATA_TYPE_DSP_CFG].len = data_len;340 341 prof_desc->prof_st = AW88395_PROFILE_OK;342 343 return 0;344}345 346static int aw_dev_parse_raw_dsp_fw(unsigned char *data, unsigned int data_len,347 struct aw_prof_desc *prof_desc)348{349 if (data_len & 0x01)350 return -EINVAL;351 352 swab16_array((u16 *)data, data_len >> 1);353 354 prof_desc->sec_desc[AW88395_DATA_TYPE_DSP_FW].data = data;355 prof_desc->sec_desc[AW88395_DATA_TYPE_DSP_FW].len = data_len;356 357 prof_desc->prof_st = AW88395_PROFILE_OK;358 359 return 0;360}361 362static int aw_dev_prof_parse_multi_bin(struct aw_device *aw_dev, unsigned char *data,363 unsigned int data_len, struct aw_prof_desc *prof_desc)364{365 int ret;366 int i;367 368 struct aw_bin *aw_bin __free(kfree) = kzalloc(data_len + sizeof(struct aw_bin),369 GFP_KERNEL);370 if (!aw_bin)371 return -ENOMEM;372 373 aw_bin->info.len = data_len;374 memcpy(aw_bin->info.data, data, data_len);375 376 ret = aw_parsing_bin_file(aw_dev, aw_bin);377 if (ret < 0) {378 dev_err(aw_dev->dev, "parse bin failed");379 return ret;380 }381 382 for (i = 0; i < aw_bin->all_bin_parse_num; i++) {383 switch (aw_bin->header_info[i].bin_data_type) {384 case DATA_TYPE_REGISTER:385 prof_desc->sec_desc[AW88395_DATA_TYPE_REG].len =386 aw_bin->header_info[i].valid_data_len;387 prof_desc->sec_desc[AW88395_DATA_TYPE_REG].data =388 data + aw_bin->header_info[i].valid_data_addr;389 break;390 case DATA_TYPE_DSP_REG:391 if (aw_bin->header_info[i].valid_data_len & 0x01)392 return -EINVAL;393 394 swab16_array((u16 *)(data + aw_bin->header_info[i].valid_data_addr),395 aw_bin->header_info[i].valid_data_len >> 1);396 397 prof_desc->sec_desc[AW88395_DATA_TYPE_DSP_CFG].len =398 aw_bin->header_info[i].valid_data_len;399 prof_desc->sec_desc[AW88395_DATA_TYPE_DSP_CFG].data =400 data + aw_bin->header_info[i].valid_data_addr;401 break;402 case DATA_TYPE_DSP_FW:403 case DATA_TYPE_SOC_APP:404 if (aw_bin->header_info[i].valid_data_len & 0x01)405 return -EINVAL;406 407 swab16_array((u16 *)(data + aw_bin->header_info[i].valid_data_addr),408 aw_bin->header_info[i].valid_data_len >> 1);409 410 prof_desc->fw_ver = aw_bin->header_info[i].app_version;411 prof_desc->sec_desc[AW88395_DATA_TYPE_DSP_FW].len =412 aw_bin->header_info[i].valid_data_len;413 prof_desc->sec_desc[AW88395_DATA_TYPE_DSP_FW].data =414 data + aw_bin->header_info[i].valid_data_addr;415 break;416 default:417 dev_dbg(aw_dev->dev, "bin_data_type not found");418 break;419 }420 }421 prof_desc->prof_st = AW88395_PROFILE_OK;422 423 return 0;424}425 426static int aw_dev_parse_reg_bin_with_hdr(struct aw_device *aw_dev,427 uint8_t *data, uint32_t data_len, struct aw_prof_desc *prof_desc)428{429 int ret;430 431 struct aw_bin *aw_bin __free(kfree) = kzalloc(data_len + sizeof(*aw_bin),432 GFP_KERNEL);433 if (!aw_bin)434 return -ENOMEM;435 436 aw_bin->info.len = data_len;437 memcpy(aw_bin->info.data, data, data_len);438 439 ret = aw_parsing_bin_file(aw_dev, aw_bin);440 if (ret < 0) {441 dev_err(aw_dev->dev, "parse bin failed");442 return ret;443 }444 445 if ((aw_bin->all_bin_parse_num != 1) ||446 (aw_bin->header_info[0].bin_data_type != DATA_TYPE_REGISTER)) {447 dev_err(aw_dev->dev, "bin num or type error");448 return -EINVAL;449 }450 451 prof_desc->sec_desc[AW88395_DATA_TYPE_REG].data =452 data + aw_bin->header_info[0].valid_data_addr;453 prof_desc->sec_desc[AW88395_DATA_TYPE_REG].len =454 aw_bin->header_info[0].valid_data_len;455 prof_desc->prof_st = AW88395_PROFILE_OK;456 457 return 0;458}459 460static int aw_dev_parse_data_by_sec_type(struct aw_device *aw_dev, struct aw_cfg_hdr *cfg_hdr,461 struct aw_cfg_dde *cfg_dde, struct aw_prof_desc *scene_prof_desc)462{463 switch (cfg_dde->data_type) {464 case ACF_SEC_TYPE_REG:465 return aw_dev_parse_raw_reg((u8 *)cfg_hdr + cfg_dde->data_offset,466 cfg_dde->data_size, scene_prof_desc);467 case ACF_SEC_TYPE_DSP_CFG:468 return aw_dev_parse_raw_dsp_cfg((u8 *)cfg_hdr + cfg_dde->data_offset,469 cfg_dde->data_size, scene_prof_desc);470 case ACF_SEC_TYPE_DSP_FW:471 return aw_dev_parse_raw_dsp_fw(472 (u8 *)cfg_hdr + cfg_dde->data_offset,473 cfg_dde->data_size, scene_prof_desc);474 case ACF_SEC_TYPE_MULTIPLE_BIN:475 return aw_dev_prof_parse_multi_bin(476 aw_dev, (u8 *)cfg_hdr + cfg_dde->data_offset,477 cfg_dde->data_size, scene_prof_desc);478 case ACF_SEC_TYPE_HDR_REG:479 return aw_dev_parse_reg_bin_with_hdr(aw_dev, (u8 *)cfg_hdr + cfg_dde->data_offset,480 cfg_dde->data_size, scene_prof_desc);481 default:482 dev_err(aw_dev->dev, "%s cfg_dde->data_type = %d\n", __func__, cfg_dde->data_type);483 break;484 }485 486 return 0;487}488 489static int aw_dev_parse_dev_type(struct aw_device *aw_dev,490 struct aw_cfg_hdr *prof_hdr, struct aw_all_prof_info *all_prof_info)491{492 struct aw_cfg_dde *cfg_dde =493 (struct aw_cfg_dde *)((char *)prof_hdr + prof_hdr->hdr_offset);494 int sec_num = 0;495 int ret, i;496 497 for (i = 0; i < prof_hdr->ddt_num; i++) {498 if ((aw_dev->i2c->adapter->nr == cfg_dde[i].dev_bus) &&499 (aw_dev->i2c->addr == cfg_dde[i].dev_addr) &&500 (cfg_dde[i].type == AW88395_DEV_TYPE_ID) &&501 (cfg_dde[i].data_type != ACF_SEC_TYPE_MONITOR)) {502 if (cfg_dde[i].dev_profile >= AW88395_PROFILE_MAX) {503 dev_err(aw_dev->dev, "dev_profile [%d] overflow",504 cfg_dde[i].dev_profile);505 return -EINVAL;506 }507 aw_dev->prof_data_type = cfg_dde[i].data_type;508 ret = aw_dev_parse_data_by_sec_type(aw_dev, prof_hdr, &cfg_dde[i],509 &all_prof_info->prof_desc[cfg_dde[i].dev_profile]);510 if (ret < 0) {511 dev_err(aw_dev->dev, "parse failed");512 return ret;513 }514 sec_num++;515 }516 }517 518 if (sec_num == 0) {519 dev_dbg(aw_dev->dev, "get dev type num is %d, please use default", sec_num);520 return AW88395_DEV_TYPE_NONE;521 }522 523 return AW88395_DEV_TYPE_OK;524}525 526static int aw_dev_parse_dev_default_type(struct aw_device *aw_dev,527 struct aw_cfg_hdr *prof_hdr, struct aw_all_prof_info *all_prof_info)528{529 struct aw_cfg_dde *cfg_dde =530 (struct aw_cfg_dde *)((char *)prof_hdr + prof_hdr->hdr_offset);531 int sec_num = 0;532 int ret, i;533 534 for (i = 0; i < prof_hdr->ddt_num; i++) {535 if ((aw_dev->channel == cfg_dde[i].dev_index) &&536 (cfg_dde[i].type == AW88395_DEV_DEFAULT_TYPE_ID) &&537 (cfg_dde[i].data_type != ACF_SEC_TYPE_MONITOR)) {538 if (cfg_dde[i].dev_profile >= AW88395_PROFILE_MAX) {539 dev_err(aw_dev->dev, "dev_profile [%d] overflow",540 cfg_dde[i].dev_profile);541 return -EINVAL;542 }543 aw_dev->prof_data_type = cfg_dde[i].data_type;544 ret = aw_dev_parse_data_by_sec_type(aw_dev, prof_hdr, &cfg_dde[i],545 &all_prof_info->prof_desc[cfg_dde[i].dev_profile]);546 if (ret < 0) {547 dev_err(aw_dev->dev, "parse failed");548 return ret;549 }550 sec_num++;551 }552 }553 554 if (sec_num == 0) {555 dev_err(aw_dev->dev, "get dev default type failed, get num[%d]", sec_num);556 return -EINVAL;557 }558 559 return 0;560}561 562static int aw_dev_cfg_get_reg_valid_prof(struct aw_device *aw_dev,563 struct aw_all_prof_info *all_prof_info)564{565 struct aw_prof_desc *prof_desc = all_prof_info->prof_desc;566 struct aw_prof_info *prof_info = &aw_dev->prof_info;567 int num = 0;568 int i;569 570 for (i = 0; i < AW88395_PROFILE_MAX; i++) {571 if (prof_desc[i].prof_st == AW88395_PROFILE_OK)572 prof_info->count++;573 }574 575 dev_dbg(aw_dev->dev, "get valid profile:%d", aw_dev->prof_info.count);576 577 if (!prof_info->count) {578 dev_err(aw_dev->dev, "no profile data");579 return -EPERM;580 }581 582 prof_info->prof_desc = devm_kcalloc(aw_dev->dev,583 prof_info->count, sizeof(struct aw_prof_desc),584 GFP_KERNEL);585 if (!prof_info->prof_desc)586 return -ENOMEM;587 588 for (i = 0; i < AW88395_PROFILE_MAX; i++) {589 if (prof_desc[i].prof_st == AW88395_PROFILE_OK) {590 if (num >= prof_info->count) {591 dev_err(aw_dev->dev, "overflow count[%d]",592 prof_info->count);593 return -EINVAL;594 }595 prof_info->prof_desc[num] = prof_desc[i];596 prof_info->prof_desc[num].id = i;597 num++;598 }599 }600 601 return 0;602}603 604static int aw_dev_cfg_get_multiple_valid_prof(struct aw_device *aw_dev,605 struct aw_all_prof_info *all_prof_info)606{607 struct aw_prof_desc *prof_desc = all_prof_info->prof_desc;608 struct aw_prof_info *prof_info = &aw_dev->prof_info;609 struct aw_sec_data_desc *sec_desc;610 int num = 0;611 int i;612 613 for (i = 0; i < AW88395_PROFILE_MAX; i++) {614 if (prof_desc[i].prof_st == AW88395_PROFILE_OK) {615 sec_desc = prof_desc[i].sec_desc;616 if ((sec_desc[AW88395_DATA_TYPE_REG].data != NULL) &&617 (sec_desc[AW88395_DATA_TYPE_REG].len != 0) &&618 (sec_desc[AW88395_DATA_TYPE_DSP_CFG].data != NULL) &&619 (sec_desc[AW88395_DATA_TYPE_DSP_CFG].len != 0) &&620 (sec_desc[AW88395_DATA_TYPE_DSP_FW].data != NULL) &&621 (sec_desc[AW88395_DATA_TYPE_DSP_FW].len != 0))622 prof_info->count++;623 }624 }625 626 dev_dbg(aw_dev->dev, "get valid profile:%d", aw_dev->prof_info.count);627 628 if (!prof_info->count) {629 dev_err(aw_dev->dev, "no profile data");630 return -EPERM;631 }632 633 prof_info->prof_desc = devm_kcalloc(aw_dev->dev,634 prof_info->count, sizeof(struct aw_prof_desc),635 GFP_KERNEL);636 if (!prof_info->prof_desc)637 return -ENOMEM;638 639 for (i = 0; i < AW88395_PROFILE_MAX; i++) {640 if (prof_desc[i].prof_st == AW88395_PROFILE_OK) {641 sec_desc = prof_desc[i].sec_desc;642 if ((sec_desc[AW88395_DATA_TYPE_REG].data != NULL) &&643 (sec_desc[AW88395_DATA_TYPE_REG].len != 0) &&644 (sec_desc[AW88395_DATA_TYPE_DSP_CFG].data != NULL) &&645 (sec_desc[AW88395_DATA_TYPE_DSP_CFG].len != 0) &&646 (sec_desc[AW88395_DATA_TYPE_DSP_FW].data != NULL) &&647 (sec_desc[AW88395_DATA_TYPE_DSP_FW].len != 0)) {648 if (num >= prof_info->count) {649 dev_err(aw_dev->dev, "overflow count[%d]",650 prof_info->count);651 return -EINVAL;652 }653 prof_info->prof_desc[num] = prof_desc[i];654 prof_info->prof_desc[num].id = i;655 num++;656 }657 }658 }659 660 return 0;661}662 663static int aw_dev_load_cfg_by_hdr(struct aw_device *aw_dev,664 struct aw_cfg_hdr *prof_hdr)665{666 int ret;667 668 struct aw_all_prof_info *all_prof_info __free(kfree) = kzalloc(sizeof(*all_prof_info),669 GFP_KERNEL);670 if (!all_prof_info)671 return -ENOMEM;672 673 ret = aw_dev_parse_dev_type(aw_dev, prof_hdr, all_prof_info);674 if (ret < 0) {675 return ret;676 } else if (ret == AW88395_DEV_TYPE_NONE) {677 dev_dbg(aw_dev->dev, "get dev type num is 0, parse default dev");678 ret = aw_dev_parse_dev_default_type(aw_dev, prof_hdr, all_prof_info);679 if (ret < 0)680 return ret;681 }682 683 switch (aw_dev->prof_data_type) {684 case ACF_SEC_TYPE_MULTIPLE_BIN:685 ret = aw_dev_cfg_get_multiple_valid_prof(aw_dev, all_prof_info);686 break;687 case ACF_SEC_TYPE_HDR_REG:688 ret = aw_dev_cfg_get_reg_valid_prof(aw_dev, all_prof_info);689 break;690 default:691 dev_err(aw_dev->dev, "unsupport data type\n");692 ret = -EINVAL;693 break;694 }695 if (!ret)696 aw_dev->prof_info.prof_name_list = profile_name;697 698 return ret;699}700 701static int aw_dev_create_prof_name_list_v1(struct aw_device *aw_dev)702{703 struct aw_prof_info *prof_info = &aw_dev->prof_info;704 struct aw_prof_desc *prof_desc = prof_info->prof_desc;705 int i;706 707 if (!prof_desc) {708 dev_err(aw_dev->dev, "prof_desc is NULL");709 return -EINVAL;710 }711 712 prof_info->prof_name_list = devm_kzalloc(aw_dev->dev,713 prof_info->count * PROFILE_STR_MAX,714 GFP_KERNEL);715 if (!prof_info->prof_name_list)716 return -ENOMEM;717 718 for (i = 0; i < prof_info->count; i++) {719 prof_desc[i].id = i;720 prof_info->prof_name_list[i] = prof_desc[i].prf_str;721 dev_dbg(aw_dev->dev, "prof name is %s", prof_info->prof_name_list[i]);722 }723 724 return 0;725}726 727static int aw_get_dde_type_info(struct aw_device *aw_dev, struct aw_container *aw_cfg)728{729 struct aw_cfg_hdr *cfg_hdr = (struct aw_cfg_hdr *)aw_cfg->data;730 struct aw_cfg_dde_v1 *cfg_dde =731 (struct aw_cfg_dde_v1 *)(aw_cfg->data + cfg_hdr->hdr_offset);732 int default_num = 0;733 int dev_num = 0;734 unsigned int i;735 736 for (i = 0; i < cfg_hdr->ddt_num; i++) {737 if (cfg_dde[i].type == AW88395_DEV_TYPE_ID)738 dev_num++;739 740 if (cfg_dde[i].type == AW88395_DEV_DEFAULT_TYPE_ID)741 default_num++;742 }743 744 if (dev_num != 0) {745 aw_dev->prof_info.prof_type = AW88395_DEV_TYPE_ID;746 } else if (default_num != 0) {747 aw_dev->prof_info.prof_type = AW88395_DEV_DEFAULT_TYPE_ID;748 } else {749 dev_err(aw_dev->dev, "can't find scene");750 return -EINVAL;751 }752 753 return 0;754}755 756static int aw_get_dev_scene_count_v1(struct aw_device *aw_dev, struct aw_container *aw_cfg,757 unsigned int *scene_num)758{759 struct aw_cfg_hdr *cfg_hdr = (struct aw_cfg_hdr *)aw_cfg->data;760 struct aw_cfg_dde_v1 *cfg_dde =761 (struct aw_cfg_dde_v1 *)(aw_cfg->data + cfg_hdr->hdr_offset);762 unsigned int i;763 764 for (i = 0; i < cfg_hdr->ddt_num; ++i) {765 if (((cfg_dde[i].data_type == ACF_SEC_TYPE_REG) ||766 (cfg_dde[i].data_type == ACF_SEC_TYPE_HDR_REG) ||767 (cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN)) &&768 (aw_dev->chip_id == cfg_dde[i].chip_id) &&769 (aw_dev->i2c->adapter->nr == cfg_dde[i].dev_bus) &&770 (aw_dev->i2c->addr == cfg_dde[i].dev_addr))771 (*scene_num)++;772 }773 774 if ((*scene_num) == 0) {775 dev_err(aw_dev->dev, "failed to obtain scene, scenu_num = %d\n", (*scene_num));776 return -EINVAL;777 }778 779 return 0;780}781 782static int aw_get_default_scene_count_v1(struct aw_device *aw_dev,783 struct aw_container *aw_cfg,784 unsigned int *scene_num)785{786 struct aw_cfg_hdr *cfg_hdr = (struct aw_cfg_hdr *)aw_cfg->data;787 struct aw_cfg_dde_v1 *cfg_dde =788 (struct aw_cfg_dde_v1 *)(aw_cfg->data + cfg_hdr->hdr_offset);789 unsigned int i;790 791 792 for (i = 0; i < cfg_hdr->ddt_num; ++i) {793 if (((cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN) ||794 (cfg_dde[i].data_type == ACF_SEC_TYPE_REG) ||795 (cfg_dde[i].data_type == ACF_SEC_TYPE_HDR_REG)) &&796 (aw_dev->chip_id == cfg_dde[i].chip_id) &&797 (aw_dev->channel == cfg_dde[i].dev_index))798 (*scene_num)++;799 }800 801 if ((*scene_num) == 0) {802 dev_err(aw_dev->dev, "failed to obtain scene, scenu_num = %d\n", (*scene_num));803 return -EINVAL;804 }805 806 return 0;807}808 809static int aw_dev_parse_scene_count_v1(struct aw_device *aw_dev,810 struct aw_container *aw_cfg,811 unsigned int *count)812{813 int ret;814 815 ret = aw_get_dde_type_info(aw_dev, aw_cfg);816 if (ret < 0)817 return ret;818 819 switch (aw_dev->prof_info.prof_type) {820 case AW88395_DEV_TYPE_ID:821 ret = aw_get_dev_scene_count_v1(aw_dev, aw_cfg, count);822 break;823 case AW88395_DEV_DEFAULT_TYPE_ID:824 ret = aw_get_default_scene_count_v1(aw_dev, aw_cfg, count);825 break;826 default:827 dev_err(aw_dev->dev, "unsupported prof_type[%x]", aw_dev->prof_info.prof_type);828 ret = -EINVAL;829 break;830 }831 832 return ret;833}834 835static int aw_dev_parse_data_by_sec_type_v1(struct aw_device *aw_dev,836 struct aw_cfg_hdr *prof_hdr,837 struct aw_cfg_dde_v1 *cfg_dde,838 int *cur_scene_id)839{840 struct aw_prof_info *prof_info = &aw_dev->prof_info;841 int ret;842 843 switch (cfg_dde->data_type) {844 case ACF_SEC_TYPE_MULTIPLE_BIN:845 ret = aw_dev_prof_parse_multi_bin(aw_dev, (u8 *)prof_hdr + cfg_dde->data_offset,846 cfg_dde->data_size, &prof_info->prof_desc[*cur_scene_id]);847 if (ret < 0) {848 dev_err(aw_dev->dev, "parse multi bin failed");849 return ret;850 }851 prof_info->prof_desc[*cur_scene_id].prf_str = cfg_dde->dev_profile_str;852 prof_info->prof_desc[*cur_scene_id].id = cfg_dde->dev_profile;853 (*cur_scene_id)++;854 break;855 case ACF_SEC_TYPE_HDR_REG:856 ret = aw_dev_parse_reg_bin_with_hdr(aw_dev,857 (uint8_t *)prof_hdr + cfg_dde->data_offset,858 cfg_dde->data_size, &prof_info->prof_desc[*cur_scene_id]);859 if (ret < 0) {860 dev_err(aw_dev->dev, "parse reg bin with hdr failed");861 return ret;862 }863 prof_info->prof_desc[*cur_scene_id].prf_str = cfg_dde->dev_profile_str;864 prof_info->prof_desc[*cur_scene_id].id = cfg_dde->dev_profile;865 (*cur_scene_id)++;866 break;867 default:868 dev_err(aw_dev->dev, "unsupported SEC_TYPE [%d]", cfg_dde->data_type);869 return -EINVAL;870 }871 872 return 0;873}874 875static int aw_dev_parse_dev_type_v1(struct aw_device *aw_dev,876 struct aw_cfg_hdr *prof_hdr)877{878 struct aw_cfg_dde_v1 *cfg_dde =879 (struct aw_cfg_dde_v1 *)((char *)prof_hdr + prof_hdr->hdr_offset);880 int cur_scene_id = 0;881 unsigned int i;882 int ret;883 884 for (i = 0; i < prof_hdr->ddt_num; i++) {885 if ((aw_dev->i2c->adapter->nr == cfg_dde[i].dev_bus) &&886 (aw_dev->i2c->addr == cfg_dde[i].dev_addr) &&887 (aw_dev->chip_id == cfg_dde[i].chip_id)) {888 ret = aw_dev_parse_data_by_sec_type_v1(aw_dev, prof_hdr,889 &cfg_dde[i], &cur_scene_id);890 if (ret < 0) {891 dev_err(aw_dev->dev, "parse failed");892 return ret;893 }894 }895 }896 897 if (cur_scene_id == 0) {898 dev_err(aw_dev->dev, "get dev type failed, get num [%d]", cur_scene_id);899 return -EINVAL;900 }901 902 return 0;903}904 905static int aw_dev_parse_default_type_v1(struct aw_device *aw_dev,906 struct aw_cfg_hdr *prof_hdr)907{908 struct aw_cfg_dde_v1 *cfg_dde =909 (struct aw_cfg_dde_v1 *)((char *)prof_hdr + prof_hdr->hdr_offset);910 int cur_scene_id = 0;911 unsigned int i;912 int ret;913 914 for (i = 0; i < prof_hdr->ddt_num; i++) {915 if ((aw_dev->channel == cfg_dde[i].dev_index) &&916 (aw_dev->chip_id == cfg_dde[i].chip_id)) {917 ret = aw_dev_parse_data_by_sec_type_v1(aw_dev, prof_hdr,918 &cfg_dde[i], &cur_scene_id);919 if (ret < 0) {920 dev_err(aw_dev->dev, "parse failed");921 return ret;922 }923 }924 }925 926 if (cur_scene_id == 0) {927 dev_err(aw_dev->dev, "get dev default type failed, get num[%d]", cur_scene_id);928 return -EINVAL;929 }930 931 return 0;932}933 934static int aw_dev_parse_by_hdr_v1(struct aw_device *aw_dev,935 struct aw_cfg_hdr *cfg_hdr)936{937 int ret;938 939 switch (aw_dev->prof_info.prof_type) {940 case AW88395_DEV_TYPE_ID:941 ret = aw_dev_parse_dev_type_v1(aw_dev, cfg_hdr);942 break;943 case AW88395_DEV_DEFAULT_TYPE_ID:944 ret = aw_dev_parse_default_type_v1(aw_dev, cfg_hdr);945 break;946 default:947 dev_err(aw_dev->dev, "prof type matched failed, get num[%d]",948 aw_dev->prof_info.prof_type);949 ret = -EINVAL;950 break;951 }952 953 return ret;954}955 956static int aw_dev_load_cfg_by_hdr_v1(struct aw_device *aw_dev,957 struct aw_container *aw_cfg)958{959 struct aw_cfg_hdr *cfg_hdr = (struct aw_cfg_hdr *)aw_cfg->data;960 struct aw_prof_info *prof_info = &aw_dev->prof_info;961 int ret;962 963 ret = aw_dev_parse_scene_count_v1(aw_dev, aw_cfg, &prof_info->count);964 if (ret < 0) {965 dev_err(aw_dev->dev, "get scene count failed");966 return ret;967 }968 969 prof_info->prof_desc = devm_kcalloc(aw_dev->dev,970 prof_info->count, sizeof(struct aw_prof_desc),971 GFP_KERNEL);972 if (!prof_info->prof_desc)973 return -ENOMEM;974 975 ret = aw_dev_parse_by_hdr_v1(aw_dev, cfg_hdr);976 if (ret < 0) {977 dev_err(aw_dev->dev, "parse hdr failed");978 return ret;979 }980 981 ret = aw_dev_create_prof_name_list_v1(aw_dev);982 if (ret < 0) {983 dev_err(aw_dev->dev, "create prof name list failed");984 return ret;985 }986 987 return 0;988}989 990int aw88395_dev_cfg_load(struct aw_device *aw_dev, struct aw_container *aw_cfg)991{992 struct aw_cfg_hdr *cfg_hdr;993 int ret;994 995 cfg_hdr = (struct aw_cfg_hdr *)aw_cfg->data;996 997 switch (cfg_hdr->hdr_version) {998 case AW88395_CFG_HDR_VER:999 ret = aw_dev_load_cfg_by_hdr(aw_dev, cfg_hdr);1000 if (ret < 0) {1001 dev_err(aw_dev->dev, "hdr_version[0x%x] parse failed",1002 cfg_hdr->hdr_version);1003 return ret;1004 }1005 break;1006 case AW88395_CFG_HDR_VER_V1:1007 ret = aw_dev_load_cfg_by_hdr_v1(aw_dev, aw_cfg);1008 if (ret < 0) {1009 dev_err(aw_dev->dev, "hdr_version[0x%x] parse failed",1010 cfg_hdr->hdr_version);1011 return ret;1012 }1013 break;1014 default:1015 dev_err(aw_dev->dev, "unsupported hdr_version [0x%x]", cfg_hdr->hdr_version);1016 return -EINVAL;1017 }1018 aw_dev->fw_status = AW88395_DEV_FW_OK;1019 1020 return 0;1021}1022EXPORT_SYMBOL_GPL(aw88395_dev_cfg_load);1023 1024static int aw_dev_check_cfg_by_hdr(struct aw_device *aw_dev, struct aw_container *aw_cfg)1025{1026 unsigned int end_data_offset;1027 struct aw_cfg_hdr *cfg_hdr;1028 struct aw_cfg_dde *cfg_dde;1029 unsigned int act_data = 0;1030 unsigned int hdr_ddt_len;1031 unsigned int i;1032 u8 act_crc8;1033 1034 cfg_hdr = (struct aw_cfg_hdr *)aw_cfg->data;1035 /* check file type id is awinic acf file */1036 if (cfg_hdr->id != ACF_FILE_ID) {1037 dev_err(aw_dev->dev, "not acf type file");1038 return -EINVAL;1039 }1040 1041 hdr_ddt_len = cfg_hdr->hdr_offset + cfg_hdr->ddt_size;1042 if (hdr_ddt_len > aw_cfg->len) {1043 dev_err(aw_dev->dev, "hdr_len with ddt_len [%d] overflow file size[%d]",1044 cfg_hdr->hdr_offset, aw_cfg->len);1045 return -EINVAL;1046 }1047 1048 /* check data size */1049 cfg_dde = (struct aw_cfg_dde *)((char *)aw_cfg->data + cfg_hdr->hdr_offset);1050 act_data += hdr_ddt_len;1051 for (i = 0; i < cfg_hdr->ddt_num; i++)1052 act_data += cfg_dde[i].data_size;1053 1054 if (act_data != aw_cfg->len) {1055 dev_err(aw_dev->dev, "act_data[%d] not equal to file size[%d]!",1056 act_data, aw_cfg->len);1057 return -EINVAL;1058 }1059 1060 for (i = 0; i < cfg_hdr->ddt_num; i++) {1061 /* data check */1062 end_data_offset = cfg_dde[i].data_offset + cfg_dde[i].data_size;1063 if (end_data_offset > aw_cfg->len) {1064 dev_err(aw_dev->dev, "ddt_num[%d] end_data_offset[%d] overflow size[%d]",1065 i, end_data_offset, aw_cfg->len);1066 return -EINVAL;1067 }1068 1069 /* crc check */1070 act_crc8 = crc8(aw_crc8_table, aw_cfg->data + cfg_dde[i].data_offset,1071 cfg_dde[i].data_size, 0);1072 if (act_crc8 != cfg_dde[i].data_crc) {1073 dev_err(aw_dev->dev, "ddt_num[%d] act_crc8:0x%x != data_crc:0x%x",1074 i, (u32)act_crc8, cfg_dde[i].data_crc);1075 return -EINVAL;1076 }1077 }1078 1079 return 0;1080}1081 1082static int aw_dev_check_acf_by_hdr_v1(struct aw_device *aw_dev, struct aw_container *aw_cfg)1083{1084 struct aw_cfg_dde_v1 *cfg_dde;1085 unsigned int end_data_offset;1086 struct aw_cfg_hdr *cfg_hdr;1087 unsigned int act_data = 0;1088 unsigned int hdr_ddt_len;1089 u8 act_crc8;1090 int i;1091 1092 cfg_hdr = (struct aw_cfg_hdr *)aw_cfg->data;1093 1094 /* check file type id is awinic acf file */1095 if (cfg_hdr->id != ACF_FILE_ID) {1096 dev_err(aw_dev->dev, "not acf type file");1097 return -EINVAL;1098 }1099 1100 hdr_ddt_len = cfg_hdr->hdr_offset + cfg_hdr->ddt_size;1101 if (hdr_ddt_len > aw_cfg->len) {1102 dev_err(aw_dev->dev, "hdrlen with ddt_len [%d] overflow file size[%d]",1103 cfg_hdr->hdr_offset, aw_cfg->len);1104 return -EINVAL;1105 }1106 1107 /* check data size */1108 cfg_dde = (struct aw_cfg_dde_v1 *)((char *)aw_cfg->data + cfg_hdr->hdr_offset);1109 act_data += hdr_ddt_len;1110 for (i = 0; i < cfg_hdr->ddt_num; i++)1111 act_data += cfg_dde[i].data_size;1112 1113 if (act_data != aw_cfg->len) {1114 dev_err(aw_dev->dev, "act_data[%d] not equal to file size[%d]!",1115 act_data, aw_cfg->len);1116 return -EINVAL;1117 }1118 1119 for (i = 0; i < cfg_hdr->ddt_num; i++) {1120 /* data check */1121 end_data_offset = cfg_dde[i].data_offset + cfg_dde[i].data_size;1122 if (end_data_offset > aw_cfg->len) {1123 dev_err(aw_dev->dev, "ddt_num[%d] end_data_offset[%d] overflow size[%d]",1124 i, end_data_offset, aw_cfg->len);1125 return -EINVAL;1126 }1127 1128 /* crc check */1129 act_crc8 = crc8(aw_crc8_table, aw_cfg->data + cfg_dde[i].data_offset,1130 cfg_dde[i].data_size, 0);1131 if (act_crc8 != cfg_dde[i].data_crc) {1132 dev_err(aw_dev->dev, "ddt_num[%d] act_crc8:0x%x != data_crc 0x%x",1133 i, (u32)act_crc8, cfg_dde[i].data_crc);1134 return -EINVAL;1135 }1136 }1137 1138 return 0;1139}1140 1141int aw88395_dev_load_acf_check(struct aw_device *aw_dev, struct aw_container *aw_cfg)1142{1143 struct aw_cfg_hdr *cfg_hdr;1144 1145 if (!aw_cfg) {1146 dev_err(aw_dev->dev, "aw_prof is NULL");1147 return -EINVAL;1148 }1149 1150 if (aw_cfg->len < sizeof(struct aw_cfg_hdr)) {1151 dev_err(aw_dev->dev, "cfg hdr size[%d] overflow file size[%d]",1152 aw_cfg->len, (int)sizeof(struct aw_cfg_hdr));1153 return -EINVAL;1154 }1155 1156 crc8_populate_lsb(aw_crc8_table, AW88395_CRC8_POLYNOMIAL);1157 1158 cfg_hdr = (struct aw_cfg_hdr *)aw_cfg->data;1159 switch (cfg_hdr->hdr_version) {1160 case AW88395_CFG_HDR_VER:1161 return aw_dev_check_cfg_by_hdr(aw_dev, aw_cfg);1162 case AW88395_CFG_HDR_VER_V1:1163 return aw_dev_check_acf_by_hdr_v1(aw_dev, aw_cfg);1164 default:1165 dev_err(aw_dev->dev, "unsupported hdr_version [0x%x]", cfg_hdr->hdr_version);1166 return -EINVAL;1167 }1168 1169 return 0;1170}1171EXPORT_SYMBOL_GPL(aw88395_dev_load_acf_check);1172 1173MODULE_DESCRIPTION("AW88395 ACF File Parsing Lib");1174MODULE_LICENSE("GPL v2");1175