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