diff options
author | Takashi Iwai <tiwai@suse.de> | 2015-01-13 01:54:02 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2015-01-13 01:54:02 -0500 |
commit | 1d69970d27210d18eaf153e04ed697ac7a4f17dc (patch) | |
tree | 9848e5f2dfa0c23482b6fac276a0eb271c890242 | |
parent | 7bfb8575b82cd1facde3dc5be2b125f408171646 (diff) | |
parent | fcf3aac5fc307f0cae429f5844ddc25761662858 (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.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.c | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_audio.c | 110 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_runtime_pm.c | 56 | ||||
-rw-r--r-- | include/drm/i915_component.h | 38 | ||||
-rw-r--r-- | include/drm/i915_powerwell.h | 37 | ||||
-rw-r--r-- | sound/pci/hda/hda_i915.c | 154 | ||||
-rw-r--r-- | sound/pci/hda/hda_i915.h | 37 | ||||
-rw-r--r-- | sound/pci/hda/hda_intel.c | 60 | ||||
-rw-r--r-- | sound/pci/hda/hda_intel.h | 71 |
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 | ||
835 | out_power_well: | 837 | out_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 | ||
941 | static int i915_pm_suspend_late(struct device *dev) | 941 | static 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 | ||
961 | static int i915_pm_resume_early(struct device *dev) | 960 | static 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 | ||
972 | static int i915_pm_resume(struct device *dev) | 970 | static 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 | ||
1787 | static 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 | |||
468 | static void i915_audio_component_get_power(struct device *dev) | ||
469 | { | ||
470 | intel_display_power_get(dev_to_i915(dev), POWER_DOMAIN_AUDIO); | ||
471 | } | ||
472 | |||
473 | static 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 */ | ||
479 | static 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 | |||
494 | static 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 | |||
501 | static 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 | |||
515 | static 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 | |||
524 | static 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 | */ | ||
545 | void 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 | */ | ||
566 | void 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); | |||
872 | void intel_init_audio(struct drm_device *dev); | 872 | void intel_init_audio(struct drm_device *dev); |
873 | void intel_audio_codec_enable(struct intel_encoder *encoder); | 873 | void intel_audio_codec_enable(struct intel_encoder *encoder); |
874 | void intel_audio_codec_disable(struct intel_encoder *encoder); | 874 | void intel_audio_codec_disable(struct intel_encoder *encoder); |
875 | void i915_audio_component_init(struct drm_i915_private *dev_priv); | ||
876 | void i915_audio_component_cleanup(struct drm_i915_private *dev_priv); | ||
875 | 877 | ||
876 | /* intel_display.c */ | 878 | /* intel_display.c */ |
877 | const char *intel_output_name(int output); | 879 | const 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 | ||
53 | static 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 | ||
1125 | static void intel_power_domains_resume(struct drm_i915_private *dev_priv) | 1118 | static 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 */ | ||
1332 | int 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 | } | ||
1344 | EXPORT_SYMBOL_GPL(i915_request_power_well); | ||
1345 | |||
1346 | /* Display audio driver power well release */ | ||
1347 | int 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 | } | ||
1359 | EXPORT_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 | */ | ||
1367 | int 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 | } | ||
1379 | EXPORT_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 | |||
27 | struct 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 */ | ||
33 | extern int i915_request_power_well(void); | ||
34 | extern int i915_release_power_well(void); | ||
35 | extern 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 | ||
34 | static int (*get_power)(void); | 36 | int hda_display_power(struct hda_intel *hda, bool enable) |
35 | static int (*put_power)(void); | ||
36 | static int (*get_cdclk)(void); | ||
37 | |||
38 | int 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 | ||
51 | void haswell_set_bclk(struct azx *chip) | 53 | void 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 | 90 | static int hda_component_master_bind(struct device *dev) | |
88 | int 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"); | 119 | out_unbind: |
120 | component_unbind_all(dev, acomp); | ||
110 | 121 | ||
111 | return err; | 122 | return ret; |
112 | } | 123 | } |
113 | 124 | ||
114 | int hda_i915_exit(void) | 125 | static 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; | 137 | static const struct component_master_ops hda_component_master_ops = { |
138 | .bind = hda_component_master_bind, | ||
139 | .unbind = hda_component_master_unbind, | ||
140 | }; | ||
141 | |||
142 | static 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 | |||
148 | int 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; | ||
175 | out_master_del: | ||
176 | component_master_del(dev, &hda_component_master_ops); | ||
177 | out_err: | ||
178 | dev_err(dev, "failed to add i915 component master (%d)\n", ret); | ||
179 | |||
180 | return ret; | ||
181 | } | ||
182 | |||
183 | int 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 | ||
20 | int hda_display_power(bool enable); | ||
21 | void haswell_set_bclk(struct azx *chip); | ||
22 | int hda_i915_init(void); | ||
23 | int hda_i915_exit(void); | ||
24 | #else | ||
25 | static inline int hda_display_power(bool enable) { return 0; } | ||
26 | static inline void haswell_set_bclk(struct azx *chip) { return; } | ||
27 | static inline int hda_i915_init(void) | ||
28 | { | ||
29 | return -ENODEV; | ||
30 | } | ||
31 | static 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 */ |
69 | enum { | 69 | enum { |
@@ -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 | ||
357 | struct 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 |
383 | static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool on) | 358 | static 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 | |||
22 | struct 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 | ||
51 | int hda_display_power(struct hda_intel *hda, bool enable); | ||
52 | void haswell_set_bclk(struct hda_intel *hda); | ||
53 | int hda_i915_init(struct hda_intel *hda); | ||
54 | int hda_i915_exit(struct hda_intel *hda); | ||
55 | #else | ||
56 | static inline int hda_display_power(struct hda_intel *hda, bool enable) | ||
57 | { | ||
58 | return 0; | ||
59 | } | ||
60 | static inline void haswell_set_bclk(struct hda_intel *hda) { return; } | ||
61 | static inline int hda_i915_init(struct hda_intel *hda) | ||
62 | { | ||
63 | return -ENODEV; | ||
64 | } | ||
65 | static inline int hda_i915_exit(struct hda_intel *hda) | ||
66 | { | ||
67 | return 0; | ||
68 | } | ||
69 | #endif | ||
70 | |||
71 | #endif | ||