[alsa-devel] [RFC 2/5] drm: add helper functions to add bridge audio capabilities

Arnaud Pouliquen arnaud.pouliquen at st.com
Mon Sep 21 15:19:53 CEST 2015


Extend bridge capabilities for audio to enable to connect an audio driver to a
DRM driver with audio capabilities

Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen at st.com>
---
 drivers/gpu/drm/drm_bridge.c | 114 +++++++++++++++++++++++++++++++++++++++++++
 include/drm/drm_crtc.h       |  31 ++++++++++++
 include/linux/hdmi.h         |  16 ++++++
 3 files changed, 161 insertions(+)

diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 6b8f721..2284ac9 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -328,6 +328,120 @@ struct drm_bridge *of_drm_find_bridge(struct device_node *np)
 EXPORT_SYMBOL(of_drm_find_bridge);
 #endif
 
+/**
+ * DOC: audio bridge callbacks
+ *
+ * The drm_audio_bridge_funcs ops are populated by the bridge driver that have
+ * audio capabilities (a.e HDMI)
+ * The drm internals(atomic and crtc helpers) use the helpers defined in
+ * drm_bridge.c
+ * These helpers call a specific drm_audio_bridge_funcs ops for all the bridges
+ * during encoder configuration.
+ *
+ * When creating a bridge driver, one can implement drm_audio_bridge_funcs op
+ * with the help of these rough rules:
+ *
+ * pre_enable: this contains things needed to be done for the bridge before
+ * audio is enabled by its source.
+ *
+ * enable: this contains things needed to be done for the audio bridge once its
+ * source is enabled. In other words, enable is called once the source is
+ * ready to start stream rendering.
+ *
+ * disable: this contains things needed to be done for audio bridge when to
+ * disable the audio part for the bridge, assuming that its source is still
+ * enabled.
+ *
+ * post_disable: this contains things needed to be done for the bridge once
+ * its source is disabled.
+ *
+ * mode_set: this sets up the mode for the audio bridge. It assumes that its
+ * source (an encoder or a bridge) has set the mode too.
+ */
+
+/**
+ * drm_audio_bridge_pre_enable - calls 'pre_enable' drm_audio_bridge_funcs ops
+ *                               for audio bridges in the encoder chain.
+ * @bridge: bridge control structure
+ *
+ * Calls 'pre_enable' drm_audio_bridge_funcs op for  audio bridge in the
+ * encoder chain.
+ *
+ */
+
+void drm_audio_bridge_pre_enable(struct drm_bridge *bridge)
+{
+	if (!bridge)
+		return;
+
+	if (bridge->audio_funcs->pre_enable)
+		bridge->audio_funcs->pre_enable(bridge);
+}
+EXPORT_SYMBOL(drm_audio_bridge_pre_enable);
+
+/**
+ * drm_audio_bridge_disable - calls 'disable' drm_audio_bridge_funcs op for
+ *                            audio bridge in the encoder chain.
+ * @bridge: bridge control structure
+ *
+ * Calls 'disable' drm_audio_bridge_funcs op for bridges with audio in the
+ * encoder chain.
+ *
+ */
+void drm_audio_bridge_disable(struct drm_bridge *bridge)
+{
+	if (!bridge)
+		return;
+
+	if (bridge->audio_funcs->disable)
+		bridge->audio_funcs->disable(bridge);
+}
+EXPORT_SYMBOL(drm_audio_bridge_disable);
+
+/**
+ * drm_audio_bridge_mode_set - set audio mode for audio bridge in the
+ *			 encoder chain
+ * @bridge: bridge control structure
+ * @mode: desired audio mode to be set for the audio bridge
+ *
+ * Calls 'mode_set' drm_audio_bridge_funcs op for audio bridge in the
+ * encoder chain.
+ *
+ */
+void drm_audio_bridge_mode_set(struct drm_bridge *bridge,
+			       struct hdmi_audio_mode *mode)
+{
+	if (!bridge)
+		return;
+
+	if (bridge->audio_funcs->mode_set)
+		bridge->audio_funcs->mode_set(bridge, mode);
+}
+EXPORT_SYMBOL(drm_audio_bridge_mode_set);
+
+/**
+ * drm_audio_bridge_enable - calls 'enable' drm_audio_bridge_funcs op for all bridges
+ *		       in the encoder chain.
+ * @bridge: bridge control structure
+ *
+ * Calls 'enable' drm_audio_bridge_funcs op for all the bridges in the encoder
+ * chain, starting from the first bridge to the last. These are called
+ * after completing the encoder's commit op.
+ *
+ * Note that the bridge passed should be the one closest to the encoder
+ */
+void drm_audio_bridge_enable(struct drm_bridge *bridge)
+{
+	if (!bridge)
+		return;
+
+	if (bridge->audio_funcs->mode_set)
+		bridge->audio_funcs->enable(bridge);
+
+}
+EXPORT_SYMBOL(drm_audio_bridge_enable);
+
+
 MODULE_AUTHOR("Ajay Kumar <ajaykumar.rs at samsung.com>");
 MODULE_DESCRIPTION("DRM bridge infrastructure");
 MODULE_LICENSE("GPL and additional rights");
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 3b4d8a4..5074019 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -583,6 +583,7 @@ struct drm_encoder_funcs {
  * @possible_clones: bitmask of potential sibling encoders for cloning
  * @crtc: currently bound CRTC
  * @bridge: bridge associated to the encoder
+ * @abridge: optional audio bridge associated to the encoder (HDMI)
  * @funcs: control functions
  * @helper_private: mid-layer private data
  *
@@ -601,6 +602,7 @@ struct drm_encoder {
 
 	struct drm_crtc *crtc;
 	struct drm_bridge *bridge;
+	struct drm_bridge *abridge;
 	const struct drm_encoder_funcs *funcs;
 	const void *helper_private;
 };
@@ -905,6 +907,24 @@ struct drm_bridge_funcs {
 };
 
 /**
+ * struct drm_audio_bridge_funcs - audio drm_bridge control functions
+ * @attach: Called during drm_audio_bridge_attach
+ * @mode_fixup: Try to fixup (or reject entirely) proposed mode for this bridge
+ * @disable: Called right before encoder prepare, disables the bridge
+ * @post_disable: Called right after encoder prepare, for lockstepped disable
+ * @mode_set: Set this mode to the bridge
+ * @pre_enable: Called right before encoder commit, for lockstepped commit
+ * @enable: Called right after encoder commit, enables the bridge
+ */
+struct drm_audio_bridge_funcs {
+	void (*disable)(struct drm_bridge *bridge);
+	void (*pre_enable)(struct drm_bridge *bridge);
+	void (*enable)(struct drm_bridge *bridge);
+	int (*mode_set)(struct drm_bridge *bridge,
+			struct hdmi_audio_mode *mode);
+};
+
+/**
  * struct drm_bridge - central DRM bridge control structure
  * @dev: DRM device this bridge belongs to
  * @encoder: encoder to which this bridge is connected
@@ -925,7 +945,9 @@ struct drm_bridge {
 	struct list_head list;
 
 	const struct drm_bridge_funcs *funcs;
+	const struct drm_audio_bridge_funcs *audio_funcs;
 	void *driver_private;
+	void *snd_private;
 };
 
 /**
@@ -1271,6 +1293,15 @@ extern int drm_encoder_init(struct drm_device *dev,
 			    const struct drm_encoder_funcs *funcs,
 			    int encoder_type);
 
+int drm_audio_bridge_attach(struct drm_device *dev,
+			     struct drm_bridge *bridge);
+void drm_audio_bridge_disable(struct drm_bridge *bridge);
+void drm_audio_bridge_mode_set(struct drm_bridge *bridge,
+			       struct hdmi_audio_mode *mode);
+void drm_audio_bridge_pre_enable(struct drm_bridge *bridge);
+void drm_audio_bridge_enable(struct drm_bridge *bridge);
+
+
 /**
  * drm_encoder_crtc_ok - can a given crtc drive a given encoder?
  * @encoder: encoder to test
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index 32107a0..d3d1a80 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -333,11 +333,27 @@ int hdmi_infoframe_unpack(union hdmi_infoframe *frame, void *buffer);
 void hdmi_infoframe_log(const char *level, struct device *dev,
 			union hdmi_infoframe *frame);
 
+/**
+ * struct hdmi_audio_n_cts - n and cts parameter for ACR packets
+ */
 struct hdmi_audio_n_cts {
 	unsigned int n;
 	unsigned int cts;
 };
 
+/**
+ * struct hdmi_audio_mode - hdmi audio structure for audio configuration
+ * @enabled audio state
+ * @infoframe: audio infoframe info frame
+ * @data: private data use by alsa driver to retrieve context
+ *
+ * This is used by audio driver to configure the HDMI audio part
+ */
+struct hdmi_audio_mode {
+	bool enabled;
+	struct hdmi_audio_infoframe infoframe;
+};
+
 int hdmi_audio_compute_n_cts(unsigned int audio_fs, unsigned long pixel_clk,
 			     struct hdmi_audio_n_cts *n_cts);
 
-- 
1.9.1



More information about the Alsa-devel mailing list