diff options
Diffstat (limited to 'drivers/gpu/drm/radeon')
-rw-r--r-- | drivers/gpu/drm/radeon/dce6_afmt.c | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_audio.c | 96 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_audio.h | 26 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_connectors.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_mode.h | 1 |
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 { |