ASoC: Fixes for v5.2

There's an awful lot of fixes here, almost all for the newly introduced
 SoF DSP drivers (including a few things it turned up in shared code).
 This is a large and complex piece of code so it's not surprising that
 there have been quite a few issues here, fortunately things seem to have
 mostly calmed down now.  Otherwise there's just a smattering of small fixes.
 -----BEGIN PGP SIGNATURE-----
 
 iQFHBAABCgAxFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAl0CaS4THGJyb29uaWVA
 a2VybmVsLm9yZwAKCRAk1otyXVSH0Ia0B/9wO0pSbtZjH63zg6khj+HQKuw5HG+5
 3tYMZml0c/vAmJxHCPlgGZRwRSq7rFCyJS+e4bBMCfWdjHtFuFkZtQ+jNbOxN5vf
 50/L/ixXs/iWQ4u9CV7wBUSTQgqQav4T5KWCQcYcY56hR20ubmT8K/MFTYOVIwhs
 VftWpUThi/onqgRoO08ZyKjcIoqJK9UqvNllSbCb2qY2zgCc9GmWcWbtTYKbFsLP
 czcHx9Wid0k3FlY+FqleGRyre7m1Gun94cxc3MQFOt7CO47x8gVQdMJVI+iAwRlQ
 5Fz+l+7oaYYpAgLhdrw0scHGU58C46h3KCQmAhYUk8NzqLB9ev6QGe18
 =SMgt
 -----END PGP SIGNATURE-----

Merge tag 'asoc-fix-v5.2-rc4' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus

ASoC: Fixes for v5.2

There's an awful lot of fixes here, almost all for the newly introduced
SoF DSP drivers (including a few things it turned up in shared code).
This is a large and complex piece of code so it's not surprising that
there have been quite a few issues here, fortunately things seem to have
mostly calmed down now.  Otherwise there's just a smattering of small fixes.
This commit is contained in:
Takashi Iwai 2019-06-13 17:33:34 +02:00
commit 84396d1418
42 changed files with 400 additions and 230 deletions

View File

@ -49,6 +49,7 @@ enum sof_ipc_dai_type {
SOF_DAI_INTEL_SSP, /**< Intel SSP */
SOF_DAI_INTEL_DMIC, /**< Intel DMIC */
SOF_DAI_INTEL_HDA, /**< Intel HD/A */
SOF_DAI_INTEL_SOUNDWIRE, /**< Intel SoundWire */
};
/* general purpose DAI configuration */

View File

@ -48,6 +48,7 @@
#define SOF_IPC_FW_READY SOF_GLB_TYPE(0x7U)
#define SOF_IPC_GLB_DAI_MSG SOF_GLB_TYPE(0x8U)
#define SOF_IPC_GLB_TRACE_MSG SOF_GLB_TYPE(0x9U)
#define SOF_IPC_GLB_GDB_DEBUG SOF_GLB_TYPE(0xAU)
/*
* DSP Command Message Types
@ -78,6 +79,7 @@
#define SOF_IPC_COMP_GET_VALUE SOF_CMD_TYPE(0x002)
#define SOF_IPC_COMP_SET_DATA SOF_CMD_TYPE(0x003)
#define SOF_IPC_COMP_GET_DATA SOF_CMD_TYPE(0x004)
#define SOF_IPC_COMP_NOTIFICATION SOF_CMD_TYPE(0x005)
/* DAI messages */
#define SOF_IPC_DAI_CONFIG SOF_CMD_TYPE(0x001)
@ -153,6 +155,27 @@ struct sof_ipc_compound_hdr {
uint32_t count; /**< count of 0 means end of compound sequence */
} __packed;
/**
* OOPS header architecture specific data.
*/
struct sof_ipc_dsp_oops_arch_hdr {
uint32_t arch; /* Identifier of architecture */
uint32_t totalsize; /* Total size of oops message */
} __packed;
/**
* OOPS header platform specific data.
*/
struct sof_ipc_dsp_oops_plat_hdr {
uint32_t configidhi; /* ConfigID hi 32bits */
uint32_t configidlo; /* ConfigID lo 32bits */
uint32_t numaregs; /* Special regs num */
uint32_t stackoffset; /* Offset to stack pointer from beginning of
* oops message
*/
uint32_t stackptr; /* Stack ptr */
} __packed;
/** @}*/
#endif

View File

