Merge branch 'topic/hda' into for-next
authorTakashi Iwai <tiwai@suse.de>
Wed, 29 Apr 2015 10:28:52 +0000 (12:28 +0200)
committerTakashi Iwai <tiwai@suse.de>
Wed, 29 Apr 2015 10:28:52 +0000 (12:28 +0200)
include/sound/hdaudio.h
sound/hda/hdac_device.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_controller.c
sound/pci/hda/hda_controller.h
sound/pci/hda/hda_i915.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_intel.h
sound/pci/hda/patch_hdmi.c

index 6a2e030..b97c59e 100644 (file)
@@ -74,6 +74,7 @@ struct hdac_device {
 
        /* misc flags */
        atomic_t in_pm;         /* suspend/resume being performed */
+       bool  link_power_control:1;
 
        /* sysfs */
        struct hdac_widget_tree *widgets;
@@ -184,6 +185,8 @@ struct hdac_bus_ops {
        /* get a response from the last command */
        int (*get_response)(struct hdac_bus *bus, unsigned int addr,
                            unsigned int *res);
+       /* control the link power  */
+       int (*link_power)(struct hdac_bus *bus, bool enable);
 };
 
 /*
@@ -311,6 +314,7 @@ static inline void snd_hdac_codec_link_down(struct hdac_device *codec)
 int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val);
 int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr,
                              unsigned int *res);
+int snd_hdac_link_power(struct hdac_device *codec, bool enable);
 
 bool snd_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset);
 void snd_hdac_bus_stop_chip(struct hdac_bus *bus);
index 55c7d08..cdee710 100644 (file)
@@ -552,6 +552,21 @@ void snd_hdac_power_down_pm(struct hdac_device *codec)
 EXPORT_SYMBOL_GPL(snd_hdac_power_down_pm);
 #endif
 
+/*
+ * Enable/disable the link power for a codec.
+ */
+int snd_hdac_link_power(struct hdac_device *codec, bool enable)
+{
+       if  (!codec->link_power_control)
+               return 0;
+
+       if  (codec->bus->ops->link_power)
+               return codec->bus->ops->link_power(codec->bus, enable);
+       else
+               return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_link_power);
+
 /* codec vendor labels */
 struct hda_vendor_id {
        unsigned int id;
index d65173a..54380ed 100644 (file)
@@ -858,6 +858,7 @@ void snd_hda_codec_register(struct hda_codec *codec)
                return;
        if (device_is_registered(hda_codec_dev(codec))) {
                snd_hda_register_beep_device(codec);
+               snd_hdac_link_power(&codec->core, true);
                pm_runtime_enable(hda_codec_dev(codec));
                /* it was powered up in snd_hda_codec_new(), now all done */
                snd_hda_power_down(codec);
@@ -884,6 +885,7 @@ static int snd_hda_codec_dev_free(struct snd_device *device)
        struct hda_codec *codec = device->device_data;
 
        codec->in_freeing = 1;
+       snd_hdac_link_power(&codec->core, false);
        snd_hdac_device_unregister(&codec->core);
        put_device(hda_codec_dev(codec));
        return 0;
@@ -3106,6 +3108,7 @@ static int hda_codec_runtime_suspend(struct device *dev)
        if (codec_has_clkstop(codec) && codec_has_epss(codec) &&
            (state & AC_PWRST_CLK_STOP_OK))
                snd_hdac_codec_link_down(&codec->core);
+       snd_hdac_link_power(&codec->core, false);
        return 0;
 }
 
@@ -3113,6 +3116,7 @@ static int hda_codec_runtime_resume(struct device *dev)
 {
        struct hda_codec *codec = dev_to_hda_codec(dev);
 
+       snd_hdac_link_power(&codec->core, true);
        snd_hdac_codec_link_up(&codec->core);
        hda_call_codec_resume(codec);
        pm_runtime_mark_last_busy(dev);
index e0bb623..120854e 100644 (file)
@@ -775,9 +775,20 @@ static int azx_get_response(struct hdac_bus *bus, unsigned int addr,
                return azx_rirb_get_response(bus, addr, res);
 }
 
+static int azx_link_power(struct hdac_bus *bus, bool enable)
+{
+       struct azx *chip = bus_to_azx(bus);
+
+       if (chip->ops->link_power)
+               return chip->ops->link_power(chip, enable);
+       else
+               return -EINVAL;
+}
+
 static const struct hdac_bus_ops bus_core_ops = {
        .command = azx_send_cmd,
        .get_response = azx_get_response,
+       .link_power = azx_link_power,
 };
 
 #ifdef CONFIG_SND_HDA_DSP_LOADER
index 3c6ebaf..314105c 100644 (file)
@@ -89,6 +89,8 @@ struct hda_controller_ops {
                                 struct vm_area_struct *area);
        /* Check if current position is acceptable */
        int (*position_check)(struct azx *chip, struct azx_dev *azx_dev);
+       /* enable/disable the link power */
+       int (*link_power)(struct azx *chip, bool enable);
 };
 
 struct azx_pcm {
index 3052a2b..d9d0793 100644 (file)
@@ -42,10 +42,15 @@ int hda_display_power(struct hda_intel *hda, bool enable)
 
        dev_dbg(&hda->chip.pci->dev, "display power %s\n",
                enable ? "enable" : "disable");
-       if (enable)
-               acomp->ops->get_power(acomp->dev);
-       else
-               acomp->ops->put_power(acomp->dev);
+
+       if (enable) {
+               if (!hda->i915_power_refcount++)
+                       acomp->ops->get_power(acomp->dev);
+       } else {
+               WARN_ON(!hda->i915_power_refcount);
+               if (!--hda->i915_power_refcount)
+                       acomp->ops->put_power(acomp->dev);
+       }
 
        return 0;
 }
@@ -189,6 +194,11 @@ out_err:
 int hda_i915_exit(struct hda_intel *hda)
 {
        struct device *dev = &hda->chip.pci->dev;
+       struct i915_audio_component *acomp = &hda->audio_component;
+
+       WARN_ON(hda->i915_power_refcount);
+       if (hda->i915_power_refcount > 0 && acomp->ops)
+               acomp->ops->put_power(acomp->dev);
 
        component_master_del(dev, &hda_component_master_ops);
 
index c212f13..5aa5cfa 100644 (file)
@@ -543,6 +543,14 @@ static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev)
        return 0;
 }
 
+/* Enable/disable i915 display power for the link */
+static int azx_intel_link_power(struct azx *chip, bool enable)
+{
+       struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
+
+       return hda_display_power(hda, enable);
+}
+
 /*
  * Check whether the current DMA position is acceptable for updating
  * periods.  Returns non-zero if it's OK.
@@ -809,7 +817,8 @@ static int azx_suspend(struct device *dev)
 
        if (chip->msi)
                pci_disable_msi(chip->pci);
-       if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
+       if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL
+               && hda->need_i915_power)
                hda_display_power(hda, false);
        return 0;
 }
@@ -829,7 +838,8 @@ static int azx_resume(struct device *dev)
        if (chip->disabled || hda->init_failed)
                return 0;
 
-       if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
+       if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL
+               && hda->need_i915_power) {
                hda_display_power(hda, true);
                haswell_set_bclk(hda);
        }
@@ -872,7 +882,8 @@ static int azx_runtime_suspend(struct device *dev)
        azx_stop_chip(chip);
        azx_enter_link_reset(chip);
        azx_clear_irq_pending(chip);
-       if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
+       if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL
+               && hda->need_i915_power)
                hda_display_power(hda, false);
 
        return 0;
@@ -897,7 +908,8 @@ static int azx_runtime_resume(struct device *dev)
        if (!azx_has_pm_runtime(chip))
                return 0;
 
-       if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
+       if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL
+               && hda->need_i915_power) {
                hda_display_power(hda, true);
                haswell_set_bclk(hda);
        }
@@ -1118,7 +1130,8 @@ static int azx_free(struct azx *chip)
        release_firmware(chip->fw);
 #endif
        if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
-               hda_display_power(hda, false);
+               if (hda->need_i915_power)
+                       hda_display_power(hda, false);
                hda_i915_exit(hda);
        }
        kfree(hda);
@@ -1789,6 +1802,7 @@ static const struct hda_controller_ops pci_hda_ops = {
        .substream_free_pages = substream_free_pages,
        .pcm_mmap_prepare = pcm_mmap_prepare,
        .position_check = azx_position_check,
+       .link_power = azx_intel_link_power,
 };
 
 static int azx_probe(struct pci_dev *pci,
@@ -1882,17 +1896,28 @@ static int azx_probe_continue(struct azx *chip)
        int err;
 
        hda->probe_continued = 1;
-       /* Request power well for Haswell HDA controller and codec */
+
+       /* Request display power well for the HDA controller or codec. For
+        * Haswell/Broadwell, both the display HDA controller and codec need
+        * this power. For other platforms, like Baytrail/Braswell, only the
+        * display codec needs the power and it can be released after probe.
+        */
        if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
+               /* Baytral/Braswell controllers don't need this power */
+               if (pci->device != 0x0f04 && pci->device != 0x2284)
+                       hda->need_i915_power = 1;
+
+
 #ifdef CONFIG_SND_HDA_I915
                err = hda_i915_init(hda);
                if (err < 0)
-                       goto out_free;
+                       goto i915_power_fail;
+
                err = hda_display_power(hda, true);
                if (err < 0) {
                        dev_err(chip->card->dev,
                                "Cannot turn on display power on i915\n");
-                       goto out_free;
+                       goto i915_power_fail;
                }
 #endif
        }
