Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 58fddc28 authored by Imre Deak's avatar Imre Deak Committed by Daniel Vetter
Browse files

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: default avatarImre Deak <imre.deak@intel.com>
Reviewed-by: default avatarTakashi Iwai <tiwai@suse.de>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent 888d0d42
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -830,6 +830,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)

	intel_runtime_pm_enable(dev_priv);

	i915_audio_component_init(dev_priv);

	return 0;

out_power_well:
@@ -870,6 +872,8 @@ int i915_driver_unload(struct drm_device *dev)
	struct drm_i915_private *dev_priv = dev->dev_private;
	int ret;

	i915_audio_component_cleanup(dev_priv);

	ret = i915_gem_suspend(dev);
	if (ret) {
		DRM_ERROR("failed to idle hardware: %d\n", ret);
+3 −0
Original line number Diff line number Diff line
@@ -1698,6 +1698,9 @@ struct drm_i915_private {
	struct drm_property *broadcast_rgb_property;
	struct drm_property *force_audio_property;

	/* hda/i915 audio component */
	bool audio_component_registered;

	uint32_t hw_context_size;
	struct list_head context_list;

+110 −0
Original line number Diff line number Diff line
@@ -22,6 +22,9 @@
 */

#include <linux/kernel.h>
#include <linux/component.h>
#include <drm/i915_component.h>
#include "intel_drv.h"

#include <drm/drmP.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;
	}
}

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;
}
+2 −0
Original line number Diff line number Diff line
@@ -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_audio_codec_enable(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 */
const char *intel_output_name(int output);
+38 −0
Original line number Diff line number Diff line
/*
 * 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_ */