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

- DP MST support (disabled by default)
- non-ATOM aux support (DCE5+)
- output csc support for clamped RGB
- Lots of new queries for profiling, Gallium HUD, etc.
- Misc fixes

* 'drm-next-4.1' of git://people.freedesktop.org/~agd5f/linux: (40 commits)
  drm/radeon: add DisplayPort MST support (v2)
  drm/radeon: improve encoder picking functions (v2)
  drm/radeon: export max link rate calculation
  drm/radeon: add new atombios encoder/transmitter interfaces
  drm/radeon: add some MST registers
  radeon/fb: add wrapper functions around fb connector add/remove
  radeon/cik: add support for short HPD irqs
  radeon/si: add support for short HPD irqs
  radeon/evergreen: add support for short HPD irqs
  radeon: introduce a dp_work handler
  drm/dp_mst: add a function to retrieve vcpi slots
  drm/radeon: program auxch directly (v2)
  drm/radeon: fix doublescan modes (v2)
  drm/radeon: typo in parameter description
  drm/radeon: add support for read reg query from radeon info ioctl
  drm/radeon: add get_allowed_info_register for CIK
  drm/radeon: add get_allowed_info_register for SI
  drm/radeon: add get_allowed_info_register for cayman/TN
  drm/radeon: add get_allowed_info_register for EG/BTC
  drm/radeon: add get_allowed_info_register for r6xx/r7xx
  ...
This commit is contained in:
Dave Airlie 2015-03-23 09:15:02 +10:00
commit b3ede177c8
43 changed files with 2408 additions and 85 deletions

View File

@ -2319,6 +2319,19 @@ out:
}
EXPORT_SYMBOL(drm_dp_mst_allocate_vcpi);
int drm_dp_mst_get_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port)
{
int slots = 0;
port = drm_dp_get_validated_port_ref(mgr, port);
if (!port)
return slots;
slots = port->vcpi.num_slots;
drm_dp_put_port(port);
return slots;
}
EXPORT_SYMBOL(drm_dp_mst_get_vcpi_slots);
/**
* drm_dp_mst_reset_vcpi_slots() - Reset number of slots to 0 for VCPI
* @mgr: manager for this port

View File

@ -81,7 +81,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.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_sync.o radeon_audio.o
radeon_sync.o radeon_audio.o radeon_dp_auxch.o radeon_dp_mst.o
radeon-$(CONFIG_MMU_NOTIFIER) += radeon_mn.o

View File

@ -330,8 +330,10 @@ atombios_set_crtc_dtd_timing(struct drm_crtc *crtc,
misc |= ATOM_COMPOSITESYNC;
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
misc |= ATOM_INTERLACE;
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
misc |= ATOM_DOUBLE_CLOCK_MODE;
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
misc |= ATOM_H_REPLICATIONBY2 | ATOM_V_REPLICATIONBY2;
args.susModeMiscInfo.usAccess = cpu_to_le16(misc);
args.ucCRTC = radeon_crtc->crtc_id;
@ -374,8 +376,10 @@ static void atombios_crtc_set_timing(struct drm_crtc *crtc,
misc |= ATOM_COMPOSITESYNC;
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
misc |= ATOM_INTERLACE;
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
misc |= ATOM_DOUBLE_CLOCK_MODE;
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
misc |= ATOM_H_REPLICATIONBY2 | ATOM_V_REPLICATIONBY2;
args.susModeMiscInfo.usAccess = cpu_to_le16(misc);
args.ucCRTC = radeon_crtc->crtc_id;
@ -606,6 +610,13 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
}
}
if (radeon_encoder->is_mst_encoder) {
struct radeon_encoder_mst *mst_enc = radeon_encoder->enc_priv;
struct radeon_connector_atom_dig *dig_connector = mst_enc->connector->con_priv;
dp_clock = dig_connector->dp_clock;
}
/* use recommended ref_div for ss */
if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
if (radeon_crtc->ss_enabled) {
@ -952,7 +963,9 @@ static bool atombios_crtc_prepare_pll(struct drm_crtc *crtc, struct drm_display_
radeon_crtc->bpc = 8;
radeon_crtc->ss_enabled = false;
if ((radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) ||
if (radeon_encoder->is_mst_encoder) {
radeon_dp_mst_prepare_pll(crtc, mode);
} else if ((radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) ||
(radeon_encoder_get_dp_bridge_encoder_id(radeon_crtc->encoder) != ENCODER_OBJECT_ID_NONE)) {
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
struct drm_connector *connector =
@ -2069,6 +2082,12 @@ static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc,
radeon_crtc->connector = NULL;
return false;
}
if (radeon_crtc->encoder) {
struct radeon_encoder *radeon_encoder =
to_radeon_encoder(radeon_crtc->encoder);
radeon_crtc->output_csc = radeon_encoder->output_csc;
}
if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode))
return false;
if (!atombios_crtc_prepare_pll(crtc, adjusted_mode))

View File

@ -158,7 +158,7 @@ done:
#define HEADER_SIZE (BARE_ADDRESS_SIZE + 1)
static ssize_t
radeon_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
radeon_dp_aux_transfer_atom(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
{
struct radeon_i2c_chan *chan =
container_of(aux, struct radeon_i2c_chan, aux);
@ -226,11 +226,20 @@ radeon_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
void radeon_dp_aux_init(struct radeon_connector *radeon_connector)
{
struct drm_device *dev = radeon_connector->base.dev;
struct radeon_device *rdev = dev->dev_private;
int ret;
radeon_connector->ddc_bus->rec.hpd = radeon_connector->hpd.hpd;
radeon_connector->ddc_bus->aux.dev = radeon_connector->base.kdev;
radeon_connector->ddc_bus->aux.transfer = radeon_dp_aux_transfer;
if (ASIC_IS_DCE5(rdev)) {
if (radeon_auxch)
radeon_connector->ddc_bus->aux.transfer = radeon_dp_aux_transfer_native;
else
radeon_connector->ddc_bus->aux.transfer = radeon_dp_aux_transfer_atom;
} else {
radeon_connector->ddc_bus->aux.transfer = radeon_dp_aux_transfer_atom;
}
ret = drm_dp_aux_register(&radeon_connector->ddc_bus->aux);
if (!ret)
@ -301,8 +310,8 @@ static int dp_get_max_dp_pix_clock(int link_rate,
/***** radeon specific DP functions *****/
static int radeon_dp_get_max_link_rate(struct drm_connector *connector,
u8 dpcd[DP_DPCD_SIZE])
int radeon_dp_get_max_link_rate(struct drm_connector *connector,
u8 dpcd[DP_DPCD_SIZE])
{
int max_link_rate;

View File

@ -671,7 +671,15 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
struct drm_connector *connector;
struct radeon_connector *radeon_connector;
struct radeon_connector_atom_dig *dig_connector;
struct radeon_encoder_atom_dig *dig_enc;
if (radeon_encoder_is_digital(encoder)) {
dig_enc = radeon_encoder->enc_priv;
if (dig_enc->active_mst_links)
return ATOM_ENCODER_MODE_DP_MST;
}
if (radeon_encoder->is_mst_encoder || radeon_encoder->offset)
return ATOM_ENCODER_MODE_DP_MST;
/* dp bridges are always DP */
if (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE)
return ATOM_ENCODER_MODE_DP;
@ -823,7 +831,7 @@ union dig_encoder_control {
};
void
atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode)
atombios_dig_encoder_setup2(struct drm_encoder *encoder, int action, int panel_mode, int enc_override)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
@ -920,7 +928,10 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo
if (ENCODER_MODE_IS_DP(args.v3.ucEncoderMode) && (dp_clock == 270000))
args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ;
args.v3.acConfig.ucDigSel = dig->dig_encoder;
if (enc_override != -1)
args.v3.acConfig.ucDigSel = enc_override;
else
args.v3.acConfig.ucDigSel = dig->dig_encoder;
args.v3.ucBitPerColor = radeon_atom_get_bpc(encoder);
break;
case 4:
@ -948,7 +959,11 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo
else
args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_1_62GHZ;
}
args.v4.acConfig.ucDigSel = dig->dig_encoder;
if (enc_override != -1)
args.v4.acConfig.ucDigSel = enc_override;
else
args.v4.acConfig.ucDigSel = dig->dig_encoder;
args.v4.ucBitPerColor = radeon_atom_get_bpc(encoder);
if (hpd_id == RADEON_HPD_NONE)
args.v4.ucHPD_ID = 0;
@ -969,6 +984,12 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo
}
void
atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode)
{
atombios_dig_encoder_setup2(encoder, action, panel_mode, -1);
}
union dig_transmitter_control {
DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1;
DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2;
@ -978,7 +999,7 @@ union dig_transmitter_control {
};
void
atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set)
atombios_dig_transmitter_setup2(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set, int fe)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
@ -1328,7 +1349,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
args.v5.asConfig.ucHPDSel = 0;
else
args.v5.asConfig.ucHPDSel = hpd_id + 1;
args.v5.ucDigEncoderSel = 1 << dig_encoder;
args.v5.ucDigEncoderSel = (fe != -1) ? (1 << fe) : (1 << dig_encoder);
args.v5.ucDPLaneSet = lane_set;
break;
default:
@ -1344,6 +1365,12 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
}
void
atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set)
{
atombios_dig_transmitter_setup2(encoder, action, lane_num, lane_set, -1);
}
bool
atombios_set_edp_panel_power(struct drm_connector *connector, int action)
{
@ -1687,6 +1714,11 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode)
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF:
/* don't power off encoders with active MST links */
if (dig->active_mst_links)
return;
if (ASIC_IS_DCE4(rdev)) {
if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector)
atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0);
@ -1955,6 +1987,53 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder)
radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id);
}
void
atombios_set_mst_encoder_crtc_source(struct drm_encoder *encoder, int fe)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source);
uint8_t frev, crev;
union crtc_source_param args;
memset(&args, 0, sizeof(args));
if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
return;
if (frev != 1 && crev != 2)
DRM_ERROR("Unknown table for MST %d, %d\n", frev, crev);
args.v2.ucCRTC = radeon_crtc->crtc_id;
args.v2.ucEncodeMode = ATOM_ENCODER_MODE_DP_MST;
switch (fe) {
case 0:
args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID;
break;
case 1:
args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
break;
case 2:
args.v2.ucEncoderID = ASIC_INT_DIG3_ENCODER_ID;
break;
case 3:
args.v2.ucEncoderID = ASIC_INT_DIG4_ENCODER_ID;
break;
case 4:
args.v2.ucEncoderID = ASIC_INT_DIG5_ENCODER_ID;
break;
case 5:
args.v2.ucEncoderID = ASIC_INT_DIG6_ENCODER_ID;
break;
case 6:
args.v2.ucEncoderID = ASIC_INT_DIG7_ENCODER_ID;
break;
}
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
}
static void
atombios_apply_encoder_quirks(struct drm_encoder *encoder,
struct drm_display_mode *mode)
@ -2003,7 +2082,14 @@ atombios_apply_encoder_quirks(struct drm_encoder *encoder,
}
}
static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
void radeon_atom_release_dig_encoder(struct radeon_device *rdev, int enc_idx)
{
if (enc_idx < 0)
return;
rdev->mode_info.active_encoders &= ~(1 << enc_idx);
}
int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder, int fe_idx)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
@ -2012,71 +2098,79 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
struct drm_encoder *test_encoder;
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
uint32_t dig_enc_in_use = 0;
int enc_idx = -1;
if (fe_idx >= 0) {
enc_idx = fe_idx;
goto assigned;
}
if (ASIC_IS_DCE6(rdev)) {
/* DCE6 */
switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
if (dig->linkb)
return 1;
enc_idx = 1;
else
return 0;
enc_idx = 0;
break;
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
if (dig->linkb)
return 3;
enc_idx = 3;
else
return 2;
enc_idx = 2;
break;
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
if (dig->linkb)
return 5;
enc_idx = 5;
else
return 4;
enc_idx = 4;
break;
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
return 6;
enc_idx = 6;
break;
}
goto assigned;
} else if (ASIC_IS_DCE4(rdev)) {
/* DCE4/5 */
if (ASIC_IS_DCE41(rdev) && !ASIC_IS_DCE61(rdev)) {
/* ontario follows DCE4 */
if (rdev->family == CHIP_PALM) {
if (dig->linkb)
return 1;
enc_idx = 1;
else
return 0;
enc_idx = 0;
} else
/* llano follows DCE3.2 */
return radeon_crtc->crtc_id;
enc_idx = radeon_crtc->crtc_id;
} else {
switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
if (dig->linkb)
return 1;
enc_idx = 1;
else
return 0;
enc_idx = 0;
break;
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
if (dig->linkb)
return 3;
enc_idx = 3;
else
return 2;
enc_idx = 2;
break;
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
if (dig->linkb)
return 5;
enc_idx = 5;
else
return 4;
enc_idx = 4;
break;
}
}
goto assigned;
}
/* on DCE32 and encoder can driver any block so just crtc id */
if (ASIC_IS_DCE32(rdev)) {
return radeon_crtc->crtc_id;
enc_idx = radeon_crtc->crtc_id;
goto assigned;
}
/* on DCE3 - LVTMA can only be driven by DIGB */
@ -2104,6 +2198,17 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
if (!(dig_enc_in_use & 1))
return 0;
return 1;
assigned:
if (enc_idx == -1) {
DRM_ERROR("Got encoder index incorrect - returning 0\n");
return 0;
}
if (rdev->mode_info.active_encoders & (1 << enc_idx)) {
DRM_ERROR("chosen encoder in use %d\n", enc_idx);
}
rdev->mode_info.active_encoders |= (1 << enc_idx);
return enc_idx;
}
/* This only needs to be called once at startup */
@ -2362,7 +2467,9 @@ static void radeon_atom_encoder_prepare(struct drm_encoder *encoder)
ENCODER_OBJECT_ID_NONE)) {
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
if (dig) {
dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder);
if (dig->dig_encoder >= 0)
radeon_atom_release_dig_encoder(rdev, dig->dig_encoder);
dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder, -1);
if (radeon_encoder->active_device & ATOM_DEVICE_DFP_SUPPORT) {
if (rdev->family >= CHIP_R600)
dig->afmt = rdev->mode_info.afmt[dig->dig_encoder];
@ -2464,10 +2571,18 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder)
disable_done:
if (radeon_encoder_is_digital(encoder)) {
dig = radeon_encoder->enc_priv;
dig->dig_encoder = -1;
}
radeon_encoder->active_device = 0;
if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) {
if (rdev->asic->display.hdmi_enable)
radeon_hdmi_enable(rdev, encoder, false);
}
if (atombios_get_encoder_mode(encoder) != ATOM_ENCODER_MODE_DP_MST) {
dig = radeon_encoder->enc_priv;
radeon_atom_release_dig_encoder(rdev, dig->dig_encoder);
dig->dig_encoder = -1;
radeon_encoder->active_device = 0;
}
} else
radeon_encoder->active_device = 0;
}
/* these are handled by the primary encoders */

View File

@ -2751,13 +2751,54 @@ void btc_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
else /* current_index == 2 */
pl = &ps->high;
seq_printf(m, "uvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
if (rdev->family >= CHIP_CEDAR) {
seq_printf(m, "power level %d sclk: %u mclk: %u vddc: %u vddci: %u\n",
current_index, pl->sclk, pl->mclk, pl->vddc, pl->vddci);
} else {
seq_printf(m, "power level %d sclk: %u mclk: %u vddc: %u\n",
current_index, pl->sclk, pl->mclk, pl->vddc);
}
seq_printf(m, "power level %d sclk: %u mclk: %u vddc: %u vddci: %u\n",
current_index, pl->sclk, pl->mclk, pl->vddc, pl->vddci);
}
}
u32 btc_dpm_get_current_sclk(struct radeon_device *rdev)
{
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
struct radeon_ps *rps = &eg_pi->current_rps;
struct rv7xx_ps *ps = rv770_get_ps(rps);
struct rv7xx_pl *pl;
u32 current_index =
(RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >>
CURRENT_PROFILE_INDEX_SHIFT;
if (current_index > 2) {
return 0;
} else {
if (current_index == 0)
pl = &ps->low;
else if (current_index == 1)
pl = &ps->medium;
else /* current_index == 2 */
pl = &ps->high;
return pl->sclk;
}
}
u32 btc_dpm_get_current_mclk(struct radeon_device *rdev)
{
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
struct radeon_ps *rps = &eg_pi->current_rps;
struct rv7xx_ps *ps = rv770_get_ps(rps);
struct rv7xx_pl *pl;
u32 current_index =
(RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >>
CURRENT_PROFILE_INDEX_SHIFT;
if (current_index > 2) {
return 0;
} else {
if (current_index == 0)
pl = &ps->low;
else if (current_index == 1)
pl = &ps->medium;
else /* current_index == 2 */
pl = &ps->high;
return pl->mclk;
}
}

View File

@ -5922,6 +5922,20 @@ void ci_dpm_print_power_state(struct radeon_device *rdev,
r600_dpm_print_ps_status(rdev, rps);
}
u32 ci_dpm_get_current_sclk(struct radeon_device *rdev)
{
u32 sclk = ci_get_average_sclk_freq(rdev);
return sclk;
}
u32 ci_dpm_get_current_mclk(struct radeon_device *rdev)
{
u32 mclk = ci_get_average_mclk_freq(rdev);
return mclk;
}
u32 ci_dpm_get_sclk(struct radeon_device *rdev, bool low)
{
struct ci_power_info *pi = ci_get_pi(rdev);

View File

@ -141,6 +141,39 @@ static void cik_fini_cg(struct radeon_device *rdev);
static void cik_enable_gui_idle_interrupt(struct radeon_device *rdev,
bool enable);
/**
* cik_get_allowed_info_register - fetch the register for the info ioctl
*
* @rdev: radeon_device pointer
* @reg: register offset in bytes
* @val: register value
*
* Returns 0 for success or -EINVAL for an invalid register
*
*/
int cik_get_allowed_info_register(struct radeon_device *rdev,
u32 reg, u32 *val)
{
switch (reg) {
case GRBM_STATUS:
case GRBM_STATUS2:
case GRBM_STATUS_SE0:
case GRBM_STATUS_SE1:
case GRBM_STATUS_SE2:
case GRBM_STATUS_SE3:
case SRBM_STATUS:
case SRBM_STATUS2:
case (SDMA0_STATUS_REG + SDMA0_REGISTER_OFFSET):
case (SDMA0_STATUS_REG + SDMA1_REGISTER_OFFSET):
case UVD_STATUS:
/* TODO VCE */
*val = RREG32(reg);
return 0;
default:
return -EINVAL;
}
}
/* get temperature in millidegrees */
int ci_get_temp(struct radeon_device *rdev)
{
@ -7394,12 +7427,12 @@ int cik_irq_set(struct radeon_device *rdev)
(CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
cp_int_cntl |= PRIV_INSTR_INT_ENABLE | PRIV_REG_INT_ENABLE;
hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN;
hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN;
hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~DC_HPDx_INT_EN;
hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~DC_HPDx_INT_EN;
hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN;
hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN;
hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
dma_cntl = RREG32(SDMA0_CNTL + SDMA0_REGISTER_OFFSET) & ~TRAP_ENABLE;
dma_cntl1 = RREG32(SDMA0_CNTL + SDMA1_REGISTER_OFFSET) & ~TRAP_ENABLE;
@ -7486,27 +7519,27 @@ int cik_irq_set(struct radeon_device *rdev)
}
if (rdev->irq.hpd[0]) {
DRM_DEBUG("cik_irq_set: hpd 1\n");
hpd1 |= DC_HPDx_INT_EN;
hpd1 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
}
if (rdev->irq.hpd[1]) {
DRM_DEBUG("cik_irq_set: hpd 2\n");
hpd2 |= DC_HPDx_INT_EN;
hpd2 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
}
if (rdev->irq.hpd[2]) {
DRM_DEBUG("cik_irq_set: hpd 3\n");
hpd3 |= DC_HPDx_INT_EN;
hpd3 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
}
if (rdev->irq.hpd[3]) {
DRM_DEBUG("cik_irq_set: hpd 4\n");
hpd4 |= DC_HPDx_INT_EN;
hpd4 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
}
if (rdev->irq.hpd[4]) {
DRM_DEBUG("cik_irq_set: hpd 5\n");
hpd5 |= DC_HPDx_INT_EN;
hpd5 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
}
if (rdev->irq.hpd[5]) {
DRM_DEBUG("cik_irq_set: hpd 6\n");
hpd6 |= DC_HPDx_INT_EN;
hpd6 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
}
WREG32(CP_INT_CNTL_RING0, cp_int_cntl);
@ -7678,6 +7711,36 @@ static inline void cik_irq_ack(struct radeon_device *rdev)
tmp |= DC_HPDx_INT_ACK;
WREG32(DC_HPD6_INT_CONTROL, tmp);
}
if (rdev->irq.stat_regs.cik.disp_int & DC_HPD1_RX_INTERRUPT) {
tmp = RREG32(DC_HPD1_INT_CONTROL);
tmp |= DC_HPDx_RX_INT_ACK;
WREG32(DC_HPD1_INT_CONTROL, tmp);
}
if (rdev->irq.stat_regs.cik.disp_int_cont & DC_HPD2_RX_INTERRUPT) {
tmp = RREG32(DC_HPD2_INT_CONTROL);
tmp |= DC_HPDx_RX_INT_ACK;
WREG32(DC_HPD2_INT_CONTROL, tmp);
}
if (rdev->irq.stat_regs.cik.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) {
tmp = RREG32(DC_HPD3_INT_CONTROL);
tmp |= DC_HPDx_RX_INT_ACK;
WREG32(DC_HPD3_INT_CONTROL, tmp);
}
if (rdev->irq.stat_regs.cik.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) {
tmp = RREG32(DC_HPD4_INT_CONTROL);
tmp |= DC_HPDx_RX_INT_ACK;
WREG32(DC_HPD4_INT_CONTROL, tmp);
}
if (rdev->irq.stat_regs.cik.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) {
tmp = RREG32(DC_HPD5_INT_CONTROL);
tmp |= DC_HPDx_RX_INT_ACK;
WREG32(DC_HPD5_INT_CONTROL, tmp);
}
if (rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
tmp = RREG32(DC_HPD5_INT_CONTROL);
tmp |= DC_HPDx_RX_INT_ACK;
WREG32(DC_HPD6_INT_CONTROL, tmp);
}
}
/**
@ -7803,6 +7866,7 @@ int cik_irq_process(struct radeon_device *rdev)
u8 me_id, pipe_id, queue_id;
u32 ring_index;
bool queue_hotplug = false;
bool queue_dp = false;
bool queue_reset = false;
u32 addr, status, mc_client;
bool queue_thermal = false;
@ -8048,6 +8112,48 @@ restart_ih:
DRM_DEBUG("IH: HPD6\n");
}
break;
case 6:
if (rdev->irq.stat_regs.cik.disp_int & DC_HPD1_RX_INTERRUPT) {
rdev->irq.stat_regs.cik.disp_int &= ~DC_HPD1_RX_INTERRUPT;
queue_dp = true;
DRM_DEBUG("IH: HPD_RX 1\n");
}
break;
case 7:
if (rdev->irq.stat_regs.cik.disp_int_cont & DC_HPD2_RX_INTERRUPT) {
rdev->irq.stat_regs.cik.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT;
queue_dp = true;
DRM_DEBUG("IH: HPD_RX 2\n");
}
break;
case 8:
if (rdev->irq.stat_regs.cik.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) {
rdev->irq.stat_regs.cik.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT;
queue_dp = true;
DRM_DEBUG("IH: HPD_RX 3\n");
}
break;
case 9:
if (rdev->irq.stat_regs.cik.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) {
rdev->irq.stat_regs.cik.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT;
queue_dp = true;
DRM_DEBUG("IH: HPD_RX 4\n");
}
break;
case 10:
if (rdev->irq.stat_regs.cik.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) {
rdev->irq.stat_regs.cik.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT;
queue_dp = true;
DRM_DEBUG("IH: HPD_RX 5\n");
}
break;
case 11:
if (rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
rdev->irq.stat_regs.cik.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT;
queue_dp = true;
DRM_DEBUG("IH: HPD_RX 6\n");
}
break;
default:
DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
break;
@ -8256,6 +8362,8 @@ restart_ih:
rptr &= rdev->ih.ptr_mask;
WREG32(IH_RB_RPTR, rptr);
}
if (queue_dp)
schedule_work(&rdev->dp_work);
if (queue_hotplug)
schedule_work(&rdev->hotplug_work);
if (queue_reset) {

View File

@ -2088,6 +2088,8 @@
# define CLK_OD(x) ((x) << 6)
# define CLK_OD_MASK (0x1f << 6)
#define UVD_STATUS 0xf6bc
/* UVD clocks */
#define CG_DCLK_CNTL 0xC050009C

View File

@ -1006,6 +1006,34 @@ static void evergreen_init_golden_registers(struct radeon_device *rdev)
}
}
/**
* evergreen_get_allowed_info_register - fetch the register for the info ioctl
*
* @rdev: radeon_device pointer
* @reg: register offset in bytes
* @val: register value
*
* Returns 0 for success or -EINVAL for an invalid register
*
*/
int evergreen_get_allowed_info_register(struct radeon_device *rdev,
u32 reg, u32 *val)
{
switch (reg) {
case GRBM_STATUS:
case GRBM_STATUS_SE0:
case GRBM_STATUS_SE1:
case SRBM_STATUS:
case SRBM_STATUS2:
case DMA_STATUS_REG:
case UVD_STATUS:
*val = RREG32(reg);
return 0;
default:
return -EINVAL;
}
}
void evergreen_tiling_fields(unsigned tiling_flags, unsigned *bankw,
unsigned *bankh, unsigned *mtaspect,
unsigned *tile_split)
@ -4392,12 +4420,12 @@ int evergreen_irq_set(struct radeon_device *rdev)
return 0;
}
hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN;
hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN;
hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~DC_HPDx_INT_EN;
hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~DC_HPDx_INT_EN;
hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN;
hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN;
hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
if (rdev->family == CHIP_ARUBA)
thermal_int = RREG32(TN_CG_THERMAL_INT_CTRL) &
~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW);
@ -4486,27 +4514,27 @@ int evergreen_irq_set(struct radeon_device *rdev)
}
if (rdev->irq.hpd[0]) {
DRM_DEBUG("evergreen_irq_set: hpd 1\n");
hpd1 |= DC_HPDx_INT_EN;
hpd1 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
}
if (rdev->irq.hpd[1]) {
DRM_DEBUG("evergreen_irq_set: hpd 2\n");
hpd2 |= DC_HPDx_INT_EN;
hpd2 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
}
if (rdev->irq.hpd[2]) {
DRM_DEBUG("evergreen_irq_set: hpd 3\n");
hpd3 |= DC_HPDx_INT_EN;
hpd3 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
}
if (rdev->irq.hpd[3]) {
DRM_DEBUG("evergreen_irq_set: hpd 4\n");
hpd4 |= DC_HPDx_INT_EN;
hpd4 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
}
if (rdev->irq.hpd[4]) {
DRM_DEBUG("evergreen_irq_set: hpd 5\n");
hpd5 |= DC_HPDx_INT_EN;
hpd5 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
}
if (rdev->irq.hpd[5]) {
DRM_DEBUG("evergreen_irq_set: hpd 6\n");
hpd6 |= DC_HPDx_INT_EN;
hpd6 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
}
if (rdev->irq.afmt[0]) {
DRM_DEBUG("evergreen_irq_set: hdmi 0\n");
@ -4700,6 +4728,38 @@ static void evergreen_irq_ack(struct radeon_device *rdev)
tmp |= DC_HPDx_INT_ACK;
WREG32(DC_HPD6_INT_CONTROL, tmp);
}
if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT) {
tmp = RREG32(DC_HPD1_INT_CONTROL);
tmp |= DC_HPDx_RX_INT_ACK;
WREG32(DC_HPD1_INT_CONTROL, tmp);
}
if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT) {
tmp = RREG32(DC_HPD2_INT_CONTROL);
tmp |= DC_HPDx_RX_INT_ACK;
WREG32(DC_HPD2_INT_CONTROL, tmp);
}
if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) {
tmp = RREG32(DC_HPD3_INT_CONTROL);
tmp |= DC_HPDx_RX_INT_ACK;
WREG32(DC_HPD3_INT_CONTROL, tmp);
}
if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) {
tmp = RREG32(DC_HPD4_INT_CONTROL);
tmp |= DC_HPDx_RX_INT_ACK;
WREG32(DC_HPD4_INT_CONTROL, tmp);
}
if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) {
tmp = RREG32(DC_HPD5_INT_CONTROL);
tmp |= DC_HPDx_RX_INT_ACK;
WREG32(DC_HPD5_INT_CONTROL, tmp);
}
if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
tmp = RREG32(DC_HPD5_INT_CONTROL);
tmp |= DC_HPDx_RX_INT_ACK;
WREG32(DC_HPD6_INT_CONTROL, tmp);
}
if (rdev->irq.stat_regs.evergreen.afmt_status1 & AFMT_AZ_FORMAT_WTRIG) {
tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET);
tmp |= AFMT_AZ_FORMAT_WTRIG_ACK;
@ -4780,6 +4840,7 @@ int evergreen_irq_process(struct radeon_device *rdev)
u32 ring_index;
bool queue_hotplug = false;
bool queue_hdmi = false;
bool queue_dp = false;
bool queue_thermal = false;
u32 status, addr;
@ -5019,6 +5080,48 @@ restart_ih:
DRM_DEBUG("IH: HPD6\n");
}
break;
case 6:
if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT) {
rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_RX_INTERRUPT;
queue_dp = true;
DRM_DEBUG("IH: HPD_RX 1\n");
}
break;
case 7:
if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT) {
rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT;
queue_dp = true;
DRM_DEBUG("IH: HPD_RX 2\n");
}
break;
case 8:
if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) {
rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT;
queue_dp = true;
DRM_DEBUG("IH: HPD_RX 3\n");
}
break;
case 9:
if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) {
rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT;
queue_dp = true;
DRM_DEBUG("IH: HPD_RX 4\n");
}
break;
case 10:
if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) {
rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT;
queue_dp = true;
DRM_DEBUG("IH: HPD_RX 5\n");
}
break;
case 11:
if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT;
queue_dp = true;
DRM_DEBUG("IH: HPD_RX 6\n");
}
break;
default:
DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
break;
@ -5151,6 +5254,8 @@ restart_ih:
rptr &= rdev->ih.ptr_mask;
WREG32(IH_RB_RPTR, rptr);
}
if (queue_dp)
schedule_work(&rdev->dp_work);
if (queue_hotplug)
schedule_work(&rdev->hotplug_work);
if (queue_hdmi)

View File

@ -1520,6 +1520,7 @@
#define UVD_UDEC_DBW_ADDR_CONFIG 0xef54
#define UVD_RBC_RB_RPTR 0xf690
#define UVD_RBC_RB_WPTR 0xf694
#define UVD_STATUS 0xf6bc
/*
* PM4

View File

@ -2820,6 +2820,29 @@ void kv_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
}
}
u32 kv_dpm_get_current_sclk(struct radeon_device *rdev)
{
struct kv_power_info *pi = kv_get_pi(rdev);
u32 current_index =
(RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_SCLK_INDEX_MASK) >>
CURR_SCLK_INDEX_SHIFT;
u32 sclk;
if (current_index >= SMU__NUM_SCLK_DPM_STATE) {
return 0;
} else {
sclk = be32_to_cpu(pi->graphics_level[current_index].SclkFrequency);
return sclk;
}
}
u32 kv_dpm_get_current_mclk(struct radeon_device *rdev)
{
struct kv_power_info *pi = kv_get_pi(rdev);
return pi->sys_info.bootup_uma_clk;
}
void kv_dpm_print_power_state(struct radeon_device *rdev,
struct radeon_ps *rps)
{

View File

@ -828,6 +828,35 @@ out:
return err;
}
/**
* cayman_get_allowed_info_register - fetch the register for the info ioctl
*
* @rdev: radeon_device pointer
* @reg: register offset in bytes
* @val: register value
*
* Returns 0 for success or -EINVAL for an invalid register
*
*/
int cayman_get_allowed_info_register(struct radeon_device *rdev,
u32 reg, u32 *val)
{
switch (reg) {
case GRBM_STATUS:
case GRBM_STATUS_SE0:
case GRBM_STATUS_SE1:
case SRBM_STATUS:
case SRBM_STATUS2:
case (DMA_STATUS_REG + DMA0_REGISTER_OFFSET):
case (DMA_STATUS_REG + DMA1_REGISTER_OFFSET):
case UVD_STATUS:
*val = RREG32(reg);
return 0;
default:
return -EINVAL;
}
}
int tn_get_temp(struct radeon_device *rdev)
{
u32 temp = RREG32_SMC(TN_CURRENT_GNB_TEMP) & 0x7ff;

View File

@ -4319,6 +4319,42 @@ void ni_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
}
}
u32 ni_dpm_get_current_sclk(struct radeon_device *rdev)
{
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
struct radeon_ps *rps = &eg_pi->current_rps;
struct ni_ps *ps = ni_get_ps(rps);
struct rv7xx_pl *pl;
u32 current_index =
(RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_INDEX_MASK) >>
CURRENT_STATE_INDEX_SHIFT;
if (current_index >= ps->performance_level_count) {
return 0;
} else {
pl = &ps->performance_levels[current_index];
return pl->sclk;
}
}
u32 ni_dpm_get_current_mclk(struct radeon_device *rdev)
{
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
struct radeon_ps *rps = &eg_pi->current_rps;
struct ni_ps *ps = ni_get_ps(rps);
struct rv7xx_pl *pl;
u32 current_index =
(RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_INDEX_MASK) >>
CURRENT_STATE_INDEX_SHIFT;
if (current_index >= ps->performance_level_count) {
return 0;
} else {
pl = &ps->performance_levels[current_index];
return pl->mclk;
}
}
u32 ni_dpm_get_sclk(struct radeon_device *rdev, bool low)
{
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);