@ -18,6 +18,14 @@
#define SOF_IPC_MAX_ELEMS 16
/*
* Firmware boot info flag bits (64-bit)
*/
#define SOF_IPC_INFO_BUILD BIT(0)
#define SOF_IPC_INFO_LOCKS BIT(1)
#define SOF_IPC_INFO_LOCKSV BIT(2)
#define SOF_IPC_INFO_GDB BIT(3)
/* extended data types that can be appended onto end of sof_ipc_fw_ready */
enum sof_ipc_ext_data {
SOF_IPC_EXT_DMA_BUFFER = 0,
@ -49,16 +57,8 @@ struct sof_ipc_fw_ready {
uint32_t hostbox_size;
struct sof_ipc_fw_version version;
/* Miscellaneous debug flags showing build/debug features enabled */
union {
uint64_t reserved;
struct {
uint64_t build:1;
uint64_t locks:1;
uint64_t locks_verbose:1;
uint64_t gdb:1;
} bits;
} debug;
/* Miscellaneous flags */
uint64_t flags;
/* reserved for future use */
uint32_t reserved[4];

View File

@ -17,7 +17,8 @@
/* Xtensa Firmware Oops data */
struct sof_ipc_dsp_oops_xtensa {
struct sof_ipc_hdr hdr;
struct sof_ipc_dsp_oops_arch_hdr arch_hdr;
struct sof_ipc_dsp_oops_plat_hdr plat_hdr;
uint32_t exccause;
uint32_t excvaddr;
uint32_t ps;
@ -38,7 +39,11 @@ struct sof_ipc_dsp_oops_xtensa {
uint32_t intenable;
uint32_t interrupt;
uint32_t sar;
uint32_t stack;
uint32_t debugcause;
uint32_t windowbase;
uint32_t windowstart;
uint32_t excsave1;
uint32_t ar[];
} __packed;
#endif

View File

@ -26,7 +26,7 @@
/* SOF ABI version major, minor and patch numbers */
#define SOF_ABI_MAJOR 3
#define SOF_ABI_MINOR 4
#define SOF_ABI_MINOR 6
#define SOF_ABI_PATCH 0
/* SOF ABI version number. Format within 32bit word is MMmmmppp */

View File

@ -170,7 +170,6 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_init);
void snd_hdac_ext_bus_device_exit(struct hdac_device *hdev)
{
snd_hdac_device_exit(hdev);
kfree(hdev);
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_exit);

View File

@ -840,7 +840,14 @@ static int snd_hda_codec_dev_free(struct snd_device *device)
if (codec->core.type == HDA_DEV_LEGACY)
snd_hdac_device_unregister(&codec->core);
codec_display_power(codec, false);
put_device(hda_codec_dev(codec));
/*
* In the case of ASoC HD-audio bus, the device refcount is released in
* snd_hdac_ext_bus_device_remove() explicitly.
*/
if (codec->core.type == HDA_DEV_LEGACY)
put_device(hda_codec_dev(codec));
return 0;
}

View File

@ -304,7 +304,10 @@ static int ak4458_rstn_control(struct snd_soc_component *component, int bit)
AK4458_00_CONTROL1,
AK4458_RSTN_MASK,
0x0);
return ret;
if (ret < 0)
return ret;
return 0;
}
static int ak4458_hw_params(struct snd_pcm_substream *substream,
@ -536,9 +539,10 @@ static void ak4458_power_on(struct ak4458_priv *ak4458)
}
}
static void ak4458_init(struct snd_soc_component *component)
static int ak4458_init(struct snd_soc_component *component)
{
struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component);
int ret;
/* External Mute ON */
if (ak4458->mute_gpiod)
@ -546,21 +550,21 @@ static void ak4458_init(struct snd_soc_component *component)
ak4458_power_on(ak4458);
snd_soc_component_update_bits(component, AK4458_00_CONTROL1,
ret = snd_soc_component_update_bits(component, AK4458_00_CONTROL1,
0x80, 0x80); /* ACKS bit = 1; 10000000 */
if (ret < 0)
return ret;
ak4458_rstn_control(component, 1);
return ak4458_rstn_control(component, 1);
}
static int ak4458_probe(struct snd_soc_component *component)
{
struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component);
ak4458_init(component);
ak4458->fs = 48000;
return 0;
return ak4458_init(component);
}
static void ak4458_remove(struct snd_soc_component *component)

View File

@ -60,7 +60,7 @@ static const struct reg_default cs4265_reg_defaults[] = {
static bool cs4265_readable_register(struct device *dev, unsigned int reg)
{
switch (reg) {
case CS4265_CHIP_ID ... CS4265_SPDIF_CTL2:
case CS4265_CHIP_ID ... CS4265_MAX_REGISTER:
return true;
default:
return false;

View File

@ -558,6 +558,7 @@ static int cs42xx8_runtime_resume(struct device *dev)
msleep(5);
regcache_cache_only(cs42xx8->regmap, false);
regcache_mark_dirty(cs42xx8->regmap);
ret = regcache_sync(cs42xx8->regmap);
if (ret) {

View File

@ -1909,6 +1909,21 @@ static int max98090_configure_dmic(struct max98090_priv *max98090,
return 0;
}
static int max98090_dai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component);
unsigned int fmt = max98090->dai_fmt;
/* Remove 24-bit format support if it is not in right justified mode. */
if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_RIGHT_J) {
substream->runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
snd_pcm_hw_constraint_msbits(substream->runtime, 0, 16, 16);
}
return 0;
}
static int max98090_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@ -2316,6 +2331,7 @@ EXPORT_SYMBOL_GPL(max98090_mic_detect);
#define MAX98090_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
static const struct snd_soc_dai_ops max98090_dai_ops = {
.startup = max98090_dai_startup,
.set_sysclk = max98090_dai_set_sysclk,
.set_fmt = max98090_dai_set_fmt,
.set_tdm_slot = max98090_set_tdm_slot,

View File

@ -405,6 +405,8 @@ static int rt274_mic_detect(struct snd_soc_component *component,
{
struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component);
rt274->jack = jack;
if (jack == NULL) {
/* Disable jack detection */
regmap_update_bits(rt274->regmap, RT274_EAPD_GPIO_IRQ_CTRL,
@ -412,7 +414,6 @@ static int rt274_mic_detect(struct snd_soc_component *component,
return 0;
}
rt274->jack = jack;
regmap_update_bits(rt274->regmap, RT274_EAPD_GPIO_IRQ_CTRL,
RT274_IRQ_EN, RT274_IRQ_EN);

View File

@ -2882,6 +2882,18 @@ static const struct dmi_system_id dmi_platform_intel_quirks[] = {
RT5670_DEV_GPIO |
RT5670_JD_MODE3),
},
{
.callback = rt5670_quirk_cb,
.ident = "Aegex 10 tablet (RU2)",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "AEGEX"),
DMI_MATCH(DMI_PRODUCT_VERSION, "RU2"),
},
.driver_data = (unsigned long *)(RT5670_DMIC_EN |
RT5670_DMIC2_INR |
RT5670_DEV_GPIO |
RT5670_JD_MODE3),
},
{}
};

View File

@ -101,7 +101,7 @@ static void rt5677_spi_reverse(u8 *dst, u32 dstlen, const u8 *src, u32 srclen)
u32 word_size = min_t(u32, dstlen, 8);
for (w = 0; w < dstlen; w += word_size) {
for (i = 0; i < word_size; i++) {
for (i = 0; i < word_size && i + w < dstlen; i++) {
si = w + word_size - i - 1;
dst[w + i] = si < srclen ? src[si] : 0;
}
@ -152,8 +152,9 @@ int rt5677_spi_read(u32 addr, void *rxbuf, size_t len)
status |= spi_sync(g_spi, &m);
mutex_unlock(&spi_mutex);
/* Copy data back to caller buffer */
rt5677_spi_reverse(cb + offset, t[1].len, body, t[1].len);
rt5677_spi_reverse(cb + offset, len - offset, body, t[1].len);
}
return status;
}

View File

@ -282,8 +282,8 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair)
return -EINVAL;
}
if ((outrate > 8000 && outrate < 30000) &&
(outrate/inrate > 24 || inrate/outrate > 8)) {
if ((outrate >= 8000 && outrate <= 30000) &&
(outrate > 24 * inrate || inrate > 8 * outrate)) {
pair_err("exceed supported ratio range [1/24, 8] for \
inrate/outrate: %d/%d\n", inrate, outrate);
return -EINVAL;

View File

@ -166,11 +166,11 @@ int sst_create_ipc_msg(struct ipc_post **arg, bool large)
{
struct ipc_post *msg;
msg = kzalloc(sizeof(*msg), GFP_KERNEL);
msg = kzalloc(sizeof(*msg), GFP_ATOMIC);
if (!msg)
return -ENOMEM;
if (large) {
msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_KERNEL);
msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_ATOMIC);
if (!msg->mailbox_data) {
kfree(msg);
return -ENOMEM;

View File

@ -495,6 +495,7 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
}
/* override plaform name, if required */
byt_cht_es8316_card.dev = dev;
platform_name = mach->mach_params.platform;
ret = snd_soc_fixup_dai_links_platform_name(&byt_cht_es8316_card,
@ -575,7 +576,6 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
(quirk & BYT_CHT_ES8316_MONO_SPEAKER) ? "mono" : "stereo",
mic_name[BYT_CHT_ES8316_MAP(quirk)]);
byt_cht_es8316_card.long_name = long_name;
byt_cht_es8316_card.dev = dev;
snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv);
ret = devm_snd_soc_register_card(dev, &byt_cht_es8316_card);

View File

@ -454,6 +454,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
}
/* override plaform name, if required */
snd_soc_card_cht.dev = &pdev->dev;
mach = (&pdev->dev)->platform_data;
platform_name = mach->mach_params.platform;
@ -463,7 +464,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
return ret_val;
/* register the soc card */
snd_soc_card_cht.dev = &pdev->dev;
snd_soc_card_set_drvdata(&snd_soc_card_cht, drv);
if (drv->quirks & QUIRK_PMC_PLT_CLK_0)

