Unverified Commit dc8b6091 authored by Mark Brown's avatar Mark Brown
Browse files

ASoC: cs35l56: Change firmware filenames for SoundWire

Merge series from Richard Fitzgerald <rf@opensource.cirrus.com>:

Change the firmware filename format on SoundWire systems to
directly tie it to the physical amp it applies to. This is mainly
to decouple it from the ALSA prefix strings to avoid complications
when the SoundWire machine driver starts creating dailinks based on
SDCA Disco info instead of hardcoded match tables. It also avoids
errors from having to rename firmware files from a hardware-address
to a ALSA-prefix naming for Linux publication. There are already
published firmware files for the L56 B0 silicon so that has a fallback
scheme for backward compatibility which has been separated into its
own patch on top of the main change.

We'd like to get this into 6.16 so that the L63 support starts "clean"
with this new naming and we don't have to support one kernel version
with L63 using the old naming. Unfortunately we didn't manage to get
these patches through internal review and testing before the merge
window opened.
parents f5942793 fa8fae5f
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -104,6 +104,13 @@ In this example the SSID is 10280c63.

The format of the firmware file names is:

SoundWire (except CS35L56 Rev B0):
    cs35lxx-b0-dsp1-misc-SSID[-spkidX]-l?u?

SoundWire CS35L56 Rev B0:
    cs35lxx-b0-dsp1-misc-SSID[-spkidX]-ampN

Non-SoundWire (HDA and I2S):
    cs35lxx-b0-dsp1-misc-SSID[-spkidX]-ampN

Where:
@@ -111,12 +118,18 @@ Where:
  * cs35lxx-b0 is the amplifier model and silicon revision. This information
    is logged by the driver during initialization.
  * SSID is the 8-digit hexadecimal SSID value.
  * l?u? is the physical address on the SoundWire bus of the amp this
    file applies to.
  * ampN is the amplifier number (for example amp1). This is the same as
    the prefix on the ALSA control names except that it is always lower-case
    in the file name.
  * spkidX is an optional part, used for laptops that have firmware
    configurations for different makes and models of internal speakers.

The CS35L56 Rev B0 continues to use the old filename scheme because a
large number of firmware files have already been published with these
names.

Sound Open Firmware and ALSA topology files
-------------------------------------------

+10 −8
Original line number Diff line number Diff line
@@ -238,16 +238,15 @@ static const struct regmap_bus cs35l56_regmap_bus_sdw = {
	.val_format_endian_default = REGMAP_ENDIAN_BIG,
};