View File

@ -83,4 +83,48 @@
# define NI_REGAMMA_PROG_B 4
# define NI_OVL_REGAMMA_MODE(x) (((x) & 0x7) << 4)
#define NI_DP_MSE_LINK_TIMING 0x73a0
# define NI_DP_MSE_LINK_FRAME (((x) & 0x3ff) << 0)
# define NI_DP_MSE_LINK_LINE (((x) & 0x3) << 16)
#define NI_DP_MSE_MISC_CNTL 0x736c
# define NI_DP_MSE_BLANK_CODE (((x) & 0x1) << 0)
# define NI_DP_MSE_TIMESTAMP_MODE (((x) & 0x1) << 4)
# define NI_DP_MSE_ZERO_ENCODER (((x) & 0x1) << 8)
#define NI_DP_MSE_RATE_CNTL 0x7384
# define NI_DP_MSE_RATE_Y(x) (((x) & 0x3ffffff) << 0)
# define NI_DP_MSE_RATE_X(x) (((x) & 0x3f) << 26)
#define NI_DP_MSE_RATE_UPDATE 0x738c
#define NI_DP_MSE_SAT0 0x7390
# define NI_DP_MSE_SAT_SRC0(x) (((x) & 0x7) << 0)
# define NI_DP_MSE_SAT_SLOT_COUNT0(x) (((x) & 0x3f) << 8)
# define NI_DP_MSE_SAT_SRC1(x) (((x) & 0x7) << 16)
# define NI_DP_MSE_SAT_SLOT_COUNT1(x) (((x) & 0x3f) << 24)
#define NI_DP_MSE_SAT1 0x7394
#define NI_DP_MSE_SAT2 0x7398
#define NI_DP_MSE_SAT_UPDATE 0x739c
#define NI_DIG_BE_CNTL 0x7140
# define NI_DIG_FE_SOURCE_SELECT(x) (((x) & 0x7f) << 8)
# define NI_DIG_FE_DIG_MODE(x) (((x) & 0x7) << 16)
# define NI_DIG_MODE_DP_SST 0
# define NI_DIG_MODE_LVDS 1
# define NI_DIG_MODE_TMDS_DVI 2
# define NI_DIG_MODE_TMDS_HDMI 3
# define NI_DIG_MODE_DP_MST 5
# define NI_DIG_HPD_SELECT(x) (((x) & 0x7) << 28)
#define NI_DIG_FE_CNTL 0x7000
# define NI_DIG_SOURCE_SELECT(x) (((x) & 0x3) << 0)
# define NI_DIG_STEREOSYNC_SELECT(x) (((x) & 0x3) << 4)
# define NI_DIG_STEREOSYNC_GATE_EN(x) (((x) & 0x1) << 8)
# define NI_DIG_DUAL_LINK_ENABLE(x) (((x) & 0x1) << 16)
# define NI_DIG_SWAP(x) (((x) & 0x1) << 18)
# define NI_DIG_SYMCLK_FE_ON (0x1 << 24)
#endif

View File

