Skip to content

Commit 84d6a46

Browse files
Shenghao-Dingtiwai
authored andcommitted
ASoC: tas2781: Support dsp firmware Alpha and Beta seaies
For calibration, basic version does not contain any calibration addresses, it depends on calibration tool to convey the addresses to the driver. Since Alpha and Beta firmware, all the calibration addresses are saved into the firmware. Signed-off-by: Shenghao Ding <[email protected]> Reviewed-by: Mark Brown <[email protected]> Reviewed-by: Andy Shevchenko <[email protected]> Signed-off-by: Takashi Iwai <[email protected]> Link: https://patch.msgid.link/[email protected]
1 parent 1a7c306 commit 84d6a46

File tree

5 files changed

+368
-86
lines changed

5 files changed

+368
-86
lines changed

include/sound/tas2781-dsp.h

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// ALSA SoC Texas Instruments TAS2781 Audio Smart Amplifier
44
//
5-
// Copyright (C) 2022 - 2024 Texas Instruments Incorporated
5+
// Copyright (C) 2022 - 2025 Texas Instruments Incorporated
66
// https://www.ti.com
77
//
88
// The TAS2781 driver implements a flexible and configurable
@@ -30,8 +30,10 @@
3030
#define PRE_DEVICE_C 0x12
3131
#define PRE_DEVICE_D 0x16
3232

33-
#define PPC3_VERSION 0x4100
34-
#define PPC3_VERSION_TAS2781 0x14600
33+
#define PPC3_VERSION_BASE 0x4100
34+
#define PPC3_VERSION_TAS2781_BASIC_MIN 0x14600
35+
#define PPC3_VERSION_TAS2781_ALPHA_MIN 0x4a00
36+
#define PPC3_VERSION_TAS2781_BETA_MIN 0x19400
3537
#define TASDEVICE_DEVICE_SUM 8
3638
#define TASDEVICE_CONFIG_SUM 64
3739

@@ -106,6 +108,27 @@ struct tasdevice_calibration {
106108
struct tasdevice_data dev_data;
107109
};
108110