View File

@ -257,6 +257,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
snd_soc_card_set_drvdata(&snd_soc_card_cht, drv);
/* override plaform name, if required */
snd_soc_card_cht.dev = &pdev->dev;
mach = (&pdev->dev)->platform_data;
platform_name = mach->mach_params.platform;
@ -266,7 +267,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
return ret_val;
/* register the soc card */
snd_soc_card_cht.dev = &pdev->dev;
ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht);
if (ret_val) {
dev_err(&pdev->dev,

View File

@ -426,6 +426,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
}
/* override plaform name, if required */
snd_soc_card_cht.dev = &pdev->dev;
platform_name = mach->mach_params.platform;
ret_val = snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cht,
@ -443,7 +444,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
snd_soc_card_set_drvdata(&snd_soc_card_cht, drv);
/* register the soc card */
snd_soc_card_cht.dev = &pdev->dev;
ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht);
if (ret_val) {
dev_err(&pdev->dev,

View File

@ -29,9 +29,10 @@
#define SOF_RT5682_MCLK_EN BIT(3)
#define SOF_RT5682_MCLK_24MHZ BIT(4)
#define SOF_SPEAKER_AMP_PRESENT BIT(5)
#define SOF_RT5682_SSP_AMP(quirk) ((quirk) & GENMASK(8, 6))
#define SOF_RT5682_SSP_AMP_MASK (GENMASK(8, 6))
#define SOF_RT5682_SSP_AMP_SHIFT 6
#define SOF_RT5682_SSP_AMP_MASK (GENMASK(8, 6))
#define SOF_RT5682_SSP_AMP(quirk) \
(((quirk) << SOF_RT5682_SSP_AMP_SHIFT) & SOF_RT5682_SSP_AMP_MASK)
/* Default: MCLK on, MCLK 19.2M, SSP0 */
static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN |
@ -144,9 +145,9 @@ static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd)
jack = &ctx->sof_headset;
snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
ret = snd_soc_component_set_jack(component, jack, NULL);
if (ret) {

View File

@ -22,6 +22,7 @@ static unsigned long byt_machine_id;
#define BYT_THINKPAD_10 1
#define BYT_POV_P1006W 2
#define BYT_AEGEX_10 3
static int byt_thinkpad10_quirk_cb(const struct dmi_system_id *id)
{
@ -35,6 +36,12 @@ static int byt_pov_p1006w_quirk_cb(const struct dmi_system_id *id)
return 1;
}
static int byt_aegex10_quirk_cb(const struct dmi_system_id *id)
{
byt_machine_id = BYT_AEGEX_10;
return 1;
}
static const struct dmi_system_id byt_table[] = {
{
.callback = byt_thinkpad10_quirk_cb,
@ -75,9 +82,18 @@ static const struct dmi_system_id byt_table[] = {
DMI_EXACT_MATCH(DMI_BOARD_NAME, "0E57"),
},
},
{
/* Aegex 10 tablet (RU2) */
.callback = byt_aegex10_quirk_cb,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "AEGEX"),
DMI_MATCH(DMI_PRODUCT_VERSION, "RU2"),
},
},
{ }
};
/* The Thinkapd 10 and Aegex 10 tablets have the same ID problem */
static struct snd_soc_acpi_mach byt_thinkpad_10 = {
.id = "10EC5640",
.drv_name = "cht-bsw-rt5672",
@ -104,6 +120,7 @@ static struct snd_soc_acpi_mach *byt_quirk(void *arg)
switch (byt_machine_id) {
case BYT_THINKPAD_10:
case BYT_AEGEX_10:
return &byt_thinkpad_10;
case BYT_POV_P1006W:
return &byt_pov_p1006w;

View File

@ -28,12 +28,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = {
.sof_fw_filename = "sof-cnl.ri",
.sof_tplg_filename = "sof-cnl-rt274.tplg",
},
{
.id = "10EC5682",
.drv_name = "sof_rt5682",
.sof_fw_filename = "sof-cnl.ri",
.sof_tplg_filename = "sof-cml-rt5682.tplg",
},
{
.id = "MX98357A",
.drv_name = "sof_rt5682",
@ -41,6 +35,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = {
.sof_fw_filename = "sof-cnl.ri",
.sof_tplg_filename = "sof-cml-rt5682-max98357a.tplg",
},
{
.id = "10EC5682",
.drv_name = "sof_rt5682",
.sof_fw_filename = "sof-cnl.ri",
.sof_tplg_filename = "sof-cml-rt5682.tplg",
},
{},
};

View File

@ -132,7 +132,7 @@ config SND_SOC_MT8183_MT6358_TS3A227E_MAX98357A
config SND_SOC_MT8183_DA7219_MAX98357A
tristate "ASoC Audio driver for MT8183 with DA7219 MAX98357A codec"
depends on SND_SOC_MT8183
depends on SND_SOC_MT8183 && I2C
select SND_SOC_MT6358
select SND_SOC_MAX98357A
select SND_SOC_DA7219

View File

@ -228,7 +228,10 @@ static void soc_init_card_debugfs(struct snd_soc_card *card)
static void soc_cleanup_card_debugfs(struct snd_soc_card *card)
{
if (!card->debugfs_card_root)
return;
debugfs_remove_recursive(card->debugfs_card_root);
card->debugfs_card_root = NULL;
}
static void snd_soc_debugfs_init(void)
@ -2037,8 +2040,10 @@ match:
static int soc_cleanup_card_resources(struct snd_soc_card *card)
{
/* free the ALSA card at first; this syncs with pending operations */
if (card->snd_card)
if (card->snd_card) {
snd_card_free(card->snd_card);
card->snd_card = NULL;
}
/* remove and free each DAI */
soc_remove_dai_links(card);
@ -2065,6 +2070,16 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
int ret, i, order;
mutex_lock(&client_mutex);
for_each_card_prelinks(card, i, dai_link) {
ret = soc_init_dai_link(card, dai_link);
if (ret) {
soc_cleanup_platform(card);
dev_err(card->dev, "ASoC: failed to init link %s: %d\n",
dai_link->name, ret);
mutex_unlock(&client_mutex);
return ret;
}
}
mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT);
card->dapm.bias_level = SND_SOC_BIAS_OFF;
@ -2789,26 +2804,9 @@ static int snd_soc_bind_card(struct snd_soc_card *card)
*/
int snd_soc_register_card(struct snd_soc_card *card)
{
int i, ret;
struct snd_soc_dai_link *link;
if (!card->name || !card->dev)
return -EINVAL;
mutex_lock(&client_mutex);
for_each_card_prelinks(card, i, link) {
ret = soc_init_dai_link(card, link);
if (ret) {
soc_cleanup_platform(card);
dev_err(card->dev, "ASoC: failed to init link %s\n",
link->name);
mutex_unlock(&client_mutex);
return ret;
}
}
mutex_unlock(&client_mutex);
dev_set_drvdata(card->dev, card);
snd_soc_initialize_card_lists(card);
@ -2839,12 +2837,14 @@ static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister)
snd_soc_dapm_shutdown(card);
snd_soc_flush_all_delayed_work(card);
mutex_lock(&client_mutex);
/* remove all components used by DAI links on this card */
for_each_comp_order(order) {
for_each_card_rtds(card, rtd) {
soc_remove_link_components(card, rtd, order);
}
}
mutex_unlock(&client_mutex);
soc_cleanup_card_resources(card);
if (!unregister)

View File

@ -2193,7 +2193,10 @@ static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
static void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
{
if (!dapm->debugfs_dapm)
return;
debugfs_remove_recursive(dapm->debugfs_dapm);
dapm->debugfs_dapm = NULL;
}
#else
@ -3831,8 +3834,8 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
ret);
goto out;
}
source->active++;
}
source->active++;
ret = soc_dai_hw_params(&substream, params, source);
if (ret < 0)
goto out;
@ -3853,8 +3856,8 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
ret);
goto out;
}
sink->active++;
}
sink->active++;
ret = soc_dai_hw_params(&substream, params, sink);
if (ret < 0)
goto out;