@ -816,6 +816,52 @@
#define MC_PMG_CMD_MRS2 0x2b5c
#define MC_SEQ_PMG_CMD_MRS2_LP 0x2b60
#define AUX_CONTROL 0x6200
#define AUX_EN (1 << 0)
#define AUX_LS_READ_EN (1 << 8)
#define AUX_LS_UPDATE_DISABLE(x) (((x) & 0x1) << 12)
#define AUX_HPD_DISCON(x) (((x) & 0x1) << 16)
#define AUX_DET_EN (1 << 18)
#define AUX_HPD_SEL(x) (((x) & 0x7) << 20)
#define AUX_IMPCAL_REQ_EN (1 << 24)
#define AUX_TEST_MODE (1 << 28)
#define AUX_DEGLITCH_EN (1 << 29)
#define AUX_SW_CONTROL 0x6204
#define AUX_SW_GO (1 << 0)
#define AUX_LS_READ_TRIG (1 << 2)
#define AUX_SW_START_DELAY(x) (((x) & 0xf) << 4)
#define AUX_SW_WR_BYTES(x) (((x) & 0x1f) << 16)
#define AUX_SW_INTERRUPT_CONTROL 0x620c
#define AUX_SW_DONE_INT (1 << 0)
#define AUX_SW_DONE_ACK (1 << 1)
#define AUX_SW_DONE_MASK (1 << 2)
#define AUX_SW_LS_DONE_INT (1 << 4)
#define AUX_SW_LS_DONE_MASK (1 << 6)
#define AUX_SW_STATUS 0x6210
#define AUX_SW_DONE (1 << 0)
#define AUX_SW_REQ (1 << 1)
#define AUX_SW_RX_TIMEOUT_STATE(x) (((x) & 0x7) << 4)
#define AUX_SW_RX_TIMEOUT (1 << 7)
#define AUX_SW_RX_OVERFLOW (1 << 8)
#define AUX_SW_RX_HPD_DISCON (1 << 9)
#define AUX_SW_RX_PARTIAL_BYTE (1 << 10)
#define AUX_SW_NON_AUX_MODE (1 << 11)
#define AUX_SW_RX_MIN_COUNT_VIOL (1 << 12)
#define AUX_SW_RX_INVALID_STOP (1 << 14)
#define AUX_SW_RX_SYNC_INVALID_L (1 << 17)
#define AUX_SW_RX_SYNC_INVALID_H (1 << 18)
#define AUX_SW_RX_INVALID_START (1 << 19)
#define AUX_SW_RX_RECV_NO_DET (1 << 20)
#define AUX_SW_RX_RECV_INVALID_H (1 << 22)
#define AUX_SW_RX_RECV_INVALID_V (1 << 23)
#define AUX_SW_DATA 0x6218
#define AUX_SW_DATA_RW (1 << 0)
#define AUX_SW_DATA_MASK(x) (((x) & 0xff) << 8)
#define AUX_SW_DATA_INDEX(x) (((x) & 0x1f) << 16)
#define AUX_SW_AUTOINCREMENT_DISABLE (1 << 31)
#define LB_SYNC_RESET_SEL 0x6b28
#define LB_SYNC_RESET_SEL_MASK (3 << 0)
#define LB_SYNC_RESET_SEL_SHIFT 0
@ -1086,6 +1132,7 @@
#define UVD_UDEC_DBW_ADDR_CONFIG 0xEF54
#define UVD_RBC_RB_RPTR 0xF690
#define UVD_RBC_RB_WPTR 0xF694
#define UVD_STATUS 0xf6bc
/*
* PM4

View File

@ -108,6 +108,32 @@ static void r600_pcie_gen2_enable(struct radeon_device *rdev);
extern int evergreen_rlc_resume(struct radeon_device *rdev);
extern void rv770_set_clk_bypass_mode(struct radeon_device *rdev);
/**
* r600_get_allowed_info_register - fetch the register for the info ioctl
*
* @rdev: radeon_device pointer
* @reg: register offset in bytes
* @val: register value
*
* Returns 0 for success or -EINVAL for an invalid register
*
*/
int r600_get_allowed_info_register(struct radeon_device *rdev,
u32 reg, u32 *val)
{
switch (reg) {
case GRBM_STATUS:
case GRBM_STATUS2:
case R_000E50_SRBM_STATUS:
case DMA_STATUS_REG:
case UVD_STATUS:
*val = RREG32(reg);
return 0;
default:
return -EINVAL;
}
}
/**
* r600_get_xclk - get the xclk
*

View File

@ -111,6 +111,8 @@ extern int radeon_deep_color;
extern int radeon_use_pflipirq;
extern int radeon_bapm;
extern int radeon_backlight;
extern int radeon_auxch;
extern int radeon_mst;
/*
* Copy from radeon_drv.h so we don't have to include both and have conflicting
@ -1856,6 +1858,8 @@ struct radeon_asic {
u32 (*get_xclk)(struct radeon_device *rdev);
/* get the gpu clock counter */
uint64_t (*get_gpu_clock_counter)(struct radeon_device *rdev);
/* get register for info ioctl */
int (*get_allowed_info_register)(struct radeon_device *rdev, u32 reg, u32 *val);
/* gart */
struct {
void (*tlb_flush)(struct radeon_device *rdev);
@ -1984,6 +1988,8 @@ struct radeon_asic {
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);
u32 (*get_current_sclk)(struct radeon_device *rdev);
u32 (*get_current_mclk)(struct radeon_device *rdev);
} dpm;
/* pageflipping */
struct {
@ -2407,6 +2413,7 @@ struct radeon_device {
struct radeon_rlc rlc;
struct radeon_mec mec;
struct work_struct hotplug_work;
struct work_struct dp_work;
struct work_struct audio_work;
int num_crtc; /* number of crtcs */
struct mutex dc_hw_i2c_mutex; /* display controller hw i2c mutex */
@ -2931,6 +2938,7 @@ static inline void radeon_ring_write(struct radeon_ring *ring, uint32_t v)
#define radeon_mc_wait_for_idle(rdev) (rdev)->asic->mc_wait_for_idle((rdev))
#define radeon_get_xclk(rdev) (rdev)->asic->get_xclk((rdev))
#define radeon_get_gpu_clock_counter(rdev) (rdev)->asic->get_gpu_clock_counter((rdev))
#define radeon_get_allowed_info_register(rdev, r, v) (rdev)->asic->get_allowed_info_register((rdev), (r), (v))
#define radeon_dpm_init(rdev) rdev->asic->dpm.init((rdev))
#define radeon_dpm_setup_asic(rdev) rdev->asic->dpm.setup_asic((rdev))
#define radeon_dpm_enable(rdev) rdev->asic->dpm.enable((rdev))
@ -2949,6 +2957,8 @@ static inline void radeon_ring_write(struct radeon_ring *ring, uint32_t v)
#define radeon_dpm_vblank_too_short(rdev) rdev->asic->dpm.vblank_too_short((rdev))
#define radeon_dpm_powergate_uvd(rdev, g) rdev->asic->dpm.powergate_uvd((rdev), (g))
#define radeon_dpm_enable_bapm(rdev, e) rdev->asic->dpm.enable_bapm((rdev), (e))
#define radeon_dpm_get_current_sclk(rdev) rdev->asic->dpm.get_current_sclk((rdev))
#define radeon_dpm_get_current_mclk(rdev) rdev->asic->dpm.get_current_mclk((rdev))
/* Common functions */
/* AGP */

View File

@ -136,6 +136,11 @@ static void radeon_register_accessor_init(struct radeon_device *rdev)
}
}
static int radeon_invalid_get_allowed_info_register(struct radeon_device *rdev,
u32 reg, u32 *val)
{
return -EINVAL;
}
/* helper to disable agp */
/**
@ -199,6 +204,7 @@ static struct radeon_asic r100_asic = {
.mmio_hdp_flush = NULL,
.gui_idle = &r100_gui_idle,
.mc_wait_for_idle = &r100_mc_wait_for_idle,
.get_allowed_info_register = radeon_invalid_get_allowed_info_register,
.gart = {
.tlb_flush = &r100_pci_gart_tlb_flush,
.get_page_entry = &r100_pci_gart_get_page_entry,
@ -266,6 +272,7 @@ static struct radeon_asic r200_asic = {
.mmio_hdp_flush = NULL,
.gui_idle = &r100_gui_idle,
.mc_wait_for_idle = &r100_mc_wait_for_idle,
.get_allowed_info_register = radeon_invalid_get_allowed_info_register,
.gart = {
.tlb_flush = &r100_pci_gart_tlb_flush,
.get_page_entry = &r100_pci_gart_get_page_entry,
@ -361,6 +368,7 @@ static struct radeon_asic r300_asic = {
.mmio_hdp_flush = NULL,
.gui_idle = &r100_gui_idle,
.mc_wait_for_idle = &r300_mc_wait_for_idle,
.get_allowed_info_register = radeon_invalid_get_allowed_info_register,
.gart = {
.tlb_flush = &r100_pci_gart_tlb_flush,
.get_page_entry = &r100_pci_gart_get_page_entry,
@ -428,6 +436,7 @@ static struct radeon_asic r300_asic_pcie = {
.mmio_hdp_flush = NULL,
.gui_idle = &r100_gui_idle,
.mc_wait_for_idle = &r300_mc_wait_for_idle,
.get_allowed_info_register = radeon_invalid_get_allowed_info_register,
.gart = {
.tlb_flush = &rv370_pcie_gart_tlb_flush,
.get_page_entry = &rv370_pcie_gart_get_page_entry,
@ -495,6 +504,7 @@ static struct radeon_asic r420_asic = {
.mmio_hdp_flush = NULL,
.gui_idle = &r100_gui_idle,
.mc_wait_for_idle = &r300_mc_wait_for_idle,
.get_allowed_info_register = radeon_invalid_get_allowed_info_register,
.gart = {
.tlb_flush = &rv370_pcie_gart_tlb_flush,
.get_page_entry = &rv370_pcie_gart_get_page_entry,
@ -562,6 +572,7 @@ static struct radeon_asic rs400_asic = {
.mmio_hdp_flush = NULL,
.gui_idle = &r100_gui_idle,
.mc_wait_for_idle = &rs400_mc_wait_for_idle,
.get_allowed_info_register = radeon_invalid_get_allowed_info_register,
.gart = {
.tlb_flush = &rs400_gart_tlb_flush,
.get_page_entry = &rs400_gart_get_page_entry,
@ -629,6 +640,7 @@ static struct radeon_asic rs600_asic = {
.mmio_hdp_flush = NULL,
.gui_idle = &r100_gui_idle,
.mc_wait_for_idle = &rs600_mc_wait_for_idle,
.get_allowed_info_register = radeon_invalid_get_allowed_info_register,
.gart = {
.tlb_flush = &rs600_gart_tlb_flush,
.get_page_entry = &rs600_gart_get_page_entry,
@ -696,6 +708,7 @@ static struct radeon_asic rs690_asic = {
.mmio_hdp_flush = NULL,
.gui_idle = &r100_gui_idle,
.mc_wait_for_idle = &rs690_mc_wait_for_idle,
.get_allowed_info_register = radeon_invalid_get_allowed_info_register,
.gart = {
.tlb_flush = &rs400_gart_tlb_flush,
.get_page_entry = &rs400_gart_get_page_entry,
@ -763,6 +776,7 @@ static struct radeon_asic rv515_asic = {
.mmio_hdp_flush = NULL,
.gui_idle = &r100_gui_idle,
.mc_wait_for_idle = &rv515_mc_wait_for_idle,
.get_allowed_info_register = radeon_invalid_get_allowed_info_register,
.gart = {
.tlb_flush = &rv370_pcie_gart_tlb_flush,
.get_page_entry = &rv370_pcie_gart_get_page_entry,
@ -830,6 +844,7 @@ static struct radeon_asic r520_asic = {
.mmio_hdp_flush = NULL,
.gui_idle = &r100_gui_idle,
.mc_wait_for_idle = &r520_mc_wait_for_idle,
.get_allowed_info_register = radeon_invalid_get_allowed_info_register,
.gart = {
.tlb_flush = &rv370_pcie_gart_tlb_flush,
.get_page_entry = &rv370_pcie_gart_get_page_entry,
@ -925,6 +940,7 @@ static struct radeon_asic r600_asic = {
.mc_wait_for_idle = &r600_mc_wait_for_idle,
.get_xclk = &r600_get_xclk,
.get_gpu_clock_counter = &r600_get_gpu_clock_counter,
.get_allowed_info_register = r600_get_allowed_info_register,
.gart = {
.tlb_flush = &r600_pcie_gart_tlb_flush,
.get_page_entry = &rs600_gart_get_page_entry,
@ -1009,6 +1025,7 @@ static struct radeon_asic rv6xx_asic = {
.mc_wait_for_idle = &r600_mc_wait_for_idle,
.get_xclk = &r600_get_xclk,
.get_gpu_clock_counter = &r600_get_gpu_clock_counter,
.get_allowed_info_register = r600_get_allowed_info_register,
.gart = {
.tlb_flush = &r600_pcie_gart_tlb_flush,
.get_page_entry = &rs600_gart_get_page_entry,
@ -1080,6 +1097,8 @@ static struct radeon_asic rv6xx_asic = {
.print_power_state = &rv6xx_dpm_print_power_state,
.debugfs_print_current_performance_level = &rv6xx_dpm_debugfs_print_current_performance_level,
.force_performance_level = &rv6xx_dpm_force_performance_level,
.get_current_sclk = &rv6xx_dpm_get_current_sclk,
.get_current_mclk = &rv6xx_dpm_get_current_mclk,
},
.pflip = {
.page_flip = &rs600_page_flip,
@ -1099,6 +1118,7 @@ static struct radeon_asic rs780_asic = {
.mc_wait_for_idle = &r600_mc_wait_for_idle,
.get_xclk = &r600_get_xclk,
.get_gpu_clock_counter = &r600_get_gpu_clock_counter,
.get_allowed_info_register = r600_get_allowed_info_register,
.gart = {
.tlb_flush = &r600_pcie_gart_tlb_flush,
.get_page_entry = &rs600_gart_get_page_entry,
@ -1170,6 +1190,8 @@ static struct radeon_asic rs780_asic = {
.print_power_state = &rs780_dpm_print_power_state,
.debugfs_print_current_performance_level = &rs780_dpm_debugfs_print_current_performance_level,
.force_performance_level = &rs780_dpm_force_performance_level,
.get_current_sclk = &rs780_dpm_get_current_sclk,
.get_current_mclk = &rs780_dpm_get_current_mclk,
},
.pflip = {
.page_flip = &rs600_page_flip,
@ -1202,6 +1224,7 @@ static struct radeon_asic rv770_asic = {
.mc_wait_for_idle = &r600_mc_wait_for_idle,
.get_xclk = &rv770_get_xclk,
.get_gpu_clock_counter = &r600_get_gpu_clock_counter,
.get_allowed_info_register = r600_get_allowed_info_register,
.gart = {
.tlb_flush = &r600_pcie_gart_tlb_flush,
.get_page_entry = &rs600_gart_get_page_entry,
@ -1274,6 +1297,8 @@ static struct radeon_asic rv770_asic = {
.debugfs_print_current_performance_level = &rv770_dpm_debugfs_print_current_performance_level,
.force_performance_level = &rv770_dpm_force_performance_level,
.vblank_too_short = &rv770_dpm_vblank_too_short,
.get_current_sclk = &rv770_dpm_get_current_sclk,
.get_current_mclk = &rv770_dpm_get_current_mclk,
},
.pflip = {
.page_flip = &rv770_page_flip,
@ -1319,6 +1344,7 @@ static struct radeon_asic evergreen_asic = {
.mc_wait_for_idle = &evergreen_mc_wait_for_idle,
.get_xclk = &rv770_get_xclk,
.get_gpu_clock_counter = &r600_get_gpu_clock_counter,
.get_allowed_info_register = evergreen_get_allowed_info_register,
.gart = {
.tlb_flush = &evergreen_pcie_gart_tlb_flush,
.get_page_entry = &rs600_gart_get_page_entry,
@ -1391,6 +1417,8 @@ static struct radeon_asic evergreen_asic = {
.debugfs_print_current_performance_level = &rv770_dpm_debugfs_print_current_performance_level,
.force_performance_level = &rv770_dpm_force_performance_level,
.vblank_too_short = &cypress_dpm_vblank_too_short,
.get_current_sclk = &rv770_dpm_get_current_sclk,
.get_current_mclk = &rv770_dpm_get_current_mclk,
},
.pflip = {
.page_flip = &evergreen_page_flip,
@ -1410,6 +1438,7 @@ static struct radeon_asic sumo_asic = {
.mc_wait_for_idle = &evergreen_mc_wait_for_idle,
.get_xclk = &r600_get_xclk,
.get_gpu_clock_counter = &r600_get_gpu_clock_counter,
.get_allowed_info_register = evergreen_get_allowed_info_register,
.gart = {
.tlb_flush = &evergreen_pcie_gart_tlb_flush,
.get_page_entry = &rs600_gart_get_page_entry,
@ -1481,6 +1510,8 @@ static struct radeon_asic sumo_asic = {
.print_power_state = &sumo_dpm_print_power_state,
.debugfs_print_current_performance_level = &sumo_dpm_debugfs_print_current_performance_level,
.force_performance_level = &sumo_dpm_force_performance_level,
.get_current_sclk = &sumo_dpm_get_current_sclk,
.get_current_mclk = &sumo_dpm_get_current_mclk,
},
.pflip = {
.page_flip = &evergreen_page_flip,
@ -1500,6 +1531,7 @@ static struct radeon_asic btc_asic = {
.mc_wait_for_idle = &evergreen_mc_wait_for_idle,
.get_xclk = &rv770_get_xclk,
.get_gpu_clock_counter = &r600_get_gpu_clock_counter,
.get_allowed_info_register = evergreen_get_allowed_info_register,
.gart = {
.tlb_flush = &evergreen_pcie_gart_tlb_flush,
.get_page_entry = &rs600_gart_get_page_entry,
@ -1572,6 +1604,8 @@ static struct radeon_asic btc_asic = {
.debugfs_print_current_performance_level = &btc_dpm_debugfs_print_current_performance_level,
.force_performance_level = &rv770_dpm_force_performance_level,
.vblank_too_short = &btc_dpm_vblank_too_short,
.get_current_sclk = &btc_dpm_get_current_sclk,
.get_current_mclk = &btc_dpm_get_current_mclk,
},
.pflip = {
.page_flip = &evergreen_page_flip,
@ -1634,6 +1668,7 @@ static struct radeon_asic cayman_asic = {
.mc_wait_for_idle = &evergreen_mc_wait_for_idle,
.get_xclk = &rv770_get_xclk,
.get_gpu_clock_counter = &r600_get_gpu_clock_counter,
.get_allowed_info_register = cayman_get_allowed_info_register,
.gart = {
.tlb_flush = &cayman_pcie_gart_tlb_flush,
.get_page_entry = &rs600_gart_get_page_entry,
@ -1717,6 +1752,8 @@ static struct radeon_asic cayman_asic = {
.debugfs_print_current_performance_level = &ni_dpm_debugfs_print_current_performance_level,
.force_performance_level = &ni_dpm_force_performance_level,
.vblank_too_short = &ni_dpm_vblank_too_short,
.get_current_sclk = &ni_dpm_get_current_sclk,
.get_current_mclk = &ni_dpm_get_current_mclk,
},
.pflip = {
.page_flip = &evergreen_page_flip,
@ -1736,6 +1773,7 @@ static struct radeon_asic trinity_asic = {
.mc_wait_for_idle = &evergreen_mc_wait_for_idle,
.get_xclk = &r600_get_xclk,
.get_gpu_clock_counter = &r600_get_gpu_clock_counter,
.get_allowed_info_register = cayman_get_allowed_info_register,
.gart = {
.tlb_flush = &cayman_pcie_gart_tlb_flush,
.get_page_entry = &rs600_gart_get_page_entry,
@ -1819,6 +1857,8 @@ static struct radeon_asic trinity_asic = {
.debugfs_print_current_performance_level = &trinity_dpm_debugfs_print_current_performance_level,
.force_performance_level = &trinity_dpm_force_performance_level,
.enable_bapm = &trinity_dpm_enable_bapm,
.get_current_sclk = &trinity_dpm_get_current_sclk,
.get_current_mclk = &trinity_dpm_get_current_mclk,
},
.pflip = {
.page_flip = &evergreen_page_flip,
@ -1868,6 +1908,7 @@ static struct radeon_asic si_asic = {
.mc_wait_for_idle = &evergreen_mc_wait_for_idle,
.get_xclk = &si_get_xclk,
.get_gpu_clock_counter = &si_get_gpu_clock_counter,
.get_allowed_info_register = si_get_allowed_info_register,
.gart = {
.tlb_flush = &si_pcie_gart_tlb_flush,
.get_page_entry = &rs600_gart_get_page_entry,
@ -1955,6 +1996,8 @@ static struct radeon_asic si_asic = {
.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,
.get_current_sclk = &si_dpm_get_current_sclk,
.get_current_mclk = &si_dpm_get_current_mclk,
},
.pflip = {
.page_flip = &evergreen_page_flip,
@ -2032,6 +2075,7 @@ static struct radeon_asic ci_asic = {
.mc_wait_for_idle = &evergreen_mc_wait_for_idle,
.get_xclk = &cik_get_xclk,
.get_gpu_clock_counter = &cik_get_gpu_clock_counter,
.get_allowed_info_register = cik_get_allowed_info_register,
.gart = {
.tlb_flush = &cik_pcie_gart_tlb_flush,
.get_page_entry = &rs600_gart_get_page_entry,
@ -2123,6 +2167,8 @@ static struct radeon_asic ci_asic = {
.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,
.get_current_sclk = &ci_dpm_get_current_sclk,
.get_current_mclk = &ci_dpm_get_current_mclk,
},
.pflip = {
.page_flip = &evergreen_page_flip,
@ -2142,6 +2188,7 @@ static struct radeon_asic kv_asic = {
.mc_wait_for_idle = &evergreen_mc_wait_for_idle,
.get_xclk = &cik_get_xclk,
.get_gpu_clock_counter = &cik_get_gpu_clock_counter,
.get_allowed_info_register = cik_get_allowed_info_register,
.gart = {
.tlb_flush = &cik_pcie_gart_tlb_flush,
.get_page_entry = &rs600_gart_get_page_entry,
@ -2229,6 +2276,8 @@ static struct radeon_asic kv_asic = {
.force_performance_level = &kv_dpm_force_performance_level,
.powergate_uvd = &kv_dpm_powergate_uvd,
.enable_bapm = &kv_dpm_enable_bapm,
.get_current_sclk = &kv_dpm_get_current_sclk,
.get_current_mclk = &kv_dpm_get_current_mclk,
},
.pflip = {
.page_flip = &evergreen_page_flip,

View File

@ -384,6 +384,8 @@ u32 r600_gfx_get_wptr(struct radeon_device *rdev,
struct radeon_ring *ring);
void r600_gfx_set_wptr(struct radeon_device *rdev,
struct radeon_ring *ring);
int r600_get_allowed_info_register(struct radeon_device *rdev,
u32 reg, u32 *val);
/* r600 irq */
int r600_irq_process(struct radeon_device *rdev);
int r600_irq_init(struct radeon_device *rdev);
@ -433,6 +435,8 @@ void rv6xx_dpm_debugfs_print_current_performance_level(struct radeon_device *rde
struct seq_file *m);
int rv6xx_dpm_force_performance_level(struct radeon_device *rdev,
enum radeon_dpm_forced_level level);
u32 rv6xx_dpm_get_current_sclk(struct radeon_device *rdev);
u32 rv6xx_dpm_get_current_mclk(struct radeon_device *rdev);
/* rs780 dpm */
int rs780_dpm_init(struct radeon_device *rdev);
int rs780_dpm_enable(struct radeon_device *rdev);
@ -449,6 +453,8 @@ void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rde
struct seq_file *m);
int rs780_dpm_force_performance_level(struct radeon_device *rdev,
enum radeon_dpm_forced_level level);
u32 rs780_dpm_get_current_sclk(struct radeon_device *rdev);
u32 rs780_dpm_get_current_mclk(struct radeon_device *rdev);
/*
* rv770,rv730,rv710,rv740
@ -488,6 +494,8 @@ void rv770_dpm_debugfs_print_current_performance_level(struct radeon_device *rde
int rv770_dpm_force_performance_level(struct radeon_device *rdev,
enum radeon_dpm_forced_level level);
bool rv770_dpm_vblank_too_short(struct radeon_device *rdev);
u32 rv770_dpm_get_current_sclk(struct radeon_device *rdev);
u32 rv770_dpm_get_current_mclk(struct radeon_device *rdev);
/*
* evergreen
@ -540,6 +548,8 @@ struct radeon_fence *evergreen_copy_dma(struct radeon_device *rdev,
unsigned num_gpu_pages,
struct reservation_object *resv);
int evergreen_get_temp(struct radeon_device *rdev);
int evergreen_get_allowed_info_register(struct radeon_device *rdev,
u32 reg, u32 *val);
int sumo_get_temp(struct radeon_device *rdev);
int tn_get_temp(struct radeon_device *rdev);
int cypress_dpm_init(struct radeon_device *rdev);
@ -563,6 +573,8 @@ u32 btc_dpm_get_mclk(struct radeon_device *rdev, bool low);
bool btc_dpm_vblank_too_short(struct radeon_device *rdev);
void btc_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
struct seq_file *m);
u32 btc_dpm_get_current_sclk(struct radeon_device *rdev);
u32 btc_dpm_get_current_mclk(struct radeon_device *rdev);
int sumo_dpm_init(struct radeon_device *rdev);
int sumo_dpm_enable(struct radeon_device *rdev);
int sumo_dpm_late_enable(struct radeon_device *rdev);
@ -581,6 +593,8 @@ void sumo_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev
struct seq_file *m);
int sumo_dpm_force_performance_level(struct radeon_device *rdev,
enum radeon_dpm_forced_level level);
u32 sumo_dpm_get_current_sclk(struct radeon_device *rdev);
u32 sumo_dpm_get_current_mclk(struct radeon_device *rdev);
/*
* cayman
@ -637,6 +651,8 @@ uint32_t cayman_dma_get_wptr(struct radeon_device *rdev,
struct radeon_ring *ring);
void cayman_dma_set_wptr(struct radeon_device *rdev,
struct radeon_ring *ring);
int cayman_get_allowed_info_register(struct radeon_device *rdev,
u32 reg, u32 *val);
int ni_dpm_init(struct radeon_device *rdev);
void ni_dpm_setup_asic(struct radeon_device *rdev);
@ -655,6 +671,8 @@ void ni_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
int ni_dpm_force_performance_level(struct radeon_device *rdev,
enum radeon_dpm_forced_level level);
bool ni_dpm_vblank_too_short(struct radeon_device *rdev);
u32 ni_dpm_get_current_sclk(struct radeon_device *rdev);
u32 ni_dpm_get_current_mclk(struct radeon_device *rdev);
int trinity_dpm_init(struct radeon_device *rdev);
int trinity_dpm_enable(struct radeon_device *rdev);
int trinity_dpm_late_enable(struct radeon_device *rdev);
@ -674,6 +692,8 @@ void trinity_dpm_debugfs_print_current_performance_level(struct radeon_device *r
int trinity_dpm_force_performance_level(struct radeon_device *rdev,
enum radeon_dpm_forced_level level);
void trinity_dpm_enable_bapm(struct radeon_device *rdev, bool enable);
u32 trinity_dpm_get_current_sclk(struct radeon_device *rdev);
u32 trinity_dpm_get_current_mclk(struct radeon_device *rdev);
/* DCE6 - SI */
void dce6_bandwidth_update(struct radeon_device *rdev);
@ -726,6 +746,8 @@ u32 si_get_xclk(struct radeon_device *rdev);
uint64_t si_get_gpu_clock_counter(struct radeon_device *rdev);
int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
int si_get_temp(struct radeon_device *rdev);
int si_get_allowed_info_register(struct radeon_device *rdev,
u32 reg, u32 *val);
int si_dpm_init(struct radeon_device *rdev);
void si_dpm_setup_asic(struct radeon_device *rdev);
int si_dpm_enable(struct radeon_device *rdev);
@ -746,6 +768,8 @@ 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);
u32 si_dpm_get_current_sclk(struct radeon_device *rdev);
u32 si_dpm_get_current_mclk(struct radeon_device *rdev);
/* DCE8 - CIK */
void dce8_bandwidth_update(struct radeon_device *rdev);
@ -841,6 +865,8 @@ void cik_sdma_set_wptr(struct radeon_device *rdev,
struct radeon_ring *ring);
int ci_get_temp(struct radeon_device *rdev);
int kv_get_temp(struct radeon_device *rdev);
int cik_get_allowed_info_register(struct radeon_device *rdev,
u32 reg, u32 *val);
int ci_dpm_init(struct radeon_device *rdev);
int ci_dpm_enable(struct radeon_device *rdev);
@ -862,6 +888,8 @@ int ci_dpm_force_performance_level(struct radeon_device *rdev,
enum radeon_dpm_forced_level level);
bool ci_dpm_vblank_too_short(struct radeon_device *rdev);
void ci_dpm_powergate_uvd(struct radeon_device *rdev, bool gate);
u32 ci_dpm_get_current_sclk(struct radeon_device *rdev);
u32 ci_dpm_get_current_mclk(struct radeon_device *rdev);
int ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
u32 *speed);
@ -890,6 +918,8 @@ int kv_dpm_force_performance_level(struct radeon_device *rdev,
enum radeon_dpm_forced_level level);
void kv_dpm_powergate_uvd(struct radeon_device *rdev, bool gate);
void kv_dpm_enable_bapm(struct radeon_device *rdev, bool enable);
u32 kv_dpm_get_current_sclk(struct radeon_device *rdev);
u32 kv_dpm_get_current_mclk(struct radeon_device *rdev);
/* uvd v1.0 */
uint32_t uvd_v1_0_get_rptr(struct radeon_device *rdev,

View File

@ -845,6 +845,7 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
radeon_link_encoder_connector(dev);
radeon_setup_mst_connector(dev);
return true;
}

View File

