Skip to content

Commit

Permalink
ASoC: SOF: Intel: override mclk_id for ES8336 support
Browse files Browse the repository at this point in the history
Merge series from Pierre-Louis Bossart <[email protected]>:

This patchset solves a known issue with ES8336 platforms wrt MCLK
selection. Most of the devices use the MCLK0 signal, but some devices
do use the MCLK1 signal.

The MCLK is defined in the topology, it would be a nightmare to
generate more topology files just for one MCLK difference. With a
minor extension to the intel-nhlt library, the MCLK information can be
found by parsing the NHLT table, and we can override the mclk_id at
boot time.

The only known issues for this platform remain the detection of GPIO
and microphone connections, currently only possible with manual
quirks.

Thanks to Eugene J. Markow for testing this patchset.
  • Loading branch information
broonie committed Sep 20, 2022
2 parents 78091ed + d925277 commit 3c193b5
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 5 deletions.
7 changes: 7 additions & 0 deletions include/sound/intel-nhlt.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ bool intel_nhlt_has_endpoint_type(struct nhlt_acpi_table *nhlt, u8 link_type);

int intel_nhlt_ssp_endpoint_mask(struct nhlt_acpi_table *nhlt, u8 device_type);

int intel_nhlt_ssp_mclk_mask(struct nhlt_acpi_table *nhlt, int ssp_num);

struct nhlt_specific_cfg *
intel_nhlt_get_endpoint_blob(struct device *dev, struct nhlt_acpi_table *nhlt,
u32 bus_id, u8 link_type, u8 vbps, u8 bps,
Expand Down Expand Up @@ -169,6 +171,11 @@ static inline int intel_nhlt_ssp_endpoint_mask(struct nhlt_acpi_table *nhlt, u8
return 0;
}

static inline int intel_nhlt_ssp_mclk_mask(struct nhlt_acpi_table *nhlt, int ssp_num)
{
return 0;
}

static inline struct nhlt_specific_cfg *
intel_nhlt_get_endpoint_blob(struct device *dev, struct nhlt_acpi_table *nhlt,
u32 bus_id, u8 link_type, u8 vbps, u8 bps,
Expand Down
79 changes: 79 additions & 0 deletions sound/hda/intel-nhlt.c
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,85 @@ int intel_nhlt_ssp_endpoint_mask(struct nhlt_acpi_table *nhlt, u8 device_type)
}
EXPORT_SYMBOL(intel_nhlt_ssp_endpoint_mask);

#define SSP_BLOB_V1_0_SIZE 84
#define SSP_BLOB_V1_0_MDIVC_OFFSET 19 /* offset in u32 */

#define SSP_BLOB_V1_5_SIZE 96
#define SSP_BLOB_V1_5_MDIVC_OFFSET 21 /* offset in u32 */
#define SSP_BLOB_VER_1_5 0xEE000105

#define SSP_BLOB_V2_0_SIZE 88
#define SSP_BLOB_V2_0_MDIVC_OFFSET 20 /* offset in u32 */
#define SSP_BLOB_VER_2_0 0xEE000200

int intel_nhlt_ssp_mclk_mask(struct nhlt_acpi_table *nhlt, int ssp_num)
{
struct nhlt_endpoint *epnt;
struct nhlt_fmt *fmt;
struct nhlt_fmt_cfg *cfg;
int mclk_mask = 0;
int i, j;

if (!nhlt)
return 0;

epnt = (struct nhlt_endpoint *)nhlt->desc;
for (i = 0; i < nhlt->endpoint_count; i++) {

/* we only care about endpoints connected to an audio codec over SSP */
if (epnt->linktype == NHLT_LINK_SSP &&
epnt->device_type == NHLT_DEVICE_I2S &&
epnt->virtual_bus_id == ssp_num) {

fmt = (struct nhlt_fmt *)(epnt->config.caps + epnt->config.size);
cfg = fmt->fmt_config;

/*
* In theory all formats should use the same MCLK but it doesn't hurt to
* double-check that the configuration is consistent
*/
for (j = 0; j < fmt->fmt_count; j++) {
u32 *blob;
int mdivc_offset;
int size;

/* first check we have enough data to read the blob type */
if (cfg->config.size < 8)
return -EINVAL;

blob = (u32 *)cfg->config.caps;

if (blob[1] == SSP_BLOB_VER_2_0) {
mdivc_offset = SSP_BLOB_V2_0_MDIVC_OFFSET;
size = SSP_BLOB_V2_0_SIZE;
} else if (blob[1] == SSP_BLOB_VER_1_5) {
mdivc_offset = SSP_BLOB_V1_5_MDIVC_OFFSET;
size = SSP_BLOB_V1_5_SIZE;
} else {
mdivc_offset = SSP_BLOB_V1_0_MDIVC_OFFSET;
size = SSP_BLOB_V1_0_SIZE;
}

/* make sure we have enough data for the fixed part of the blob */
if (cfg->config.size < size)
return -EINVAL;

mclk_mask |= blob[mdivc_offset] & GENMASK(1, 0);

cfg = (struct nhlt_fmt_cfg *)(cfg->config.caps + cfg->config.size);
}
}
epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length);
}

/* make sure only one MCLK is used */
if (hweight_long(mclk_mask) != 1)
return -EINVAL;

return mclk_mask;
}
EXPORT_SYMBOL(intel_nhlt_ssp_mclk_mask);

