Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions sound/soc/sof/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -351,14 +351,6 @@ static int sof_probe(struct platform_device *pdev)
dev_dbg(sdev->dev, "created machine %s\n",
dev_name(&plat_data->pdev_mach->dev));

/* autosuspend sof device */
pm_runtime_mark_last_busy(sdev->dev);
pm_runtime_put_autosuspend(sdev->dev);

/* autosuspend pci/acpi/spi device */
pm_runtime_mark_last_busy(plat_data->dev);
pm_runtime_put_autosuspend(plat_data->dev);

return 0;

comp_err:
Expand Down
4 changes: 4 additions & 0 deletions sound/soc/sof/intel/apl.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ struct snd_sof_dsp_ops sof_apl_ops = {
/* firmware run */
.run = hda_dsp_cl_boot_firmware,

/* pre/post fw run */
.pre_fw_run = hda_dsp_pre_fw_run,
.post_fw_run = hda_dsp_post_fw_run,

/* trace callback */
.trace_init = hda_dsp_trace_init,
.trace_release = hda_dsp_trace_release,
Expand Down
4 changes: 4 additions & 0 deletions sound/soc/sof/intel/cnl.c
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,10 @@ struct snd_sof_dsp_ops sof_cnl_ops = {
/* firmware loading */
.load_firmware = hda_dsp_cl_load_fw,

/* pre/post fw run */
.pre_fw_run = hda_dsp_pre_fw_run,
.post_fw_run = hda_dsp_post_fw_run,

/* firmware run */
.run = hda_dsp_cl_boot_firmware,

Expand Down
68 changes: 39 additions & 29 deletions sound/soc/sof/intel/hda-ctrl.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <sound/sof.h>
#include <sound/pcm_params.h>
#include <linux/pm_runtime.h>
#include <sound/hda_register.h>

#include "../sof-priv.h"
#include "../ops.h"
Expand All @@ -38,49 +39,31 @@
* HDA Operations.
*/

int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev)
int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev, bool reset)
{
unsigned long timeout;
u32 gctl = 0;
u32 val;

/* reset the HDA controller */
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCTL,
SOF_HDA_GCTL_RESET, 0);

/* wait for reset */
timeout = jiffies + msecs_to_jiffies(HDA_DSP_CTRL_RESET_TIMEOUT);
while (time_before(jiffies, timeout)) {
usleep_range(500, 1000);
gctl = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCTL);
if ((gctl & SOF_HDA_GCTL_RESET) == 0)
goto clear;
}

/* reset failed */
dev_err(sdev->dev, "error: failed to reset HDA controller gctl 0x%x\n",
gctl);
return -EIO;
/* 0 to enter reset and 1 to exit reset */
val = reset ? 0 : SOF_HDA_GCTL_RESET;

clear:
/* wait for codec */
usleep_range(500, 1000);

/* now take controller out of reset */
/* enter/exit HDA controller reset */
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCTL,
SOF_HDA_GCTL_RESET, SOF_HDA_GCTL_RESET);
SOF_HDA_GCTL_RESET, val);

/* wait for controller to be ready */
/* wait to enter/exit reset */
timeout = jiffies + msecs_to_jiffies(HDA_DSP_CTRL_RESET_TIMEOUT);
while (time_before(jiffies, timeout)) {
gctl = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCTL);
if ((gctl & SOF_HDA_GCTL_RESET) == 1)
if ((gctl & SOF_HDA_GCTL_RESET) == val)
return 0;
usleep_range(500, 1000);
}

/* reset failed */
dev_err(sdev->dev, "error: failed to ready HDA controller gctl 0x%x\n",
gctl);
/* enter/exit reset failed */
dev_err(sdev->dev, "error: failed to %s HDA controller gctl 0x%x\n",
reset ? "reset" : "ready", gctl);
return -EIO;
}

Expand Down Expand Up @@ -148,6 +131,33 @@ void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable)
snd_sof_pci_update_bits(sdev, PCI_CGCTL, PCI_CGCTL_MISCBDCGE_MASK, val);
}

/*
* enable/disable audio dsp clock gating and power gating bits.
* This allows the HW to opportunistically power and clock gate
* the audio dsp when it is idle
*/
int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable)
{
struct hdac_bus *bus = sof_to_bus(sdev);
u32 val;

/* enable/disable audio dsp clock gating */
val = enable ? PCI_CGCTL_ADSPDCGE : 0;
snd_sof_pci_update_bits(sdev, PCI_CGCTL, PCI_CGCTL_ADSPDCGE, val);

#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
/* enable/disable L1 support */
val = enable ? SOF_HDA_VS_EM2_L1SEN : 0;
snd_hdac_chip_updatel(bus, VS_EM2, SOF_HDA_VS_EM2_L1SEN, val);
#endif

/* enable/disable audio dsp power gating */
val = enable ? 0 : PCI_PGCTL_ADSPPGD;
snd_sof_pci_update_bits(sdev, PCI_PGCTL, PCI_PGCTL_ADSPPGD, val);

return 0;
}