@ -520,16 +520,40 @@ static int radeon_audio_set_avi_packet(struct drm_encoder *encoder,
struct radeon_device *rdev = encoder->dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
struct drm_connector *connector;
struct radeon_connector *radeon_connector = NULL;
u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
struct hdmi_avi_infoframe frame;
int err;
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 -ENOENT;
}
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;
}
if (drm_rgb_quant_range_selectable(radeon_connector_edid(connector))) {
if (radeon_encoder->output_csc == RADEON_OUTPUT_CSC_TVRGB)
frame.quantization_range = HDMI_QUANTIZATION_RANGE_LIMITED;
else
frame.quantization_range = HDMI_QUANTIZATION_RANGE_FULL;
} else {
frame.quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT;
}
err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer));
if (err < 0) {
DRM_ERROR("failed to pack AVI infoframe: %d\n", err);

View File

@ -27,6 +27,7 @@
#include <drm/drm_edid.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_dp_mst_helper.h>
#include <drm/radeon_drm.h>
#include "radeon.h"
#include "radeon_audio.h"
@ -34,12 +35,33 @@
#include <linux/pm_runtime.h>
static int radeon_dp_handle_hpd(struct drm_connector *connector)
{
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
int ret;
ret = radeon_dp_mst_check_status(radeon_connector);
if (ret == -EINVAL)
return 1;
return 0;
}
void radeon_connector_hotplug(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
struct radeon_connector_atom_dig *dig_connector =
radeon_connector->con_priv;
if (radeon_connector->is_mst_connector)
return;
if (dig_connector->is_mst) {
radeon_dp_handle_hpd(connector);
return;
}
}
/* bail if the connector does not have hpd pin, e.g.,
* VGA, TV, etc.
*/
@ -725,6 +747,30 @@ static int radeon_connector_set_property(struct drm_connector *connector, struct
radeon_property_change_mode(&radeon_encoder->base);
}
if (property == rdev->mode_info.output_csc_property) {
if (connector->encoder)
radeon_encoder = to_radeon_encoder(connector->encoder);
else {
struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
radeon_encoder = to_radeon_encoder(connector_funcs->best_encoder(connector));
}
if (radeon_encoder->output_csc == val)
return 0;
radeon_encoder->output_csc = val;
if (connector->encoder->crtc) {
struct drm_crtc *crtc = connector->encoder->crtc;
struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
radeon_crtc->output_csc = radeon_encoder->output_csc;
(*crtc_funcs->load_lut)(crtc);
}
}
return 0;
}
@ -1585,6 +1631,9 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
struct drm_encoder *encoder = radeon_best_single_encoder(connector);
int r;
if (radeon_dig_connector->is_mst)
return connector_status_disconnected;
r = pm_runtime_get_sync(connector->dev->dev);
if (r < 0)
return connector_status_disconnected;
@ -1643,12 +1692,21 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
radeon_dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector);
if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) {
ret = connector_status_connected;
if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT)
if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
radeon_dp_getdpcd(radeon_connector);
r = radeon_dp_mst_probe(radeon_connector);
if (r == 1)
ret = connector_status_disconnected;
}
} else {
if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
if (radeon_dp_getdpcd(radeon_connector))
ret = connector_status_connected;
if (radeon_dp_getdpcd(radeon_connector)) {
r = radeon_dp_mst_probe(radeon_connector);
if (r == 1)
ret = connector_status_disconnected;
else
ret = connector_status_connected;
}
} else {
/* try non-aux ddc (DP to DVI/HDMI/etc. adapter) */
if (radeon_ddc_probe(radeon_connector, false))
@ -1872,6 +1930,10 @@ radeon_add_atom_connector(struct drm_device *dev,
drm_object_attach_property(&radeon_connector->base.base,
dev->mode_config.scaling_mode_property,
DRM_MODE_SCALE_NONE);
if (ASIC_IS_DCE5(rdev))
drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.output_csc_property,
RADEON_OUTPUT_CSC_BYPASS);
break;
case DRM_MODE_CONNECTOR_DVII:
case DRM_MODE_CONNECTOR_DVID:
@ -1904,6 +1966,10 @@ radeon_add_atom_connector(struct drm_device *dev,
drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.audio_property,
RADEON_AUDIO_AUTO);
if (ASIC_IS_DCE5(rdev))
drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.output_csc_property,
RADEON_OUTPUT_CSC_BYPASS);
subpixel_order = SubPixelHorizontalRGB;
connector->interlace_allowed = true;
@ -1950,6 +2016,10 @@ radeon_add_atom_connector(struct drm_device *dev,
drm_object_attach_property(&radeon_connector->base.base,
dev->mode_config.scaling_mode_property,
DRM_MODE_SCALE_NONE);
if (ASIC_IS_DCE5(rdev))
drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.output_csc_property,
RADEON_OUTPUT_CSC_BYPASS);
/* no HPD on analog connectors */
radeon_connector->hpd.hpd = RADEON_HPD_NONE;
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
@ -1972,6 +2042,10 @@ radeon_add_atom_connector(struct drm_device *dev,
drm_object_attach_property(&radeon_connector->base.base,
dev->mode_config.scaling_mode_property,
DRM_MODE_SCALE_NONE);
if (ASIC_IS_DCE5(rdev))
drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.output_csc_property,
RADEON_OUTPUT_CSC_BYPASS);
/* no HPD on analog connectors */
radeon_connector->hpd.hpd = RADEON_HPD_NONE;
connector->interlace_allowed = true;
@ -2023,6 +2097,10 @@ radeon_add_atom_connector(struct drm_device *dev,
rdev->mode_info.load_detect_property,
1);
}
if (ASIC_IS_DCE5(rdev))
drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.output_csc_property,
RADEON_OUTPUT_CSC_BYPASS);
connector->interlace_allowed = true;
if (connector_type == DRM_MODE_CONNECTOR_DVII)
connector->doublescan_allowed = true;
@ -2068,6 +2146,10 @@ radeon_add_atom_connector(struct drm_device *dev,
rdev->mode_info.audio_property,
RADEON_AUDIO_AUTO);
}
if (ASIC_IS_DCE5(rdev))
drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.output_csc_property,
RADEON_OUTPUT_CSC_BYPASS);
subpixel_order = SubPixelHorizontalRGB;
connector->interlace_allowed = true;
if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
@ -2116,6 +2198,10 @@ radeon_add_atom_connector(struct drm_device *dev,
rdev->mode_info.audio_property,
RADEON_AUDIO_AUTO);
}
if (ASIC_IS_DCE5(rdev))
drm_object_attach_property(&radeon_connector->base.base,
rdev->mode_info.output_csc_property,
RADEON_OUTPUT_CSC_BYPASS);
connector->interlace_allowed = true;
/* in theory with a DP to VGA converter... */
connector->doublescan_allowed = false;
@ -2352,3 +2438,27 @@ radeon_add_legacy_connector(struct drm_device *dev,
connector->display_info.subpixel_order = subpixel_order;
drm_connector_register(connector);
}
void radeon_setup_mst_connector(struct drm_device *dev)
{
struct radeon_device *rdev = dev->dev_private;
struct drm_connector *connector;
struct radeon_connector *radeon_connector;
if (!ASIC_IS_DCE5(rdev))
return;
if (radeon_mst == 0)
return;
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
int ret;
radeon_connector = to_radeon_connector(connector);
if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort)
continue;
ret = radeon_dp_mst_init(radeon_connector);
}
}

View File

@ -1442,6 +1442,11 @@ int radeon_device_init(struct radeon_device *rdev,
DRM_ERROR("registering gem debugfs failed (%d).\n", r);
}
r = radeon_mst_debugfs_init(rdev);
if (r) {
DRM_ERROR("registering mst debugfs failed (%d).\n", r);
}
if (rdev->flags & RADEON_IS_AGP && !rdev->accel_working) {
/* Acceleration not working on AGP card try again
* with fallback to PCI or PCIE GART

View File

@ -154,7 +154,7 @@ static void dce5_crtc_load_lut(struct drm_crtc *crtc)
(NI_GRPH_REGAMMA_MODE(NI_REGAMMA_BYPASS) |
NI_OVL_REGAMMA_MODE(NI_REGAMMA_BYPASS)));
WREG32(NI_OUTPUT_CSC_CONTROL + radeon_crtc->crtc_offset,
(NI_OUTPUT_CSC_GRPH_MODE(NI_OUTPUT_CSC_BYPASS) |
(NI_OUTPUT_CSC_GRPH_MODE(radeon_crtc->output_csc) |
NI_OUTPUT_CSC_OVL_MODE(NI_OUTPUT_CSC_BYPASS)));
/* XXX match this to the depth of the crtc fmt block, move to modeset? */
WREG32(0x6940 + radeon_crtc->crtc_offset, 0);
@ -1382,6 +1382,13 @@ static struct drm_prop_enum_list radeon_dither_enum_list[] =
{ RADEON_FMT_DITHER_ENABLE, "on" },
};
static struct drm_prop_enum_list radeon_output_csc_enum_list[] =
{ { RADEON_OUTPUT_CSC_BYPASS, "bypass" },
{ RADEON_OUTPUT_CSC_TVRGB, "tvrgb" },
{ RADEON_OUTPUT_CSC_YCBCR601, "ycbcr601" },
{ RADEON_OUTPUT_CSC_YCBCR709, "ycbcr709" },
};
static int radeon_modeset_create_props(struct radeon_device *rdev)
{
int sz;
@ -1444,6 +1451,12 @@ static int radeon_modeset_create_props(struct radeon_device *rdev)
"dither",
radeon_dither_enum_list, sz);
sz = ARRAY_SIZE(radeon_output_csc_enum_list);
rdev->mode_info.output_csc_property =
drm_property_create_enum(rdev->ddev, 0,
"output_csc",
radeon_output_csc_enum_list, sz);
return 0;
}

View File

