Skip to content

Commit 6f8ad04

Browse files
rfvirgilbroonie
authored andcommitted
ALSA: hda: cs35l56: Firmware file must match the version of preloaded firmware
Check whether the firmware is already patched. If so, include the firmware version in the firmware file name. If the firmware has already been patched by the BIOS the driver can only replace it if it has control of hard RESET. If the driver cannot replace the firmware, it can still load a wmfw (for ALSA control definitions) and/or a bin (for additional tunings). But these must match the version of firmware that is running on the CS35L56. The firmware is pre-patched if either: - FIRMWARE_MISSING == 0, or - it is a secured CS35L56 (which implies that is was already patched), cs35l56_hw_init() will set preloaded_fw_ver to the (non-zero) firmware version if either of these conditions is true. Normal (unpatched or replaceable firmware): cs35l56-rev-dsp1-misc[-system_name].[wmfw|bin] Preloaded firmware: cs35l56-rev[-s]-VVVVVV-dsp1-misc[-system_name].[wmfw|bin] Where: [-s] is an optional -s added into the name for a secured CS35L56 VVVVVV is the 24-bit firmware version in hexadecimal. Backport note: This won't apply to kernel versions older than v6.6. Signed-off-by: Richard Fitzgerald <rf@opensource.cirrus.com> Fixes: 73cfbfa ("ALSA: hda/cs35l56: Add driver for Cirrus Logic CS35L56 amplifier") Link: https://msgid.link/r/20240129162737.497-18-rf@opensource.cirrus.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent e82bc51 commit 6f8ad04

File tree

1 file changed

+49
-44
lines changed

1 file changed

+49
-44
lines changed

sound/pci/hda/cs35l56_hda.c

Lines changed: 49 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -397,28 +397,21 @@ static const struct cs_dsp_client_ops cs35l56_hda_client_ops = {
397397

398398
static int cs35l56_hda_request_firmware_file(struct cs35l56_hda *cs35l56,
399399
const struct firmware **firmware, char **filename,
400-
const char *dir, const char *system_name,
400+
const char *base_name, const char *system_name,
401401
const char *amp_name,
402402
const char *filetype)
403403
{
404404
char *s, c;
405405
int ret = 0;
406406

407407
if (system_name && amp_name)
408-
*filename = kasprintf(GFP_KERNEL, "%scs35l56-%02x%s-dsp1-misc-%s-%s.%s", dir,
409-
cs35l56->base.rev,
410-
cs35l56->base.secured ? "-s" : "",
408+
*filename = kasprintf(GFP_KERNEL, "%s-%s-%s.%s", base_name,
411409
system_name, amp_name, filetype);
412410
else if (system_name)
413-
*filename = kasprintf(GFP_KERNEL, "%scs35l56-%02x%s-dsp1-misc-%s.%s", dir,
414-
cs35l56->base.rev,
415-
cs35l56->base.secured ? "-s" : "",
411+
*filename = kasprintf(GFP_KERNEL, "%s-%s.%s", base_name,
416412
system_name, filetype);
417413
else
418-
*filename = kasprintf(GFP_KERNEL, "%scs35l56-%02x%s-dsp1-misc.%s", dir,
419-
cs35l56->base.rev,
420-
cs35l56->base.secured ? "-s" : "",
421-
filetype);
414+
*filename = kasprintf(GFP_KERNEL, "%s.%s", base_name, filetype);
422415

423416
if (!*filename)
424417
return -ENOMEM;
@@ -451,38 +444,52 @@ static int cs35l56_hda_request_firmware_file(struct cs35l56_hda *cs35l56,
451444
return 0;
452445
}
453446

454-
static const char cirrus_dir[] = "cirrus/";
455447
static void cs35l56_hda_request_firmware_files(struct cs35l56_hda *cs35l56,
448+
unsigned int preloaded_fw_ver,
456449
const struct firmware **wmfw_firmware,
457450
char **wmfw_filename,
458451
const struct firmware **coeff_firmware,
459452
char **coeff_filename)
460453
{
461454
const char *system_name = cs35l56->system_name;
462455
const char *amp_name = cs35l56->amp_name;
456+
char base_name[37];
463457
int ret;
464458

459+
if (preloaded_fw_ver) {
460+
snprintf(base_name, sizeof(base_name),
461+
"cirrus/cs35l56-%02x%s-%06x-dsp1-misc",
462+
cs35l56->base.rev,
463+
cs35l56->base.secured ? "-s" : "",
464+
preloaded_fw_ver & 0xffffff);
465+
} else {
466+
snprintf(base_name, sizeof(base_name),
467+
"cirrus/cs35l56-%02x%s-dsp1-misc",
468+
cs35l56->base.rev,
469+
cs35l56->base.secured ? "-s" : "");
470+
}
471+
465472
if (system_name && amp_name) {
466473
if (!cs35l56_hda_request_firmware_file(cs35l56, wmfw_firmware, wmfw_filename,
467-
cirrus_dir, system_name, amp_name, "wmfw")) {
474+
base_name, system_name, amp_name, "wmfw")) {
468475
cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
469-
cirrus_dir, system_name, amp_name, "bin");
476+
base_name, system_name, amp_name, "bin");
470477
return;
471478
}
472479
}
473480

474481
if (system_name) {
475482
if (!cs35l56_hda_request_firmware_file(cs35l56, wmfw_firmware, wmfw_filename,
476-
cirrus_dir, system_name, NULL, "wmfw")) {
483+
base_name, system_name, NULL, "wmfw")) {
477484
if (amp_name)
478485
cs35l56_hda_request_firmware_file(cs35l56,
479486
coeff_firmware, coeff_filename,
480-
cirrus_dir, system_name,
487+
base_name, system_name,
481488
amp_name, "bin");
482489
if (!*coeff_firmware)
483490
cs35l56_hda_request_firmware_file(cs35l56,
484491
coeff_firmware, coeff_filename,
485-
cirrus_dir, system_name,
492+
base_name, system_name,
486493
NULL, "bin");
487494
return;
488495
}
@@ -493,26 +500,26 @@ static void cs35l56_hda_request_firmware_files(struct cs35l56_hda *cs35l56,
493500
*/
494501
if (amp_name)
495502
cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
496-
cirrus_dir, system_name, amp_name, "bin");
503+
base_name, system_name, amp_name, "bin");
497504
if (!*coeff_firmware)
498505
cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
499-
cirrus_dir, system_name, NULL, "bin");
506+
base_name, system_name, NULL, "bin");
500507

