brintos

brintos / linux-shallow public Read only

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