@ -0,0 +1,206 @@
/*
* Copyright 2015 Red Hat 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: Dave Airlie
*/
#include <drm/drmP.h>
#include <drm/radeon_drm.h>
#include "radeon.h"
#include "nid.h"
#define AUX_RX_ERROR_FLAGS (AUX_SW_RX_OVERFLOW | \
AUX_SW_RX_HPD_DISCON | \
AUX_SW_RX_PARTIAL_BYTE | \
AUX_SW_NON_AUX_MODE | \
AUX_SW_RX_MIN_COUNT_VIOL | \
AUX_SW_RX_INVALID_STOP | \
AUX_SW_RX_SYNC_INVALID_L | \
AUX_SW_RX_SYNC_INVALID_H | \
AUX_SW_RX_INVALID_START | \
AUX_SW_RX_RECV_NO_DET | \
AUX_SW_RX_RECV_INVALID_H | \
AUX_SW_RX_RECV_INVALID_V)
#define AUX_SW_REPLY_GET_BYTE_COUNT(x) (((x) >> 24) & 0x1f)
#define BARE_ADDRESS_SIZE 3
static const u32 aux_offset[] =
{
0x6200 - 0x6200,
0x6250 - 0x6200,
0x62a0 - 0x6200,
0x6300 - 0x6200,
0x6350 - 0x6200,
0x63a0 - 0x6200,
};
ssize_t
radeon_dp_aux_transfer_native(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
{
struct radeon_i2c_chan *chan =
container_of(aux, struct radeon_i2c_chan, aux);
struct drm_device *dev = chan->dev;
struct radeon_device *rdev = dev->dev_private;
int ret = 0, i;
uint32_t tmp, ack = 0;
int instance = chan->rec.i2c_id & 0xf;
u8 byte;
u8 *buf = msg->buffer;
int retry_count = 0;
int bytes;
int msize;
bool is_write = false;
if (WARN_ON(msg->size > 16))
return -E2BIG;
switch (msg->request & ~DP_AUX_I2C_MOT) {
case DP_AUX_NATIVE_WRITE:
case DP_AUX_I2C_WRITE:
is_write = true;
break;
case DP_AUX_NATIVE_READ:
case DP_AUX_I2C_READ:
break;
default:
return -EINVAL;
}
/* work out two sizes required */
msize = 0;
bytes = BARE_ADDRESS_SIZE;
if (msg->size) {
msize = msg->size - 1;
bytes++;
if (is_write)
bytes += msg->size;
}
mutex_lock(&chan->mutex);
/* switch the pad to aux mode */
tmp = RREG32(chan->rec.mask_clk_reg);
tmp |= (1 << 16);
WREG32(chan->rec.mask_clk_reg, tmp);
/* setup AUX control register with correct HPD pin */
tmp = RREG32(AUX_CONTROL + aux_offset[instance]);
tmp &= AUX_HPD_SEL(0x7);
tmp |= AUX_HPD_SEL(chan->rec.hpd);
tmp |= AUX_EN | AUX_LS_READ_EN;
WREG32(AUX_CONTROL + aux_offset[instance], tmp);
/* atombios appears to write this twice lets copy it */
WREG32(AUX_SW_CONTROL + aux_offset[instance],
AUX_SW_WR_BYTES(bytes));
WREG32(AUX_SW_CONTROL + aux_offset[instance],
AUX_SW_WR_BYTES(bytes));
/* write the data header into the registers */
/* request, addres, msg size */
byte = (msg->request << 4);
WREG32(AUX_SW_DATA + aux_offset[instance],
AUX_SW_DATA_MASK(byte) | AUX_SW_AUTOINCREMENT_DISABLE);
byte = (msg->address >> 8) & 0xff;
WREG32(AUX_SW_DATA + aux_offset[instance],
AUX_SW_DATA_MASK(byte));
byte = msg->address & 0xff;
WREG32(AUX_SW_DATA + aux_offset[instance],
AUX_SW_DATA_MASK(byte));
byte = msize;
WREG32(AUX_SW_DATA + aux_offset[instance],
AUX_SW_DATA_MASK(byte));
/* if we are writing - write the msg buffer */
if (is_write) {
for (i = 0; i < msg->size; i++) {
WREG32(AUX_SW_DATA + aux_offset[instance],
AUX_SW_DATA_MASK(buf[i]));
}
}
/* clear the ACK */
WREG32(AUX_SW_INTERRUPT_CONTROL + aux_offset[instance], AUX_SW_DONE_ACK);
/* write the size and GO bits */
WREG32(AUX_SW_CONTROL + aux_offset[instance],
AUX_SW_WR_BYTES(bytes) | AUX_SW_GO);
/* poll the status registers - TODO irq support */
do {
tmp = RREG32(AUX_SW_STATUS + aux_offset[instance]);
if (tmp & AUX_SW_DONE) {
break;
}
usleep_range(100, 200);
} while (retry_count++ < 1000);
if (retry_count >= 1000) {
DRM_ERROR("auxch hw never signalled completion, error %08x\n", tmp);
ret = -EIO;
goto done;
}
if (tmp & AUX_SW_RX_TIMEOUT) {
DRM_DEBUG_KMS("dp_aux_ch timed out\n");
ret = -ETIMEDOUT;
goto done;
}
if (tmp & AUX_RX_ERROR_FLAGS) {
DRM_DEBUG_KMS("dp_aux_ch flags not zero: %08x\n", tmp);
ret = -EIO;
goto done;
}
bytes = AUX_SW_REPLY_GET_BYTE_COUNT(tmp);
if (bytes) {
WREG32(AUX_SW_DATA + aux_offset[instance],
AUX_SW_DATA_RW | AUX_SW_AUTOINCREMENT_DISABLE);
tmp = RREG32(AUX_SW_DATA + aux_offset[instance]);
ack = (tmp >> 8) & 0xff;
for (i = 0; i < bytes - 1; i++) {
tmp = RREG32(AUX_SW_DATA + aux_offset[instance]);
if (buf)
buf[i] = (tmp >> 8) & 0xff;
}
if (buf)
ret = bytes - 1;
}
WREG32(AUX_SW_INTERRUPT_CONTROL + aux_offset[instance], AUX_SW_DONE_ACK);
if (is_write)
ret = msg->size;
done:
mutex_unlock(&chan->mutex);
if (ret >= 0)
msg->reply = ack >> 4;
return ret;
}

View File

@ -0,0 +1,782 @@
#include <drm/drmP.h>
#include <drm/drm_dp_mst_helper.h>
#include <drm/drm_fb_helper.h>
#include "radeon.h"
#include "atom.h"
#include "ni_reg.h"
static struct radeon_encoder *radeon_dp_create_fake_mst_encoder(struct radeon_connector *connector);
static int radeon_atom_set_enc_offset(int id)
{
static const int offsets[] = { EVERGREEN_CRTC0_REGISTER_OFFSET,
EVERGREEN_CRTC1_REGISTER_OFFSET,
EVERGREEN_CRTC2_REGISTER_OFFSET,
EVERGREEN_CRTC3_REGISTER_OFFSET,
EVERGREEN_CRTC4_REGISTER_OFFSET,
EVERGREEN_CRTC5_REGISTER_OFFSET,
0x13830 - 0x7030 };
return offsets[id];
}
static int radeon_dp_mst_set_be_cntl(struct radeon_encoder *primary,
struct radeon_encoder_mst *mst_enc,
enum radeon_hpd_id hpd, bool enable)
{
struct drm_device *dev = primary->base.dev;
struct radeon_device *rdev = dev->dev_private;
uint32_t reg;
int retries = 0;
uint32_t temp;
reg = RREG32(NI_DIG_BE_CNTL + primary->offset);
/* set MST mode */
reg &= ~NI_DIG_FE_DIG_MODE(7);
reg |= NI_DIG_FE_DIG_MODE(NI_DIG_MODE_DP_MST);
if (enable)
reg |= NI_DIG_FE_SOURCE_SELECT(1 << mst_enc->fe);
else
reg &= ~NI_DIG_FE_SOURCE_SELECT(1 << mst_enc->fe);
reg |= NI_DIG_HPD_SELECT(hpd);
DRM_DEBUG_KMS("writing 0x%08x 0x%08x\n", NI_DIG_BE_CNTL + primary->offset, reg);
WREG32(NI_DIG_BE_CNTL + primary->offset, reg);
if (enable) {
uint32_t offset = radeon_atom_set_enc_offset(mst_enc->fe);
do {
temp = RREG32(NI_DIG_FE_CNTL + offset);
} while ((temp & NI_DIG_SYMCLK_FE_ON) && retries++ < 10000);
if (retries == 10000)
DRM_ERROR("timed out waiting for FE %d %d\n", primary->offset, mst_enc->fe);
}
return 0;
}
static int radeon_dp_mst_set_stream_attrib(struct radeon_encoder *primary,
int stream_number,
int fe,
int slots)
{
struct drm_device *dev = primary->base.dev;
struct radeon_device *rdev = dev->dev_private;
u32 temp, val;
int retries = 0;
int satreg, satidx;
satreg = stream_number >> 1;
satidx = stream_number & 1;
temp = RREG32(NI_DP_MSE_SAT0 + satreg + primary->offset);
val = NI_DP_MSE_SAT_SLOT_COUNT0(slots) | NI_DP_MSE_SAT_SRC0(fe);
val <<= (16 * satidx);
temp &= ~(0xffff << (16 * satidx));
temp |= val;
DRM_DEBUG_KMS("writing 0x%08x 0x%08x\n", NI_DP_MSE_SAT0 + satreg + primary->offset, temp);
WREG32(NI_DP_MSE_SAT0 + satreg + primary->offset, temp);
WREG32(NI_DP_MSE_SAT_UPDATE + primary->offset, 1);
do {
temp = RREG32(NI_DP_MSE_SAT_UPDATE + primary->offset);
} while ((temp & 0x1) && retries++ < 10000);
if (retries == 10000)
DRM_ERROR("timed out waitin for SAT update %d\n", primary->offset);
/* MTP 16 ? */
return 0;
}
static int radeon_dp_mst_update_stream_attribs(struct radeon_connector *mst_conn,
struct radeon_encoder *primary)
{
struct drm_device *dev = mst_conn->base.dev;
struct stream_attribs new_attribs[6];
int i;
int idx = 0;
struct radeon_connector *radeon_connector;
struct drm_connector *connector;
memset(new_attribs, 0, sizeof(new_attribs));
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
struct radeon_encoder *subenc;
struct radeon_encoder_mst *mst_enc;
radeon_connector = to_radeon_connector(connector);
if (!radeon_connector->is_mst_connector)
continue;
if (radeon_connector->mst_port != mst_conn)
continue;
subenc = radeon_connector->mst_encoder;
mst_enc = subenc->enc_priv;
if (!mst_enc->enc_active)
continue;
new_attribs[idx].fe = mst_enc->fe;
new_attribs[idx].slots = drm_dp_mst_get_vcpi_slots(&mst_conn->mst_mgr, mst_enc->port);
idx++;
}
for (i = 0; i < idx; i++) {
if (new_attribs[i].fe != mst_conn->cur_stream_attribs[i].fe ||
new_attribs[i].slots != mst_conn->cur_stream_attribs[i].slots) {
radeon_dp_mst_set_stream_attrib(primary, i, new_attribs[i].fe, new_attribs[i].slots);
mst_conn->cur_stream_attribs[i].fe = new_attribs[i].fe;
mst_conn->cur_stream_attribs[i].slots = new_attribs[i].slots;
}
}
for (i = idx; i < mst_conn->enabled_attribs; i++) {
radeon_dp_mst_set_stream_attrib(primary, i, 0, 0);
mst_conn->cur_stream_attribs[i].fe = 0;
mst_conn->cur_stream_attribs[i].slots = 0;
}
mst_conn->enabled_attribs = idx;
return 0;
}
static int radeon_dp_mst_set_vcp_size(struct radeon_encoder *mst, uint32_t x, uint32_t y)
{
struct drm_device *dev = mst->base.dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder_mst *mst_enc = mst->enc_priv;
uint32_t val, temp;
uint32_t offset = radeon_atom_set_enc_offset(mst_enc->fe);
int retries = 0;
val = NI_DP_MSE_RATE_X(x) | NI_DP_MSE_RATE_Y(y);
WREG32(NI_DP_MSE_RATE_CNTL + offset, val);
do {
temp = RREG32(NI_DP_MSE_RATE_UPDATE + offset);
} while ((temp & 0x1) && (retries++ < 10000));
if (retries >= 10000)
DRM_ERROR("timed out wait for rate cntl %d\n", mst_enc->fe);
return 0;
}
static int radeon_dp_mst_get_ddc_modes(struct drm_connector *connector)
{
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
struct radeon_connector *master = radeon_connector->mst_port;
struct edid *edid;
int ret = 0;
edid = drm_dp_mst_get_edid(connector, &master->mst_mgr, radeon_connector->port);
radeon_connector->edid = edid;
DRM_DEBUG_KMS("edid retrieved %p\n", edid);
if (radeon_connector->edid) {
drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid);
ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid);
drm_edid_to_eld(&radeon_connector->base, radeon_connector->edid);
return ret;
}
drm_mode_connector_update_edid_property(&radeon_connector->base, NULL);
return ret;
}
static int radeon_dp_mst_get_modes(struct drm_connector *connector)
{
return radeon_dp_mst_get_ddc_modes(connector);
}
static enum drm_mode_status
radeon_dp_mst_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
/* TODO - validate mode against available PBN for link */
if (mode->clock < 10000)
return MODE_CLOCK_LOW;
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
return MODE_H_ILLEGAL;
return MODE_OK;
}
struct drm_encoder *radeon_mst_best_encoder(struct drm_connector *connector)
{
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
return &radeon_connector->mst_encoder->base;
}
static const struct drm_connector_helper_funcs radeon_dp_mst_connector_helper_funcs = {
.get_modes = radeon_dp_mst_get_modes,
.mode_valid = radeon_dp_mst_mode_valid,
.best_encoder = radeon_mst_best_encoder,
};
static enum drm_connector_status
radeon_dp_mst_detect(struct drm_connector *connector, bool force)
{
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
struct radeon_connector *master = radeon_connector->mst_port;
return drm_dp_mst_detect_port(connector, &master->mst_mgr, radeon_connector->port);
}
static void
radeon_dp_mst_connector_destroy(struct drm_connector *connector)
{
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
struct radeon_encoder *radeon_encoder = radeon_connector->mst_encoder;
drm_encoder_cleanup(&radeon_encoder->base);
kfree(radeon_encoder);
drm_connector_cleanup(connector);
kfree(radeon_connector);
}
static void radeon_connector_dpms(struct drm_connector *connector, int mode)
{
DRM_DEBUG_KMS("\n");
}
static const struct drm_connector_funcs radeon_dp_mst_connector_funcs = {
.dpms = radeon_connector_dpms,
.detect = radeon_dp_mst_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = radeon_dp_mst_connector_destroy,
};
static struct drm_connector *radeon_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
struct drm_dp_mst_port *port,
const char *pathprop)
{
struct radeon_connector *master = container_of(mgr, struct radeon_connector, mst_mgr);
struct drm_device *dev = master->base.dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_connector *radeon_connector;
struct drm_connector *connector;
radeon_connector = kzalloc(sizeof(*radeon_connector), GFP_KERNEL);
if (!radeon_connector)
return NULL;
radeon_connector->is_mst_connector = true;
connector = &radeon_connector->base;
radeon_connector->port = port;
radeon_connector->mst_port = master;
DRM_DEBUG_KMS("\n");
drm_connector_init(dev, connector, &radeon_dp_mst_connector_funcs, DRM_MODE_CONNECTOR_DisplayPort);
drm_connector_helper_add(connector, &radeon_dp_mst_connector_helper_funcs);
radeon_connector->mst_encoder = radeon_dp_create_fake_mst_encoder(master);
drm_object_attach_property(&connector->base, dev->mode_config.path_property, 0);
drm_mode_connector_set_path_property(connector, pathprop);
drm_reinit_primary_mode_group(dev);
mutex_lock(&dev->mode_config.mutex);
radeon_fb_add_connector(rdev, connector);
mutex_unlock(&dev->mode_config.mutex);
drm_connector_register(connector);
return connector;
}
static void radeon_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
struct drm_connector *connector)
{
struct radeon_connector *master = container_of(mgr, struct radeon_connector, mst_mgr);
struct drm_device *dev = master->base.dev;
struct radeon_device *rdev = dev->dev_private;
drm_connector_unregister(connector);
/* need to nuke the connector */
mutex_lock(&dev->mode_config.mutex);
/* dpms off */
radeon_fb_remove_connector(rdev, connector);
drm_connector_cleanup(connector);
mutex_unlock(&dev->mode_config.mutex);
drm_reinit_primary_mode_group(dev);
kfree(connector);
DRM_DEBUG_KMS("\n");
}
static void radeon_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr)
{
struct radeon_connector *master = container_of(mgr, struct radeon_connector, mst_mgr);
struct drm_device *dev = master->base.dev;
drm_kms_helper_hotplug_event(dev);
}
struct drm_dp_mst_topology_cbs mst_cbs = {
.add_connector = radeon_dp_add_mst_connector,
.destroy_connector = radeon_dp_destroy_mst_connector,
.hotplug = radeon_dp_mst_hotplug,
};
struct radeon_connector *radeon_mst_find_connector(struct drm_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
struct drm_connector *connector;
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
if (!connector->encoder)
continue;
if (!radeon_connector->is_mst_connector)
continue;
DRM_DEBUG_KMS("checking %p vs %p\n", connector->encoder, encoder);
if (connector->encoder == encoder)
return radeon_connector;
}
return NULL;
}
void radeon_dp_mst_prepare_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
{
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct drm_device *dev = crtc->dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(radeon_crtc->encoder);
struct radeon_encoder_mst *mst_enc = radeon_encoder->enc_priv;
struct radeon_connector *radeon_connector = radeon_mst_find_connector(&radeon_encoder->base);
int dp_clock;
struct radeon_connector_atom_dig *dig_connector = mst_enc->connector->con_priv;
if (radeon_connector) {
radeon_connector->pixelclock_for_modeset = mode->clock;
if (radeon_connector->base.display_info.bpc)
radeon_crtc->bpc = radeon_connector->base.display_info.bpc;
else
radeon_crtc->bpc = 8;
}
DRM_DEBUG_KMS("dp_clock %p %d\n", dig_connector, dig_connector->dp_clock);
dp_clock = dig_connector->dp_clock;
radeon_crtc->ss_enabled =
radeon_atombios_get_asic_ss_info(rdev, &radeon_crtc->ss,
ASIC_INTERNAL_SS_ON_DP,
dp_clock);
}
static void
radeon_mst_encoder_dpms(struct drm_encoder *encoder, int mode)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder, *primary;
struct radeon_encoder_mst *mst_enc;
struct radeon_encoder_atom_dig *dig_enc;
struct radeon_connector *radeon_connector;
struct drm_crtc *crtc;
struct radeon_crtc *radeon_crtc;
int ret, slots;
if (!ASIC_IS_DCE5(rdev)) {
DRM_ERROR("got mst dpms on non-DCE5\n");
return;
}
radeon_connector = radeon_mst_find_connector(encoder);
if (!radeon_connector)
return;
radeon_encoder = to_radeon_encoder(encoder);
mst_enc = radeon_encoder->enc_priv;
primary = mst_enc->primary;
dig_enc = primary->enc_priv;
crtc = encoder->crtc;
DRM_DEBUG_KMS("got connector %d\n", dig_enc->active_mst_links);
switch (mode) {
case DRM_MODE_DPMS_ON:
dig_enc->active_mst_links++;
radeon_crtc = to_radeon_crtc(crtc);
if (dig_enc->active_mst_links == 1) {
mst_enc->fe = dig_enc->dig_encoder;
mst_enc->fe_from_be = true;
atombios_set_mst_encoder_crtc_source(encoder, mst_enc->fe);
atombios_dig_encoder_setup(&primary->base, ATOM_ENCODER_CMD_SETUP, 0);
atombios_dig_transmitter_setup2(&primary->base, ATOM_TRANSMITTER_ACTION_ENABLE,
0, 0, dig_enc->dig_encoder);
if (radeon_dp_needs_link_train(mst_enc->connector) ||
dig_enc->active_mst_links == 1) {
radeon_dp_link_train(&primary->base, &mst_enc->connector->base);
}
} else {
mst_enc->fe = radeon_atom_pick_dig_encoder(encoder, radeon_crtc->crtc_id);
if (mst_enc->fe == -1)
DRM_ERROR("failed to get frontend for dig encoder\n");
mst_enc->fe_from_be = false;
atombios_set_mst_encoder_crtc_source(encoder, mst_enc->fe);
}
DRM_DEBUG_KMS("dig encoder is %d %d %d\n", dig_enc->dig_encoder,
dig_enc->linkb, radeon_crtc->crtc_id);
ret = drm_dp_mst_allocate_vcpi(&radeon_connector->mst_port->mst_mgr,
radeon_connector->port,
mst_enc->pbn, &slots);
ret = drm_dp_update_payload_part1(&radeon_connector->mst_port->mst_mgr);
radeon_dp_mst_set_be_cntl(primary, mst_enc,
radeon_connector->mst_port->hpd.hpd, true);
mst_enc->enc_active = true;
radeon_dp_mst_update_stream_attribs(radeon_connector->mst_port, primary);
radeon_dp_mst_set_vcp_size(radeon_encoder, slots, 0);
atombios_dig_encoder_setup2(&primary->base, ATOM_ENCODER_CMD_DP_VIDEO_ON, 0,
mst_enc->fe);
ret = drm_dp_check_act_status(&radeon_connector->mst_port->mst_mgr);
ret = drm_dp_update_payload_part2(&radeon_connector->mst_port->mst_mgr);
break;
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF:
DRM_ERROR("DPMS OFF %d\n", dig_enc->active_mst_links);
if (!mst_enc->enc_active)
return;
drm_dp_mst_reset_vcpi_slots(&radeon_connector->mst_port->mst_mgr, mst_enc->port);
ret = drm_dp_update_payload_part1(&radeon_connector->mst_port->mst_mgr);
drm_dp_check_act_status(&radeon_connector->mst_port->mst_mgr);
/* and this can also fail */
drm_dp_update_payload_part2(&radeon_connector->mst_port->mst_mgr);
drm_dp_mst_deallocate_vcpi(&radeon_connector->mst_port->mst_mgr, mst_enc->port);
mst_enc->enc_active = false;
radeon_dp_mst_update_stream_attribs(radeon_connector->mst_port, primary);
radeon_dp_mst_set_be_cntl(primary, mst_enc,
radeon_connector->mst_port->hpd.hpd, false);
atombios_dig_encoder_setup2(&primary->base, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0,
mst_enc->fe);
if (!mst_enc->fe_from_be)
radeon_atom_release_dig_encoder(rdev, mst_enc->fe);
mst_enc->fe_from_be = false;
dig_enc->active_mst_links--;
if (dig_enc->active_mst_links == 0) {
/* drop link */
}
break;
}
}
static bool radeon_mst_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
struct radeon_encoder_mst *mst_enc;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
int bpp = 24;
mst_enc = radeon_encoder->enc_priv;
mst_enc->pbn = drm_dp_calc_pbn_mode(adjusted_mode->clock, bpp);
mst_enc->primary->active_device = mst_enc->primary->devices & mst_enc->connector->devices;
DRM_DEBUG_KMS("setting active device to %08x from %08x %08x for encoder %d\n",
mst_enc->primary->active_device, mst_enc->primary->devices,
mst_enc->connector->devices, mst_enc->primary->base.encoder_type);
drm_mode_set_crtcinfo(adjusted_mode, 0);
{
struct radeon_connector_atom_dig *dig_connector;
dig_connector = mst_enc->connector->con_priv;
dig_connector->dp_lane_count = drm_dp_max_lane_count(dig_connector->dpcd);
dig_connector->dp_clock = radeon_dp_get_max_link_rate(&mst_enc->connector->base,
dig_connector->dpcd);
DRM_DEBUG_KMS("dig clock %p %d %d\n", dig_connector,
dig_connector->dp_lane_count, dig_connector->dp_clock);
}
return true;
}
static void radeon_mst_encoder_prepare(struct drm_encoder *encoder)
{
struct radeon_connector *radeon_connector;
struct radeon_encoder *radeon_encoder, *primary;
struct radeon_encoder_mst *mst_enc;
struct radeon_encoder_atom_dig *dig_enc;
radeon_connector = radeon_mst_find_connector(encoder);
if (!radeon_connector) {
DRM_DEBUG_KMS("failed to find connector %p\n", encoder);
return;
}
radeon_encoder = to_radeon_encoder(encoder);
radeon_mst_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
mst_enc = radeon_encoder->enc_priv;
primary = mst_enc->primary;
dig_enc = primary->enc_priv;
mst_enc->port = radeon_connector->port;
if (dig_enc->dig_encoder == -1) {
dig_enc->dig_encoder = radeon_atom_pick_dig_encoder(&primary->base, -1);
primary->offset = radeon_atom_set_enc_offset(dig_enc->dig_encoder);
atombios_set_mst_encoder_crtc_source(encoder, dig_enc->dig_encoder);
}
DRM_DEBUG_KMS("%d %d\n", dig_enc->dig_encoder, primary->offset);
}
static void
radeon_mst_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
DRM_DEBUG_KMS("\n");
}
static void radeon_mst_encoder_commit(struct drm_encoder *encoder)
{
radeon_mst_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
DRM_DEBUG_KMS("\n");
}
static const struct drm_encoder_helper_funcs radeon_mst_helper_funcs = {
.dpms = radeon_mst_encoder_dpms,
.mode_fixup = radeon_mst_mode_fixup,
.prepare = radeon_mst_encoder_prepare,
.mode_set = radeon_mst_encoder_mode_set,
.commit = radeon_mst_encoder_commit,
};
void radeon_dp_mst_encoder_destroy(struct drm_encoder *encoder)
{
drm_encoder_cleanup(encoder);
kfree(encoder);
}
static const struct drm_encoder_funcs radeon_dp_mst_enc_funcs = {
.destroy = radeon_dp_mst_encoder_destroy,
};
static struct radeon_encoder *
radeon_dp_create_fake_mst_encoder(struct radeon_connector *connector)
{
struct drm_device *dev = connector->base.dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder;
struct radeon_encoder_mst *mst_enc;
struct drm_encoder *encoder;
struct drm_connector_helper_funcs *connector_funcs = connector->base.helper_private;
struct drm_encoder *enc_master = connector_funcs->best_encoder(&connector->base);
DRM_DEBUG_KMS("enc master is %p\n", enc_master);
radeon_encoder = kzalloc(sizeof(*radeon_encoder), GFP_KERNEL);
if (!radeon_encoder)
return NULL;
radeon_encoder->enc_priv = kzalloc(sizeof(*mst_enc), GFP_KERNEL);
if (!radeon_encoder->enc_priv) {
kfree(radeon_encoder);
return NULL;
}
encoder = &radeon_encoder->base;
switch (rdev->num_crtc) {
case 1:
encoder->possible_crtcs = 0x1;
break;
case 2:
default:
encoder->possible_crtcs = 0x3;
break;
case 4:
encoder->possible_crtcs = 0xf;
break;
case 6:
encoder->possible_crtcs = 0x3f;
break;
}
drm_encoder_init(dev, &radeon_encoder->base, &radeon_dp_mst_enc_funcs,
DRM_MODE_ENCODER_DPMST);
drm_encoder_helper_add(encoder, &radeon_mst_helper_funcs);
mst_enc = radeon_encoder->enc_priv;
mst_enc->connector = connector;
mst_enc->primary = to_radeon_encoder(enc_master);
radeon_encoder->is_mst_encoder = true;
return radeon_encoder;
}
int
radeon_dp_mst_init(struct radeon_connector *radeon_connector)
{
struct drm_device *dev = radeon_connector->base.dev;
if (!radeon_connector->ddc_bus->has_aux)
return 0;
radeon_connector->mst_mgr.cbs = &mst_cbs;
return drm_dp_mst_topology_mgr_init(&radeon_connector->mst_mgr, dev->dev,
&radeon_connector->ddc_bus->aux, 16, 6,
radeon_connector->base.base.id);
}
int
radeon_dp_mst_probe(struct radeon_connector *radeon_connector)
{
struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
int ret;
u8 msg[1];
if (dig_connector->dpcd[DP_DPCD_REV] < 0x12)
return 0;
ret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_MSTM_CAP, msg,
1);
if (ret) {
if (msg[0] & DP_MST_CAP) {
DRM_DEBUG_KMS("Sink is MST capable\n");
dig_connector->is_mst = true;
} else {
DRM_DEBUG_KMS("Sink is not MST capable\n");
dig_connector->is_mst = false;
}
}
drm_dp_mst_topology_mgr_set_mst(&radeon_connector->mst_mgr,
dig_connector->is_mst);
return dig_connector->is_mst;
}
int
radeon_dp_mst_check_status(struct radeon_connector *radeon_connector)
{
struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
int retry;
if (dig_connector->is_mst) {
u8 esi[16] = { 0 };
int dret;
int ret = 0;
bool handled;
dret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux,
DP_SINK_COUNT_ESI, esi, 8);
go_again:
if (dret == 8) {
DRM_DEBUG_KMS("got esi %02x %02x %02x\n", esi[0], esi[1], esi[2]);
ret = drm_dp_mst_hpd_irq(&radeon_connector->mst_mgr, esi, &handled);
if (handled) {
for (retry = 0; retry < 3; retry++) {
int wret;
wret = drm_dp_dpcd_write(&radeon_connector->ddc_bus->aux,
DP_SINK_COUNT_ESI + 1, &esi[1], 3);
if (wret == 3)
break;
}
dret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux,
DP_SINK_COUNT_ESI, esi, 8);
if (dret == 8) {
DRM_DEBUG_KMS("got esi2 %02x %02x %02x\n", esi[0], esi[1], esi[2]);
goto go_again;
}
} else
ret = 0;
return ret;
} else {
DRM_DEBUG_KMS("failed to get ESI - device may have failed %d\n", ret);
dig_connector->is_mst = false;
drm_dp_mst_topology_mgr_set_mst(&radeon_connector->mst_mgr,
dig_connector->is_mst);
/* send a hotplug event */
}
}
return -EINVAL;
}
#if defined(CONFIG_DEBUG_FS)
static int radeon_debugfs_mst_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *)m->private;
struct drm_device *dev = node->minor->dev;
struct drm_connector *connector;
struct radeon_connector *radeon_connector;
struct radeon_connector_atom_dig *dig_connector;
int i;
drm_modeset_lock_all(dev);
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort)
continue;
radeon_connector = to_radeon_connector(connector);
dig_connector = radeon_connector->con_priv;
if (radeon_connector->is_mst_connector)
continue;
if (!dig_connector->is_mst)
continue;
drm_dp_mst_dump_topology(m, &radeon_connector->mst_mgr);
for (i = 0; i < radeon_connector->enabled_attribs; i++)
seq_printf(m, "attrib %d: %d %d\n", i,
radeon_connector->cur_stream_attribs[i].fe,
radeon_connector->cur_stream_attribs[i].slots);
}
drm_modeset_unlock_all(dev);
return 0;
}
static struct drm_info_list radeon_debugfs_mst_list[] = {
{"radeon_mst_info", &radeon_debugfs_mst_info, 0, NULL},
};
#endif
int radeon_mst_debugfs_init(struct radeon_device *rdev)
{
#if defined(CONFIG_DEBUG_FS)
return radeon_debugfs_add_files(rdev, radeon_debugfs_mst_list, 1);
#endif
return 0;
}

