Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 6103 → Rev 6104

/drivers/video/drm/radeon/dce6_afmt.c
23,9 → 23,13
#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,
#define DCE8_DCCG_AUDIO_DTO1_PHASE 0x05b8
#define DCE8_DCCG_AUDIO_DTO1_MODULE 0x05bc
 
u32 dce6_endpoint_rreg(struct radeon_device *rdev,
u32 block_offset, u32 reg)
{
unsigned long flags;
39,7 → 43,7
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 → 58,6
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;
76,16 → 76,35
 
struct r600_audio_pin *dce6_audio_get_pin(struct radeon_device *rdev)
{
int i;
struct drm_encoder *encoder;
struct radeon_encoder *radeon_encoder;
struct radeon_encoder_atom_dig *dig;
struct r600_audio_pin *pin = NULL;
int i, pin_count;
 
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];
if (rdev->audio.pin[i].connected) {
pin = &rdev->audio.pin[i];
pin_count = 0;
 
list_for_each_entry(encoder, &rdev->ddev->mode_config.encoder_list, head) {
if (radeon_encoder_is_digital(encoder)) {
radeon_encoder = to_radeon_encoder(encoder);
dig = radeon_encoder->enc_priv;
if (dig->pin == pin)
pin_count++;
}
}
 
if (pin_count == 0)
return pin;
}
}
if (!pin)
DRM_ERROR("No connected audio pins found!\n");
return NULL;
return pin;
}
 
void dce6_afmt_select_pin(struct drm_encoder *encoder)
93,44 → 112,26
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;
 
if (!dig || !dig->afmt || !dig->afmt->pin)
if (!dig || !dig->afmt || !dig->pin)
return;
 
offset = dig->afmt->offset;
 
WREG32(AFMT_AUDIO_SRC_CONTROL + offset,
AFMT_AUDIO_SRC_SELECT(dig->afmt->pin->id));
WREG32(AFMT_AUDIO_SRC_CONTROL + dig->afmt->offset,
AFMT_AUDIO_SRC_SELECT(dig->pin->id));
}
 
void dce6_afmt_write_latency_fields(struct drm_encoder *encoder,
struct drm_connector *connector,
struct drm_display_mode *mode)
{
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;
struct drm_connector *connector;
struct radeon_connector *radeon_connector = NULL;
u32 tmp = 0, offset;
u32 tmp = 0;
 
if (!dig || !dig->afmt || !dig->afmt->pin)
if (!dig || !dig->afmt || !dig->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);
break;
}
}
 
if (!radeon_connector) {
DRM_ERROR("Couldn't find encoder's connector\n");
return;
}
 
if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
if (connector->latency_present[1])
tmp = VIDEO_LIPSYNC(connector->video_latency[1]) |
144,45 → 145,24
else
tmp = VIDEO_LIPSYNC(0) | AUDIO_LIPSYNC(0);
}
WREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC, tmp);
WREG32_ENDPOINT(dig->pin->offset,
AZ_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC, tmp);
}
 
void dce6_afmt_write_speaker_allocation(struct drm_encoder *encoder)
void dce6_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder,
u8 *sadb, int sad_count)
{
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;
struct drm_connector *connector;
struct radeon_connector *radeon_connector = NULL;
u32 offset, tmp;
u8 *sadb = NULL;
int sad_count;
u32 tmp;
 
if (!dig || !dig->afmt || !dig->afmt->pin)
if (!dig || !dig->afmt || !dig->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);
break;
}
}
 
if (!radeon_connector) {
DRM_ERROR("Couldn't find encoder's connector\n");
return;
}
 
sad_count = drm_edid_to_speaker_allocation(radeon_connector_edid(connector), &sadb);
if (sad_count < 0) {
DRM_DEBUG("Couldn't read Speaker Allocation Data Block: %d\n", sad_count);
sad_count = 0;
}
 
/* program the speaker allocation */
tmp = RREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER);
tmp = RREG32_ENDPOINT(dig->pin->offset,
AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER);
tmp &= ~(DP_CONNECTION | SPEAKER_ALLOCATION_MASK);
/* set HDMI mode */
tmp |= HDMI_CONNECTION;
190,22 → 170,42
tmp |= SPEAKER_ALLOCATION(sadb[0]);
else
tmp |= SPEAKER_ALLOCATION(5); /* stereo */
WREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp);
 
kfree(sadb);
WREG32_ENDPOINT(dig->pin->offset,
AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp);
}
 
void dce6_afmt_write_sad_regs(struct drm_encoder *encoder)
void dce6_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder,
u8 *sadb, int sad_count)
{
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;
struct drm_connector *connector;
struct radeon_connector *radeon_connector = NULL;
struct cea_sad *sads;
int i, sad_count;
u32 tmp;
 
if (!dig || !dig->afmt || !dig->pin)
return;
 
/* program the speaker allocation */
tmp = RREG32_ENDPOINT(dig->pin->offset,
AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER);
tmp &= ~(HDMI_CONNECTION | SPEAKER_ALLOCATION_MASK);
/* set DP mode */
tmp |= DP_CONNECTION;
if (sad_count)
tmp |= SPEAKER_ALLOCATION(sadb[0]);
else
tmp |= SPEAKER_ALLOCATION(5); /* stereo */
WREG32_ENDPOINT(dig->pin->offset,
AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp);
}
 
