diff options
Diffstat (limited to 'drivers')
41 files changed, 2402 insertions, 85 deletions
| diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 9a5b68717ec8..0d15e6e30732 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -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 diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile index 4605633e253b..dea53e36a2ef 100644 --- a/drivers/gpu/drm/radeon/Makefile +++ b/drivers/gpu/drm/radeon/Makefile @@ -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 diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 86807ee91bd1..dac78ad24b31 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -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)) diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 8d74de82456e..3e3290c203c6 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -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; diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index c39c1d0d9d4e..f57c1ab617bc 100644 --- a/drivers/gpu/drm/radeon/atombios_encoders.c +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -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 */ diff --git a/drivers/gpu/drm/radeon/btc_dpm.c b/drivers/gpu/drm/radeon/btc_dpm.c index db08f17be76b..69556f5e247e 100644 --- a/drivers/gpu/drm/radeon/btc_dpm.c +++ b/drivers/gpu/drm/radeon/btc_dpm.c @@ -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;  	}  } diff --git a/drivers/gpu/drm/radeon/ci_dpm.c b/drivers/gpu/drm/radeon/ci_dpm.c index bcd2f1fe803f..8730562323a8 100644 --- a/drivers/gpu/drm/radeon/ci_dpm.c +++ b/drivers/gpu/drm/radeon/ci_dpm.c @@ -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); diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index 3e670d344a20..28faea9996f9 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -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) { diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h index c648e1996dab..4870df898230 100644 --- a/drivers/gpu/drm/radeon/cikd.h +++ b/drivers/gpu/drm/radeon/cikd.h @@ -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 diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 973df064c14f..f848acfd3fc8 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -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) diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index a8d1d5240fcb..4aa5f755572b 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -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 diff --git a/drivers/gpu/drm/radeon/kv_dpm.c b/drivers/gpu/drm/radeon/kv_dpm.c index 0e236d067d66..2d71da448487 100644 --- a/drivers/gpu/drm/radeon/kv_dpm.c +++ b/drivers/gpu/drm/radeon/kv_dpm.c @@ -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)  { diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index dab00812abaa..e8a496ff007e 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -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; diff --git a/drivers/gpu/drm/radeon/ni_dpm.c b/drivers/gpu/drm/radeon/ni_dpm.c index 7bc9f8d9804a..c3d531a1114b 100644 --- a/drivers/gpu/drm/radeon/ni_dpm.c +++ b/drivers/gpu/drm/radeon/ni_dpm.c @@ -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); diff --git a/drivers/gpu/drm/radeon/ni_reg.h b/drivers/gpu/drm/radeon/ni_reg.h index 5db7b7d6feb0..da310a70c0f0 100644 --- a/drivers/gpu/drm/radeon/ni_reg.h +++ b/drivers/gpu/drm/radeon/ni_reg.h @@ -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 diff --git a/drivers/gpu/drm/radeon/nid.h b/drivers/gpu/drm/radeon/nid.h index 6b44580440d0..3b290838918c 100644 --- a/drivers/gpu/drm/radeon/nid.h +++ b/drivers/gpu/drm/radeon/nid.h @@ -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 diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 2fcad344492f..8f6d862a1882 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -109,6 +109,32 @@ 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   *   * @rdev: radeon_device pointer diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 5587603b4a89..35ab65d53cc1 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -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 */ diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index c0ecd128b14b..fafd8ce4d58f 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -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, diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 72bdd3bf0d8e..cf0a90bb61ca 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -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, diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index fc1b3f34cf18..8f285244c839 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -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;  } diff --git a/drivers/gpu/drm/radeon/radeon_audio.c b/drivers/gpu/drm/radeon/radeon_audio.c index b21ef69a34ac..48d49e651a30 100644 --- a/drivers/gpu/drm/radeon/radeon_audio.c +++ b/drivers/gpu/drm/radeon/radeon_audio.c @@ -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); diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 27def67cb6be..7ffa7d5563b9 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -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); +	} +} diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index bd7519fdd3f4..b7ca4c514621 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -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 diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 913fafa597ad..d2e9e9efc159 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -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;  } diff --git a/drivers/gpu/drm/radeon/radeon_dp_auxch.c b/drivers/gpu/drm/radeon/radeon_dp_auxch.c new file mode 100644 index 000000000000..bf1fecc6cceb --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_dp_auxch.c @@ -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; +} diff --git a/drivers/gpu/drm/radeon/radeon_dp_mst.c b/drivers/gpu/drm/radeon/radeon_dp_mst.c new file mode 100644 index 000000000000..5952ff2bb647 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_dp_mst.c @@ -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; +} diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 5d684beb48d3..d688f6cd1ae4 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -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  }; diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 3a297037cc17..ef99917f000d 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -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)) diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index ea276ff6d174..aeb676708e60 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -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); +} diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index 00fc59762e0d..7162c935371c 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -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; diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 686411e4e4f6..7b2a7335cc5d 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -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; diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 920a8be8abad..fa91a17b81b6 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -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 diff --git a/drivers/gpu/drm/radeon/rs780_dpm.c b/drivers/gpu/drm/radeon/rs780_dpm.c index 9031f4b69824..cb0afe78abed 100644 --- a/drivers/gpu/drm/radeon/rs780_dpm.c +++ b/drivers/gpu/drm/radeon/rs780_dpm.c @@ -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)  { diff --git a/drivers/gpu/drm/radeon/rv6xx_dpm.c b/drivers/gpu/drm/radeon/rv6xx_dpm.c index 6a5c233361e9..97e5a6f1ce58 100644 --- a/drivers/gpu/drm/radeon/rv6xx_dpm.c +++ b/drivers/gpu/drm/radeon/rv6xx_dpm.c @@ -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; diff --git a/drivers/gpu/drm/radeon/rv770_dpm.c b/drivers/gpu/drm/radeon/rv770_dpm.c index 306732641b23..b9c770745a7a 100644 --- a/drivers/gpu/drm/radeon/rv770_dpm.c +++ b/drivers/gpu/drm/radeon/rv770_dpm.c @@ -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; diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index e088e5558da0..86e75798320f 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -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) diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index 7be11651b7e6..b35bccfeef79 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -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; +	} +} diff --git a/drivers/gpu/drm/radeon/sid.h b/drivers/gpu/drm/radeon/sid.h index 99a9835c9f61..3afac3013983 100644 --- a/drivers/gpu/drm/radeon/sid.h +++ b/drivers/gpu/drm/radeon/sid.h @@ -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) diff --git a/drivers/gpu/drm/radeon/sumo_dpm.c b/drivers/gpu/drm/radeon/sumo_dpm.c index 25fd4ced36c8..cd0862809adf 100644 --- a/drivers/gpu/drm/radeon/sumo_dpm.c +++ b/drivers/gpu/drm/radeon/sumo_dpm.c @@ -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; diff --git a/drivers/gpu/drm/radeon/trinity_dpm.c b/drivers/gpu/drm/radeon/trinity_dpm.c index 38dacb7a3689..a5b02c575d77 100644 --- a/drivers/gpu/drm/radeon/trinity_dpm.c +++ b/drivers/gpu/drm/radeon/trinity_dpm.c @@ -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; |