View File

@ -190,6 +190,8 @@ int radeon_deep_color = 0;
int radeon_use_pflipirq = 2;
int radeon_bapm = -1;
int radeon_backlight = -1;
int radeon_auxch = -1;
int radeon_mst = 0;
MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers");
module_param_named(no_wb, radeon_no_wb, int, 0444);
@ -239,7 +241,7 @@ module_param_named(pcie_gen2, radeon_pcie_gen2, int, 0444);
MODULE_PARM_DESC(msi, "MSI support (1 = enable, 0 = disable, -1 = auto)");
module_param_named(msi, radeon_msi, int, 0444);
MODULE_PARM_DESC(lockup_timeout, "GPU lockup timeout in ms (defaul 10000 = 10 seconds, 0 = disable)");
MODULE_PARM_DESC(lockup_timeout, "GPU lockup timeout in ms (default 10000 = 10 seconds, 0 = disable)");
module_param_named(lockup_timeout, radeon_lockup_timeout, int, 0444);
MODULE_PARM_DESC(fastfb, "Direct FB access for IGP chips (0 = disable, 1 = enable)");
@ -275,6 +277,12 @@ module_param_named(bapm, radeon_bapm, int, 0444);
MODULE_PARM_DESC(backlight, "backlight support (1 = enable, 0 = disable, -1 = auto)");
module_param_named(backlight, radeon_backlight, int, 0444);
MODULE_PARM_DESC(auxch, "Use native auxch experimental support (1 = enable, 0 = disable, -1 = auto)");
module_param_named(auxch, radeon_auxch, int, 0444);
MODULE_PARM_DESC(mst, "DisplayPort MST experimental support (1 = enable, 0 = disable)");
module_param_named(mst, radeon_mst, int, 0444);
static struct pci_device_id pciidlist[] = {
radeon_PCI_IDS
};

View File

@ -247,7 +247,16 @@ radeon_get_connector_for_encoder(struct drm_encoder *encoder)
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
radeon_connector = to_radeon_connector(connector);
if (radeon_encoder->active_device & radeon_connector->devices)
if (radeon_encoder->is_mst_encoder) {
struct radeon_encoder_mst *mst_enc;
if (!radeon_connector->is_mst_connector)
continue;
mst_enc = radeon_encoder->enc_priv;
if (mst_enc->connector == radeon_connector->mst_port)
return connector;
} else if (radeon_encoder->active_device & radeon_connector->devices)
return connector;
}
return NULL;
@ -393,6 +402,9 @@ bool radeon_dig_monitor_is_duallink(struct drm_encoder *encoder,
case DRM_MODE_CONNECTOR_DVID:
case DRM_MODE_CONNECTOR_HDMIA:
case DRM_MODE_CONNECTOR_DisplayPort:
if (radeon_connector->is_mst_connector)
return false;
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))

View File

@ -257,6 +257,7 @@ static int radeonfb_create(struct drm_fb_helper *helper,
}
info->par = rfbdev;
info->skip_vt_switch = true;
ret = radeon_framebuffer_init(rdev->ddev, &rfbdev->rfb, &mode_cmd, gobj);
if (ret) {
@ -434,3 +435,13 @@ bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj)
return true;
return false;
}
void radeon_fb_add_connector(struct radeon_device *rdev, struct drm_connector *connector)
{
drm_fb_helper_add_one_connector(&rdev->mode_info.rfbdev->helper, connector);
}
void radeon_fb_remove_connector(struct radeon_device *rdev, struct drm_connector *connector)
{
drm_fb_helper_remove_one_connector(&rdev->mode_info.rfbdev->helper, connector);
}

View File

@ -87,6 +87,20 @@ static void radeon_hotplug_work_func(struct work_struct *work)
drm_helper_hpd_irq_event(dev);
}
static void radeon_dp_work_func(struct work_struct *work)
{
struct radeon_device *rdev = container_of(work, struct radeon_device,
dp_work);
struct drm_device *dev = rdev->ddev;
struct drm_mode_config *mode_config = &dev->mode_config;
struct drm_connector *connector;
/* this should take a mutex */
if (mode_config->num_connector) {
list_for_each_entry(connector, &mode_config->connector_list, head)
radeon_connector_hotplug(connector);
}
}
/**
* radeon_driver_irq_preinstall_kms - drm irq preinstall callback
*
@ -276,6 +290,7 @@ int radeon_irq_kms_init(struct radeon_device *rdev)
}
INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func);
INIT_WORK(&rdev->dp_work, radeon_dp_work_func);
INIT_WORK(&rdev->audio_work, r600_audio_update_hdmi);
rdev->irq.installed = true;

View File

@ -547,6 +547,35 @@ static int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file
else
*value = 1;
break;
case RADEON_INFO_CURRENT_GPU_TEMP:
/* get temperature in millidegrees C */
if (rdev->asic->pm.get_temperature)
*value = radeon_get_temperature(rdev);
else
*value = 0;
break;
case RADEON_INFO_CURRENT_GPU_SCLK:
/* get sclk in Mhz */
if (rdev->pm.dpm_enabled)
*value = radeon_dpm_get_current_sclk(rdev) / 100;
else
*value = rdev->pm.current_sclk / 100;
break;
case RADEON_INFO_CURRENT_GPU_MCLK:
/* get mclk in Mhz */
if (rdev->pm.dpm_enabled)
*value = radeon_dpm_get_current_mclk(rdev) / 100;
else
*value = rdev->pm.current_mclk / 100;
break;
case RADEON_INFO_READ_REG:
if (copy_from_user(value, value_ptr, sizeof(uint32_t))) {
DRM_ERROR("copy_from_user %s:%u\n", __func__, __LINE__);
return -EFAULT;
}
if (radeon_get_allowed_info_register(rdev, *value, value))
return -EINVAL;
break;
default:
DRM_DEBUG_KMS("Invalid request %d\n", info->request);
return -EINVAL;

View File

@ -33,6 +33,7 @@
#include <drm/drm_crtc.h>
#include <drm/drm_edid.h>
#include <drm/drm_dp_helper.h>
#include <drm/drm_dp_mst_helper.h>
#include <drm/drm_fixed.h>
#include <drm/drm_crtc_helper.h>
#include <linux/i2c.h>
@ -85,6 +86,13 @@ enum radeon_hpd_id {
RADEON_HPD_NONE = 0xff,
};
enum radeon_output_csc {
RADEON_OUTPUT_CSC_BYPASS = 0,
RADEON_OUTPUT_CSC_TVRGB = 1,
RADEON_OUTPUT_CSC_YCBCR601 = 2,
RADEON_OUTPUT_CSC_YCBCR709 = 3,
};
#define RADEON_MAX_I2C_BUS 16
/* radeon gpio-based i2c
@ -255,6 +263,8 @@ struct radeon_mode_info {
struct drm_property *audio_property;
/* FMT dithering */
struct drm_property *dither_property;
/* Output CSC */
struct drm_property *output_csc_property;
/* hardcoded DFP edid from BIOS */
struct edid *bios_hardcoded_edid;
int bios_hardcoded_edid_size;
@ -265,6 +275,9 @@ struct radeon_mode_info {
u16 firmware_flags;
/* pointer to backlight encoder */
struct radeon_encoder *bl_encoder;
/* bitmask for active encoder frontends */
uint32_t active_encoders;
};
#define RADEON_MAX_BL_LEVEL 0xFF
@ -357,6 +370,7 @@ struct radeon_crtc {
u32 wm_low;
u32 wm_high;
struct drm_display_mode hw_mode;
enum radeon_output_csc output_csc;
};
struct radeon_encoder_primary_dac {
@ -426,12 +440,24 @@ struct radeon_encoder_atom_dig {
uint8_t backlight_level;
int panel_mode;
struct radeon_afmt *afmt;
int active_mst_links;
};
struct radeon_encoder_atom_dac {
enum radeon_tv_std tv_std;
};
struct radeon_encoder_mst {
int crtc;
struct radeon_encoder *primary;
struct radeon_connector *connector;
struct drm_dp_mst_port *port;
int pbn;
int fe;
bool fe_from_be;
bool enc_active;
};
struct radeon_encoder {
struct drm_encoder base;
uint32_t encoder_enum;
@ -450,6 +476,11 @@ struct radeon_encoder {
bool is_ext_encoder;
u16 caps;
struct radeon_audio_funcs *audio;
enum radeon_output_csc output_csc;
bool can_mst;
uint32_t offset;
bool is_mst_encoder;
/* front end for this mst encoder */
};
struct radeon_connector_atom_dig {
@ -460,6 +491,7 @@ struct radeon_connector_atom_dig {
int dp_clock;
int dp_lane_count;
bool edp_on;
bool is_mst;
};
struct radeon_gpio_rec {
@ -503,6 +535,11 @@ enum radeon_connector_dither {
RADEON_FMT_DITHER_ENABLE = 1,
};
struct stream_attribs {
uint16_t fe;
uint16_t slots;
};
struct radeon_connector {
struct drm_connector base;
uint32_t connector_id;
@ -524,6 +561,14 @@ struct radeon_connector {
enum radeon_connector_audio audio;
enum radeon_connector_dither dither;
int pixelclock_for_modeset;
bool is_mst_connector;
struct radeon_connector *mst_port;
struct drm_dp_mst_port *port;
struct drm_dp_mst_topology_mgr mst_mgr;
struct radeon_encoder *mst_encoder;
struct stream_attribs cur_stream_attribs[6];
int enabled_attribs;
};
struct radeon_framebuffer {
@ -708,15 +753,26 @@ extern u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector);
extern bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector);
extern int radeon_dp_get_panel_mode(struct drm_encoder *encoder,
struct drm_connector *connector);
int radeon_dp_get_max_link_rate(struct drm_connector *connector,
u8 *dpcd);
extern void radeon_dp_set_rx_power_state(struct drm_connector *connector,
u8 power_state);
extern void radeon_dp_aux_init(struct radeon_connector *radeon_connector);
extern ssize_t
radeon_dp_aux_transfer_native(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg);
extern void atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode);
extern void atombios_dig_encoder_setup2(struct drm_encoder *encoder, int action, int panel_mode, int enc_override);
extern void radeon_atom_encoder_init(struct radeon_device *rdev);
extern void radeon_atom_disp_eng_pll_init(struct radeon_device *rdev);
extern void atombios_dig_transmitter_setup(struct drm_encoder *encoder,
int action, uint8_t lane_num,
uint8_t lane_set);
extern void atombios_dig_transmitter_setup2(struct drm_encoder *encoder,
int action, uint8_t lane_num,
uint8_t lane_set, int fe);
extern void atombios_set_mst_encoder_crtc_source(struct drm_encoder *encoder,
int fe);
extern void radeon_atom_ext_encoder_setup_ddc(struct drm_encoder *encoder);
extern struct drm_encoder *radeon_get_external_encoder(struct drm_encoder *encoder);
void radeon_atom_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le);
@ -929,7 +985,23 @@ bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj)
void radeon_fb_output_poll_changed(struct radeon_device *rdev);
void radeon_crtc_handle_vblank(struct radeon_device *rdev, int crtc_id);
void radeon_fb_add_connector(struct radeon_device *rdev, struct drm_connector *connector);
void radeon_fb_remove_connector(struct radeon_device *rdev, struct drm_connector *connector);
void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id);
int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bool tiled);
/* mst */
int radeon_dp_mst_init(struct radeon_connector *radeon_connector);
int radeon_dp_mst_probe(struct radeon_connector *radeon_connector);
int radeon_dp_mst_check_status(struct radeon_connector *radeon_connector);
int radeon_mst_debugfs_init(struct radeon_device *rdev);
void radeon_dp_mst_prepare_pll(struct drm_crtc *crtc, struct drm_display_mode *mode);
void radeon_setup_mst_connector(struct drm_device *dev);
int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder, int fe_idx);
void radeon_atom_release_dig_encoder(struct radeon_device *rdev, int enc_idx);
#endif