View File

@ -2479,7 +2479,8 @@ int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND) &&
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
continue;
dev_dbg(be->dev, "ASoC: prepare BE %s\n",

View File

@ -44,7 +44,10 @@ config SND_SOC_SOF_OPTIONS
if SND_SOC_SOF_OPTIONS
config SND_SOC_SOF_NOCODEC
tristate "SOF nocodec mode Support"
tristate
config SND_SOC_SOF_NOCODEC_SUPPORT
bool "SOF nocodec mode support"
help
This adds support for a dummy/nocodec machine driver fallback
option if no known codec is detected. This is typically only
@ -80,7 +83,7 @@ if SND_SOC_SOF_DEBUG
config SND_SOC_SOF_FORCE_NOCODEC_MODE
bool "SOF force nocodec Mode"
depends on SND_SOC_SOF_NOCODEC
depends on SND_SOC_SOF_NOCODEC_SUPPORT
help
This forces SOF to use dummy/nocodec as machine driver, even
though there is a codec detected on the real platform. This is
@ -135,6 +138,7 @@ endif ## SND_SOC_SOF_OPTIONS
config SND_SOC_SOF
tristate
select SND_SOC_TOPOLOGY
select SND_SOC_SOF_NOCODEC if SND_SOC_SOF_NOCODEC_SUPPORT
help
This option is not user-selectable but automagically handled by
'select' statements at a higher level

View File

@ -349,6 +349,7 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
struct snd_sof_dev *sdev = scontrol->sdev;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
struct sof_abi_hdr *data = cdata->data;
size_t size = data->size + sizeof(*data);
int ret, err;
if (be->max > sizeof(ucontrol->value.bytes.data)) {
@ -358,10 +359,10 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
return -EINVAL;
}
if (data->size > be->max) {
if (size > be->max) {
dev_err_ratelimited(sdev->dev,
"error: size too big %d bytes max is %d\n",
data->size, be->max);
"error: size too big %zu bytes max is %d\n",
size, be->max);
return -EINVAL;
}
@ -375,7 +376,7 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
}
/* copy from kcontrol */
memcpy(data, ucontrol->value.bytes.data, data->size);
memcpy(data, ucontrol->value.bytes.data, size);
/* notify DSP of byte control updates */
snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,

View File

@ -382,7 +382,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
if (IS_ERR(plat_data->pdev_mach)) {
ret = PTR_ERR(plat_data->pdev_mach);
goto comp_err;
goto fw_run_err;
}
dev_dbg(sdev->dev, "created machine %s\n",
@ -393,8 +393,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
return 0;
comp_err:
snd_soc_unregister_component(sdev->dev);
#if !IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)
fw_run_err:
snd_sof_fw_unload(sdev);
fw_load_err:
@ -403,6 +402,21 @@ ipc_err:
snd_sof_free_debug(sdev);
dbg_err:
snd_sof_remove(sdev);
#else
/*
* when the probe_continue is handled in a work queue, the
* probe does not fail so we don't release resources here.
* They will be released with an explicit call to
* snd_sof_device_remove() when the PCI/ACPI device is removed
*/
fw_run_err:
fw_load_err:
ipc_err:
dbg_err:
#endif
return ret;
}
@ -484,7 +498,6 @@ int snd_sof_device_remove(struct device *dev)
snd_sof_ipc_free(sdev);
snd_sof_free_debug(sdev);
snd_sof_free_trace(sdev);
snd_sof_remove(sdev);
/*
* Unregister machine driver. This will unbind the snd_card which
@ -494,6 +507,14 @@ int snd_sof_device_remove(struct device *dev)
if (!IS_ERR_OR_NULL(pdata->pdev_mach))
platform_device_unregister(pdata->pdev_mach);
/*
* Unregistering the machine driver results in unloading the topology.
* Some widgets, ex: scheduler, attempt to power down the core they are
* scheduled on, when they are unloaded. Therefore, the DSP must be
* removed only after the topology has been unloaded.
*/
snd_sof_remove(sdev);
/* release firmware */
release_firmware(pdata->fw);
pdata->fw = NULL;

View File

@ -220,17 +220,20 @@ static void bdw_get_registers(struct snd_sof_dev *sdev,
struct sof_ipc_panic_info *panic_info,
u32 *stack, size_t stack_words)
{
/* first read regsisters */
sof_mailbox_read(sdev, sdev->dsp_oops_offset, xoops, sizeof(*xoops));
u32 offset = sdev->dsp_oops_offset;
/* first read registers */
sof_mailbox_read(sdev, offset, xoops, sizeof(*xoops));
/* note: variable AR register array is not read */
/* then get panic info */
sof_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops),
panic_info, sizeof(*panic_info));
offset += xoops->arch_hdr.totalsize;
sof_mailbox_read(sdev, offset, panic_info, sizeof(*panic_info));
/* then get the stack */
sof_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops) +
sizeof(*panic_info), stack,
stack_words * sizeof(u32));
offset += sizeof(*panic_info);
sof_mailbox_read(sdev, offset, stack, stack_words * sizeof(u32));
}
static void bdw_dump(struct snd_sof_dev *sdev, u32 flags)
@ -283,6 +286,8 @@ static irqreturn_t bdw_irq_thread(int irq, void *context)
SHIM_IMRX, SHIM_IMRX_DONE,
SHIM_IMRX_DONE);
spin_lock_irq(&sdev->ipc_lock);
/*
* handle immediate reply from DSP core. If the msg is
* found, set done bit in cmd_done which is called at the
@ -294,6 +299,8 @@ static irqreturn_t bdw_irq_thread(int irq, void *context)
snd_sof_ipc_reply(sdev, ipcx);
bdw_dsp_done(sdev);
spin_unlock_irq(&sdev->ipc_lock);
}
ipcd = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IPCD);
@ -485,7 +492,6 @@ static void bdw_get_reply(struct snd_sof_dev *sdev)
{
struct snd_sof_ipc_msg *msg = sdev->msg;
struct sof_ipc_reply reply;
unsigned long flags;
int ret = 0;
/*
@ -501,8 +507,6 @@ static void bdw_get_reply(struct snd_sof_dev *sdev)
/* get reply */
sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply));
spin_lock_irqsave(&sdev->ipc_lock, flags);
if (reply.error < 0) {
memcpy(msg->reply_data, &reply, sizeof(reply));
ret = reply.error;
@ -521,8 +525,6 @@ static void bdw_get_reply(struct snd_sof_dev *sdev)
}
msg->reply_error = ret;
spin_unlock_irqrestore(&sdev->ipc_lock, flags);
}
static void bdw_host_done(struct snd_sof_dev *sdev)

View File

@ -265,17 +265,20 @@ static void byt_get_registers(struct snd_sof_dev *sdev,
struct sof_ipc_panic_info *panic_info,
u32 *stack, size_t stack_words)
{
u32 offset = sdev->dsp_oops_offset;
/* first read regsisters */
sof_mailbox_read(sdev, sdev->dsp_oops_offset, xoops, sizeof(*xoops));
sof_mailbox_read(sdev, offset, xoops, sizeof(*xoops));
/* note: variable AR register array is not read */
/* then get panic info */
sof_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops),
panic_info, sizeof(*panic_info));
offset += xoops->arch_hdr.totalsize;
sof_mailbox_read(sdev, offset, panic_info, sizeof(*panic_info));
/* then get the stack */
sof_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops) +
sizeof(*panic_info), stack,
stack_words * sizeof(u32));
offset += sizeof(*panic_info);
sof_mailbox_read(sdev, offset, stack, stack_words * sizeof(u32));
}
static void byt_dump(struct snd_sof_dev *sdev, u32 flags)
@ -329,6 +332,9 @@ static irqreturn_t byt_irq_thread(int irq, void *context)
SHIM_IMRX,
SHIM_IMRX_DONE,
SHIM_IMRX_DONE);
spin_lock_irq(&sdev->ipc_lock);
/*
* handle immediate reply from DSP core. If the msg is
* found, set done bit in cmd_done which is called at the
@ -340,6 +346,8 @@ static irqreturn_t byt_irq_thread(int irq, void *context)
snd_sof_ipc_reply(sdev, ipcx);
byt_dsp_done(sdev);
spin_unlock_irq(&sdev->ipc_lock);
}
/* new message from DSP */
@ -383,7 +391,6 @@ static void byt_get_reply(struct snd_sof_dev *sdev)
{
struct snd_sof_ipc_msg *msg = sdev->msg;
struct sof_ipc_reply reply;
unsigned long flags;
int ret = 0;
/*
@ -399,8 +406,6 @@ static void byt_get_reply(struct snd_sof_dev *sdev)
/* get reply */
sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply));
spin_lock_irqsave(&sdev->ipc_lock, flags);
if (reply.error < 0) {
memcpy(msg->reply_data, &reply, sizeof(reply));
ret = reply.error;
@ -419,8 +424,6 @@ static void byt_get_reply(struct snd_sof_dev *sdev)
}
msg->reply_error = ret;
spin_unlock_irqrestore(&sdev->ipc_lock, flags);
}
static void byt_host_done(struct snd_sof_dev *sdev)