static struct nhlt_specific_cfg *
nhlt_get_specific_cfg(struct device *dev, struct nhlt_fmt *fmt, u8 num_ch,
u32 rate, u8 vbps, u8 bps)
Expand Down
39 changes: 39 additions & 0 deletions sound/soc/sof/intel/hda.c
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,10 @@ static int dmic_num_override = -1;
module_param_named(dmic_num, dmic_num_override, int, 0444);
MODULE_PARM_DESC(dmic_num, "SOF HDA DMIC number");

static int mclk_id_override = -1;
module_param_named(mclk_id, mclk_id_override, int, 0444);
MODULE_PARM_DESC(mclk_id, "SOF SSP mclk_id");

#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
static bool hda_codec_use_common_hdmi = IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI);
module_param_named(use_common_hdmi, hda_codec_use_common_hdmi, bool, 0444);
Expand Down Expand Up @@ -752,6 +756,18 @@ static int check_nhlt_ssp_mask(struct snd_sof_dev *sdev)
return ssp_mask;
}

static int check_nhlt_ssp_mclk_mask(struct snd_sof_dev *sdev, int ssp_num)
{
struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
struct nhlt_acpi_table *nhlt;

nhlt = hdev->nhlt;
if (!nhlt)
return 0;

return intel_nhlt_ssp_mclk_mask(nhlt, ssp_num);
}

#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) || IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)

static const char *fixup_tplg_name(struct snd_sof_dev *sdev,
Expand Down Expand Up @@ -1540,6 +1556,7 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
mach->mach_params.i2s_link_mask) {
const struct sof_intel_dsp_desc *chip = get_chip_info(sdev->pdata);
int ssp_num;
int mclk_mask;

if (hweight_long(mach->mach_params.i2s_link_mask) > 1 &&
!(mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_SSP_MSB))
Expand All @@ -1564,6 +1581,21 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)

sof_pdata->tplg_filename = tplg_filename;
add_extension = true;

mclk_mask = check_nhlt_ssp_mclk_mask(sdev, ssp_num);

if (mclk_mask < 0) {
dev_err(sdev->dev, "Invalid MCLK configuration\n");
return NULL;
}

dev_dbg(sdev->dev, "MCLK mask %#x found in NHLT\n", mclk_mask);

if (mclk_mask) {
dev_info(sdev->dev, "Overriding topology with MCLK mask %#x from NHLT\n", mclk_mask);
sdev->mclk_id_override = true;
sdev->mclk_id_quirk = (mclk_mask & BIT(0)) ? 0 : 1;
}
}

if (tplg_fixup && add_extension) {
Expand All @@ -1576,6 +1608,13 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)

sof_pdata->tplg_filename = tplg_filename;
}

/* check if mclk_id should be modified from topology defaults */
if (mclk_id_override >= 0) {
dev_info(sdev->dev, "Overriding topology with MCLK %d from kernel_parameter\n", mclk_id_override);
sdev->mclk_id_override = true;
sdev->mclk_id_quirk = mclk_id_override;
}
}