#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
/*
* While performing reset, controller may not come back properly and causing
Expand Down
28 changes: 26 additions & 2 deletions sound/soc/sof/intel/hda-dsp.c
Original file line number Diff line number Diff line change
Expand Up @@ -298,8 +298,16 @@ static int hda_suspend(struct snd_sof_dev *sdev, int state)
#endif

/* disable LP retention mode */
snd_sof_pci_update_bits(sdev, PCI_TCSEL,
PCI_CGCTL_LSRMD_MASK, PCI_CGCTL_LSRMD_MASK);
snd_sof_pci_update_bits(sdev, PCI_PGCTL,
PCI_PGCTL_LSRMD_MASK, PCI_PGCTL_LSRMD_MASK);

/* reset controller */
ret = hda_dsp_ctrl_link_reset(sdev, true);
if (ret < 0) {
dev_err(sdev->dev,
"error: failed to reset controller during suspend\n");
return ret;
}

return 0;
}
Expand Down Expand Up @@ -339,6 +347,22 @@ static int hda_resume(struct snd_sof_dev *sdev)
snd_hdac_ext_bus_ppcap_int_enable(bus, true);
#endif

/* reset controller */
ret = hda_dsp_ctrl_link_reset(sdev, true);
if (ret < 0) {
dev_err(sdev->dev,
"error: failed to reset controller during resume\n");
return ret;
}

/* take controller out of reset */
ret = hda_dsp_ctrl_link_reset(sdev, false);
if (ret < 0) {
dev_err(sdev->dev,
"error: failed to ready controller during resume\n");
return ret;
}

/* power up the DSP */
ret = hda_dsp_core_power_up(sdev, chip->cores_mask);
if (ret < 0) {
Expand Down
14 changes: 14 additions & 0 deletions sound/soc/sof/intel/hda-loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -372,3 +372,17 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
dev_err(sdev->dev, "error: load fw failed err: %d\n", ret);
return ret;
}

/* pre fw run operations */
int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev)
{
/* disable clock gating and power gating */
return hda_dsp_ctrl_clock_power_gating(sdev, false);
}

/* post fw run operations */
int hda_dsp_post_fw_run(struct snd_sof_dev *sdev)
{
/* re-enable clock gating and power gating */
return hda_dsp_ctrl_clock_power_gating(sdev, true);
}
9 changes: 8 additions & 1 deletion sound/soc/sof/intel/hda.c
Original file line number Diff line number Diff line change
Expand Up @@ -617,12 +617,19 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
goto free_ipc_irq;

/* reset HDA controller */
ret = hda_dsp_ctrl_link_reset(sdev);
ret = hda_dsp_ctrl_link_reset(sdev, true);
if (ret < 0) {
dev_err(&pci->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(&pci->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);
Expand Down
15 changes: 13 additions & 2 deletions sound/soc/sof/intel/hda.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,16 @@

/* PCI registers */
#define PCI_TCSEL 0x44
#define PCI_PGCTL PCI_TCSEL
#define PCI_CGCTL 0x48

/* PCI_PGCTL bits */
#define PCI_PGCTL_ADSPPGD BIT(2)
#define PCI_PGCTL_LSRMD_MASK BIT(4)

/* PCI_CGCTL bits */
#define PCI_CGCTL_MISCBDCGE_MASK BIT(6)
#define PCI_CGCTL_LSRMD_MASK BIT(4)
#define PCI_CGCTL_ADSPDCGE BIT(1)

/* Legacy HDA registers and bits used - widths are variable */
#define SOF_HDA_GCAP 0x0
Expand All @@ -32,6 +37,7 @@
#define SOF_HDA_WAKESTS 0x0E
#define SOF_HDA_WAKESTS_INT_MASK ((1 << 8) - 1)
#define SOF_HDA_RIRBSTS 0x5d
#define SOF_HDA_VS_EM2_L1SEN BIT(13)

/* SOF_HDA_GCTL register bist */
#define SOF_HDA_GCTL_RESET BIT(0)
Expand Down Expand Up @@ -484,12 +490,17 @@ int hda_dsp_cl_load_fw(struct snd_sof_dev *sdev, bool first_boot);
int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev);
int hda_dsp_cl_boot_firmware_skl(struct snd_sof_dev *sdev);

/* pre and post fw run ops */
int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev);
int hda_dsp_post_fw_run(struct snd_sof_dev *sdev);

/*
* HDA Controller Operations.
*/
int hda_dsp_ctrl_get_caps(struct snd_sof_dev *sdev);
int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev);
int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev, bool reset);
void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable);
int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable);
int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset);

/*
Expand Down
4 changes: 4 additions & 0 deletions sound/soc/sof/intel/skl.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ struct snd_sof_dsp_ops sof_skl_ops = {
/* firmware loading */
.load_firmware = hda_dsp_cl_load_fw,

/* pre/post fw run */
.pre_fw_run = hda_dsp_pre_fw_run,
.post_fw_run = hda_dsp_post_fw_run,

/* firmware run */
.run = hda_dsp_cl_boot_firmware_skl,

Expand Down
14 changes: 14 additions & 0 deletions sound/soc/sof/loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,13 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev)
}
}

/* perform pre fw run operations */
ret = snd_sof_dsp_pre_fw_run(sdev);
if (ret < 0) {
dev_err(sdev->dev, "error: failed pre fw run op\n");
return ret;
}

dev_dbg(sdev->dev, "booting DSP firmware\n");

/* boot the firmware on the DSP */
Expand All @@ -317,6 +324,13 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev)

dev_info(sdev->dev, "firmware boot complete\n");

/* perform post fw run operations */
ret = snd_sof_dsp_post_fw_run(sdev);
if (ret < 0) {
dev_err(sdev->dev, "error: failed post fw run op\n");
return ret;
}

return 0;
}
EXPORT_SYMBOL(snd_sof_run_firmware);
Expand Down
17 changes: 17 additions & 0 deletions sound/soc/sof/ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,23 @@ static inline int snd_sof_dsp_reset(struct snd_sof_dev *sdev)
return 0;
}

/* pre/post fw load */
static inline int snd_sof_dsp_pre_fw_run(struct snd_sof_dev *sdev)
{
if (sdev->ops->pre_fw_run)
return sdev->ops->pre_fw_run(sdev);
else
return 0;
}

static inline int snd_sof_dsp_post_fw_run(struct snd_sof_dev *sdev)
{
if (sdev->ops->post_fw_run)
return sdev->ops->post_fw_run(sdev);
else
return 0;
}

/* power management */
static inline int snd_sof_dsp_resume(struct snd_sof_dev *sdev)
{
Expand Down
4 changes: 3 additions & 1 deletion sound/soc/sof/pcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -712,7 +712,9 @@ static int sof_pcm_probe(struct snd_soc_component *component)
SND_SOF_SUSPEND_DELAY);
pm_runtime_use_autosuspend(component->dev);
pm_runtime_enable(component->dev);
err = pm_runtime_idle(component->dev);

pm_runtime_mark_last_busy(component->dev);
err = pm_runtime_put_autosuspend(component->dev);
if (err < 0)
dev_err(sdev->dev, "error: failed to enter PM idle %d\n", err);

Expand Down
11 changes: 11 additions & 0 deletions sound/soc/sof/sof-pci-dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -259,8 +259,16 @@ static int sof_pci_probe(struct pci_dev *pci,
/* allow runtime_pm */
pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY);
pm_runtime_use_autosuspend(dev);

/*
* runtime pm for pci device is "forbidden" by default.
* so call pm_runtime_allow() to enable it.
*/
pm_runtime_allow(dev);

/* follow recommendation in pci-driver.c to decrement usage counter */
pm_runtime_put_noidle(dev);

return ret;

release_regions:
Expand Down Expand Up @@ -291,6 +299,9 @@ static void sof_pci_remove(struct pci_dev *pci)
/* release firmware */
release_firmware(sof_pdata->fw);

/* follow recommendation in pci-driver.c to increment usage counter */
pm_runtime_get_noresume(&pci->dev);

/* release pci regions and disable device */
pci_release_regions(pci);
pci_disable_device(pci);
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 @@ -78,6 +78,10 @@ struct snd_sof_dsp_ops {
int (*stall)(struct snd_sof_dev *sof_dev);
int (*reset)(struct snd_sof_dev *sof_dev);

/* pre/post firmware run */
int (*pre_fw_run)(struct snd_sof_dev *sof_dev);
int (*post_fw_run)(struct snd_sof_dev *sof_dev);

/* DSP PM */
int (*suspend)(struct snd_sof_dev *sof_dev, int state);
int (*resume)(struct snd_sof_dev *sof_dev);
Expand Down