Merge branch 'drm-next-3.20' of git://people.freedesktop.org/~agd5f/linux into drm-next

Radeon drm-next changes for 3.20.  Highlights:
- Indirect draw support for evergreen/NI hw
- SMC fan control support for SI/CI
- Manual fan control for SI/CI
- DP audio support
- Lots of code cleanup

* 'drm-next-3.20' of git://people.freedesktop.org/~agd5f/linux: (45 commits)
  drm/radeon: make MMU_NOTIFIER optional
  drm/radeon: use NULL rather then 0 in audio detect
  drm/radeon: whitespace clean up in radeon_audio.c
  radeon/audio: enable DP audio
  radeon/audio: moved audio caps programming to audio_hotplug() function
  radeon/audio: applied audio_dpms() and audio_mode_set() calls
  radeon/audio: consolidate audio_mode_set() functions
  radeon/audio: removed unnecessary debug settings
  radeon/audio: moved mute programming to a separate function
  radeon/audio: moved audio packet programming to a separate function
  radeon/audio: set_avi_packet() function cleanup
  radeon/audio: removed unnecessary CRC control programing
  radeon: moved HDMI color depth programming to a separate function
  radeon/audio: moved VBI packet programming to separate functions
  radeon/audio: consolidate update_acr() functions (v2)
  radeon/audio: consolidate update_avi_infoframe() functions
  radeon/audio: consolidate audio_set_dto() functions
  radeon/audio: consolidate audio_fini() functions
  radeon/audio: consolidate audio_enable() functions
  radeon/audio: consolidate select_pin() functions
  ...
This commit is contained in:
Dave Airlie 2015-01-27 09:39:58 +10:00
commit cc0cc1aa27
46 changed files with 1850 additions and 984 deletions

View File

@ -110,7 +110,6 @@ config DRM_RADEON
select HWMON
select BACKLIGHT_CLASS_DEVICE
select INTERVAL_TREE
select MMU_NOTIFIER
help
Choose this option if you have an ATI Radeon graphics card. There
are both PCI and AGP versions. You don't need to choose this to

View File

@ -80,8 +80,10 @@ 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 dce6_afmt.o radeon_vm.o radeon_ucode.o radeon_ib.o radeon_mn.o \
radeon_sync.o
ci_dpm.o dce6_afmt.o radeon_vm.o radeon_ucode.o radeon_ib.o \
radeon_sync.o radeon_audio.o
radeon-$(CONFIG_MMU_NOTIFIER) += radeon_mn.o
# add async DMA block
radeon-y += \

View File

@ -27,6 +27,7 @@
#include <drm/drm_crtc_helper.h>
#include <drm/radeon_drm.h>
#include "radeon.h"
#include "radeon_audio.h"
#include "atom.h"
#include <linux/backlight.h>
@ -664,6 +665,8 @@ 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;
@ -728,6 +731,8 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
dig_connector = radeon_connector->con_priv;
if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
(dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
if (radeon_audio != 0 && ASIC_IS_DCE4(rdev) && !ASIC_IS_DCE5(rdev))
return ATOM_ENCODER_MODE_DP_AUDIO;
return ATOM_ENCODER_MODE_DP;
} else if (radeon_audio != 0) {
if (radeon_connector->audio == RADEON_AUDIO_ENABLE)
@ -742,6 +747,8 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
}
break;
case DRM_MODE_CONNECTOR_eDP:
if (radeon_audio != 0 && ASIC_IS_DCE4(rdev) && !ASIC_IS_DCE5(rdev))
return ATOM_ENCODER_MODE_DP_AUDIO;
return ATOM_ENCODER_MODE_DP;
case DRM_MODE_CONNECTOR_DVIA:
case DRM_MODE_CONNECTOR_VGA:
@ -1615,6 +1622,7 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode)
struct radeon_connector *radeon_connector = NULL;
struct radeon_connector_atom_dig *radeon_dig_connector = NULL;
bool travis_quirk = false;
int encoder_mode;
if (connector) {
radeon_connector = to_radeon_connector(connector);
@ -1710,6 +1718,11 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode)
}
break;
}
encoder_mode = atombios_get_encoder_mode(encoder);
if (radeon_audio != 0 &&
(encoder_mode == ATOM_ENCODER_MODE_HDMI || ENCODER_MODE_IS_DP(encoder_mode)))
radeon_audio_dpms(encoder, mode);
}
static void
@ -2123,6 +2136,7 @@ radeon_atom_encoder_mode_set(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);
int encoder_mode;
radeon_encoder->pixel_clock = adjusted_mode->clock;
@ -2149,6 +2163,10 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
/* handled in dpms */
encoder_mode = atombios_get_encoder_mode(encoder);
if (radeon_audio != 0 &&
(encoder_mode == ATOM_ENCODER_MODE_HDMI || ENCODER_MODE_IS_DP(encoder_mode)))
radeon_audio_mode_set(encoder, adjusted_mode);
break;
case ENCODER_OBJECT_ID_INTERNAL_DDI:
case ENCODER_OBJECT_ID_INTERNAL_DVO1:
@ -2170,13 +2188,6 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
}
atombios_apply_encoder_quirks(encoder, adjusted_mode);
if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) {
if (rdev->asic->display.hdmi_enable)
radeon_hdmi_enable(rdev, encoder, true);
if (rdev->asic->display.hdmi_setmode)
radeon_hdmi_setmode(rdev, encoder, adjusted_mode);
}
}
static bool
@ -2442,10 +2453,6 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder)
disable_done:
if (radeon_encoder_is_digital(encoder)) {
if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) {
if (rdev->asic->display.hdmi_enable)
radeon_hdmi_enable(rdev, encoder, false);
}
dig = radeon_encoder->enc_priv;
dig->dig_encoder = -1;
}

View File

@ -2277,6 +2277,7 @@ static void btc_update_requested_ps(struct radeon_device *rdev,
eg_pi->requested_rps.ps_priv = &eg_pi->requested_ps;
}
#if 0
void btc_dpm_reset_asic(struct radeon_device *rdev)
{
rv770_restrict_performance_levels_before_switch(rdev);
@ -2284,6 +2285,7 @@ void btc_dpm_reset_asic(struct radeon_device *rdev)
btc_set_boot_state_timing(rdev);
rv770_set_boot_state(rdev);
}
#endif
int btc_dpm_pre_set_power_state(struct radeon_device *rdev)
{

View File

@ -187,6 +187,9 @@ static int ci_update_uvd_dpm(struct radeon_device *rdev, bool gate);
static PPSMC_Result ci_send_msg_to_smc_with_parameter(struct radeon_device *rdev,
PPSMC_Msg msg, u32 parameter);
static void ci_thermal_start_smc_fan_control(struct radeon_device *rdev);
static void ci_fan_ctrl_set_default_mode(struct radeon_device *rdev);
static struct ci_power_info *ci_get_pi(struct radeon_device *rdev)
{
struct ci_power_info *pi = rdev->pm.dpm.priv;
@ -1043,22 +1046,24 @@ static int ci_fan_ctrl_start_smc_fan_control(struct radeon_device *rdev)
return -EINVAL;
}
pi->fan_is_controlled_by_smc = true;
return 0;
}
#if 0
static int ci_fan_ctrl_stop_smc_fan_control(struct radeon_device *rdev)
{
PPSMC_Result ret;
struct ci_power_info *pi = ci_get_pi(rdev);
ret = ci_send_msg_to_smc(rdev, PPSMC_StopFanControl);
if (ret == PPSMC_Result_OK)
if (ret == PPSMC_Result_OK) {
pi->fan_is_controlled_by_smc = false;
return 0;
else
} else
return -EINVAL;
}
static int ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
int ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
u32 *speed)
{
u32 duty, duty100;
@ -1083,21 +1088,22 @@ static int ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
return 0;
}
static int ci_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
int ci_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
u32 speed)
{
u32 tmp;
u32 duty, duty100;
u64 tmp64;
struct ci_power_info *pi = ci_get_pi(rdev);
if (rdev->pm.no_fan)
return -ENOENT;
if (speed > 100)
if (pi->fan_is_controlled_by_smc)
return -EINVAL;
if (rdev->pm.dpm.fan.ucode_fan_control)
ci_fan_ctrl_stop_smc_fan_control(rdev);
if (speed > 100)
return -EINVAL;
duty100 = (RREG32_SMC(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT;
@ -1112,11 +1118,38 @@ static int ci_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
tmp |= FDO_STATIC_DUTY(duty);
WREG32_SMC(CG_FDO_CTRL0, tmp);
ci_fan_ctrl_set_static_mode(rdev, FDO_PWM_MODE_STATIC);
return 0;
}
void ci_fan_ctrl_set_mode(struct radeon_device *rdev, u32 mode)
{
if (mode) {
/* stop auto-manage */
if (rdev->pm.dpm.fan.ucode_fan_control)
ci_fan_ctrl_stop_smc_fan_control(rdev);
ci_fan_ctrl_set_static_mode(rdev, mode);
} else {
/* restart auto-manage */
if (rdev->pm.dpm.fan.ucode_fan_control)
ci_thermal_start_smc_fan_control(rdev);
else
ci_fan_ctrl_set_default_mode(rdev);
}
}
u32 ci_fan_ctrl_get_mode(struct radeon_device *rdev)
{
struct ci_power_info *pi = ci_get_pi(rdev);
u32 tmp;
if (pi->fan_is_controlled_by_smc)
return 0;
tmp = RREG32_SMC(CG_FDO_CTRL2) & FDO_PWM_MODE_MASK;
return (tmp >> FDO_PWM_MODE_SHIFT);
}
#if 0
static int ci_fan_ctrl_get_fan_speed_rpm(struct radeon_device *rdev,
u32 *speed)
{
@ -1698,10 +1731,12 @@ static int ci_set_overdrive_target_tdp(struct radeon_device *rdev,
return 0;
}
#if 0
static int ci_set_boot_state(struct radeon_device *rdev)
{
return ci_enable_sclk_mclk_dpm(rdev, false);
}
#endif
static u32 ci_get_average_sclk_freq(struct radeon_device *rdev)
{
@ -5343,10 +5378,12 @@ int ci_dpm_set_power_state(struct radeon_device *rdev)
return 0;
}
#if 0
void ci_dpm_reset_asic(struct radeon_device *rdev)
{
ci_set_boot_state(rdev);
}
#endif
void ci_dpm_display_configuration_changed(struct radeon_device *rdev)
{

View File

@ -291,6 +291,7 @@ struct ci_power_info {
struct ci_ps requested_ps;
/* fan control */
bool fan_ctrl_is_in_default_mode;
bool fan_is_controlled_by_smc;
u32 t_min;
u32 fan_ctrl_default_mode;
};

View File

@ -184,6 +184,7 @@ PPSMC_Result ci_send_msg_to_smc(struct radeon_device *rdev, PPSMC_Msg msg)
return (PPSMC_Result)tmp;
}
#if 0
PPSMC_Result ci_wait_for_smc_inactive(struct radeon_device *rdev)
{
u32 tmp;
@ -201,6 +202,7 @@ PPSMC_Result ci_wait_for_smc_inactive(struct radeon_device *rdev)
return PPSMC_Result_OK;
}
#endif
int ci_load_smc_ucode(struct radeon_device *rdev, u32 limit)
{

View File

@ -27,6 +27,7 @@
#include "drmP.h"
#include "radeon.h"
#include "radeon_asic.h"
#include "radeon_audio.h"
#include "cikd.h"
#include "atom.h"
#include "cik_blit_shaders.h"
@ -8517,7 +8518,7 @@ static int cik_startup(struct radeon_device *rdev)
return r;
}
r = dce6_audio_init(rdev);
r = radeon_audio_init(rdev);
if (r)
return r;
@ -8575,7 +8576,7 @@ int cik_suspend(struct radeon_device *rdev)
{
radeon_kfd_suspend(rdev);
radeon_pm_suspend(rdev);
dce6_audio_fini(rdev);
radeon_audio_fini(rdev);
radeon_vm_manager_fini(rdev);
cik_cp_enable(rdev, false);
cik_sdma_enable(rdev, false);

View File

@ -2005,11 +2005,13 @@ int cypress_dpm_set_power_state(struct radeon_device *rdev)
return 0;
}
#if 0
void cypress_dpm_reset_asic(struct radeon_device *rdev)
{
rv770_restrict_performance_levels_before_switch(rdev);
rv770_set_boot_state(rdev);
}
#endif
void cypress_dpm_display_configuration_changed(struct radeon_device *rdev)
{

View File

@ -24,37 +24,17 @@
#include <drm/drmP.h>
#include "radeon.h"
#include "radeon_asic.h"
#include "radeon_audio.h"
#include "r600d.h"
static void dce3_2_afmt_write_speaker_allocation(struct drm_encoder *encoder)
void dce3_2_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder,
u8 *sadb, int sad_count)
{
struct radeon_device *rdev = encoder->dev->dev_private;
struct drm_connector *connector;
struct radeon_connector *radeon_connector = NULL;
u32 tmp;
u8 *sadb = NULL;
int sad_count;
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, &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(AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER);
tmp = RREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER);
tmp &= ~(DP_CONNECTION | SPEAKER_ALLOCATION_MASK);
/* set HDMI mode */
tmp |= HDMI_CONNECTION;
@ -62,19 +42,32 @@ static void dce3_2_afmt_write_speaker_allocation(struct drm_encoder *encoder)
tmp |= SPEAKER_ALLOCATION(sadb[0]);
else
tmp |= SPEAKER_ALLOCATION(5); /* stereo */
WREG32(AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp);
kfree(sadb);
WREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp);
}
static void dce3_2_afmt_write_sad_regs(struct drm_encoder *encoder)
void dce3_2_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder,
u8 *sadb, int sad_count)
{
struct radeon_device *rdev = encoder->dev->dev_private;
struct drm_connector *connector;
struct radeon_connector *radeon_connector = NULL;
struct cea_sad *sads;
int i, sad_count;
u32 tmp;
/* program the speaker allocation */
tmp = RREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_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(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp);
}
void dce3_2_afmt_write_sad_regs(struct drm_encoder *encoder,
struct cea_sad *sads, int sad_count)
{
int i;
struct radeon_device *rdev = encoder->dev->dev_private;
static const u16 eld_reg_to_type[][2] = {
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR0, HDMI_AUDIO_CODING_TYPE_PCM },
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR1, HDMI_AUDIO_CODING_TYPE_AC3 },
@ -90,25 +83,6 @@ static void dce3_2_afmt_write_sad_regs(struct drm_encoder *encoder)
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR13, HDMI_AUDIO_CODING_TYPE_WMA_PRO },
};
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, &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;
@ -135,110 +109,124 @@ static void dce3_2_afmt_write_sad_regs(struct drm_encoder *encoder)
value |= SUPPORTED_FREQUENCIES_STEREO(stereo_freqs);
WREG32(eld_reg_to_type[i][0], value);
WREG32_ENDPOINT(0, eld_reg_to_type[i][0], value);
}
kfree(sads);
}
/*
* update the info frames with the data from the current display mode
*/
void dce3_1_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode)
void dce3_2_audio_set_dto(struct radeon_device *rdev,
struct radeon_crtc *crtc, unsigned int clock)
{
struct radeon_encoder *radeon_encoder;
struct radeon_encoder_atom_dig *dig;
unsigned int max_ratio = clock / 24000;
u32 dto_phase;
u32 wallclock_ratio;
u32 dto_cntl;
if (!crtc)
return;
radeon_encoder = to_radeon_encoder(crtc->encoder);
dig = radeon_encoder->enc_priv;
if (!dig)
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 {
dto_phase = 24 * 1000;
wallclock_ratio = 0;
}
/* 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 (dig->dig_encoder == 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);
WREG32(DCCG_AUDIO_DTO0_PHASE, dto_phase);
WREG32(DCCG_AUDIO_DTO0_MODULE, clock);
WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */
} else {
dto_cntl = RREG32(DCCG_AUDIO_DTO1_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio);
WREG32(DCCG_AUDIO_DTO1_CNTL, dto_cntl);
WREG32(DCCG_AUDIO_DTO1_PHASE, dto_phase);
WREG32(DCCG_AUDIO_DTO1_MODULE, clock);
WREG32(DCCG_AUDIO_DTO_SELECT, 1); /* select DTO1 */
}
}
void dce3_2_hdmi_update_acr(struct drm_encoder *encoder, long offset,
const struct radeon_hdmi_acr *acr)
{
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;
u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
struct hdmi_avi_infoframe frame;
uint32_t offset;
ssize_t err;
if (!dig || !dig->afmt)
return;
/* Silent, r600_hdmi_enable will raise WARN for us */
if (!dig->afmt->enabled)
return;
offset = dig->afmt->offset;
/* disable audio prior to setting up hw */
dig->afmt->pin = r600_audio_get_pin(rdev);
r600_audio_enable(rdev, dig->afmt->pin, 0);
r600_audio_set_dto(encoder, mode->clock);
WREG32(HDMI0_VBI_PACKET_CONTROL + offset,
HDMI0_NULL_SEND); /* send null packets when required */
WREG32(HDMI0_AUDIO_CRC_CONTROL + offset, 0x1000);
if (ASIC_IS_DCE32(rdev)) {
WREG32(HDMI0_AUDIO_PACKET_CONTROL + offset,
HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */
HDMI0_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */
WREG32(AFMT_AUDIO_PACKET_CONTROL + offset,
AFMT_AUDIO_SAMPLE_SEND | /* send audio packets */
AFMT_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */
} else {
WREG32(HDMI0_AUDIO_PACKET_CONTROL + offset,
HDMI0_AUDIO_SAMPLE_SEND | /* send audio packets */
HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */
HDMI0_AUDIO_PACKETS_PER_LINE(3) | /* should be suffient for all audio modes and small enough for all hblanks */
HDMI0_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */
}
if (ASIC_IS_DCE32(rdev)) {
dce3_2_afmt_write_speaker_allocation(encoder);
dce3_2_afmt_write_sad_regs(encoder);
}
WREG32(HDMI0_ACR_PACKET_CONTROL + offset,
HDMI0_ACR_SOURCE | /* select SW CTS value - XXX verify that hw CTS works on all families */
HDMI0_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */
HDMI0_ACR_SOURCE | /* select SW CTS value */
HDMI0_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */
WREG32(HDMI0_VBI_PACKET_CONTROL + offset,
HDMI0_NULL_SEND | /* send null packets when required */
HDMI0_GC_SEND | /* send general control packets */
HDMI0_GC_CONT); /* send general control packets every frame */
WREG32_P(HDMI0_ACR_32_0 + offset,
HDMI0_ACR_CTS_32(acr->cts_32khz),
~HDMI0_ACR_CTS_32_MASK);
WREG32_P(HDMI0_ACR_32_1 + offset,
HDMI0_ACR_N_32(acr->n_32khz),
~HDMI0_ACR_N_32_MASK);
/* TODO: HDMI0_AUDIO_INFO_UPDATE */
WREG32(HDMI0_INFOFRAME_CONTROL0 + offset,
HDMI0_AVI_INFO_SEND | /* enable AVI info frames */
HDMI0_AVI_INFO_CONT | /* send AVI info frames every frame/field */
HDMI0_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
HDMI0_AUDIO_INFO_CONT); /* send audio info frames every frame/field */
WREG32_P(HDMI0_ACR_44_0 + offset,
HDMI0_ACR_CTS_44(acr->cts_44_1khz),
~HDMI0_ACR_CTS_44_MASK);
WREG32_P(HDMI0_ACR_44_1 + offset,
HDMI0_ACR_N_44(acr->n_44_1khz),
~HDMI0_ACR_N_44_MASK);
WREG32(HDMI0_INFOFRAME_CONTROL1 + offset,
HDMI0_AVI_INFO_LINE(2) | /* anything other than 0 */
HDMI0_AUDIO_INFO_LINE(2)); /* anything other than 0 */
WREG32(HDMI0_GC + offset, 0); /* unset HDMI0_GC_AVMUTE */
err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
if (err < 0) {
DRM_ERROR("failed to setup AVI infoframe: %zd\n", err);
return;
}
err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer));
if (err < 0) {
DRM_ERROR("failed to pack AVI infoframe: %zd\n", err);
return;
}
r600_hdmi_update_avi_infoframe(encoder, buffer, sizeof(buffer));
r600_hdmi_update_ACR(encoder, mode->clock);
/* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */
WREG32(HDMI0_RAMP_CONTROL0 + offset, 0x00FFFFFF);
WREG32(HDMI0_RAMP_CONTROL1 + offset, 0x007FFFFF);
WREG32(HDMI0_RAMP_CONTROL2 + offset, 0x00000001);
WREG32(HDMI0_RAMP_CONTROL3 + offset, 0x00000001);
r600_hdmi_audio_workaround(encoder);
/* enable audio after to setting up hw */
r600_audio_enable(rdev, dig->afmt->pin, 0xf);
WREG32_P(HDMI0_ACR_48_0 + offset,
HDMI0_ACR_CTS_48(acr->cts_48khz),
~HDMI0_ACR_CTS_48_MASK);
WREG32_P(HDMI0_ACR_48_1 + offset,
HDMI0_ACR_N_48(acr->n_48khz),
~HDMI0_ACR_N_48_MASK);
}
void dce3_2_set_audio_packet(struct drm_encoder *encoder, u32 offset)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
WREG32(HDMI0_AUDIO_PACKET_CONTROL + offset,
HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */
HDMI0_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */
WREG32(AFMT_AUDIO_PACKET_CONTROL + offset,
AFMT_AUDIO_SAMPLE_SEND | /* send audio packets */
AFMT_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */
WREG32_OR(HDMI0_INFOFRAME_CONTROL0 + offset,
HDMI0_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
HDMI0_AUDIO_INFO_CONT); /* send audio info frames every frame/field */
WREG32_OR(HDMI0_INFOFRAME_CONTROL1 + offset,
HDMI0_AUDIO_INFO_LINE(2)); /* anything other than 0 */
}
void dce3_2_set_mute(struct drm_encoder *encoder, u32 offset, bool mute)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
if (mute)
WREG32_OR(HDMI0_GC + offset, HDMI0_GC_AVMUTE);
else
WREG32_AND(HDMI0_GC + offset, ~HDMI0_GC_AVMUTE);
}

View File

@ -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;
@ -105,13 +102,11 @@ void dce6_afmt_select_pin(struct drm_encoder *encoder)
}
void dce6_afmt_write_latency_fields(struct drm_encoder *encoder,
struct drm_display_mode *mode)
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;
if (!dig || !dig->afmt || !dig->afmt->pin)
@ -119,18 +114,6 @@ void dce6_afmt_write_latency_fields(struct drm_encoder *encoder,
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]) |
@ -147,40 +130,19 @@ void dce6_afmt_write_latency_fields(struct drm_encoder *encoder,
WREG32_ENDPOINT(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;
if (!dig || !dig->afmt || !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);
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 &= ~(DP_CONNECTION | SPEAKER_ALLOCATION_MASK);
@ -191,21 +153,41 @@ void dce6_afmt_write_speaker_allocation(struct drm_encoder *encoder)
else
tmp |= SPEAKER_ALLOCATION(5); /* stereo */
WREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp);
kfree(sadb);
}
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 offset, tmp;
if (!dig || !dig->afmt || !dig->afmt->pin)
return;
offset = dig->afmt->pin->offset;
/* program the speaker allocation */
tmp = RREG32_ENDPOINT(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(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)
{
u32 offset;
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 },
@ -226,25 +208,6 @@ void dce6_afmt_write_sad_regs(struct drm_encoder *encoder)
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;
@ -273,13 +236,6 @@ void dce6_afmt_write_sad_regs(struct drm_encoder *encoder)
WREG32_ENDPOINT(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,
@ -293,64 +249,76 @@ void dce6_audio_enable(struct radeon_device *rdev,
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);
}
return 0;
/* 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);
}
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)
if (crtc)
value |= DCCG_AUDIO_DTO0_SOURCE_SEL(crtc->crtc_id);
WREG32(DCCG_AUDIO_DTO_SOURCE, value);
/* 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_DTO1_PHASE, 24000);
WREG32(DCCG_AUDIO_DTO1_MODULE, clock);
}
void dce6_enable_dp_audio_packets(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;
uint32_t offset;
if (!dig || !dig->afmt)
return;
for (i = 0; i < rdev->audio.num_pins; i++)
dce6_audio_enable(rdev, &rdev->audio.pin[i], false);
offset = dig->afmt->offset;
rdev->audio.enabled = false;
if (enable) {
if (dig->afmt->enabled)
return;
WREG32(EVERGREEN_DP_SEC_TIMESTAMP + offset, EVERGREEN_DP_SEC_TIMESTAMP_MODE(1));
WREG32(EVERGREEN_DP_SEC_CNTL + offset,
EVERGREEN_DP_SEC_ASP_ENABLE | /* Audio packet transmission */
EVERGREEN_DP_SEC_ATP_ENABLE | /* Audio timestamp packet transmission */
EVERGREEN_DP_SEC_AIP_ENABLE | /* Audio infoframe packet transmission */
EVERGREEN_DP_SEC_STREAM_ENABLE); /* Master enable for secondary stream engine */
radeon_audio_enable(rdev, dig->afmt->pin, true);
} else {
if (!dig->afmt->enabled)
return;
WREG32(EVERGREEN_DP_SEC_CNTL + offset, 0);
radeon_audio_enable(rdev, dig->afmt->pin, false);
}
dig->afmt->enabled = enable;
}

View File

@ -26,6 +26,7 @@
#include <drm/drmP.h>
#include "radeon.h"
#include "radeon_asic.h"
#include "radeon_audio.h"
#include <drm/radeon_drm.h>
#include "evergreend.h"
#include "atom.h"
@ -5286,7 +5287,7 @@ static int evergreen_startup(struct radeon_device *rdev)
return r;
}
r = r600_audio_init(rdev);
r = radeon_audio_init(rdev);
if (r) {
DRM_ERROR("radeon: audio init failed\n");
return r;
@ -5332,7 +5333,7 @@ int evergreen_resume(struct radeon_device *rdev)
int evergreen_suspend(struct radeon_device *rdev)
{
radeon_pm_suspend(rdev);
r600_audio_fini(rdev);
radeon_audio_fini(rdev);
uvd_v1_0_fini(rdev);
radeon_uvd_suspend(rdev);
r700_cp_stop(rdev);
@ -5482,7 +5483,7 @@ int evergreen_init(struct radeon_device *rdev)
void evergreen_fini(struct radeon_device *rdev)
{
radeon_pm_fini(rdev);
r600_audio_fini(rdev);
radeon_audio_fini(rdev);
r700_cp_fini(rdev);
r600_dma_fini(rdev);
r600_irq_fini(rdev);

View File

@ -83,6 +83,7 @@ struct evergreen_cs_track {
u32 htile_offset;
u32 htile_surface;
struct radeon_bo *htile_bo;
unsigned long indirect_draw_buffer_size;
};
static u32 evergreen_cs_get_aray_mode(u32 tiling_flags)
@ -1896,6 +1897,14 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,
}
break;
}
case PACKET3_INDEX_BUFFER_SIZE:
{
if (pkt->count != 0) {
DRM_ERROR("bad INDEX_BUFFER_SIZE\n");
return -EINVAL;
}
break;
}
case PACKET3_DRAW_INDEX:
{
uint64_t offset;
@ -2006,6 +2015,67 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,
return r;
}
break;
case PACKET3_SET_BASE:
{
/*
DW 1 HEADER Header of the packet. Shader_Type in bit 1 of the Header will correspond to the shader type of the Load, see Type-3 Packet.
2 BASE_INDEX Bits [3:0] BASE_INDEX - Base Index specifies which base address is specified in the last two DWs.
0001: DX11 Draw_Index_Indirect Patch Table Base: Base address for Draw_Index_Indirect data.
3 ADDRESS_LO Bits [31:3] - Lower bits of QWORD-Aligned Address. Bits [2:0] - Reserved
4 ADDRESS_HI Bits [31:8] - Reserved. Bits [7:0] - Upper bits of Address [47:32]
*/
if (pkt->count != 2) {
DRM_ERROR("bad SET_BASE\n");
return -EINVAL;
}
/* currently only supporting setting indirect draw buffer base address */
if (idx_value != 1) {
DRM_ERROR("bad SET_BASE\n");
return -EINVAL;
}
r = radeon_cs_packet_next_reloc(p, &reloc, 0);
if (r) {
DRM_ERROR("bad SET_BASE\n");
return -EINVAL;
}
track->indirect_draw_buffer_size = radeon_bo_size(reloc->robj);
ib[idx+1] = reloc->gpu_offset;
ib[idx+2] = upper_32_bits(reloc->gpu_offset) & 0xff;
break;
}
case PACKET3_DRAW_INDIRECT:
case PACKET3_DRAW_INDEX_INDIRECT:
{
u64 size = pkt->opcode == PACKET3_DRAW_INDIRECT ? 16 : 20;
/*
DW 1 HEADER
2 DATA_OFFSET Bits [31:0] + byte aligned offset where the required data structure starts. Bits 1:0 are zero
3 DRAW_INITIATOR Draw Initiator Register. Written to the VGT_DRAW_INITIATOR register for the assigned context
*/
if (pkt->count != 1) {
DRM_ERROR("bad DRAW_INDIRECT\n");
return -EINVAL;
}
if (idx_value + size > track->indirect_draw_buffer_size) {
dev_warn(p->dev, "DRAW_INDIRECT buffer too small %u + %llu > %lu\n",
idx_value, size, track->indirect_draw_buffer_size);
return -EINVAL;
}
r = evergreen_cs_track_check(p);
if (r) {
dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
return r;
}
break;
}
case PACKET3_DISPATCH_DIRECT:
if (pkt->count != 3) {
DRM_ERROR("bad DISPATCH_DIRECT\n");
@ -3243,7 +3313,13 @@ static int evergreen_vm_packet3_check(struct radeon_device *rdev,
switch (pkt->opcode) {
case PACKET3_NOP:
break;
case PACKET3_SET_BASE:
if (idx_value != 1) {
DRM_ERROR("bad SET_BASE");
return -EINVAL;
}
break;
case PACKET3_CLEAR_STATE:
case PACKET3_INDEX_BUFFER_SIZE:
case PACKET3_DISPATCH_DIRECT:

View File

@ -29,17 +29,12 @@
#include <drm/radeon_drm.h>
#include "radeon.h"
#include "radeon_asic.h"
#include "radeon_audio.h"
#include "evergreend.h"
#include "atom.h"
extern void dce6_afmt_write_speaker_allocation(struct drm_encoder *encoder);
extern void dce6_afmt_write_sad_regs(struct drm_encoder *encoder);
extern void dce6_afmt_select_pin(struct drm_encoder *encoder);
extern void dce6_afmt_write_latency_fields(struct drm_encoder *encoder,
struct drm_display_mode *mode);
/* enable the audio stream */
static void dce4_audio_enable(struct radeon_device *rdev,
void dce4_audio_enable(struct radeon_device *rdev,
struct r600_audio_pin *pin,
u8 enable_mask)
{
@ -69,48 +64,42 @@ static void dce4_audio_enable(struct radeon_device *rdev,
WREG32(AZ_HOT_PLUG_CONTROL, tmp);
}
/*
* update the N and CTS parameters for a given pixel clock rate
*/
static void evergreen_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t clock)
void evergreen_hdmi_update_acr(struct drm_encoder *encoder, long offset,
const struct radeon_hdmi_acr *acr)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_hdmi_acr acr = r600_hdmi_acr(clock);
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
uint32_t offset = dig->afmt->offset;
int bpc = 8;
WREG32(HDMI_ACR_32_0 + offset, HDMI_ACR_CTS_32(acr.cts_32khz));
WREG32(HDMI_ACR_32_1 + offset, acr.n_32khz);
if (encoder->crtc) {
struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
bpc = radeon_crtc->bpc;
}
WREG32(HDMI_ACR_44_0 + offset, HDMI_ACR_CTS_44(acr.cts_44_1khz));
WREG32(HDMI_ACR_44_1 + offset, acr.n_44_1khz);
if (bpc > 8)
WREG32(HDMI_ACR_PACKET_CONTROL + offset,
HDMI_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */
else
WREG32(HDMI_ACR_PACKET_CONTROL + offset,
HDMI_ACR_SOURCE | /* select SW CTS value */
HDMI_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */
WREG32(HDMI_ACR_48_0 + offset, HDMI_ACR_CTS_48(acr.cts_48khz));
WREG32(HDMI_ACR_48_1 + offset, acr.n_48khz);
WREG32(HDMI_ACR_32_0 + offset, HDMI_ACR_CTS_32(acr->cts_32khz));
WREG32(HDMI_ACR_32_1 + offset, acr->n_32khz);
WREG32(HDMI_ACR_44_0 + offset, HDMI_ACR_CTS_44(acr->cts_44_1khz));
WREG32(HDMI_ACR_44_1 + offset, acr->n_44_1khz);
WREG32(HDMI_ACR_48_0 + offset, HDMI_ACR_CTS_48(acr->cts_48khz));
WREG32(HDMI_ACR_48_1 + offset, acr->n_48khz);
}
static void dce4_afmt_write_latency_fields(struct drm_encoder *encoder,
struct drm_display_mode *mode)
void dce4_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 drm_connector *connector;
struct radeon_connector *radeon_connector = NULL;
u32 tmp = 0;
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]) |
@ -124,38 +113,17 @@ static void dce4_afmt_write_latency_fields(struct drm_encoder *encoder,
else
tmp = VIDEO_LIPSYNC(255) | AUDIO_LIPSYNC(255);
}
WREG32(AZ_F0_CODEC_PIN0_CONTROL_RESPONSE_LIPSYNC, tmp);
WREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_RESPONSE_LIPSYNC, tmp);
}
static void dce4_afmt_write_speaker_allocation(struct drm_encoder *encoder)
void dce4_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder,
u8 *sadb, int sad_count)
{
struct radeon_device *rdev = encoder->dev->dev_private;
struct drm_connector *connector;
struct radeon_connector *radeon_connector = NULL;
u32 tmp;
u8 *sadb = NULL;
int sad_count;
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(AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER);
tmp = RREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER);
tmp &= ~(DP_CONNECTION | SPEAKER_ALLOCATION_MASK);
/* set HDMI mode */
tmp |= HDMI_CONNECTION;
@ -163,19 +131,32 @@ static void dce4_afmt_write_speaker_allocation(struct drm_encoder *encoder)
tmp |= SPEAKER_ALLOCATION(sadb[0]);
else
tmp |= SPEAKER_ALLOCATION(5); /* stereo */
WREG32(AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp);
kfree(sadb);
WREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp);
}
static void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder)
void dce4_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder,
u8 *sadb, int sad_count)
{
struct radeon_device *rdev = encoder->dev->dev_private;
struct drm_connector *connector;
struct radeon_connector *radeon_connector = NULL;
struct cea_sad *sads;
int i, sad_count;
u32 tmp;
/* program the speaker allocation */
tmp = RREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_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(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp);
}
void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder,
struct cea_sad *sads, int sad_count)
{
int i;
struct radeon_device *rdev = encoder->dev->dev_private;
static const u16 eld_reg_to_type[][2] = {
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR0, HDMI_AUDIO_CODING_TYPE_PCM },
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR1, HDMI_AUDIO_CODING_TYPE_AC3 },
@ -191,25 +172,6 @@ static void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder)
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR13, HDMI_AUDIO_CODING_TYPE_WMA_PRO },
};
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;
@ -236,25 +198,17 @@ static void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder)
value |= SUPPORTED_FREQUENCIES_STEREO(stereo_freqs);
WREG32(eld_reg_to_type[i][0], value);
WREG32_ENDPOINT(0, eld_reg_to_type[i][0], value);
}
kfree(sads);
}
/*
* build a HDMI Video Info Frame
* build a AVI Info Frame
*/
static void evergreen_hdmi_update_avi_infoframe(struct drm_encoder *encoder,
void *buffer, size_t size)
void evergreen_set_avi_packet(struct radeon_device *rdev, u32 offset,
unsigned char *buffer, size_t size)
{
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;
uint32_t offset = dig->afmt->offset;
uint8_t *frame = buffer + 3;
uint8_t *header = buffer;
WREG32(AFMT_AVI_INFO0 + offset,
frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24));
@ -263,104 +217,103 @@ static void evergreen_hdmi_update_avi_infoframe(struct drm_encoder *encoder,
WREG32(AFMT_AVI_INFO2 + offset,
frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24));
WREG32(AFMT_AVI_INFO3 + offset,
frame[0xC] | (frame[0xD] << 8) | (header[1] << 24));
frame[0xC] | (frame[0xD] << 8) | (buffer[1] << 24));
WREG32_OR(HDMI_INFOFRAME_CONTROL0 + offset,
HDMI_AVI_INFO_SEND | /* enable AVI info frames */
HDMI_AVI_INFO_CONT); /* required for audio info values to be updated */
WREG32_P(HDMI_INFOFRAME_CONTROL1 + offset,
HDMI_AVI_INFO_LINE(2), /* anything other than 0 */
~HDMI_AVI_INFO_LINE_MASK);
}
static void evergreen_audio_set_dto(struct drm_encoder *encoder, u32 clock)
void dce4_hdmi_audio_set_dto(struct radeon_device *rdev,
struct radeon_crtc *crtc, unsigned int clock)
{
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;
struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
u32 base_rate = 24000;
u32 max_ratio = clock / base_rate;
unsigned int max_ratio = clock / 24000;
u32 dto_phase;
u32 dto_modulo = clock;
u32 wallclock_ratio;
u32 dto_cntl;
u32 value;
if (!dig || !dig->afmt)
return;
if (ASIC_IS_DCE6(rdev)) {
dto_phase = 24 * 1000;
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 (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_phase = 24 * 1000;
wallclock_ratio = 0;
}
/* XXX two dtos; generally use dto0 for hdmi */
value = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
value |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio);
value &= ~DCCG_AUDIO_DTO1_USE_512FBR_DTO;
WREG32(DCCG_AUDIO_DTO0_CNTL, value);
/* Two dtos; generally use dto0 for HDMI */
value = 0;
if (crtc)
value |= DCCG_AUDIO_DTO0_SOURCE_SEL(crtc->crtc_id);
WREG32(DCCG_AUDIO_DTO_SOURCE, value);
/* 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_DTO_SOURCE, DCCG_AUDIO_DTO0_SOURCE_SEL(radeon_crtc->crtc_id));
WREG32(DCCG_AUDIO_DTO0_PHASE, dto_phase);
WREG32(DCCG_AUDIO_DTO0_MODULE, dto_modulo);
WREG32(DCCG_AUDIO_DTO0_MODULE, clock);
}
void dce4_dp_audio_set_dto(struct radeon_device *rdev,
struct radeon_crtc *crtc, unsigned int clock)
{
u32 value;
/*
* update the info frames with the data from the current display mode
*/
void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode)
value = RREG32(DCCG_AUDIO_DTO1_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
value |= DCCG_AUDIO_DTO1_USE_512FBR_DTO;
WREG32(DCCG_AUDIO_DTO1_CNTL, value);
/* Two dtos; generally use dto1 for DP */
value = 0;
value |= DCCG_AUDIO_DTO_SEL;
if (crtc)
value |= DCCG_AUDIO_DTO0_SOURCE_SEL(crtc->crtc_id);
WREG32(DCCG_AUDIO_DTO_SOURCE, value);
/* 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_DTO1_PHASE, 24000);
WREG32(DCCG_AUDIO_DTO1_MODULE, rdev->clock.max_pixel_clock * 10);
}
void dce4_set_vbi_packet(struct drm_encoder *encoder, u32 offset)
{
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;
struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
struct hdmi_avi_infoframe frame;
uint32_t offset;
ssize_t err;
uint32_t val;
int bpc = 8;
if (!dig || !dig->afmt)
return;
/* Silent, r600_hdmi_enable will raise WARN for us */
if (!dig->afmt->enabled)
return;
offset = dig->afmt->offset;
/* hdmi deep color mode general control packets setup, if bpc > 8 */
if (encoder->crtc) {
struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
bpc = radeon_crtc->bpc;
}
/* disable audio prior to setting up hw */
if (ASIC_IS_DCE6(rdev)) {
dig->afmt->pin = dce6_audio_get_pin(rdev);
dce6_audio_enable(rdev, dig->afmt->pin, 0);
} else {
dig->afmt->pin = r600_audio_get_pin(rdev);
dce4_audio_enable(rdev, dig->afmt->pin, 0);
}
evergreen_audio_set_dto(encoder, mode->clock);
WREG32(HDMI_VBI_PACKET_CONTROL + offset,
HDMI_NULL_SEND); /* send null packets when required */
HDMI_NULL_SEND | /* send null packets when required */
HDMI_GC_SEND | /* send general control packets */
HDMI_GC_CONT); /* send general control packets every frame */
}
WREG32(AFMT_AUDIO_CRC_CONTROL + offset, 0x1000);
void dce4_hdmi_set_color_depth(struct drm_encoder *encoder, u32 offset, int bpc)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
uint32_t val;
val = RREG32(HDMI_CONTROL + offset);
val &= ~HDMI_DEEP_COLOR_ENABLE;
@ -390,113 +343,59 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode
}
WREG32(HDMI_CONTROL + offset, val);
}
WREG32(HDMI_VBI_PACKET_CONTROL + offset,
HDMI_NULL_SEND | /* send null packets when required */
HDMI_GC_SEND | /* send general control packets */
HDMI_GC_CONT); /* send general control packets every frame */
void dce4_set_audio_packet(struct drm_encoder *encoder, u32 offset)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
WREG32(HDMI_INFOFRAME_CONTROL0 + offset,
HDMI_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
HDMI_AUDIO_INFO_CONT); /* required for audio info values to be updated */
HDMI_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
HDMI_AUDIO_INFO_CONT); /* required for audio info values to be updated */
WREG32(AFMT_INFOFRAME_CONTROL0 + offset,
AFMT_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */
AFMT_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */
WREG32(HDMI_INFOFRAME_CONTROL1 + offset,
HDMI_AUDIO_INFO_LINE(2)); /* anything other than 0 */
WREG32(HDMI_GC + offset, 0); /* unset HDMI_GC_AVMUTE */
HDMI_AUDIO_INFO_LINE(2)); /* anything other than 0 */
WREG32(HDMI_AUDIO_PACKET_CONTROL + offset,
HDMI_AUDIO_DELAY_EN(1) | /* set the default audio delay */
HDMI_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */
WREG32(AFMT_AUDIO_PACKET_CONTROL + offset,
AFMT_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */
/* fglrx clears sth in AFMT_AUDIO_PACKET_CONTROL2 here */
if (bpc > 8)
WREG32(HDMI_ACR_PACKET_CONTROL + offset,
HDMI_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */
else
WREG32(HDMI_ACR_PACKET_CONTROL + offset,
HDMI_ACR_SOURCE | /* select SW CTS value */
HDMI_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */
evergreen_hdmi_update_ACR(encoder, mode->clock);
HDMI_AUDIO_DELAY_EN(1) | /* set the default audio delay */
HDMI_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */
WREG32(AFMT_60958_0 + offset,
AFMT_60958_CS_CHANNEL_NUMBER_L(1));
AFMT_60958_CS_CHANNEL_NUMBER_L(1));
WREG32(AFMT_60958_1 + offset,
AFMT_60958_CS_CHANNEL_NUMBER_R(2));
AFMT_60958_CS_CHANNEL_NUMBER_R(2));
WREG32(AFMT_60958_2 + offset,
AFMT_60958_CS_CHANNEL_NUMBER_2(3) |
AFMT_60958_CS_CHANNEL_NUMBER_3(4) |
AFMT_60958_CS_CHANNEL_NUMBER_4(5) |
AFMT_60958_CS_CHANNEL_NUMBER_5(6) |
AFMT_60958_CS_CHANNEL_NUMBER_6(7) |
AFMT_60958_CS_CHANNEL_NUMBER_7(8));
if (ASIC_IS_DCE6(rdev)) {
dce6_afmt_write_speaker_allocation(encoder);
} else {
dce4_afmt_write_speaker_allocation(encoder);
}
AFMT_60958_CS_CHANNEL_NUMBER_2(3) |
AFMT_60958_CS_CHANNEL_NUMBER_3(4) |
AFMT_60958_CS_CHANNEL_NUMBER_4(5) |
AFMT_60958_CS_CHANNEL_NUMBER_5(6) |
AFMT_60958_CS_CHANNEL_NUMBER_6(7) |
AFMT_60958_CS_CHANNEL_NUMBER_7(8));
WREG32(AFMT_AUDIO_PACKET_CONTROL2 + offset,
AFMT_AUDIO_CHANNEL_ENABLE(0xff));
AFMT_AUDIO_CHANNEL_ENABLE(0xff));
/* fglrx sets 0x40 in 0x5f80 here */
/* allow 60958 channel status and send audio packets fields to be updated */
WREG32(AFMT_AUDIO_PACKET_CONTROL + offset,
AFMT_AUDIO_SAMPLE_SEND | AFMT_RESET_FIFO_WHEN_AUDIO_DIS | AFMT_60958_CS_UPDATE);
}
if (ASIC_IS_DCE6(rdev)) {
dce6_afmt_select_pin(encoder);
dce6_afmt_write_sad_regs(encoder);
dce6_afmt_write_latency_fields(encoder, mode);
} else {
evergreen_hdmi_write_sad_regs(encoder);
dce4_afmt_write_latency_fields(encoder, mode);
}
err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
if (err < 0) {
DRM_ERROR("failed to setup AVI infoframe: %zd\n", err);
return;
}
void dce4_set_mute(struct drm_encoder *encoder, u32 offset, bool mute)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer));
if (err < 0) {
DRM_ERROR("failed to pack AVI infoframe: %zd\n", err);
return;
}
evergreen_hdmi_update_avi_infoframe(encoder, buffer, sizeof(buffer));
WREG32_OR(HDMI_INFOFRAME_CONTROL0 + offset,
HDMI_AVI_INFO_SEND | /* enable AVI info frames */
HDMI_AVI_INFO_CONT); /* required for audio info values to be updated */
WREG32_P(HDMI_INFOFRAME_CONTROL1 + offset,
HDMI_AVI_INFO_LINE(2), /* anything other than 0 */
~HDMI_AVI_INFO_LINE_MASK);
WREG32_OR(AFMT_AUDIO_PACKET_CONTROL + offset,
AFMT_AUDIO_SAMPLE_SEND); /* send audio packets */
/* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */
WREG32(AFMT_RAMP_CONTROL0 + offset, 0x00FFFFFF);
WREG32(AFMT_RAMP_CONTROL1 + offset, 0x007FFFFF);
WREG32(AFMT_RAMP_CONTROL2 + offset, 0x00000001);
WREG32(AFMT_RAMP_CONTROL3 + offset, 0x00000001);
/* enable audio after to setting up hw */
if (ASIC_IS_DCE6(rdev))
dce6_audio_enable(rdev, dig->afmt->pin, 1);
if (mute)
WREG32_OR(HDMI_GC + offset, HDMI_GC_AVMUTE);
else
dce4_audio_enable(rdev, dig->afmt->pin, 0xf);
WREG32_AND(HDMI_GC + offset, ~HDMI_GC_AVMUTE);
}
void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
@ -516,10 +415,7 @@ void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
return;
if (!enable && dig->afmt->pin) {
if (ASIC_IS_DCE6(rdev))
dce6_audio_enable(rdev, dig->afmt->pin, 0);
else
dce4_audio_enable(rdev, dig->afmt->pin, 0);
radeon_audio_enable(rdev, dig->afmt->pin, 0);
dig->afmt->pin = NULL;
}
@ -528,3 +424,57 @@ void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
DRM_DEBUG("%sabling HDMI interface @ 0x%04X for encoder 0x%x\n",
enable ? "En" : "Dis", dig->afmt->offset, radeon_encoder->encoder_id);
}
void evergreen_enable_dp_audio_packets(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;
uint32_t offset;
if (!dig || !dig->afmt)
return;
offset = dig->afmt->offset;
if (enable) {
struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
struct radeon_connector_atom_dig *dig_connector;
uint32_t val;
if (dig->afmt->enabled)
return;
WREG32(EVERGREEN_DP_SEC_TIMESTAMP + offset, EVERGREEN_DP_SEC_TIMESTAMP_MODE(1));
if (radeon_connector->con_priv) {
dig_connector = radeon_connector->con_priv;
val = RREG32(EVERGREEN_DP_SEC_AUD_N + offset);
val &= ~EVERGREEN_DP_SEC_N_BASE_MULTIPLE(0xf);
if (dig_connector->dp_clock == 162000)
val |= EVERGREEN_DP_SEC_N_BASE_MULTIPLE(3);
else
val |= EVERGREEN_DP_SEC_N_BASE_MULTIPLE(5);
WREG32(EVERGREEN_DP_SEC_AUD_N + offset, val);
}
WREG32(EVERGREEN_DP_SEC_CNTL + offset,
EVERGREEN_DP_SEC_ASP_ENABLE | /* Audio packet transmission */
EVERGREEN_DP_SEC_ATP_ENABLE | /* Audio timestamp packet transmission */
EVERGREEN_DP_SEC_AIP_ENABLE | /* Audio infoframe packet transmission */
EVERGREEN_DP_SEC_STREAM_ENABLE); /* Master enable for secondary stream engine */
radeon_audio_enable(rdev, dig->afmt->pin, 0xf);
} else {
if (!dig->afmt->enabled)
return;
WREG32(EVERGREEN_DP_SEC_CNTL + offset, 0);
radeon_audio_enable(rdev, dig->afmt->pin, 0);
}
dig->afmt->enabled = enable;
}

