drm/radeon: add audio support for DCE6/8 GPUs (v12)

Similar to DCE4/5, but supports multiple audio pins
which can be assigned per afmt block.

v2: rework the driver to handle more than one audio
pin.
v3: try different dto reg
v4: properly program dto
v5 (ck): change dto programming order
v6: program speaker allocation block
v7: rebase
v8: rebase on Rafał's changes
v9: integrated Rafał's comments, update to latest
    drm_edid_to_speaker_allocation API
v10: add missing line break in error message
v11: add back audio enabled messages
v12: fix copy paste typo in r600_audio_enable

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Christian König <christian.koenig@amd.com>
Acked-by: Rafał Miłecki <zajec5@gmail.com>
This commit is contained in:
Alex Deucher 2013-07-31 16:51:33 -04:00
parent a4d39e6894
commit b530602fd4
15 changed files with 455 additions and 62 deletions

View File

@ -80,7 +80,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
r600_dpm.o rs780_dpm.o rv6xx_dpm.o rv770_dpm.o rv730_dpm.o rv740_dpm.o \
rv770_smc.o cypress_dpm.o btc_dpm.o sumo_dpm.o sumo_smc.o trinity_dpm.o \
trinity_smc.o ni_dpm.o si_smc.o si_dpm.o kv_smc.o kv_dpm.o ci_smc.o \
ci_dpm.o
ci_dpm.o dce6_afmt.o
# add async DMA block
radeon-y += \

View File

@ -682,8 +682,6 @@ atombios_digital_setup(struct drm_encoder *encoder, int action)
int
atombios_get_encoder_mode(struct drm_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct drm_connector *connector;
struct radeon_connector *radeon_connector;
@ -710,8 +708,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
case DRM_MODE_CONNECTOR_DVII:
case DRM_MODE_CONNECTOR_HDMIB: /* HDMI-B is basically DL-DVI; analog works fine */
if (drm_detect_hdmi_monitor(radeon_connector->edid) &&
radeon_audio &&
!ASIC_IS_DCE6(rdev)) /* remove once we support DCE6 */
radeon_audio)
return ATOM_ENCODER_MODE_HDMI;
else if (radeon_connector->use_digital)
return ATOM_ENCODER_MODE_DVI;
@ -722,8 +719,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
case DRM_MODE_CONNECTOR_HDMIA:
default:
if (drm_detect_hdmi_monitor(radeon_connector->edid) &&
radeon_audio &&
!ASIC_IS_DCE6(rdev)) /* remove once we support DCE6 */
radeon_audio)
return ATOM_ENCODER_MODE_HDMI;
else
return ATOM_ENCODER_MODE_DVI;
@ -737,8 +733,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
(dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP))
return ATOM_ENCODER_MODE_DP;
else if (drm_detect_hdmi_monitor(radeon_connector->edid) &&
radeon_audio &&
!ASIC_IS_DCE6(rdev)) /* remove once we support DCE6 */
radeon_audio)
return ATOM_ENCODER_MODE_HDMI;
else
return ATOM_ENCODER_MODE_DVI;

View File

