Commit 79b3b7c4 authored by Mark Brown's avatar Mark Brown

Merge branch 'asoc-5.2' into asoc-5.3

parents e13ef82a 1f2675f6
...@@ -283,6 +283,11 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv, ...@@ -283,6 +283,11 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv,
codec_dai = codec_dai =
dai_props->codec_dai = &priv->dais[li->dais++]; dai_props->codec_dai = &priv->dais[li->dais++];
ret = asoc_simple_parse_daifmt(dev, node, codec,
prefix, &dai_link->dai_fmt);
if (ret < 0)
goto dai_link_of_err;
simple_parse_mclk_fs(top, cpu, codec, dai_props, prefix); simple_parse_mclk_fs(top, cpu, codec, dai_props, prefix);
ret = asoc_simple_parse_cpu(cpu, dai_link, &single_cpu); ret = asoc_simple_parse_cpu(cpu, dai_link, &single_cpu);
...@@ -293,11 +298,6 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv, ...@@ -293,11 +298,6 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv,
if (ret < 0) if (ret < 0)
goto dai_link_of_err; goto dai_link_of_err;
ret = asoc_simple_parse_daifmt(dev, node, dai_link->codecs->of_node,
prefix, &dai_link->dai_fmt);
if (ret < 0)
goto dai_link_of_err;
ret = asoc_simple_parse_platform(plat, dai_link); ret = asoc_simple_parse_platform(plat, dai_link);
if (ret < 0) if (ret < 0)
goto dai_link_of_err; goto dai_link_of_err;
......
...@@ -228,7 +228,10 @@ static void soc_init_card_debugfs(struct snd_soc_card *card) ...@@ -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) static void soc_cleanup_card_debugfs(struct snd_soc_card *card)
{ {
if (!card->debugfs_card_root)
return;
debugfs_remove_recursive(card->debugfs_card_root); debugfs_remove_recursive(card->debugfs_card_root);
card->debugfs_card_root = NULL;
} }
static void snd_soc_debugfs_init(void) static void snd_soc_debugfs_init(void)
...@@ -1010,12 +1013,14 @@ static void soc_remove_link_components(struct snd_soc_card *card, ...@@ -1010,12 +1013,14 @@ static void soc_remove_link_components(struct snd_soc_card *card,
struct snd_soc_component *component; struct snd_soc_component *component;
struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_rtdcom_list *rtdcom;
mutex_lock(&client_mutex);
for_each_rtdcom(rtd, rtdcom) { for_each_rtdcom(rtd, rtdcom) {
component = rtdcom->component; component = rtdcom->component;
if (component->driver->remove_order == order) if (component->driver->remove_order == order)
soc_remove_component(component); soc_remove_component(component);
} }
mutex_unlock(&client_mutex);
} }
static void soc_remove_dai_links(struct snd_soc_card *card) static void soc_remove_dai_links(struct snd_soc_card *card)
...@@ -2035,8 +2040,10 @@ static void soc_check_tplg_fes(struct snd_soc_card *card) ...@@ -2035,8 +2040,10 @@ static void soc_check_tplg_fes(struct snd_soc_card *card)
static int soc_cleanup_card_resources(struct snd_soc_card *card) static int soc_cleanup_card_resources(struct snd_soc_card *card)
{ {
/* free the ALSA card at first; this syncs with pending operations */ /* 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); snd_card_free(card->snd_card);
card->snd_card = NULL;
}
/* remove and free each DAI */ /* remove and free each DAI */
soc_remove_dai_links(card); soc_remove_dai_links(card);
......
...@@ -2194,7 +2194,10 @@ static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w) ...@@ -2194,7 +2194,10 @@ static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
static void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm) static void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
{ {
if (!dapm->debugfs_dapm)
return;
debugfs_remove_recursive(dapm->debugfs_dapm); debugfs_remove_recursive(dapm->debugfs_dapm);
dapm->debugfs_dapm = NULL;
} }
#else #else
......
...@@ -349,6 +349,7 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, ...@@ -349,6 +349,7 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
struct snd_sof_dev *sdev = scontrol->sdev; struct snd_sof_dev *sdev = scontrol->sdev;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data; struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
struct sof_abi_hdr *data = cdata->data; struct sof_abi_hdr *data = cdata->data;
size_t size = data->size + sizeof(*data);
int ret, err; int ret, err;
if (be->max > sizeof(ucontrol->value.bytes.data)) { if (be->max > sizeof(ucontrol->value.bytes.data)) {
...@@ -358,10 +359,10 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, ...@@ -358,10 +359,10 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
return -EINVAL; return -EINVAL;
} }
if (data->size > be->max) { if (size > be->max) {
dev_err_ratelimited(sdev->dev, dev_err_ratelimited(sdev->dev,
"error: size too big %d bytes max is %d\n", "error: size too big %zu bytes max is %d\n",
data->size, be->max); size, be->max);
return -EINVAL; return -EINVAL;
} }
...@@ -375,7 +376,7 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, ...@@ -375,7 +376,7 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
} }
/* copy from 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 */ /* notify DSP of byte control updates */
snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
......
...@@ -382,7 +382,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) ...@@ -382,7 +382,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
if (IS_ERR(plat_data->pdev_mach)) { if (IS_ERR(plat_data->pdev_mach)) {
ret = PTR_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", dev_dbg(sdev->dev, "created machine %s\n",
...@@ -393,8 +393,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) ...@@ -393,8 +393,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
return 0; return 0;
comp_err: #if !IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)
snd_soc_unregister_component(sdev->dev);
fw_run_err: fw_run_err:
snd_sof_fw_unload(sdev); snd_sof_fw_unload(sdev);
fw_load_err: fw_load_err:
...@@ -403,6 +402,21 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) ...@@ -403,6 +402,21 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
snd_sof_free_debug(sdev); snd_sof_free_debug(sdev);
dbg_err: dbg_err:
snd_sof_remove(sdev); 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; return ret;
} }
...@@ -484,7 +498,6 @@ int snd_sof_device_remove(struct device *dev) ...@@ -484,7 +498,6 @@ int snd_sof_device_remove(struct device *dev)
snd_sof_ipc_free(sdev); snd_sof_ipc_free(sdev);
snd_sof_free_debug(sdev); snd_sof_free_debug(sdev);
snd_sof_free_trace(sdev); snd_sof_free_trace(sdev);
snd_sof_remove(sdev);
/* /*
* Unregister machine driver. This will unbind the snd_card which * Unregister machine driver. This will unbind the snd_card which
...@@ -494,6 +507,14 @@ int snd_sof_device_remove(struct device *dev) ...@@ -494,6 +507,14 @@ int snd_sof_device_remove(struct device *dev)
if (!IS_ERR_OR_NULL(pdata->pdev_mach)) if (!IS_ERR_OR_NULL(pdata->pdev_mach))
platform_device_unregister(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 */
release_firmware(pdata->fw); release_firmware(pdata->fw);
pdata->fw = NULL; pdata->fw = NULL;
......
...@@ -283,6 +283,8 @@ static irqreturn_t bdw_irq_thread(int irq, void *context) ...@@ -283,6 +283,8 @@ static irqreturn_t bdw_irq_thread(int irq, void *context)
SHIM_IMRX, SHIM_IMRX_DONE, SHIM_IMRX, SHIM_IMRX_DONE,
SHIM_IMRX_DONE); SHIM_IMRX_DONE);
spin_lock_irq(&sdev->ipc_lock);
/* /*
* handle immediate reply from DSP core. If the msg is * handle immediate reply from DSP core. If the msg is
* found, set done bit in cmd_done which is called at the * found, set done bit in cmd_done which is called at the
...@@ -294,6 +296,8 @@ static irqreturn_t bdw_irq_thread(int irq, void *context) ...@@ -294,6 +296,8 @@ static irqreturn_t bdw_irq_thread(int irq, void *context)
snd_sof_ipc_reply(sdev, ipcx); snd_sof_ipc_reply(sdev, ipcx);
bdw_dsp_done(sdev); bdw_dsp_done(sdev);
spin_unlock_irq(&sdev->ipc_lock);
} }
ipcd = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IPCD); ipcd = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IPCD);
...@@ -485,7 +489,6 @@ static void bdw_get_reply(struct snd_sof_dev *sdev) ...@@ -485,7 +489,6 @@ static void bdw_get_reply(struct snd_sof_dev *sdev)
{ {
struct snd_sof_ipc_msg *msg = sdev->msg; struct snd_sof_ipc_msg *msg = sdev->msg;
struct sof_ipc_reply reply; struct sof_ipc_reply reply;
unsigned long flags;
int ret = 0; int ret = 0;
/* /*
...@@ -501,8 +504,6 @@ static void bdw_get_reply(struct snd_sof_dev *sdev) ...@@ -501,8 +504,6 @@ static void bdw_get_reply(struct snd_sof_dev *sdev)
/* get reply */ /* get reply */
sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply));
spin_lock_irqsave(&sdev->ipc_lock, flags);
if (reply.error < 0) { if (reply.error < 0) {
memcpy(msg->reply_data, &reply, sizeof(reply)); memcpy(msg->reply_data, &reply, sizeof(reply));
ret = reply.error; ret = reply.error;
...@@ -521,8 +522,6 @@ static void bdw_get_reply(struct snd_sof_dev *sdev) ...@@ -521,8 +522,6 @@ static void bdw_get_reply(struct snd_sof_dev *sdev)
} }
msg->reply_error = ret; msg->reply_error = ret;
spin_unlock_irqrestore(&sdev->ipc_lock, flags);
} }
static void bdw_host_done(struct snd_sof_dev *sdev) static void bdw_host_done(struct snd_sof_dev *sdev)
......
...@@ -329,6 +329,9 @@ static irqreturn_t byt_irq_thread(int irq, void *context) ...@@ -329,6 +329,9 @@ static irqreturn_t byt_irq_thread(int irq, void *context)
SHIM_IMRX, SHIM_IMRX,
SHIM_IMRX_DONE, SHIM_IMRX_DONE,
SHIM_IMRX_DONE); SHIM_IMRX_DONE);
spin_lock_irq(&sdev->ipc_lock);
/* /*
* handle immediate reply from DSP core. If the msg is * handle immediate reply from DSP core. If the msg is
* found, set done bit in cmd_done which is called at the * found, set done bit in cmd_done which is called at the
...@@ -340,6 +343,8 @@ static irqreturn_t byt_irq_thread(int irq, void *context) ...@@ -340,6 +343,8 @@ static irqreturn_t byt_irq_thread(int irq, void *context)
snd_sof_ipc_reply(sdev, ipcx); snd_sof_ipc_reply(sdev, ipcx);
byt_dsp_done(sdev); byt_dsp_done(sdev);
spin_unlock_irq(&sdev->ipc_lock);
} }
/* new message from DSP */ /* new message from DSP */
...@@ -383,7 +388,6 @@ static void byt_get_reply(struct snd_sof_dev *sdev) ...@@ -383,7 +388,6 @@ static void byt_get_reply(struct snd_sof_dev *sdev)
{ {
struct snd_sof_ipc_msg *msg = sdev->msg; struct snd_sof_ipc_msg *msg = sdev->msg;
struct sof_ipc_reply reply; struct sof_ipc_reply reply;
unsigned long flags;
int ret = 0; int ret = 0;
/* /*
...@@ -399,8 +403,6 @@ static void byt_get_reply(struct snd_sof_dev *sdev) ...@@ -399,8 +403,6 @@ static void byt_get_reply(struct snd_sof_dev *sdev)
/* get reply */ /* get reply */
sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply));
spin_lock_irqsave(&sdev->ipc_lock, flags);
if (reply.error < 0) { if (reply.error < 0) {
memcpy(msg->reply_data, &reply, sizeof(reply)); memcpy(msg->reply_data, &reply, sizeof(reply));
ret = reply.error; ret = reply.error;
...@@ -419,8 +421,6 @@ static void byt_get_reply(struct snd_sof_dev *sdev) ...@@ -419,8 +421,6 @@ static void byt_get_reply(struct snd_sof_dev *sdev)
} }
msg->reply_error = ret; msg->reply_error = ret;
spin_unlock_irqrestore(&sdev->ipc_lock, flags);
} }
static void byt_host_done(struct snd_sof_dev *sdev) static void byt_host_done(struct snd_sof_dev *sdev)
......
...@@ -64,6 +64,8 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) ...@@ -64,6 +64,8 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
CNL_DSP_REG_HIPCCTL, CNL_DSP_REG_HIPCCTL,
CNL_DSP_REG_HIPCCTL_DONE, 0); CNL_DSP_REG_HIPCCTL_DONE, 0);
spin_lock_irq(&sdev->ipc_lock);
/* handle immediate reply from DSP core */ /* handle immediate reply from DSP core */
hda_dsp_ipc_get_reply(sdev); hda_dsp_ipc_get_reply(sdev);
snd_sof_ipc_reply(sdev, msg); snd_sof_ipc_reply(sdev, msg);
...@@ -75,6 +77,8 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) ...@@ -75,6 +77,8 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
cnl_ipc_dsp_done(sdev); cnl_ipc_dsp_done(sdev);
spin_unlock_irq(&sdev->ipc_lock);
ret = IRQ_HANDLED; ret = IRQ_HANDLED;
} }
......
...@@ -161,21 +161,105 @@ int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable) ...@@ -161,21 +161,105 @@ int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable)
return 0; 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) int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset)
{ {
struct hdac_bus *bus = sof_to_bus(sdev); 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); 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); hda_dsp_ctrl_misc_clock_gating(sdev, true);
return ret; return ret;
} }
#endif
...@@ -72,7 +72,6 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev) ...@@ -72,7 +72,6 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev)
struct snd_sof_ipc_msg *msg = sdev->msg; struct snd_sof_ipc_msg *msg = sdev->msg;
struct sof_ipc_reply reply; struct sof_ipc_reply reply;
struct sof_ipc_cmd_hdr *hdr; struct sof_ipc_cmd_hdr *hdr;
unsigned long flags;
int ret = 0; int ret = 0;
/* /*
...@@ -84,7 +83,6 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev) ...@@ -84,7 +83,6 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev)
dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n"); dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n");
return; return;
} }
spin_lock_irqsave(&sdev->ipc_lock, flags);
hdr = msg->msg_data; hdr = msg->msg_data;
if (hdr->cmd == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CTX_SAVE)) { 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) ...@@ -123,7 +121,6 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev)
out: out:
msg->reply_error = ret; msg->reply_error = ret;
spin_unlock_irqrestore(&sdev->ipc_lock, flags);
} }
static bool hda_dsp_ipc_is_sof(uint32_t msg) 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) ...@@ -172,6 +169,18 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context)
HDA_DSP_REG_HIPCCTL, HDA_DSP_REG_HIPCCTL,
HDA_DSP_REG_HIPCCTL_DONE, 0); 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 */ /* handle immediate reply from DSP core - ignore ROM messages */
if (hda_dsp_ipc_is_sof(msg)) { if (hda_dsp_ipc_is_sof(msg)) {
hda_dsp_ipc_get_reply(sdev); hda_dsp_ipc_get_reply(sdev);
...@@ -187,6 +196,8 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) ...@@ -187,6 +196,8 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context)
/* set the done bit */ /* set the done bit */
hda_dsp_ipc_dsp_done(sdev); hda_dsp_ipc_dsp_done(sdev);
spin_unlock_irq(&sdev->ipc_lock);
ret = IRQ_HANDLED; ret = IRQ_HANDLED;
} }
......
...@@ -264,9 +264,12 @@ static const char *fixup_tplg_name(struct snd_sof_dev *sdev, ...@@ -264,9 +264,12 @@ static const char *fixup_tplg_name(struct snd_sof_dev *sdev,
return tplg_filename; return tplg_filename;
} }
#endif
static int hda_init_caps(struct snd_sof_dev *sdev) static int hda_init_caps(struct snd_sof_dev *sdev)
{ {
struct hdac_bus *bus = sof_to_bus(sdev); struct hdac_bus *bus = sof_to_bus(sdev);
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
struct hdac_ext_link *hlink; struct hdac_ext_link *hlink;
struct snd_soc_acpi_mach_params *mach_params; struct snd_soc_acpi_mach_params *mach_params;
struct snd_soc_acpi_mach *hda_mach; struct snd_soc_acpi_mach *hda_mach;
...@@ -274,8 +277,9 @@ static int hda_init_caps(struct snd_sof_dev *sdev) ...@@ -274,8 +277,9 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
struct snd_soc_acpi_mach *mach; struct snd_soc_acpi_mach *mach;
const char *tplg_filename; const char *tplg_filename;
int codec_num = 0; int codec_num = 0;
int ret = 0;
int i; int i;
#endif
int ret = 0;
device_disable_async_suspend(bus->dev); device_disable_async_suspend(bus->dev);
...@@ -283,6 +287,14 @@ static int hda_init_caps(struct snd_sof_dev *sdev) ...@@ -283,6 +287,14 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
if (bus->ppcap) if (bus->ppcap)
dev_dbg(sdev->dev, "PP capability, will probe DSP later.\n"); 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) if (bus->mlcap)
snd_hdac_ext_bus_get_ml_capabilities(bus); snd_hdac_ext_bus_get_ml_capabilities(bus);
...@@ -293,12 +305,6 @@ static int hda_init_caps(struct snd_sof_dev *sdev) ...@@ -293,12 +305,6 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
return ret; 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 */ /* codec detection */
if (!bus->codec_mask) { if (!bus->codec_mask) {
dev_info(bus->dev, "no hda codecs found!\n"); dev_info(bus->dev, "no hda codecs found!\n");
...@@ -339,8 +345,10 @@ static int hda_init_caps(struct snd_sof_dev *sdev) ...@@ -339,8 +345,10 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
/* use local variable for readability */ /* use local variable for readability */
tplg_filename = pdata->tplg_filename; tplg_filename = pdata->tplg_filename;
tplg_filename = fixup_tplg_name(sdev, tplg_filename); tplg_filename = fixup_tplg_name(sdev, tplg_filename);
if (!tplg_filename) if (!tplg_filename) {
goto out; hda_codec_i915_exit(sdev);
return ret;
}
pdata->tplg_filename = tplg_filename; pdata->tplg_filename = tplg_filename;
} }
} }
...@@ -364,35 +372,10 @@ static int hda_init_caps(struct snd_sof_dev *sdev) ...@@ -364,35 +372,10 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
*/ */
list_for_each_entry(hlink, &bus->hlink_list, list) list_for_each_entry(hlink, &bus->hlink_list, list)
snd_hdac_ext_bus_link_put(bus, hlink); snd_hdac_ext_bus_link_put(bus, hlink);
#endif
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; return 0;
} }
#endif
static const struct sof_intel_dsp_desc static const struct sof_intel_dsp_desc
*get_chip_info(struct snd_sof_pdata *pdata) *get_chip_info(struct snd_sof_pdata *pdata)
{ {
...@@ -409,9 +392,8 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) ...@@ -409,9 +392,8 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
struct pci_dev *pci = to_pci_dev(sdev->dev); struct pci_dev *pci = to_pci_dev(sdev->dev);
struct sof_intel_hda_dev *hdev; struct sof_intel_hda_dev *hdev;
struct hdac_bus *bus; struct hdac_bus *bus;
struct hdac_stream *stream;
const struct sof_intel_dsp_desc *chip; const struct sof_intel_dsp_desc *chip;
int sd_offset, ret = 0; int ret = 0;
/* /*
* detect DSP by checking class/subclass/prog-id information * detect DSP by checking class/subclass/prog-id information
...@@ -562,49 +544,6 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) ...@@ -562,49 +544,6 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
if (ret < 0) if (ret < 0)
goto free_ipc_irq; 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 */ /* enable DSP features */
snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
SOF_HDA_PPCTL_GPROCEN, SOF_HDA_PPCTL_GPROCEN); SOF_HDA_PPCTL_GPROCEN, SOF_HDA_PPCTL_GPROCEN);
......
...@@ -308,19 +308,8 @@ EXPORT_SYMBOL(sof_ipc_tx_message); ...@@ -308,19 +308,8 @@ EXPORT_SYMBOL(sof_ipc_tx_message);
int snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id) int snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id)
{ {
struct snd_sof_ipc_msg *msg = &sdev->ipc->msg; 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) { if (msg->ipc_complete) {
spin_unlock_irqrestore(&sdev->ipc_lock, flags);
dev_err(sdev->dev, "error: no reply expected, received 0x%x", dev_err(sdev->dev, "error: no reply expected, received 0x%x",
msg_id); msg_id);
return -EINVAL; return -EINVAL;
...@@ -330,8 +319,6 @@ int snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id) ...@@ -330,8 +319,6 @@ int snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id)
msg->ipc_complete = true; msg->ipc_complete = true;
wake_up(&msg->waitq); wake_up(&msg->waitq);
spin_unlock_irqrestore(&sdev->ipc_lock, flags);
return 0; return 0;
} }
EXPORT_SYMBOL(snd_sof_ipc_reply); EXPORT_SYMBOL(snd_sof_ipc_reply);
......
...@@ -211,8 +211,8 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, ...@@ -211,8 +211,8 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream,
/* save pcm hw_params */ /* save pcm hw_params */
memcpy(&spcm->params[substream->stream], params, sizeof(*params)); memcpy(&spcm->params[substream->stream], params, sizeof(*params));
INIT_WORK(&spcm->stream[substream->stream].period_elapsed_work, /* clear hw_params_upon_resume flag */
sof_pcm_period_elapsed_work); spcm->hw_params_upon_resume[substream->stream] = 0;
return ret; return ret;
} }
...@@ -428,8 +428,8 @@ static int sof_pcm_open(struct snd_pcm_substream *substream) ...@@ -428,8 +428,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, dev_dbg(sdev->dev, "pcm: open stream %d dir %d\n", spcm->pcm.pcm_id,
substream->stream); substream->stream);
/* clear hw_params_upon_resume flag */ INIT_WORK(&spcm->stream[substream->stream].period_elapsed_work,
spcm->hw_params_upon_resume[substream->stream] = 0; sof_pcm_period_elapsed_work);
caps = &spcm->pcm.caps[substream->stream]; caps = &spcm->pcm.caps[substream->stream];
......
...@@ -1329,6 +1329,15 @@ static int sun4i_codec_spk_event(struct snd_soc_dapm_widget *w, ...@@ -1329,6 +1329,15 @@ static int sun4i_codec_spk_event(struct snd_soc_dapm_widget *w,
gpiod_set_value_cansleep(scodec->gpio_pa, gpiod_set_value_cansleep(scodec->gpio_pa,
!!SND_SOC_DAPM_EVENT_ON(event)); !!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; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment