Skip to content

Commit 687ae9e

Browse files
committed
ASoC: intel: skl: Fix display power regression
Since the refactoring of HD-audio display power management, the display power status is managed per domain. Meanwhile the ASoC hdac_hdmi driver still keeps and relies (incorrectly) on the refcounting together with ASoC skl driver, and this leads to the display state always on. This patch is an attempt to address the regression by simplifying the PM code of ASoC skl and hdac_hdmi drivers. Basically, since the refactoring, we don't have to manage the display power at HD-audio controller suspend / resume but only at HD-audio HDMI codec suspend / resume. So the patch drops the superfluous snd_hdac_display_power() calls in skl driver. Meanwhile, in hdac_hdmi side, we rewrite the PM call just to re-use the runtime PM callbacks like other drivers do. Now the logic is simple: turn off at suspend and turn on at resume. The patch also fixes the possibly missing display-power off at skl driver removal as well as some error paths at probe. Fixes: 029d92c ("ALSA: hda: Refactor display power management") Reported-by: Libin Yang <libin.yang@intel.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
1 parent 82aa0d7 commit 687ae9e

File tree

2 files changed

+17
-112
lines changed

2 files changed

+17
-112
lines changed

sound/soc/codecs/hdac_hdmi.c

Lines changed: 13 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1890,51 +1890,31 @@ static void hdmi_codec_remove(struct snd_soc_component *component)
18901890
pm_runtime_disable(&hdev->dev);
18911891
}
18921892

1893-
#ifdef CONFIG_PM
1894-
static int hdmi_codec_prepare(struct device *dev)
1895-
{
1896-
struct hdac_device *hdev = dev_to_hdac_dev(dev);
1897-
1898-
pm_runtime_get_sync(&hdev->dev);
1899-
1900-
/*
1901-
* Power down afg.
1902-
* codec_read is preferred over codec_write to set the power state.
1903-
* This way verb is send to set the power state and response
1904-
* is received. So setting power state is ensured without using loop
1905-
* to read the state.
1906-
*/
1907-
snd_hdac_codec_read(hdev, hdev->afg, 0, AC_VERB_SET_POWER_STATE,
1908-
AC_PWRST_D3);
1909-
1910-
return 0;
1911-
}
1912-
1913-
static void hdmi_codec_complete(struct device *dev)
1893+
#ifdef CONFIG_PM_SLEEP
1894+
static int hdmi_codec_resume(struct device *dev)
19141895
{
19151896
struct hdac_device *hdev = dev_to_hdac_dev(dev);
19161897
struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
1898+
int ret;
19171899

1918-
/* Power up afg */
1919-
snd_hdac_codec_read(hdev, hdev->afg, 0, AC_VERB_SET_POWER_STATE,
1920-
AC_PWRST_D0);
1921-
1922-
hdac_hdmi_skl_enable_all_pins(hdev);
1923-
hdac_hdmi_skl_enable_dp12(hdev);
1924-
1900+
ret = pm_runtime_force_resume(dev);
1901+
if (ret < 0)
1902+
return ret;
19251903
/*
19261904
* As the ELD notify callback request is not entertained while the
19271905
* device is in suspend state. Need to manually check detection of
19281906
* all pins here. pin capablity change is not support, so use the
19291907
* already set pin caps.
1908+
*
1909+
* NOTE: this is safe to call even if the codec doesn't actually resume.
1910+
* The pin check involves only with DRM audio component hooks, so it
1911+
* works even if the HD-audio side is still dreaming peacefully.
19301912
*/
19311913
hdac_hdmi_present_sense_all_pins(hdev, hdmi, false);
1932-
1933-
pm_runtime_put_sync(&hdev->dev);
1914+
return 0;
19341915
}
19351916
#else
1936-
#define hdmi_codec_prepare NULL
1937-
#define hdmi_codec_complete NULL
1917+
#define hdmi_codec_resume NULL
19381918
#endif
19391919

19401920
static const struct snd_soc_component_driver hdmi_hda_codec = {
@@ -2135,75 +2115,6 @@ static int hdac_hdmi_dev_remove(struct hdac_device *hdev)
21352115
}
21362116