@ -7004,6 +7004,10 @@ static int cik_startup(struct radeon_device *rdev)
return r;
}
r = dce6_audio_init(rdev);
if (r)
return r;
return 0;
}
@ -7049,6 +7053,7 @@ int cik_resume(struct radeon_device *rdev)
*/
int cik_suspend(struct radeon_device *rdev)
{
dce6_audio_fini(rdev);
radeon_vm_manager_fini(rdev);
cik_cp_enable(rdev, false);
cik_sdma_enable(rdev, false);

View File

@ -0,0 +1,251 @@
/*
* Copyright 2013 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include <linux/hdmi.h>
#include <drm/drmP.h>
#include "radeon.h"
#include "sid.h"
static u32 dce6_endpoint_rreg(struct radeon_device *rdev,
u32 block_offset, u32 reg)
{
u32 r;
WREG32(AZ_F0_CODEC_ENDPOINT_INDEX + block_offset, reg);
r = RREG32(AZ_F0_CODEC_ENDPOINT_DATA + block_offset);
return r;
}
static void dce6_endpoint_wreg(struct radeon_device *rdev,
u32 block_offset, u32 reg, u32 v)
{
if (ASIC_IS_DCE8(rdev))
WREG32(AZ_F0_CODEC_ENDPOINT_INDEX + block_offset, reg);
else
WREG32(AZ_F0_CODEC_ENDPOINT_INDEX + block_offset,
AZ_ENDPOINT_REG_WRITE_EN | AZ_ENDPOINT_REG_INDEX(reg));
WREG32(AZ_F0_CODEC_ENDPOINT_DATA + block_offset, v);
}
#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;
u32 offset, tmp;
for (i = 0; i < rdev->audio.num_pins; i++) {
offset = rdev->audio.pin[i].offset;
tmp = RREG32_ENDPOINT(offset,
AZ_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT);
if (((tmp & PORT_CONNECTIVITY_MASK) >> PORT_CONNECTIVITY_SHIFT) == 1)
rdev->audio.pin[i].connected = false;
else
rdev->audio.pin[i].connected = true;
}
}
struct r600_audio_pin *dce6_audio_get_pin(struct radeon_device *rdev)
{
int i;
dce6_afmt_get_connected_pins(rdev);
for (i = 0; i < rdev->audio.num_pins; i++) {
if (rdev->audio.pin[i].connected)
return &rdev->audio.pin[i];
}
DRM_ERROR("No connected audio pins found!\n");
return NULL;
}
void dce6_afmt_select_pin(struct drm_encoder *encoder)
{
struct radeon_device *rdev = encoder->dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
u32 offset = dig->afmt->offset;
u32 id = dig->afmt->pin->id;
if (!dig->afmt->pin)
return;
WREG32(AFMT_AUDIO_SRC_CONTROL + offset, AFMT_AUDIO_SRC_SELECT(id));
}
void dce6_afmt_write_sad_regs(struct drm_encoder *encoder)
{
struct radeon_device *rdev = encoder->dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
u32 offset, tmp;
struct drm_connector *connector;
struct radeon_connector *radeon_connector = NULL;
struct cea_sad *sads;
int i, sad_count, sadb_count;
u8 *sadb;
static const u16 eld_reg_to_type[][2] = {
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0, HDMI_AUDIO_CODING_TYPE_PCM },
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR1, HDMI_AUDIO_CODING_TYPE_AC3 },
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR2, HDMI_AUDIO_CODING_TYPE_MPEG1 },
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR3, HDMI_AUDIO_CODING_TYPE_MP3 },
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR4, HDMI_AUDIO_CODING_TYPE_MPEG2 },
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR5, HDMI_AUDIO_CODING_TYPE_AAC_LC },
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR6, HDMI_AUDIO_CODING_TYPE_DTS },
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR7, HDMI_AUDIO_CODING_TYPE_ATRAC },
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR9, HDMI_AUDIO_CODING_TYPE_EAC3 },
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR10, HDMI_AUDIO_CODING_TYPE_DTS_HD },
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR11, HDMI_AUDIO_CODING_TYPE_MLP },
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR13, HDMI_AUDIO_CODING_TYPE_WMA_PRO },
};
if (!dig->afmt->pin)
return;
offset = dig->afmt->pin->offset;
list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
if (connector->encoder == encoder)
radeon_connector = to_radeon_connector(connector);
}
if (!radeon_connector) {
DRM_ERROR("Couldn't find encoder's connector\n");
return;
}
sad_count = drm_edid_to_sad(radeon_connector->edid, &sads);
if (sad_count < 0) {
DRM_ERROR("Couldn't read SADs: %d\n", sad_count);
return;
}
BUG_ON(!sads);
sadb_count = drm_edid_to_speaker_allocation(radeon_connector->edid, &sadb);
if (sadb_count < 0) {
DRM_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", sadb_count);
return;
}
/* program the speaker allocation */
tmp = RREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER);
tmp &= ~(DP_CONNECTION | SPEAKER_ALLOCATION_MASK);
/* set HDMI mode */
tmp |= HDMI_CONNECTION;
if (sadb_count)
tmp |= SPEAKER_ALLOCATION(sadb[0]);
else
tmp |= SPEAKER_ALLOCATION(5); /* stereo */
WREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp);
for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) {
u32 value = 0;
int j;
for (j = 0; j < sad_count; j++) {
struct cea_sad *sad = &sads[j];
if (sad->format == eld_reg_to_type[i][1]) {
value = MAX_CHANNELS(sad->channels) |
DESCRIPTOR_BYTE_2(sad->byte2) |
SUPPORTED_FREQUENCIES(sad->freq);
if (sad->format == HDMI_AUDIO_CODING_TYPE_PCM)
value |= SUPPORTED_FREQUENCIES_STEREO(sad->freq);
break;
}
}
WREG32_ENDPOINT(offset, eld_reg_to_type[i][0], value);
}
kfree(sads);
kfree(sadb);
}
static int dce6_audio_chipset_supported(struct radeon_device *rdev)
{
return !ASIC_IS_NODCE(rdev);
}
static void dce6_audio_enable(struct radeon_device *rdev,
struct r600_audio_pin *pin,
bool enable)
{
WREG32_ENDPOINT(pin->offset, AZ_F0_CODEC_PIN_CONTROL_HOTPLUG_CONTROL,
AUDIO_ENABLED);
DRM_INFO("%s audio %d support\n", enable ? "Enabling" : "Disabling", pin->id);
}
static const u32 pin_offsets[7] =
{
(0x5e00 - 0x5e00),
(0x5e18 - 0x5e00),
(0x5e30 - 0x5e00),
(0x5e48 - 0x5e00),
(0x5e60 - 0x5e00),
(0x5e78 - 0x5e00),
(0x5e90 - 0x5e00),
};
int dce6_audio_init(struct radeon_device *rdev)
{
int i;
if (!radeon_audio || !dce6_audio_chipset_supported(rdev))
return 0;
rdev->audio.enabled = true;
if (ASIC_IS_DCE8(rdev))
rdev->audio.num_pins = 7;
else
rdev->audio.num_pins = 6;
for (i = 0; i < rdev->audio.num_pins; i++) {
rdev->audio.pin[i].channels = -1;
rdev->audio.pin[i].rate = -1;
rdev->audio.pin[i].bits_per_sample = -1;
rdev->audio.pin[i].status_bits = 0;
rdev->audio.pin[i].category_code = 0;
rdev->audio.pin[i].connected = false;
rdev->audio.pin[i].offset = pin_offsets[i];
rdev->audio.pin[i].id = i;
dce6_audio_enable(rdev, &rdev->audio.pin[i], true);
}
return 0;
}
void dce6_audio_fini(struct radeon_device *rdev)
{
int i;
if (!rdev->audio.enabled)
return;
for (i = 0; i < rdev->audio.num_pins; i++)
dce6_audio_enable(rdev, &rdev->audio.pin[i], false);
rdev->audio.enabled = false;
}

