diff --git a/drivers/soundwire/bus_type.c b/drivers/soundwire/bus_type.c index 575b9bad99d510..893296f3fe395e 100644 --- a/drivers/soundwire/bus_type.c +++ b/drivers/soundwire/bus_type.c @@ -82,6 +82,7 @@ static int sdw_drv_probe(struct device *dev) struct sdw_slave *slave = dev_to_sdw_dev(dev); struct sdw_driver *drv = drv_to_sdw_driver(dev->driver); const struct sdw_device_id *id; + const char *name; int ret; /* @@ -108,7 +109,10 @@ static int sdw_drv_probe(struct device *dev) ret = drv->probe(slave, id); if (ret) { - dev_err(dev, "Probe of %s failed: %d\n", drv->name, ret); + name = drv->name; + if (!name) + name = drv->driver.name; + dev_err(dev, "Probe of %s failed: %d\n", name, ret); dev_pm_domain_detach(dev, false); return ret; } @@ -174,11 +178,16 @@ static void sdw_drv_shutdown(struct device *dev) */ int __sdw_register_driver(struct sdw_driver *drv, struct module *owner) { + const char *name; + drv->driver.bus = &sdw_bus_type; if (!drv->probe) { - pr_err("driver %s didn't provide SDW probe routine\n", - drv->name); + name = drv->name; + if (!name) + name = drv->driver.name; + + pr_err("driver %s didn't provide SDW probe routine\n", name); return -EINVAL; } diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index 9a43c44dcbbbaa..ed92ff2573dee4 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -91,12 +91,14 @@ struct snd_soc_acpi_endpoint { /** * snd_soc_acpi_adr_device - descriptor for _ADR-enumerated device * @adr: 64 bit ACPI _ADR value + * @adr_override: used when @adr is not correct in platform firmware * @num_endpoints: number of endpoints for this device * @endpoints: array of endpoints * @name_prefix: string used for codec controls */ struct snd_soc_acpi_adr_device { const u64 adr; + const u64 adr_override; const u8 num_endpoints; const struct snd_soc_acpi_endpoint *endpoints; const char *name_prefix; diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c index afd2c3b687ccb0..25d2c0f036483e 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -7,6 +7,7 @@ // #include #include +#include #include #include #include @@ -668,16 +669,48 @@ static int rt1308_sdw_init(struct device *dev, struct regmap *regmap, return ret; } +#define RT701_WORKAROUND_LINK1 1 + +/* DMI quirks */ +static const struct dmi_system_id rt701_quirk_table[] = { + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x360 Convertible 13-aw2xxx"), + }, + .driver_data = (void *)(RT701_WORKAROUND_LINK1), + }, + {} +}; + static int rt1308_sdw_probe(struct sdw_slave *slave, const struct sdw_device_id *id) { struct regmap *regmap; + const struct dmi_system_id *dmi_id; + unsigned long link_id; + + /* only allow BIOS work-around in specific configurations */ + if (id->part_id == 0x701) { + dmi_id = dmi_first_match(rt701_quirk_table); + if (!dmi_id) { + dev_dbg(&slave->dev, "%s: probe workaround requires DMI quirk\n", __func__); + return -ENODEV; + } + link_id = (unsigned long)dmi_id->driver_data; + if (link_id != slave->bus->link_id) { + dev_dbg(&slave->dev, "%s: probe workaround on link %d not supported\n", + __func__, slave->bus->link_id); + return -ENODEV; + } + } /* Regmap Initialization */ regmap = devm_regmap_init_sdw(slave, &rt1308_sdw_regmap); if (IS_ERR(regmap)) return PTR_ERR(regmap); + slave->id.part_id = 0x1308; rt1308_sdw_init(&slave->dev, regmap, slave); return 0; @@ -685,6 +718,8 @@ static int rt1308_sdw_probe(struct sdw_slave *slave, static const struct sdw_device_id rt1308_id[] = { SDW_SLAVE_ENTRY_EXT(0x025d, 0x1308, 0x2, 0, 0), + /* fake part_id to work-around incorrect _ADR in DSDT */ + SDW_SLAVE_ENTRY_EXT(0x025d, 0x701, 0x1, 0, 0), {}, }; MODULE_DEVICE_TABLE(sdw, rt1308_id); diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c index 2beb4286d997bf..41ece32ee9bb8f 100644 --- a/sound/soc/codecs/rt711-sdw.c +++ b/sound/soc/codecs/rt711-sdw.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -438,10 +439,42 @@ static struct sdw_slave_ops rt711_slave_ops = { .bus_config = rt711_bus_config, }; +#define RT701_WORKAROUND_LINK0 0 + +/* DMI quirks */ +static const struct dmi_system_id rt701_quirk_table[] = { + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x360 Convertible 13-aw2xxx"), + }, + .driver_data = (void *)(RT701_WORKAROUND_LINK0), + + }, + {} +}; + static int rt711_sdw_probe(struct sdw_slave *slave, const struct sdw_device_id *id) { struct regmap *sdw_regmap, *regmap; + const struct dmi_system_id *dmi_id; + unsigned long link_id; + + /* only allow BIOS work-around in specific configurations */ + if (id->part_id == 0x701) { + dmi_id = dmi_first_match(rt701_quirk_table); + if (!dmi_id) { + dev_dbg(&slave->dev, "%s: probe workaround requires DMI quirk\n", __func__); + return -ENODEV; + } + link_id = (unsigned long)dmi_id->driver_data; + if (link_id != slave->bus->link_id) { + dev_dbg(&slave->dev, "%s: probe workaround on link %d not supported\n", + __func__, slave->bus->link_id); + return -ENODEV; + } + } /* Regmap Initialization */ sdw_regmap = devm_regmap_init_sdw(slave, &rt711_sdw_regmap); @@ -453,6 +486,7 @@ static int rt711_sdw_probe(struct sdw_slave *slave, if (IS_ERR(regmap)) return PTR_ERR(regmap); + slave->id.part_id = 0x711; rt711_init(&slave->dev, sdw_regmap, regmap, slave); return 0; @@ -473,6 +507,8 @@ static int rt711_sdw_remove(struct sdw_slave *slave) static const struct sdw_device_id rt711_id[] = { SDW_SLAVE_ENTRY_EXT(0x025d, 0x711, 0x2, 0, 0), + /* fake part_id to work-around incorrect _ADR in DSDT */ + SDW_SLAVE_ENTRY_EXT(0x025d, 0x701, 0x1, 0, 0), {}, }; MODULE_DEVICE_TABLE(sdw, rt711_id); diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 6daee89bb19da2..6b5c227cec6353 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -161,7 +161,15 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { .driver_data = (void *)(SOF_SDW_TGL_HDMI | SOF_SDW_PCH_DMIC | SOF_SDW_FOUR_SPK), }, - + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x360 Convertible 13-aw2xxx"), + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | SOF_SDW_PCH_DMIC | + SOF_RT711_JD_SRC_JD2), + }, {} }; @@ -424,7 +432,11 @@ static int get_sdw_dailink_info(const struct snd_soc_acpi_link_adr *links, int stream; u64 adr; - adr = link->adr_d->adr; + if (link->adr_d->adr_override) + adr = link->adr_d->adr_override; + else + adr = link->adr_d->adr; + codec_index = find_codec_info_part(adr); if (codec_index < 0) return codec_index; @@ -562,6 +574,15 @@ static int create_codec_dai_name(struct device *dev, if (!codec[comp_index].name) return -ENOMEM; + /* + * special case: we override the _ADR only here since + * the codec component name above needs to use a name + * made after the firmware _ADR. All other case + * override the _ADR directly. + */ + if (link->adr_d[i].adr_override) + adr = link->adr_d[i].adr_override; + codec_index = find_codec_info_part(adr); if (codec_index < 0) return codec_index; @@ -592,8 +613,14 @@ static int set_codec_init_func(const struct snd_soc_acpi_link_adr *link, */ for (i = 0; i < link->num_adr; i++) { int codec_index; + u64 adr; - codec_index = find_codec_info_part(link->adr_d[i].adr); + if (link->adr_d[i].adr_override) + adr = link->adr_d[i].adr_override; + else + adr = link->adr_d[i].adr; + + codec_index = find_codec_info_part(adr); if (codec_index < 0) return codec_index; @@ -707,6 +734,7 @@ static int create_sdw_dailink(struct device *dev, int *be_index, int codec_num; int stream; int ret; + u64 adr; int k; ret = get_slave_info(link, dev, cpu_dai_id, &cpu_dai_num, &codec_num, @@ -743,7 +771,12 @@ static int create_sdw_dailink(struct device *dev, int *be_index, } /* find codec info to create BE DAI */ - codec_index = find_codec_info_part(link->adr_d[0].adr); + if (link->adr_d[0].adr_override) + adr = link->adr_d[0].adr_override; + else + adr = link->adr_d[0].adr; + + codec_index = find_codec_info_part(adr); if (codec_index < 0) return codec_index; @@ -1197,6 +1230,15 @@ static int mc_probe(struct platform_device *pdev) if (!card->components) return -ENOMEM; + if (mach->mach_params.dmic_num) { + card->components = devm_kasprintf(card->dev, GFP_KERNEL, + "%s mic:dmic cfg-mics:%d", + card->components, + mach->mach_params.dmic_num); + if (!card->components) + return -ENOMEM; + } + card->long_name = sdw_card_long_name; /* Register the card */ diff --git a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c index e3ddbf05bf7296..fd438638dd3aeb 100644 --- a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c @@ -6,6 +6,7 @@ * */ +#include #include #include @@ -44,6 +45,16 @@ static const struct snd_soc_acpi_adr_device rt711_0_adr[] = { } }; +static const struct snd_soc_acpi_adr_device workaround_rt711_0_adr[] = { + { + .adr = 0x000010025D070100, + .adr_override = 0x000020025D071100, /* same as rt711_0_adr */ + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt711" + } +}; + static const struct snd_soc_acpi_adr_device rt711_1_adr[] = { { .adr = 0x000120025D071100, @@ -77,6 +88,16 @@ static const struct snd_soc_acpi_adr_device rt1308_1_single_adr[] = { } }; +static const struct snd_soc_acpi_adr_device workaround_rt1308_1_single_adr[] = { + { + .adr = 0x000110025d070100, + .adr_override = 0x000120025D130800, /* same as rt1308_1_single_adr */ + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt1308-1" + } +}; + static const struct snd_soc_acpi_adr_device rt1308_2_single_adr[] = { { .adr = 0x000220025D130800, @@ -281,6 +302,20 @@ static const struct snd_soc_acpi_link_adr tgl_sdw_rt711_link1_rt1308_link2_rt715 {} }; +static const struct snd_soc_acpi_link_adr workaround_tgl_hp[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(workaround_rt711_0_adr), + .adr_d = workaround_rt711_0_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(workaround_rt1308_1_single_adr), + .adr_d = workaround_rt1308_1_single_adr, + }, + {} +}; + static const struct snd_soc_acpi_link_adr tgl_3_in_1_sdca[] = { { .mask = BIT(0), @@ -352,6 +387,29 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = { }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_tgl_machines); +/* DMI quirks */ +static const struct dmi_system_id tgl_quirk_table[] = { + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x360 Convertible 13-aw2xxx"), + }, + }, + {} +}; + +static struct snd_soc_acpi_mach *tgl_quirk(void *arg) +{ + struct snd_soc_acpi_mach *mach = arg; + const struct dmi_system_id *dmi_id; + + dmi_id = dmi_first_match(tgl_quirk_table); + if (!dmi_id) + return NULL; + + return mach; +} + /* this table is used when there is no I2S codec present */ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_sdw_machines[] = { { @@ -401,6 +459,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_sdw_machines[] = { .drv_name = "sof_sdw", .sof_tplg_filename = "sof-tgl-rt5682.tplg", }, + /* workaround, this shall remain last to avoid matching on the wrong platforms */ + { + .link_mask = 0x3, /* rt711 on link 0 and rt1308 on link 1 */ + .links = workaround_tgl_hp, + .machine_quirk = tgl_quirk, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-tgl-rt711-rt1308.tplg", + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_tgl_sdw_machines); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 14ce0f731c688c..c000a01d8a7a18 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -505,7 +505,7 @@ static int hda_init(struct snd_sof_dev *sdev) return ret; } -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) || IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) static int check_nhlt_dmic(struct snd_sof_dev *sdev) { @@ -548,6 +548,53 @@ static const char *fixup_tplg_name(struct snd_sof_dev *sdev, return tplg_filename; } +static int dmic_topology_fixup(struct snd_sof_dev *sdev, + const char **tplg_filename, + const char *idisp_str, + int *dmic_found) +{ + const char *dmic_str; + const char *default_tplg_filename = *tplg_filename; + const char *fixed_tplg_filename; + int dmic_num; + + /* first check NHLT for DMICs */ + dmic_num = check_nhlt_dmic(sdev); + + /* allow for module parameter override */ + if (hda_dmic_num != -1) + dmic_num = hda_dmic_num; + + switch (dmic_num) { + case 1: + dmic_str = "-1ch"; + break; + case 2: + dmic_str = "-2ch"; + break; + case 3: + dmic_str = "-3ch"; + break; + case 4: + dmic_str = "-4ch"; + break; + default: + dmic_num = 0; + dmic_str = ""; + break; + } + + fixed_tplg_filename = fixup_tplg_name(sdev, default_tplg_filename, + idisp_str, dmic_str); + if (!fixed_tplg_filename) + return -EINVAL; + + dev_info(sdev->dev, "DMICs detected in NHLT tables: %d\n", dmic_num); + *dmic_found = dmic_num; + *tplg_filename = fixed_tplg_filename; + + return 0; +} #endif static int hda_init_caps(struct snd_sof_dev *sdev) @@ -917,9 +964,9 @@ static int hda_generic_machine_select(struct snd_sof_dev *sdev) struct snd_sof_pdata *pdata = sdev->pdata; const char *tplg_filename; const char *idisp_str; - const char *dmic_str; int dmic_num = 0; int codec_num = 0; + int ret; int i; /* codec detection */ @@ -945,8 +992,7 @@ static int hda_generic_machine_select(struct snd_sof_dev *sdev) hda_mach = snd_soc_acpi_intel_hda_machines; /* topology: use the info from hda_machines */ - pdata->tplg_filename = - hda_mach->sof_tplg_filename; + pdata->tplg_filename = hda_mach->sof_tplg_filename; dev_info(bus->dev, "using HDA machine driver %s now\n", hda_mach->drv_name); @@ -956,42 +1002,12 @@ static int hda_generic_machine_select(struct snd_sof_dev *sdev) else idisp_str = ""; - /* first check NHLT for DMICs */ - dmic_num = check_nhlt_dmic(sdev); - - /* allow for module parameter override */ - if (hda_dmic_num != -1) - dmic_num = hda_dmic_num; - - switch (dmic_num) { - case 1: - dmic_str = "-1ch"; - break; - case 2: - dmic_str = "-2ch"; - break; - case 3: - dmic_str = "-3ch"; - break; - case 4: - dmic_str = "-4ch"; - break; - default: - dmic_num = 0; - dmic_str = ""; - break; - } - - tplg_filename = pdata->tplg_filename; - tplg_filename = fixup_tplg_name(sdev, tplg_filename, - idisp_str, dmic_str); - if (!tplg_filename) - return -EINVAL; - - dev_info(bus->dev, - "DMICs detected in NHLT tables: %d\n", - dmic_num); + tplg_filename = hda_mach->sof_tplg_filename; + ret = dmic_topology_fixup(sdev, &tplg_filename, idisp_str, &dmic_num); + if (ret < 0) + return ret; + hda_mach->mach_params.dmic_num = dmic_num; pdata->machine = hda_mach; pdata->tplg_filename = tplg_filename; } @@ -1003,7 +1019,6 @@ static int hda_generic_machine_select(struct snd_sof_dev *sdev) &pdata->machine->mach_params; mach_params->codec_mask = bus->codec_mask; mach_params->common_hdmi_codec_drv = hda_codec_use_common_hdmi; - mach_params->dmic_num = dmic_num; } return 0; @@ -1067,7 +1082,6 @@ static int hda_sdw_machine_select(struct snd_sof_dev *sdev) { struct snd_sof_pdata *pdata = sdev->pdata; const struct snd_soc_acpi_link_adr *link; - struct hdac_bus *bus = sof_to_bus(sdev); struct snd_soc_acpi_mach *mach; struct sof_intel_hda_dev *hdev; u32 link_mask; @@ -1111,14 +1125,22 @@ static int hda_sdw_machine_select(struct snd_sof_dev *sdev) break; } /* Found if all Slaves are checked */ - if (i == hdev->info.count || !link->num_adr) + if (i == hdev->info.count || !link->num_adr) { + /* last paranoia check on machine_quirk */ + if (mach->machine_quirk) { + struct snd_soc_acpi_mach *mach_alt; + + mach_alt = mach->machine_quirk(mach); + if (!mach_alt) + continue; /* not full match, ignore */ + mach = mach_alt; + } break; + } } if (mach && mach->link_mask) { - dev_dbg(bus->dev, - "SoundWire machine driver %s topology %s\n", - mach->drv_name, - mach->sof_tplg_filename); + int dmic_num = 0; + pdata->machine = mach; mach->mach_params.links = mach->links; mach->mach_params.link_mask = mach->link_mask; @@ -1128,6 +1150,25 @@ static int hda_sdw_machine_select(struct snd_sof_dev *sdev) else pdata->fw_filename = pdata->desc->default_fw_filename; pdata->tplg_filename = mach->sof_tplg_filename; + + /* see if DMICs are pin-muxed with SoundWire link 2 and 3 */ + if (!(mach->link_mask & GENMASK(3, 2))) { + const char *tplg_filename = mach->sof_tplg_filename; + int ret; + + ret = dmic_topology_fixup(sdev, &tplg_filename, "", &dmic_num); + + if (ret < 0) + return ret; + + pdata->tplg_filename = tplg_filename; + } + mach->mach_params.dmic_num = dmic_num; + + dev_dbg(sdev->dev, + "SoundWire machine driver %s topology %s\n", + mach->drv_name, + pdata->tplg_filename); } else { dev_info(sdev->dev, "No SoundWire machine driver found\n");