View File

@ -64,6 +64,8 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
CNL_DSP_REG_HIPCCTL,
CNL_DSP_REG_HIPCCTL_DONE, 0);
spin_lock_irq(&sdev->ipc_lock);
/* handle immediate reply from DSP core */
hda_dsp_ipc_get_reply(sdev);
snd_sof_ipc_reply(sdev, msg);
@ -75,6 +77,8 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
cnl_ipc_dsp_done(sdev);
spin_unlock_irq(&sdev->ipc_lock);
ret = IRQ_HANDLED;
}

View File

@ -161,21 +161,105 @@ int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable)
return 0;
}
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
/*
* While performing reset, controller may not come back properly and causing
* issues, so recommendation is to set CGCTL.MISCBDCGE to 0 then do reset
* (init chip) and then again set CGCTL.MISCBDCGE to 1
*/
int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset)
{
struct hdac_bus *bus = sof_to_bus(sdev);
int ret;
struct hdac_stream *stream;
int sd_offset, ret = 0;
if (bus->chip_init)
return 0;
hda_dsp_ctrl_misc_clock_gating(sdev, false);
ret = snd_hdac_bus_init_chip(bus, full_reset);
if (full_reset) {
/* clear WAKESTS */
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS,
SOF_HDA_WAKESTS_INT_MASK,
SOF_HDA_WAKESTS_INT_MASK);
/* reset HDA controller */
ret = hda_dsp_ctrl_link_reset(sdev, true);
if (ret < 0) {
dev_err(sdev->dev, "error: failed to reset HDA controller\n");
return ret;
}
usleep_range(500, 1000);
/* exit HDA controller reset */
ret = hda_dsp_ctrl_link_reset(sdev, false);
if (ret < 0) {
dev_err(sdev->dev, "error: failed to exit HDA controller reset\n");
return ret;
}
usleep_range(1000, 1200);
}
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
/* check to see if controller is ready */
if (!snd_hdac_chip_readb(bus, GCTL)) {
dev_dbg(bus->dev, "controller not ready!\n");
return -EBUSY;
}
/* Accept unsolicited responses */
snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL);
/* detect codecs */
if (!bus->codec_mask) {
bus->codec_mask = snd_hdac_chip_readw(bus, STATESTS);
dev_dbg(bus->dev, "codec_mask = 0x%lx\n", bus->codec_mask);
}
#endif
/* clear stream status */
list_for_each_entry(stream, &bus->stream_list, list) {
sd_offset = SOF_STREAM_SD_OFFSET(stream);
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
sd_offset +
SOF_HDA_ADSP_REG_CL_SD_STS,
SOF_HDA_CL_DMA_SD_INT_MASK,
SOF_HDA_CL_DMA_SD_INT_MASK);
}
/* clear WAKESTS */
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS,
SOF_HDA_WAKESTS_INT_MASK,
SOF_HDA_WAKESTS_INT_MASK);
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
/* clear rirb status */
snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK);
#endif
/* clear interrupt status register */
snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS,
SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_ALL_STREAM);
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
/* initialize the codec command I/O */
snd_hdac_bus_init_cmd_io(bus);
#endif
/* enable CIE and GIE interrupts */
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN,
SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN);
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
/* program the position buffer */
if (bus->use_posbuf && bus->posbuf.addr) {
snd_hdac_chip_writel(bus, DPLBASE, (u32)bus->posbuf.addr);
snd_hdac_chip_writel(bus, DPUBASE,
upper_32_bits(bus->posbuf.addr));
}
#endif
bus->chip_init = true;
hda_dsp_ctrl_misc_clock_gating(sdev, true);
return ret;
}
#endif

View File

@ -72,7 +72,6 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev)
struct snd_sof_ipc_msg *msg = sdev->msg;
struct sof_ipc_reply reply;
struct sof_ipc_cmd_hdr *hdr;
unsigned long flags;
int ret = 0;
/*
@ -84,7 +83,6 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev)
dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n");
return;
}
spin_lock_irqsave(&sdev->ipc_lock, flags);
hdr = msg->msg_data;
if (hdr->cmd == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CTX_SAVE)) {
@ -123,7 +121,6 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev)
out:
msg->reply_error = ret;
spin_unlock_irqrestore(&sdev->ipc_lock, flags);
}
static bool hda_dsp_ipc_is_sof(uint32_t msg)
@ -172,6 +169,18 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context)
HDA_DSP_REG_HIPCCTL,
HDA_DSP_REG_HIPCCTL_DONE, 0);
/*
* Make sure the interrupt thread cannot be preempted between
* waking up the sender and re-enabling the interrupt. Also
* protect against a theoretical race with sof_ipc_tx_message():
* if the DSP is fast enough to receive an IPC message, reply to
* it, and the host interrupt processing calls this function on
* a different core from the one, where the sending is taking
* place, the message might not yet be marked as expecting a
* reply.
*/
spin_lock_irq(&sdev->ipc_lock);
/* handle immediate reply from DSP core - ignore ROM messages */
if (hda_dsp_ipc_is_sof(msg)) {
hda_dsp_ipc_get_reply(sdev);
@ -187,6 +196,8 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context)
/* set the done bit */
hda_dsp_ipc_dsp_done(sdev);
spin_unlock_irq(&sdev->ipc_lock);
ret = IRQ_HANDLED;
}

View File