501508
if (*coeff_firmware)
502509
return;
503510
}
504511

505512
ret = cs35l56_hda_request_firmware_file(cs35l56, wmfw_firmware, wmfw_filename,
506-
cirrus_dir, NULL, NULL, "wmfw");
513+
base_name, NULL, NULL, "wmfw");
507514
if (!ret) {
508515
cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
509-
cirrus_dir, NULL, NULL, "bin");
516+
base_name, NULL, NULL, "bin");
510517
return;
511518
}
512519

513520
if (!*coeff_firmware)
514521
cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
515-
cirrus_dir, NULL, NULL, "bin");
522+
base_name, NULL, NULL, "bin");
516523
}
517524

518525
static void cs35l56_hda_release_firmware_files(const struct firmware *wmfw_firmware,
@@ -546,7 +553,8 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)
546553
const struct firmware *wmfw_firmware = NULL;
547554
char *coeff_filename = NULL;
548555
char *wmfw_filename = NULL;
549-
unsigned int firmware_missing;
556+
unsigned int preloaded_fw_ver;
557+
bool firmware_missing;
550558
int ret = 0;
551559

552560
/* Prepare for a new DSP power-up */
@@ -557,24 +565,21 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)
557565

558566
pm_runtime_get_sync(cs35l56->base.dev);
559567

560-
ret = regmap_read(cs35l56->base.regmap, CS35L56_PROTECTION_STATUS, &firmware_missing);
561-
if (ret) {
562-
dev_err(cs35l56->base.dev, "Failed to read PROTECTION_STATUS: %d\n", ret);
568+
/*
569+
* The firmware can only be upgraded if it is currently running
570+
* from the built-in ROM. If not, the wmfw/bin must be for the
571+
* version of firmware that is running on the chip.
572+
*/
573+
ret = cs35l56_read_prot_status(&cs35l56->base, &firmware_missing, &preloaded_fw_ver);
574+
if (ret)
563575
goto err_pm_put;
564-
}
565576

566-
firmware_missing &= CS35L56_FIRMWARE_MISSING;
577+
if (firmware_missing)
578+
preloaded_fw_ver = 0;
567579

568-
/*
569-
* Firmware can only be downloaded if the CS35L56 is secured or is
570-
* running from the built-in ROM. If it is secured the BIOS will have
571-
* downloaded firmware, and the wmfw/bin files will only contain
572-
* tunings that are safe to download with the firmware running.
573-
*/
574-
if (cs35l56->base.secured || firmware_missing) {
575-
cs35l56_hda_request_firmware_files(cs35l56, &wmfw_firmware, &wmfw_filename,
576-
&coeff_firmware, &coeff_filename);
577-
}
580+
cs35l56_hda_request_firmware_files(cs35l56, preloaded_fw_ver,
581+
&wmfw_firmware, &wmfw_filename,
582+
&coeff_firmware, &coeff_filename);
578583

579584
/*
580585
* If the BIOS didn't patch the firmware a bin file is mandatory to
@@ -589,12 +594,12 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)
589594
mutex_lock(&cs35l56->base.irq_lock);
590595

591596
/*
592-
* When the device is running in secure mode the firmware files can
593-
* only contain insecure tunings and therefore we do not need to
594-
* shutdown the firmware to apply them and can use the lower cost
595-
* reinit sequence instead.
597+
* If the firmware hasn't been patched it must be shutdown before
598+
* doing a full patch and reset afterwards. If it is already
599+
* running a patched version the firmware files only contain
600+
* tunings and we can use the lower cost reinit sequence instead.
596601
*/
597-
if (!cs35l56->base.secured && (wmfw_firmware || coeff_firmware)) {
602+
if (firmware_missing && (wmfw_firmware || coeff_firmware)) {
598603
ret = cs35l56_firmware_shutdown(&cs35l56->base);
599604
if (ret)
600605
goto err;
@@ -613,7 +618,7 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)
613618
if (coeff_filename)
614619
dev_dbg(cs35l56->base.dev, "Loaded Coefficients: %s\n", coeff_filename);
615620

616-
if (cs35l56->base.secured) {
621+
if (!firmware_missing) {
617622
ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_REINIT);
618623
if (ret)
619624
goto err_powered_up;

0 commit comments

Comments
 (0)