View File

@ -251,4 +251,19 @@
/* HDMI blocks at 0x7030, 0x7c30, 0x10830, 0x11430, 0x12030, 0x12c30 */
#define EVERGREEN_HDMI_BASE 0x7030
/* Display Port block */
#define EVERGREEN_DP_SEC_CNTL 0x7280
# define EVERGREEN_DP_SEC_STREAM_ENABLE (1 << 0)
# define EVERGREEN_DP_SEC_ASP_ENABLE (1 << 4)
# define EVERGREEN_DP_SEC_ATP_ENABLE (1 << 8)
# define EVERGREEN_DP_SEC_AIP_ENABLE (1 << 12)
# define EVERGREEN_DP_SEC_GSP_ENABLE (1 << 20)
# define EVERGREEN_DP_SEC_AVI_ENABLE (1 << 24)
# define EVERGREEN_DP_SEC_MPG_ENABLE (1 << 28)
#define EVERGREEN_DP_SEC_TIMESTAMP 0x72a4
# define EVERGREEN_DP_SEC_TIMESTAMP_MODE(x) (((x) & 0x3) << 0)
#define EVERGREEN_DP_SEC_AUD_N 0x7294
# define EVERGREEN_DP_SEC_N_BASE_MULTIPLE(x) (((x) & 0xf) << 24)
# define EVERGREEN_DP_SEC_SS_EN (1 << 28)
#endif

