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 | 137 ++++++++++++++++++++++++++++++++++++++++++-
 include/drm/drm_crtc.h       |  62 ++++++++++++++++++++
 include/drm/drm_modes.h      |  12 ++++
 3 files changed, 210 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 6b8f721..d1a437e 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -194,7 +194,7 @@ EXPORT_SYMBOL(drm_bridge_mode_fixup);
  * chain, starting from the last bridge to the first. These are called before
  * calling the encoder's prepare op.
  *
- * Note: the bridge passed should be the one closest to the encoder
+ * Note: the bridge passed should be the othingsne closest to the encoder
  */
 void drm_bridge_disable(struct drm_bridge *bridge)
 {
@@ -328,6 +328,141 @@ 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 has
+ * audio capabilities (e.g. HDMI)
+ * The alsa driver (or asoc codec) uses the defined helpers.
+ * These helpers call a specific drm_audio_bridge_funcs ops defined by
+ * bridges with audio capabilities during encoder configuration.
+ *
+ * pre_enable: this contains actions needed to be done by the bridge before
+ * audio is enabled by its source.
+ *
+ * enable: this contains actions needed to be done by 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 actions needed to be done by audio bridge when
+ * disable the audio part, assuming that its source is still enabled.
+ *
+ * post_disable: this contains actions needed to be done by the bridge once
+ * its source is disabled.
+ *
+ * mode_set: this sets up the mode by the audio bridge. It assumes that its
+ * audio source is aligned on this mode.
+ *
+ * mode_get: this get the supported modes based on ELD table. this can be use
+ * by audio source to fix audio constraints according to mode.
+ */
+
+/**
+ * drm_audio_bridge_pre_enable - calls 'pre_enable' drm_audio_bridge_funcs op
+ * for audio bridge in the encoder chain.
+ * @bridge: bridge control structure
+ */
+int drm_audio_bridge_pre_enable(struct drm_bridge *bridge,
+                                struct drm_audio_bridge_cfg *cfg)
+{
+       if (!bridge)
+               return -EINVAL;
+
+       if (bridge->audio_funcs->pre_enable)
+               return bridge->audio_funcs->pre_enable(bridge, cfg);
+
+       return 0;
+}
+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
+ */
+int drm_audio_bridge_disable(struct drm_bridge *bridge)
+{
+       if (!bridge)
+               return -EINVAL;
+
+       if (bridge->audio_funcs->disable)
+               return bridge->audio_funcs->disable(bridge);
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_audio_bridge_disable);
+
+/**
+ * drm_audio_bridge_enable - calls 'enable' drm_audio_bridge_funcs audio
+ * bridge in the encoder chain.
+ * @bridge: bridge control structure
+ */
+int drm_audio_bridge_enable(struct drm_bridge *bridge)
+{
+       if (!bridge)
+               return -EINVAL;
+
+       if (bridge->audio_funcs->enable)
+               return bridge->audio_funcs->enable(bridge);
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_audio_bridge_enable);
+
+/**
+ * drm_audio_bridge_post_disable - calls 'disable' drm_audio_bridge_funcs op
+ * for audio bridge in the encoder chain.
+ * @bridge: bridge control structure
+ */
+int drm_audio_bridge_post_disable(struct drm_bridge *bridge)
+{
+       if (!bridge)
+               return -EINVAL;
+
+       if (bridge->audio_funcs->post_disable)
+               return bridge->audio_funcs->post_disable(bridge);
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_audio_bridge_post_disable);
+
+/**
+ * drm_audio_bridge_mode_set - calls 'mode_set' drm_audio_bridge_funcs op
+ * for audio bridge in the encoder chain.
+ * @bridge: bridge control structure
+ * @mode: desired audio mode to be set for the audio bridge
+ */
+int drm_audio_bridge_mode_set(struct drm_bridge *bridge,
+                              struct hdmi_audio_mode *mode)
+{
+       if (!bridge)
+               return -EINVAL;
+
+       if (bridge->audio_funcs->mode_set)
+               return bridge->audio_funcs->mode_set(bridge, mode);
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_audio_bridge_mode_set);
+
+/**
+ * drm_audio_bridge_mode_get - calls 'enable'drm_audio_bridge_funcs op
+ * for audio bridge in the encoder chain.
+ * @bridge: bridge control structure
+ * Note: The returned pointer needs to be freed using kfree().
+ */
+uint8_t *drm_audio_bridge_mode_get(struct drm_bridge *bridge)
+{
+       if (!bridge)
+               return NULL;
+
+       if (bridge->audio_funcs->mode_get)
+               return bridge->audio_funcs->mode_get(bridge);
+
+       return NULL;
+}
+EXPORT_SYMBOL(drm_audio_bridge_mode_get);
+
 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..f13626a 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,56 @@ struct drm_bridge_funcs {
 };

 /**
+ * struct drm_audio_bridge_cfg - audio interface configuration
+ * @fmt: bus format
+ * @sample_rate: sampling frequency
+ * @sample_width: sample size
+ * @channels: number of channels
+ * @frame_clk_master: frame synchro master
+ * @frame_clk_inv: frame clock inverted
+ * @bit_clk_master: bit clock master
+ * @bit_clk_inv: bit clock inverted
+ */
+struct drm_audio_bridge_cfg {
+       enum {
+               HDMI_I2S,
+               HDMI_RIGHT_J,
+               HDMI_LEFT_J,
+               HDMI_DSP_A,
+               HDMI_DSP_B,
+               HDMI_AC97,
+               HDMI_SPDIF,
+       } fmt;
+       int sample_rate;
+       int sample_width;
+       int channels;
+       int frame_clk_master:1;
+       int frame_clk_inv:1;
+       int bit_clk_master:1;
+       int bit_clk_inv:1;
+};
+
+/**
+ * struct drm_audio_bridge_funcs - audio drm_bridge control functions
+ * @disable: Called to disable the audio bridge
+ * @post_disable: Called for post disable actions
+ * @pre_enable: Called to configure the audio bridge
+ * @enable: Called to enable the audio bridge
+ * @mode_set: Set the audio bridge mode
+ * @mode_get: Get ELD buffer for audio mode supported.
+ */
+struct drm_audio_bridge_funcs {
+       int (*disable)(struct drm_bridge *bridge);
+       int (*post_disable)(struct drm_bridge *bridge);
+       int (*pre_enable)(struct drm_bridge *bridge,
+                          struct drm_audio_bridge_cfg *cfg);
+       int (*enable)(struct drm_bridge *bridge);
+       int  (*mode_set)(struct drm_bridge *bridge,
+                        struct hdmi_audio_mode *mode);
+       uint8_t *(*mode_get)(struct drm_bridge *bridge);
+};
+
+/**
  * struct drm_bridge - central DRM bridge control structure
  * @dev: DRM device this bridge belongs to
  * @encoder: encoder to which this bridge is connected
@@ -925,6 +977,7 @@ struct drm_bridge {
        struct list_head list;

        const struct drm_bridge_funcs *funcs;
+       const struct drm_audio_bridge_funcs *audio_funcs;
        void *driver_private;
 };

@@ -1266,6 +1319,15 @@ void drm_bridge_mode_set(struct drm_bridge *bridge,
 void drm_bridge_pre_enable(struct drm_bridge *bridge);
 void drm_bridge_enable(struct drm_bridge *bridge);

+int drm_audio_bridge_pre_enable(struct drm_bridge *bridge,
+                               struct drm_audio_bridge_cfg *cfg);
+int drm_audio_bridge_enable(struct drm_bridge *bridge);
+int drm_audio_bridge_disable(struct drm_bridge *bridge);
+int drm_audio_bridge_post_disable(struct drm_bridge *bridge);
+int drm_audio_bridge_mode_set(struct drm_bridge *bridge,
+                              struct hdmi_audio_mode *mode);
+uint8_t *drm_audio_bridge_mode_get(struct drm_bridge *bridge);
+
 extern int drm_encoder_init(struct drm_device *dev,
                            struct drm_encoder *encoder,
                            const struct drm_encoder_funcs *funcs,
diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h
index 08a8cac..e923e32 100644
--- a/include/drm/drm_modes.h
+++ b/include/drm/drm_modes.h
@@ -164,6 +164,18 @@ struct drm_cmdline_mode {
        enum drm_connector_force force;
 };

+/*
+ * struct hdmi_audio_mode - hdmi audio structure for audio configuration
+ * @infoframe: audio info frame
+ * @iec_status: iec60958 channel status bytes
+ *
+ * This is used by audio driver to configure the HDMI audio part
+ */
+struct hdmi_audio_mode {
+       struct hdmi_audio_infoframe infoframe;
+       unsigned char iec_status[24];
+};
+
 /**
  * drm_mode_is_stereo - check for stereo mode flags
  * @mode: drm_display_mode to check
-- 
1.9.1

Reply via email to