summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorSlava Grigorev <slava.grigorev@amd.com>2014-12-01 21:49:39 +0300
committerAlex Deucher <alexander.deucher@amd.com>2015-01-22 18:39:00 +0300
commit1a626b68fbfa4782477caad56f3b8b652a9dbf7e (patch)
tree6b56038c9f72076fe96f96097b7d318e1f8ff58b /drivers
parentbfc1f97d8ac5d3dc6f7ded64ba9adbac371e912c (diff)
downloadlinux-1a626b68fbfa4782477caad56f3b8b652a9dbf7e.tar.xz
radeon/audio: defined initial audio interface that gets initialized via detect() call
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/radeon/dce6_afmt.c9
-rw-r--r--drivers/gpu/drm/radeon/radeon.h3
-rw-r--r--drivers/gpu/drm/radeon/radeon_audio.c96
-rw-r--r--drivers/gpu/drm/radeon/radeon_audio.h26
-rw-r--r--drivers/gpu/drm/radeon/radeon_connectors.c8
-rw-r--r--drivers/gpu/drm/radeon/radeon_mode.h1
6 files changed, 136 insertions, 7 deletions
diff --git a/drivers/gpu/drm/radeon/dce6_afmt.c b/drivers/gpu/drm/radeon/dce6_afmt.c
index a97fb22ed06a..821f53ce3f65 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 4195e6cc4e52..d15e3c0c09f5 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 cc835e2e0de5..36174b6ca681 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 8455fbdf97e4..e4b0b6437df7 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 26baa9c05f6c..27def67cb6be 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 5135d02b7c1e..920a8be8abad 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 {