mirror of https://gitee.com/openkylin/linux.git
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:
commit
cc0cc1aa27
drivers/gpu/drm
Kconfig
radeon
Makefileatombios_encoders.cbtc_dpm.cci_dpm.cci_dpm.hci_smc.ccik.ccypress_dpm.cdce3_1_afmt.cdce6_afmt.cevergreen.cevergreen_cs.cevergreen_hdmi.cevergreen_reg.hevergreend.hkv_dpm.cni.cni_dpm.cr600.cr600_hdmi.cradeon.hradeon_asic.cradeon_asic.hradeon_audio.cradeon_audio.hradeon_connectors.cradeon_drv.cradeon_fb.cradeon_i2c.cradeon_mode.hradeon_object.cradeon_object.hradeon_pm.crs600.crs690.crv770.crv770_dpm.crv770_dpm.hsi.csi_dpm.csi_dpm.hsid.hsumo_dpm.csumo_dpm.htrinity_dpm.c
|
@ -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
|
||||
|
|
|
@ -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 += \
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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 @@ radeon_dvi_detect(struct drm_connector *connector, bool force)
|
|||
/* updated in get modes as well since we need to know if it's analog or digital */
|
||||
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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 @@ static ssize_t radeon_set_dpm_forced_performance_level(struct device *dev,
|
|||
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 = {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue