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>
This commit is contained in:
Imre Deak 2015-01-08 17:54:14 +02:00 коммит произвёл Daniel Vetter
Родитель 888d0d4216
Коммит 58fddc288b
5 изменённых файлов: 157 добавлений и 0 удалений

Просмотреть файл

@ -830,6 +830,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
intel_runtime_pm_enable(dev_priv); intel_runtime_pm_enable(dev_priv);
i915_audio_component_init(dev_priv);
return 0; return 0;
out_power_well: out_power_well:
@ -870,6 +872,8 @@ int i915_driver_unload(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
int ret; int ret;
i915_audio_component_cleanup(dev_priv);
ret = i915_gem_suspend(dev); ret = i915_gem_suspend(dev);
if (ret) { if (ret) {
DRM_ERROR("failed to idle hardware: %d\n", ret); DRM_ERROR("failed to idle hardware: %d\n", ret);

Просмотреть файл

@ -1698,6 +1698,9 @@ struct drm_i915_private {
struct drm_property *broadcast_rgb_property; struct drm_property *broadcast_rgb_property;
struct drm_property *force_audio_property; struct drm_property *force_audio_property;
/* hda/i915 audio component */
bool audio_component_registered;
uint32_t hw_context_size; uint32_t hw_context_size;
struct list_head context_list; struct list_head context_list;

Просмотреть файл

@ -22,6 +22,9 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/component.h>
#include <drm/i915_component.h>
#include "intel_drv.h"
#include <drm/drmP.h> #include <drm/drmP.h>
#include <drm/drm_edid.h> #include <drm/drm_edid.h>
@ -461,3 +464,110 @@ void intel_init_audio(struct drm_device *dev)
dev_priv->display.audio_codec_disable = ilk_audio_codec_disable; dev_priv->display.audio_codec_disable = ilk_audio_codec_disable;
} }
} }
static void i915_audio_component_get_power(struct device *dev)
{
intel_display_power_get(dev_to_i915(dev), POWER_DOMAIN_AUDIO);
}
static void i915_audio_component_put_power(struct device *dev)
{
intel_display_power_put(dev_to_i915(dev), POWER_DOMAIN_AUDIO);
}
/* Get CDCLK in kHz */
static int i915_audio_component_get_cdclk_freq(struct device *dev)
{
struct drm_i915_private *dev_priv = dev_to_i915(dev);
int ret;
if (WARN_ON_ONCE(!HAS_DDI(dev_priv)))
return -ENODEV;
intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO);
ret = intel_ddi_get_cdclk_freq(dev_priv);
intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO);
return ret;
}
static const struct i915_audio_component_ops i915_audio_component_ops = {
.owner = THIS_MODULE,
.get_power = i915_audio_component_get_power,
.put_power = i915_audio_component_put_power,
.get_cdclk_freq = i915_audio_component_get_cdclk_freq,
};
static int i915_audio_component_bind(struct device *i915_dev,
struct device *hda_dev, void *data)
{
struct i915_audio_component *acomp = data;
if (WARN_ON(acomp->ops || acomp->dev))
return -EEXIST;
acomp->ops = &i915_audio_component_ops;
acomp->dev = i915_dev;
return 0;
}
static void i915_audio_component_unbind(struct device *i915_dev,
struct device *hda_dev, void *data)
{
struct i915_audio_component *acomp = data;
acomp->ops = NULL;
acomp->dev = NULL;
}
static const struct component_ops i915_audio_component_bind_ops = {
.bind = i915_audio_component_bind,
.unbind = i915_audio_component_unbind,
};
/**
* i915_audio_component_init - initialize and register the audio component
* @dev_priv: i915 device instance
*
* This will register with the component framework a child component which
* will bind dynamically to the snd_hda_intel driver's corresponding master
* component when the latter is registered. During binding the child
* initializes an instance of struct i915_audio_component which it receives
* from the master. The master can then start to use the interface defined by
* this struct. Each side can break the binding at any point by deregistering
* its own component after which each side's component unbind callback is
* called.
*
* We ignore any error during registration and continue with reduced
* functionality (i.e. without HDMI audio).
*/
void i915_audio_component_init(struct drm_i915_private *dev_priv)
{
int ret;
ret = component_add(dev_priv->dev->dev, &i915_audio_component_bind_ops);
if (ret < 0) {
DRM_ERROR("failed to add audio component (%d)\n", ret);
/* continue with reduced functionality */
return;
}
dev_priv->audio_component_registered = true;
}
/**
* i915_audio_component_cleanup - deregister the audio component
* @dev_priv: i915 device instance
*
* Deregisters the audio component, breaking any existing binding to the
* corresponding snd_hda_intel driver's master component.
*/
void i915_audio_component_cleanup(struct drm_i915_private *dev_priv)
{
if (!dev_priv->audio_component_registered)
return;
component_del(dev_priv->dev->dev, &i915_audio_component_bind_ops);
dev_priv->audio_component_registered = false;
}

Просмотреть файл

@ -872,6 +872,8 @@ void intel_fb_obj_flush(struct drm_i915_gem_object *obj, bool retire);
void intel_init_audio(struct drm_device *dev); void intel_init_audio(struct drm_device *dev);
void intel_audio_codec_enable(struct intel_encoder *encoder); void intel_audio_codec_enable(struct intel_encoder *encoder);
void intel_audio_codec_disable(struct intel_encoder *encoder); void intel_audio_codec_disable(struct intel_encoder *encoder);
void i915_audio_component_init(struct drm_i915_private *dev_priv);
void i915_audio_component_cleanup(struct drm_i915_private *dev_priv);
/* intel_display.c */ /* intel_display.c */
const char *intel_output_name(int output); const char *intel_output_name(int output);

Просмотреть файл

@ -0,0 +1,38 @@
/*
* Copyright © 2014 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef _I915_COMPONENT_H_
#define _I915_COMPONENT_H_
struct i915_audio_component {
struct device *dev;
const struct i915_audio_component_ops {
struct module *owner;
void (*get_power)(struct device *);
void (*put_power)(struct device *);
int (*get_cdclk_freq)(struct device *);
} *ops;
};
#endif /* _I915_COMPONENT_H_ */