6db4831e98
Android 14
513 lines
16 KiB
C
513 lines
16 KiB
C
/*
|
|
* aw_bin_parse.c
|
|
*
|
|
* Copyright (c) 2020 AWINIC Technology CO., LTD
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation; either version 2 of the License, or (at your
|
|
* option) any later version.
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/i2c.h>
|
|
#include <linux/of_gpio.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/device.h>
|
|
#include <linux/firmware.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/version.h>
|
|
#include <linux/input.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/debugfs.h>
|
|
#include <linux/miscdevice.h>
|
|
#include <asm/uaccess.h>
|
|
#include <linux/regmap.h>
|
|
#include <linux/timer.h>
|
|
#include <linux/workqueue.h>
|
|
#include <linux/hrtimer.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/cdev.h>
|
|
#include <linux/list.h>
|
|
#include <linux/string.h>
|
|
#include "aw_bin_parse.h"
|
|
|
|
#define AWINIC_CODE_VERSION "V0.0.7-V1.0.4" /* "code version"-"excel version" */
|
|
|
|
#define DEBUG_LOG_LEVEL
|
|
#ifdef DEBUG_LOG_LEVEL
|
|
#define DBG(fmt, arg...) do {\
|
|
printk("AWINIC_BIN %s,line= %d,"fmt, __func__, __LINE__, ##arg);\
|
|
} while (0)
|
|
#define DBG_ERR(fmt, arg...) do {\
|
|
printk("AWINIC_BIN_ERR %s,line= %d,"fmt, __func__, __LINE__, ##arg);\
|
|
} while (0)
|
|
#else
|
|
#define DBG(fmt, arg...) do {} while (0)
|
|
#define DBG_ERR(fmt, arg...) do {} while (0)
|
|
#endif
|
|
|
|
#define printing_data_code
|
|
|
|
typedef unsigned short int aw_uint16;
|
|
typedef unsigned long int aw_uint32;
|
|
|
|
#define BigLittleSwap16(A) ((((aw_uint16)(A) & 0xff00) >> 8) | \
|
|
(((aw_uint16)(A) & 0x00ff) << 8))
|
|
|
|
#define BigLittleSwap32(A) ((((aw_uint32)(A) & 0xff000000) >> 24) | \
|
|
(((aw_uint32)(A) & 0x00ff0000) >> 8) | \
|
|
(((aw_uint32)(A) & 0x0000ff00) << 8) | \
|
|
(((aw_uint32)(A) & 0x000000ff) << 24))
|
|
|
|
/**
|
|
*
|
|
* Interface function
|
|
*
|
|
* return value:
|
|
* value = 0 :success;
|
|
* value = -1 :check bin header version
|
|
* value = -2 :check bin data type
|
|
* value = -3 :check sum or check bin data len error
|
|
* value = -4 :check data version
|
|
* value = -5 :check register num
|
|
* value = -6 :check dsp reg num
|
|
* value = -7 :check soc app num
|
|
* value = -8 :bin is NULL point
|
|
*
|
|
**/
|
|
|
|
/********************************************************
|
|
*
|
|
* check sum data
|
|
*
|
|
********************************************************/
|
|
int aw_check_sum(struct aw_bin *bin, int bin_num)
|
|
{
|
|
unsigned int i = 0;
|
|
unsigned int sum_data = 0;
|
|
unsigned int check_sum = 0;
|
|
unsigned char *p_check_sum = NULL;
|
|
|
|
DBG("enter\n");
|
|
|
|
p_check_sum =
|
|
&(bin->info.data[(bin->header_info[bin_num].valid_data_addr -
|
|
bin->header_info[bin_num].header_len)]);
|
|
DBG("aw_bin_parse p_check_sum = %p\n", p_check_sum);
|
|
check_sum = GET_32_DATA(*(p_check_sum + 3),
|
|
*(p_check_sum + 2),
|
|
*(p_check_sum + 1), *(p_check_sum));
|
|
|
|
for (i = 4;
|
|
i <
|
|
bin->header_info[bin_num].bin_data_len +
|
|
bin->header_info[bin_num].header_len; i++) {
|
|
sum_data += *(p_check_sum + i);
|
|
}
|
|
DBG("aw_bin_parse bin_num=%d, check_sum = 0x%x, sum_data = 0x%x\n",
|
|
bin_num, check_sum, sum_data);
|
|
if (sum_data != check_sum) {
|
|
p_check_sum = NULL;
|
|
DBG_ERR("aw_bin_parse check sum or check bin data len error\n");
|
|
DBG_ERR("aw_bin_parse bin_num=%d, check_sum = 0x%x, sum_data = 0x%x\n", bin_num, check_sum, sum_data);
|
|
return -3;
|
|
}
|
|
p_check_sum = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int aw_check_data_version(struct aw_bin *bin, int bin_num)
|
|
{
|
|
int i = 0;
|
|
DBG("enter\n");
|
|
|
|
for (i = DATA_VERSION_V1; i < DATA_VERSION_MAX; i++) {
|
|
if (bin->header_info[bin_num].bin_data_ver == i) {
|
|
return 0;
|
|
}
|
|
}
|
|
DBG_ERR("aw_bin_parse Unrecognized this bin data version\n");
|
|
return -4;
|
|
}
|
|
|
|
int aw_check_register_num_v1(struct aw_bin *bin, int bin_num)
|
|
{
|
|
unsigned int check_register_num = 0;
|
|
unsigned int parse_register_num = 0;
|
|
char *p_check_sum = NULL;
|
|
|
|
DBG("enter\n");
|
|
|
|
p_check_sum =
|
|
&(bin->info.data[(bin->header_info[bin_num].valid_data_addr)]);
|
|
DBG("aw_bin_parse p_check_sum = %p\n", p_check_sum);
|
|
parse_register_num = GET_32_DATA(*(p_check_sum + 3),
|
|
*(p_check_sum + 2),
|
|
*(p_check_sum + 1), *(p_check_sum));
|
|
check_register_num = (bin->header_info[bin_num].bin_data_len - 4) /
|
|
(bin->header_info[bin_num].reg_byte_len +
|
|
bin->header_info[bin_num].data_byte_len);
|
|
DBG
|
|
("aw_bin_parse bin_num=%d, parse_register_num = 0x%x, check_register_num = 0x%x\n",
|
|
bin_num, parse_register_num, check_register_num);
|
|
if (parse_register_num != check_register_num) {
|
|
p_check_sum = NULL;
|
|
DBG_ERR("aw_bin_parse register num is error\n");
|
|
DBG_ERR("aw_bin_parse bin_num=%d, parse_register_num = 0x%x, check_register_num = 0x%x\n", bin_num, parse_register_num, check_register_num);
|
|
return -5;
|
|
}
|
|
bin->header_info[bin_num].reg_num = parse_register_num;
|
|
bin->header_info[bin_num].valid_data_len =
|
|
bin->header_info[bin_num].bin_data_len - 4;
|
|
p_check_sum = NULL;
|
|
bin->header_info[bin_num].valid_data_addr =
|
|
bin->header_info[bin_num].valid_data_addr + 4;
|
|
return 0;
|
|
}
|
|
|
|
int aw_check_dsp_reg_num_v1(struct aw_bin *bin, int bin_num)
|
|
{
|
|
unsigned int check_dsp_reg_num = 0;
|
|
unsigned int parse_dsp_reg_num = 0;
|
|
char *p_check_sum = NULL;
|
|
|
|
DBG("enter\n");
|
|
|
|
p_check_sum =
|
|
&(bin->info.data[(bin->header_info[bin_num].valid_data_addr)]);
|
|
DBG("aw_bin_parse p_check_sum = %p\n", p_check_sum);
|
|
parse_dsp_reg_num = GET_32_DATA(*(p_check_sum + 7),
|
|
*(p_check_sum + 6),
|
|
*(p_check_sum + 5), *(p_check_sum + 4));
|
|
bin->header_info[bin_num].reg_data_byte_len =
|
|
GET_32_DATA(*(p_check_sum + 11), *(p_check_sum + 10),
|
|
*(p_check_sum + 9), *(p_check_sum + 8));
|
|
check_dsp_reg_num =
|
|
(bin->header_info[bin_num].bin_data_len -
|
|
12) / bin->header_info[bin_num].reg_data_byte_len;
|
|
DBG
|
|
("aw_bin_parse bin_num=%d, parse_dsp_reg_num = 0x%x, check_dsp_reg_num = 0x%x\n",
|
|
bin_num, parse_dsp_reg_num, check_dsp_reg_num);
|
|
if (parse_dsp_reg_num != check_dsp_reg_num) {
|
|
p_check_sum = NULL;
|
|
DBG_ERR("aw_bin_parse dsp reg num is error\n");
|
|
DBG_ERR("aw_bin_parse bin_num=%d, parse_dsp_reg_num = 0x%x, check_dsp_reg_num = 0x%x\n", bin_num, parse_dsp_reg_num, check_dsp_reg_num);
|
|
return -6;
|
|
}
|
|
bin->header_info[bin_num].download_addr =
|
|
GET_32_DATA(*(p_check_sum + 3), *(p_check_sum + 2),
|
|
*(p_check_sum + 1), *(p_check_sum));
|
|
bin->header_info[bin_num].reg_num = parse_dsp_reg_num;
|
|
bin->header_info[bin_num].valid_data_len =
|
|
bin->header_info[bin_num].bin_data_len - 12;
|
|
p_check_sum = NULL;
|
|
bin->header_info[bin_num].valid_data_addr =
|
|
bin->header_info[bin_num].valid_data_addr + 12;
|
|
return 0;
|
|
}
|
|
|
|
int aw_check_soc_app_num_v1(struct aw_bin *bin, int bin_num)
|
|
{
|
|
unsigned int check_soc_app_num = 0;
|
|
unsigned int parse_soc_app_num = 0;
|
|
char *p_check_sum = NULL;
|
|
|
|
DBG("enter\n");
|
|
|
|
p_check_sum =
|
|
&(bin->info.data[(bin->header_info[bin_num].valid_data_addr)]);
|
|
DBG("aw_bin_parse p_check_sum = %p\n", p_check_sum);
|
|
bin->header_info[bin_num].app_version = GET_32_DATA(*(p_check_sum + 3),
|
|
*(p_check_sum + 2),
|
|
*(p_check_sum + 1),
|
|
*(p_check_sum));
|
|
parse_soc_app_num = GET_32_DATA(*(p_check_sum + 11),
|
|
*(p_check_sum + 10),
|
|
*(p_check_sum + 9), *(p_check_sum + 8));
|
|
check_soc_app_num = bin->header_info[bin_num].bin_data_len - 12;
|
|
DBG
|
|
("aw_bin_parse bin_num=%d, parse_soc_app_num = 0x%x, check_soc_app_num = 0x%x\n",
|
|
bin_num, parse_soc_app_num, check_soc_app_num);
|
|
if (parse_soc_app_num != check_soc_app_num) {
|
|
p_check_sum = NULL;
|
|
DBG_ERR("aw_bin_parse soc app num is error\n");
|
|
DBG_ERR("aw_bin_parse bin_num=%d, parse_soc_app_num = 0x%x, check_soc_app_num = 0x%x\n", bin_num, parse_soc_app_num, check_soc_app_num);
|
|
return -7;
|
|
}
|
|
bin->header_info[bin_num].reg_num = parse_soc_app_num;
|
|
bin->header_info[bin_num].download_addr =
|
|
GET_32_DATA(*(p_check_sum + 7), *(p_check_sum + 6),
|
|
*(p_check_sum + 5), *(p_check_sum + 4));
|
|
bin->header_info[bin_num].valid_data_len =
|
|
bin->header_info[bin_num].bin_data_len - 12;
|
|
p_check_sum = NULL;
|
|
bin->header_info[bin_num].valid_data_addr =
|
|
bin->header_info[bin_num].valid_data_addr + 12;
|
|
return 0;
|
|
}
|
|
|
|
/************************
|
|
***
|
|
***bin header 1_0_0
|
|
***
|
|
************************/
|
|
void aw_get_single_bin_header_1_0_0(struct aw_bin *bin)
|
|
{
|
|
int i;
|
|
DBG("enter %s\n", __func__);
|
|
bin->header_info[bin->all_bin_parse_num].header_len = 60;
|
|
bin->header_info[bin->all_bin_parse_num].check_sum =
|
|
GET_32_DATA(*(bin->p_addr + 3), *(bin->p_addr + 2),
|
|
*(bin->p_addr + 1), *(bin->p_addr));
|
|
bin->header_info[bin->all_bin_parse_num].header_ver =
|
|
GET_32_DATA(*(bin->p_addr + 7), *(bin->p_addr + 6),
|
|
*(bin->p_addr + 5), *(bin->p_addr + 4));
|
|
bin->header_info[bin->all_bin_parse_num].bin_data_type =
|
|
GET_32_DATA(*(bin->p_addr + 11), *(bin->p_addr + 10),
|
|
*(bin->p_addr + 9), *(bin->p_addr + 8));
|
|
bin->header_info[bin->all_bin_parse_num].bin_data_ver =
|
|
GET_32_DATA(*(bin->p_addr + 15), *(bin->p_addr + 14),
|
|
*(bin->p_addr + 13), *(bin->p_addr + 12));
|
|
bin->header_info[bin->all_bin_parse_num].bin_data_len =
|
|
GET_32_DATA(*(bin->p_addr + 19), *(bin->p_addr + 18),
|
|
*(bin->p_addr + 17), *(bin->p_addr + 16));
|
|
bin->header_info[bin->all_bin_parse_num].ui_ver =
|
|
GET_32_DATA(*(bin->p_addr + 23), *(bin->p_addr + 22),
|
|
*(bin->p_addr + 21), *(bin->p_addr + 20));
|
|
bin->header_info[bin->all_bin_parse_num].reg_byte_len =
|
|
GET_32_DATA(*(bin->p_addr + 35), *(bin->p_addr + 34),
|
|
*(bin->p_addr + 33), *(bin->p_addr + 32));
|
|
bin->header_info[bin->all_bin_parse_num].data_byte_len =
|
|
GET_32_DATA(*(bin->p_addr + 39), *(bin->p_addr + 38),
|
|
*(bin->p_addr + 37), *(bin->p_addr + 36));
|
|
bin->header_info[bin->all_bin_parse_num].device_addr =
|
|
GET_32_DATA(*(bin->p_addr + 43), *(bin->p_addr + 42),
|
|
*(bin->p_addr + 41), *(bin->p_addr + 40));
|
|
for (i = 0; i < 8; i++) {
|
|
bin->header_info[bin->all_bin_parse_num].chip_type[i] =
|
|
*(bin->p_addr + 24 + i);
|
|
}
|
|
bin->header_info[bin->all_bin_parse_num].reg_num = 0x00000000;
|
|
bin->header_info[bin->all_bin_parse_num].reg_data_byte_len = 0x00000000;
|
|
bin->header_info[bin->all_bin_parse_num].download_addr = 0x00000000;
|
|
bin->header_info[bin->all_bin_parse_num].app_version = 0x00000000;
|
|
bin->header_info[bin->all_bin_parse_num].valid_data_len = 0x00000000;
|
|
bin->all_bin_parse_num += 1;
|
|
}
|
|
|
|
int aw_parse_each_of_multi_bins_1_0_0(unsigned int bin_num, int bin_serial_num,
|
|
struct aw_bin *bin)
|
|
{
|
|
int ret = 0;
|
|
unsigned int bin_start_addr = 0;
|
|
unsigned int valid_data_len = 0;
|
|
DBG("aw_bin_parse enter multi bin branch -- %s\n", __func__);
|
|
if (!bin_serial_num) {
|
|
bin_start_addr = GET_32_DATA(*(bin->p_addr + 67),
|
|
*(bin->p_addr + 66),
|
|
*(bin->p_addr + 65),
|
|
*(bin->p_addr + 64));
|
|
bin->p_addr += (60 + bin_start_addr);
|
|
bin->header_info[bin->all_bin_parse_num].valid_data_addr =
|
|
bin->header_info[bin->all_bin_parse_num -
|
|
1].valid_data_addr + 4 + 8 * bin_num + 60;
|
|
} else {
|
|
valid_data_len =
|
|
bin->header_info[bin->all_bin_parse_num - 1].bin_data_len;
|
|
bin->p_addr += (60 + valid_data_len);
|
|
bin->header_info[bin->all_bin_parse_num].valid_data_addr =
|
|
bin->header_info[bin->all_bin_parse_num -
|
|
1].valid_data_addr +
|
|
bin->header_info[bin->all_bin_parse_num - 1].bin_data_len +
|
|
60;
|
|
}
|
|
|
|
ret = aw_parse_bin_header_1_0_0(bin);
|
|
return ret;
|
|
}
|
|
|
|
/* Get the number of bins in multi bins, and set a for loop, loop processing each bin data */
|
|
int aw_get_multi_bin_header_1_0_0(struct aw_bin *bin)
|
|
{
|
|
int i = 0;
|
|
int ret = 0;
|
|
unsigned int bin_num = 0;
|
|
DBG("aw_bin_parse enter multi bin branch -- %s\n", __func__);
|
|
bin_num = GET_32_DATA(*(bin->p_addr + 63),
|
|
*(bin->p_addr + 62),
|
|
*(bin->p_addr + 61), *(bin->p_addr + 60));
|
|
if (bin->multi_bin_parse_num == 1) {
|
|
bin->header_info[bin->all_bin_parse_num].valid_data_addr = 60;
|
|
}
|
|
aw_get_single_bin_header_1_0_0(bin);
|
|
|
|
for (i = 0; i < bin_num; i++) {
|
|
DBG("aw_bin_parse enter multi bin for is %d\n", i);
|
|
ret = aw_parse_each_of_multi_bins_1_0_0(bin_num, i, bin);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/********************************************************
|
|
*
|
|
* If the bin framework header version is 1.0.0,
|
|
determine the data type of bin, and then perform different processing
|
|
according to the data type
|
|
If it is a single bin data type, write the data directly into the structure array
|
|
If it is a multi-bin data type, first obtain the number of bins,
|
|
and then recursively call the bin frame header processing function
|
|
according to the bin number to process the frame header information of each bin separately
|
|
*
|
|
********************************************************/
|
|
int aw_parse_bin_header_1_0_0(struct aw_bin *bin)
|
|
{
|
|
int ret = 0;
|
|
unsigned int bin_data_type;
|
|
DBG("enter %s\n", __func__);
|
|
bin_data_type = GET_32_DATA(*(bin->p_addr + 11),
|
|
*(bin->p_addr + 10),
|
|
*(bin->p_addr + 9), *(bin->p_addr + 8));
|
|
DBG("aw_bin_parse bin_data_type 0x%x\n", bin_data_type);
|
|
switch (bin_data_type) {
|
|
case DATA_TYPE_REGISTER:
|
|
case DATA_TYPE_DSP_REG:
|
|
case DATA_TYPE_SOC_APP:
|
|
/* Divided into two processing methods,
|
|
one is single bin processing,
|
|
and the other is single bin processing in multi bin */
|
|
DBG("aw_bin_parse enter single bin branch\n");
|
|
bin->single_bin_parse_num += 1;
|
|
DBG("%s bin->single_bin_parse_num is %d\n", __func__,
|
|
bin->single_bin_parse_num);
|
|
if (!bin->multi_bin_parse_num) {
|
|
bin->header_info[bin->
|
|
all_bin_parse_num].valid_data_addr =
|
|
60;
|
|
}
|
|
aw_get_single_bin_header_1_0_0(bin);
|
|
break;
|
|
case DATA_TYPE_MULTI_BINS:
|
|
/* Get the number of times to enter multi bins */
|
|
DBG("aw_bin_parse enter multi bin branch\n");
|
|
bin->multi_bin_parse_num += 1;
|
|
DBG("%s bin->multi_bin_parse_num is %d\n", __func__,
|
|
bin->multi_bin_parse_num);
|
|
ret = aw_get_multi_bin_header_1_0_0(bin);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
break;
|
|
default:
|
|
DBG_ERR("aw_bin_parse Unrecognized this bin data type\n");
|
|
return -2;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* get the bin's header version */
|
|
static int aw_check_bin_header_version(struct aw_bin *bin)
|
|
{
|
|
int ret = 0;
|
|
unsigned int header_version = 0;
|
|
|
|
header_version = GET_32_DATA(*(bin->p_addr + 7),
|
|
*(bin->p_addr + 6),
|
|
*(bin->p_addr + 5), *(bin->p_addr + 4));
|
|
|
|
DBG("aw_bin_parse header_version 0x%x\n", header_version);
|
|
|
|
/* Write data to the corresponding structure array
|
|
according to different formats of the bin frame header version */
|
|
switch (header_version) {
|
|
case HEADER_VERSION_1_0_0:
|
|
ret = aw_parse_bin_header_1_0_0(bin);
|
|
return ret;
|
|
default:
|
|
DBG_ERR("aw_bin_parse Unrecognized this bin header version \n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int aw_parsing_bin_file(struct aw_bin *bin)
|
|
{
|
|
int i = 0;
|
|
int ret = 0;
|
|
|
|
DBG("aw_bin_parse code version:%s\n", AWINIC_CODE_VERSION);
|
|
if (!bin) {
|
|
DBG_ERR("aw_bin_parse bin is NULL\n");
|
|
return -8;
|
|
}
|
|
bin->p_addr = bin->info.data;
|
|
bin->all_bin_parse_num = 0;
|
|
bin->multi_bin_parse_num = 0;
|
|
bin->single_bin_parse_num = 0;
|
|
|
|
/* filling bins header info */
|
|
ret = aw_check_bin_header_version(bin);
|
|
if (ret < 0) {
|
|
DBG_ERR("aw_bin_parse check bin header version error\n");
|
|
return ret;
|
|
}
|
|
bin->p_addr = NULL;
|
|
|
|
/* check bin header info */
|
|
for (i = 0; i < bin->all_bin_parse_num; i++) {
|
|
/* check sum */
|
|
ret = aw_check_sum(bin, i);
|
|
if (ret < 0) {
|
|
DBG_ERR("aw_bin_parse check sum data error\n");
|
|
return ret;
|
|
}
|
|
/* check bin data version */
|
|
ret = aw_check_data_version(bin, i);
|
|
if (ret < 0) {
|
|
DBG_ERR("aw_bin_parse check data version error\n");
|
|
return ret;
|
|
}
|
|
/* check valid data */
|
|
if (bin->header_info[i].bin_data_ver == DATA_VERSION_V1) {
|
|
/* check register num */
|
|
if (bin->header_info[i].bin_data_type ==
|
|
DATA_TYPE_REGISTER) {
|
|
ret = aw_check_register_num_v1(bin, i);
|
|
if (ret < 0) {
|
|
DBG_ERR
|
|
("aw_bin_parse check register num error\n");
|
|
return ret;
|
|
}
|
|
/* check dsp reg num */
|
|
} else if (bin->header_info[i].bin_data_type ==
|
|
DATA_TYPE_DSP_REG) {
|
|
ret = aw_check_dsp_reg_num_v1(bin, i);
|
|
if (ret < 0) {
|
|
DBG_ERR
|
|
("aw_bin_parse check dsp reg num error\n");
|
|
return ret;
|
|
}
|
|
/* check soc app num */
|
|
} else if (bin->header_info[i].bin_data_type ==
|
|
DATA_TYPE_SOC_APP) {
|
|
ret = aw_check_soc_app_num_v1(bin, i);
|
|
if (ret < 0) {
|
|
DBG_ERR
|
|
("aw_bin_parse check soc app num error\n");
|
|
return ret;
|
|
}
|
|
} else {
|
|
bin->header_info[i].valid_data_len =
|
|
bin->header_info[i].bin_data_len;
|
|
}
|
|
}
|
|
}
|
|
DBG("aw_bin_parse parsing success\n");
|
|
|
|
return 0;
|
|
}
|