static int cs35l56_sdw_set_cal_index(struct cs35l56_private *cs35l56)
static int cs35l56_sdw_get_unique_id(struct cs35l56_private *cs35l56)
{
	int ret;

	/* SoundWire UniqueId is used to index the calibration array */
	ret = sdw_read_no_pm(cs35l56->sdw_peripheral, SDW_SCP_DEVID_0);
	if (ret < 0)
		return ret;

	cs35l56->base.cal_index = ret & 0xf;
	cs35l56->sdw_unique_id = ret & 0xf;

	return 0;
}
@@ -259,11 +258,13 @@ static void cs35l56_sdw_init(struct sdw_slave *peripheral)

	pm_runtime_get_noresume(cs35l56->base.dev);

	if (cs35l56->base.cal_index < 0) {
		ret = cs35l56_sdw_set_cal_index(cs35l56);
		if (ret < 0)
	ret = cs35l56_sdw_get_unique_id(cs35l56);
	if (ret)
		goto out;
	}

	/* SoundWire UniqueId is used to index the calibration array */
	if (cs35l56->base.cal_index < 0)
		cs35l56->base.cal_index = cs35l56->sdw_unique_id;

	ret = cs35l56_init(cs35l56);
	if (ret < 0) {
@@ -587,6 +588,7 @@ static int cs35l56_sdw_probe(struct sdw_slave *peripheral, const struct sdw_devi

	cs35l56->base.dev = dev;
	cs35l56->sdw_peripheral = peripheral;
	cs35l56->sdw_link_num = peripheral->bus->link_id;
	INIT_WORK(&cs35l56->sdw_irq_work, cs35l56_sdw_irq_work);

	dev_set_drvdata(dev, cs35l56);
+63 −9
Original line number Diff line number Diff line
@@ -706,17 +706,41 @@ static int cs35l56_write_cal(struct cs35l56_private *cs35l56)
	return ret;
}

static void cs35l56_reinit_patch(struct cs35l56_private *cs35l56)
static int cs35l56_dsp_download_and_power_up(struct cs35l56_private *cs35l56,
					     bool load_firmware)
{
	int ret;

	/* Use wm_adsp to load and apply the firmware patch and coefficient files */
	ret = wm_adsp_power_up(&cs35l56->dsp, true);
	/*
	 * Abort the first load if it didn't find the suffixed bins and
	 * we have an alternate fallback suffix.
	 */
	cs35l56->dsp.bin_mandatory = (load_firmware && cs35l56->fallback_fw_suffix);

	ret = wm_adsp_power_up(&cs35l56->dsp, load_firmware);
	if ((ret == -ENOENT) && cs35l56->dsp.bin_mandatory) {
		cs35l56->dsp.fwf_suffix = cs35l56->fallback_fw_suffix;
		cs35l56->fallback_fw_suffix = NULL;
		cs35l56->dsp.bin_mandatory = false;
		ret = wm_adsp_power_up(&cs35l56->dsp, load_firmware);
	}

	if (ret) {
		dev_dbg(cs35l56->base.dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret);
		return;
		dev_dbg(cs35l56->base.dev, "wm_adsp_power_up ret %d\n", ret);
		return ret;
	}

	return 0;
}

static void cs35l56_reinit_patch(struct cs35l56_private *cs35l56)
{
	int ret;

	ret = cs35l56_dsp_download_and_power_up(cs35l56, true);
	if (ret)
		return;

	cs35l56_write_cal(cs35l56);

	/* Always REINIT after applying patch or coefficients */
@@ -750,11 +774,9 @@ static void cs35l56_patch(struct cs35l56_private *cs35l56, bool firmware_missing
	 * but only if firmware is missing. If firmware is already patched just
	 * power-up wm_adsp without downloading firmware.
	 */
	ret = wm_adsp_power_up(&cs35l56->dsp, !!firmware_missing);
	if (ret) {
		dev_dbg(cs35l56->base.dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret);
	ret = cs35l56_dsp_download_and_power_up(cs35l56, firmware_missing);
	if (ret)
		goto err;
	}

	mutex_lock(&cs35l56->base.irq_lock);

@@ -853,6 +875,34 @@ static void cs35l56_dsp_work(struct work_struct *work)
	pm_runtime_put_autosuspend(cs35l56->base.dev);
}

static int cs35l56_set_fw_suffix(struct cs35l56_private *cs35l56)
{
	if (cs35l56->dsp.fwf_suffix)
		return 0;

	if (!cs35l56->sdw_peripheral)
		return 0;

	cs35l56->dsp.fwf_suffix = devm_kasprintf(cs35l56->base.dev, GFP_KERNEL,
						 "l%uu%u",
						 cs35l56->sdw_link_num,
						 cs35l56->sdw_unique_id);
	if (!cs35l56->dsp.fwf_suffix)
		return -ENOMEM;

	/*
	 * There are published firmware files for L56 B0 silicon using
	 * the ALSA prefix as the filename suffix. Default to trying these
	 * first, with the new name as an alternate.
	 */
	if ((cs35l56->base.type == 0x56) && (cs35l56->base.rev == 0xb0)) {
		cs35l56->fallback_fw_suffix = cs35l56->dsp.fwf_suffix;
		cs35l56->dsp.fwf_suffix = cs35l56->component->name_prefix;
	}

	return 0;
}

static int cs35l56_component_probe(struct snd_soc_component *component)
{
	struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
@@ -892,6 +942,10 @@ static int cs35l56_component_probe(struct snd_soc_component *component)
		return -ENOMEM;

	cs35l56->component = component;
	ret = cs35l56_set_fw_suffix(cs35l56);
	if (ret)
		return ret;

	wm_adsp2_component_probe(&cs35l56->dsp, component);

	debugfs_create_bool("init_done", 0444, debugfs_root, &cs35l56->base.init_done);
+3 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ struct cs35l56_private {
	struct snd_soc_component *component;
	struct regulator_bulk_data supplies[CS35L56_NUM_BULK_SUPPLIES];
	struct sdw_slave *sdw_peripheral;
	const char *fallback_fw_suffix;
	struct work_struct sdw_irq_work;
	bool sdw_irq_no_unmask;
	bool soft_resetting;
@@ -52,6 +53,8 @@ struct cs35l56_private {
	bool tdm_mode;
	bool sysclk_set;
	u8 old_sdw_clock_scale;
	u8 sdw_link_num;
	u8 sdw_unique_id;
};

extern const struct dev_pm_ops cs35l56_pm_ops_i2c_spi;
+18 −9
Original line number Diff line number Diff line
@@ -783,16 +783,19 @@ static int wm_adsp_request_firmware_files(struct wm_adsp *dsp,
					  char **coeff_filename)
{
	const char *system_name = dsp->system_name;
	const char *asoc_component_prefix = dsp->component->name_prefix;
	const char *suffix = dsp->component->name_prefix;
	int ret = 0;

	if (system_name && asoc_component_prefix) {
	if (dsp->fwf_suffix)
		suffix = dsp->fwf_suffix;

	if (system_name && suffix) {
		if (!wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename,
						   cirrus_dir, system_name,
						   asoc_component_prefix, "wmfw")) {
						   suffix, "wmfw")) {
			wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
						      cirrus_dir, system_name,
						      asoc_component_prefix, "bin");
						      suffix, "bin");
			return 0;
		}
	}
@@ -801,10 +804,10 @@ static int wm_adsp_request_firmware_files(struct wm_adsp *dsp,
		if (!wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename,
						   cirrus_dir, system_name,
						   NULL, "wmfw")) {
			if (asoc_component_prefix)
			if (suffix)
				wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
							      cirrus_dir, system_name,
							      asoc_component_prefix, "bin");
							      suffix, "bin");

			if (!*coeff_firmware)
				wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
@@ -816,10 +819,10 @@ static int wm_adsp_request_firmware_files(struct wm_adsp *dsp,

	/* Check system-specific bin without wmfw before falling back to generic */
	if (dsp->wmfw_optional && system_name) {
		if (asoc_component_prefix)
		if (suffix)
			wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
						      cirrus_dir, system_name,
						      asoc_component_prefix, "bin");
						      suffix, "bin");

		if (!*coeff_firmware)
			wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
@@ -850,7 +853,7 @@ static int wm_adsp_request_firmware_files(struct wm_adsp *dsp,
	adsp_err(dsp, "Failed to request firmware <%s>%s-%s-%s<-%s<%s>>.wmfw\n",
		 cirrus_dir, dsp->part,
		 dsp->fwf_name ? dsp->fwf_name : dsp->cs_dsp.name,
		 wm_adsp_fw[dsp->fw].file, system_name, asoc_component_prefix);
		 wm_adsp_fw[dsp->fw].file, system_name, suffix);

	return -ENOENT;
}
@@ -997,11 +1000,17 @@ int wm_adsp_power_up(struct wm_adsp *dsp, bool load_firmware)
			return ret;
	}

	if (dsp->bin_mandatory && !coeff_firmware) {
		ret = -ENOENT;
		goto err;
	}

	ret = cs_dsp_power_up(&dsp->cs_dsp,
			      wmfw_firmware, wmfw_filename,
			      coeff_firmware, coeff_filename,
			      wm_adsp_fw_text[dsp->fw]);

err:
	wm_adsp_release_firmware_files(dsp,
				       wmfw_firmware, wmfw_filename,
				       coeff_firmware, coeff_filename);
Loading