1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // |
3 | // tasdevice-fmw.c -- TASDEVICE firmware support |
4 | // |
5 | // Copyright 2023 Texas Instruments, Inc. |
6 | // |
7 | // Author: Shenghao Ding <shenghao-ding@ti.com> |
8 | |
9 | #include <linux/crc8.h> |
10 | #include <linux/firmware.h> |
11 | #include <linux/i2c.h> |
12 | #include <linux/init.h> |
13 | #include <linux/interrupt.h> |
14 | #include <linux/module.h> |
15 | #include <linux/of.h> |
16 | #include <linux/of_gpio.h> |
17 | #include <linux/of_irq.h> |
18 | #include <linux/regmap.h> |
19 | #include <linux/slab.h> |
20 | #include <sound/pcm_params.h> |
21 | #include <sound/soc.h> |
22 | #include <sound/tlv.h> |
23 | #include <sound/tas2781.h> |
24 | |
25 | |
26 | #define ERROR_PRAM_CRCCHK 0x0000000 |
27 | #define ERROR_YRAM_CRCCHK 0x0000001 |
28 | #define PPC_DRIVER_CRCCHK 0x00000200 |
29 | |
30 | #define TAS2781_SA_COEFF_SWAP_REG TASDEVICE_REG(0, 0x35, 0x2c) |
31 | #define TAS2781_YRAM_BOOK1 140 |
32 | #define TAS2781_YRAM1_PAGE 42 |
33 | #define TAS2781_YRAM1_START_REG 88 |
34 | |
35 | #define TAS2781_YRAM2_START_PAGE 43 |
36 | #define TAS2781_YRAM2_END_PAGE 49 |
37 | #define TAS2781_YRAM2_START_REG 8 |
38 | #define TAS2781_YRAM2_END_REG 127 |
39 | |
40 | #define TAS2781_YRAM3_PAGE 50 |
41 | #define TAS2781_YRAM3_START_REG 8 |
42 | #define TAS2781_YRAM3_END_REG 27 |
43 | |
44 | /*should not include B0_P53_R44-R47 */ |
45 | #define TAS2781_YRAM_BOOK2 0 |
46 | #define TAS2781_YRAM4_START_PAGE 50 |
47 | #define TAS2781_YRAM4_END_PAGE 60 |
48 | |
49 | #define TAS2781_YRAM5_PAGE 61 |
50 | #define TAS2781_YRAM5_START_REG TAS2781_YRAM3_START_REG |
51 | #define TAS2781_YRAM5_END_REG TAS2781_YRAM3_END_REG |
52 | |
53 | #define TASDEVICE_MAXPROGRAM_NUM_KERNEL 5 |
54 | #define TASDEVICE_MAXCONFIG_NUM_KERNEL_MULTIPLE_AMPS 64 |
55 | #define TASDEVICE_MAXCONFIG_NUM_KERNEL 10 |
56 | #define MAIN_ALL_DEVICES_1X 0x01 |
57 | #define MAIN_DEVICE_A_1X 0x02 |
58 | #define MAIN_DEVICE_B_1X 0x03 |
59 | #define MAIN_DEVICE_C_1X 0x04 |
60 | #define MAIN_DEVICE_D_1X 0x05 |
61 | #define COEFF_DEVICE_A_1X 0x12 |
62 | #define COEFF_DEVICE_B_1X 0x13 |
63 | #define COEFF_DEVICE_C_1X 0x14 |
64 | #define COEFF_DEVICE_D_1X 0x15 |
65 | #define PRE_DEVICE_A_1X 0x22 |
66 | #define PRE_DEVICE_B_1X 0x23 |
67 | #define PRE_DEVICE_C_1X 0x24 |
68 | #define PRE_DEVICE_D_1X 0x25 |
69 | #define PRE_SOFTWARE_RESET_DEVICE_A 0x41 |
70 | #define PRE_SOFTWARE_RESET_DEVICE_B 0x42 |
71 | #define PRE_SOFTWARE_RESET_DEVICE_C 0x43 |
72 | #define PRE_SOFTWARE_RESET_DEVICE_D 0x44 |
73 | #define POST_SOFTWARE_RESET_DEVICE_A 0x45 |
74 | #define POST_SOFTWARE_RESET_DEVICE_B 0x46 |
75 | #define POST_SOFTWARE_RESET_DEVICE_C 0x47 |
76 | #define POST_SOFTWARE_RESET_DEVICE_D 0x48 |
77 | |
78 | struct tas_crc { |
79 | unsigned char offset; |
80 | unsigned char len; |
81 | }; |
82 | |
83 | struct blktyp_devidx_map { |
84 | unsigned char blktyp; |
85 | unsigned char dev_idx; |
86 | }; |
87 | |
88 | static const char deviceNumber[TASDEVICE_DSP_TAS_MAX_DEVICE] = { |
89 | 1, 2, 1, 2, 1, 1, 0, 2, 4, 3, 1, 2, 3, 4 |
90 | }; |
91 | |
92 | /* fixed m68k compiling issue: mapping table can save code field */ |
93 | static const struct blktyp_devidx_map ppc3_tas2781_mapping_table[] = { |
94 | { MAIN_ALL_DEVICES_1X, 0x80 }, |
95 | { MAIN_DEVICE_A_1X, 0x81 }, |
96 | { COEFF_DEVICE_A_1X, 0xC1 }, |
97 | { PRE_DEVICE_A_1X, 0xC1 }, |
98 | { PRE_SOFTWARE_RESET_DEVICE_A, 0xC1 }, |
99 | { POST_SOFTWARE_RESET_DEVICE_A, 0xC1 }, |
100 | { MAIN_DEVICE_B_1X, 0x82 }, |
101 | { COEFF_DEVICE_B_1X, 0xC2 }, |
102 | { PRE_DEVICE_B_1X, 0xC2 }, |
103 | { PRE_SOFTWARE_RESET_DEVICE_B, 0xC2 }, |
104 | { POST_SOFTWARE_RESET_DEVICE_B, 0xC2 }, |
105 | { MAIN_DEVICE_C_1X, 0x83 }, |
106 | { COEFF_DEVICE_C_1X, 0xC3 }, |
107 | { PRE_DEVICE_C_1X, 0xC3 }, |
108 | { PRE_SOFTWARE_RESET_DEVICE_C, 0xC3 }, |
109 | { POST_SOFTWARE_RESET_DEVICE_C, 0xC3 }, |
110 | { MAIN_DEVICE_D_1X, 0x84 }, |
111 | { COEFF_DEVICE_D_1X, 0xC4 }, |
112 | { PRE_DEVICE_D_1X, 0xC4 }, |
113 | { PRE_SOFTWARE_RESET_DEVICE_D, 0xC4 }, |
114 | { POST_SOFTWARE_RESET_DEVICE_D, 0xC4 }, |
115 | }; |
116 | |
117 | static const struct blktyp_devidx_map ppc3_mapping_table[] = { |
118 | { MAIN_ALL_DEVICES_1X, 0x80 }, |
119 | { MAIN_DEVICE_A_1X, 0x81 }, |
120 | { COEFF_DEVICE_A_1X, 0xC1 }, |
121 | { PRE_DEVICE_A_1X, 0xC1 }, |
122 | { MAIN_DEVICE_B_1X, 0x82 }, |
123 | { COEFF_DEVICE_B_1X, 0xC2 }, |
124 | { PRE_DEVICE_B_1X, 0xC2 }, |
125 | { MAIN_DEVICE_C_1X, 0x83 }, |
126 | { COEFF_DEVICE_C_1X, 0xC3 }, |
127 | { PRE_DEVICE_C_1X, 0xC3 }, |
128 | { MAIN_DEVICE_D_1X, 0x84 }, |
129 | { COEFF_DEVICE_D_1X, 0xC4 }, |
130 | { PRE_DEVICE_D_1X, 0xC4 }, |
131 | }; |
132 | |
133 | static const struct blktyp_devidx_map non_ppc3_mapping_table[] = { |
134 | { MAIN_ALL_DEVICES, 0x80 }, |
135 | { MAIN_DEVICE_A, 0x81 }, |
136 | { COEFF_DEVICE_A, 0xC1 }, |
137 | { PRE_DEVICE_A, 0xC1 }, |
138 | { MAIN_DEVICE_B, 0x82 }, |
139 | { COEFF_DEVICE_B, 0xC2 }, |
140 | { PRE_DEVICE_B, 0xC2 }, |
141 | { MAIN_DEVICE_C, 0x83 }, |
142 | { COEFF_DEVICE_C, 0xC3 }, |
143 | { PRE_DEVICE_C, 0xC3 }, |
144 | { MAIN_DEVICE_D, 0x84 }, |
145 | { COEFF_DEVICE_D, 0xC4 }, |
146 | { PRE_DEVICE_D, 0xC4 }, |
147 | }; |
148 | |
149 | static struct tasdevice_config_info *tasdevice_add_config( |
150 | struct tasdevice_priv *tas_priv, unsigned char *config_data, |
151 | unsigned int config_size, int *status) |
152 | { |
153 | struct tasdevice_config_info *cfg_info; |
154 | struct tasdev_blk_data **bk_da; |
155 | unsigned int config_offset = 0; |
156 | unsigned int i; |
157 | |
158 | /* In most projects are many audio cases, such as music, handfree, |
159 | * receiver, games, audio-to-haptics, PMIC record, bypass mode, |
160 | * portrait, landscape, etc. Even in multiple audios, one or |
161 | * two of the chips will work for the special case, such as |
162 | * ultrasonic application. In order to support these variable-numbers |
163 | * of audio cases, flexible configs have been introduced in the |
164 | * dsp firmware. |
165 | */ |
166 | cfg_info = kzalloc(size: sizeof(struct tasdevice_config_info), GFP_KERNEL); |
167 | if (!cfg_info) { |
168 | *status = -ENOMEM; |
169 | goto out; |
170 | } |
171 | |
172 | if (tas_priv->rcabin.fw_hdr.binary_version_num >= 0x105) { |
173 | if (config_offset + 64 > (int)config_size) { |
174 | *status = -EINVAL; |
175 | dev_err(tas_priv->dev, "add conf: Out of boundary\n" ); |
176 | goto out; |
177 | } |
178 | config_offset += 64; |
179 | } |
180 | |
181 | if (config_offset + 4 > (int)config_size) { |
182 | *status = -EINVAL; |
183 | dev_err(tas_priv->dev, "add config: Out of boundary\n" ); |
184 | goto out; |
185 | } |
186 | |
187 | /* convert data[offset], data[offset + 1], data[offset + 2] and |
188 | * data[offset + 3] into host |
189 | */ |
190 | cfg_info->nblocks = |
191 | be32_to_cpup(p: (__be32 *)&config_data[config_offset]); |
192 | config_offset += 4; |
193 | |
194 | /* Several kinds of dsp/algorithm firmwares can run on tas2781, |
195 | * the number and size of blk are not fixed and different among |
196 | * these firmwares. |
197 | */ |
198 | bk_da = cfg_info->blk_data = kcalloc(n: cfg_info->nblocks, |
199 | size: sizeof(struct tasdev_blk_data *), GFP_KERNEL); |
200 | if (!bk_da) { |
201 | *status = -ENOMEM; |
202 | goto out; |
203 | } |
204 | cfg_info->real_nblocks = 0; |
205 | for (i = 0; i < cfg_info->nblocks; i++) { |
206 | if (config_offset + 12 > config_size) { |
207 | *status = -EINVAL; |
208 | dev_err(tas_priv->dev, |
209 | "%s: Out of boundary: i = %d nblocks = %u!\n" , |
210 | __func__, i, cfg_info->nblocks); |
211 | break; |
212 | } |
213 | bk_da[i] = kzalloc(size: sizeof(struct tasdev_blk_data), GFP_KERNEL); |
214 | if (!bk_da[i]) { |
215 | *status = -ENOMEM; |
216 | break; |
217 | } |
218 | |
219 | bk_da[i]->dev_idx = config_data[config_offset]; |
220 | config_offset++; |
221 | |
222 | bk_da[i]->block_type = config_data[config_offset]; |
223 | config_offset++; |
224 | |
225 | if (bk_da[i]->block_type == TASDEVICE_BIN_BLK_PRE_POWER_UP) { |
226 | if (bk_da[i]->dev_idx == 0) |
227 | cfg_info->active_dev = |
228 | (1 << tas_priv->ndev) - 1; |
229 | else |
230 | cfg_info->active_dev |= 1 << |
231 | (bk_da[i]->dev_idx - 1); |
232 | |
233 | } |
234 | bk_da[i]->yram_checksum = |
235 | be16_to_cpup(p: (__be16 *)&config_data[config_offset]); |
236 | config_offset += 2; |
237 | bk_da[i]->block_size = |
238 | be32_to_cpup(p: (__be32 *)&config_data[config_offset]); |
239 | config_offset += 4; |
240 | |
241 | bk_da[i]->n_subblks = |
242 | be32_to_cpup(p: (__be32 *)&config_data[config_offset]); |
243 | |
244 | config_offset += 4; |
245 | |
246 | if (config_offset + bk_da[i]->block_size > config_size) { |
247 | *status = -EINVAL; |
248 | dev_err(tas_priv->dev, |
249 | "%s: Out of boundary: i = %d blks = %u!\n" , |
250 | __func__, i, cfg_info->nblocks); |
251 | break; |
252 | } |
253 | /* instead of kzalloc+memcpy */ |
254 | bk_da[i]->regdata = kmemdup(p: &config_data[config_offset], |
255 | size: bk_da[i]->block_size, GFP_KERNEL); |
256 | if (!bk_da[i]->regdata) { |
257 | *status = -ENOMEM; |
258 | goto out; |
259 | } |
260 | |
261 | config_offset += bk_da[i]->block_size; |
262 | cfg_info->real_nblocks += 1; |
263 | } |
264 | |
265 | out: |
266 | return cfg_info; |
267 | } |
268 | |
269 | int tasdevice_rca_parser(void *context, const struct firmware *fmw) |
270 | { |
271 | struct tasdevice_priv *tas_priv = context; |
272 | struct tasdevice_config_info **cfg_info; |
273 | struct tasdevice_rca_hdr *fw_hdr; |
274 | struct tasdevice_rca *rca; |
275 | unsigned int total_config_sz = 0; |
276 | unsigned char *buf; |
277 | int offset = 0; |
278 | int ret = 0; |
279 | int i; |
280 | |
281 | rca = &(tas_priv->rcabin); |
282 | fw_hdr = &(rca->fw_hdr); |
283 | if (!fmw || !fmw->data) { |
284 | dev_err(tas_priv->dev, "Failed to read %s\n" , |
285 | tas_priv->rca_binaryname); |
286 | tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL; |
287 | ret = -EINVAL; |
288 | goto out; |
289 | } |
290 | buf = (unsigned char *)fmw->data; |
291 | |
292 | fw_hdr->img_sz = be32_to_cpup(p: (__be32 *)&buf[offset]); |
293 | offset += 4; |
294 | if (fw_hdr->img_sz != fmw->size) { |
295 | dev_err(tas_priv->dev, |
296 | "File size not match, %d %u" , (int)fmw->size, |
297 | fw_hdr->img_sz); |
298 | tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL; |
299 | ret = -EINVAL; |
300 | goto out; |
301 | } |
302 | |
303 | fw_hdr->checksum = be32_to_cpup(p: (__be32 *)&buf[offset]); |
304 | offset += 4; |
305 | fw_hdr->binary_version_num = be32_to_cpup(p: (__be32 *)&buf[offset]); |
306 | if (fw_hdr->binary_version_num < 0x103) { |
307 | dev_err(tas_priv->dev, "File version 0x%04x is too low" , |
308 | fw_hdr->binary_version_num); |
309 | tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL; |
310 | ret = -EINVAL; |
311 | goto out; |
312 | } |
313 | offset += 4; |
314 | fw_hdr->drv_fw_version = be32_to_cpup(p: (__be32 *)&buf[offset]); |
315 | offset += 8; |
316 | fw_hdr->plat_type = buf[offset]; |
317 | offset += 1; |
318 | fw_hdr->dev_family = buf[offset]; |
319 | offset += 1; |
320 | fw_hdr->reserve = buf[offset]; |
321 | offset += 1; |
322 | fw_hdr->ndev = buf[offset]; |
323 | offset += 1; |
324 | if (fw_hdr->ndev != tas_priv->ndev) { |
325 | dev_err(tas_priv->dev, |
326 | "ndev(%u) in rcabin mismatch ndev(%u) in DTS\n" , |
327 | fw_hdr->ndev, tas_priv->ndev); |
328 | tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL; |
329 | ret = -EINVAL; |
330 | goto out; |
331 | } |
332 | if (offset + TASDEVICE_DEVICE_SUM > fw_hdr->img_sz) { |
333 | dev_err(tas_priv->dev, "rca_ready: Out of boundary!\n" ); |
334 | ret = -EINVAL; |
335 | tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL; |
336 | goto out; |
337 | } |
338 | |
339 | for (i = 0; i < TASDEVICE_DEVICE_SUM; i++, offset++) |
340 | fw_hdr->devs[i] = buf[offset]; |
341 | |
342 | fw_hdr->nconfig = be32_to_cpup(p: (__be32 *)&buf[offset]); |
343 | offset += 4; |
344 | |
345 | for (i = 0; i < TASDEVICE_CONFIG_SUM; i++) { |
346 | fw_hdr->config_size[i] = be32_to_cpup(p: (__be32 *)&buf[offset]); |
347 | offset += 4; |
348 | total_config_sz += fw_hdr->config_size[i]; |
349 | } |
350 | |
351 | if (fw_hdr->img_sz - total_config_sz != (unsigned int)offset) { |
352 | dev_err(tas_priv->dev, "Bin file error!\n" ); |
353 | ret = -EINVAL; |
354 | tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL; |
355 | goto out; |
356 | } |
357 | |
358 | cfg_info = kcalloc(n: fw_hdr->nconfig, size: sizeof(*cfg_info), GFP_KERNEL); |
359 | if (!cfg_info) { |
360 | ret = -ENOMEM; |
361 | tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL; |
362 | goto out; |
363 | } |
364 | rca->cfg_info = cfg_info; |
365 | rca->ncfgs = 0; |
366 | for (i = 0; i < (int)fw_hdr->nconfig; i++) { |
367 | rca->ncfgs += 1; |
368 | cfg_info[i] = tasdevice_add_config(tas_priv, config_data: &buf[offset], |
369 | config_size: fw_hdr->config_size[i], status: &ret); |
370 | if (ret) { |
371 | tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL; |
372 | goto out; |
373 | } |
374 | offset += (int)fw_hdr->config_size[i]; |
375 | } |
376 | out: |
377 | return ret; |
378 | } |
379 | EXPORT_SYMBOL_NS_GPL(tasdevice_rca_parser, SND_SOC_TAS2781_FMWLIB); |
380 | |
381 | /* fixed m68k compiling issue: mapping table can save code field */ |
382 | static unsigned char map_dev_idx(struct tasdevice_fw *tas_fmw, |
383 | struct tasdev_blk *block) |
384 | { |
385 | |
386 | struct blktyp_devidx_map *p = |
387 | (struct blktyp_devidx_map *)non_ppc3_mapping_table; |
388 | struct tasdevice_dspfw_hdr *fw_hdr = &(tas_fmw->fw_hdr); |
389 | struct tasdevice_fw_fixed_hdr *fw_fixed_hdr = &(fw_hdr->fixed_hdr); |
390 | |
391 | int i, n = ARRAY_SIZE(non_ppc3_mapping_table); |
392 | unsigned char dev_idx = 0; |
393 | |
394 | if (fw_fixed_hdr->ppcver >= PPC3_VERSION_TAS2781) { |
395 | p = (struct blktyp_devidx_map *)ppc3_tas2781_mapping_table; |
396 | n = ARRAY_SIZE(ppc3_tas2781_mapping_table); |
397 | } else if (fw_fixed_hdr->ppcver >= PPC3_VERSION) { |
398 | p = (struct blktyp_devidx_map *)ppc3_mapping_table; |
399 | n = ARRAY_SIZE(ppc3_mapping_table); |
400 | } |
401 | |
402 | for (i = 0; i < n; i++) { |
403 | if (block->type == p[i].blktyp) { |
404 | dev_idx = p[i].dev_idx; |
405 | break; |
406 | } |
407 | } |
408 | |
409 | return dev_idx; |
410 | } |
411 | |
412 | static int fw_parse_block_data_kernel(struct tasdevice_fw *tas_fmw, |
413 | struct tasdev_blk *block, const struct firmware *fmw, int offset) |
414 | { |
415 | const unsigned char *data = fmw->data; |
416 | |
417 | if (offset + 16 > fmw->size) { |
418 | dev_err(tas_fmw->dev, "%s: File Size error\n" , __func__); |
419 | offset = -EINVAL; |
420 | goto out; |
421 | } |
422 | |
423 | /* convert data[offset], data[offset + 1], data[offset + 2] and |
424 | * data[offset + 3] into host |
425 | */ |
426 | block->type = be32_to_cpup(p: (__be32 *)&data[offset]); |
427 | offset += 4; |
428 | |
429 | block->is_pchksum_present = data[offset]; |
430 | offset++; |
431 | |
432 | block->pchksum = data[offset]; |
433 | offset++; |
434 | |
435 | block->is_ychksum_present = data[offset]; |
436 | offset++; |
437 | |
438 | block->ychksum = data[offset]; |
439 | offset++; |
440 | |
441 | block->blk_size = be32_to_cpup(p: (__be32 *)&data[offset]); |
442 | offset += 4; |
443 | |
444 | block->nr_subblocks = be32_to_cpup(p: (__be32 *)&data[offset]); |
445 | offset += 4; |
446 | |
447 | /* fixed m68k compiling issue: |
448 | * 1. mapping table can save code field. |
449 | * 2. storing the dev_idx as a member of block can reduce unnecessary |
450 | * time and system resource comsumption of dev_idx mapping every |
451 | * time the block data writing to the dsp. |
452 | */ |
453 | block->dev_idx = map_dev_idx(tas_fmw, block); |
454 | |
455 | if (offset + block->blk_size > fmw->size) { |
456 | dev_err(tas_fmw->dev, "%s: nSublocks error\n" , __func__); |
457 | offset = -EINVAL; |
458 | goto out; |
459 | } |
460 | /* instead of kzalloc+memcpy */ |
461 | block->data = kmemdup(p: &data[offset], size: block->blk_size, GFP_KERNEL); |
462 | if (!block->data) { |
463 | offset = -ENOMEM; |
464 | goto out; |
465 | } |
466 | offset += block->blk_size; |
467 | |
468 | out: |
469 | return offset; |
470 | } |
471 | |
472 | static int fw_parse_data_kernel(struct tasdevice_fw *tas_fmw, |
473 | struct tasdevice_data *img_data, const struct firmware *fmw, |
474 | int offset) |
475 | { |
476 | const unsigned char *data = fmw->data; |
477 | struct tasdev_blk *blk; |
478 | unsigned int i; |
479 | |
480 | if (offset + 4 > fmw->size) { |
481 | dev_err(tas_fmw->dev, "%s: File Size error\n" , __func__); |
482 | offset = -EINVAL; |
483 | goto out; |
484 | } |
485 | img_data->nr_blk = be32_to_cpup(p: (__be32 *)&data[offset]); |
486 | offset += 4; |
487 | |
488 | img_data->dev_blks = kcalloc(n: img_data->nr_blk, |
489 | size: sizeof(struct tasdev_blk), GFP_KERNEL); |
490 | if (!img_data->dev_blks) { |
491 | offset = -ENOMEM; |
492 | goto out; |
493 | } |
494 | |
495 | for (i = 0; i < img_data->nr_blk; i++) { |
496 | blk = &(img_data->dev_blks[i]); |
497 | offset = fw_parse_block_data_kernel(tas_fmw, block: blk, fmw, offset); |
498 | if (offset < 0) { |
499 | offset = -EINVAL; |
500 | break; |
501 | } |
502 | } |
503 | |
504 | out: |
505 | return offset; |
506 | } |
507 | |
508 | static int fw_parse_program_data_kernel( |
509 | struct tasdevice_priv *tas_priv, struct tasdevice_fw *tas_fmw, |
510 | const struct firmware *fmw, int offset) |
511 | { |
512 | struct tasdevice_prog *program; |
513 | unsigned int i; |
514 | |
515 | for (i = 0; i < tas_fmw->nr_programs; i++) { |
516 | program = &(tas_fmw->programs[i]); |
517 | if (offset + 72 > fmw->size) { |
518 | dev_err(tas_priv->dev, "%s: mpName error\n" , __func__); |
519 | offset = -EINVAL; |
520 | goto out; |
521 | } |
522 | /*skip 72 unused byts*/ |
523 | offset += 72; |
524 | |
525 | offset = fw_parse_data_kernel(tas_fmw, img_data: &(program->dev_data), |
526 | fmw, offset); |
527 | if (offset < 0) |
528 | goto out; |
529 | } |
530 | |
531 | out: |
532 | return offset; |
533 | } |
534 | |
535 | static int fw_parse_configuration_data_kernel( |
536 | struct tasdevice_priv *tas_priv, |
537 | struct tasdevice_fw *tas_fmw, const struct firmware *fmw, int offset) |
538 | { |
539 | const unsigned char *data = fmw->data; |
540 | struct tasdevice_config *config; |
541 | unsigned int i; |
542 | |
543 | for (i = 0; i < tas_fmw->nr_configurations; i++) { |
544 | config = &(tas_fmw->configs[i]); |
545 | if (offset + 80 > fmw->size) { |
546 | dev_err(tas_priv->dev, "%s: mpName error\n" , __func__); |
547 | offset = -EINVAL; |
548 | goto out; |
549 | } |
550 | memcpy(config->name, &data[offset], 64); |
551 | /*skip extra 16 bytes*/ |
552 | offset += 80; |
553 | |
554 | offset = fw_parse_data_kernel(tas_fmw, img_data: &(config->dev_data), |
555 | fmw, offset); |
556 | if (offset < 0) |
557 | goto out; |
558 | } |
559 | |
560 | out: |
561 | return offset; |
562 | } |
563 | |
564 | static int ( |
565 | struct tasdevice_priv *tas_priv, const struct firmware *fmw, |
566 | int offset) |
567 | { |
568 | struct tasdevice_fw *tas_fmw = tas_priv->fmw; |
569 | struct tasdevice_dspfw_hdr *fw_hdr = &(tas_fmw->fw_hdr); |
570 | struct tasdevice_prog *program; |
571 | struct tasdevice_config *config; |
572 | const unsigned char *buf = fmw->data; |
573 | unsigned short max_confs; |
574 | unsigned int i; |
575 | |
576 | if (offset + 12 + 4 * TASDEVICE_MAXPROGRAM_NUM_KERNEL > fmw->size) { |
577 | dev_err(tas_priv->dev, "%s: File Size error\n" , __func__); |
578 | offset = -EINVAL; |
579 | goto out; |
580 | } |
581 | fw_hdr->device_family = be16_to_cpup(p: (__be16 *)&buf[offset]); |
582 | if (fw_hdr->device_family != 0) { |
583 | dev_err(tas_priv->dev, "%s:not TAS device\n" , __func__); |
584 | offset = -EINVAL; |
585 | goto out; |
586 | } |
587 | offset += 2; |
588 | fw_hdr->device = be16_to_cpup(p: (__be16 *)&buf[offset]); |
589 | if (fw_hdr->device >= TASDEVICE_DSP_TAS_MAX_DEVICE || |
590 | fw_hdr->device == 6) { |
591 | dev_err(tas_priv->dev, "Unsupported dev %d\n" , fw_hdr->device); |
592 | offset = -EINVAL; |
593 | goto out; |
594 | } |
595 | offset += 2; |
596 | fw_hdr->ndev = deviceNumber[fw_hdr->device]; |
597 | |
598 | if (fw_hdr->ndev != tas_priv->ndev) { |
599 | dev_err(tas_priv->dev, |
600 | "%s: ndev(%u) in dspbin mismatch ndev(%u) in DTS\n" , |
601 | __func__, fw_hdr->ndev, tas_priv->ndev); |
602 | offset = -EINVAL; |
603 | goto out; |
604 | } |
605 | |
606 | tas_fmw->nr_programs = be32_to_cpup(p: (__be32 *)&buf[offset]); |
607 | offset += 4; |
608 | |
609 | if (tas_fmw->nr_programs == 0 || tas_fmw->nr_programs > |
610 | TASDEVICE_MAXPROGRAM_NUM_KERNEL) { |
611 | dev_err(tas_priv->dev, "mnPrograms is invalid\n" ); |
612 | offset = -EINVAL; |
613 | goto out; |
614 | } |
615 | |
616 | tas_fmw->programs = kcalloc(n: tas_fmw->nr_programs, |
617 | size: sizeof(struct tasdevice_prog), GFP_KERNEL); |
618 | if (!tas_fmw->programs) { |
619 | offset = -ENOMEM; |
620 | goto out; |
621 | } |
622 | |
623 | for (i = 0; i < tas_fmw->nr_programs; i++) { |
624 | program = &(tas_fmw->programs[i]); |
625 | program->prog_size = be32_to_cpup(p: (__be32 *)&buf[offset]); |
626 | offset += 4; |
627 | } |
628 | |
629 | /* Skip the unused prog_size */ |
630 | offset += 4 * (TASDEVICE_MAXPROGRAM_NUM_KERNEL - tas_fmw->nr_programs); |
631 | |
632 | tas_fmw->nr_configurations = be32_to_cpup(p: (__be32 *)&buf[offset]); |
633 | offset += 4; |
634 | |
635 | /* The max number of config in firmware greater than 4 pieces of |
636 | * tas2781s is different from the one lower than 4 pieces of |
637 | * tas2781s. |
638 | */ |
639 | max_confs = (fw_hdr->ndev >= 4) ? |
640 | TASDEVICE_MAXCONFIG_NUM_KERNEL_MULTIPLE_AMPS : |
641 | TASDEVICE_MAXCONFIG_NUM_KERNEL; |
642 | if (tas_fmw->nr_configurations == 0 || |
643 | tas_fmw->nr_configurations > max_confs) { |
644 | dev_err(tas_priv->dev, "%s: Conf is invalid\n" , __func__); |
645 | offset = -EINVAL; |
646 | goto out; |
647 | } |
648 | |
649 | if (offset + 4 * max_confs > fmw->size) { |
650 | dev_err(tas_priv->dev, "%s: mpConfigurations err\n" , __func__); |
651 | offset = -EINVAL; |
652 | goto out; |
653 | } |
654 | |
655 | tas_fmw->configs = kcalloc(n: tas_fmw->nr_configurations, |
656 | size: sizeof(struct tasdevice_config), GFP_KERNEL); |
657 | if (!tas_fmw->configs) { |
658 | offset = -ENOMEM; |
659 | goto out; |
660 | } |
661 | |
662 | for (i = 0; i < tas_fmw->nr_programs; i++) { |
663 | config = &(tas_fmw->configs[i]); |
664 | config->cfg_size = be32_to_cpup(p: (__be32 *)&buf[offset]); |
665 | offset += 4; |
666 | } |
667 | |
668 | /* Skip the unused configs */ |
669 | offset += 4 * (max_confs - tas_fmw->nr_programs); |
670 | |
671 | out: |
672 | return offset; |
673 | } |
674 | |
675 | static int tasdevice_process_block(void *context, unsigned char *data, |
676 | unsigned char dev_idx, int sublocksize) |
677 | { |
678 | struct tasdevice_priv *tas_priv = (struct tasdevice_priv *)context; |
679 | int subblk_offset, chn, chnend, rc; |
680 | unsigned char subblk_typ = data[1]; |
681 | int blktyp = dev_idx & 0xC0; |
682 | int idx = dev_idx & 0x3F; |
683 | bool is_err = false; |
684 | |
685 | if (idx) { |
686 | chn = idx - 1; |
687 | chnend = idx; |
688 | } else { |
689 | chn = 0; |
690 | chnend = tas_priv->ndev; |
691 | } |
692 | |
693 | for (; chn < chnend; chn++) { |
694 | if (tas_priv->tasdevice[chn].is_loading == false) |
695 | continue; |
696 | |
697 | is_err = false; |
698 | subblk_offset = 2; |
699 | switch (subblk_typ) { |
700 | case TASDEVICE_CMD_SING_W: { |
701 | int i; |
702 | unsigned short len = be16_to_cpup(p: (__be16 *)&data[2]); |
703 | |
704 | subblk_offset += 2; |
705 | if (subblk_offset + 4 * len > sublocksize) { |
706 | dev_err(tas_priv->dev, |
707 | "process_block: Out of boundary\n" ); |
708 | is_err = true; |
709 | break; |
710 | } |
711 | |
712 | for (i = 0; i < len; i++) { |
713 | rc = tasdevice_dev_write(tas_priv, chn, |
714 | TASDEVICE_REG(data[subblk_offset], |
715 | data[subblk_offset + 1], |
716 | data[subblk_offset + 2]), |
717 | value: data[subblk_offset + 3]); |
718 | if (rc < 0) { |
719 | is_err = true; |
720 | dev_err(tas_priv->dev, |
721 | "process_block: single write error\n" ); |
722 | } |
723 | subblk_offset += 4; |
724 | } |
725 | } |
726 | break; |
727 | case TASDEVICE_CMD_BURST: { |
728 | unsigned short len = be16_to_cpup(p: (__be16 *)&data[2]); |
729 | |
730 | subblk_offset += 2; |
731 | if (subblk_offset + 4 + len > sublocksize) { |
732 | dev_err(tas_priv->dev, |
733 | "%s: BST Out of boundary\n" , |
734 | __func__); |
735 | is_err = true; |
736 | break; |
737 | } |
738 | if (len % 4) { |
739 | dev_err(tas_priv->dev, |
740 | "%s:Bst-len(%u)not div by 4\n" , |
741 | __func__, len); |
742 | break; |
743 | } |
744 | |
745 | rc = tasdevice_dev_bulk_write(tas_priv, chn, |
746 | TASDEVICE_REG(data[subblk_offset], |
747 | data[subblk_offset + 1], |
748 | data[subblk_offset + 2]), |
749 | p_data: &(data[subblk_offset + 4]), n_length: len); |
750 | if (rc < 0) { |
751 | is_err = true; |
752 | dev_err(tas_priv->dev, |
753 | "%s: bulk_write error = %d\n" , |
754 | __func__, rc); |
755 | } |
756 | subblk_offset += (len + 4); |
757 | } |
758 | break; |
759 | case TASDEVICE_CMD_DELAY: { |
760 | unsigned int sleep_time = 0; |
761 | |
762 | if (subblk_offset + 2 > sublocksize) { |
763 | dev_err(tas_priv->dev, |
764 | "%s: delay Out of boundary\n" , |
765 | __func__); |
766 | is_err = true; |
767 | break; |
768 | } |
769 | sleep_time = be16_to_cpup(p: (__be16 *)&data[2]) * 1000; |
770 | usleep_range(min: sleep_time, max: sleep_time + 50); |
771 | subblk_offset += 2; |
772 | } |
773 | break; |
774 | case TASDEVICE_CMD_FIELD_W: |
775 | if (subblk_offset + 6 > sublocksize) { |
776 | dev_err(tas_priv->dev, |
777 | "%s: bit write Out of boundary\n" , |
778 | __func__); |
779 | is_err = true; |
780 | break; |
781 | } |
782 | rc = tasdevice_dev_update_bits(tasdevice: tas_priv, chn, |
783 | TASDEVICE_REG(data[subblk_offset + 2], |
784 | data[subblk_offset + 3], |
785 | data[subblk_offset + 4]), |
786 | mask: data[subblk_offset + 1], |
787 | value: data[subblk_offset + 5]); |
788 | if (rc < 0) { |
789 | is_err = true; |
790 | dev_err(tas_priv->dev, |
791 | "%s: update_bits error = %d\n" , |
792 | __func__, rc); |
793 | } |
794 | subblk_offset += 6; |
795 | break; |
796 | default: |
797 | break; |
798 | } |
799 | if (is_err == true && blktyp != 0) { |
800 | if (blktyp == 0x80) { |
801 | tas_priv->tasdevice[chn].cur_prog = -1; |
802 | tas_priv->tasdevice[chn].cur_conf = -1; |
803 | } else |
804 | tas_priv->tasdevice[chn].cur_conf = -1; |
805 | } |
806 | } |
807 | |
808 | return subblk_offset; |
809 | } |
810 | |
811 | void tasdevice_select_cfg_blk(void *pContext, int conf_no, |
812 | unsigned char block_type) |
813 | { |
814 | struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) pContext; |
815 | struct tasdevice_rca *rca = &(tas_priv->rcabin); |
816 | struct tasdevice_config_info **cfg_info = rca->cfg_info; |
817 | struct tasdev_blk_data **blk_data; |
818 | int j, k, chn, chnend; |
819 | |
820 | if (conf_no >= rca->ncfgs || conf_no < 0 || !cfg_info) { |
821 | dev_err(tas_priv->dev, "conf_no should be not more than %u\n" , |
822 | rca->ncfgs); |
823 | return; |
824 | } |
825 | blk_data = cfg_info[conf_no]->blk_data; |
826 | |
827 | for (j = 0; j < (int)cfg_info[conf_no]->real_nblocks; j++) { |
828 | unsigned int length = 0, rc = 0; |
829 | |
830 | if (block_type > 5 || block_type < 2) { |
831 | dev_err(tas_priv->dev, |
832 | "block_type should be in range from 2 to 5\n" ); |
833 | break; |
834 | } |
835 | if (block_type != blk_data[j]->block_type) |
836 | continue; |
837 | |
838 | for (k = 0; k < (int)blk_data[j]->n_subblks; k++) { |
839 | if (blk_data[j]->dev_idx) { |
840 | chn = blk_data[j]->dev_idx - 1; |
841 | chnend = blk_data[j]->dev_idx; |
842 | } else { |
843 | chn = 0; |
844 | chnend = tas_priv->ndev; |
845 | } |
846 | for (; chn < chnend; chn++) |
847 | tas_priv->tasdevice[chn].is_loading = true; |
848 | |
849 | rc = tasdevice_process_block(context: tas_priv, |
850 | data: blk_data[j]->regdata + length, |
851 | dev_idx: blk_data[j]->dev_idx, |
852 | sublocksize: blk_data[j]->block_size - length); |
853 | length += rc; |
854 | if (blk_data[j]->block_size < length) { |
855 | dev_err(tas_priv->dev, |
856 | "%s: %u %u out of boundary\n" , |
857 | __func__, length, |
858 | blk_data[j]->block_size); |
859 | break; |
860 | } |
861 | } |
862 | if (length != blk_data[j]->block_size) |
863 | dev_err(tas_priv->dev, "%s: %u %u size is not same\n" , |
864 | __func__, length, blk_data[j]->block_size); |
865 | } |
866 | } |
867 | EXPORT_SYMBOL_NS_GPL(tasdevice_select_cfg_blk, SND_SOC_TAS2781_FMWLIB); |
868 | |
869 | static int tasdevice_load_block_kernel( |
870 | struct tasdevice_priv *tasdevice, struct tasdev_blk *block) |
871 | { |
872 | const unsigned int blk_size = block->blk_size; |
873 | unsigned int i, length; |
874 | unsigned char *data = block->data; |
875 | |
876 | for (i = 0, length = 0; i < block->nr_subblocks; i++) { |
877 | int rc = tasdevice_process_block(context: tasdevice, data: data + length, |
878 | dev_idx: block->dev_idx, sublocksize: blk_size - length); |
879 | if (rc < 0) { |
880 | dev_err(tasdevice->dev, |
881 | "%s: %u %u sublock write error\n" , |
882 | __func__, length, blk_size); |
883 | break; |
884 | } |
885 | length += (unsigned int)rc; |
886 | if (blk_size < length) { |
887 | dev_err(tasdevice->dev, "%s: %u %u out of boundary\n" , |
888 | __func__, length, blk_size); |
889 | break; |
890 | } |
891 | } |
892 | |
893 | return 0; |
894 | } |
895 | |
896 | static int fw_parse_variable_hdr(struct tasdevice_priv |
897 | *tas_priv, struct tasdevice_dspfw_hdr *fw_hdr, |
898 | const struct firmware *fmw, int offset) |
899 | { |
900 | const unsigned char *buf = fmw->data; |
901 | int len = strlen((char *)&buf[offset]); |
902 | |
903 | len++; |
904 | |
905 | if (offset + len + 8 > fmw->size) { |
906 | dev_err(tas_priv->dev, "%s: File Size error\n" , __func__); |
907 | offset = -EINVAL; |
908 | goto out; |
909 | } |
910 | |
911 | offset += len; |
912 | |
913 | fw_hdr->device_family = be32_to_cpup(p: (__be32 *)&buf[offset]); |
914 | if (fw_hdr->device_family != 0) { |
915 | dev_err(tas_priv->dev, "%s: not TAS device\n" , __func__); |
916 | offset = -EINVAL; |
917 | goto out; |
918 | } |
919 | offset += 4; |
920 | |
921 | fw_hdr->device = be32_to_cpup(p: (__be32 *)&buf[offset]); |
922 | if (fw_hdr->device >= TASDEVICE_DSP_TAS_MAX_DEVICE || |
923 | fw_hdr->device == 6) { |
924 | dev_err(tas_priv->dev, "Unsupported dev %d\n" , fw_hdr->device); |
925 | offset = -EINVAL; |
926 | goto out; |
927 | } |
928 | offset += 4; |
929 | fw_hdr->ndev = deviceNumber[fw_hdr->device]; |
930 | |
931 | out: |
932 | return offset; |
933 | } |
934 | |
935 | static int (struct tasdevice_priv |
936 | *tas_priv, const struct firmware *fmw, int offset) |
937 | { |
938 | struct tasdevice_fw *tas_fmw = tas_priv->fmw; |
939 | struct tasdevice_dspfw_hdr *fw_hdr = &(tas_fmw->fw_hdr); |
940 | |
941 | offset = fw_parse_variable_hdr(tas_priv, fw_hdr, fmw, offset); |
942 | if (offset < 0) |
943 | goto out; |
944 | if (fw_hdr->ndev != tas_priv->ndev) { |
945 | dev_err(tas_priv->dev, |
946 | "%s: ndev(%u) in dspbin mismatch ndev(%u) in DTS\n" , |
947 | __func__, fw_hdr->ndev, tas_priv->ndev); |
948 | offset = -EINVAL; |
949 | } |
950 | |
951 | out: |
952 | return offset; |
953 | } |
954 | |
955 | static int fw_parse_block_data(struct tasdevice_fw *tas_fmw, |
956 | struct tasdev_blk *block, const struct firmware *fmw, int offset) |
957 | { |
958 | unsigned char *data = (unsigned char *)fmw->data; |
959 | int n; |
960 | |
961 | if (offset + 8 > fmw->size) { |
962 | dev_err(tas_fmw->dev, "%s: Type error\n" , __func__); |
963 | offset = -EINVAL; |
964 | goto out; |
965 | } |
966 | block->type = be32_to_cpup(p: (__be32 *)&data[offset]); |
967 | offset += 4; |
968 | |
969 | if (tas_fmw->fw_hdr.fixed_hdr.drv_ver >= PPC_DRIVER_CRCCHK) { |
970 | if (offset + 8 > fmw->size) { |
971 | dev_err(tas_fmw->dev, "PChkSumPresent error\n" ); |
972 | offset = -EINVAL; |
973 | goto out; |
974 | } |
975 | block->is_pchksum_present = data[offset]; |
976 | offset++; |
977 | |
978 | block->pchksum = data[offset]; |
979 | offset++; |
980 | |
981 | block->is_ychksum_present = data[offset]; |
982 | offset++; |
983 | |
984 | block->ychksum = data[offset]; |
985 | offset++; |
986 | } else { |
987 | block->is_pchksum_present = 0; |
988 | block->is_ychksum_present = 0; |
989 | } |
990 | |
991 | block->nr_cmds = be32_to_cpup(p: (__be32 *)&data[offset]); |
992 | offset += 4; |
993 | |
994 | n = block->nr_cmds * 4; |
995 | if (offset + n > fmw->size) { |
996 | dev_err(tas_fmw->dev, |
997 | "%s: File Size(%lu) error offset = %d n = %d\n" , |
998 | __func__, (unsigned long)fmw->size, offset, n); |
999 | offset = -EINVAL; |
1000 | goto out; |
1001 | } |
1002 | /* instead of kzalloc+memcpy */ |
1003 | block->data = kmemdup(p: &data[offset], size: n, GFP_KERNEL); |
1004 | if (!block->data) { |
1005 | offset = -ENOMEM; |
1006 | goto out; |
1007 | } |
1008 | offset += n; |
1009 | |
1010 | out: |
1011 | return offset; |
1012 | } |
1013 | |
1014 | /* When parsing error occurs, all the memory resource will be released |
1015 | * in the end of tasdevice_rca_ready. |
1016 | */ |
1017 | static int fw_parse_data(struct tasdevice_fw *tas_fmw, |
1018 | struct tasdevice_data *img_data, const struct firmware *fmw, |
1019 | int offset) |
1020 | { |
1021 | const unsigned char *data = (unsigned char *)fmw->data; |
1022 | struct tasdev_blk *blk; |
1023 | unsigned int i; |
1024 | int n; |
1025 | |
1026 | if (offset + 64 > fmw->size) { |
1027 | dev_err(tas_fmw->dev, "%s: Name error\n" , __func__); |
1028 | offset = -EINVAL; |
1029 | goto out; |
1030 | } |
1031 | memcpy(img_data->name, &data[offset], 64); |
1032 | offset += 64; |
1033 | |
1034 | n = strlen((char *)&data[offset]); |
1035 | n++; |
1036 | if (offset + n + 2 > fmw->size) { |
1037 | dev_err(tas_fmw->dev, "%s: Description error\n" , __func__); |
1038 | offset = -EINVAL; |
1039 | goto out; |
1040 | } |
1041 | offset += n; |
1042 | img_data->nr_blk = be16_to_cpup(p: (__be16 *)&data[offset]); |
1043 | offset += 2; |
1044 | |
1045 | img_data->dev_blks = kcalloc(n: img_data->nr_blk, |
1046 | size: sizeof(struct tasdev_blk), GFP_KERNEL); |
1047 | if (!img_data->dev_blks) { |
1048 | offset = -ENOMEM; |
1049 | goto out; |
1050 | } |
1051 | for (i = 0; i < img_data->nr_blk; i++) { |
1052 | blk = &(img_data->dev_blks[i]); |
1053 | offset = fw_parse_block_data(tas_fmw, block: blk, fmw, offset); |
1054 | if (offset < 0) { |
1055 | offset = -EINVAL; |
1056 | goto out; |
1057 | } |
1058 | } |
1059 | |
1060 | out: |
1061 | return offset; |
1062 | } |
1063 | |
1064 | /* When parsing error occurs, all the memory resource will be released |
1065 | * in the end of tasdevice_rca_ready. |
1066 | */ |
1067 | static int fw_parse_program_data(struct tasdevice_priv *tas_priv, |
1068 | struct tasdevice_fw *tas_fmw, const struct firmware *fmw, int offset) |
1069 | { |
1070 | unsigned char *buf = (unsigned char *)fmw->data; |
1071 | struct tasdevice_prog *program; |
1072 | int i; |
1073 | |
1074 | if (offset + 2 > fmw->size) { |
1075 | dev_err(tas_priv->dev, "%s: File Size error\n" , __func__); |
1076 | offset = -EINVAL; |
1077 | goto out; |
1078 | } |
1079 | tas_fmw->nr_programs = be16_to_cpup(p: (__be16 *)&buf[offset]); |
1080 | offset += 2; |
1081 | |
1082 | if (tas_fmw->nr_programs == 0) { |
1083 | /*Not error in calibration Data file, return directly*/ |
1084 | dev_info(tas_priv->dev, "%s: No Programs data, maybe calbin\n" , |
1085 | __func__); |
1086 | goto out; |
1087 | } |
1088 | |
1089 | tas_fmw->programs = |
1090 | kcalloc(n: tas_fmw->nr_programs, size: sizeof(struct tasdevice_prog), |
1091 | GFP_KERNEL); |
1092 | if (!tas_fmw->programs) { |
1093 | offset = -ENOMEM; |
1094 | goto out; |
1095 | } |
1096 | for (i = 0; i < tas_fmw->nr_programs; i++) { |
1097 | int n = 0; |
1098 | |
1099 | program = &(tas_fmw->programs[i]); |
1100 | if (offset + 64 > fmw->size) { |
1101 | dev_err(tas_priv->dev, "%s: mpName error\n" , __func__); |
1102 | offset = -EINVAL; |
1103 | goto out; |
1104 | } |
1105 | offset += 64; |
1106 | |
1107 | n = strlen((char *)&buf[offset]); |
1108 | /* skip '\0' and 5 unused bytes */ |
1109 | n += 6; |
1110 | if (offset + n > fmw->size) { |
1111 | dev_err(tas_priv->dev, "Description err\n" ); |
1112 | offset = -EINVAL; |
1113 | goto out; |
1114 | } |
1115 | |
1116 | offset += n; |
1117 | |
1118 | offset = fw_parse_data(tas_fmw, img_data: &(program->dev_data), fmw, |
1119 | offset); |
1120 | if (offset < 0) |
1121 | goto out; |
1122 | } |
1123 | |
1124 | out: |
1125 | return offset; |
1126 | } |
1127 | |
1128 | /* When parsing error occurs, all the memory resource will be released |
1129 | * in the end of tasdevice_rca_ready. |
1130 | */ |
1131 | static int fw_parse_configuration_data( |
1132 | struct tasdevice_priv *tas_priv, |
1133 | struct tasdevice_fw *tas_fmw, |
1134 | const struct firmware *fmw, int offset) |
1135 | { |
1136 | unsigned char *data = (unsigned char *)fmw->data; |
1137 | struct tasdevice_config *config; |
1138 | unsigned int i; |
1139 | int n; |
1140 | |
1141 | if (offset + 2 > fmw->size) { |
1142 | dev_err(tas_priv->dev, "%s: File Size error\n" , __func__); |
1143 | offset = -EINVAL; |
1144 | goto out; |
1145 | } |
1146 | tas_fmw->nr_configurations = be16_to_cpup(p: (__be16 *)&data[offset]); |
1147 | offset += 2; |
1148 | |
1149 | if (tas_fmw->nr_configurations == 0) { |
1150 | dev_err(tas_priv->dev, "%s: Conf is zero\n" , __func__); |
1151 | /*Not error for calibration Data file, return directly*/ |
1152 | goto out; |
1153 | } |
1154 | tas_fmw->configs = kcalloc(n: tas_fmw->nr_configurations, |
1155 | size: sizeof(struct tasdevice_config), GFP_KERNEL); |
1156 | if (!tas_fmw->configs) { |
1157 | offset = -ENOMEM; |
1158 | goto out; |
1159 | } |
1160 | for (i = 0; i < tas_fmw->nr_configurations; i++) { |
1161 | config = &(tas_fmw->configs[i]); |
1162 | if (offset + 64 > fmw->size) { |
1163 | dev_err(tas_priv->dev, "File Size err\n" ); |
1164 | offset = -EINVAL; |
1165 | goto out; |
1166 | } |
1167 | memcpy(config->name, &data[offset], 64); |
1168 | offset += 64; |
1169 | |
1170 | n = strlen((char *)&data[offset]); |
1171 | n += 15; |
1172 | if (offset + n > fmw->size) { |
1173 | dev_err(tas_priv->dev, "Description err\n" ); |
1174 | offset = -EINVAL; |
1175 | goto out; |
1176 | } |
1177 | |
1178 | offset += n; |
1179 | |
1180 | offset = fw_parse_data(tas_fmw, img_data: &(config->dev_data), |
1181 | fmw, offset); |
1182 | if (offset < 0) |
1183 | goto out; |
1184 | } |
1185 | |
1186 | out: |
1187 | return offset; |
1188 | } |
1189 | |
1190 | static bool check_inpage_yram_rg(struct tas_crc *cd, |
1191 | unsigned char reg, unsigned char len) |
1192 | { |
1193 | bool in = false; |
1194 | |
1195 | |
1196 | if (reg <= TAS2781_YRAM5_END_REG && |
1197 | reg >= TAS2781_YRAM5_START_REG) { |
1198 | if (reg + len > TAS2781_YRAM5_END_REG) |
1199 | cd->len = TAS2781_YRAM5_END_REG - reg + 1; |
1200 | else |
1201 | cd->len = len; |
1202 | cd->offset = reg; |
1203 | in = true; |
1204 | } else if (reg < TAS2781_YRAM5_START_REG) { |
1205 | if (reg + len > TAS2781_YRAM5_START_REG) { |
1206 | cd->offset = TAS2781_YRAM5_START_REG; |
1207 | cd->len = len - TAS2781_YRAM5_START_REG + reg; |
1208 | in = true; |
1209 | } |
1210 | } |
1211 | |
1212 | return in; |
1213 | } |
1214 | |
1215 | static bool check_inpage_yram_bk1(struct tas_crc *cd, |
1216 | unsigned char page, unsigned char reg, unsigned char len) |
1217 | { |
1218 | bool in = false; |
1219 | |
1220 | if (page == TAS2781_YRAM1_PAGE) { |
1221 | if (reg >= TAS2781_YRAM1_START_REG) { |
1222 | cd->offset = reg; |
1223 | cd->len = len; |
1224 | in = true; |
1225 | } else if (reg + len > TAS2781_YRAM1_START_REG) { |
1226 | cd->offset = TAS2781_YRAM1_START_REG; |
1227 | cd->len = len - TAS2781_YRAM1_START_REG + reg; |
1228 | in = true; |
1229 | } |
1230 | } else if (page == TAS2781_YRAM3_PAGE) |
1231 | in = check_inpage_yram_rg(cd, reg, len); |
1232 | |
1233 | return in; |
1234 | } |
1235 | |
1236 | /* Return Code: |
1237 | * true -- the registers are in the inpage yram |
1238 | * false -- the registers are NOT in the inpage yram |
1239 | */ |
1240 | static bool check_inpage_yram(struct tas_crc *cd, unsigned char book, |
1241 | unsigned char page, unsigned char reg, unsigned char len) |
1242 | { |
1243 | bool in = false; |
1244 | |
1245 | if (book == TAS2781_YRAM_BOOK1) { |
1246 | in = check_inpage_yram_bk1(cd, page, reg, len); |
1247 | goto end; |
1248 | } |
1249 | if (book == TAS2781_YRAM_BOOK2 && page == TAS2781_YRAM5_PAGE) |
1250 | in = check_inpage_yram_rg(cd, reg, len); |
1251 | |
1252 | end: |
1253 | return in; |
1254 | } |
1255 | |
1256 | static bool check_inblock_yram_bk(struct tas_crc *cd, |
1257 | unsigned char page, unsigned char reg, unsigned char len) |
1258 | { |
1259 | bool in = false; |
1260 | |
1261 | if ((page >= TAS2781_YRAM4_START_PAGE && |
1262 | page <= TAS2781_YRAM4_END_PAGE) || |
1263 | (page >= TAS2781_YRAM2_START_PAGE && |
1264 | page <= TAS2781_YRAM2_END_PAGE)) { |
1265 | if (reg <= TAS2781_YRAM2_END_REG && |
1266 | reg >= TAS2781_YRAM2_START_REG) { |
1267 | cd->offset = reg; |
1268 | cd->len = len; |
1269 | in = true; |
1270 | } else if (reg < TAS2781_YRAM2_START_REG) { |
1271 | if (reg + len - 1 >= TAS2781_YRAM2_START_REG) { |
1272 | cd->offset = TAS2781_YRAM2_START_REG; |
1273 | cd->len = reg + len - TAS2781_YRAM2_START_REG; |
1274 | in = true; |
1275 | } |
1276 | } |
1277 | } |
1278 | |
1279 | return in; |
1280 | } |
1281 | |
1282 | /* Return Code: |
1283 | * true -- the registers are in the inblock yram |
1284 | * false -- the registers are NOT in the inblock yram |
1285 | */ |
1286 | static bool check_inblock_yram(struct tas_crc *cd, unsigned char book, |
1287 | unsigned char page, unsigned char reg, unsigned char len) |
1288 | { |
1289 | bool in = false; |
1290 | |
1291 | if (book == TAS2781_YRAM_BOOK1 || book == TAS2781_YRAM_BOOK2) |
1292 | in = check_inblock_yram_bk(cd, page, reg, len); |
1293 | |
1294 | return in; |
1295 | } |
1296 | |
1297 | static bool check_yram(struct tas_crc *cd, unsigned char book, |
1298 | unsigned char page, unsigned char reg, unsigned char len) |
1299 | { |
1300 | bool in; |
1301 | |
1302 | in = check_inpage_yram(cd, book, page, reg, len); |
1303 | if (in) |
1304 | goto end; |
1305 | in = check_inblock_yram(cd, book, page, reg, len); |
1306 | |
1307 | end: |
1308 | return in; |
1309 | } |
1310 | |
1311 | static int tasdev_multibytes_chksum(struct tasdevice_priv *tasdevice, |
1312 | unsigned short chn, unsigned char book, unsigned char page, |
1313 | unsigned char reg, unsigned int len) |
1314 | { |
1315 | struct tas_crc crc_data; |
1316 | unsigned char crc_chksum = 0; |
1317 | unsigned char nBuf1[128]; |
1318 | int ret = 0; |
1319 | int i; |
1320 | bool in; |
1321 | |
1322 | if ((reg + len - 1) > 127) { |
1323 | ret = -EINVAL; |
1324 | dev_err(tasdevice->dev, "firmware error\n" ); |
1325 | goto end; |
1326 | } |
1327 | |
1328 | if ((book == TASDEVICE_BOOK_ID(TAS2781_SA_COEFF_SWAP_REG)) |
1329 | && (page == TASDEVICE_PAGE_ID(TAS2781_SA_COEFF_SWAP_REG)) |
1330 | && (reg == TASDEVICE_PAGE_REG(TAS2781_SA_COEFF_SWAP_REG)) |
1331 | && (len == 4)) { |
1332 | /*DSP swap command, pass */ |
1333 | ret = 0; |
1334 | goto end; |
1335 | } |
1336 | |
1337 | in = check_yram(cd: &crc_data, book, page, reg, len); |
1338 | if (!in) |
1339 | goto end; |
1340 | |
1341 | if (len == 1) { |
1342 | dev_err(tasdevice->dev, "firmware error\n" ); |
1343 | ret = -EINVAL; |
1344 | goto end; |
1345 | } |
1346 | |
1347 | ret = tasdevice_dev_bulk_read(tas_priv: tasdevice, chn, |
1348 | TASDEVICE_REG(book, page, crc_data.offset), |
1349 | p_data: nBuf1, n_length: crc_data.len); |
1350 | if (ret < 0) |
1351 | goto end; |
1352 | |
1353 | for (i = 0; i < crc_data.len; i++) { |
1354 | if ((book == TASDEVICE_BOOK_ID(TAS2781_SA_COEFF_SWAP_REG)) |
1355 | && (page == TASDEVICE_PAGE_ID( |
1356 | TAS2781_SA_COEFF_SWAP_REG)) |
1357 | && ((i + crc_data.offset) |
1358 | >= TASDEVICE_PAGE_REG(TAS2781_SA_COEFF_SWAP_REG)) |
1359 | && ((i + crc_data.offset) |
1360 | <= (TASDEVICE_PAGE_REG(TAS2781_SA_COEFF_SWAP_REG) |
1361 | + 4))) |
1362 | /*DSP swap command, bypass */ |
1363 | continue; |
1364 | else |
1365 | crc_chksum += crc8(table: tasdevice->crc8_lkp_tbl, pdata: &nBuf1[i], |
1366 | nbytes: 1, crc: 0); |
1367 | } |
1368 | |
1369 | ret = crc_chksum; |
1370 | |
1371 | end: |
1372 | return ret; |
1373 | } |
1374 | |
1375 | static int do_singlereg_checksum(struct tasdevice_priv *tasdevice, |
1376 | unsigned short chl, unsigned char book, unsigned char page, |
1377 | unsigned char reg, unsigned char val) |
1378 | { |
1379 | struct tas_crc crc_data; |
1380 | unsigned int nData1; |
1381 | int ret = 0; |
1382 | bool in; |
1383 | |
1384 | if ((book == TASDEVICE_BOOK_ID(TAS2781_SA_COEFF_SWAP_REG)) |
1385 | && (page == TASDEVICE_PAGE_ID(TAS2781_SA_COEFF_SWAP_REG)) |
1386 | && (reg >= TASDEVICE_PAGE_REG(TAS2781_SA_COEFF_SWAP_REG)) |
1387 | && (reg <= (TASDEVICE_PAGE_REG( |
1388 | TAS2781_SA_COEFF_SWAP_REG) + 4))) { |
1389 | /*DSP swap command, pass */ |
1390 | ret = 0; |
1391 | goto end; |
1392 | } |
1393 | |
1394 | in = check_yram(cd: &crc_data, book, page, reg, len: 1); |
1395 | if (!in) |
1396 | goto end; |
1397 | ret = tasdevice_dev_read(tas_priv: tasdevice, chn: chl, |
1398 | TASDEVICE_REG(book, page, reg), value: &nData1); |
1399 | if (ret < 0) |
1400 | goto end; |
1401 | |
1402 | if (nData1 != val) { |
1403 | dev_err(tasdevice->dev, |
1404 | "B[0x%x]P[0x%x]R[0x%x] W[0x%x], R[0x%x]\n" , |
1405 | book, page, reg, val, nData1); |
1406 | tasdevice->tasdevice[chl].err_code |= ERROR_YRAM_CRCCHK; |
1407 | ret = -EAGAIN; |
1408 | goto end; |
1409 | } |
1410 | |
1411 | ret = crc8(table: tasdevice->crc8_lkp_tbl, pdata: &val, nbytes: 1, crc: 0); |
1412 | |
1413 | end: |
1414 | return ret; |
1415 | } |
1416 | |
1417 | static void set_err_prg_cfg(unsigned int type, struct tasdevice *dev) |
1418 | { |
1419 | if ((type == MAIN_ALL_DEVICES) || (type == MAIN_DEVICE_A) |
1420 | || (type == MAIN_DEVICE_B) || (type == MAIN_DEVICE_C) |
1421 | || (type == MAIN_DEVICE_D)) |
1422 | dev->cur_prog = -1; |
1423 | else |
1424 | dev->cur_conf = -1; |
1425 | } |
1426 | |
1427 | static int tasdev_bytes_chksum(struct tasdevice_priv *tas_priv, |
1428 | struct tasdev_blk *block, int chn, unsigned char book, |
1429 | unsigned char page, unsigned char reg, unsigned int len, |
1430 | unsigned char val, unsigned char *crc_chksum) |
1431 | { |
1432 | int ret; |
1433 | |
1434 | if (len > 1) |
1435 | ret = tasdev_multibytes_chksum(tasdevice: tas_priv, chn, book, page, reg, |
1436 | len); |
1437 | else |
1438 | ret = do_singlereg_checksum(tasdevice: tas_priv, chl: chn, book, page, reg, |
1439 | val); |
1440 | |
1441 | if (ret > 0) { |
1442 | *crc_chksum += (unsigned char)ret; |
1443 | goto end; |
1444 | } |
1445 | |
1446 | if (ret != -EAGAIN) |
1447 | goto end; |
1448 | |
1449 | block->nr_retry--; |
1450 | if (block->nr_retry > 0) |
1451 | goto end; |
1452 | |
1453 | set_err_prg_cfg(type: block->type, dev: &tas_priv->tasdevice[chn]); |
1454 | |
1455 | end: |
1456 | return ret; |
1457 | } |
1458 | |
1459 | static int tasdev_multibytes_wr(struct tasdevice_priv *tas_priv, |
1460 | struct tasdev_blk *block, int chn, unsigned char book, |
1461 | unsigned char page, unsigned char reg, unsigned char *data, |
1462 | unsigned int len, unsigned int *nr_cmds, |
1463 | unsigned char *crc_chksum) |
1464 | { |
1465 | int ret; |
1466 | |
1467 | if (len > 1) { |
1468 | ret = tasdevice_dev_bulk_write(tas_priv, chn, |
1469 | TASDEVICE_REG(book, page, reg), p_data: data + 3, n_length: len); |
1470 | if (ret < 0) |
1471 | goto end; |
1472 | if (block->is_ychksum_present) |
1473 | ret = tasdev_bytes_chksum(tas_priv, block, chn, |
1474 | book, page, reg, len, val: 0, crc_chksum); |
1475 | } else { |
1476 | ret = tasdevice_dev_write(tas_priv, chn, |
1477 | TASDEVICE_REG(book, page, reg), value: data[3]); |
1478 | if (ret < 0) |
1479 | goto end; |
1480 | if (block->is_ychksum_present) |
1481 | ret = tasdev_bytes_chksum(tas_priv, block, chn, book, |
1482 | page, reg, len: 1, val: data[3], crc_chksum); |
1483 | } |
1484 | |
1485 | if (!block->is_ychksum_present || ret >= 0) { |
1486 | *nr_cmds += 1; |
1487 | if (len >= 2) |
1488 | *nr_cmds += ((len - 2) / 4) + 1; |
1489 | } |
1490 | |
1491 | end: |
1492 | return ret; |
1493 | } |
1494 | |
1495 | static int tasdev_block_chksum(struct tasdevice_priv *tas_priv, |
1496 | struct tasdev_blk *block, int chn) |
1497 | { |
1498 | unsigned int nr_value; |
1499 | int ret; |
1500 | |
1501 | ret = tasdevice_dev_read(tas_priv, chn, TASDEVICE_I2CChecksum, |
1502 | value: &nr_value); |
1503 | if (ret < 0) { |
1504 | dev_err(tas_priv->dev, "%s: Chn %d\n" , __func__, chn); |
1505 | set_err_prg_cfg(type: block->type, dev: &tas_priv->tasdevice[chn]); |
1506 | goto end; |
1507 | } |
1508 | |
1509 | if ((nr_value & 0xff) != block->pchksum) { |
1510 | dev_err(tas_priv->dev, "%s: Blk PChkSum Chn %d " , __func__, |
1511 | chn); |
1512 | dev_err(tas_priv->dev, "PChkSum = 0x%x, Reg = 0x%x\n" , |
1513 | block->pchksum, (nr_value & 0xff)); |
1514 | tas_priv->tasdevice[chn].err_code |= ERROR_PRAM_CRCCHK; |
1515 | ret = -EAGAIN; |
1516 | block->nr_retry--; |
1517 | |
1518 | if (block->nr_retry <= 0) |
1519 | set_err_prg_cfg(type: block->type, |
1520 | dev: &tas_priv->tasdevice[chn]); |
1521 | } else |
1522 | tas_priv->tasdevice[chn].err_code &= ~ERROR_PRAM_CRCCHK; |
1523 | |
1524 | end: |
1525 | return ret; |
1526 | } |
1527 | |
1528 | static int tasdev_load_blk(struct tasdevice_priv *tas_priv, |
1529 | struct tasdev_blk *block, int chn) |
1530 | { |
1531 | unsigned int sleep_time; |
1532 | unsigned int len; |
1533 | unsigned int nr_cmds; |
1534 | unsigned char *data; |
1535 | unsigned char crc_chksum = 0; |
1536 | unsigned char offset; |
1537 | unsigned char book; |
1538 | unsigned char page; |
1539 | unsigned char val; |
1540 | int ret = 0; |
1541 | |
1542 | while (block->nr_retry > 0) { |
1543 | if (block->is_pchksum_present) { |
1544 | ret = tasdevice_dev_write(tas_priv, chn, |
1545 | TASDEVICE_I2CChecksum, value: 0); |
1546 | if (ret < 0) |
1547 | break; |
1548 | } |
1549 | |
1550 | if (block->is_ychksum_present) |
1551 | crc_chksum = 0; |
1552 | |
1553 | nr_cmds = 0; |
1554 | |
1555 | while (nr_cmds < block->nr_cmds) { |
1556 | data = block->data + nr_cmds * 4; |
1557 | |
1558 | book = data[0]; |
1559 | page = data[1]; |
1560 | offset = data[2]; |
1561 | val = data[3]; |
1562 | |
1563 | nr_cmds++; |
1564 | /*Single byte write*/ |
1565 | if (offset <= 0x7F) { |
1566 | ret = tasdevice_dev_write(tas_priv, chn, |
1567 | TASDEVICE_REG(book, page, offset), |
1568 | value: val); |
1569 | if (ret < 0) |
1570 | goto end; |
1571 | if (block->is_ychksum_present) { |
1572 | ret = tasdev_bytes_chksum(tas_priv, |
1573 | block, chn, book, page, reg: offset, |
1574 | len: 1, val, crc_chksum: &crc_chksum); |
1575 | if (ret < 0) |
1576 | break; |
1577 | } |
1578 | continue; |
1579 | } |
1580 | /*sleep command*/ |
1581 | if (offset == 0x81) { |
1582 | /*book -- data[0] page -- data[1]*/ |
1583 | sleep_time = ((book << 8) + page)*1000; |
1584 | usleep_range(min: sleep_time, max: sleep_time + 50); |
1585 | continue; |
1586 | } |
1587 | /*Multiple bytes write*/ |
1588 | if (offset == 0x85) { |
1589 | data += 4; |
1590 | len = (book << 8) + page; |
1591 | book = data[0]; |
1592 | page = data[1]; |
1593 | offset = data[2]; |
1594 | ret = tasdev_multibytes_wr(tas_priv, |
1595 | block, chn, book, page, reg: offset, data, |
1596 | len, nr_cmds: &nr_cmds, crc_chksum: &crc_chksum); |
1597 | if (ret < 0) |
1598 | break; |
1599 | } |
1600 | } |
1601 | if (ret == -EAGAIN) { |
1602 | if (block->nr_retry > 0) |
1603 | continue; |
1604 | } else if (ret < 0) /*err in current device, skip it*/ |
1605 | break; |
1606 | |
1607 | if (block->is_pchksum_present) { |
1608 | ret = tasdev_block_chksum(tas_priv, block, chn); |
1609 | if (ret == -EAGAIN) { |
1610 | if (block->nr_retry > 0) |
1611 | continue; |
1612 | } else if (ret < 0) /*err in current device, skip it*/ |
1613 | break; |
1614 | } |
1615 | |
1616 | if (block->is_ychksum_present) { |
1617 | /* TBD, open it when FW ready */ |
1618 | dev_err(tas_priv->dev, |
1619 | "Blk YChkSum: FW = 0x%x, YCRC = 0x%x\n" , |
1620 | block->ychksum, crc_chksum); |
1621 | |
1622 | tas_priv->tasdevice[chn].err_code &= |
1623 | ~ERROR_YRAM_CRCCHK; |
1624 | ret = 0; |
1625 | } |
1626 | /*skip current blk*/ |
1627 | break; |
1628 | } |
1629 | |
1630 | end: |
1631 | return ret; |
1632 | } |
1633 | |
1634 | static int tasdevice_load_block(struct tasdevice_priv *tas_priv, |
1635 | struct tasdev_blk *block) |
1636 | { |
1637 | int chnend = 0; |
1638 | int ret = 0; |
1639 | int chn = 0; |
1640 | int rc = 0; |
1641 | |
1642 | switch (block->type) { |
1643 | case MAIN_ALL_DEVICES: |
1644 | chn = 0; |
1645 | chnend = tas_priv->ndev; |
1646 | break; |
1647 | case MAIN_DEVICE_A: |
1648 | case COEFF_DEVICE_A: |
1649 | case PRE_DEVICE_A: |
1650 | chn = 0; |
1651 | chnend = 1; |
1652 | break; |
1653 | case MAIN_DEVICE_B: |
1654 | case COEFF_DEVICE_B: |
1655 | case PRE_DEVICE_B: |
1656 | chn = 1; |
1657 | chnend = 2; |
1658 | break; |
1659 | case MAIN_DEVICE_C: |
1660 | case COEFF_DEVICE_C: |
1661 | case PRE_DEVICE_C: |
1662 | chn = 2; |
1663 | chnend = 3; |
1664 | break; |
1665 | case MAIN_DEVICE_D: |
1666 | case COEFF_DEVICE_D: |
1667 | case PRE_DEVICE_D: |
1668 | chn = 3; |
1669 | chnend = 4; |
1670 | break; |
1671 | default: |
1672 | dev_dbg(tas_priv->dev, "load blk: Other Type = 0x%02x\n" , |
1673 | block->type); |
1674 | break; |
1675 | } |
1676 | |
1677 | for (; chn < chnend; chn++) { |
1678 | block->nr_retry = 6; |
1679 | if (tas_priv->tasdevice[chn].is_loading == false) |
1680 | continue; |
1681 | ret = tasdev_load_blk(tas_priv, block, chn); |
1682 | if (ret < 0) |
1683 | dev_err(tas_priv->dev, "dev %d, Blk (%d) load error\n" , |
1684 | chn, block->type); |
1685 | rc |= ret; |
1686 | } |
1687 | |
1688 | return rc; |
1689 | } |
1690 | |
1691 | static int dspfw_default_callback(struct tasdevice_priv *tas_priv, |
1692 | unsigned int drv_ver, unsigned int ppcver) |
1693 | { |
1694 | int rc = 0; |
1695 | |
1696 | if (drv_ver == 0x100) { |
1697 | if (ppcver >= PPC3_VERSION) { |
1698 | tas_priv->fw_parse_variable_header = |
1699 | fw_parse_variable_header_kernel; |
1700 | tas_priv->fw_parse_program_data = |
1701 | fw_parse_program_data_kernel; |
1702 | tas_priv->fw_parse_configuration_data = |
1703 | fw_parse_configuration_data_kernel; |
1704 | tas_priv->tasdevice_load_block = |
1705 | tasdevice_load_block_kernel; |
1706 | } else { |
1707 | switch (ppcver) { |
1708 | case 0x00: |
1709 | tas_priv->fw_parse_variable_header = |
1710 | fw_parse_variable_header_git; |
1711 | tas_priv->fw_parse_program_data = |
1712 | fw_parse_program_data; |
1713 | tas_priv->fw_parse_configuration_data = |
1714 | fw_parse_configuration_data; |
1715 | tas_priv->tasdevice_load_block = |
1716 | tasdevice_load_block; |
1717 | break; |
1718 | default: |
1719 | dev_err(tas_priv->dev, |
1720 | "%s: PPCVer must be 0x0 or 0x%02x" , |
1721 | __func__, PPC3_VERSION); |
1722 | dev_err(tas_priv->dev, " Current:0x%02x\n" , |
1723 | ppcver); |
1724 | rc = -EINVAL; |
1725 | break; |
1726 | } |
1727 | } |
1728 | } else { |
1729 | dev_err(tas_priv->dev, |
1730 | "DrvVer must be 0x0, 0x230 or above 0x230 " ); |
1731 | dev_err(tas_priv->dev, "current is 0x%02x\n" , drv_ver); |
1732 | rc = -EINVAL; |
1733 | } |
1734 | |
1735 | return rc; |
1736 | } |
1737 | |
1738 | static int load_calib_data(struct tasdevice_priv *tas_priv, |
1739 | struct tasdevice_data *dev_data) |
1740 | { |
1741 | struct tasdev_blk *block; |
1742 | unsigned int i; |
1743 | int ret = 0; |
1744 | |
1745 | for (i = 0; i < dev_data->nr_blk; i++) { |
1746 | block = &(dev_data->dev_blks[i]); |
1747 | ret = tasdevice_load_block(tas_priv, block); |
1748 | if (ret < 0) |
1749 | break; |
1750 | } |
1751 | |
1752 | return ret; |
1753 | } |
1754 | |
1755 | static int (struct tasdevice_priv *tas_priv, |
1756 | struct tasdevice_fw *tas_fmw, const struct firmware *fmw, int offset) |
1757 | { |
1758 | struct tasdevice_dspfw_hdr *fw_hdr = &(tas_fmw->fw_hdr); |
1759 | struct tasdevice_fw_fixed_hdr *fw_fixed_hdr = &(fw_hdr->fixed_hdr); |
1760 | static const unsigned char magic_number[] = { 0x35, 0x35, 0x35, 0x32 }; |
1761 | const unsigned char *buf = (unsigned char *)fmw->data; |
1762 | |
1763 | if (offset + 92 > fmw->size) { |
1764 | dev_err(tas_priv->dev, "%s: File Size error\n" , __func__); |
1765 | offset = -EINVAL; |
1766 | goto out; |
1767 | } |
1768 | if (memcmp(p: &buf[offset], q: magic_number, size: 4)) { |
1769 | dev_err(tas_priv->dev, "%s: Magic num NOT match\n" , __func__); |
1770 | offset = -EINVAL; |
1771 | goto out; |
1772 | } |
1773 | offset += 4; |
1774 | |
1775 | /* Convert data[offset], data[offset + 1], data[offset + 2] and |
1776 | * data[offset + 3] into host |
1777 | */ |
1778 | fw_fixed_hdr->fwsize = be32_to_cpup(p: (__be32 *)&buf[offset]); |
1779 | offset += 4; |
1780 | if (fw_fixed_hdr->fwsize != fmw->size) { |
1781 | dev_err(tas_priv->dev, "File size not match, %lu %u" , |
1782 | (unsigned long)fmw->size, fw_fixed_hdr->fwsize); |
1783 | offset = -EINVAL; |
1784 | goto out; |
1785 | } |
1786 | offset += 4; |
1787 | fw_fixed_hdr->ppcver = be32_to_cpup(p: (__be32 *)&buf[offset]); |
1788 | offset += 8; |
1789 | fw_fixed_hdr->drv_ver = be32_to_cpup(p: (__be32 *)&buf[offset]); |
1790 | offset += 72; |
1791 | |
1792 | out: |
1793 | return offset; |
1794 | } |
1795 | |
1796 | static int fw_parse_variable_hdr_cal(struct tasdevice_priv *tas_priv, |
1797 | struct tasdevice_fw *tas_fmw, const struct firmware *fmw, int offset) |
1798 | { |
1799 | struct tasdevice_dspfw_hdr *fw_hdr = &(tas_fmw->fw_hdr); |
1800 | |
1801 | offset = fw_parse_variable_hdr(tas_priv, fw_hdr, fmw, offset); |
1802 | if (offset < 0) |
1803 | goto out; |
1804 | if (fw_hdr->ndev != 1) { |
1805 | dev_err(tas_priv->dev, |
1806 | "%s: calbin must be 1, but currently ndev(%u)\n" , |
1807 | __func__, fw_hdr->ndev); |
1808 | offset = -EINVAL; |
1809 | } |
1810 | |
1811 | out: |
1812 | return offset; |
1813 | } |
1814 | |
1815 | /* When calibrated data parsing error occurs, DSP can still work with default |
1816 | * calibrated data, memory resource related to calibrated data will be |
1817 | * released in the tasdevice_codec_remove. |
1818 | */ |
1819 | static int fw_parse_calibration_data(struct tasdevice_priv *tas_priv, |
1820 | struct tasdevice_fw *tas_fmw, const struct firmware *fmw, int offset) |
1821 | { |
1822 | struct tasdevice_calibration *calibration; |
1823 | unsigned char *data = (unsigned char *)fmw->data; |
1824 | unsigned int i, n; |
1825 | |
1826 | if (offset + 2 > fmw->size) { |
1827 | dev_err(tas_priv->dev, "%s: Calibrations error\n" , __func__); |
1828 | offset = -EINVAL; |
1829 | goto out; |
1830 | } |
1831 | tas_fmw->nr_calibrations = be16_to_cpup(p: (__be16 *)&data[offset]); |
1832 | offset += 2; |
1833 | |
1834 | if (tas_fmw->nr_calibrations != 1) { |
1835 | dev_err(tas_priv->dev, |
1836 | "%s: only supports one calibration (%d)!\n" , |
1837 | __func__, tas_fmw->nr_calibrations); |
1838 | goto out; |
1839 | } |
1840 | |
1841 | tas_fmw->calibrations = kcalloc(n: tas_fmw->nr_calibrations, |
1842 | size: sizeof(struct tasdevice_calibration), GFP_KERNEL); |
1843 | if (!tas_fmw->calibrations) { |
1844 | offset = -ENOMEM; |
1845 | goto out; |
1846 | } |
1847 | for (i = 0; i < tas_fmw->nr_calibrations; i++) { |
1848 | if (offset + 64 > fmw->size) { |
1849 | dev_err(tas_priv->dev, "Calibrations error\n" ); |
1850 | offset = -EINVAL; |
1851 | goto out; |
1852 | } |
1853 | calibration = &(tas_fmw->calibrations[i]); |
1854 | offset += 64; |
1855 | |
1856 | n = strlen((char *)&data[offset]); |
1857 | /* skip '\0' and 2 unused bytes */ |
1858 | n += 3; |
1859 | if (offset + n > fmw->size) { |
1860 | dev_err(tas_priv->dev, "Description err\n" ); |
1861 | offset = -EINVAL; |
1862 | goto out; |
1863 | } |
1864 | offset += n; |
1865 | |
1866 | offset = fw_parse_data(tas_fmw, img_data: &(calibration->dev_data), fmw, |
1867 | offset); |
1868 | if (offset < 0) |
1869 | goto out; |
1870 | } |
1871 | |
1872 | out: |
1873 | return offset; |
1874 | } |
1875 | |
1876 | int tas2781_load_calibration(void *context, char *file_name, |
1877 | unsigned short i) |
1878 | { |
1879 | struct tasdevice_priv *tas_priv = (struct tasdevice_priv *)context; |
1880 | struct tasdevice *tasdev = &(tas_priv->tasdevice[i]); |
1881 | const struct firmware *fw_entry; |
1882 | struct tasdevice_fw *tas_fmw; |
1883 | struct firmware fmw; |
1884 | int offset = 0; |
1885 | int ret; |
1886 | |
1887 | ret = request_firmware(fw: &fw_entry, name: file_name, device: tas_priv->dev); |
1888 | if (ret) { |
1889 | dev_err(tas_priv->dev, "%s: Request firmware %s failed\n" , |
1890 | __func__, file_name); |
1891 | goto out; |
1892 | } |
1893 | |
1894 | if (!fw_entry->size) { |
1895 | dev_err(tas_priv->dev, "%s: file read error: size = %lu\n" , |
1896 | __func__, (unsigned long)fw_entry->size); |
1897 | ret = -EINVAL; |
1898 | goto out; |
1899 | } |
1900 | fmw.size = fw_entry->size; |
1901 | fmw.data = fw_entry->data; |
1902 | |
1903 | tas_fmw = tasdev->cali_data_fmw = kzalloc(size: sizeof(struct tasdevice_fw), |
1904 | GFP_KERNEL); |
1905 | if (!tasdev->cali_data_fmw) { |
1906 | ret = -ENOMEM; |
1907 | goto out; |
1908 | } |
1909 | tas_fmw->dev = tas_priv->dev; |
1910 | offset = fw_parse_header(tas_priv, tas_fmw, fmw: &fmw, offset); |
1911 | if (offset == -EINVAL) { |
1912 | dev_err(tas_priv->dev, "fw_parse_header EXIT!\n" ); |
1913 | ret = offset; |
1914 | goto out; |
1915 | } |
1916 | offset = fw_parse_variable_hdr_cal(tas_priv, tas_fmw, fmw: &fmw, offset); |
1917 | if (offset == -EINVAL) { |
1918 | dev_err(tas_priv->dev, |
1919 | "%s: fw_parse_variable_header_cal EXIT!\n" , __func__); |
1920 | ret = offset; |
1921 | goto out; |
1922 | } |
1923 | offset = fw_parse_program_data(tas_priv, tas_fmw, fmw: &fmw, offset); |
1924 | if (offset < 0) { |
1925 | dev_err(tas_priv->dev, "fw_parse_program_data EXIT!\n" ); |
1926 | ret = offset; |
1927 | goto out; |
1928 | } |
1929 | offset = fw_parse_configuration_data(tas_priv, tas_fmw, fmw: &fmw, offset); |
1930 | if (offset < 0) { |
1931 | dev_err(tas_priv->dev, "fw_parse_configuration_data EXIT!\n" ); |
1932 | ret = offset; |
1933 | goto out; |
1934 | } |
1935 | offset = fw_parse_calibration_data(tas_priv, tas_fmw, fmw: &fmw, offset); |
1936 | if (offset < 0) { |
1937 | dev_err(tas_priv->dev, "fw_parse_calibration_data EXIT!\n" ); |
1938 | ret = offset; |
1939 | goto out; |
1940 | } |
1941 | |
1942 | out: |
1943 | if (fw_entry) |
1944 | release_firmware(fw: fw_entry); |
1945 | |
1946 | return ret; |
1947 | } |
1948 | EXPORT_SYMBOL_NS_GPL(tas2781_load_calibration, SND_SOC_TAS2781_FMWLIB); |
1949 | |
1950 | static int tasdevice_dspfw_ready(const struct firmware *fmw, |
1951 | void *context) |
1952 | { |
1953 | struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) context; |
1954 | struct tasdevice_fw_fixed_hdr *fw_fixed_hdr; |
1955 | struct tasdevice_fw *tas_fmw; |
1956 | int offset = 0; |
1957 | int ret = 0; |
1958 | |
1959 | if (!fmw || !fmw->data) { |
1960 | dev_err(tas_priv->dev, "%s: Failed to read firmware %s\n" , |
1961 | __func__, tas_priv->coef_binaryname); |
1962 | ret = -EINVAL; |
1963 | goto out; |
1964 | } |
1965 | |
1966 | tas_priv->fmw = kzalloc(size: sizeof(struct tasdevice_fw), GFP_KERNEL); |
1967 | if (!tas_priv->fmw) { |
1968 | ret = -ENOMEM; |
1969 | goto out; |
1970 | } |
1971 | tas_fmw = tas_priv->fmw; |
1972 | tas_fmw->dev = tas_priv->dev; |
1973 | offset = fw_parse_header(tas_priv, tas_fmw, fmw, offset); |
1974 | |
1975 | if (offset == -EINVAL) { |
1976 | ret = -EINVAL; |
1977 | goto out; |
1978 | } |
1979 | fw_fixed_hdr = &(tas_fmw->fw_hdr.fixed_hdr); |
1980 | /* Support different versions of firmware */ |
1981 | switch (fw_fixed_hdr->drv_ver) { |
1982 | case 0x301: |
1983 | case 0x302: |
1984 | case 0x502: |
1985 | case 0x503: |
1986 | tas_priv->fw_parse_variable_header = |
1987 | fw_parse_variable_header_kernel; |
1988 | tas_priv->fw_parse_program_data = |
1989 | fw_parse_program_data_kernel; |
1990 | tas_priv->fw_parse_configuration_data = |
1991 | fw_parse_configuration_data_kernel; |
1992 | tas_priv->tasdevice_load_block = |
1993 | tasdevice_load_block_kernel; |
1994 | break; |
1995 | case 0x202: |
1996 | case 0x400: |
1997 | tas_priv->fw_parse_variable_header = |
1998 | fw_parse_variable_header_git; |
1999 | tas_priv->fw_parse_program_data = |
2000 | fw_parse_program_data; |
2001 | tas_priv->fw_parse_configuration_data = |
2002 | fw_parse_configuration_data; |
2003 | tas_priv->tasdevice_load_block = |
2004 | tasdevice_load_block; |
2005 | break; |
2006 | default: |
2007 | ret = dspfw_default_callback(tas_priv, |
2008 | drv_ver: fw_fixed_hdr->drv_ver, ppcver: fw_fixed_hdr->ppcver); |
2009 | if (ret) |
2010 | goto out; |
2011 | break; |
2012 | } |
2013 | |
2014 | offset = tas_priv->fw_parse_variable_header(tas_priv, fmw, offset); |
2015 | if (offset < 0) { |
2016 | ret = offset; |
2017 | goto out; |
2018 | } |
2019 | offset = tas_priv->fw_parse_program_data(tas_priv, tas_fmw, fmw, |
2020 | offset); |
2021 | if (offset < 0) { |
2022 | ret = offset; |
2023 | goto out; |
2024 | } |
2025 | offset = tas_priv->fw_parse_configuration_data(tas_priv, |
2026 | tas_fmw, fmw, offset); |
2027 | if (offset < 0) |
2028 | ret = offset; |
2029 | |
2030 | out: |
2031 | return ret; |
2032 | } |
2033 | |
2034 | int tasdevice_dsp_parser(void *context) |
2035 | { |
2036 | struct tasdevice_priv *tas_priv = (struct tasdevice_priv *)context; |
2037 | const struct firmware *fw_entry; |
2038 | int ret; |
2039 | |
2040 | ret = request_firmware(fw: &fw_entry, name: tas_priv->coef_binaryname, |
2041 | device: tas_priv->dev); |
2042 | if (ret) { |
2043 | dev_err(tas_priv->dev, "%s: load %s error\n" , __func__, |
2044 | tas_priv->coef_binaryname); |
2045 | goto out; |
2046 | } |
2047 | |
2048 | ret = tasdevice_dspfw_ready(fmw: fw_entry, context: tas_priv); |
2049 | release_firmware(fw: fw_entry); |
2050 | fw_entry = NULL; |
2051 | |
2052 | out: |
2053 | return ret; |
2054 | } |
2055 | EXPORT_SYMBOL_NS_GPL(tasdevice_dsp_parser, SND_SOC_TAS2781_FMWLIB); |
2056 | |
2057 | static void tas2781_clear_calfirmware(struct tasdevice_fw *tas_fmw) |
2058 | { |
2059 | struct tasdevice_calibration *calibration; |
2060 | struct tasdev_blk *block; |
2061 | struct tasdevice_data *im; |
2062 | unsigned int blks; |
2063 | int i; |
2064 | |
2065 | if (!tas_fmw->calibrations) |
2066 | goto out; |
2067 | |
2068 | for (i = 0; i < tas_fmw->nr_calibrations; i++) { |
2069 | calibration = &(tas_fmw->calibrations[i]); |
2070 | if (!calibration) |
2071 | continue; |
2072 | |
2073 | im = &(calibration->dev_data); |
2074 | |
2075 | if (!im->dev_blks) |
2076 | continue; |
2077 | |
2078 | for (blks = 0; blks < im->nr_blk; blks++) { |
2079 | block = &(im->dev_blks[blks]); |
2080 | if (!block) |
2081 | continue; |
2082 | kfree(objp: block->data); |
2083 | } |
2084 | kfree(objp: im->dev_blks); |
2085 | } |
2086 | kfree(objp: tas_fmw->calibrations); |
2087 | out: |
2088 | kfree(objp: tas_fmw); |
2089 | } |
2090 | |
2091 | void tasdevice_calbin_remove(void *context) |
2092 | { |
2093 | struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) context; |
2094 | struct tasdevice *tasdev; |
2095 | int i; |
2096 | |
2097 | if (!tas_priv) |
2098 | return; |
2099 | |
2100 | for (i = 0; i < tas_priv->ndev; i++) { |
2101 | tasdev = &(tas_priv->tasdevice[i]); |
2102 | if (!tasdev->cali_data_fmw) |
2103 | continue; |
2104 | tas2781_clear_calfirmware(tas_fmw: tasdev->cali_data_fmw); |
2105 | tasdev->cali_data_fmw = NULL; |
2106 | } |
2107 | } |
2108 | EXPORT_SYMBOL_NS_GPL(tasdevice_calbin_remove, SND_SOC_TAS2781_FMWLIB); |
2109 | |
2110 | void tasdevice_config_info_remove(void *context) |
2111 | { |
2112 | struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) context; |
2113 | struct tasdevice_rca *rca = &(tas_priv->rcabin); |
2114 | struct tasdevice_config_info **ci = rca->cfg_info; |
2115 | int i, j; |
2116 | |
2117 | if (!ci) |
2118 | return; |
2119 | for (i = 0; i < rca->ncfgs; i++) { |
2120 | if (!ci[i]) |
2121 | continue; |
2122 | if (ci[i]->blk_data) { |
2123 | for (j = 0; j < (int)ci[i]->real_nblocks; j++) { |
2124 | if (!ci[i]->blk_data[j]) |
2125 | continue; |
2126 | kfree(objp: ci[i]->blk_data[j]->regdata); |
2127 | kfree(objp: ci[i]->blk_data[j]); |
2128 | } |
2129 | kfree(objp: ci[i]->blk_data); |
2130 | } |
2131 | kfree(objp: ci[i]); |
2132 | } |
2133 | kfree(objp: ci); |
2134 | } |
2135 | EXPORT_SYMBOL_NS_GPL(tasdevice_config_info_remove, SND_SOC_TAS2781_FMWLIB); |
2136 | |
2137 | static int tasdevice_load_data(struct tasdevice_priv *tas_priv, |
2138 | struct tasdevice_data *dev_data) |
2139 | { |
2140 | struct tasdev_blk *block; |
2141 | unsigned int i; |
2142 | int ret = 0; |
2143 | |
2144 | for (i = 0; i < dev_data->nr_blk; i++) { |
2145 | block = &(dev_data->dev_blks[i]); |
2146 | ret = tas_priv->tasdevice_load_block(tas_priv, block); |
2147 | if (ret < 0) |
2148 | break; |
2149 | } |
2150 | |
2151 | return ret; |
2152 | } |
2153 | |
2154 | int tasdevice_select_tuningprm_cfg(void *context, int prm_no, |
2155 | int cfg_no, int rca_conf_no) |
2156 | { |
2157 | struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) context; |
2158 | struct tasdevice_rca *rca = &(tas_priv->rcabin); |
2159 | struct tasdevice_config_info **cfg_info = rca->cfg_info; |
2160 | struct tasdevice_fw *tas_fmw = tas_priv->fmw; |
2161 | struct tasdevice_prog *program; |
2162 | struct tasdevice_config *conf; |
2163 | int prog_status = 0; |
2164 | int status, i; |
2165 | |
2166 | if (!tas_fmw) { |
2167 | dev_err(tas_priv->dev, "%s: Firmware is NULL\n" , __func__); |
2168 | goto out; |
2169 | } |
2170 | |
2171 | if (cfg_no >= tas_fmw->nr_configurations) { |
2172 | dev_err(tas_priv->dev, |
2173 | "%s: cfg(%d) is not in range of conf %u\n" , |
2174 | __func__, cfg_no, tas_fmw->nr_configurations); |
2175 | goto out; |
2176 | } |
2177 | |
2178 | if (prm_no >= tas_fmw->nr_programs) { |
2179 | dev_err(tas_priv->dev, |
2180 | "%s: prm(%d) is not in range of Programs %u\n" , |
2181 | __func__, prm_no, tas_fmw->nr_programs); |
2182 | goto out; |
2183 | } |
2184 | |
2185 | if (rca_conf_no >= rca->ncfgs || rca_conf_no < 0 || |
2186 | !cfg_info) { |
2187 | dev_err(tas_priv->dev, |
2188 | "conf_no:%d should be in range from 0 to %u\n" , |
2189 | rca_conf_no, rca->ncfgs-1); |
2190 | goto out; |
2191 | } |
2192 | |
2193 | for (i = 0, prog_status = 0; i < tas_priv->ndev; i++) { |
2194 | if (cfg_info[rca_conf_no]->active_dev & (1 << i)) { |
2195 | if (prm_no >= 0 |
2196 | && (tas_priv->tasdevice[i].cur_prog != prm_no |
2197 | || tas_priv->force_fwload_status)) { |
2198 | tas_priv->tasdevice[i].cur_conf = -1; |
2199 | tas_priv->tasdevice[i].is_loading = true; |
2200 | prog_status++; |
2201 | } |
2202 | } else |
2203 | tas_priv->tasdevice[i].is_loading = false; |
2204 | tas_priv->tasdevice[i].is_loaderr = false; |
2205 | } |
2206 | |
2207 | if (prog_status) { |
2208 | program = &(tas_fmw->programs[prm_no]); |
2209 | tasdevice_load_data(tas_priv, dev_data: &(program->dev_data)); |
2210 | for (i = 0; i < tas_priv->ndev; i++) { |
2211 | if (tas_priv->tasdevice[i].is_loaderr == true) |
2212 | continue; |
2213 | else if (tas_priv->tasdevice[i].is_loaderr == false |
2214 | && tas_priv->tasdevice[i].is_loading == true) { |
2215 | struct tasdevice_fw *cal_fmw = |
2216 | tas_priv->tasdevice[i].cali_data_fmw; |
2217 | |
2218 | if (cal_fmw) { |
2219 | struct tasdevice_calibration |
2220 | *cal = cal_fmw->calibrations; |
2221 | |
2222 | if (cal) |
2223 | load_calib_data(tas_priv, |
2224 | dev_data: &(cal->dev_data)); |
2225 | } |
2226 | tas_priv->tasdevice[i].cur_prog = prm_no; |
2227 | } |
2228 | } |
2229 | } |
2230 | |
2231 | for (i = 0, status = 0; i < tas_priv->ndev; i++) { |
2232 | if (cfg_no >= 0 |
2233 | && tas_priv->tasdevice[i].cur_conf != cfg_no |
2234 | && (cfg_info[rca_conf_no]->active_dev & (1 << i)) |
2235 | && (tas_priv->tasdevice[i].is_loaderr == false)) { |
2236 | status++; |
2237 | tas_priv->tasdevice[i].is_loading = true; |
2238 | } else |
2239 | tas_priv->tasdevice[i].is_loading = false; |
2240 | } |
2241 | |
2242 | if (status) { |
2243 | conf = &(tas_fmw->configs[cfg_no]); |
2244 | status = 0; |
2245 | tasdevice_load_data(tas_priv, dev_data: &(conf->dev_data)); |
2246 | for (i = 0; i < tas_priv->ndev; i++) { |
2247 | if (tas_priv->tasdevice[i].is_loaderr == true) { |
2248 | status |= 1 << (i + 4); |
2249 | continue; |
2250 | } else if (tas_priv->tasdevice[i].is_loaderr == false |
2251 | && tas_priv->tasdevice[i].is_loading == true) |
2252 | tas_priv->tasdevice[i].cur_conf = cfg_no; |
2253 | } |
2254 | } else |
2255 | dev_dbg(tas_priv->dev, "%s: Unneeded loading dsp conf %d\n" , |
2256 | __func__, cfg_no); |
2257 | |
2258 | status |= cfg_info[rca_conf_no]->active_dev; |
2259 | |
2260 | out: |
2261 | return prog_status; |
2262 | } |
2263 | EXPORT_SYMBOL_NS_GPL(tasdevice_select_tuningprm_cfg, |
2264 | SND_SOC_TAS2781_FMWLIB); |
2265 | |
2266 | int tasdevice_prmg_load(void *context, int prm_no) |
2267 | { |
2268 | struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) context; |
2269 | struct tasdevice_fw *tas_fmw = tas_priv->fmw; |
2270 | struct tasdevice_prog *program; |
2271 | int prog_status = 0; |
2272 | int i; |
2273 | |
2274 | if (!tas_fmw) { |
2275 | dev_err(tas_priv->dev, "%s: Firmware is NULL\n" , __func__); |
2276 | goto out; |
2277 | } |
2278 | |
2279 | if (prm_no >= tas_fmw->nr_programs) { |
2280 | dev_err(tas_priv->dev, |
2281 | "%s: prm(%d) is not in range of Programs %u\n" , |
2282 | __func__, prm_no, tas_fmw->nr_programs); |
2283 | goto out; |
2284 | } |
2285 | |
2286 | for (i = 0, prog_status = 0; i < tas_priv->ndev; i++) { |
2287 | if (prm_no >= 0 && tas_priv->tasdevice[i].cur_prog != prm_no) { |
2288 | tas_priv->tasdevice[i].cur_conf = -1; |
2289 | tas_priv->tasdevice[i].is_loading = true; |
2290 | prog_status++; |
2291 | } |
2292 | } |
2293 | |
2294 | if (prog_status) { |
2295 | program = &(tas_fmw->programs[prm_no]); |
2296 | tasdevice_load_data(tas_priv, dev_data: &(program->dev_data)); |
2297 | for (i = 0; i < tas_priv->ndev; i++) { |
2298 | if (tas_priv->tasdevice[i].is_loaderr == true) |
2299 | continue; |
2300 | else if (tas_priv->tasdevice[i].is_loaderr == false |
2301 | && tas_priv->tasdevice[i].is_loading == true) |
2302 | tas_priv->tasdevice[i].cur_prog = prm_no; |
2303 | } |
2304 | } |
2305 | |
2306 | out: |
2307 | return prog_status; |
2308 | } |
2309 | EXPORT_SYMBOL_NS_GPL(tasdevice_prmg_load, SND_SOC_TAS2781_FMWLIB); |
2310 | |
2311 | int tasdevice_prmg_calibdata_load(void *context, int prm_no) |
2312 | { |
2313 | struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) context; |
2314 | struct tasdevice_fw *tas_fmw = tas_priv->fmw; |
2315 | struct tasdevice_prog *program; |
2316 | int prog_status = 0; |
2317 | int i; |
2318 | |
2319 | if (!tas_fmw) { |
2320 | dev_err(tas_priv->dev, "%s: Firmware is NULL\n" , __func__); |
2321 | goto out; |
2322 | } |
2323 | |
2324 | if (prm_no >= tas_fmw->nr_programs) { |
2325 | dev_err(tas_priv->dev, |
2326 | "%s: prm(%d) is not in range of Programs %u\n" , |
2327 | __func__, prm_no, tas_fmw->nr_programs); |
2328 | goto out; |
2329 | } |
2330 | |
2331 | for (i = 0, prog_status = 0; i < tas_priv->ndev; i++) { |
2332 | if (prm_no >= 0 && tas_priv->tasdevice[i].cur_prog != prm_no) { |
2333 | tas_priv->tasdevice[i].cur_conf = -1; |
2334 | tas_priv->tasdevice[i].is_loading = true; |
2335 | prog_status++; |
2336 | } |
2337 | tas_priv->tasdevice[i].is_loaderr = false; |
2338 | } |
2339 | |
2340 | if (prog_status) { |
2341 | program = &(tas_fmw->programs[prm_no]); |
2342 | tasdevice_load_data(tas_priv, dev_data: &(program->dev_data)); |
2343 | for (i = 0; i < tas_priv->ndev; i++) { |
2344 | if (tas_priv->tasdevice[i].is_loaderr == true) |
2345 | continue; |
2346 | else if (tas_priv->tasdevice[i].is_loaderr == false |
2347 | && tas_priv->tasdevice[i].is_loading == true) { |
2348 | struct tasdevice_fw *cal_fmw = |
2349 | tas_priv->tasdevice[i].cali_data_fmw; |
2350 | |
2351 | if (cal_fmw) { |
2352 | struct tasdevice_calibration *cal = |
2353 | cal_fmw->calibrations; |
2354 | |
2355 | if (cal) |
2356 | load_calib_data(tas_priv, |
2357 | dev_data: &(cal->dev_data)); |
2358 | } |
2359 | tas_priv->tasdevice[i].cur_prog = prm_no; |
2360 | } |
2361 | } |
2362 | } |
2363 | |
2364 | out: |
2365 | return prog_status; |
2366 | } |
2367 | EXPORT_SYMBOL_NS_GPL(tasdevice_prmg_calibdata_load, |
2368 | SND_SOC_TAS2781_FMWLIB); |
2369 | |
2370 | void tasdevice_tuning_switch(void *context, int state) |
2371 | { |
2372 | struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) context; |
2373 | struct tasdevice_fw *tas_fmw = tas_priv->fmw; |
2374 | int profile_cfg_id = tas_priv->rcabin.profile_cfg_id; |
2375 | |
2376 | if (tas_priv->fw_state == TASDEVICE_DSP_FW_FAIL) { |
2377 | dev_err(tas_priv->dev, "DSP bin file not loaded\n" ); |
2378 | return; |
2379 | } |
2380 | |
2381 | if (state == 0) { |
2382 | if (tas_priv->cur_prog < tas_fmw->nr_programs) { |
2383 | /*dsp mode or tuning mode*/ |
2384 | profile_cfg_id = tas_priv->rcabin.profile_cfg_id; |
2385 | tasdevice_select_tuningprm_cfg(tas_priv, |
2386 | tas_priv->cur_prog, tas_priv->cur_conf, |
2387 | profile_cfg_id); |
2388 | } |
2389 | |
2390 | tasdevice_select_cfg_blk(tas_priv, profile_cfg_id, |
2391 | TASDEVICE_BIN_BLK_PRE_POWER_UP); |
2392 | } else |
2393 | tasdevice_select_cfg_blk(tas_priv, profile_cfg_id, |
2394 | TASDEVICE_BIN_BLK_PRE_SHUTDOWN); |
2395 | } |
2396 | EXPORT_SYMBOL_NS_GPL(tasdevice_tuning_switch, |
2397 | SND_SOC_TAS2781_FMWLIB); |
2398 | |
2399 | MODULE_DESCRIPTION("Texas Firmware Support" ); |
2400 | MODULE_AUTHOR("Shenghao Ding, TI, <shenghao-ding@ti.com>" ); |
2401 | MODULE_LICENSE("GPL" ); |
2402 | |