Commit 1a626b68 authored by Slava Grigorev's avatar Slava Grigorev Committed by Alex Deucher

radeon/audio: defined initial audio interface that gets initialized via detect() call

Reviewed-by: default avatarChristian König <christian.koenig@amd.com>
Signed-off-by: default avatarSlava Grigorev <slava.grigorev@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent bfc1f97d
...@@ -23,9 +23,10 @@ ...@@ -23,9 +23,10 @@
#include <linux/hdmi.h> #include <linux/hdmi.h>
#include <drm/drmP.h> #include <drm/drmP.h>
#include "radeon.h" #include "radeon.h"
#include "radeon_audio.h"
#include "sid.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) u32 block_offset, u32 reg)
{ {
unsigned long flags; unsigned long flags;
...@@ -39,7 +40,7 @@ static u32 dce6_endpoint_rreg(struct radeon_device *rdev, ...@@ -39,7 +40,7 @@ static u32 dce6_endpoint_rreg(struct radeon_device *rdev,
return r; 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) u32 block_offset, u32 reg, u32 v)
{ {
unsigned long flags; unsigned long flags;
...@@ -54,10 +55,6 @@ static void dce6_endpoint_wreg(struct radeon_device *rdev, ...@@ -54,10 +55,6 @@ static void dce6_endpoint_wreg(struct radeon_device *rdev,
spin_unlock_irqrestore(&rdev->end_idx_lock, flags); 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) static void dce6_afmt_get_connected_pins(struct radeon_device *rdev)
{ {
int i; int i;
......
...@@ -1757,6 +1757,9 @@ struct r600_audio { ...@@ -1757,6 +1757,9 @@ struct r600_audio {
bool enabled; bool enabled;
struct r600_audio_pin pin[RADEON_MAX_AFMT_BLOCKS]; struct r600_audio_pin pin[RADEON_MAX_AFMT_BLOCKS];
int num_pins; int num_pins;
struct radeon_audio_funcs *hdmi_funcs;
struct radeon_audio_funcs *dp_funcs;
struct radeon_audio_basic_funcs *funcs;
}; };
/* /*
......
...@@ -23,12 +23,18 @@ ...@@ -23,12 +23,18 @@
*/ */
#include <drm/drmP.h> #include <drm/drmP.h>
#include <drm/drm_crtc.h>
#include "radeon.h" #include "radeon.h"
#include "atom.h"
#include "radeon_audio.h"
void r600_audio_enable(struct radeon_device *rdev, struct r600_audio_pin *pin, void r600_audio_enable(struct radeon_device *rdev, struct r600_audio_pin *pin,
u8 enable_mask); u8 enable_mask);
void dce6_audio_enable(struct radeon_device *rdev, struct r600_audio_pin *pin, void dce6_audio_enable(struct radeon_device *rdev, struct r600_audio_pin *pin,
u8 enable_mask); 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] = static const u32 pin_offsets[7] =
{ {
...@@ -41,6 +47,43 @@ static const u32 pin_offsets[7] = ...@@ -41,6 +47,43 @@ static const u32 pin_offsets[7] =
(0x5e90 - 0x5e00), (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) static int radeon_audio_chipset_supported(struct radeon_device *rdev)
{ {
return ASIC_IS_DCE2(rdev) && !ASIC_IS_NODCE(rdev); return ASIC_IS_DCE2(rdev) && !ASIC_IS_NODCE(rdev);
...@@ -79,12 +122,63 @@ int radeon_audio_init(struct radeon_device *rdev) ...@@ -79,12 +122,63 @@ int radeon_audio_init(struct radeon_device *rdev)
rdev->audio.pin[i].connected = false; rdev->audio.pin[i].connected = false;
rdev->audio.pin[i].offset = pin_offsets[i]; rdev->audio.pin[i].offset = pin_offsets[i];
rdev->audio.pin[i].id = 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)) if (ASIC_IS_DCE6(rdev))
dce6_audio_enable(rdev, &rdev->audio.pin[i], false); dce6_audio_enable(rdev, &rdev->audio.pin[i], false);
else else
r600_audio_enable(rdev, &rdev->audio.pin[i], false); 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; 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);
}
...@@ -21,9 +21,35 @@ ...@@ -21,9 +21,35 @@
* *
* Authors: Slava Grigorev <slava.grigorev@amd.com> * Authors: Slava Grigorev <slava.grigorev@amd.com>
*/ */
#ifndef __RADEON_AUDIO_H__ #ifndef __RADEON_AUDIO_H__
#define __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); 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 #endif
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <drm/drm_fb_helper.h> #include <drm/drm_fb_helper.h>
#include <drm/radeon_drm.h> #include <drm/radeon_drm.h>
#include "radeon.h" #include "radeon.h"
#include "radeon_audio.h"
#include "atom.h" #include "atom.h"
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
...@@ -1332,6 +1333,9 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) ...@@ -1332,6 +1333,9 @@ radeon_dvi_detect(struct drm_connector *connector, bool force)
/* updated in get modes as well since we need to know if it's analog or digital */ /* updated in get modes as well since we need to know if it's analog or digital */
radeon_connector_update_scratch_regs(connector, ret); radeon_connector_update_scratch_regs(connector, ret);
if (radeon_audio != 0)
radeon_audio_detect(connector, ret);
exit: exit:
pm_runtime_mark_last_busy(connector->dev->dev); pm_runtime_mark_last_busy(connector->dev->dev);
pm_runtime_put_autosuspend(connector->dev->dev); pm_runtime_put_autosuspend(connector->dev->dev);
...@@ -1654,6 +1658,10 @@ radeon_dp_detect(struct drm_connector *connector, bool force) ...@@ -1654,6 +1658,10 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
} }
radeon_connector_update_scratch_regs(connector, ret); radeon_connector_update_scratch_regs(connector, ret);
if (radeon_audio != 0)
radeon_audio_detect(connector, ret);
out: out:
pm_runtime_mark_last_busy(connector->dev->dev); pm_runtime_mark_last_busy(connector->dev->dev);
pm_runtime_put_autosuspend(connector->dev->dev); pm_runtime_put_autosuspend(connector->dev->dev);
......
...@@ -449,6 +449,7 @@ struct radeon_encoder { ...@@ -449,6 +449,7 @@ struct radeon_encoder {
int audio_polling_active; int audio_polling_active;
bool is_ext_encoder; bool is_ext_encoder;
u16 caps; u16 caps;
struct radeon_audio_funcs *audio;
}; };
struct radeon_connector_atom_dig { struct radeon_connector_atom_dig {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment