diff --git a/drivers/gpu/drm/radeon/dce6_afmt.c b/drivers/gpu/drm/radeon/dce6_afmt.c
index a97fb22..821f53c 100644
--- a/drivers/gpu/drm/radeon/dce6_afmt.c
+++ b/drivers/gpu/drm/radeon/dce6_afmt.c
@@ -23,9 +23,10 @@
 #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;
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 4195e6c..d15e3c0 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -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;
 };
 
 /*
diff --git a/drivers/gpu/drm/radeon/radeon_audio.c b/drivers/gpu/drm/radeon/radeon_audio.c
index cc835e2..36174b6 100644
--- a/drivers/gpu/drm/radeon/radeon_audio.c
+++ b/drivers/gpu/drm/radeon/radeon_audio.c
@@ -23,12 +23,18 @@
  */
 
 #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);
+}
diff --git a/drivers/gpu/drm/radeon/radeon_audio.h b/drivers/gpu/drm/radeon/radeon_audio.h
index 8455fbd..e4b0b64 100644
--- a/drivers/gpu/drm/radeon/radeon_audio.h
+++ b/drivers/gpu/drm/radeon/radeon_audio.h
@@ -21,9 +21,35 @@
  *
  * 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
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index 26baa9c..27def67 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -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);
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 390db89..c0deaec 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -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 {