View File

@ -509,6 +509,7 @@
#define DCCG_AUDIO_DTO1_MODULE 0x05c4
#define DCCG_AUDIO_DTO1_LOAD 0x05c8
#define DCCG_AUDIO_DTO1_CNTL 0x05cc
# define DCCG_AUDIO_DTO1_USE_512FBR_DTO (1 << 3)
/* DCE 4.0 AFMT */
#define HDMI_CONTROL 0x7030

View File

@ -1925,6 +1925,7 @@ void kv_dpm_setup_asic(struct radeon_device *rdev)
kv_init_sclk_t(rdev);
}
#if 0
void kv_dpm_reset_asic(struct radeon_device *rdev)
{
struct kv_power_info *pi = kv_get_pi(rdev);
@ -1945,6 +1946,7 @@ void kv_dpm_reset_asic(struct radeon_device *rdev)
kv_set_enabled_level(rdev, pi->graphics_boot_level);
}
}
#endif
//XXX use sumo_dpm_display_configuration_changed

View File

@ -27,6 +27,7 @@
#include <drm/drmP.h>
#include "radeon.h"
#include "radeon_asic.h"
#include "radeon_audio.h"
#include <drm/radeon_drm.h>
#include "nid.h"
#include "atom.h"
@ -2097,15 +2098,9 @@ static int cayman_startup(struct radeon_device *rdev)
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;
}
r = radeon_audio_init(rdev);
if (r)
return r;
return 0;
}
@ -2140,10 +2135,7 @@ int cayman_resume(struct radeon_device *rdev)
int cayman_suspend(struct radeon_device *rdev)
{
radeon_pm_suspend(rdev);
if (ASIC_IS_DCE6(rdev))
dce6_audio_fini(rdev);
else
r600_audio_fini(rdev);
radeon_audio_fini(rdev);
radeon_vm_manager_fini(rdev);
cayman_cp_enable(rdev, false);
cayman_dma_stop(rdev);

View File

@ -3862,11 +3862,13 @@ void ni_dpm_post_set_power_state(struct radeon_device *rdev)
ni_update_current_ps(rdev, new_ps);
}
#if 0
void ni_dpm_reset_asic(struct radeon_device *rdev)
{
ni_restrict_performance_levels_before_switch(rdev);
rv770_set_boot_state(rdev);
}
#endif
union power_info {
struct _ATOM_POWERPLAY_INFO info;

View File

@ -33,6 +33,7 @@
#include <drm/radeon_drm.h>
#include "radeon.h"
#include "radeon_asic.h"
#include "radeon_audio.h"
#include "radeon_mode.h"
#include "r600d.h"
#include "atom.h"
@ -3054,7 +3055,7 @@ static int r600_startup(struct radeon_device *rdev)
return r;
}
r = r600_audio_init(rdev);
r = radeon_audio_init(rdev);
if (r) {
DRM_ERROR("radeon: audio init failed\n");
return r;
@ -3105,7 +3106,7 @@ int r600_resume(struct radeon_device *rdev)
int r600_suspend(struct radeon_device *rdev)
{
radeon_pm_suspend(rdev);
r600_audio_fini(rdev);
radeon_audio_fini(rdev);
r600_cp_stop(rdev);
if (rdev->has_uvd) {
uvd_v1_0_fini(rdev);
@ -3224,7 +3225,7 @@ int r600_init(struct radeon_device *rdev)
void r600_fini(struct radeon_device *rdev)
{
radeon_pm_fini(rdev);
r600_audio_fini(rdev);
radeon_audio_fini(rdev);
r600_cp_fini(rdev);
r600_irq_fini(rdev);
if (rdev->has_uvd) {

View File

@ -29,6 +29,7 @@
#include <drm/radeon_drm.h>
#include "radeon.h"
#include "radeon_asic.h"
#include "radeon_audio.h"
#include "r600d.h"
#include "atom.h"
@ -55,30 +56,6 @@ enum r600_hdmi_iec_status_bits {
AUDIO_STATUS_LEVEL = 0x80
};
static const struct radeon_hdmi_acr r600_hdmi_predefined_acr[] = {
/* 32kHz 44.1kHz 48kHz */
/* Clock N CTS N CTS N CTS */
{ 25175, 4096, 25175, 28224, 125875, 6144, 25175 }, /* 25,20/1.001 MHz */
{ 25200, 4096, 25200, 6272, 28000, 6144, 25200 }, /* 25.20 MHz */
{ 27000, 4096, 27000, 6272, 30000, 6144, 27000 }, /* 27.00 MHz */
{ 27027, 4096, 27027, 6272, 30030, 6144, 27027 }, /* 27.00*1.001 MHz */
{ 54000, 4096, 54000, 6272, 60000, 6144, 54000 }, /* 54.00 MHz */
{ 54054, 4096, 54054, 6272, 60060, 6144, 54054 }, /* 54.00*1.001 MHz */
{ 74176, 4096, 74176, 5733, 75335, 6144, 74176 }, /* 74.25/1.001 MHz */
{ 74250, 4096, 74250, 6272, 82500, 6144, 74250 }, /* 74.25 MHz */
{ 148352, 4096, 148352, 5733, 150670, 6144, 148352 }, /* 148.50/1.001 MHz */
{ 148500, 4096, 148500, 6272, 165000, 6144, 148500 }, /* 148.50 MHz */
};
/*
* check if the chipset is supported
*/
static int r600_audio_chipset_supported(struct radeon_device *rdev)
{
return ASIC_IS_DCE2(rdev) && !ASIC_IS_NODCE(rdev);
}
static struct r600_audio_pin r600_audio_status(struct radeon_device *rdev)
{
struct r600_audio_pin status;
@ -191,155 +168,56 @@ void r600_audio_enable(struct radeon_device *rdev,
WREG32(AZ_HOT_PLUG_CONTROL, tmp);
}
/*
* initialize the audio vars
*/
int r600_audio_init(struct radeon_device *rdev)
{
if (!radeon_audio || !r600_audio_chipset_supported(rdev))
return 0;
rdev->audio.enabled = true;
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;
/* disable audio. it will be set up later */
r600_audio_enable(rdev, &rdev->audio.pin[0], 0);
return 0;
}
/*
* release the audio timer
* TODO: How to do this correctly on SMP systems?
*/
void r600_audio_fini(struct radeon_device *rdev)
{
if (!rdev->audio.enabled)
return;
r600_audio_enable(rdev, &rdev->audio.pin[0], 0);
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];
}
/*
* calculate CTS and N values if they are not found in the table
*/
static void r600_hdmi_calc_cts(uint32_t clock, int *CTS, int *N, int freq)
{
int n, cts;
unsigned long div, mul;
/* Safe, but overly large values */
n = 128 * freq;
cts = clock * 1000;
/* Smallest valid fraction */
div = gcd(n, cts);
n /= div;
cts /= div;
/*
* The optimal N is 128*freq/1000. Calculate the closest larger
* value that doesn't truncate any bits.
*/
mul = ((128*freq/1000) + (n-1))/n;
n *= mul;
cts *= mul;
/* Check that we are in spec (not always possible) */
if (n < (128*freq/1500))
printk(KERN_WARNING "Calculated ACR N value is too small. You may experience audio problems.\n");
if (n > (128*freq/300))
printk(KERN_WARNING "Calculated ACR N value is too large. You may experience audio problems.\n");
*N = n;
*CTS = cts;
DRM_DEBUG("Calculated ACR timing N=%d CTS=%d for frequency %d\n",
*N, *CTS, freq);
}
struct radeon_hdmi_acr r600_hdmi_acr(uint32_t clock)
{
struct radeon_hdmi_acr res;
u8 i;
/* Precalculated values for common clocks */
for (i = 0; i < ARRAY_SIZE(r600_hdmi_predefined_acr); i++) {
if (r600_hdmi_predefined_acr[i].clock == clock)
return r600_hdmi_predefined_acr[i];
}
/* And odd clocks get manually calculated */
r600_hdmi_calc_cts(clock, &res.cts_32khz, &res.n_32khz, 32000);
r600_hdmi_calc_cts(clock, &res.cts_44_1khz, &res.n_44_1khz, 44100);
r600_hdmi_calc_cts(clock, &res.cts_48khz, &res.n_48khz, 48000);
return res;
}
/*
* update the N and CTS parameters for a given pixel clock rate
*/
void r600_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t clock)
void r600_hdmi_update_acr(struct drm_encoder *encoder, long offset,
const struct radeon_hdmi_acr *acr)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_hdmi_acr acr = r600_hdmi_acr(clock);
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
uint32_t offset = dig->afmt->offset;
/* DCE 3.0 uses register that's normally for CRC_CONTROL */
uint32_t acr_ctl = ASIC_IS_DCE3(rdev) ? DCE3_HDMI0_ACR_PACKET_CONTROL :
HDMI0_ACR_PACKET_CONTROL;
WREG32_P(acr_ctl + offset,
HDMI0_ACR_SOURCE | /* select SW CTS value */
HDMI0_ACR_AUTO_SEND, /* allow hw to sent ACR packets when required */
~(HDMI0_ACR_SOURCE |
HDMI0_ACR_AUTO_SEND));
WREG32_P(HDMI0_ACR_32_0 + offset,
HDMI0_ACR_CTS_32(acr.cts_32khz),
~HDMI0_ACR_CTS_32_MASK);
HDMI0_ACR_CTS_32(acr->cts_32khz),
~HDMI0_ACR_CTS_32_MASK);
WREG32_P(HDMI0_ACR_32_1 + offset,
HDMI0_ACR_N_32(acr.n_32khz),
~HDMI0_ACR_N_32_MASK);
HDMI0_ACR_N_32(acr->n_32khz),
~HDMI0_ACR_N_32_MASK);
WREG32_P(HDMI0_ACR_44_0 + offset,
HDMI0_ACR_CTS_44(acr.cts_44_1khz),
~HDMI0_ACR_CTS_44_MASK);
HDMI0_ACR_CTS_44(acr->cts_44_1khz),
~HDMI0_ACR_CTS_44_MASK);
WREG32_P(HDMI0_ACR_44_1 + offset,
HDMI0_ACR_N_44(acr.n_44_1khz),
~HDMI0_ACR_N_44_MASK);
HDMI0_ACR_N_44(acr->n_44_1khz),
~HDMI0_ACR_N_44_MASK);
WREG32_P(HDMI0_ACR_48_0 + offset,
HDMI0_ACR_CTS_48(acr.cts_48khz),
~HDMI0_ACR_CTS_48_MASK);
HDMI0_ACR_CTS_48(acr->cts_48khz),
~HDMI0_ACR_CTS_48_MASK);
WREG32_P(HDMI0_ACR_48_1 + offset,
HDMI0_ACR_N_48(acr.n_48khz),
~HDMI0_ACR_N_48_MASK);
HDMI0_ACR_N_48(acr->n_48khz),
~HDMI0_ACR_N_48_MASK);
}
/*
* build a HDMI Video Info Frame
*/
void r600_hdmi_update_avi_infoframe(struct drm_encoder *encoder, void *buffer,
size_t size)
void r600_set_avi_packet(struct radeon_device *rdev, u32 offset,
unsigned char *buffer, size_t size)
{
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;
uint32_t offset = dig->afmt->offset;
uint8_t *frame = buffer + 3;
uint8_t *header = buffer;
WREG32(HDMI0_AVI_INFO0 + offset,
frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24));
@ -348,7 +226,14 @@ void r600_hdmi_update_avi_infoframe(struct drm_encoder *encoder, void *buffer,
WREG32(HDMI0_AVI_INFO2 + offset,
frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24));
WREG32(HDMI0_AVI_INFO3 + offset,
frame[0xC] | (frame[0xD] << 8) | (header[1] << 24));
frame[0xC] | (frame[0xD] << 8) | (buffer[1] << 24));
WREG32_OR(HDMI0_INFOFRAME_CONTROL0 + offset,
HDMI0_AVI_INFO_SEND | /* enable AVI info frames */
HDMI0_AVI_INFO_CONT); /* send AVI info frames every frame/field */
WREG32_OR(HDMI0_INFOFRAME_CONTROL1 + offset,
HDMI0_AVI_INFO_LINE(2)); /* anything other than 0 */
}
/*
@ -425,188 +310,94 @@ void r600_hdmi_audio_workaround(struct drm_encoder *encoder)
value, ~HDMI0_AUDIO_TEST_EN);
}
void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock)
void r600_hdmi_audio_set_dto(struct radeon_device *rdev,
struct radeon_crtc *crtc, unsigned int clock)
{
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;
u32 base_rate = 24000;
u32 max_ratio = clock / base_rate;
u32 dto_phase;
u32 dto_modulo = clock;
u32 wallclock_ratio;
u32 dto_cntl;
struct radeon_encoder *radeon_encoder;
struct radeon_encoder_atom_dig *dig;
if (!dig || !dig->afmt)
if (!crtc)
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 {
dto_phase = 24 * 1000;
wallclock_ratio = 0;
}
radeon_encoder = to_radeon_encoder(crtc->encoder);
dig = radeon_encoder->enc_priv;
/* there are two DTOs selected by DCCG_AUDIO_DTO_SELECT.
* doesn't matter which one you use. Just use the first one.
*/
/* XXX two dtos; generally use dto0 for hdmi */
/* 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_DCE32(rdev)) {
if (dig->dig_encoder == 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);
WREG32(DCCG_AUDIO_DTO0_PHASE, dto_phase);
WREG32(DCCG_AUDIO_DTO0_MODULE, dto_modulo);
WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */
} else {
dto_cntl = RREG32(DCCG_AUDIO_DTO1_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio);
WREG32(DCCG_AUDIO_DTO1_CNTL, dto_cntl);
WREG32(DCCG_AUDIO_DTO1_PHASE, dto_phase);
WREG32(DCCG_AUDIO_DTO1_MODULE, dto_modulo);
WREG32(DCCG_AUDIO_DTO_SELECT, 1); /* select DTO1 */
}
if (!dig)
return;
if (dig->dig_encoder == 0) {
WREG32(DCCG_AUDIO_DTO0_PHASE, 24000 * 100);
WREG32(DCCG_AUDIO_DTO0_MODULE, clock * 100);
WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */
} else {
/* according to the reg specs, this should DCE3.2 only, but in
* practice it seems to cover DCE2.0/3.0/3.1 as well.
*/
if (dig->dig_encoder == 0) {
WREG32(DCCG_AUDIO_DTO0_PHASE, base_rate * 100);
WREG32(DCCG_AUDIO_DTO0_MODULE, clock * 100);
WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */
} else {
WREG32(DCCG_AUDIO_DTO1_PHASE, base_rate * 100);
WREG32(DCCG_AUDIO_DTO1_MODULE, clock * 100);
WREG32(DCCG_AUDIO_DTO_SELECT, 1); /* select DTO1 */
}
WREG32(DCCG_AUDIO_DTO1_PHASE, 24000 * 100);
WREG32(DCCG_AUDIO_DTO1_MODULE, clock * 100);
WREG32(DCCG_AUDIO_DTO_SELECT, 1); /* select DTO1 */
}
}
/*
* update the info frames with the data from the current display mode
*/
void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode)
void r600_set_vbi_packet(struct drm_encoder *encoder, u32 offset)
{
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;
u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
struct hdmi_avi_infoframe frame;
uint32_t offset;
uint32_t acr_ctl;
ssize_t err;
if (!dig || !dig->afmt)
return;
/* Silent, r600_hdmi_enable will raise WARN for us */
if (!dig->afmt->enabled)
return;
offset = dig->afmt->offset;
/* disable audio prior to setting up hw */
dig->afmt->pin = r600_audio_get_pin(rdev);
r600_audio_enable(rdev, dig->afmt->pin, 0xf);
r600_audio_set_dto(encoder, mode->clock);
WREG32_P(HDMI0_AUDIO_PACKET_CONTROL + offset,
HDMI0_AUDIO_SAMPLE_SEND | /* send audio packets */
HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */
HDMI0_AUDIO_PACKETS_PER_LINE(3) | /* should be suffient for all audio modes and small enough for all hblanks */
HDMI0_60958_CS_UPDATE, /* allow 60958 channel status fields to be updated */
~(HDMI0_AUDIO_SAMPLE_SEND |
HDMI0_AUDIO_DELAY_EN_MASK |
HDMI0_AUDIO_PACKETS_PER_LINE_MASK |
HDMI0_60958_CS_UPDATE));
/* DCE 3.0 uses register that's normally for CRC_CONTROL */
acr_ctl = ASIC_IS_DCE3(rdev) ? DCE3_HDMI0_ACR_PACKET_CONTROL :
HDMI0_ACR_PACKET_CONTROL;
WREG32_P(acr_ctl + offset,
HDMI0_ACR_SOURCE | /* select SW CTS value - XXX verify that hw CTS works on all families */
HDMI0_ACR_AUTO_SEND, /* allow hw to sent ACR packets when required */
~(HDMI0_ACR_SOURCE |
HDMI0_ACR_AUTO_SEND));
WREG32_OR(HDMI0_VBI_PACKET_CONTROL + offset,
HDMI0_NULL_SEND | /* send null packets when required */
HDMI0_GC_SEND | /* send general control packets */
HDMI0_GC_CONT); /* send general control packets every frame */
HDMI0_NULL_SEND | /* send null packets when required */
HDMI0_GC_SEND | /* send general control packets */
HDMI0_GC_CONT); /* send general control packets every frame */
}
void r600_set_audio_packet(struct drm_encoder *encoder, u32 offset)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
WREG32_P(HDMI0_AUDIO_PACKET_CONTROL + offset,
HDMI0_AUDIO_SAMPLE_SEND | /* send audio packets */
HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */
HDMI0_AUDIO_PACKETS_PER_LINE(3) | /* should be suffient for all audio modes and small enough for all hblanks */
HDMI0_60958_CS_UPDATE, /* allow 60958 channel status fields to be updated */
~(HDMI0_AUDIO_SAMPLE_SEND |
HDMI0_AUDIO_DELAY_EN_MASK |
HDMI0_AUDIO_PACKETS_PER_LINE_MASK |
HDMI0_60958_CS_UPDATE));
WREG32_OR(HDMI0_INFOFRAME_CONTROL0 + offset,
HDMI0_AVI_INFO_SEND | /* enable AVI info frames */
HDMI0_AVI_INFO_CONT | /* send AVI info frames every frame/field */
HDMI0_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
HDMI0_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */
HDMI0_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
HDMI0_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */
WREG32_P(HDMI0_INFOFRAME_CONTROL1 + offset,
HDMI0_AVI_INFO_LINE(2) | /* anything other than 0 */
HDMI0_AUDIO_INFO_LINE(2), /* anything other than 0 */
~(HDMI0_AVI_INFO_LINE_MASK |
HDMI0_AUDIO_INFO_LINE_MASK));
WREG32_AND(HDMI0_GC + offset,
~HDMI0_GC_AVMUTE); /* unset HDMI0_GC_AVMUTE */
err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
if (err < 0) {
DRM_ERROR("failed to setup AVI infoframe: %zd\n", err);
return;
}
err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer));
if (err < 0) {
DRM_ERROR("failed to pack AVI infoframe: %zd\n", err);
return;
}
r600_hdmi_update_avi_infoframe(encoder, buffer, sizeof(buffer));
/* fglrx duplicates INFOFRAME_CONTROL0 & INFOFRAME_CONTROL1 ops here */
HDMI0_AUDIO_INFO_LINE(2), /* anything other than 0 */
~HDMI0_AUDIO_INFO_LINE_MASK);
WREG32_AND(HDMI0_GENERIC_PACKET_CONTROL + offset,
~(HDMI0_GENERIC0_SEND |
HDMI0_GENERIC0_CONT |
HDMI0_GENERIC0_UPDATE |
HDMI0_GENERIC1_SEND |
HDMI0_GENERIC1_CONT |
HDMI0_GENERIC0_LINE_MASK |
HDMI0_GENERIC1_LINE_MASK));
r600_hdmi_update_ACR(encoder, mode->clock);
~(HDMI0_GENERIC0_SEND |
HDMI0_GENERIC0_CONT |
HDMI0_GENERIC0_UPDATE |
HDMI0_GENERIC1_SEND |
HDMI0_GENERIC1_CONT |
HDMI0_GENERIC0_LINE_MASK |
HDMI0_GENERIC1_LINE_MASK));
WREG32_P(HDMI0_60958_0 + offset,
HDMI0_60958_CS_CHANNEL_NUMBER_L(1),
~(HDMI0_60958_CS_CHANNEL_NUMBER_L_MASK |
HDMI0_60958_CS_CLOCK_ACCURACY_MASK));
HDMI0_60958_CS_CHANNEL_NUMBER_L(1),
~(HDMI0_60958_CS_CHANNEL_NUMBER_L_MASK |
HDMI0_60958_CS_CLOCK_ACCURACY_MASK));
WREG32_P(HDMI0_60958_1 + offset,
HDMI0_60958_CS_CHANNEL_NUMBER_R(2),
~HDMI0_60958_CS_CHANNEL_NUMBER_R_MASK);
HDMI0_60958_CS_CHANNEL_NUMBER_R(2),
~HDMI0_60958_CS_CHANNEL_NUMBER_R_MASK);
}
/* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */
WREG32(HDMI0_RAMP_CONTROL0 + offset, 0x00FFFFFF);
WREG32(HDMI0_RAMP_CONTROL1 + offset, 0x007FFFFF);
WREG32(HDMI0_RAMP_CONTROL2 + offset, 0x00000001);
WREG32(HDMI0_RAMP_CONTROL3 + offset, 0x00000001);
void r600_set_mute(struct drm_encoder *encoder, u32 offset, bool mute)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
/* enable audio after to setting up hw */
r600_audio_enable(rdev, dig->afmt->pin, 0xf);
if (mute)
WREG32_OR(HDMI0_GC + offset, HDMI0_GC_AVMUTE);
else
WREG32_AND(HDMI0_GC + offset, ~HDMI0_GC_AVMUTE);
}
/**
@ -692,7 +483,7 @@ void r600_hdmi_enable(struct drm_encoder *encoder, bool enable)
return;
if (!enable && dig->afmt->pin) {
r600_audio_enable(rdev, dig->afmt->pin, 0);
radeon_audio_enable(rdev, dig->afmt->pin, 0);
dig->afmt->pin = NULL;
}

View File

@ -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;
};
/*
@ -1777,8 +1780,16 @@ void radeon_test_syncing(struct radeon_device *rdev);
/*
* MMU Notifier
*/
#if defined(CONFIG_MMU_NOTIFIER)
int radeon_mn_register(struct radeon_bo *bo, unsigned long addr);
void radeon_mn_unregister(struct radeon_bo *bo);
#else
static inline int radeon_mn_register(struct radeon_bo *bo, unsigned long addr)
{
return -ENODEV;
}
static inline void radeon_mn_unregister(struct radeon_bo *bo) {}
#endif
/*
* Debugfs
@ -1967,6 +1978,10 @@ struct radeon_asic {
bool (*vblank_too_short)(struct radeon_device *rdev);
void (*powergate_uvd)(struct radeon_device *rdev, bool gate);
void (*enable_bapm)(struct radeon_device *rdev, bool enable);
void (*fan_ctrl_set_mode)(struct radeon_device *rdev, u32 mode);
u32 (*fan_ctrl_get_mode)(struct radeon_device *rdev);
int (*set_fan_speed_percent)(struct radeon_device *rdev, u32 speed);
int (*get_fan_speed_percent)(struct radeon_device *rdev, u32 *speed);
} dpm;
/* pageflipping */
struct {

View File

@ -638,8 +638,6 @@ static struct radeon_asic rs600_asic = {
.wait_for_vblank = &avivo_wait_for_vblank,
.set_backlight_level = &atombios_set_backlight_level,
.get_backlight_level = &atombios_get_backlight_level,
.hdmi_enable = &r600_hdmi_enable,
.hdmi_setmode = &r600_hdmi_setmode,
},
.copy = {
.blit = &r100_copy_blit,
@ -706,8 +704,6 @@ static struct radeon_asic rs690_asic = {
.wait_for_vblank = &avivo_wait_for_vblank,
.set_backlight_level = &atombios_set_backlight_level,
.get_backlight_level = &atombios_get_backlight_level,
.hdmi_enable = &r600_hdmi_enable,
.hdmi_setmode = &r600_hdmi_setmode,
},
.copy = {
.blit = &r100_copy_blit,
@ -935,8 +931,6 @@ static struct radeon_asic r600_asic = {
.wait_for_vblank = &avivo_wait_for_vblank,
.set_backlight_level = &atombios_set_backlight_level,
.get_backlight_level = &atombios_get_backlight_level,
.hdmi_enable = &r600_hdmi_enable,
.hdmi_setmode = &r600_hdmi_setmode,
},
.copy = {
.blit = &r600_copy_cpdma,
@ -1021,8 +1015,6 @@ static struct radeon_asic rv6xx_asic = {
.wait_for_vblank = &avivo_wait_for_vblank,
.set_backlight_level = &atombios_set_backlight_level,
.get_backlight_level = &atombios_get_backlight_level,
.hdmi_enable = &r600_hdmi_enable,
.hdmi_setmode = &r600_hdmi_setmode,
},
.copy = {
.blit = &r600_copy_cpdma,
@ -1112,8 +1104,6 @@ static struct radeon_asic rs780_asic = {
.wait_for_vblank = &avivo_wait_for_vblank,
.set_backlight_level = &atombios_set_backlight_level,
.get_backlight_level = &atombios_get_backlight_level,
.hdmi_enable = &r600_hdmi_enable,
.hdmi_setmode = &r600_hdmi_setmode,
},
.copy = {
.blit = &r600_copy_cpdma,
@ -1216,8 +1206,6 @@ static struct radeon_asic rv770_asic = {
.wait_for_vblank = &avivo_wait_for_vblank,
.set_backlight_level = &atombios_set_backlight_level,
.get_backlight_level = &atombios_get_backlight_level,
.hdmi_enable = &r600_hdmi_enable,
.hdmi_setmode = &dce3_1_hdmi_setmode,
},
.copy = {
.blit = &r600_copy_cpdma,
@ -1334,8 +1322,6 @@ static struct radeon_asic evergreen_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,
@ -1426,8 +1412,6 @@ static struct radeon_asic sumo_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,
@ -1517,8 +1501,6 @@ static struct radeon_asic btc_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,
@ -1663,8 +1645,6 @@ static struct radeon_asic cayman_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,
@ -1766,8 +1746,6 @@ 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,
@ -1899,8 +1877,6 @@ 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 = &r600_copy_cpdma,
@ -1953,6 +1929,10 @@ static struct radeon_asic si_asic = {
.debugfs_print_current_performance_level = &si_dpm_debugfs_print_current_performance_level,
.force_performance_level = &si_dpm_force_performance_level,
.vblank_too_short = &ni_dpm_vblank_too_short,
.fan_ctrl_set_mode = &si_fan_ctrl_set_mode,
.fan_ctrl_get_mode = &si_fan_ctrl_get_mode,
.get_fan_speed_percent = &si_fan_ctrl_get_fan_speed_percent,
.set_fan_speed_percent = &si_fan_ctrl_set_fan_speed_percent,
},
.pflip = {
.page_flip = &evergreen_page_flip,
@ -2062,8 +2042,6 @@ static struct radeon_asic ci_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 = &cik_copy_cpdma,
@ -2118,6 +2096,10 @@ static struct radeon_asic ci_asic = {
.force_performance_level = &ci_dpm_force_performance_level,
.vblank_too_short = &ci_dpm_vblank_too_short,
.powergate_uvd = &ci_dpm_powergate_uvd,
.fan_ctrl_set_mode = &ci_fan_ctrl_set_mode,
.fan_ctrl_get_mode = &ci_fan_ctrl_get_mode,
.get_fan_speed_percent = &ci_fan_ctrl_get_fan_speed_percent,
.set_fan_speed_percent = &ci_fan_ctrl_set_fan_speed_percent,
},
.pflip = {
.page_flip = &evergreen_page_flip,
@ -2169,8 +2151,6 @@ static struct radeon_asic kv_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 = &cik_copy_cpdma,

View File

@ -390,7 +390,6 @@ void r600_irq_suspend(struct radeon_device *rdev);
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);
void r600_audio_fini(struct radeon_device *rdev);
void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock);
void r600_hdmi_update_avi_infoframe(struct drm_encoder *encoder, void *buffer,
@ -399,8 +398,6 @@ void r600_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t clock);
void r600_hdmi_audio_workaround(struct drm_encoder *encoder);
int r600_hdmi_buffer_status_changed(struct drm_encoder *encoder);
void r600_hdmi_update_audio_settings(struct drm_encoder *encoder);
void r600_hdmi_enable(struct drm_encoder *encoder, bool enable);
void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode);
int r600_mc_wait_for_idle(struct radeon_device *rdev);
u32 r600_get_xclk(struct radeon_device *rdev);
uint64_t r600_get_gpu_clock_counter(struct radeon_device *rdev);
@ -469,8 +466,6 @@ struct radeon_fence *rv770_copy_dma(struct radeon_device *rdev,
u32 rv770_get_xclk(struct radeon_device *rdev);
int rv770_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
int rv770_get_temp(struct radeon_device *rdev);
/* hdmi */
void dce3_1_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode);
/* rv7xx pm */
int rv770_dpm_init(struct radeon_device *rdev);
int rv770_dpm_enable(struct radeon_device *rdev);
@ -540,8 +535,6 @@ struct radeon_fence *evergreen_copy_dma(struct radeon_device *rdev,
uint64_t src_offset, uint64_t dst_offset,
unsigned num_gpu_pages,
struct reservation_object *resv);
void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable);
void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode);
int evergreen_get_temp(struct radeon_device *rdev);
int sumo_get_temp(struct radeon_device *rdev);
int tn_get_temp(struct radeon_device *rdev);
@ -680,7 +673,6 @@ void trinity_dpm_enable_bapm(struct radeon_device *rdev, bool enable);
/* 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);
/*
@ -744,6 +736,12 @@ void si_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
struct seq_file *m);
int si_dpm_force_performance_level(struct radeon_device *rdev,
enum radeon_dpm_forced_level level);
int si_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
u32 *speed);
int si_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
u32 speed);
u32 si_fan_ctrl_get_mode(struct radeon_device *rdev);
void si_fan_ctrl_set_mode(struct radeon_device *rdev, u32 mode);
/* DCE8 - CIK */
void dce8_bandwidth_update(struct radeon_device *rdev);
@ -861,6 +859,13 @@ int ci_dpm_force_performance_level(struct radeon_device *rdev,
bool ci_dpm_vblank_too_short(struct radeon_device *rdev);
void ci_dpm_powergate_uvd(struct radeon_device *rdev, bool gate);
int ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
u32 *speed);
int ci_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
u32 speed);
u32 ci_fan_ctrl_get_mode(struct radeon_device *rdev);
void ci_fan_ctrl_set_mode(struct radeon_device *rdev, u32 mode);
int kv_dpm_init(struct radeon_device *rdev);
int kv_dpm_enable(struct radeon_device *rdev);
int kv_dpm_late_enable(struct radeon_device *rdev);

View File

@ -0,0 +1,766 @@
/*
* Copyright 2014 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.
*
* Authors: Slava Grigorev <slava.grigorev@amd.com>
*/
#include <linux/gcd.h>
#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 dce4_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);
void dce3_2_afmt_write_sad_regs(struct drm_encoder *encoder,
struct cea_sad *sads, int sad_count);
void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder,
struct cea_sad *sads, int sad_count);
void dce6_afmt_write_sad_regs(struct drm_encoder *encoder,
struct cea_sad *sads, int sad_count);
void dce3_2_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder,
u8 *sadb, int sad_count);
void dce3_2_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder,
u8 *sadb, int sad_count);
void dce4_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder,
u8 *sadb, int sad_count);
void dce4_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder,
u8 *sadb, int sad_count);
void dce6_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder,
u8 *sadb, int sad_count);
void dce6_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder,
u8 *sadb, int sad_count);
void dce4_afmt_write_latency_fields(struct drm_encoder *encoder,
struct drm_connector *connector, struct drm_display_mode *mode);
void dce6_afmt_write_latency_fields(struct drm_encoder *encoder,
struct drm_connector *connector, struct drm_display_mode *mode);
struct r600_audio_pin* r600_audio_get_pin(struct radeon_device *rdev);
struct r600_audio_pin* dce6_audio_get_pin(struct radeon_device *rdev);
void dce6_afmt_select_pin(struct drm_encoder *encoder);
void r600_hdmi_audio_set_dto(struct radeon_device *rdev,
struct radeon_crtc *crtc, unsigned int clock);
void dce3_2_audio_set_dto(struct radeon_device *rdev,
struct radeon_crtc *crtc, unsigned int clock);
void dce4_hdmi_audio_set_dto(struct radeon_device *rdev,
struct radeon_crtc *crtc, unsigned int clock);
void dce4_dp_audio_set_dto(struct radeon_device *rdev,
struct radeon_crtc *crtc, unsigned int clock);
void dce6_hdmi_audio_set_dto(struct radeon_device *rdev,
struct radeon_crtc *crtc, unsigned int clock);
void dce6_dp_audio_set_dto(struct radeon_device *rdev,
struct radeon_crtc *crtc, unsigned int clock);
void r600_set_avi_packet(struct radeon_device *rdev, u32 offset,
unsigned char *buffer, size_t size);
void evergreen_set_avi_packet(struct radeon_device *rdev, u32 offset,
unsigned char *buffer, size_t size);
void r600_hdmi_update_acr(struct drm_encoder *encoder, long offset,
const struct radeon_hdmi_acr *acr);
void dce3_2_hdmi_update_acr(struct drm_encoder *encoder, long offset,
const struct radeon_hdmi_acr *acr);
void evergreen_hdmi_update_acr(struct drm_encoder *encoder, long offset,
const struct radeon_hdmi_acr *acr);
void r600_set_vbi_packet(struct drm_encoder *encoder, u32 offset);
void dce4_set_vbi_packet(struct drm_encoder *encoder, u32 offset);
void dce4_hdmi_set_color_depth(struct drm_encoder *encoder,
u32 offset, int bpc);
void r600_set_audio_packet(struct drm_encoder *encoder, u32 offset);
void dce3_2_set_audio_packet(struct drm_encoder *encoder, u32 offset);
void dce4_set_audio_packet(struct drm_encoder *encoder, u32 offset);
void r600_set_mute(struct drm_encoder *encoder, u32 offset, bool mute);
void dce3_2_set_mute(struct drm_encoder *encoder, u32 offset, bool mute);
void dce4_set_mute(struct drm_encoder *encoder, u32 offset, bool mute);
static void radeon_audio_hdmi_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode);
static void radeon_audio_dp_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode);
void r600_hdmi_enable(struct drm_encoder *encoder, bool enable);
void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable);
void evergreen_enable_dp_audio_packets(struct drm_encoder *encoder, bool enable);
void dce6_enable_dp_audio_packets(struct drm_encoder *encoder, bool enable);
static const u32 pin_offsets[7] =
{
(0x5e00 - 0x5e00),
(0x5e18 - 0x5e00),
(0x5e30 - 0x5e00),
(0x5e48 - 0x5e00),
(0x5e60 - 0x5e00),
(0x5e78 - 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 r600_funcs = {
.endpoint_rreg = radeon_audio_rreg,
.endpoint_wreg = radeon_audio_wreg,
.enable = r600_audio_enable,
};
static struct radeon_audio_basic_funcs dce32_funcs = {
.endpoint_rreg = radeon_audio_rreg,
.endpoint_wreg = radeon_audio_wreg,
.enable = r600_audio_enable,
};
static struct radeon_audio_basic_funcs dce4_funcs = {
.endpoint_rreg = radeon_audio_rreg,
.endpoint_wreg = radeon_audio_wreg,
.enable = dce4_audio_enable,
};
static struct radeon_audio_basic_funcs dce6_funcs = {
.endpoint_rreg = dce6_endpoint_rreg,
.endpoint_wreg = dce6_endpoint_wreg,
.enable = dce6_audio_enable,
};
static struct radeon_audio_funcs r600_hdmi_funcs = {
.get_pin = r600_audio_get_pin,
.set_dto = r600_hdmi_audio_set_dto,
.update_acr = r600_hdmi_update_acr,
.set_vbi_packet = r600_set_vbi_packet,
.set_avi_packet = r600_set_avi_packet,
.set_audio_packet = r600_set_audio_packet,
.set_mute = r600_set_mute,
.mode_set = radeon_audio_hdmi_mode_set,
.dpms = r600_hdmi_enable,
};
static struct radeon_audio_funcs dce32_hdmi_funcs = {
.get_pin = r600_audio_get_pin,
.write_sad_regs = dce3_2_afmt_write_sad_regs,
.write_speaker_allocation = dce3_2_afmt_hdmi_write_speaker_allocation,
.set_dto = dce3_2_audio_set_dto,
.update_acr = dce3_2_hdmi_update_acr,
.set_vbi_packet = r600_set_vbi_packet,
.set_avi_packet = r600_set_avi_packet,
.set_audio_packet = dce3_2_set_audio_packet,
.set_mute = dce3_2_set_mute,
.mode_set = radeon_audio_hdmi_mode_set,
.dpms = r600_hdmi_enable,
};
static struct radeon_audio_funcs dce32_dp_funcs = {
.get_pin = r600_audio_get_pin,
.write_sad_regs = dce3_2_afmt_write_sad_regs,
.write_speaker_allocation = dce3_2_afmt_dp_write_speaker_allocation,
.set_dto = dce3_2_audio_set_dto,
.set_avi_packet = r600_set_avi_packet,
.set_audio_packet = dce3_2_set_audio_packet,
};
static struct radeon_audio_funcs dce4_hdmi_funcs = {
.get_pin = r600_audio_get_pin,
.write_sad_regs = evergreen_hdmi_write_sad_regs,
.write_speaker_allocation = dce4_afmt_hdmi_write_speaker_allocation,
.write_latency_fields = dce4_afmt_write_latency_fields,
.set_dto = dce4_hdmi_audio_set_dto,
.update_acr = evergreen_hdmi_update_acr,
.set_vbi_packet = dce4_set_vbi_packet,
.set_color_depth = dce4_hdmi_set_color_depth,
.set_avi_packet = evergreen_set_avi_packet,
.set_audio_packet = dce4_set_audio_packet,
.set_mute = dce4_set_mute,
.mode_set = radeon_audio_hdmi_mode_set,
.dpms = evergreen_hdmi_enable,
};
static struct radeon_audio_funcs dce4_dp_funcs = {
.get_pin = r600_audio_get_pin,
.write_sad_regs = evergreen_hdmi_write_sad_regs,
.write_speaker_allocation = dce4_afmt_dp_write_speaker_allocation,
.write_latency_fields = dce4_afmt_write_latency_fields,
.set_dto = dce4_dp_audio_set_dto,
.set_avi_packet = evergreen_set_avi_packet,
.set_audio_packet = dce4_set_audio_packet,
.mode_set = radeon_audio_dp_mode_set,
.dpms = evergreen_enable_dp_audio_packets,
};
static struct radeon_audio_funcs dce6_hdmi_funcs = {
.select_pin = dce6_afmt_select_pin,
.get_pin = dce6_audio_get_pin,
.write_sad_regs = dce6_afmt_write_sad_regs,
.write_speaker_allocation = dce6_afmt_hdmi_write_speaker_allocation,
.write_latency_fields = dce6_afmt_write_latency_fields,
.set_dto = dce6_hdmi_audio_set_dto,
.update_acr = evergreen_hdmi_update_acr,
.set_vbi_packet = dce4_set_vbi_packet,
.set_color_depth = dce4_hdmi_set_color_depth,
.set_avi_packet = evergreen_set_avi_packet,
.set_audio_packet = dce4_set_audio_packet,
.set_mute = dce4_set_mute,
.mode_set = radeon_audio_hdmi_mode_set,
.dpms = evergreen_hdmi_enable,
};
static struct radeon_audio_funcs dce6_dp_funcs = {
.select_pin = dce6_afmt_select_pin,
.get_pin = dce6_audio_get_pin,
.write_sad_regs = dce6_afmt_write_sad_regs,
.write_speaker_allocation = dce6_afmt_dp_write_speaker_allocation,
.write_latency_fields = dce6_afmt_write_latency_fields,
.set_dto = dce6_dp_audio_set_dto,
.set_avi_packet = evergreen_set_avi_packet,
.set_audio_packet = dce4_set_audio_packet,
.mode_set = radeon_audio_dp_mode_set,
.dpms = dce6_enable_dp_audio_packets,
};
static void radeon_audio_interface_init(struct radeon_device *rdev)
{
if (ASIC_IS_DCE6(rdev)) {
rdev->audio.funcs = &dce6_funcs;
rdev->audio.hdmi_funcs = &dce6_hdmi_funcs;
rdev->audio.dp_funcs = &dce6_dp_funcs;
} else if (ASIC_IS_DCE4(rdev)) {
rdev->audio.funcs = &dce4_funcs;
rdev->audio.hdmi_funcs = &dce4_hdmi_funcs;
rdev->audio.dp_funcs = &dce4_dp_funcs;
} else if (ASIC_IS_DCE32(rdev)) {
rdev->audio.funcs = &dce32_funcs;
rdev->audio.hdmi_funcs = &dce32_hdmi_funcs;
rdev->audio.dp_funcs = &dce32_dp_funcs;
} else {
rdev->audio.funcs = &r600_funcs;
rdev->audio.hdmi_funcs = &r600_hdmi_funcs;
rdev->audio.dp_funcs = 0;
}
}
static int radeon_audio_chipset_supported(struct radeon_device *rdev)
{
return ASIC_IS_DCE2(rdev) && !ASIC_IS_NODCE(rdev);
}
int radeon_audio_init(struct radeon_device *rdev)
{
int i;
if (!radeon_audio || !radeon_audio_chipset_supported(rdev))
return 0;
rdev->audio.enabled = true;
if (ASIC_IS_DCE83(rdev)) /* KB: 2 streams, 3 endpoints */
rdev->audio.num_pins = 3;
else if (ASIC_IS_DCE81(rdev)) /* KV: 4 streams, 7 endpoints */
rdev->audio.num_pins = 7;
else if (ASIC_IS_DCE8(rdev)) /* BN/HW: 6 streams, 7 endpoints */
rdev->audio.num_pins = 7;
else if (ASIC_IS_DCE64(rdev)) /* OL: 2 streams, 2 endpoints */
rdev->audio.num_pins = 2;
else if (ASIC_IS_DCE61(rdev)) /* TN: 4 streams, 6 endpoints */
rdev->audio.num_pins = 6;
else if (ASIC_IS_DCE6(rdev)) /* SI: 6 streams, 6 endpoints */
rdev->audio.num_pins = 6;
else
rdev->audio.num_pins = 1;
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;
}
radeon_audio_interface_init(rdev);
/* disable audio. it will be set up later */
for (i = 0; i < rdev->audio.num_pins; i++)
radeon_audio_enable(rdev, &rdev->audio.pin[i], false);
return 0;
}
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);
}
static void radeon_audio_write_sad_regs(struct drm_encoder *encoder)
{
struct radeon_encoder *radeon_encoder;
struct drm_connector *connector;
struct radeon_connector *radeon_connector = NULL;
struct cea_sad *sads;
int sad_count;
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);
radeon_encoder = to_radeon_encoder(encoder);
if (radeon_encoder->audio && radeon_encoder->audio->write_sad_regs)
radeon_encoder->audio->write_sad_regs(encoder, sads, sad_count);
kfree(sads);
}
static void radeon_audio_write_speaker_allocation(struct drm_encoder *encoder)
{
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct drm_connector *connector;
struct radeon_connector *radeon_connector = NULL;
u8 *sadb = NULL;
int sad_count;
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;
}
if (radeon_encoder->audio && radeon_encoder->audio->write_speaker_allocation)
radeon_encoder->audio->write_speaker_allocation(encoder, sadb, sad_count);
kfree(sadb);
}
static void radeon_audio_write_latency_fields(struct drm_encoder *encoder,
struct drm_display_mode *mode)
{
struct radeon_encoder *radeon_encoder;
struct drm_connector *connector;
struct radeon_connector *radeon_connector = 0;
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;
}
radeon_encoder = to_radeon_encoder(encoder);
if (radeon_encoder->audio && radeon_encoder->audio->write_latency_fields)
radeon_encoder->audio->write_latency_fields(encoder, connector, mode);
}
struct r600_audio_pin* radeon_audio_get_pin(struct drm_encoder *encoder)
{
struct radeon_device *rdev = encoder->dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
if (radeon_encoder->audio && radeon_encoder->audio->get_pin)
return radeon_encoder->audio->get_pin(rdev);
return NULL;
}
static void radeon_audio_select_pin(struct drm_encoder *encoder)
{
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
if (radeon_encoder->audio && radeon_encoder->audio->select_pin)
radeon_encoder->audio->select_pin(encoder);
}
void radeon_audio_enable(struct radeon_device *rdev,
struct r600_audio_pin *pin, u8 enable_mask)
{
if (rdev->audio.funcs->enable)
rdev->audio.funcs->enable(rdev, pin, enable_mask);
}
void radeon_audio_detect(struct drm_connector *connector,
enum drm_connector_status status)
{
struct radeon_device *rdev;
struct radeon_encoder *radeon_encoder;
struct radeon_encoder_atom_dig *dig;
if (!connector || !connector->encoder)
return;
rdev = connector->encoder->dev->dev_private;
radeon_encoder = to_radeon_encoder(connector->encoder);
dig = radeon_encoder->enc_priv;
if (status == connector_status_connected) {
struct radeon_connector *radeon_connector;
int sink_type;
if (!drm_detect_monitor_audio(radeon_connector_edid(connector))) {
radeon_encoder->audio = NULL;
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;
radeon_audio_write_speaker_allocation(connector->encoder);
radeon_audio_write_sad_regs(connector->encoder);
if (connector->encoder->crtc)
radeon_audio_write_latency_fields(connector->encoder,
&connector->encoder->crtc->mode);
radeon_audio_enable(rdev, dig->afmt->pin, 0xf);
} else {
radeon_audio_enable(rdev, dig->afmt->pin, 0);
}
}
void radeon_audio_fini(struct radeon_device *rdev)
{
int i;
if (!rdev->audio.enabled)
return;
for (i = 0; i < rdev->audio.num_pins; i++)
radeon_audio_enable(rdev, &rdev->audio.pin[i], false);
rdev->audio.enabled = false;
}
static void radeon_audio_set_dto(struct drm_encoder *encoder, unsigned int clock)
{
struct radeon_device *rdev = encoder->dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_crtc *crtc = to_radeon_crtc(encoder->crtc);
if (radeon_encoder->audio && radeon_encoder->audio->set_dto)
radeon_encoder->audio->set_dto(rdev, crtc, clock);
}
static int radeon_audio_set_avi_packet(struct drm_encoder *encoder,
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;
u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
struct hdmi_avi_infoframe frame;
int err;
err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
if (err < 0) {
DRM_ERROR("failed to setup AVI infoframe: %d\n", err);
return err;
}
err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer));
if (err < 0) {
DRM_ERROR("failed to pack AVI infoframe: %d\n", err);
return err;
}
if (dig && dig->afmt &&
radeon_encoder->audio && radeon_encoder->audio->set_avi_packet)
radeon_encoder->audio->set_avi_packet(rdev, dig->afmt->offset,
buffer, sizeof(buffer));
return 0;
}
/*
* calculate CTS and N values if they are not found in the table
*/
static void radeon_audio_calc_cts(unsigned int clock, int *CTS, int *N, int freq)
{
int n, cts;
unsigned long div, mul;
/* Safe, but overly large values */
n = 128 * freq;
cts = clock * 1000;
/* Smallest valid fraction */
div = gcd(n, cts);
n /= div;
cts /= div;
/*
* The optimal N is 128*freq/1000. Calculate the closest larger
* value that doesn't truncate any bits.
*/
mul = ((128*freq/1000) + (n-1))/n;
n *= mul;
cts *= mul;
/* Check that we are in spec (not always possible) */
if (n < (128*freq/1500))
printk(KERN_WARNING "Calculated ACR N value is too small. You may experience audio problems.\n");
if (n > (128*freq/300))
printk(KERN_WARNING "Calculated ACR N value is too large. You may experience audio problems.\n");
*N = n;
*CTS = cts;
DRM_DEBUG("Calculated ACR timing N=%d CTS=%d for frequency %d\n",
*N, *CTS, freq);
}
static const struct radeon_hdmi_acr* radeon_audio_acr(unsigned int clock)
{
static struct radeon_hdmi_acr res;
u8 i;
static const struct radeon_hdmi_acr hdmi_predefined_acr[] = {
/* 32kHz 44.1kHz 48kHz */
/* Clock N CTS N CTS N CTS */
{ 25175, 4096, 25175, 28224, 125875, 6144, 25175 }, /* 25,20/1.001 MHz */
{ 25200, 4096, 25200, 6272, 28000, 6144, 25200 }, /* 25.20 MHz */
{ 27000, 4096, 27000, 6272, 30000, 6144, 27000 }, /* 27.00 MHz */
{ 27027, 4096, 27027, 6272, 30030, 6144, 27027 }, /* 27.00*1.001 MHz */
{ 54000, 4096, 54000, 6272, 60000, 6144, 54000 }, /* 54.00 MHz */
{ 54054, 4096, 54054, 6272, 60060, 6144, 54054 }, /* 54.00*1.001 MHz */
{ 74176, 4096, 74176, 5733, 75335, 6144, 74176 }, /* 74.25/1.001 MHz */
{ 74250, 4096, 74250, 6272, 82500, 6144, 74250 }, /* 74.25 MHz */
{ 148352, 4096, 148352, 5733, 150670, 6144, 148352 }, /* 148.50/1.001 MHz */
{ 148500, 4096, 148500, 6272, 165000, 6144, 148500 }, /* 148.50 MHz */
};
/* Precalculated values for common clocks */
for (i = 0; i < ARRAY_SIZE(hdmi_predefined_acr); i++)
if (hdmi_predefined_acr[i].clock == clock)
return &hdmi_predefined_acr[i];
/* And odd clocks get manually calculated */
radeon_audio_calc_cts(clock, &res.cts_32khz, &res.n_32khz, 32000);
radeon_audio_calc_cts(clock, &res.cts_44_1khz, &res.n_44_1khz, 44100);
radeon_audio_calc_cts(clock, &res.cts_48khz, &res.n_48khz, 48000);
return &res;
}
/*
* update the N and CTS parameters for a given pixel clock rate
*/
static void radeon_audio_update_acr(struct drm_encoder *encoder, unsigned int clock)
{
const struct radeon_hdmi_acr *acr = radeon_audio_acr(clock);
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
if (!dig || !dig->afmt)
return;
if (radeon_encoder->audio && radeon_encoder->audio->update_acr)
radeon_encoder->audio->update_acr(encoder, dig->afmt->offset, acr);
}
static void radeon_audio_set_vbi_packet(struct drm_encoder *encoder)
{
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
if (!dig || !dig->afmt)
return;
if (radeon_encoder->audio && radeon_encoder->audio->set_vbi_packet)
radeon_encoder->audio->set_vbi_packet(encoder, dig->afmt->offset);
}
static void radeon_hdmi_set_color_depth(struct drm_encoder *encoder)
{
int bpc = 8;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
if (!dig || !dig->afmt)
return;
if (encoder->crtc) {
struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
bpc = radeon_crtc->bpc;
}
if (radeon_encoder->audio && radeon_encoder->audio->set_color_depth)
radeon_encoder->audio->set_color_depth(encoder, dig->afmt->offset, bpc);
}
static void radeon_audio_set_audio_packet(struct drm_encoder *encoder)
{
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
if (!dig || !dig->afmt)
return;
if (radeon_encoder->audio && radeon_encoder->audio->set_audio_packet)
radeon_encoder->audio->set_audio_packet(encoder, dig->afmt->offset);
}
static void radeon_audio_set_mute(struct drm_encoder *encoder, bool mute)
{
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
if (!dig || !dig->afmt)
return;
if (radeon_encoder->audio && radeon_encoder->audio->set_mute)
radeon_encoder->audio->set_mute(encoder, dig->afmt->offset, mute);
}
/*
* update the info frames with the data from the current display mode
*/
static void radeon_audio_hdmi_mode_set(struct drm_encoder *encoder,
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;
if (!dig || !dig->afmt)
return;
/* disable audio prior to setting up hw */
dig->afmt->pin = radeon_audio_get_pin(encoder);
radeon_audio_enable(rdev, dig->afmt->pin, 0);
radeon_audio_set_dto(encoder, mode->clock);
radeon_audio_set_vbi_packet(encoder);
radeon_hdmi_set_color_depth(encoder);
radeon_audio_set_mute(encoder, false);
radeon_audio_update_acr(encoder, mode->clock);
radeon_audio_set_audio_packet(encoder);
radeon_audio_select_pin(encoder);
if (radeon_audio_set_avi_packet(encoder, mode) < 0)
return;
/* enable audio after to setting up hw */
radeon_audio_enable(rdev, dig->afmt->pin, 0xf);
}
static void radeon_audio_dp_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode)
{
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;
if (!dig || !dig->afmt)
return;
/* disable audio prior to setting up hw */
dig->afmt->pin = radeon_audio_get_pin(encoder);
radeon_audio_enable(rdev, dig->afmt->pin, 0);
radeon_audio_set_dto(encoder, rdev->clock.default_dispclk * 10);
radeon_audio_set_audio_packet(encoder);
radeon_audio_select_pin(encoder);
if (radeon_audio_set_avi_packet(encoder, mode) < 0)
return;
/* enable audio after to setting up hw */
radeon_audio_enable(rdev, dig->afmt->pin, 0xf);
}
void radeon_audio_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode)
{
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
if (radeon_encoder->audio && radeon_encoder->audio->mode_set)
radeon_encoder->audio->mode_set(encoder, mode);
}
void radeon_audio_dpms(struct drm_encoder *encoder, int mode)
{
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
if (radeon_encoder->audio && radeon_encoder->audio->dpms)
radeon_encoder->audio->dpms(encoder, mode == DRM_MODE_DPMS_ON);
}