21372117
#ifdef CONFIG_PM
2138-
/*
2139-
* Power management sequences
2140-
* ==========================
2141-
*
2142-
* The following explains the PM handling of HDAC HDMI with its parent
2143-
* device SKL and display power usage
2144-
*
2145-
* Probe
2146-
* -----
2147-
* In SKL probe,
2148-
* 1. skl_probe_work() powers up the display (refcount++ -> 1)
2149-
* 2. enumerates the codecs on the link
2150-
* 3. powers down the display (refcount-- -> 0)
2151-
*
2152-
* In HDAC HDMI probe,
2153-
* 1. hdac_hdmi_dev_probe() powers up the display (refcount++ -> 1)
2154-
* 2. probe the codec
2155-
* 3. put the HDAC HDMI device to runtime suspend
2156-
* 4. hdac_hdmi_runtime_suspend() powers down the display (refcount-- -> 0)
2157-
*
2158-
* Once children are runtime suspended, SKL device also goes to runtime
2159-
* suspend
2160-
*
2161-
* HDMI Playback
2162-
* -------------
2163-
* Open HDMI device,
2164-
* 1. skl_runtime_resume() invoked
2165-
* 2. hdac_hdmi_runtime_resume() powers up the display (refcount++ -> 1)
2166-
*
2167-
* Close HDMI device,
2168-
* 1. hdac_hdmi_runtime_suspend() powers down the display (refcount-- -> 0)
2169-
* 2. skl_runtime_suspend() invoked
2170-
*
2171-
* S0/S3 Cycle with playback in progress
2172-
* -------------------------------------
2173-
* When the device is opened for playback, the device is runtime active
2174-
* already and the display refcount is 1 as explained above.
2175-
*
2176-
* Entering to S3,
2177-
* 1. hdmi_codec_prepare() invoke the runtime resume of codec which just
2178-
* increments the PM runtime usage count of the codec since the device
2179-
* is in use already
2180-
* 2. skl_suspend() powers down the display (refcount-- -> 0)
2181-
*
2182-
* Wakeup from S3,
2183-
* 1. skl_resume() powers up the display (refcount++ -> 1)
2184-
* 2. hdmi_codec_complete() invokes the runtime suspend of codec which just
2185-
* decrements the PM runtime usage count of the codec since the device
2186-
* is in use already
2187-
*
2188-
* Once playback is stopped, the display refcount is set to 0 as explained
2189-
* above in the HDMI playback sequence. The PM handlings are designed in
2190-
* such way that to balance the refcount of display power when the codec
2191-
* device put to S3 while playback is going on.
2192-
*
2193-
* S0/S3 Cycle without playback in progress
2194-
* ----------------------------------------
2195-
* Entering to S3,
2196-
* 1. hdmi_codec_prepare() invoke the runtime resume of codec
2197-
* 2. skl_runtime_resume() invoked
2198-
* 3. hdac_hdmi_runtime_resume() powers up the display (refcount++ -> 1)
2199-
* 4. skl_suspend() powers down the display (refcount-- -> 0)
2200-
*
2201-
* Wakeup from S3,
2202-
* 1. skl_resume() powers up the display (refcount++ -> 1)
2203-
* 2. hdmi_codec_complete() invokes the runtime suspend of codec
2204-
* 3. hdac_hdmi_runtime_suspend() powers down the display (refcount-- -> 0)
2205-
* 4. skl_runtime_suspend() invoked
2206-
*/
22072118
static int hdac_hdmi_runtime_suspend(struct device *dev)
22082119
{
22092120
struct hdac_device *hdev = dev_to_hdac_dev(dev);
@@ -2277,8 +2188,7 @@ static int hdac_hdmi_runtime_resume(struct device *dev)
22772188

22782189
static const struct dev_pm_ops hdac_hdmi_pm = {
22792190
SET_RUNTIME_PM_OPS(hdac_hdmi_runtime_suspend, hdac_hdmi_runtime_resume, NULL)
2280-
.prepare = hdmi_codec_prepare,
2281-
.complete = hdmi_codec_complete,
2191+
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, hdmi_codec_resume)
22822192
};
22832193

22842194
static const struct hda_device_id hdmi_list[] = {

sound/soc/intel/skylake/skl.c

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -336,9 +336,6 @@ static int skl_suspend(struct device *dev)
336336
skl->skl_sst->fw_loaded = false;
337337
}
338338

339-
if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI))
340-
snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
341-
342339
return 0;
343340
}
344341

@@ -350,10 +347,6 @@ static int skl_resume(struct device *dev)
350347
struct hdac_ext_link *hlink = NULL;
351348
int ret;
352349

353-
/* Turned OFF in HDMI codec driver after codec reconfiguration */
354-
if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI))
355-
snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true);
356-
357350
/*
358351
* resume only when we are not in suspend active, otherwise need to
359352
* restore the device
@@ -446,8 +439,10 @@ static int skl_free(struct hdac_bus *bus)
446439
snd_hdac_ext_bus_exit(bus);
447440

448441
cancel_work_sync(&skl->probe_work);
449-
if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI))
442+
if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) {
443+
snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
450444
snd_hdac_i915_exit(bus);
445+
}
451446

452447
return 0;
453448
}
@@ -814,7 +809,7 @@ static void skl_probe_work(struct work_struct *work)
814809
err = skl_platform_register(bus->dev);
815810
if (err < 0) {
816811
dev_err(bus->dev, "platform register failed: %d\n", err);
817-
return;
812+
goto out_err;
818813
}
819814

820815
err = skl_machine_device_register(skl);

0 commit comments

Comments
 (0)