Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 150
PM related changes#249
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
PM related changes #249
Changes from all commits
cfb997aa4c7e27d69b39ef41dd300ffb067a7c6900File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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" | ||
| @@ -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; | ||
ranj063 marked this conversation as resolved.
Outdated
Uh oh!There was an error while loading. Please reload this page. | ||
| /* 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; | ||
| } | ||
| @@ -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 | ||
plbossart marked this conversation as resolved.
Outdated
Uh oh!There was an error while loading. Please reload this page. | ||
| /* 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 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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); | ||
plbossart marked this conversation as resolved.
Outdated
Uh oh!There was an error while loading. Please reload this page. | ||
| /* 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; | ||
| } | ||
| @@ -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; | ||
ranj063 marked this conversation as resolved.
Outdated
Uh oh!There was an error while loading. Please reload this page. | ||
| } | ||
| /* 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) { | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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, | ||
ranj063 marked this conversation as resolved.
Outdated
Uh oh!There was an error while loading. Please reload this page. | ||
| .post_fw_run = hda_dsp_post_fw_run, | ||
| /* firmware run */ | ||
| .run = hda_dsp_cl_boot_firmware_skl, | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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) { | ||
plbossart marked this conversation as resolved.
Outdated
Uh oh!There was an error while loading. Please reload this page. | ||
| 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 */ | ||
| @@ -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; | ||
plbossart marked this conversation as resolved.
Outdated
Uh oh!There was an error while loading. Please reload this page. | ||
| } | ||
| EXPORT_SYMBOL(snd_sof_run_firmware); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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) | ||
plbossart marked this conversation as resolved.
Outdated
Uh oh!There was an error while loading. Please reload this page. | ||
| dev_err(sdev->dev, "error: failed to enter PM idle %d\n", err); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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); | ||
plbossart marked this conversation as resolved.
Outdated
Uh oh!There was an error while loading. Please reload this page. plbossart marked this conversation as resolved.
Outdated
Uh oh!There was an error while loading. Please reload this page. | ||
| /* follow recommendation in pci-driver.c to decrement usage counter */ | ||
| pm_runtime_put_noidle(dev); | ||
| return ret; | ||
| release_regions: | ||
| @@ -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); | ||
plbossart marked this conversation as resolved.
Outdated
Uh oh!There was an error while loading. Please reload this page. | ||
| /* release pci regions and disable device */ | ||
| pci_release_regions(pci); | ||
| pci_disable_device(pci); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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); | ||
ranj063 marked this conversation as resolved.
Outdated
Uh oh!There was an error while loading. Please reload this page. | ||
| 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); | ||
Uh oh!
There was an error while loading. Please reload this page.