111+
struct fct_param_address {
112+
/* Thermal data for PG 1.0 device */
113+
unsigned char thr[3];
114+
/* Thermal data for PG 2.0 device */
115+
unsigned char thr2[3];
116+
/* Pilot tone enable flag, usually the sine wave */
117+
unsigned char plt_flg[3];
118+
/* Pilot tone gain for calibration */
119+
unsigned char sin_gn[3];
120+
/* Pilot tone gain for calibration */
121+
unsigned char sin_gn2[3];
122+
/* high 32-bit of real-time spk impedance */
123+
unsigned char r0_reg[3];
124+
/* check spk connection */
125+
unsigned char tf_reg[3];
126+
/* check spk resonant frequency */
127+
unsigned char a1_reg[3];
128+
/* check spk resonant frequency */
129+
unsigned char a2_reg[3];
130+
};
131+
109132
struct tasdevice_fw {
110133
struct tasdevice_dspfw_hdr fw_hdr;
111134
unsigned short nr_programs;
@@ -114,6 +137,7 @@ struct tasdevice_fw {
114137
struct tasdevice_config *configs;
115138
unsigned short nr_calibrations;
116139
struct tasdevice_calibration *calibrations;
140+
struct fct_param_address fct_par_addr;
117141
struct device *dev;
118142
};
119143

include/sound/tas2781.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,12 @@ enum audio_device {
112112
TAS2781,
113113
};
114114

115+
enum dspbin_type {
116+
TASDEV_BASIC,
117+
TASDEV_ALPHA,
118+
TASDEV_BETA,
119+
};
120+
115121
enum device_catlog_id {
116122
LENOVO = 0,
117123
OTHERS
@@ -126,6 +132,7 @@ struct bulk_reg_val {
126132

127133
struct tasdevice {
128134
struct bulk_reg_val *cali_data_backup;
135+
struct bulk_reg_val alp_cali_bckp;
129136
struct tasdevice_fw *cali_data_fmw;
130137
unsigned int dev_addr;
131138
unsigned int err_code;
@@ -171,6 +178,7 @@ struct tasdevice_priv {
171178
unsigned char dev_name[32];
172179
const char *name_prefix;
173180
unsigned char ndev;
181+
unsigned int dspbin_typ;
174182
unsigned int magic_num;
175183
unsigned int chip_id;
176184
unsigned int sysclk;
@@ -196,6 +204,9 @@ struct tasdevice_priv {
196204
int (*fw_parse_configuration_data)(struct tasdevice_priv *tas_priv,
197205
struct tasdevice_fw *tas_fmw,
198206
const struct firmware *fmw, int offset);
207+
int (*fw_parse_fct_param_address)(struct tasdevice_priv *tas_priv,
208+
struct tasdevice_fw *tas_fmw,
209+
const struct firmware *fmw, int offset);
199210
int (*tasdevice_load_block)(struct tasdevice_priv *tas_priv,
200211
struct tasdev_blk *block);
201212

sound/pci/hda/tas2781_spi_fwlib.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// TAS2781 HDA SPI driver
44
//
5-
// Copyright 2024-2025 Texas Instruments, Inc.
5+
// Copyright 2024 - 2025 Texas Instruments, Inc.
66
//
77
// Author: Baojun Xu <[email protected]>
88

@@ -370,10 +370,10 @@ static unsigned char map_dev_idx(struct tasdevice_fw *tas_fmw,
370370
int i, n = ARRAY_SIZE(non_ppc3_mapping_table);
371371
unsigned char dev_idx = 0;
372372

373-
if (fw_fixed_hdr->ppcver >= PPC3_VERSION_TAS2781) {
373+
if (fw_fixed_hdr->ppcver >= PPC3_VERSION_TAS2781_BASIC_MIN) {
374374
p = (struct blktyp_devidx_map *)ppc3_tas2781_mapping_table;
375375
n = ARRAY_SIZE(ppc3_tas2781_mapping_table);
376-
} else if (fw_fixed_hdr->ppcver >= PPC3_VERSION) {
376+
} else if (fw_fixed_hdr->ppcver >= PPC3_VERSION_BASE) {
377377
p = (struct blktyp_devidx_map *)ppc3_mapping_table;
378378
n = ARRAY_SIZE(ppc3_mapping_table);
379379
}
@@ -1605,7 +1605,7 @@ static int dspfw_default_callback(struct tasdevice_priv *tas_priv,
16051605
int rc = 0;
16061606

16071607
if (drv_ver == 0x100) {
1608-
if (ppcver >= PPC3_VERSION) {
1608+
if (ppcver >= PPC3_VERSION_BASE) {
16091609
tas_priv->fw_parse_variable_header =
16101610
fw_parse_variable_header_kernel;
16111611
tas_priv->fw_parse_program_data =

sound/soc/codecs/tas2781-fmwlib.c

Lines changed: 163 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -389,10 +389,10 @@ static unsigned char map_dev_idx(struct tasdevice_fw *tas_fmw,
389389
int i, n = ARRAY_SIZE(non_ppc3_mapping_table);
390390
unsigned char dev_idx = 0;
391391

392-
if (fw_fixed_hdr->ppcver >= PPC3_VERSION_TAS2781) {
392+
if (fw_fixed_hdr->ppcver >= PPC3_VERSION_TAS2781_BASIC_MIN) {
393393
p = (struct blktyp_devidx_map *)ppc3_tas2781_mapping_table;
394394
n = ARRAY_SIZE(ppc3_tas2781_mapping_table);
395-
} else if (fw_fixed_hdr->ppcver >= PPC3_VERSION) {
395+
} else if (fw_fixed_hdr->ppcver >= PPC3_VERSION_BASE) {
396396
p = (struct blktyp_devidx_map *)ppc3_mapping_table;
397397
n = ARRAY_SIZE(ppc3_mapping_table);
398398
}
@@ -559,6 +559,124 @@ static int fw_parse_configuration_data_kernel(
559559
return offset;
560560
}
561561

562+
static void fct_param_address_parser(struct cali_reg *r,
563+
struct tasdevice_fw *tas_fmw, const unsigned char *data)
564+
{
565+
struct fct_param_address *p = &tas_fmw->fct_par_addr;
566+
unsigned int i;
567+
568+
/*
569+
* Calibration parameters locations and data schema in dsp firmware.
570+
* The number of items are flexible, but not more than 20. The dsp tool
571+
* will reseve 20*24-byte space for fct params. In some cases, the
572+
* number of fct param is less than 20, the data will be saved from the
573+
* beginning, the rest part will be stuffed with zero.
574+
*
575+
* fct_param_num (not more than 20)
576+
* for (i = 0; i < fct_param_num; i++) {
577+
* Alias of fct param (20 bytes)
578+
* Book (1 byte)
579+
* Page (1 byte)
580+
* Offset (1 byte)
581+
* CoeffLength (1 byte) = 0x1
582+
* }
583+
* if (20 - fct_param_num)
584+
* 24*(20 - fct_param_num) pieces of '0' as stuffing
585+
*
586+
* As follow:
587+
* umg_SsmKEGCye = Book, Page, Offset, CoeffLength
588+
* iks_E0 = Book, Page, Offset, CoeffLength
589+
* yep_LsqM0 = Book, Page, Offset, CoeffLength
590+
* oyz_U0_ujx = Book, Page, Offset, CoeffLength
591+
* iks_GC_GMgq = Book, Page, Offset, CoeffLength
592+
* gou_Yao = Book, Page, Offset, CoeffLength
593+
* kgd_Wsc_Qsbp = Book, Page, Offset, CoeffLength
594+
* yec_CqseSsqs = Book, Page, Offset, CoeffLength
595+
* iks_SogkGgog2 = Book, Page, Offset, CoeffLength
596+
* yec_Sae_Y = Book, Page, Offset, CoeffLength
597+
* Re_Int = Book, Page, Offset, CoeffLength
598+
* SigFlag = Book, Page, Offset, CoeffLength
599+
* a1_Int = Book, Page, Offset, CoeffLength
600+
* a2_Int = Book, Page, Offset, CoeffLength
601+
*/
602+
for (i = 0; i < 20; i++) {
603+
const unsigned char *dat = &data[24 * i];
604+
605+
/*
606+
* check whether current fct param is empty.
607+
*/
608+
if (dat[23] != 1)
609+
break;
610+
611+
if (!strncmp(dat, "umg_SsmKEGCye", 20))
612+
r->pow_reg = TASDEVICE_REG(dat[20], dat[21], dat[22]);
613+
/* high 32-bit of real-time spk impedance */
614+
else if (!strncmp(dat, "iks_E0", 20))
615+
r->r0_reg = TASDEVICE_REG(dat[20], dat[21], dat[22]);
616+
/* inverse of real-time spk impedance */
617+
else if (!strncmp(dat, "yep_LsqM0", 20))
618+
r->invr0_reg =
619+
TASDEVICE_REG(dat[20], dat[21], dat[22]);
620+
/* low 32-bit of real-time spk impedance */
621+
else if (!strncmp(dat, "oyz_U0_ujx", 20))
622+
r->r0_low_reg =
623+
TASDEVICE_REG(dat[20], dat[21], dat[22]);
624+
/* Delta Thermal Limit */
625+
else if (!strncmp(dat, "iks_GC_GMgq", 20))
626+
r->tlimit_reg =
627+
TASDEVICE_REG(dat[20], dat[21], dat[22]);
628+
/* Thermal data for PG 1.0 device */
629+
else if (!strncmp(dat, "gou_Yao", 20))
630+
memcpy(p->thr, &dat[20], 3);
631+
/* Pilot tone enable flag, usually the sine wave */
632+
else if (!strncmp(dat, "kgd_Wsc_Qsbp", 20))
633+
memcpy(p->plt_flg, &dat[20], 3);
634+
/* Pilot tone gain for calibration */
635+
else if (!strncmp(dat, "yec_CqseSsqs", 20))
636+
memcpy(p->sin_gn, &dat[20], 3);
637+
/* Pilot tone gain for calibration, useless in PG 2.0 */
638+
else if (!strncmp(dat, "iks_SogkGgog2", 20))
639+
memcpy(p->sin_gn2, &dat[20], 3);
640+
/* Thermal data for PG 2.0 device */
641+
else if (!strncmp(dat, "yec_Sae_Y", 20))
642+
memcpy(p->thr2, &dat[20], 3);
643+
/* Spk Equivalent Resistance in fixed-point format */
644+
else if (!strncmp(dat, "Re_Int", 20))
645+
memcpy(p->r0_reg, &dat[20], 3);
646+
/* Check whether the spk connection is open */
647+
else if (!strncmp(dat, "SigFlag", 20))
648+
memcpy(p->tf_reg, &dat[20], 3);
649+
/* check spk resonant frequency */
650+
else if (!strncmp(dat, "a1_Int", 20))
651+
memcpy(p->a1_reg, &dat[20], 3);
652+
/* check spk resonant frequency */
653+
else if (!strncmp(dat, "a2_Int", 20))
654+
memcpy(p->a2_reg, &dat[20], 3);
655+
}
656+
}
657+
658+
static int fw_parse_fct_param_address(struct tasdevice_priv *tas_priv,
659+
struct tasdevice_fw *tas_fmw, const struct firmware *fmw, int offset)
660+
{
661+
struct calidata *cali_data = &tas_priv->cali_data;
662+
struct cali_reg *r = &cali_data->cali_reg_array;
663+
const unsigned char *data = fmw->data;
664+
665+
if (offset + 520 > fmw->size) {
666+
dev_err(tas_priv->dev, "%s: File Size error\n", __func__);
667+
return -EINVAL;
668+
}
669+
670+
/* skip reserved part */
671+
offset += 40;
672+
673+
fct_param_address_parser(r, tas_fmw, &data[offset]);
674+
675+
offset += 480;
676+
677+
return offset;
678+
}
679+
562680
static int fw_parse_variable_header_kernel(
563681
struct tasdevice_priv *tas_priv, const struct firmware *fmw,
564682
int offset)
@@ -1686,13 +1804,29 @@ static int tasdevice_load_block(struct tasdevice_priv *tas_priv,
16861804
return rc;
16871805
}
16881806

1807+
static void dspbin_type_check(struct tasdevice_priv *tas_priv,
1808+
unsigned int ppcver)
1809+
{
1810+
if (ppcver >= PPC3_VERSION_TAS2781_ALPHA_MIN) {
1811+
if (ppcver >= PPC3_VERSION_TAS2781_BETA_MIN)
1812+
tas_priv->dspbin_typ = TASDEV_BETA;
1813+
else if (ppcver >= PPC3_VERSION_TAS2781_BASIC_MIN)
1814+
tas_priv->dspbin_typ = TASDEV_BASIC;
1815+
else
1816+
tas_priv->dspbin_typ = TASDEV_ALPHA;
1817+
}
1818+
if (tas_priv->dspbin_typ != TASDEV_BASIC)
1819+
tas_priv->fw_parse_fct_param_address =
1820+
fw_parse_fct_param_address;
1821+
}
1822+
16891823
static int dspfw_default_callback(struct tasdevice_priv *tas_priv,
16901824
unsigned int drv_ver, unsigned int ppcver)
16911825
{
16921826
int rc = 0;
16931827

16941828
if (drv_ver == 0x100) {
1695-
if (ppcver >= PPC3_VERSION) {
1829+
if (ppcver >= PPC3_VERSION_BASE) {
16961830
tas_priv->fw_parse_variable_header =
16971831
fw_parse_variable_header_kernel;
16981832
tas_priv->fw_parse_program_data =
@@ -1701,6 +1835,7 @@ static int dspfw_default_callback(struct tasdevice_priv *tas_priv,
17011835
fw_parse_configuration_data_kernel;
17021836
tas_priv->tasdevice_load_block =
17031837
tasdevice_load_block_kernel;
1838+
dspbin_type_check(tas_priv, ppcver);
17041839
} else {
17051840
switch (ppcver) {
17061841
case 0x00:
@@ -1716,7 +1851,7 @@ static int dspfw_default_callback(struct tasdevice_priv *tas_priv,
17161851
default:
17171852
dev_err(tas_priv->dev,
17181853
"%s: PPCVer must be 0x0 or 0x%02x",
1719-
__func__, PPC3_VERSION);
1854+
__func__, PPC3_VERSION_BASE);
17201855
dev_err(tas_priv->dev, " Current:0x%02x\n",
17211856
ppcver);
17221857
rc = -EINVAL;
@@ -1952,28 +2087,25 @@ static int tasdevice_dspfw_ready(const struct firmware *fmw,
19522087
struct tasdevice_fw_fixed_hdr *fw_fixed_hdr;
19532088
struct tasdevice_fw *tas_fmw;
19542089
int offset = 0;
1955-
int ret = 0;
2090+
int ret;
19562091

19572092
if (!fmw || !fmw->data) {
19582093
dev_err(tas_priv->dev, "%s: Failed to read firmware %s\n",
19592094
__func__, tas_priv->coef_binaryname);
1960-
ret = -EINVAL;
1961-
goto out;
2095+
return -EINVAL;
19622096
}
19632097

19642098
tas_priv->fmw = kzalloc(sizeof(struct tasdevice_fw), GFP_KERNEL);
1965-
if (!tas_priv->fmw) {
1966-
ret = -ENOMEM;
1967-
goto out;
1968-
}
2099+
if (!tas_priv->fmw)
2100+
return -ENOMEM;
2101+
19692102
tas_fmw = tas_priv->fmw;
19702103
tas_fmw->dev = tas_priv->dev;
19712104
offset = fw_parse_header(tas_priv, tas_fmw, fmw, offset);
19722105

1973-
if (offset == -EINVAL) {
1974-
ret = -EINVAL;
1975-
goto out;
1976-
}
2106+
if (offset == -EINVAL)
2107+
return -EINVAL;
2108+
19772109
fw_fixed_hdr = &(tas_fmw->fw_hdr.fixed_hdr);
19782110
/* Support different versions of firmware */
19792111
switch (fw_fixed_hdr->drv_ver) {
@@ -2006,28 +2138,32 @@ static int tasdevice_dspfw_ready(const struct firmware *fmw,
20062138
ret = dspfw_default_callback(tas_priv,
20072139
fw_fixed_hdr->drv_ver, fw_fixed_hdr->ppcver);
20082140
if (ret)
2009-
goto out;
2141+
return ret;
20102142
break;
20112143
}
20122144

20132145
offset = tas_priv->fw_parse_variable_header(tas_priv, fmw, offset);
2014-
if (offset < 0) {
2015-
ret = offset;
2016-
goto out;
2017-
}
2146+
if (offset < 0)
2147+
return offset;
2148+
20182149
offset = tas_priv->fw_parse_program_data(tas_priv, tas_fmw, fmw,
20192150
offset);
2020-
if (offset < 0) {
2021-
ret = offset;
2022-
goto out;
2023-
}
2151+
if (offset < 0)
2152+
return offset;
2153+
20242154
offset = tas_priv->fw_parse_configuration_data(tas_priv,
20252155
tas_fmw, fmw, offset);
20262156
if (offset < 0)
2027-
ret = offset;
2157+
return offset;
20282158

2029-
out:
2030-
return ret;
2159+
if (tas_priv->fw_parse_fct_param_address) {
2160+
offset = tas_priv->fw_parse_fct_param_address(tas_priv,
2161+
tas_fmw, fmw, offset);
2162+
if (offset < 0)
2163+
return offset;
2164+
}
2165+
2166+
return 0;
20312167
}
20322168

20332169
int tasdevice_dsp_parser(void *context)

0 commit comments

Comments
 (0)