View File

@ -0,0 +1,84 @@
/*
* Copyright 2014 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.
*
* 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);
void (*enable)(struct radeon_device *rdev,
struct r600_audio_pin *pin, u8 enable_mask);
};
struct radeon_audio_funcs
{
void (*select_pin)(struct drm_encoder *encoder);
struct r600_audio_pin* (*get_pin)(struct radeon_device *rdev);
void (*write_latency_fields)(struct drm_encoder *encoder,
struct drm_connector *connector, struct drm_display_mode *mode);
void (*write_sad_regs)(struct drm_encoder *encoder,
struct cea_sad *sads, int sad_count);
void (*write_speaker_allocation)(struct drm_encoder *encoder,
u8 *sadb, int sad_count);
void (*set_dto)(struct radeon_device *rdev,
struct radeon_crtc *crtc, unsigned int clock);
void (*update_acr)(struct drm_encoder *encoder, long offset,
const struct radeon_hdmi_acr *acr);
void (*set_vbi_packet)(struct drm_encoder *encoder, u32 offset);
void (*set_color_depth)(struct drm_encoder *encoder, u32 offset, int bpc);
void (*set_avi_packet)(struct radeon_device *rdev, u32 offset,
unsigned char *buffer, size_t size);
void (*set_audio_packet)(struct drm_encoder *encoder, u32 offset);
void (*set_mute)(struct drm_encoder *encoder, u32 offset, bool mute);
void (*mode_set)(struct drm_encoder *encoder,
struct drm_display_mode *mode);
void (*dpms)(struct drm_encoder *encoder, bool mode);
};
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);
struct r600_audio_pin *radeon_audio_get_pin(struct drm_encoder *encoder);
void radeon_audio_enable(struct radeon_device *rdev,
struct r600_audio_pin *pin, u8 enable_mask);
void radeon_audio_fini(struct radeon_device *rdev);
void radeon_audio_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode);
void radeon_audio_dpms(struct drm_encoder *encoder, int mode);
#endif

View File

@ -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);

View File

@ -88,9 +88,10 @@
* 2.39.0 - Add INFO query for number of active CUs
* 2.40.0 - Add RADEON_GEM_GTT_WC/UC, flush HDP cache before submitting
* CS to GPU on >= r600
* 2.41.0 - evergreen/cayman: Add SET_BASE/DRAW_INDIRECT command parsing support
*/
#define KMS_DRIVER_MAJOR 2
#define KMS_DRIVER_MINOR 40
#define KMS_DRIVER_MINOR 41
#define KMS_DRIVER_PATCHLEVEL 0
int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);
int radeon_driver_unload_kms(struct drm_device *dev);