/*
Expand Down
2 changes: 2 additions & 0 deletions sound/soc/sof/intel/hda.h
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,8 @@
#define APL_SSP_COUNT 6
#define CNL_SSP_COUNT 3
#define ICL_SSP_COUNT 6
#define TGL_SSP_COUNT 3
#define MTL_SSP_COUNT 3

/* SSP Registers */
#define SSP_SSC1_OFFSET 0x4
Expand Down
2 changes: 1 addition & 1 deletion sound/soc/sof/intel/mtl.c
Original file line number Diff line number Diff line change
Expand Up @@ -785,7 +785,7 @@ const struct sof_intel_dsp_desc mtl_chip_info = {
.ipc_ctl = MTL_DSP_REG_HFIPCXCTL,
.rom_status_reg = MTL_DSP_ROM_STS,
.rom_init_timeout = 300,
.ssp_count = ICL_SSP_COUNT,
.ssp_count = MTL_SSP_COUNT,
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
.sdw_shim_base = SDW_SHIM_BASE_ACE,
.sdw_alh_base = SDW_ALH_BASE_ACE,
Expand Down
8 changes: 4 additions & 4 deletions sound/soc/sof/intel/tgl.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ const struct sof_intel_dsp_desc tgl_chip_info = {
.ipc_ctl = CNL_DSP_REG_HIPCCTL,
.rom_status_reg = HDA_DSP_SRAM_REG_ROM_STATUS,
.rom_init_timeout = 300,
.ssp_count = ICL_SSP_COUNT,
.ssp_count = TGL_SSP_COUNT,
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
.sdw_shim_base = SDW_SHIM_BASE,
.sdw_alh_base = SDW_ALH_BASE,
Expand All @@ -146,7 +146,7 @@ const struct sof_intel_dsp_desc tglh_chip_info = {
.ipc_ctl = CNL_DSP_REG_HIPCCTL,
.rom_status_reg = HDA_DSP_SRAM_REG_ROM_STATUS,
.rom_init_timeout = 300,
.ssp_count = ICL_SSP_COUNT,
.ssp_count = TGL_SSP_COUNT,
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
.sdw_shim_base = SDW_SHIM_BASE,
.sdw_alh_base = SDW_ALH_BASE,
Expand All @@ -169,7 +169,7 @@ const struct sof_intel_dsp_desc ehl_chip_info = {
.ipc_ctl = CNL_DSP_REG_HIPCCTL,
.rom_status_reg = HDA_DSP_SRAM_REG_ROM_STATUS,
.rom_init_timeout = 300,
.ssp_count = ICL_SSP_COUNT,
.ssp_count = TGL_SSP_COUNT,
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
.sdw_shim_base = SDW_SHIM_BASE,
.sdw_alh_base = SDW_ALH_BASE,
Expand All @@ -192,7 +192,7 @@ const struct sof_intel_dsp_desc adls_chip_info = {
.ipc_ctl = CNL_DSP_REG_HIPCCTL,
.rom_status_reg = HDA_DSP_SRAM_REG_ROM_STATUS,
.rom_init_timeout = 300,
.ssp_count = ICL_SSP_COUNT,
.ssp_count = TGL_SSP_COUNT,
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
.sdw_shim_base = SDW_SHIM_BASE,
.sdw_alh_base = SDW_ALH_BASE,
Expand Down
7 changes: 7 additions & 0 deletions sound/soc/sof/ipc3-topology.c
Original file line number Diff line number Diff line change
Expand Up @@ -1249,6 +1249,7 @@ static int sof_link_afe_load(struct snd_soc_component *scomp, struct snd_sof_dai
static int sof_link_ssp_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
{
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
struct sof_dai_private_data *private = dai->private;
u32 size = sizeof(*config);
Expand All @@ -1273,6 +1274,12 @@ static int sof_link_ssp_load(struct snd_soc_component *scomp, struct snd_sof_dai

config[i].hdr.size = size;

if (sdev->mclk_id_override) {
dev_dbg(scomp->dev, "tplg: overriding topology mclk_id %d by quirk %d\n",
config[i].ssp.mclk_id, sdev->mclk_id_quirk);
config[i].ssp.mclk_id = sdev->mclk_id_quirk;
}

/* copy differentiating hw configs to ipc structs */
config[i].ssp.mclk_rate = le32_to_cpu(hw_config[i].mclk_rate);
config[i].ssp.bclk_rate = le32_to_cpu(hw_config[i].bclk_rate);
Expand Down
4 changes: 4 additions & 0 deletions sound/soc/sof/sof-priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,10 @@ struct snd_sof_dev {
/* to protect the ipc_rx_handler_list and dsp_state_handler_list list */
struct mutex client_event_handler_mutex;

/* quirks to override topology values */
bool mclk_id_override;
u16 mclk_id_quirk; /* same size as in IPC3 definitions */

void *private; /* core does not touch this */
};

Expand Down

0 comments on commit 3c193b5

Please sign in to comment.