View File

@ -32,6 +32,9 @@
#include "evergreend.h"
#include "atom.h"
extern void dce6_afmt_write_sad_regs(struct drm_encoder *encoder);
extern void dce6_afmt_select_pin(struct drm_encoder *encoder);
/*
* update the N and CTS parameters for a given pixel clock rate
*/
@ -157,22 +160,26 @@ static void evergreen_audio_set_dto(struct drm_encoder *encoder, u32 clock)
if (!dig || !dig->afmt)
return;
if (max_ratio >= 8) {
dto_phase = 192 * 1000;
wallclock_ratio = 3;
} else if (max_ratio >= 4) {
dto_phase = 96 * 1000;
wallclock_ratio = 2;
} else if (max_ratio >= 2) {
dto_phase = 48 * 1000;
wallclock_ratio = 1;
} else {
if (ASIC_IS_DCE6(rdev)) {
dto_phase = 24 * 1000;
wallclock_ratio = 0;
} else {
if (max_ratio >= 8) {
dto_phase = 192 * 1000;
wallclock_ratio = 3;
} else if (max_ratio >= 4) {
dto_phase = 96 * 1000;
wallclock_ratio = 2;
} else if (max_ratio >= 2) {
dto_phase = 48 * 1000;
wallclock_ratio = 1;
} else {
dto_phase = 24 * 1000;
wallclock_ratio = 0;
}
dto_cntl = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio);
WREG32(DCCG_AUDIO_DTO0_CNTL, dto_cntl);
}
dto_cntl = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio);
WREG32(DCCG_AUDIO_DTO0_CNTL, dto_cntl);
/* XXX two dtos; generally use dto0 for hdmi */
/* Express [24MHz / target pixel clock] as an exact rational
@ -266,7 +273,13 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode
AFMT_AUDIO_CHANNEL_ENABLE(0xff));
/* fglrx sets 0x40 in 0x5f80 here */
evergreen_hdmi_write_sad_regs(encoder);
if (ASIC_IS_DCE6(rdev)) {
dce6_afmt_select_pin(encoder);
dce6_afmt_write_sad_regs(encoder);
} else {
evergreen_hdmi_write_sad_regs(encoder);
}
err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
if (err < 0) {
@ -302,6 +315,8 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode
void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
@ -314,6 +329,15 @@ void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
if (!enable && !dig->afmt->enabled)
return;
if (enable) {
if (ASIC_IS_DCE6(rdev))
dig->afmt->pin = dce6_audio_get_pin(rdev);
else
dig->afmt->pin = r600_audio_get_pin(rdev);
} else {
dig->afmt->pin = NULL;
}
dig->afmt->enabled = enable;
DRM_DEBUG("%sabling HDMI interface @ 0x%04X for encoder 0x%x\n",

View File

@ -2027,9 +2027,15 @@ static int cayman_startup(struct radeon_device *rdev)
return r;
}
r = r600_audio_init(rdev);
if (r)
return r;
if (ASIC_IS_DCE6(rdev)) {
r = dce6_audio_init(rdev);
if (r)
return r;
} else {
r = r600_audio_init(rdev);
if (r)
return r;
}
return 0;
}
@ -2060,7 +2066,10 @@ int cayman_resume(struct radeon_device *rdev)
int cayman_suspend(struct radeon_device *rdev)
{
r600_audio_fini(rdev);
if (ASIC_IS_DCE6(rdev))
dce6_audio_fini(rdev);
else
r600_audio_fini(rdev);
radeon_vm_manager_fini(rdev);
cayman_cp_enable(rdev, false);
cayman_dma_stop(rdev);

View File

@ -57,12 +57,12 @@ static bool radeon_dig_encoder(struct drm_encoder *encoder)
*/
static int r600_audio_chipset_supported(struct radeon_device *rdev)
{
return ASIC_IS_DCE2(rdev) && !ASIC_IS_DCE6(rdev);
return ASIC_IS_DCE2(rdev) && !ASIC_IS_NODCE(rdev);
}
struct r600_audio r600_audio_status(struct radeon_device *rdev)
struct r600_audio_pin r600_audio_status(struct radeon_device *rdev)
{
struct r600_audio status;
struct r600_audio_pin status;
uint32_t value;
value = RREG32(R600_AUDIO_RATE_BPS_CHANNEL);
@ -120,16 +120,16 @@ void r600_audio_update_hdmi(struct work_struct *work)
struct radeon_device *rdev = container_of(work, struct radeon_device,
audio_work);
struct drm_device *dev = rdev->ddev;
struct r600_audio audio_status = r600_audio_status(rdev);
struct r600_audio_pin audio_status = r600_audio_status(rdev);
struct drm_encoder *encoder;
bool changed = false;
if (rdev->audio_status.channels != audio_status.channels ||
rdev->audio_status.rate != audio_status.rate ||
rdev->audio_status.bits_per_sample != audio_status.bits_per_sample ||
rdev->audio_status.status_bits != audio_status.status_bits ||
rdev->audio_status.category_code != audio_status.category_code) {
rdev->audio_status = audio_status;
if (rdev->audio.pin[0].channels != audio_status.channels ||
rdev->audio.pin[0].rate != audio_status.rate ||
rdev->audio.pin[0].bits_per_sample != audio_status.bits_per_sample ||
rdev->audio.pin[0].status_bits != audio_status.status_bits ||
rdev->audio.pin[0].category_code != audio_status.category_code) {
rdev->audio.pin[0] = audio_status;
changed = true;
}
@ -141,13 +141,13 @@ void r600_audio_update_hdmi(struct work_struct *work)
}
}
/*
* turn on/off audio engine
*/
static void r600_audio_engine_enable(struct radeon_device *rdev, bool enable)
/* enable the audio stream */
static void r600_audio_enable(struct radeon_device *rdev,
struct r600_audio_pin *pin,
bool enable)
{
u32 value = 0;
DRM_INFO("%s audio support\n", enable ? "Enabling" : "Disabling");
if (ASIC_IS_DCE4(rdev)) {
if (enable) {
value |= 0x81000000; /* Required to enable audio */
@ -158,7 +158,7 @@ static void r600_audio_engine_enable(struct radeon_device *rdev, bool enable)
WREG32_P(R600_AUDIO_ENABLE,
enable ? 0x81000000 : 0x0, ~0x81000000);
}
rdev->audio_enabled = enable;
DRM_INFO("%s audio %d support\n", enable ? "Enabling" : "Disabling", pin->id);
}
/*
@ -169,13 +169,17 @@ int r600_audio_init(struct radeon_device *rdev)
if (!radeon_audio || !r600_audio_chipset_supported(rdev))
return 0;
r600_audio_engine_enable(rdev, true);
rdev->audio.enabled = true;
rdev->audio_status.channels = -1;
rdev->audio_status.rate = -1;
rdev->audio_status.bits_per_sample = -1;
rdev->audio_status.status_bits = 0;
rdev->audio_status.category_code = 0;
rdev->audio.num_pins = 1;
rdev->audio.pin[0].channels = -1;
rdev->audio.pin[0].rate = -1;
rdev->audio.pin[0].bits_per_sample = -1;
rdev->audio.pin[0].status_bits = 0;
rdev->audio.pin[0].category_code = 0;
rdev->audio.pin[0].id = 0;
r600_audio_enable(rdev, &rdev->audio.pin[0], true);
return 0;
}
@ -186,8 +190,16 @@ int r600_audio_init(struct radeon_device *rdev)
*/
void r600_audio_fini(struct radeon_device *rdev)
{
if (!rdev->audio_enabled)
if (!rdev->audio.enabled)
return;
r600_audio_engine_enable(rdev, false);
r600_audio_enable(rdev, &rdev->audio.pin[0], false);
rdev->audio.enabled = false;
}
struct r600_audio_pin *r600_audio_get_pin(struct radeon_device *rdev)
{
/* only one pin on 6xx-NI */
return &rdev->audio.pin[0];
}

View File

@ -382,7 +382,7 @@ void r600_hdmi_update_audio_settings(struct drm_encoder *encoder)
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
struct r600_audio audio = r600_audio_status(rdev);
struct r600_audio_pin audio = r600_audio_status(rdev);
uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE];
struct hdmi_audio_infoframe frame;
uint32_t offset;
@ -491,6 +491,11 @@ void r600_hdmi_enable(struct drm_encoder *encoder, bool enable)
if (!enable && !dig->afmt->enabled)
return;
if (enable)
dig->afmt->pin = r600_audio_get_pin(rdev);
else
dig->afmt->pin = NULL;
/* Older chipsets require setting HDMI and routing manually */
if (!ASIC_IS_DCE3(rdev)) {
if (enable)

View File

@ -696,7 +696,7 @@ union radeon_irq_stat_regs {
#define RADEON_MAX_HPD_PINS 6
#define RADEON_MAX_CRTCS 6
#define RADEON_MAX_AFMT_BLOCKS 6
#define RADEON_MAX_AFMT_BLOCKS 7
struct radeon_irq {
bool installed;
@ -1537,12 +1537,21 @@ int radeon_uvd_calc_upll_dividers(struct radeon_device *rdev,
int radeon_uvd_send_upll_ctlreq(struct radeon_device *rdev,
unsigned cg_upll_func_cntl);
struct r600_audio {
struct r600_audio_pin {
int channels;
int rate;
int bits_per_sample;
u8 status_bits;
u8 category_code;
u32 offset;
bool connected;
u32 id;
};
struct r600_audio {
bool enabled;
struct r600_audio_pin pin[RADEON_MAX_AFMT_BLOCKS];
int num_pins;
};
/*
@ -2128,9 +2137,8 @@ struct radeon_device {
struct work_struct reset_work;
int num_crtc; /* number of crtcs */
struct mutex dc_hw_i2c_mutex; /* display controller hw i2c mutex */
bool audio_enabled;
bool has_uvd;
struct r600_audio audio_status; /* audio stuff */
struct r600_audio audio; /* audio stuff */
struct notifier_block acpi_nb;
/* only one userspace can use Hyperz features or CMASK at a time */
struct drm_file *hyperz_filp;
@ -2594,6 +2602,8 @@ int radeon_vm_bo_rmv(struct radeon_device *rdev,
/* audio */
void r600_audio_update_hdmi(struct work_struct *work);
struct r600_audio_pin *r600_audio_get_pin(struct radeon_device *rdev);
struct r600_audio_pin *dce6_audio_get_pin(struct radeon_device *rdev);
/*
* R600 vram scratch functions

View File

@ -1739,6 +1739,8 @@ static struct radeon_asic trinity_asic = {
.wait_for_vblank = &dce4_wait_for_vblank,
.set_backlight_level = &atombios_set_backlight_level,
.get_backlight_level = &atombios_get_backlight_level,
.hdmi_enable = &evergreen_hdmi_enable,
.hdmi_setmode = &evergreen_hdmi_setmode,
},
.copy = {
.blit = &r600_copy_cpdma,
@ -1867,6 +1869,8 @@ static struct radeon_asic si_asic = {
.wait_for_vblank = &dce4_wait_for_vblank,
.set_backlight_level = &atombios_set_backlight_level,
.get_backlight_level = &atombios_get_backlight_level,
.hdmi_enable = &evergreen_hdmi_enable,
.hdmi_setmode = &evergreen_hdmi_setmode,
},
.copy = {
.blit = NULL,
@ -2009,6 +2013,8 @@ static struct radeon_asic ci_asic = {
.bandwidth_update = &dce8_bandwidth_update,
.get_vblank_counter = &evergreen_get_vblank_counter,
.wait_for_vblank = &dce4_wait_for_vblank,
.hdmi_enable = &evergreen_hdmi_enable,
.hdmi_setmode = &evergreen_hdmi_setmode,
},
.copy = {
.blit = NULL,
@ -2107,6 +2113,8 @@ static struct radeon_asic kv_asic = {
.bandwidth_update = &dce8_bandwidth_update,
.get_vblank_counter = &evergreen_get_vblank_counter,
.wait_for_vblank = &dce4_wait_for_vblank,
.hdmi_enable = &evergreen_hdmi_enable,
.hdmi_setmode = &evergreen_hdmi_setmode,
},
.copy = {
.blit = NULL,

View File

@ -379,7 +379,7 @@ void r600_disable_interrupts(struct radeon_device *rdev);
void r600_rlc_stop(struct radeon_device *rdev);
/* r600 audio */
int r600_audio_init(struct radeon_device *rdev);
struct r600_audio r600_audio_status(struct radeon_device *rdev);
struct r600_audio_pin r600_audio_status(struct radeon_device *rdev);
void r600_audio_fini(struct radeon_device *rdev);
int r600_hdmi_buffer_status_changed(struct drm_encoder *encoder);
void r600_hdmi_update_audio_settings(struct drm_encoder *encoder);
@ -628,6 +628,8 @@ int trinity_dpm_force_performance_level(struct radeon_device *rdev,
/* DCE6 - SI */
void dce6_bandwidth_update(struct radeon_device *rdev);
int dce6_audio_init(struct radeon_device *rdev);
void dce6_audio_fini(struct radeon_device *rdev);
/*
* si

View File

@ -1254,8 +1254,8 @@ static void radeon_afmt_init(struct radeon_device *rdev)
for (i = 0; i < RADEON_MAX_AFMT_BLOCKS; i++)
rdev->mode_info.afmt[i] = NULL;
if (ASIC_IS_DCE6(rdev)) {
/* todo */
if (ASIC_IS_NODCE(rdev)) {
/* nothing to do */
} else if (ASIC_IS_DCE4(rdev)) {
static uint32_t eg_offsets[] = {
EVERGREEN_CRTC0_REGISTER_OFFSET,
@ -1264,12 +1264,19 @@ static void radeon_afmt_init(struct radeon_device *rdev)
EVERGREEN_CRTC3_REGISTER_OFFSET,
EVERGREEN_CRTC4_REGISTER_OFFSET,
EVERGREEN_CRTC5_REGISTER_OFFSET,
0x13830 - 0x7030,
};
int num_afmt;
/* DCE8 has 7 audio blocks tied to DIG encoders */
/* DCE6 has 6 audio blocks tied to DIG encoders */
/* DCE4/5 has 6 audio blocks tied to DIG encoders */
/* DCE4.1 has 2 audio blocks tied to DIG encoders */
if (ASIC_IS_DCE5(rdev))
if (ASIC_IS_DCE8(rdev))
num_afmt = 7;
else if (ASIC_IS_DCE6(rdev))
num_afmt = 6;
else if (ASIC_IS_DCE5(rdev))
num_afmt = 6;
else if (ASIC_IS_DCE41(rdev))
num_afmt = 2;

View File

@ -225,6 +225,7 @@ struct radeon_afmt {
int offset;
bool last_buffer_filled_status;
int id;
struct r600_audio_pin *pin;
};
struct radeon_mode_info {
@ -233,7 +234,7 @@ struct radeon_mode_info {
enum radeon_connector_table connector_table;
bool mode_config_initialized;
struct radeon_crtc *crtcs[6];
struct radeon_afmt *afmt[6];
struct radeon_afmt *afmt[7];
/* DVI-I properties */
struct drm_property *coherent_mode_property;
/* DAC enable load detect */

View File

@ -6264,6 +6264,10 @@ static int si_startup(struct radeon_device *rdev)
return r;
}
r = dce6_audio_init(rdev);
if (r)
return r;
return 0;
}
@ -6295,6 +6299,7 @@ int si_resume(struct radeon_device *rdev)
int si_suspend(struct radeon_device *rdev)
{
dce6_audio_fini(rdev);
radeon_vm_manager_fini(rdev);
si_cp_enable(rdev, false);
cayman_dma_stop(rdev);

View File

@ -635,6 +635,54 @@
#define HDP_REG_COHERENCY_FLUSH_CNTL 0x54A0
/* DCE6 ELD audio interface */
#define AZ_F0_CODEC_ENDPOINT_INDEX 0x5E00
# define AZ_ENDPOINT_REG_INDEX(x) (((x) & 0xff) << 0)
# define AZ_ENDPOINT_REG_WRITE_EN (1 << 8)
#define AZ_F0_CODEC_ENDPOINT_DATA 0x5E04
#define AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER 0x25
#define SPEAKER_ALLOCATION(x) (((x) & 0x7f) << 0)
#define SPEAKER_ALLOCATION_MASK (0x7f << 0)
#define SPEAKER_ALLOCATION_SHIFT 0
#define HDMI_CONNECTION (1 << 16)
#define DP_CONNECTION (1 << 17)
#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0 0x28 /* LPCM */
#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR1 0x29 /* AC3 */
#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR2 0x2A /* MPEG1 */
#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR3 0x2B /* MP3 */
#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR4 0x2C /* MPEG2 */
#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR5 0x2D /* AAC */
#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR6 0x2E /* DTS */
#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR7 0x2F /* ATRAC */
#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR8 0x30 /* one bit audio - leave at 0 (default) */
#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR9 0x31 /* Dolby Digital */
#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR10 0x32 /* DTS-HD */
#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR11 0x33 /* MAT-MLP */
#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR12 0x34 /* DTS */
#define AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR13 0x35 /* WMA Pro */
# define MAX_CHANNELS(x) (((x) & 0x7) << 0)
/* max channels minus one. 7 = 8 channels */
# define SUPPORTED_FREQUENCIES(x) (((x) & 0xff) << 8)
# define DESCRIPTOR_BYTE_2(x) (((x) & 0xff) << 16)
# define SUPPORTED_FREQUENCIES_STEREO(x) (((x) & 0xff) << 24) /* LPCM only */
/* SUPPORTED_FREQUENCIES, SUPPORTED_FREQUENCIES_STEREO
* bit0 = 32 kHz
* bit1 = 44.1 kHz
* bit2 = 48 kHz
* bit3 = 88.2 kHz
* bit4 = 96 kHz
* bit5 = 176.4 kHz
* bit6 = 192 kHz
*/
#define AZ_F0_CODEC_PIN_CONTROL_HOTPLUG_CONTROL 0x54
# define AUDIO_ENABLED (1 << 31)
#define AZ_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT 0x56
#define PORT_CONNECTIVITY_MASK (3 << 30)
#define PORT_CONNECTIVITY_SHIFT 30
#define DC_LB_MEMORY_SPLIT 0x6b0c
#define DC_LB_MEMORY_CONFIG(x) ((x) << 20)
@ -755,6 +803,17 @@
/* 0x6e98, 0x7a98, 0x10698, 0x11298, 0x11e98, 0x12a98 */
#define CRTC_STATUS_FRAME_COUNT 0x6e98
#define AFMT_AUDIO_SRC_CONTROL 0x713c
#define AFMT_AUDIO_SRC_SELECT(x) (((x) & 7) << 0)
/* AFMT_AUDIO_SRC_SELECT
* 0 = stream0
* 1 = stream1
* 2 = stream2
* 3 = stream3
* 4 = stream4
* 5 = stream5
*/
#define GRBM_CNTL 0x8000
#define GRBM_READ_TIMEOUT(x) ((x) << 0)