diff options
author | Imre Deak <imre.deak@intel.com> | 2015-01-08 10:54:14 -0500 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2015-01-11 20:48:20 -0500 |
commit | 58fddc288b5cec192ad9eb9221da7ed14d974a27 (patch) | |
tree | 1f7e7a2c7d6f5b7992e258427dce4293a295cb44 /drivers/gpu | |
parent | 888d0d421663313739a8bf93459c6ba61fd4b121 (diff) |
drm/i915: add component support
Register a component to be used to interface with the snd_hda_intel
driver. This is meant to replace the same interface that is currently
based on module symbol lookup.
v2:
- change roles between the hda and i915 components (Daniel)
- add the implementation to a new file (Jani)
- use better namespacing (Jani)
v3:
- move the implementation to intel_audio.c (Daniel)
- rename display_component to audio_component (Daniel)
- add kerneldoc (Daniel)
v4:
- run forgotten git rm i915_component.c (Jani)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Reviewed-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/i915/i915_dma.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_audio.c | 110 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 2 |
4 files changed, 119 insertions, 0 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.h b/drivers/gpu/drm/i915/i915_drv.h index a343f2f35dfd..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 | ||
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); |