void dce6_afmt_write_sad_regs(struct drm_encoder *encoder,
struct cea_sad *sads, int sad_count)
{
int i;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
struct radeon_device *rdev = encoder->dev->dev_private;
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 },
221,30 → 221,9
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR13, HDMI_AUDIO_CODING_TYPE_WMA_PRO },
};
 
if (!dig || !dig->afmt || !dig->afmt->pin)
if (!dig || !dig->afmt || !dig->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);
break;
}
}
 
if (!radeon_connector) {
DRM_ERROR("Couldn't find encoder's connector\n");
return;
}
 
sad_count = drm_edid_to_sad(radeon_connector_edid(connector), &sads);
if (sad_count <= 0) {
DRM_ERROR("Couldn't read SADs: %d\n", sad_count);
return;
}
BUG_ON(!sads);
 
for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) {
u32 value = 0;
u8 stereo_freqs = 0;
271,17 → 250,10
 
value |= SUPPORTED_FREQUENCIES_STEREO(stereo_freqs);
 
WREG32_ENDPOINT(offset, eld_reg_to_type[i][0], value);
WREG32_ENDPOINT(dig->pin->offset, eld_reg_to_type[i][0], value);
}
 
kfree(sads);
}
 
static int dce6_audio_chipset_supported(struct radeon_device *rdev)
{
return !ASIC_IS_NODCE(rdev);
}
 
void dce6_audio_enable(struct radeon_device *rdev,
struct r600_audio_pin *pin,
u8 enable_mask)
293,64 → 265,46
enable_mask ? AUDIO_ENABLED : 0);
}
 
static const u32 pin_offsets[7] =
void dce6_hdmi_audio_set_dto(struct radeon_device *rdev,
struct radeon_crtc *crtc, unsigned int clock)
{
(0x5e00 - 0x5e00),
(0x5e18 - 0x5e00),
(0x5e30 - 0x5e00),
(0x5e48 - 0x5e00),
(0x5e60 - 0x5e00),
(0x5e78 - 0x5e00),
(0x5e90 - 0x5e00),
};
/* Two dtos; generally use dto0 for HDMI */
u32 value = 0;
 
int dce6_audio_init(struct radeon_device *rdev)
{
int i;
if (crtc)
value |= DCCG_AUDIO_DTO0_SOURCE_SEL(crtc->crtc_id);
 
if (!radeon_audio || !dce6_audio_chipset_supported(rdev))
return 0;
WREG32(DCCG_AUDIO_DTO_SOURCE, value);
 
rdev->audio.enabled = true;
 
if (ASIC_IS_DCE81(rdev)) /* KV: 4 streams, 7 endpoints */
rdev->audio.num_pins = 7;
else if (ASIC_IS_DCE83(rdev)) /* KB: 2 streams, 3 endpoints */
rdev->audio.num_pins = 3;
else if (ASIC_IS_DCE8(rdev)) /* BN/HW: 6 streams, 7 endpoints */
rdev->audio.num_pins = 7;
else if (ASIC_IS_DCE61(rdev)) /* TN: 4 streams, 6 endpoints */
rdev->audio.num_pins = 6;
else if (ASIC_IS_DCE64(rdev)) /* OL: 2 streams, 2 endpoints */
rdev->audio.num_pins = 2;
else /* SI: 6 streams, 6 endpoints */
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;
/* disable audio. it will be set up later */
dce6_audio_enable(rdev, &rdev->audio.pin[i], false);
/* Express [24MHz / target pixel clock] as an exact rational
* number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE
* is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
*/
WREG32(DCCG_AUDIO_DTO0_PHASE, 24000);
WREG32(DCCG_AUDIO_DTO0_MODULE, clock);
}
 
return 0;
}
 
void dce6_audio_fini(struct radeon_device *rdev)
void dce6_dp_audio_set_dto(struct radeon_device *rdev,
struct radeon_crtc *crtc, unsigned int clock)
{
int i;
/* Two dtos; generally use dto1 for DP */
u32 value = 0;
value |= DCCG_AUDIO_DTO_SEL;
 
if (!rdev->audio.enabled)
return;
if (crtc)
value |= DCCG_AUDIO_DTO0_SOURCE_SEL(crtc->crtc_id);
 
for (i = 0; i < rdev->audio.num_pins; i++)
dce6_audio_enable(rdev, &rdev->audio.pin[i], false);
WREG32(DCCG_AUDIO_DTO_SOURCE, value);
 
rdev->audio.enabled = false;
/* Express [24MHz / target pixel clock] as an exact rational
* number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE
* is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
*/
if (ASIC_IS_DCE8(rdev)) {
WREG32(DCE8_DCCG_AUDIO_DTO1_PHASE, 24000);
WREG32(DCE8_DCCG_AUDIO_DTO1_MODULE, clock);
} else {
WREG32(DCCG_AUDIO_DTO1_PHASE, 24000);
WREG32(DCCG_AUDIO_DTO1_MODULE, clock);
}
}