View File

@ -1001,6 +1001,28 @@ void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rde
ps->sclk_high, ps->max_voltage);
}
/* get the current sclk in 10 khz units */
u32 rs780_dpm_get_current_sclk(struct radeon_device *rdev)
{
u32 current_fb_div = RREG32(FVTHROT_STATUS_REG0) & CURRENT_FEEDBACK_DIV_MASK;
u32 func_cntl = RREG32(CG_SPLL_FUNC_CNTL);
u32 ref_div = ((func_cntl & SPLL_REF_DIV_MASK) >> SPLL_REF_DIV_SHIFT) + 1;
u32 post_div = ((func_cntl & SPLL_SW_HILEN_MASK) >> SPLL_SW_HILEN_SHIFT) + 1 +
((func_cntl & SPLL_SW_LOLEN_MASK) >> SPLL_SW_LOLEN_SHIFT) + 1;
u32 sclk = (rdev->clock.spll.reference_freq * current_fb_div) /
(post_div * ref_div);
return sclk;
}
/* get the current mclk in 10 khz units */
u32 rs780_dpm_get_current_mclk(struct radeon_device *rdev)
{
struct igp_power_info *pi = rs780_get_pi(rdev);
return pi->bootup_uma_clk;
}
int rs780_dpm_force_performance_level(struct radeon_device *rdev,
enum radeon_dpm_forced_level level)
{

View File

@ -2050,6 +2050,52 @@ void rv6xx_dpm_debugfs_print_current_performance_level(struct radeon_device *rde
}
}
/* get the current sclk in 10 khz units */
u32 rv6xx_dpm_get_current_sclk(struct radeon_device *rdev)
{
struct radeon_ps *rps = rdev->pm.dpm.current_ps;
struct rv6xx_ps *ps = rv6xx_get_ps(rps);
struct rv6xx_pl *pl;
u32 current_index =
(RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >>
CURRENT_PROFILE_INDEX_SHIFT;
if (current_index > 2) {
return 0;
} else {
if (current_index == 0)
pl = &ps->low;
else if (current_index == 1)
pl = &ps->medium;
else /* current_index == 2 */
pl = &ps->high;
return pl->sclk;
}
}
/* get the current mclk in 10 khz units */
u32 rv6xx_dpm_get_current_mclk(struct radeon_device *rdev)
{
struct radeon_ps *rps = rdev->pm.dpm.current_ps;
struct rv6xx_ps *ps = rv6xx_get_ps(rps);
struct rv6xx_pl *pl;
u32 current_index =
(RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >>
CURRENT_PROFILE_INDEX_SHIFT;
if (current_index > 2) {
return 0;
} else {
if (current_index == 0)
pl = &ps->low;
else if (current_index == 1)
pl = &ps->medium;
else /* current_index == 2 */
pl = &ps->high;
return pl->mclk;
}
}
void rv6xx_dpm_fini(struct radeon_device *rdev)
{
int i;

View File

@ -2492,6 +2492,50 @@ void rv770_dpm_debugfs_print_current_performance_level(struct radeon_device *rde
}
}
u32 rv770_dpm_get_current_sclk(struct radeon_device *rdev)
{
struct radeon_ps *rps = rdev->pm.dpm.current_ps;
struct rv7xx_ps *ps = rv770_get_ps(rps);
struct rv7xx_pl *pl;
u32 current_index =
(RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >>
CURRENT_PROFILE_INDEX_SHIFT;
if (current_index > 2) {
return 0;
} else {
if (current_index == 0)
pl = &ps->low;
else if (current_index == 1)
pl = &ps->medium;
else /* current_index == 2 */
pl = &ps->high;
return pl->sclk;
}
}
u32 rv770_dpm_get_current_mclk(struct radeon_device *rdev)
{
struct radeon_ps *rps = rdev->pm.dpm.current_ps;
struct rv7xx_ps *ps = rv770_get_ps(rps);
struct rv7xx_pl *pl;
u32 current_index =
(RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >>
CURRENT_PROFILE_INDEX_SHIFT;
if (current_index > 2) {
return 0;
} else {
if (current_index == 0)
pl = &ps->low;
else if (current_index == 1)
pl = &ps->medium;
else /* current_index == 2 */
pl = &ps->high;
return pl->mclk;
}
}
void rv770_dpm_fini(struct radeon_device *rdev)
{
int i;

View File

@ -1264,6 +1264,36 @@ static void si_init_golden_registers(struct radeon_device *rdev)
}
}
/**
* si_get_allowed_info_register - fetch the register for the info ioctl
*
* @rdev: radeon_device pointer
* @reg: register offset in bytes
* @val: register value
*
* Returns 0 for success or -EINVAL for an invalid register
*
*/
int si_get_allowed_info_register(struct radeon_device *rdev,
u32 reg, u32 *val)
{
switch (reg) {
case GRBM_STATUS:
case GRBM_STATUS2:
case GRBM_STATUS_SE0:
case GRBM_STATUS_SE1:
case SRBM_STATUS:
case SRBM_STATUS2:
case (DMA_STATUS_REG + DMA0_REGISTER_OFFSET):
case (DMA_STATUS_REG + DMA1_REGISTER_OFFSET):
case UVD_STATUS:
*val = RREG32(reg);
return 0;
default:
return -EINVAL;
}
}
#define PCIE_BUS_CLK 10000
#define TCLK (PCIE_BUS_CLK / 10)
@ -6055,12 +6085,12 @@ int si_irq_set(struct radeon_device *rdev)
(CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
if (!ASIC_IS_NODCE(rdev)) {
hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN;
hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN;
hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~DC_HPDx_INT_EN;
hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~DC_HPDx_INT_EN;
hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN;
hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN;
hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~(DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN);
}
dma_cntl = RREG32(DMA_CNTL + DMA0_REGISTER_OFFSET) & ~TRAP_ENABLE;
@ -6123,27 +6153,27 @@ int si_irq_set(struct radeon_device *rdev)
}
if (rdev->irq.hpd[0]) {
DRM_DEBUG("si_irq_set: hpd 1\n");
hpd1 |= DC_HPDx_INT_EN;
hpd1 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
}
if (rdev->irq.hpd[1]) {
DRM_DEBUG("si_irq_set: hpd 2\n");
hpd2 |= DC_HPDx_INT_EN;
hpd2 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
}
if (rdev->irq.hpd[2]) {
DRM_DEBUG("si_irq_set: hpd 3\n");
hpd3 |= DC_HPDx_INT_EN;
hpd3 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
}
if (rdev->irq.hpd[3]) {
DRM_DEBUG("si_irq_set: hpd 4\n");
hpd4 |= DC_HPDx_INT_EN;
hpd4 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
}
if (rdev->irq.hpd[4]) {
DRM_DEBUG("si_irq_set: hpd 5\n");
hpd5 |= DC_HPDx_INT_EN;
hpd5 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
}
if (rdev->irq.hpd[5]) {
DRM_DEBUG("si_irq_set: hpd 6\n");
hpd6 |= DC_HPDx_INT_EN;
hpd6 |= DC_HPDx_INT_EN | DC_HPDx_RX_INT_EN;
}
WREG32(CP_INT_CNTL_RING0, cp_int_cntl);
@ -6306,6 +6336,37 @@ static inline void si_irq_ack(struct radeon_device *rdev)
tmp |= DC_HPDx_INT_ACK;
WREG32(DC_HPD6_INT_CONTROL, tmp);
}
if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT) {
tmp = RREG32(DC_HPD1_INT_CONTROL);
tmp |= DC_HPDx_RX_INT_ACK;
WREG32(DC_HPD1_INT_CONTROL, tmp);
}
if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT) {
tmp = RREG32(DC_HPD2_INT_CONTROL);
tmp |= DC_HPDx_RX_INT_ACK;
WREG32(DC_HPD2_INT_CONTROL, tmp);
}
if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) {
tmp = RREG32(DC_HPD3_INT_CONTROL);
tmp |= DC_HPDx_RX_INT_ACK;
WREG32(DC_HPD3_INT_CONTROL, tmp);
}
if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) {
tmp = RREG32(DC_HPD4_INT_CONTROL);
tmp |= DC_HPDx_RX_INT_ACK;
WREG32(DC_HPD4_INT_CONTROL, tmp);
}
if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) {
tmp = RREG32(DC_HPD5_INT_CONTROL);
tmp |= DC_HPDx_RX_INT_ACK;
WREG32(DC_HPD5_INT_CONTROL, tmp);
}
if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
tmp = RREG32(DC_HPD5_INT_CONTROL);
tmp |= DC_HPDx_RX_INT_ACK;
WREG32(DC_HPD6_INT_CONTROL, tmp);
}
}
static void si_irq_disable(struct radeon_device *rdev)
@ -6371,6 +6432,7 @@ int si_irq_process(struct radeon_device *rdev)
u32 src_id, src_data, ring_id;
u32 ring_index;
bool queue_hotplug = false;
bool queue_dp = false;
bool queue_thermal = false;
u32 status, addr;
@ -6611,6 +6673,48 @@ restart_ih:
DRM_DEBUG("IH: HPD6\n");
}
break;
case 6:
if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT) {
rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_RX_INTERRUPT;
queue_dp = true;
DRM_DEBUG("IH: HPD_RX 1\n");
}
break;
case 7:
if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT) {
rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT;
queue_dp = true;
DRM_DEBUG("IH: HPD_RX 2\n");
}
break;
case 8:
if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) {
rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT;
queue_dp = true;
DRM_DEBUG("IH: HPD_RX 3\n");
}
break;
case 9:
if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) {
rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT;
queue_dp = true;
DRM_DEBUG("IH: HPD_RX 4\n");
}
break;
case 10:
if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) {
rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT;
queue_dp = true;
DRM_DEBUG("IH: HPD_RX 5\n");
}
break;
case 11:
if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT;
queue_dp = true;
DRM_DEBUG("IH: HPD_RX 6\n");
}
break;
default:
DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
break;
@ -6693,6 +6797,8 @@ restart_ih:
rptr &= rdev->ih.ptr_mask;
WREG32(IH_RB_RPTR, rptr);
}
if (queue_dp)
schedule_work(&rdev->dp_work);
if (queue_hotplug)
schedule_work(&rdev->hotplug_work);
if (queue_thermal && rdev->pm.dpm_enabled)

View File

@ -6993,3 +6993,39 @@ void si_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
current_index, pl->sclk, pl->mclk, pl->vddc, pl->vddci, pl->pcie_gen + 1);
}
}
u32 si_dpm_get_current_sclk(struct radeon_device *rdev)
{
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
struct radeon_ps *rps = &eg_pi->current_rps;
struct ni_ps *ps = ni_get_ps(rps);
struct rv7xx_pl *pl;
u32 current_index =
(RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_INDEX_MASK) >>
CURRENT_STATE_INDEX_SHIFT;
if (current_index >= ps->performance_level_count) {
return 0;
} else {
pl = &ps->performance_levels[current_index];
return pl->sclk;
}
}
u32 si_dpm_get_current_mclk(struct radeon_device *rdev)
{
struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
struct radeon_ps *rps = &eg_pi->current_rps;
struct ni_ps *ps = ni_get_ps(rps);
struct rv7xx_pl *pl;
u32 current_index =
(RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_INDEX_MASK) >>
CURRENT_STATE_INDEX_SHIFT;
if (current_index >= ps->performance_level_count) {
return 0;
} else {
pl = &ps->performance_levels[current_index];
return pl->mclk;
}
}

View File

@ -1556,6 +1556,7 @@
#define UVD_UDEC_DBW_ADDR_CONFIG 0xEF54
#define UVD_RBC_RB_RPTR 0xF690
#define UVD_RBC_RB_WPTR 0xF694
#define UVD_STATUS 0xf6bc
#define UVD_CGC_CTRL 0xF4B0
# define DCM (1 << 0)

View File

@ -1837,6 +1837,34 @@ void sumo_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev
}
}
u32 sumo_dpm_get_current_sclk(struct radeon_device *rdev)
{
struct sumo_power_info *pi = sumo_get_pi(rdev);
struct radeon_ps *rps = &pi->current_rps;
struct sumo_ps *ps = sumo_get_ps(rps);
struct sumo_pl *pl;
u32 current_index =
(RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_INDEX_MASK) >>
CURR_INDEX_SHIFT;
if (current_index == BOOST_DPM_LEVEL) {
pl = &pi->boost_pl;
return pl->sclk;
} else if (current_index >= ps->num_levels) {
return 0;
} else {
pl = &ps->levels[current_index];
return pl->sclk;
}
}
u32 sumo_dpm_get_current_mclk(struct radeon_device *rdev)
{
struct sumo_power_info *pi = sumo_get_pi(rdev);
return pi->sys_info.bootup_uma_clk;
}
void sumo_dpm_fini(struct radeon_device *rdev)
{
int i;

View File

@ -1964,6 +1964,31 @@ void trinity_dpm_debugfs_print_current_performance_level(struct radeon_device *r
}
}
u32 trinity_dpm_get_current_sclk(struct radeon_device *rdev)
{
struct trinity_power_info *pi = trinity_get_pi(rdev);
struct radeon_ps *rps = &pi->current_rps;
struct trinity_ps *ps = trinity_get_ps(rps);
struct trinity_pl *pl;
u32 current_index =
(RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) >>
CURRENT_STATE_SHIFT;
if (current_index >= ps->num_levels) {
return 0;
} else {
pl = &ps->levels[current_index];
return pl->sclk;
}
}
u32 trinity_dpm_get_current_mclk(struct radeon_device *rdev)
{
struct trinity_power_info *pi = trinity_get_pi(rdev);
return pi->sys_info.bootup_uma_clk;
}
void trinity_dpm_fini(struct radeon_device *rdev)
{
int i;

View File

@ -486,6 +486,8 @@ int drm_dp_calc_pbn_mode(int clock, int bpp);
bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, int pbn, int *slots);
int drm_dp_mst_get_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port);
void drm_dp_mst_reset_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port);

View File

@ -1034,6 +1034,10 @@ struct drm_radeon_cs {
#define RADEON_INFO_VRAM_USAGE 0x1e
#define RADEON_INFO_GTT_USAGE 0x1f
#define RADEON_INFO_ACTIVE_CU_COUNT 0x20
#define RADEON_INFO_CURRENT_GPU_TEMP 0x21
#define RADEON_INFO_CURRENT_GPU_SCLK 0x22
#define RADEON_INFO_CURRENT_GPU_MCLK 0x23
#define RADEON_INFO_READ_REG 0x24
struct drm_radeon_info {
uint32_t request;