radeon/audio: defined initial audio interface that gets initialized via detect()...
authorSlava Grigorev <slava.grigorev@amd.com>
Mon, 1 Dec 2014 18:49:39 +0000 (13:49 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Thu, 22 Jan 2015 15:39:00 +0000 (10:39 -0500)
Reviewed-by: Christian König <christian.koenig@amd.com>
Signed-off-by: Slava Grigorev <slava.grigorev@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/radeon/dce6_afmt.c
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_audio.c
drivers/gpu/drm/radeon/radeon_audio.h
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_mode.h

index a97fb22ed06afef20de76ea26ea42e14a7404abb..821f53ce3f65323460e63007bf5f6d4b2ca8bea1 100644 (file)
 #include <linux/hdmi.h>
 #include <drm/drmP.h>
 #include "radeon.h"
+#include "radeon_audio.h"
 #include "sid.h"
 
-static u32 dce6_endpoint_rreg(struct radeon_device *rdev,
+u32 dce6_endpoint_rreg(struct radeon_device *rdev,
                              u32 block_offset, u32 reg)
 {
        unsigned long flags;
@@ -39,7 +40,7 @@ static u32 dce6_endpoint_rreg(struct radeon_device *rdev,
        return r;
 }
 
-static void dce6_endpoint_wreg(struct radeon_device *rdev,
+void dce6_endpoint_wreg(struct radeon_device *rdev,
                               u32 block_offset, u32 reg, u32 v)
 {
        unsigned long flags;
@@ -54,10 +55,6 @@ static void dce6_endpoint_wreg(struct radeon_device *rdev,
        spin_unlock_irqrestore(&rdev->end_idx_lock, flags);
 }
 
-#define RREG32_ENDPOINT(block, reg) dce6_endpoint_rreg(rdev, (block), (reg))
-#define WREG32_ENDPOINT(block, reg, v) dce6_endpoint_wreg(rdev, (block), (reg), (v))
-
-
 static void dce6_afmt_get_connected_pins(struct radeon_device *rdev)
 {
        int i;
index 4195e6cc4e52fac927f2304ed70eddea528b9a74..d15e3c0c09f5cf335419bbfd80fa399b36adad11 100644 (file)
@@ -1757,6 +1757,9 @@ struct r600_audio {
        bool enabled;
        struct r600_audio_pin pin[RADEON_MAX_AFMT_BLOCKS];
        int num_pins;
+       struct radeon_audio_funcs *hdmi_funcs;
+       struct radeon_audio_funcs *dp_funcs;
+       struct radeon_audio_basic_funcs *funcs;
 };
 
 /*
index cc835e2e0de561daf7f485158c6e91a23a5c5c59..36174b6ca681cedd581eb8f114ca8e5ebf68ecdb 100644 (file)
  */
 
 #include <drm/drmP.h>
+#include <drm/drm_crtc.h>
 #include "radeon.h"
+#include "atom.h"
+#include "radeon_audio.h"
 
 void r600_audio_enable(struct radeon_device *rdev, struct r600_audio_pin *pin,
                u8 enable_mask);
 void dce6_audio_enable(struct radeon_device *rdev, struct r600_audio_pin *pin,
                u8 enable_mask);
+u32 dce6_endpoint_rreg(struct radeon_device *rdev, u32 offset, u32 reg);
+void dce6_endpoint_wreg(struct radeon_device *rdev,
+               u32 offset, u32 reg, u32 v);
 
 static const u32 pin_offsets[7] =
 {
@@ -41,6 +47,43 @@ static const u32 pin_offsets[7] =
        (0x5e90 - 0x5e00),
 };
 
+static u32 radeon_audio_rreg(struct radeon_device *rdev, u32 offset, u32 reg)
+{
+       return RREG32(reg);
+}
+
+static void radeon_audio_wreg(struct radeon_device *rdev, u32 offset,
+               u32 reg, u32 v)
+{
+       WREG32(reg, v);
+}
+
+static struct radeon_audio_basic_funcs dce32_funcs = {
+       .endpoint_rreg = radeon_audio_rreg,
+       .endpoint_wreg = radeon_audio_wreg,
+};
+
+static struct radeon_audio_basic_funcs dce4_funcs = {
+       .endpoint_rreg = radeon_audio_rreg,
+       .endpoint_wreg = radeon_audio_wreg,
+};
+
+static struct radeon_audio_basic_funcs dce6_funcs = {
+       .endpoint_rreg = dce6_endpoint_rreg,
+       .endpoint_wreg = dce6_endpoint_wreg,
+};
+
+static void radeon_audio_interface_init(struct radeon_device *rdev)
+{
+       if (ASIC_IS_DCE6(rdev)) {
+               rdev->audio.funcs = &dce6_funcs;
+       } else if (ASIC_IS_DCE4(rdev)) {
+               rdev->audio.funcs = &dce4_funcs;
+       } else {
+               rdev->audio.funcs = &dce32_funcs;
+       }
+}
+
 static int radeon_audio_chipset_supported(struct radeon_device *rdev)
 {
        return ASIC_IS_DCE2(rdev) && !ASIC_IS_NODCE(rdev);
@@ -79,12 +122,63 @@ int radeon_audio_init(struct radeon_device *rdev)
                rdev->audio.pin[i].connected = false;
                rdev->audio.pin[i].offset = pin_offsets[i];
                rdev->audio.pin[i].id = i;
-               /* disable audio.  it will be set up later */
+       }
+
+       radeon_audio_interface_init(rdev);
+
+       /* disable audio.  it will be set up later */
+       for (i = 0; i < rdev->audio.num_pins; i++)
                if (ASIC_IS_DCE6(rdev))
                        dce6_audio_enable(rdev, &rdev->audio.pin[i], false);
                else
                        r600_audio_enable(rdev, &rdev->audio.pin[i], false);
+
+       return 0;
+}
+
+void radeon_audio_detect(struct drm_connector *connector,
+       enum drm_connector_status status)
+{
+       if (!connector || !connector->encoder)
+               return;
+
+       if (status == connector_status_connected) {
+               int sink_type;
+               struct radeon_device *rdev = connector->encoder->dev->dev_private;
+               struct radeon_connector *radeon_connector;
+               struct radeon_encoder *radeon_encoder =
+                       to_radeon_encoder(connector->encoder);
+
+               if (!drm_detect_monitor_audio(radeon_connector_edid(connector))) {
+                       radeon_encoder->audio = 0;
+                       return;
+               }
+
+               radeon_connector = to_radeon_connector(connector);
+               sink_type = radeon_dp_getsinktype(radeon_connector);
+
+               if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort &&
+                       sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT)
+                       radeon_encoder->audio = rdev->audio.dp_funcs;
+               else
+                       radeon_encoder->audio = rdev->audio.hdmi_funcs;
+               /* TODO: set up the sads, etc. and set the audio enable_mask */
+       } else {
+               /* TODO: reset the audio enable_mask */
        }
+}
+
+u32 radeon_audio_endpoint_rreg(struct radeon_device *rdev, u32 offset, u32 reg)
+{
+       if (rdev->audio.funcs->endpoint_rreg)
+               return rdev->audio.funcs->endpoint_rreg(rdev, offset, reg);
 
        return 0;
 }
+
+void radeon_audio_endpoint_wreg(struct radeon_device *rdev, u32 offset,
+       u32 reg, u32 v)
+{
+       if (rdev->audio.funcs->endpoint_wreg)
+               rdev->audio.funcs->endpoint_wreg(rdev, offset, reg, v);
+}
index 8455fbdf97e4475fc4b6d6b9281ace03299dab81..e4b0b6437df7c707d945dbbf16be83c0fd4843d2 100644 (file)
  *
  * Authors: Slava Grigorev <slava.grigorev@amd.com>
  */
+
 #ifndef __RADEON_AUDIO_H__
 #define __RADEON_AUDIO_H__
 
+#include <linux/types.h>
+
+#define RREG32_ENDPOINT(block, reg)            \
+       radeon_audio_endpoint_rreg(rdev, (block), (reg))
+#define WREG32_ENDPOINT(block, reg, v) \
+       radeon_audio_endpoint_wreg(rdev, (block), (reg), (v))
+
+struct radeon_audio_basic_funcs
+{
+       u32  (*endpoint_rreg)(struct radeon_device *rdev, u32 offset, u32 reg);
+       void (*endpoint_wreg)(struct radeon_device *rdev,
+               u32 offset, u32 reg, u32 v);
+};
+
+struct radeon_audio_funcs
+{
+       /* TODO: add mode depended audio interface */
+};
+
 int radeon_audio_init(struct radeon_device *rdev);
+void radeon_audio_detect(struct drm_connector *connector,
+       enum drm_connector_status status);
+u32 radeon_audio_endpoint_rreg(struct radeon_device *rdev,
+       u32 offset, u32 reg);
+void radeon_audio_endpoint_wreg(struct radeon_device *rdev,
+       u32 offset,     u32 reg, u32 v);
 
 #endif
index 26baa9c05f6c49ac40e2a238a6079fa8e0e40920..27def67cb6beb31ca398956cf911ebdc0658755a 100644 (file)
@@ -29,6 +29,7 @@
 #include <drm/drm_fb_helper.h>
 #include <drm/radeon_drm.h>
 #include "radeon.h"
+#include "radeon_audio.h"
 #include "atom.h"
 
 #include <linux/pm_runtime.h>
@@ -1332,6 +1333,9 @@ out:
        /* updated in get modes as well since we need to know if it's analog or digital */
        radeon_connector_update_scratch_regs(connector, ret);
 
+       if (radeon_audio != 0)
+               radeon_audio_detect(connector, ret);
+
 exit:
        pm_runtime_mark_last_busy(connector->dev->dev);
        pm_runtime_put_autosuspend(connector->dev->dev);
@@ -1654,6 +1658,10 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
        }
 
        radeon_connector_update_scratch_regs(connector, ret);
+
+       if (radeon_audio != 0)
+               radeon_audio_detect(connector, ret);
+
 out:
        pm_runtime_mark_last_busy(connector->dev->dev);
        pm_runtime_put_autosuspend(connector->dev->dev);
index 5135d02b7c1ef719ed870e603dbaa656771e79d7..920a8be8abada71c8b1473f844e39ca3535807a8 100644 (file)
@@ -449,6 +449,7 @@ struct radeon_encoder {
        int audio_polling_active;
        bool is_ext_encoder;
        u16 caps;
+       struct radeon_audio_funcs *audio;
 };
 
 struct radeon_connector_atom_dig {