View File

@ -428,16 +428,6 @@ void radeon_fbdev_set_suspend(struct radeon_device *rdev, int state)
fb_set_suspend(rdev->mode_info.rfbdev->helper.fbdev, state);
}
int radeon_fbdev_total_size(struct radeon_device *rdev)
{
struct radeon_bo *robj;
int size = 0;
robj = gem_to_radeon_bo(rdev->mode_info.rfbdev->rfb.obj);
size += radeon_bo_size(robj);
return size;
}
bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj)
{
if (robj == gem_to_radeon_bo(rdev->mode_info.rfbdev->rfb.obj))

View File

@ -1048,11 +1048,6 @@ struct radeon_i2c_chan *radeon_i2c_lookup(struct radeon_device *rdev,
return NULL;
}
struct drm_encoder *radeon_best_encoder(struct drm_connector *connector)
{
return NULL;
}
void radeon_i2c_get_byte(struct radeon_i2c_chan *i2c_bus,
u8 slave_addr,
u8 addr,

View File

@ -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 {
@ -745,8 +746,6 @@ extern void radeon_router_select_ddc_port(struct radeon_connector *radeon_connec
extern void radeon_router_select_cd_port(struct radeon_connector *radeon_connector);
extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector, bool use_aux);
extern struct drm_encoder *radeon_best_encoder(struct drm_connector *connector);
extern bool radeon_atombios_get_ppll_ss_info(struct radeon_device *rdev,
struct radeon_atom_ss *ss,
int id);
@ -925,7 +924,6 @@ void dce8_program_fmt(struct drm_encoder *encoder);
int radeon_fbdev_init(struct radeon_device *rdev);
void radeon_fbdev_fini(struct radeon_device *rdev);
void radeon_fbdev_set_suspend(struct radeon_device *rdev, int state);
int radeon_fbdev_total_size(struct radeon_device *rdev);
bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj);
void radeon_fb_output_poll_changed(struct radeon_device *rdev);

View File

@ -576,12 +576,6 @@ int radeon_bo_list_validate(struct radeon_device *rdev,
return 0;
}
int radeon_bo_fbdev_mmap(struct radeon_bo *bo,
struct vm_area_struct *vma)
{
return ttm_fbdev_mmap(vma, &bo->tbo);
}
int radeon_bo_get_surface_reg(struct radeon_bo *bo)
{
struct radeon_device *rdev = bo->rdev;

View File

@ -143,8 +143,6 @@ extern void radeon_bo_fini(struct radeon_device *rdev);
extern int radeon_bo_list_validate(struct radeon_device *rdev,
struct ww_acquire_ctx *ticket,
struct list_head *head, int ring);
extern int radeon_bo_fbdev_mmap(struct radeon_bo *bo,
struct vm_area_struct *vma);
extern int radeon_bo_set_tiling_flags(struct radeon_bo *bo,
u32 tiling_flags, u32 pitch);
extern void radeon_bo_get_tiling_flags(struct radeon_bo *bo,

View File

@ -24,6 +24,7 @@
#include "radeon.h"
#include "avivod.h"
#include "atom.h"
#include "r600_dpm.h"
#include <linux/power_supply.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
@ -554,6 +555,96 @@ fail:
return count;
}
static ssize_t radeon_hwmon_get_pwm1_enable(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct radeon_device *rdev = dev_get_drvdata(dev);
u32 pwm_mode = 0;
if (rdev->asic->dpm.fan_ctrl_get_mode)
pwm_mode = rdev->asic->dpm.fan_ctrl_get_mode(rdev);
/* never 0 (full-speed), fuse or smc-controlled always */
return sprintf(buf, "%i\n", pwm_mode == FDO_PWM_MODE_STATIC ? 1 : 2);
}
static ssize_t radeon_hwmon_set_pwm1_enable(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t count)
{
struct radeon_device *rdev = dev_get_drvdata(dev);
int err;
int value;
if(!rdev->asic->dpm.fan_ctrl_set_mode)
return -EINVAL;
err = kstrtoint(buf, 10, &value);
if (err)
return err;
switch(value) {
case 1: /* manual, percent-based */
rdev->asic->dpm.fan_ctrl_set_mode(rdev, FDO_PWM_MODE_STATIC);
break;
default: /* disable */
rdev->asic->dpm.fan_ctrl_set_mode(rdev, 0);
break;
}
return count;
}
static ssize_t radeon_hwmon_get_pwm1_min(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "%i\n", 0);
}
static ssize_t radeon_hwmon_get_pwm1_max(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "%i\n", 100); /* pwm uses percent-based fan-control */
}
static ssize_t radeon_hwmon_set_pwm1(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct radeon_device *rdev = dev_get_drvdata(dev);
int err;
u32 value;
err = kstrtou32(buf, 10, &value);
if (err)
return err;
err = rdev->asic->dpm.set_fan_speed_percent(rdev, value);
if (err)
return err;
return count;
}
static ssize_t radeon_hwmon_get_pwm1(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct radeon_device *rdev = dev_get_drvdata(dev);
int err;
u32 speed;
err = rdev->asic->dpm.get_fan_speed_percent(rdev, &speed);
if (err)
return err;
return sprintf(buf, "%i\n", speed);
}
static DEVICE_ATTR(power_profile, S_IRUGO | S_IWUSR, radeon_get_pm_profile, radeon_set_pm_profile);
static DEVICE_ATTR(power_method, S_IRUGO | S_IWUSR, radeon_get_pm_method, radeon_set_pm_method);
static DEVICE_ATTR(power_dpm_state, S_IRUGO | S_IWUSR, radeon_get_dpm_state, radeon_set_dpm_state);
@ -601,11 +692,20 @@ static ssize_t radeon_hwmon_show_temp_thresh(struct device *dev,
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, radeon_hwmon_show_temp, NULL, 0);
static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, radeon_hwmon_show_temp_thresh, NULL, 0);
static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, radeon_hwmon_show_temp_thresh, NULL, 1);
static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, radeon_hwmon_get_pwm1, radeon_hwmon_set_pwm1, 0);
static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, radeon_hwmon_get_pwm1_enable, radeon_hwmon_set_pwm1_enable, 0);
static SENSOR_DEVICE_ATTR(pwm1_min, S_IRUGO, radeon_hwmon_get_pwm1_min, NULL, 0);
static SENSOR_DEVICE_ATTR(pwm1_max, S_IRUGO, radeon_hwmon_get_pwm1_max, NULL, 0);
static struct attribute *hwmon_attributes[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp1_crit.dev_attr.attr,
&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
&sensor_dev_attr_pwm1.dev_attr.attr,
&sensor_dev_attr_pwm1_enable.dev_attr.attr,
&sensor_dev_attr_pwm1_min.dev_attr.attr,
&sensor_dev_attr_pwm1_max.dev_attr.attr,
NULL
};
@ -614,6 +714,7 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj,
{
struct device *dev = container_of(kobj, struct device, kobj);
struct radeon_device *rdev = dev_get_drvdata(dev);
umode_t effective_mode = attr->mode;
/* Skip limit attributes if DPM is not enabled */
if (rdev->pm.pm_method != PM_METHOD_DPM &&
@ -621,7 +722,35 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj,
attr == &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr))
return 0;
return attr->mode;
/* Skip fan attributes if fan is not present */
if (rdev->pm.no_fan &&
(attr == &sensor_dev_attr_pwm1.dev_attr.attr ||
attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr ||
attr == &sensor_dev_attr_pwm1_max.dev_attr.attr ||
attr == &sensor_dev_attr_pwm1_min.dev_attr.attr))
return 0;
/* mask fan attributes if we have no bindings for this asic to expose */
if ((!rdev->asic->dpm.get_fan_speed_percent &&
attr == &sensor_dev_attr_pwm1.dev_attr.attr) || /* can't query fan */
(!rdev->asic->dpm.fan_ctrl_get_mode &&
attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr)) /* can't query state */
effective_mode &= ~S_IRUGO;
if ((!rdev->asic->dpm.set_fan_speed_percent &&
attr == &sensor_dev_attr_pwm1.dev_attr.attr) || /* can't manage fan */
(!rdev->asic->dpm.fan_ctrl_set_mode &&
attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr)) /* can't manage state */
effective_mode &= ~S_IWUSR;
/* hide max/min values if we can't both query and manage the fan */
if ((!rdev->asic->dpm.set_fan_speed_percent &&
!rdev->asic->dpm.get_fan_speed_percent) &&
(attr == &sensor_dev_attr_pwm1_max.dev_attr.attr ||
attr == &sensor_dev_attr_pwm1_min.dev_attr.attr))
return 0;
return effective_mode;
}
static const struct attribute_group hwmon_attrgroup = {

View File

@ -38,6 +38,7 @@
#include <drm/drmP.h>
#include "radeon.h"
#include "radeon_asic.h"
#include "radeon_audio.h"
#include "atom.h"
#include "rs600d.h"
@ -1012,7 +1013,7 @@ static int rs600_startup(struct radeon_device *rdev)
return r;
}
r = r600_audio_init(rdev);
r = radeon_audio_init(rdev);
if (r) {
dev_err(rdev->dev, "failed initializing audio\n");
return r;
@ -1053,7 +1054,7 @@ int rs600_resume(struct radeon_device *rdev)
int rs600_suspend(struct radeon_device *rdev)
{
radeon_pm_suspend(rdev);
r600_audio_fini(rdev);
radeon_audio_fini(rdev);
r100_cp_disable(rdev);
radeon_wb_disable(rdev);
rs600_irq_disable(rdev);
@ -1064,7 +1065,7 @@ int rs600_suspend(struct radeon_device *rdev)
void rs600_fini(struct radeon_device *rdev)
{
radeon_pm_fini(rdev);
r600_audio_fini(rdev);
radeon_audio_fini(rdev);
r100_cp_fini(rdev);
radeon_wb_fini(rdev);
radeon_ib_pool_fini(rdev);

View File

@ -28,6 +28,7 @@
#include <drm/drmP.h>
#include "radeon.h"
#include "radeon_asic.h"
#include "radeon_audio.h"
#include "atom.h"
#include "rs690d.h"
@ -729,7 +730,7 @@ static int rs690_startup(struct radeon_device *rdev)
return r;
}
r = r600_audio_init(rdev);
r = radeon_audio_init(rdev);
if (r) {
dev_err(rdev->dev, "failed initializing audio\n");
return r;
@ -770,7 +771,7 @@ int rs690_resume(struct radeon_device *rdev)
int rs690_suspend(struct radeon_device *rdev)
{
radeon_pm_suspend(rdev);
r600_audio_fini(rdev);
radeon_audio_fini(rdev);
r100_cp_disable(rdev);
radeon_wb_disable(rdev);
rs600_irq_disable(rdev);
@ -781,7 +782,7 @@ int rs690_suspend(struct radeon_device *rdev)
void rs690_fini(struct radeon_device *rdev)
{
radeon_pm_fini(rdev);
r600_audio_fini(rdev);
radeon_audio_fini(rdev);
r100_cp_fini(rdev);
radeon_wb_fini(rdev);
radeon_ib_pool_fini(rdev);

View File

@ -30,6 +30,7 @@
#include <drm/drmP.h>
#include "radeon.h"
#include "radeon_asic.h"
#include "radeon_audio.h"
#include <drm/radeon_drm.h>
#include "rv770d.h"
#include "atom.h"
@ -1788,7 +1789,7 @@ static int rv770_startup(struct radeon_device *rdev)
return r;
}
r = r600_audio_init(rdev);
r = radeon_audio_init(rdev);
if (r) {
DRM_ERROR("radeon: audio init failed\n");
return r;
@ -1829,7 +1830,7 @@ int rv770_resume(struct radeon_device *rdev)
int rv770_suspend(struct radeon_device *rdev)
{
radeon_pm_suspend(rdev);
r600_audio_fini(rdev);
radeon_audio_fini(rdev);
uvd_v1_0_fini(rdev);
radeon_uvd_suspend(rdev);
r700_cp_stop(rdev);

View File

@ -231,6 +231,7 @@ u8 rv770_get_seq_value(struct radeon_device *rdev,
MC_CG_SEQ_DRAMCONF_S0 : MC_CG_SEQ_DRAMCONF_S1;
}
#if 0
int rv770_read_smc_soft_register(struct radeon_device *rdev,
u16 reg_offset, u32 *value)
{
@ -240,6 +241,7 @@ int rv770_read_smc_soft_register(struct radeon_device *rdev,
pi->soft_regs_start + reg_offset,
value, pi->sram_end);
}
#endif
int rv770_write_smc_soft_register(struct radeon_device *rdev,
u16 reg_offset, u32 value)
@ -2075,6 +2077,7 @@ int rv770_dpm_set_power_state(struct radeon_device *rdev)
return 0;
}
#if 0
void rv770_dpm_reset_asic(struct radeon_device *rdev)
{
struct rv7xx_power_info *pi = rv770_get_pi(rdev);
@ -2087,6 +2090,7 @@ void rv770_dpm_reset_asic(struct radeon_device *rdev)
if (pi->dcodt)
rv770_program_dcodt_after_state_switch(rdev, boot_ps, boot_ps);
}
#endif
void rv770_dpm_setup_asic(struct radeon_device *rdev)
{

View File

@ -278,8 +278,6 @@ void rv770_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev,
void rv770_get_engine_memory_ss(struct radeon_device *rdev);
/* smc */
int rv770_read_smc_soft_register(struct radeon_device *rdev,
u16 reg_offset, u32 *value);
int rv770_write_smc_soft_register(struct radeon_device *rdev,
u16 reg_offset, u32 value);

View File

@ -27,6 +27,7 @@
#include <drm/drmP.h>
#include "radeon.h"
#include "radeon_asic.h"
#include "radeon_audio.h"
#include <drm/radeon_drm.h>
#include "sid.h"
#include "atom.h"
@ -6869,7 +6870,7 @@ static int si_startup(struct radeon_device *rdev)
return r;
}
r = dce6_audio_init(rdev);
r = radeon_audio_init(rdev);
if (r)
return r;
@ -6908,7 +6909,7 @@ int si_resume(struct radeon_device *rdev)
int si_suspend(struct radeon_device *rdev)
{
radeon_pm_suspend(rdev);
dce6_audio_fini(rdev);
radeon_audio_fini(rdev);
radeon_vm_manager_fini(rdev);
si_cp_enable(rdev, false);
cayman_dma_stop(rdev);

View File

@ -1756,6 +1756,9 @@ static int si_calculate_sclk_params(struct radeon_device *rdev,
u32 engine_clock,
SISLANDS_SMC_SCLK_VALUE *sclk);
static void si_thermal_start_smc_fan_control(struct radeon_device *rdev);
static void si_fan_ctrl_set_default_mode(struct radeon_device *rdev);
static struct si_power_info *si_get_pi(struct radeon_device *rdev)
{
struct si_power_info *pi = rdev->pm.dpm.priv;
@ -3359,11 +3362,13 @@ int si_dpm_force_performance_level(struct radeon_device *rdev,
return 0;
}
#if 0
static int si_set_boot_state(struct radeon_device *rdev)
{
return (si_send_msg_to_smc(rdev, PPSMC_MSG_SwitchToInitialState) == PPSMC_Result_OK) ?
0 : -EINVAL;
}
#endif
static int si_set_sw_state(struct radeon_device *rdev)
{
@ -5973,6 +5978,10 @@ static int si_thermal_setup_fan_table(struct radeon_device *rdev)
slope1 = (u16)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
slope2 = (u16)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
fan_table.temp_min = cpu_to_be16((50 + rdev->pm.dpm.fan.t_min) / 100);
fan_table.temp_med = cpu_to_be16((50 + rdev->pm.dpm.fan.t_med) / 100);
fan_table.temp_max = cpu_to_be16((50 + rdev->pm.dpm.fan.t_max) / 100);
fan_table.slope1 = cpu_to_be16(slope1);
fan_table.slope2 = cpu_to_be16(slope2);
@ -6012,29 +6021,35 @@ static int si_thermal_setup_fan_table(struct radeon_device *rdev)
static int si_fan_ctrl_start_smc_fan_control(struct radeon_device *rdev)
{
struct si_power_info *si_pi = si_get_pi(rdev);
PPSMC_Result ret;
ret = si_send_msg_to_smc(rdev, PPSMC_StartFanControl);
if (ret == PPSMC_Result_OK)
if (ret == PPSMC_Result_OK) {
si_pi->fan_is_controlled_by_smc = true;
return 0;
else
} else {
return -EINVAL;
}
}
static int si_fan_ctrl_stop_smc_fan_control(struct radeon_device *rdev)
{
struct si_power_info *si_pi = si_get_pi(rdev);
PPSMC_Result ret;
ret = si_send_msg_to_smc(rdev, PPSMC_StopFanControl);
if (ret == PPSMC_Result_OK)
if (ret == PPSMC_Result_OK) {
si_pi->fan_is_controlled_by_smc = false;
return 0;
else
} else {
return -EINVAL;
}
}
#if 0
static int si_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
u32 *speed)
int si_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
u32 *speed)
{
u32 duty, duty100;
u64 tmp64;
@ -6058,9 +6073,10 @@ static int si_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
return 0;
}
static int si_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
u32 speed)
int si_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
u32 speed)
{
struct si_power_info *si_pi = si_get_pi(rdev);
u32 tmp;
u32 duty, duty100;
u64 tmp64;
@ -6068,11 +6084,11 @@ static int si_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
if (rdev->pm.no_fan)
return -ENOENT;
if (speed > 100)
if (si_pi->fan_is_controlled_by_smc)
return -EINVAL;
if (rdev->pm.dpm.fan.ucode_fan_control)
si_fan_ctrl_stop_smc_fan_control(rdev);
if (speed > 100)
return -EINVAL;
duty100 = (RREG32(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT;
@ -6087,11 +6103,38 @@ static int si_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
tmp |= FDO_STATIC_DUTY(duty);
WREG32(CG_FDO_CTRL0, tmp);
si_fan_ctrl_set_static_mode(rdev, FDO_PWM_MODE_STATIC);
return 0;
}
void si_fan_ctrl_set_mode(struct radeon_device *rdev, u32 mode)
{
if (mode) {
/* stop auto-manage */
if (rdev->pm.dpm.fan.ucode_fan_control)
si_fan_ctrl_stop_smc_fan_control(rdev);
si_fan_ctrl_set_static_mode(rdev, mode);
} else {
/* restart auto-manage */
if (rdev->pm.dpm.fan.ucode_fan_control)
si_thermal_start_smc_fan_control(rdev);
else
si_fan_ctrl_set_default_mode(rdev);
}
}
u32 si_fan_ctrl_get_mode(struct radeon_device *rdev)
{
struct si_power_info *si_pi = si_get_pi(rdev);
u32 tmp;
if (si_pi->fan_is_controlled_by_smc)
return 0;
tmp = RREG32(CG_FDO_CTRL2) & FDO_PWM_MODE_MASK;
return (tmp >> FDO_PWM_MODE_SHIFT);
}
#if 0
static int si_fan_ctrl_get_fan_speed_rpm(struct radeon_device *rdev,
u32 *speed)
{
@ -6538,13 +6581,14 @@ void si_dpm_post_set_power_state(struct radeon_device *rdev)
ni_update_current_ps(rdev, new_ps);
}
#if 0
void si_dpm_reset_asic(struct radeon_device *rdev)
{
si_restrict_performance_levels_before_switch(rdev);
si_disable_ulv(rdev);
si_set_boot_state(rdev);
}
#endif
void si_dpm_display_configuration_changed(struct radeon_device *rdev)
{
@ -6912,7 +6956,6 @@ int si_dpm_init(struct radeon_device *rdev)
rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
si_pi->fan_ctrl_is_in_default_mode = true;
rdev->pm.dpm.fan.ucode_fan_control = false;
return 0;
}

View File

@ -202,6 +202,7 @@ struct si_power_info {
bool fan_ctrl_is_in_default_mode;
u32 t_min;
u32 fan_ctrl_default_mode;
bool fan_is_controlled_by_smc;
};
#define SISLANDS_INITIAL_STATE_ARB_INDEX 0

View File

@ -901,6 +901,16 @@
/* 0x6e98, 0x7a98, 0x10698, 0x11298, 0x11e98, 0x12a98 */
#define CRTC_STATUS_FRAME_COUNT 0x6e98
/* Audio clocks */
#define DCCG_AUDIO_DTO_SOURCE 0x05ac
# define DCCG_AUDIO_DTO0_SOURCE_SEL(x) ((x) << 0) /* crtc0 - crtc5 */
# define DCCG_AUDIO_DTO_SEL (1 << 4) /* 0=dto0 1=dto1 */
#define DCCG_AUDIO_DTO0_PHASE 0x05b0
#define DCCG_AUDIO_DTO0_MODULE 0x05b4
#define DCCG_AUDIO_DTO1_PHASE 0x05b8
#define DCCG_AUDIO_DTO1_MODULE 0x05bc
#define AFMT_AUDIO_SRC_CONTROL 0x713c
#define AFMT_AUDIO_SRC_SELECT(x) (((x) & 7) << 0)
/* AFMT_AUDIO_SRC_SELECT

View File

@ -1338,6 +1338,7 @@ void sumo_dpm_post_set_power_state(struct radeon_device *rdev)
sumo_update_current_ps(rdev, new_ps);
}
#if 0
void sumo_dpm_reset_asic(struct radeon_device *rdev)
{
sumo_program_bootup_state(rdev);
@ -1349,6 +1350,7 @@ void sumo_dpm_reset_asic(struct radeon_device *rdev)
sumo_set_forced_mode_enabled(rdev);
sumo_set_forced_mode_disabled(rdev);
}
#endif
void sumo_dpm_setup_asic(struct radeon_device *rdev)
{
@ -1537,6 +1539,7 @@ u32 sumo_convert_vid2_to_vid7(struct radeon_device *rdev,
return vid_mapping_table->entries[vid_mapping_table->num_entries - 1].vid_7bit;
}
#if 0
u32 sumo_convert_vid7_to_vid2(struct radeon_device *rdev,
struct sumo_vid_mapping_table *vid_mapping_table,
u32 vid_7bit)
@ -1550,6 +1553,7 @@ u32 sumo_convert_vid7_to_vid2(struct radeon_device *rdev,
return vid_mapping_table->entries[vid_mapping_table->num_entries - 1].vid_2bit;
}
#endif
static u16 sumo_convert_voltage_index_to_value(struct radeon_device *rdev,
u32 vid_2bit)

View File

@ -202,9 +202,6 @@ void sumo_construct_vid_mapping_table(struct radeon_device *rdev,
u32 sumo_convert_vid2_to_vid7(struct radeon_device *rdev,
struct sumo_vid_mapping_table *vid_mapping_table,
u32 vid_2bit);
u32 sumo_convert_vid7_to_vid2(struct radeon_device *rdev,
struct sumo_vid_mapping_table *vid_mapping_table,
u32 vid_7bit);
u32 sumo_get_sleep_divider_from_id(u32 id);
u32 sumo_get_sleep_divider_id_from_clock(struct radeon_device *rdev,
u32 sclk,

View File

@ -1269,6 +1269,7 @@ void trinity_dpm_setup_asic(struct radeon_device *rdev)
trinity_release_mutex(rdev);
}
#if 0
void trinity_dpm_reset_asic(struct radeon_device *rdev)
{
struct trinity_power_info *pi = trinity_get_pi(rdev);
@ -1284,6 +1285,7 @@ void trinity_dpm_reset_asic(struct radeon_device *rdev)
}
trinity_release_mutex(rdev);
}
#endif
static u16 trinity_convert_voltage_index_to_value(struct radeon_device *rdev,
u32 vid_2bit)