@ -108,17 +108,21 @@ static void hda_dsp_get_registers(struct snd_sof_dev *sdev,
struct sof_ipc_panic_info *panic_info,
u32 *stack, size_t stack_words)
{
u32 offset = sdev->dsp_oops_offset;
/* first read registers */
sof_block_read(sdev, sdev->mmio_bar, sdev->dsp_oops_offset, xoops,
sizeof(*xoops));
sof_mailbox_read(sdev, offset, xoops, sizeof(*xoops));
/* note: variable AR register array is not read */
/* then get panic info */
sof_block_read(sdev, sdev->mmio_bar, sdev->dsp_oops_offset +
sizeof(*xoops), panic_info, sizeof(*panic_info));
offset += xoops->arch_hdr.totalsize;
sof_block_read(sdev, sdev->mmio_bar, offset,
panic_info, sizeof(*panic_info));
/* then get the stack */
sof_block_read(sdev, sdev->mmio_bar, sdev->dsp_oops_offset +
sizeof(*xoops) + sizeof(*panic_info), stack,
offset += sizeof(*panic_info);
sof_block_read(sdev, sdev->mmio_bar, offset, stack,
stack_words * sizeof(u32));
}
@ -223,7 +227,9 @@ static int hda_init(struct snd_sof_dev *sdev)
/* initialise hdac bus */
bus->addr = pci_resource_start(pci, 0);
#if IS_ENABLED(CONFIG_PCI)
bus->remap_addr = pci_ioremap_bar(pci, 0);
#endif
if (!bus->remap_addr) {
dev_err(bus->dev, "error: ioremap error\n");
return -ENXIO;
@ -264,9 +270,12 @@ static const char *fixup_tplg_name(struct snd_sof_dev *sdev,
return tplg_filename;
}
#endif
static int hda_init_caps(struct snd_sof_dev *sdev)
{
struct hdac_bus *bus = sof_to_bus(sdev);
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
struct hdac_ext_link *hlink;
struct snd_soc_acpi_mach_params *mach_params;
struct snd_soc_acpi_mach *hda_mach;
@ -274,8 +283,9 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
struct snd_soc_acpi_mach *mach;
const char *tplg_filename;
int codec_num = 0;
int ret = 0;
int i;
#endif
int ret = 0;
device_disable_async_suspend(bus->dev);
@ -283,6 +293,14 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
if (bus->ppcap)
dev_dbg(sdev->dev, "PP capability, will probe DSP later.\n");
ret = hda_dsp_ctrl_init_chip(sdev, true);
if (ret < 0) {
dev_err(bus->dev, "error: init chip failed with ret: %d\n",
ret);
return ret;
}
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
if (bus->mlcap)
snd_hdac_ext_bus_get_ml_capabilities(bus);
@ -293,12 +311,6 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
return ret;
}
ret = hda_dsp_ctrl_init_chip(sdev, true);
if (ret < 0) {
dev_err(bus->dev, "error: init chip failed with ret: %d\n", ret);
goto out;
}
/* codec detection */
if (!bus->codec_mask) {
dev_info(bus->dev, "no hda codecs found!\n");
@ -339,8 +351,10 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
/* use local variable for readability */
tplg_filename = pdata->tplg_filename;
tplg_filename = fixup_tplg_name(sdev, tplg_filename);
if (!tplg_filename)
goto out;
if (!tplg_filename) {
hda_codec_i915_exit(sdev);
return ret;
}
pdata->tplg_filename = tplg_filename;
}
}
@ -364,34 +378,9 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
*/
list_for_each_entry(hlink, &bus->hlink_list, list)
snd_hdac_ext_bus_link_put(bus, hlink);
return 0;
out:
hda_codec_i915_exit(sdev);
return ret;
}
#else
static int hda_init_caps(struct snd_sof_dev *sdev)
{
/*
* set CGCTL.MISCBDCGE to 0 during reset and set back to 1
* when reset finished.
* TODO: maybe no need for init_caps?
*/
hda_dsp_ctrl_misc_clock_gating(sdev, 0);
/* clear WAKESTS */
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS,
SOF_HDA_WAKESTS_INT_MASK,
SOF_HDA_WAKESTS_INT_MASK);
return 0;
}
#endif
return 0;
}
static const struct sof_intel_dsp_desc
*get_chip_info(struct snd_sof_pdata *pdata)
@ -409,9 +398,8 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
struct pci_dev *pci = to_pci_dev(sdev->dev);
struct sof_intel_hda_dev *hdev;
struct hdac_bus *bus;
struct hdac_stream *stream;
const struct sof_intel_dsp_desc *chip;
int sd_offset, ret = 0;
int ret = 0;
/*
* detect DSP by checking class/subclass/prog-id information
@ -468,7 +456,9 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
goto hdac_bus_unmap;
/* DSP base */
#if IS_ENABLED(CONFIG_PCI)
sdev->bar[HDA_DSP_BAR] = pci_ioremap_bar(pci, HDA_DSP_BAR);
#endif
if (!sdev->bar[HDA_DSP_BAR]) {
dev_err(sdev->dev, "error: ioremap error\n");
ret = -ENXIO;
@ -558,56 +548,9 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
if (ret < 0)
goto free_ipc_irq;
/* reset HDA controller */
ret = hda_dsp_ctrl_link_reset(sdev, true);
if (ret < 0) {
dev_err(sdev->dev, "error: failed to reset HDA controller\n");
goto free_ipc_irq;
}
/* exit HDA controller reset */
ret = hda_dsp_ctrl_link_reset(sdev, false);
if (ret < 0) {
dev_err(sdev->dev, "error: failed to exit HDA controller reset\n");
goto free_ipc_irq;
}
/* clear stream status */
list_for_each_entry(stream, &bus->stream_list, list) {
sd_offset = SOF_STREAM_SD_OFFSET(stream);
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
sd_offset +
SOF_HDA_ADSP_REG_CL_SD_STS,
SOF_HDA_CL_DMA_SD_INT_MASK,
SOF_HDA_CL_DMA_SD_INT_MASK);
}
/* clear WAKESTS */
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS,
SOF_HDA_WAKESTS_INT_MASK,
SOF_HDA_WAKESTS_INT_MASK);
/* clear interrupt status register */
snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS,
SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_ALL_STREAM);
/* enable CIE and GIE interrupts */
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN,
SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN);
/* re-enable CGCTL.MISCBDCGE after reset */
hda_dsp_ctrl_misc_clock_gating(sdev, true);
device_disable_async_suspend(&pci->dev);
/* enable DSP features */
snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
SOF_HDA_PPCTL_GPROCEN, SOF_HDA_PPCTL_GPROCEN);
/* enable DSP IRQ */
snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
SOF_HDA_PPCTL_PIE, SOF_HDA_PPCTL_PIE);
/* enable ppcap interrupt */
hda_dsp_ctrl_ppcap_enable(sdev, true);
hda_dsp_ctrl_ppcap_int_enable(sdev, true);
/* initialize waitq for code loading */
init_waitqueue_head(&sdev->waitq);

