aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2015-01-13 01:54:02 -0500
committerTakashi Iwai <tiwai@suse.de>2015-01-13 01:54:02 -0500
commit1d69970d27210d18eaf153e04ed697ac7a4f17dc (patch)
tree9848e5f2dfa0c23482b6fac276a0eb271c890242
parent7bfb8575b82cd1facde3dc5be2b125f408171646 (diff)
parentfcf3aac5fc307f0cae429f5844ddc25761662858 (diff)
Merge tag 'topic/i915-hda-componentized-2015-01-12' of git://anongit.freedesktop.org/drm-intel into for-next
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c4
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c9
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h8
-rw-r--r--drivers/gpu/drm/i915/intel_audio.c110
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h2
-rw-r--r--drivers/gpu/drm/i915/intel_runtime_pm.c56
-rw-r--r--include/drm/i915_component.h38
-rw-r--r--include/drm/i915_powerwell.h37
-rw-r--r--sound/pci/hda/hda_i915.c154
-rw-r--r--sound/pci/hda/hda_i915.h37
-rw-r--r--sound/pci/hda/hda_intel.c60
-rw-r--r--sound/pci/hda/hda_intel.h71
12 files changed, 361 insertions, 225 deletions
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index ecee3bcc8772..26b3199e0af2 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -830,6 +830,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
830 830
831 intel_runtime_pm_enable(dev_priv); 831 intel_runtime_pm_enable(dev_priv);
832 832
833 i915_audio_component_init(dev_priv);
834
833 return 0; 835 return 0;
834 836
835out_power_well: 837out_power_well:
@@ -870,6 +872,8 @@ int i915_driver_unload(struct drm_device *dev)
870 struct drm_i915_private *dev_priv = dev->dev_private; 872 struct drm_i915_private *dev_priv = dev->dev_private;
871 int ret; 873 int ret;
872 874
875 i915_audio_component_cleanup(dev_priv);
876
873 ret = i915_gem_suspend(dev); 877 ret = i915_gem_suspend(dev);
874 if (ret) { 878 if (ret) {
875 DRM_ERROR("failed to idle hardware: %d\n", ret); 879 DRM_ERROR("failed to idle hardware: %d\n", ret);
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 574057cd1d09..cbbd23f78518 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -940,8 +940,7 @@ static int i915_pm_suspend(struct device *dev)
940 940
941static int i915_pm_suspend_late(struct device *dev) 941static int i915_pm_suspend_late(struct device *dev)
942{ 942{
943 struct pci_dev *pdev = to_pci_dev(dev); 943 struct drm_device *drm_dev = dev_to_i915(dev)->dev;
944 struct drm_device *drm_dev = pci_get_drvdata(pdev);
945 944
946 /* 945 /*
947 * We have a suspedn ordering issue with the snd-hda driver also 946 * We have a suspedn ordering issue with the snd-hda driver also
@@ -960,8 +959,7 @@ static int i915_pm_suspend_late(struct device *dev)
960 959
961static int i915_pm_resume_early(struct device *dev) 960static int i915_pm_resume_early(struct device *dev)
962{ 961{
963 struct pci_dev *pdev = to_pci_dev(dev); 962 struct drm_device *drm_dev = dev_to_i915(dev)->dev;
964 struct drm_device *drm_dev = pci_get_drvdata(pdev);
965 963
966 if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF) 964 if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
967 return 0; 965 return 0;
@@ -971,8 +969,7 @@ static int i915_pm_resume_early(struct device *dev)
971 969
972static int i915_pm_resume(struct device *dev) 970static int i915_pm_resume(struct device *dev)
973{ 971{
974 struct pci_dev *pdev = to_pci_dev(dev); 972 struct drm_device *drm_dev = dev_to_i915(dev)->dev;
975 struct drm_device *drm_dev = pci_get_drvdata(pdev);
976 973
977 if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF) 974 if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
978 return 0; 975 return 0;
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index e9f891c432f8..176afc507f7c 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1698,6 +1698,9 @@ struct drm_i915_private {
1698 struct drm_property *broadcast_rgb_property; 1698 struct drm_property *broadcast_rgb_property;
1699 struct drm_property *force_audio_property; 1699 struct drm_property *force_audio_property;
1700 1700
1701 /* hda/i915 audio component */
1702 bool audio_component_registered;
1703
1701 uint32_t hw_context_size; 1704 uint32_t hw_context_size;
1702 struct list_head context_list; 1705 struct list_head context_list;
1703 1706
@@ -1781,6 +1784,11 @@ static inline struct drm_i915_private *to_i915(const struct drm_device *dev)
1781 return dev->dev_private; 1784 return dev->dev_private;
1782} 1785}
1783 1786
1787static inline struct drm_i915_private *dev_to_i915(struct device *dev)
1788{
1789 return to_i915(dev_get_drvdata(dev));
1790}
1791
1784/* Iterate over initialised rings */ 1792/* Iterate over initialised rings */
1785#define for_each_ring(ring__, dev_priv__, i__) \ 1793#define for_each_ring(ring__, dev_priv__, i__) \
1786 for ((i__) = 0; (i__) < I915_NUM_RINGS; (i__)++) \ 1794 for ((i__) = 0; (i__) < I915_NUM_RINGS; (i__)++) \
diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c
index 2c7ed5cb29c0..ee41b882e71a 100644
--- a/drivers/gpu/drm/i915/intel_audio.c
+++ b/drivers/gpu/drm/i915/intel_audio.c
@@ -22,6 +22,9 @@
22 */ 22 */
23 23
24#include <linux/kernel.h> 24#include <linux/kernel.h>
25#include <linux/component.h>
26#include <drm/i915_component.h>
27#include "intel_drv.h"
25 28
26#include <drm/drmP.h> 29#include <drm/drmP.h>
27#include <drm/drm_edid.h> 30#include <drm/drm_edid.h>
@@ -461,3 +464,110 @@ void intel_init_audio(struct drm_device *dev)
461 dev_priv->display.audio_codec_disable = ilk_audio_codec_disable; 464 dev_priv->display.audio_codec_disable = ilk_audio_codec_disable;
462 } 465 }
463} 466}
467
468static void i915_audio_component_get_power(struct device *dev)
469{
470 intel_display_power_get(dev_to_i915(dev), POWER_DOMAIN_AUDIO);
471}
472
473static void i915_audio_component_put_power(struct device *dev)
474{
475 intel_display_power_put(dev_to_i915(dev), POWER_DOMAIN_AUDIO);
476}
477
478/* Get CDCLK in kHz */
479static int i915_audio_component_get_cdclk_freq(struct device *dev)
480{
481 struct drm_i915_private *dev_priv = dev_to_i915(dev);
482 int ret;
483
484 if (WARN_ON_ONCE(!HAS_DDI(dev_priv)))
485 return -ENODEV;
486
487 intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO);
488 ret = intel_ddi_get_cdclk_freq(dev_priv);
489 intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO);
490
491 return ret;
492}
493
494static const struct i915_audio_component_ops i915_audio_component_ops = {
495 .owner = THIS_MODULE,
496 .get_power = i915_audio_component_get_power,
497 .put_power = i915_audio_component_put_power,
498 .get_cdclk_freq = i915_audio_component_get_cdclk_freq,
499};
500
501static int i915_audio_component_bind(struct device *i915_dev,
502 struct device *hda_dev, void *data)
503{
504 struct i915_audio_component *acomp = data;
505
506 if (WARN_ON(acomp->ops || acomp->dev))
507 return -EEXIST;
508
509 acomp->ops = &i915_audio_component_ops;
510 acomp->dev = i915_dev;
511
512 return 0;
513}
514
515static void i915_audio_component_unbind(struct device *i915_dev,
516 struct device *hda_dev, void *data)
517{
518 struct i915_audio_component *acomp = data;
519
520 acomp->ops = NULL;
521 acomp->dev = NULL;
522}
523
524static const struct component_ops i915_audio_component_bind_ops = {
525 .bind = i915_audio_component_bind,
526 .unbind = i915_audio_component_unbind,
527};
528
529/**
530 * i915_audio_component_init - initialize and register the audio component
531 * @dev_priv: i915 device instance
532 *
533 * This will register with the component framework a child component which
534 * will bind dynamically to the snd_hda_intel driver's corresponding master
535 * component when the latter is registered. During binding the child
536 * initializes an instance of struct i915_audio_component which it receives
537 * from the master. The master can then start to use the interface defined by
538 * this struct. Each side can break the binding at any point by deregistering
539 * its own component after which each side's component unbind callback is
540 * called.
541 *
542 * We ignore any error during registration and continue with reduced
543 * functionality (i.e. without HDMI audio).
544 */
545void i915_audio_component_init(struct drm_i915_private *dev_priv)
546{
547 int ret;
548
549 ret = component_add(dev_priv->dev->dev, &i915_audio_component_bind_ops);
550 if (ret < 0) {
551 DRM_ERROR("failed to add audio component (%d)\n", ret);
552 /* continue with reduced functionality */
553 return;
554 }
555
556 dev_priv->audio_component_registered = true;
557}
558
559/**
560 * i915_audio_component_cleanup - deregister the audio component
561 * @dev_priv: i915 device instance
562 *
563 * Deregisters the audio component, breaking any existing binding to the
564 * corresponding snd_hda_intel driver's master component.
565 */
566void i915_audio_component_cleanup(struct drm_i915_private *dev_priv)
567{
568 if (!dev_priv->audio_component_registered)
569 return;
570
571 component_del(dev_priv->dev->dev, &i915_audio_component_bind_ops);
572 dev_priv->audio_component_registered = false;
573}
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 25fdbb16d4e0..e88fd5d12f05 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -872,6 +872,8 @@ void intel_fb_obj_flush(struct drm_i915_gem_object *obj, bool retire);
872void intel_init_audio(struct drm_device *dev); 872void intel_init_audio(struct drm_device *dev);
873void intel_audio_codec_enable(struct intel_encoder *encoder); 873void intel_audio_codec_enable(struct intel_encoder *encoder);
874void intel_audio_codec_disable(struct intel_encoder *encoder); 874void intel_audio_codec_disable(struct intel_encoder *encoder);
875void i915_audio_component_init(struct drm_i915_private *dev_priv);
876void i915_audio_component_cleanup(struct drm_i915_private *dev_priv);
875 877
876/* intel_display.c */ 878/* intel_display.c */
877const char *intel_output_name(int output); 879const char *intel_output_name(int output);
diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
index ac6da7102fbb..39ddf40171bf 100644
--- a/drivers/gpu/drm/i915/intel_runtime_pm.c
+++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
@@ -31,7 +31,6 @@
31 31
32#include "i915_drv.h" 32#include "i915_drv.h"
33#include "intel_drv.h" 33#include "intel_drv.h"
34#include <drm/i915_powerwell.h>
35 34
36/** 35/**
37 * DOC: runtime pm 36 * DOC: runtime pm
@@ -50,8 +49,6 @@
50 * present for a given platform. 49 * present for a given platform.
51 */ 50 */
52 51
53static struct i915_power_domains *hsw_pwr;
54
55#define for_each_power_well(i, power_well, domain_mask, power_domains) \ 52#define for_each_power_well(i, power_well, domain_mask, power_domains) \
56 for (i = 0; \ 53 for (i = 0; \
57 i < (power_domains)->power_well_count && \ 54 i < (power_domains)->power_well_count && \
@@ -1071,10 +1068,8 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv)
1071 */ 1068 */
1072 if (IS_HASWELL(dev_priv->dev)) { 1069 if (IS_HASWELL(dev_priv->dev)) {
1073 set_power_wells(power_domains, hsw_power_wells); 1070 set_power_wells(power_domains, hsw_power_wells);
1074 hsw_pwr = power_domains;
1075 } else if (IS_BROADWELL(dev_priv->dev)) { 1071 } else if (IS_BROADWELL(dev_priv->dev)) {
1076 set_power_wells(power_domains, bdw_power_wells); 1072 set_power_wells(power_domains, bdw_power_wells);
1077 hsw_pwr = power_domains;
1078 } else if (IS_CHERRYVIEW(dev_priv->dev)) { 1073 } else if (IS_CHERRYVIEW(dev_priv->dev)) {
1079 set_power_wells(power_domains, chv_power_wells); 1074 set_power_wells(power_domains, chv_power_wells);
1080 } else if (IS_VALLEYVIEW(dev_priv->dev)) { 1075 } else if (IS_VALLEYVIEW(dev_priv->dev)) {
@@ -1118,8 +1113,6 @@ void intel_power_domains_fini(struct drm_i915_private *dev_priv)
1118 * the power well is not enabled, so just enable it in case 1113 * the power well is not enabled, so just enable it in case
1119 * we're going to unload/reload. */ 1114 * we're going to unload/reload. */
1120 intel_display_set_init_power(dev_priv, true); 1115 intel_display_set_init_power(dev_priv, true);
1121
1122 hsw_pwr = NULL;
1123} 1116}
1124 1117
1125static void intel_power_domains_resume(struct drm_i915_private *dev_priv) 1118static void intel_power_domains_resume(struct drm_i915_private *dev_priv)
@@ -1328,52 +1321,3 @@ void intel_runtime_pm_enable(struct drm_i915_private *dev_priv)
1328 pm_runtime_put_autosuspend(device); 1321 pm_runtime_put_autosuspend(device);
1329} 1322}
1330 1323
1331/* Display audio driver power well request */
1332int i915_request_power_well(void)
1333{
1334 struct drm_i915_private *dev_priv;
1335
1336 if (!hsw_pwr)
1337 return -ENODEV;
1338
1339 dev_priv = container_of(hsw_pwr, struct drm_i915_private,
1340 power_domains);
1341 intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO);
1342 return 0;
1343}
1344EXPORT_SYMBOL_GPL(i915_request_power_well);
1345
1346/* Display audio driver power well release */
1347int i915_release_power_well(void)
1348{
1349 struct drm_i915_private *dev_priv;
1350
1351 if (!hsw_pwr)
1352 return -ENODEV;
1353
1354 dev_priv = container_of(hsw_pwr, struct drm_i915_private,
1355 power_domains);
1356 intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO);
1357 return 0;
1358}
1359EXPORT_SYMBOL_GPL(i915_release_power_well);
1360
1361/*
1362 * Private interface for the audio driver to get CDCLK in kHz.
1363 *
1364 * Caller must request power well using i915_request_power_well() prior to
1365 * making the call.
1366 */
1367int i915_get_cdclk_freq(void)
1368{
1369 struct drm_i915_private *dev_priv;
1370
1371 if (!hsw_pwr)
1372 return -ENODEV;
1373
1374 dev_priv = container_of(hsw_pwr, struct drm_i915_private,
1375 power_domains);
1376
1377 return intel_ddi_get_cdclk_freq(dev_priv);
1378}
1379EXPORT_SYMBOL_GPL(i915_get_cdclk_freq);
diff --git a/include/drm/i915_component.h b/include/drm/i915_component.h
new file mode 100644
index 000000000000..3e2f22e5bf3c
--- /dev/null
+++ b/include/drm/i915_component.h
@@ -0,0 +1,38 @@
1/*
2 * Copyright © 2014 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24#ifndef _I915_COMPONENT_H_
25#define _I915_COMPONENT_H_
26
27struct i915_audio_component {
28 struct device *dev;
29
30 const struct i915_audio_component_ops {
31 struct module *owner;
32 void (*get_power)(struct device *);
33 void (*put_power)(struct device *);
34 int (*get_cdclk_freq)(struct device *);
35 } *ops;
36};
37
38#endif /* _I915_COMPONENT_H_ */
diff --git a/include/drm/i915_powerwell.h b/include/drm/i915_powerwell.h
deleted file mode 100644
index baa6f11b1837..000000000000
--- a/include/drm/i915_powerwell.h
+++ /dev/null
@@ -1,37 +0,0 @@
1/**************************************************************************
2 *
3 * Copyright 2013 Intel Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 * USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 *
27 **************************************************************************/
28
29#ifndef _I915_POWERWELL_H_
30#define _I915_POWERWELL_H_
31
32/* For use by hda_i915 driver */
33extern int i915_request_power_well(void);
34extern int i915_release_power_well(void);
35extern int i915_get_cdclk_freq(void);
36
37#endif /* _I915_POWERWELL_H_ */
diff --git a/sound/pci/hda/hda_i915.c b/sound/pci/hda/hda_i915.c
index d4d0375ac181..714894527e06 100644
--- a/sound/pci/hda/hda_i915.c
+++ b/sound/pci/hda/hda_i915.c
@@ -18,10 +18,12 @@
18 18
19#include <linux/init.h> 19#include <linux/init.h>
20#include <linux/module.h> 20#include <linux/module.h>
21#include <linux/pci.h>
22#include <linux/component.h>
23#include <drm/i915_component.h>
21#include <sound/core.h> 24#include <sound/core.h>
22#include <drm/i915_powerwell.h>
23#include "hda_priv.h" 25#include "hda_priv.h"
24#include "hda_i915.h" 26#include "hda_intel.h"
25 27
26/* Intel HSW/BDW display HDA controller Extended Mode registers. 28/* Intel HSW/BDW display HDA controller Extended Mode registers.
27 * EM4 (M value) and EM5 (N Value) are used to convert CDClk (Core Display 29 * EM4 (M value) and EM5 (N Value) are used to convert CDClk (Core Display
@@ -31,32 +33,33 @@
31#define AZX_REG_EM4 0x100c 33#define AZX_REG_EM4 0x100c
32#define AZX_REG_EM5 0x1010 34#define AZX_REG_EM5 0x1010
33 35
34static int (*get_power)(void); 36int hda_display_power(struct hda_intel *hda, bool enable)
35static int (*put_power)(void);
36static int (*get_cdclk)(void);
37
38int hda_display_power(bool enable)
39{ 37{
40 if (!get_power || !put_power) 38 struct i915_audio_component *acomp = &hda->audio_component;
39
40 if (!acomp->ops)
41 return -ENODEV; 41 return -ENODEV;
42 42
43 pr_debug("HDA display power %s \n", 43 dev_dbg(&hda->chip.pci->dev, "display power %s\n",
44 enable ? "Enable" : "Disable"); 44 enable ? "enable" : "disable");
45 if (enable) 45 if (enable)
46 return get_power(); 46 acomp->ops->get_power(acomp->dev);
47 else 47 else
48 return put_power(); 48 acomp->ops->put_power(acomp->dev);
49
50 return 0;
49} 51}
50 52
51void haswell_set_bclk(struct azx *chip) 53void haswell_set_bclk(struct hda_intel *hda)
52{ 54{
53 int cdclk_freq; 55 int cdclk_freq;
54 unsigned int bclk_m, bclk_n; 56 unsigned int bclk_m, bclk_n;
57 struct i915_audio_component *acomp = &hda->audio_component;
55 58
56 if (!get_cdclk) 59 if (!acomp->ops)
57 return; 60 return;
58 61
59 cdclk_freq = get_cdclk(); 62 cdclk_freq = acomp->ops->get_cdclk_freq(acomp->dev);
60 switch (cdclk_freq) { 63 switch (cdclk_freq) {
61 case 337500: 64 case 337500:
62 bclk_m = 16; 65 bclk_m = 16;
@@ -80,51 +83,108 @@ void haswell_set_bclk(struct azx *chip)
80 break; 83 break;
81 } 84 }
82 85
83 azx_writew(chip, EM4, bclk_m); 86 azx_writew(&hda->chip, EM4, bclk_m);
84 azx_writew(chip, EM5, bclk_n); 87 azx_writew(&hda->chip, EM5, bclk_n);
85} 88}
86 89
87 90static int hda_component_master_bind(struct device *dev)
88int hda_i915_init(void)
89{ 91{
90 int err = 0; 92 struct snd_card *card = dev_get_drvdata(dev);
91 93 struct azx *chip = card->private_data;
92 get_power = symbol_request(i915_request_power_well); 94 struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
93 if (!get_power) { 95 struct i915_audio_component *acomp = &hda->audio_component;
94 pr_warn("hda-i915: get_power symbol get fail\n"); 96 int ret;
95 return -ENODEV; 97
98 ret = component_bind_all(dev, acomp);
99 if (ret < 0)
100 return ret;
101
102 if (WARN_ON(!(acomp->dev && acomp->ops && acomp->ops->get_power &&
103 acomp->ops->put_power && acomp->ops->get_cdclk_freq))) {
104 ret = -EINVAL;
105 goto out_unbind;
96 } 106 }
97 107
98 put_power = symbol_request(i915_release_power_well); 108 /*
99 if (!put_power) { 109 * Atm, we don't support dynamic unbinding initiated by the child
100 symbol_put(i915_request_power_well); 110 * component, so pin its containing module until we unbind.
101 get_power = NULL; 111 */
102 return -ENODEV; 112 if (!try_module_get(acomp->ops->owner)) {
113 ret = -ENODEV;
114 goto out_unbind;
103 } 115 }
104 116
105 get_cdclk = symbol_request(i915_get_cdclk_freq); 117 return 0;
106 if (!get_cdclk) /* may have abnormal BCLK and audio playback rate */
107 pr_warn("hda-i915: get_cdclk symbol get fail\n");
108 118
109 pr_debug("HDA driver get symbol successfully from i915 module\n"); 119out_unbind:
120 component_unbind_all(dev, acomp);
110 121
111 return err; 122 return ret;
112} 123}
113 124
114int hda_i915_exit(void) 125static void hda_component_master_unbind(struct device *dev)
115{ 126{
116 if (get_power) { 127 struct snd_card *card = dev_get_drvdata(dev);
117 symbol_put(i915_request_power_well); 128 struct azx *chip = card->private_data;
118 get_power = NULL; 129 struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
119 } 130 struct i915_audio_component *acomp = &hda->audio_component;
120 if (put_power) { 131
121 symbol_put(i915_release_power_well); 132 module_put(acomp->ops->owner);
122 put_power = NULL; 133 component_unbind_all(dev, acomp);
123 } 134 WARN_ON(acomp->ops || acomp->dev);
124 if (get_cdclk) { 135}
125 symbol_put(i915_get_cdclk_freq); 136
126 get_cdclk = NULL; 137static const struct component_master_ops hda_component_master_ops = {
138 .bind = hda_component_master_bind,
139 .unbind = hda_component_master_unbind,
140};
141
142static int hda_component_master_match(struct device *dev, void *data)
143{
144 /* i915 is the only supported component */
145 return !strcmp(dev->driver->name, "i915");
146}
147
148int hda_i915_init(struct hda_intel *hda)
149{
150 struct component_match *match = NULL;
151 struct device *dev = &hda->chip.pci->dev;
152 struct i915_audio_component *acomp = &hda->audio_component;
153 int ret;
154
155 component_match_add(dev, &match, hda_component_master_match, hda);
156 ret = component_master_add_with_match(dev, &hda_component_master_ops,
157 match);
158 if (ret < 0)
159 goto out_err;
160
161 /*
162 * Atm, we don't support deferring the component binding, so make sure
163 * i915 is loaded and that the binding successfully completes.
164 */
165 request_module("i915");
166
167 if (!acomp->ops) {
168 ret = -ENODEV;
169 goto out_master_del;
127 } 170 }
128 171
172 dev_dbg(dev, "bound to i915 component master\n");
173
174 return 0;
175out_master_del:
176 component_master_del(dev, &hda_component_master_ops);
177out_err:
178 dev_err(dev, "failed to add i915 component master (%d)\n", ret);
179
180 return ret;
181}
182
183int hda_i915_exit(struct hda_intel *hda)
184{
185 struct device *dev = &hda->chip.pci->dev;
186
187 component_master_del(dev, &hda_component_master_ops);
188
129 return 0; 189 return 0;
130} 190}
diff --git a/sound/pci/hda/hda_i915.h b/sound/pci/hda/hda_i915.h
deleted file mode 100644
index e6072c627583..000000000000
--- a/sound/pci/hda/hda_i915.h
+++ /dev/null
@@ -1,37 +0,0 @@
1/*
2 * This program is free software; you can redistribute it and/or modify it
3 * under the terms of the GNU General Public License as published by the Free
4 * Software Foundation; either version 2 of the License, or (at your option)
5 * any later version.
6 *
7 * This program is distributed in the hope that it will be useful, but WITHOUT
8 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
9 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
10 * more details.
11 *
12 * You should have received a copy of the GNU General Public License along with
13 * this program; if not, write to the Free Software Foundation, Inc., 59
14 * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 */
16#ifndef __SOUND_HDA_I915_H
17#define __SOUND_HDA_I915_H
18
19#ifdef CONFIG_SND_HDA_I915
20int hda_display_power(bool enable);
21void haswell_set_bclk(struct azx *chip);
22int hda_i915_init(void);
23int hda_i915_exit(void);
24#else
25static inline int hda_display_power(bool enable) { return 0; }
26static inline void haswell_set_bclk(struct azx *chip) { return; }
27static inline int hda_i915_init(void)
28{
29 return -ENODEV;
30}
31static inline int hda_i915_exit(void)
32{
33 return 0;
34}
35#endif
36
37#endif
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 23b35687025a..36d2f20db7a4 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -63,7 +63,7 @@
63#include "hda_codec.h" 63#include "hda_codec.h"
64#include "hda_controller.h" 64#include "hda_controller.h"
65#include "hda_priv.h" 65#include "hda_priv.h"
66#include "hda_i915.h" 66#include "hda_intel.h"
67 67
68/* position fix mode */ 68/* position fix mode */
69enum { 69enum {
@@ -354,31 +354,6 @@ static char *driver_short_names[] = {
354 [AZX_DRIVER_GENERIC] = "HD-Audio Generic", 354 [AZX_DRIVER_GENERIC] = "HD-Audio Generic",
355}; 355};
356 356
357struct hda_intel {
358 struct azx chip;
359
360 /* for pending irqs */
361 struct work_struct irq_pending_work;
362
363 /* sync probing */
364 struct completion probe_wait;
365 struct work_struct probe_work;
366
367 /* card list (for power_save trigger) */
368 struct list_head list;
369
370 /* extra flags */
371 unsigned int irq_pending_warned:1;
372
373 /* VGA-switcheroo setup */
374 unsigned int use_vga_switcheroo:1;
375 unsigned int vga_switcheroo_registered:1;
376 unsigned int init_failed:1; /* delayed init failed */
377
378 /* secondary power domain for hdmi audio under vga device */
379 struct dev_pm_domain hdmi_pm_domain;
380};
381
382#ifdef CONFIG_X86 357#ifdef CONFIG_X86
383static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool on) 358static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool on)
384{ 359{
@@ -824,7 +799,7 @@ static int azx_suspend(struct device *dev)
824 if (chip->msi) 799 if (chip->msi)
825 pci_disable_msi(chip->pci); 800 pci_disable_msi(chip->pci);
826 if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) 801 if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
827 hda_display_power(false); 802 hda_display_power(hda, false);
828 return 0; 803 return 0;
829} 804}
830 805
@@ -844,8 +819,8 @@ static int azx_resume(struct device *dev)
844 return 0; 819 return 0;
845 820
846 if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { 821 if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
847 hda_display_power(true); 822 hda_display_power(hda, true);
848 haswell_set_bclk(chip); 823 haswell_set_bclk(hda);
849 } 824 }
850 if (chip->msi) 825 if (chip->msi)
851 if (pci_enable_msi(pci) < 0) 826 if (pci_enable_msi(pci) < 0)
@@ -888,7 +863,7 @@ static int azx_runtime_suspend(struct device *dev)
888 azx_enter_link_reset(chip); 863 azx_enter_link_reset(chip);
889 azx_clear_irq_pending(chip); 864 azx_clear_irq_pending(chip);
890 if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) 865 if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
891 hda_display_power(false); 866 hda_display_power(hda, false);
892 867
893 return 0; 868 return 0;
894} 869}
@@ -914,8 +889,8 @@ static int azx_runtime_resume(struct device *dev)
914 return 0; 889 return 0;
915 890
916 if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { 891 if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
917 hda_display_power(true); 892 hda_display_power(hda, true);
918 haswell_set_bclk(chip); 893 haswell_set_bclk(hda);
919 } 894 }
920 895
921 /* Read STATESTS before controller reset */ 896 /* Read STATESTS before controller reset */
@@ -1136,8 +1111,8 @@ static int azx_free(struct azx *chip)
1136 release_firmware(chip->fw); 1111 release_firmware(chip->fw);
1137#endif 1112#endif
1138 if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { 1113 if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
1139 hda_display_power(false); 1114 hda_display_power(hda, false);
1140 hda_i915_exit(); 1115 hda_i915_exit(hda);
1141 } 1116 }
1142 kfree(hda); 1117 kfree(hda);
1143 1118
@@ -1615,8 +1590,12 @@ static int azx_first_init(struct azx *chip)
1615 /* initialize chip */ 1590 /* initialize chip */
1616 azx_init_pci(chip); 1591 azx_init_pci(chip);
1617 1592
1618 if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) 1593 if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
1619 haswell_set_bclk(chip); 1594 struct hda_intel *hda;
1595
1596 hda = container_of(chip, struct hda_intel, chip);
1597 haswell_set_bclk(hda);
1598 }
1620 1599
1621 azx_init_chip(chip, (probe_only[dev] & 2) == 0); 1600 azx_init_chip(chip, (probe_only[dev] & 2) == 0);
1622 1601
@@ -1896,13 +1875,10 @@ static int azx_probe_continue(struct azx *chip)
1896 /* Request power well for Haswell HDA controller and codec */ 1875 /* Request power well for Haswell HDA controller and codec */
1897 if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { 1876 if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
1898#ifdef CONFIG_SND_HDA_I915 1877#ifdef CONFIG_SND_HDA_I915
1899 err = hda_i915_init(); 1878 err = hda_i915_init(hda);
1900 if (err < 0) { 1879 if (err < 0)
1901 dev_err(chip->card->dev,
1902 "Error request power-well from i915\n");
1903 goto out_free; 1880 goto out_free;
1904 } 1881 err = hda_display_power(hda, true);
1905 err = hda_display_power(true);
1906 if (err < 0) { 1882 if (err < 0) {
1907 dev_err(chip->card->dev, 1883 dev_err(chip->card->dev,
1908 "Cannot turn on display power on i915\n"); 1884 "Cannot turn on display power on i915\n");
diff --git a/sound/pci/hda/hda_intel.h b/sound/pci/hda/hda_intel.h
new file mode 100644
index 000000000000..348611835476
--- /dev/null
+++ b/sound/pci/hda/hda_intel.h
@@ -0,0 +1,71 @@
1/*
2 * This program is free software; you can redistribute it and/or modify it
3 * under the terms of the GNU General Public License as published by the Free
4 * Software Foundation; either version 2 of the License, or (at your option)
5 * any later version.
6 *
7 * This program is distributed in the hope that it will be useful, but WITHOUT
8 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
9 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
10 * more details.
11 *
12 * You should have received a copy of the GNU General Public License along with
13 * this program; if not, write to the Free Software Foundation, Inc., 59
14 * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 */
16#ifndef __SOUND_HDA_INTEL_H
17#define __SOUND_HDA_INTEL_H
18
19#include <drm/i915_component.h>
20#include "hda_priv.h"
21
22struct hda_intel {
23 struct azx chip;
24
25 /* for pending irqs */
26 struct work_struct irq_pending_work;
27
28 /* sync probing */
29 struct completion probe_wait;
30 struct work_struct probe_work;
31
32 /* card list (for power_save trigger) */
33 struct list_head list;
34
35 /* extra flags */
36 unsigned int irq_pending_warned:1;
37
38 /* VGA-switcheroo setup */
39 unsigned int use_vga_switcheroo:1;
40 unsigned int vga_switcheroo_registered:1;
41 unsigned int init_failed:1; /* delayed init failed */
42
43 /* secondary power domain for hdmi audio under vga device */
44 struct dev_pm_domain hdmi_pm_domain;
45
46 /* i915 component interface */
47 struct i915_audio_component audio_component;
48};
49
50#ifdef CONFIG_SND_HDA_I915
51int hda_display_power(struct hda_intel *hda, bool enable);
52void haswell_set_bclk(struct hda_intel *hda);
53int hda_i915_init(struct hda_intel *hda);
54int hda_i915_exit(struct hda_intel *hda);
55#else
56static inline int hda_display_power(struct hda_intel *hda, bool enable)
57{
58 return 0;
59}
60static inline void haswell_set_bclk(struct hda_intel *hda) { return; }
61static inline int hda_i915_init(struct hda_intel *hda)
62{
63 return -ENODEV;
64}
65static inline int hda_i915_exit(struct hda_intel *hda)
66{
67 return 0;
68}
69#endif
70
71#endif