@@ -1939,6 +1964,11 @@ static int azx_probe_continue(struct azx *chip)
                pm_runtime_put_noidle(&pci->dev);
 
 out_free:
+       if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL
+               && !hda->need_i915_power)
+               hda_display_power(hda, false);
+
+i915_power_fail:
        if (err < 0)
                hda->init_failed = 1;
        complete_all(&hda->probe_wait);
index 2069898..505f987 100644 (file)
@@ -45,7 +45,9 @@ struct hda_intel {
        struct dev_pm_domain hdmi_pm_domain;
 
        /* i915 component interface */
+       bool need_i915_power:1; /* the hda controller needs i915 power */
        struct i915_audio_component audio_component;
+       int i915_power_refcount;
 };
 
 #ifdef CONFIG_SND_HDA_I915
index d925742..e8d8478 100644 (file)
@@ -2335,6 +2335,15 @@ static int patch_generic_hdmi(struct hda_codec *codec)
                intel_haswell_fixup_enable_dp12(codec);
        }
 
+       /* For Valleyview/Cherryview, only the display codec is in the display
+        * power well and can use link_power ops to request/release the power.
+        * For Haswell/Broadwell, the controller is also in the power well and
+        * can cover the codec power request, and so need not set this flag.
+        * For previous platforms, there is no such power well feature.
+        */
+       if (is_valleyview_plus(codec))
+               codec->core.link_power_control = 1;
+
        if (is_haswell_plus(codec) || is_valleyview_plus(codec))
                codec->depop_delay = 0;