View File

@ -115,7 +115,7 @@ static void ipc_log_header(struct device *dev, u8 *text, u32 cmd)
}
break;
case SOF_IPC_GLB_COMP_MSG:
str = "GLB_COMP_MSG: SET_VALUE";
str = "GLB_COMP_MSG";
switch (type) {
case SOF_IPC_COMP_SET_VALUE:
str2 = "SET_VALUE"; break;
@ -308,19 +308,8 @@ EXPORT_SYMBOL(sof_ipc_tx_message);
int snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id)
{
struct snd_sof_ipc_msg *msg = &sdev->ipc->msg;
unsigned long flags;
/*
* Protect against a theoretical race with sof_ipc_tx_message(): if the
* DSP is fast enough to receive an IPC message, reply to it, and the
* host interrupt processing calls this function on a different core
* from the one, where the sending is taking place, the message might
* not yet be marked as expecting a reply.
*/
spin_lock_irqsave(&sdev->ipc_lock, flags);
if (msg->ipc_complete) {
spin_unlock_irqrestore(&sdev->ipc_lock, flags);
dev_err(sdev->dev, "error: no reply expected, received 0x%x",
msg_id);
return -EINVAL;
@ -330,8 +319,6 @@ int snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id)
msg->ipc_complete = true;
wake_up(&msg->waitq);
spin_unlock_irqrestore(&sdev->ipc_lock, flags);
return 0;
}
EXPORT_SYMBOL(snd_sof_ipc_reply);
@ -776,16 +763,19 @@ int snd_sof_ipc_valid(struct snd_sof_dev *sdev)
}
}
if (ready->debug.bits.build) {
if (ready->flags & SOF_IPC_INFO_BUILD) {
dev_info(sdev->dev,
"Firmware debug build %d on %s-%s - options:\n"
" GDB: %s\n"
" lock debug: %s\n"
" lock vdebug: %s\n",
v->build, v->date, v->time,
ready->debug.bits.gdb ? "enabled" : "disabled",
ready->debug.bits.locks ? "enabled" : "disabled",
ready->debug.bits.locks_verbose ? "enabled" : "disabled");
ready->flags & SOF_IPC_INFO_GDB ?
"enabled" : "disabled",
ready->flags & SOF_IPC_INFO_LOCKS ?
"enabled" : "disabled",
ready->flags & SOF_IPC_INFO_LOCKSV ?
"enabled" : "disabled");
}
/* copy the fw_version into debugfs at first boot */

View File

@ -372,6 +372,8 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev)
msecs_to_jiffies(sdev->boot_timeout));
if (ret == 0) {
dev_err(sdev->dev, "error: firmware boot failure\n");
/* after this point FW_READY msg should be ignored */
sdev->boot_complete = true;
snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX |
SOF_DBG_TEXT | SOF_DBG_PCI);
return -EIO;

View File

@ -211,8 +211,8 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream,
/* save pcm hw_params */
memcpy(&spcm->params[substream->stream], params, sizeof(*params));
INIT_WORK(&spcm->stream[substream->stream].period_elapsed_work,
sof_pcm_period_elapsed_work);
/* clear hw_params_upon_resume flag */
spcm->hw_params_upon_resume[substream->stream] = 0;
return ret;
}
@ -429,8 +429,8 @@ static int sof_pcm_open(struct snd_pcm_substream *substream)
dev_dbg(sdev->dev, "pcm: open stream %d dir %d\n", spcm->pcm.pcm_id,
substream->stream);
/* clear hw_params_upon_resume flag */
spcm->hw_params_upon_resume[substream->stream] = 0;
INIT_WORK(&spcm->stream[substream->stream].period_elapsed_work,
sof_pcm_period_elapsed_work);
caps = &spcm->pcm.caps[substream->stream];

View File

@ -110,7 +110,7 @@ static void xtensa_stack(struct snd_sof_dev *sdev, void *oops, u32 *stack,
u32 stack_words)
{
struct sof_ipc_dsp_oops_xtensa *xoops = oops;
u32 stack_ptr = xoops->stack;
u32 stack_ptr = xoops->plat_hdr.stackptr;
/* 4 * 8chars + 3 ws + 1 terminating NUL */
unsigned char buf[4 * 8 + 3 + 1];
int i;

View File

@ -1329,6 +1329,15 @@ static int sun4i_codec_spk_event(struct snd_soc_dapm_widget *w,
gpiod_set_value_cansleep(scodec->gpio_pa,
!!SND_SOC_DAPM_EVENT_ON(event));
if (SND_SOC_DAPM_EVENT_ON(event)) {
/*
* Need a delay to wait for DAC to push the data. 700ms seems
* to be the best compromise not to feel this delay while
* playing a sound.
*/
msleep(700);
}
return 0;
}

View File

@ -110,7 +110,7 @@
#define SUN8I_I2S_TX_CHAN_MAP_REG 0x44
#define SUN8I_I2S_TX_CHAN_SEL_REG 0x34
#define SUN8I_I2S_TX_CHAN_OFFSET_MASK GENMASK(13, 11)
#define SUN8I_I2S_TX_CHAN_OFFSET_MASK GENMASK(13, 12)
#define SUN8I_I2S_TX_CHAN_OFFSET(offset) (offset << 12)
#define SUN8I_I2S_TX_CHAN_EN_MASK GENMASK(11, 4)
#define SUN8I_I2S_TX_CHAN_EN(num_chan) (((1 << num_chan) - 1) << 4)
@ -460,6 +460,10 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
SUN8I_I2S_TX_CHAN_OFFSET_MASK,
SUN8I_I2S_TX_CHAN_OFFSET(offset));
regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG,
SUN8I_I2S_TX_CHAN_OFFSET_MASK,
SUN8I_I2S_TX_CHAN_OFFSET(offset));
}
regmap_field_write(i2s->field_fmt_mode, val);