diff options
Diffstat (limited to 'drivers/gpu/drm/radeon')
32 files changed, 861 insertions, 441 deletions
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 9e6f76fec52..e721e3087b9 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -258,8 +258,7 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode)  		radeon_crtc->enabled = true;  		/* adjust pm to dpms changes BEFORE enabling crtcs */  		radeon_pm_compute_clocks(rdev); -		/* disable crtc pair power gating before programming */ -		if (ASIC_IS_DCE6(rdev)) +		if (ASIC_IS_DCE6(rdev) && !radeon_crtc->in_mode_set)  			atombios_powergate_crtc(crtc, ATOM_DISABLE);  		atombios_enable_crtc(crtc, ATOM_ENABLE);  		if (ASIC_IS_DCE3(rdev) && !ASIC_IS_DCE6(rdev)) @@ -278,25 +277,8 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode)  			atombios_enable_crtc_memreq(crtc, ATOM_DISABLE);  		atombios_enable_crtc(crtc, ATOM_DISABLE);  		radeon_crtc->enabled = false; -		/* power gating is per-pair */ -		if (ASIC_IS_DCE6(rdev)) { -			struct drm_crtc *other_crtc; -			struct radeon_crtc *other_radeon_crtc; -			list_for_each_entry(other_crtc, &rdev->ddev->mode_config.crtc_list, head) { -				other_radeon_crtc = to_radeon_crtc(other_crtc); -				if (((radeon_crtc->crtc_id == 0) && (other_radeon_crtc->crtc_id == 1)) || -				    ((radeon_crtc->crtc_id == 1) && (other_radeon_crtc->crtc_id == 0)) || -				    ((radeon_crtc->crtc_id == 2) && (other_radeon_crtc->crtc_id == 3)) || -				    ((radeon_crtc->crtc_id == 3) && (other_radeon_crtc->crtc_id == 2)) || -				    ((radeon_crtc->crtc_id == 4) && (other_radeon_crtc->crtc_id == 5)) || -				    ((radeon_crtc->crtc_id == 5) && (other_radeon_crtc->crtc_id == 4))) { -					/* if both crtcs in the pair are off, enable power gating */ -					if (other_radeon_crtc->enabled == false) -						atombios_powergate_crtc(crtc, ATOM_ENABLE); -					break; -				} -			} -		} +		if (ASIC_IS_DCE6(rdev) && !radeon_crtc->in_mode_set) +			atombios_powergate_crtc(crtc, ATOM_ENABLE);  		/* adjust pm to dpms changes AFTER disabling crtcs */  		radeon_pm_compute_clocks(rdev);  		break; @@ -444,11 +426,28 @@ union atom_enable_ss {  static void atombios_crtc_program_ss(struct radeon_device *rdev,  				     int enable,  				     int pll_id, +				     int crtc_id,  				     struct radeon_atom_ss *ss)  { +	unsigned i;  	int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL);  	union atom_enable_ss args; +	if (!enable) { +		for (i = 0; i < rdev->num_crtc; i++) { +			if (rdev->mode_info.crtcs[i] && +			    rdev->mode_info.crtcs[i]->enabled && +			    i != crtc_id && +			    pll_id == rdev->mode_info.crtcs[i]->pll_id) { +				/* one other crtc is using this pll don't turn +				 * off spread spectrum as it might turn off +				 * display on active crtc +				 */ +				return; +			} +		} +	} +  	memset(&args, 0, sizeof(args));  	if (ASIC_IS_DCE5(rdev)) { @@ -1028,7 +1027,7 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode  		radeon_compute_pll_legacy(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div,  					  &ref_div, &post_div); -	atombios_crtc_program_ss(rdev, ATOM_DISABLE, radeon_crtc->pll_id, &ss); +	atombios_crtc_program_ss(rdev, ATOM_DISABLE, radeon_crtc->pll_id, radeon_crtc->crtc_id, &ss);  	atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id,  				  encoder_mode, radeon_encoder->encoder_id, mode->clock, @@ -1051,7 +1050,7 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode  			ss.step = step_size;  		} -		atombios_crtc_program_ss(rdev, ATOM_ENABLE, radeon_crtc->pll_id, &ss); +		atombios_crtc_program_ss(rdev, ATOM_ENABLE, radeon_crtc->pll_id, radeon_crtc->crtc_id, &ss);  	}  } @@ -1480,14 +1479,98 @@ static void radeon_legacy_atom_fixup(struct drm_crtc *crtc)  	}  } +/** + * radeon_get_pll_use_mask - look up a mask of which pplls are in use + * + * @crtc: drm crtc + * + * Returns the mask of which PPLLs (Pixel PLLs) are in use. + */ +static u32 radeon_get_pll_use_mask(struct drm_crtc *crtc) +{ +	struct drm_device *dev = crtc->dev; +	struct drm_crtc *test_crtc; +	struct radeon_crtc *radeon_test_crtc; +	u32 pll_in_use = 0; + +	list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { +		if (crtc == test_crtc) +			continue; + +		radeon_test_crtc = to_radeon_crtc(test_crtc); +		if (radeon_test_crtc->pll_id != ATOM_PPLL_INVALID) +			pll_in_use |= (1 << radeon_test_crtc->pll_id); +	} +	return pll_in_use; +} + +/** + * radeon_get_shared_dp_ppll - return the PPLL used by another crtc for DP + * + * @crtc: drm crtc + * + * Returns the PPLL (Pixel PLL) used by another crtc/encoder which is + * also in DP mode.  For DP, a single PPLL can be used for all DP + * crtcs/encoders. + */ +static int radeon_get_shared_dp_ppll(struct drm_crtc *crtc) +{ +	struct drm_device *dev = crtc->dev; +	struct drm_encoder *test_encoder; +	struct radeon_crtc *radeon_test_crtc; + +	list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { +		if (test_encoder->crtc && (test_encoder->crtc != crtc)) { +			if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { +				/* for DP use the same PLL for all */ +				radeon_test_crtc = to_radeon_crtc(test_encoder->crtc); +				if (radeon_test_crtc->pll_id != ATOM_PPLL_INVALID) +					return radeon_test_crtc->pll_id; +			} +		} +	} +	return ATOM_PPLL_INVALID; +} + +/** + * radeon_atom_pick_pll - Allocate a PPLL for use by the crtc. + * + * @crtc: drm crtc + * + * Returns the PPLL (Pixel PLL) to be used by the crtc.  For DP monitors + * a single PPLL can be used for all DP crtcs/encoders.  For non-DP + * monitors a dedicated PPLL must be used.  If a particular board has + * an external DP PLL, return ATOM_PPLL_INVALID to skip PLL programming + * as there is no need to program the PLL itself.  If we are not able to + * allocate a PLL, return ATOM_PPLL_INVALID to skip PLL programming to + * avoid messing up an existing monitor. + * + * Asic specific PLL information + * + * DCE 6.1 + * - PPLL2 is only available to UNIPHYA (both DP and non-DP) + * - PPLL0, PPLL1 are available for UNIPHYB/C/D/E/F (both DP and non-DP) + * + * DCE 6.0 + * - PPLL0 is available to all UNIPHY (DP only) + * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC + * + * DCE 5.0 + * - DCPLL is available to all UNIPHY (DP only) + * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC + * + * DCE 3.0/4.0/4.1 + * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC + * + */  static int radeon_atom_pick_pll(struct drm_crtc *crtc)  {  	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);  	struct drm_device *dev = crtc->dev;  	struct radeon_device *rdev = dev->dev_private;  	struct drm_encoder *test_encoder; -	struct drm_crtc *test_crtc; -	uint32_t pll_in_use = 0; +	u32 pll_in_use; +	int pll;  	if (ASIC_IS_DCE61(rdev)) {  		list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { @@ -1499,64 +1582,75 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc)  				if ((test_radeon_encoder->encoder_id ==  				     ENCODER_OBJECT_ID_INTERNAL_UNIPHY) && -				    (dig->linkb == false)) /* UNIPHY A uses PPLL2 */ +				    (dig->linkb == false)) +					/* UNIPHY A uses PPLL2 */  					return ATOM_PPLL2; +				else if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { +					/* UNIPHY B/C/D/E/F */ +					if (rdev->clock.dp_extclk) +						/* skip PPLL programming if using ext clock */ +						return ATOM_PPLL_INVALID; +					else { +						/* use the same PPLL for all DP monitors */ +						pll = radeon_get_shared_dp_ppll(crtc); +						if (pll != ATOM_PPLL_INVALID) +							return pll; +					} +				} +				break;  			}  		}  		/* UNIPHY B/C/D/E/F */ -		list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { -			struct radeon_crtc *radeon_test_crtc; - -			if (crtc == test_crtc) -				continue; - -			radeon_test_crtc = to_radeon_crtc(test_crtc); -			if ((radeon_test_crtc->pll_id == ATOM_PPLL0) || -			    (radeon_test_crtc->pll_id == ATOM_PPLL1)) -				pll_in_use |= (1 << radeon_test_crtc->pll_id); -		} -		if (!(pll_in_use & 4)) +		pll_in_use = radeon_get_pll_use_mask(crtc); +		if (!(pll_in_use & (1 << ATOM_PPLL0)))  			return ATOM_PPLL0; -		return ATOM_PPLL1; +		if (!(pll_in_use & (1 << ATOM_PPLL1))) +			return ATOM_PPLL1; +		DRM_ERROR("unable to allocate a PPLL\n"); +		return ATOM_PPLL_INVALID;  	} else if (ASIC_IS_DCE4(rdev)) {  		list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) {  			if (test_encoder->crtc && (test_encoder->crtc == crtc)) {  				/* in DP mode, the DP ref clock can come from PPLL, DCPLL, or ext clock,  				 * depending on the asic:  				 * DCE4: PPLL or ext clock -				 * DCE5: DCPLL or ext clock +				 * DCE5: PPLL, DCPLL, or ext clock +				 * DCE6: PPLL, PPLL0, or ext clock  				 *  				 * Setting ATOM_PPLL_INVALID will cause SetPixelClock to skip  				 * PPLL/DCPLL programming and only program the DP DTO for the  				 * crtc virtual pixel clock.  				 */  				if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { -					if (ASIC_IS_DCE5(rdev)) -						return ATOM_DCPLL; +					if (rdev->clock.dp_extclk) +						/* skip PPLL programming if using ext clock */ +						return ATOM_PPLL_INVALID;  					else if (ASIC_IS_DCE6(rdev)) +						/* use PPLL0 for all DP */  						return ATOM_PPLL0; -					else if (rdev->clock.dp_extclk) -						return ATOM_PPLL_INVALID; +					else if (ASIC_IS_DCE5(rdev)) +						/* use DCPLL for all DP */ +						return ATOM_DCPLL; +					else { +						/* use the same PPLL for all DP monitors */ +						pll = radeon_get_shared_dp_ppll(crtc); +						if (pll != ATOM_PPLL_INVALID) +							return pll; +					}  				} +				break;  			}  		} - -		/* otherwise, pick one of the plls */ -		list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) { -			struct radeon_crtc *radeon_test_crtc; - -			if (crtc == test_crtc) -				continue; - -			radeon_test_crtc = to_radeon_crtc(test_crtc); -			if ((radeon_test_crtc->pll_id >= ATOM_PPLL1) && -			    (radeon_test_crtc->pll_id <= ATOM_PPLL2)) -				pll_in_use |= (1 << radeon_test_crtc->pll_id); -		} -		if (!(pll_in_use & 1)) +		/* all other cases */ +		pll_in_use = radeon_get_pll_use_mask(crtc); +		if (!(pll_in_use & (1 << ATOM_PPLL2))) +			return ATOM_PPLL2; +		if (!(pll_in_use & (1 << ATOM_PPLL1)))  			return ATOM_PPLL1; -		return ATOM_PPLL2; +		DRM_ERROR("unable to allocate a PPLL\n"); +		return ATOM_PPLL_INVALID;  	} else +		/* use PPLL1 or PPLL2 */  		return radeon_crtc->crtc_id;  } @@ -1572,11 +1666,11 @@ void radeon_atom_disp_eng_pll_init(struct radeon_device *rdev)  								   ASIC_INTERNAL_SS_ON_DCPLL,  								   rdev->clock.default_dispclk);  		if (ss_enabled) -			atombios_crtc_program_ss(rdev, ATOM_DISABLE, ATOM_DCPLL, &ss); +			atombios_crtc_program_ss(rdev, ATOM_DISABLE, ATOM_DCPLL, -1, &ss);  		/* XXX: DCE5, make sure voltage, dispclk is high enough */  		atombios_crtc_set_disp_eng_pll(rdev, rdev->clock.default_dispclk);  		if (ss_enabled) -			atombios_crtc_program_ss(rdev, ATOM_ENABLE, ATOM_DCPLL, &ss); +			atombios_crtc_program_ss(rdev, ATOM_ENABLE, ATOM_DCPLL, -1, &ss);  	}  } @@ -1635,18 +1729,28 @@ static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc,  static void atombios_crtc_prepare(struct drm_crtc *crtc)  {  	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); +	struct drm_device *dev = crtc->dev; +	struct radeon_device *rdev = dev->dev_private; +	radeon_crtc->in_mode_set = true;  	/* pick pll */  	radeon_crtc->pll_id = radeon_atom_pick_pll(crtc); +	/* disable crtc pair power gating before programming */ +	if (ASIC_IS_DCE6(rdev)) +		atombios_powergate_crtc(crtc, ATOM_DISABLE); +  	atombios_lock_crtc(crtc, ATOM_ENABLE);  	atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);  }  static void atombios_crtc_commit(struct drm_crtc *crtc)  { +	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); +  	atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON);  	atombios_lock_crtc(crtc, ATOM_DISABLE); +	radeon_crtc->in_mode_set = false;  }  static void atombios_crtc_disable(struct drm_crtc *crtc) @@ -1655,9 +1759,22 @@ static void atombios_crtc_disable(struct drm_crtc *crtc)  	struct drm_device *dev = crtc->dev;  	struct radeon_device *rdev = dev->dev_private;  	struct radeon_atom_ss ss; +	int i;  	atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); +	for (i = 0; i < rdev->num_crtc; i++) { +		if (rdev->mode_info.crtcs[i] && +		    rdev->mode_info.crtcs[i]->enabled && +		    i != radeon_crtc->crtc_id && +		    radeon_crtc->pll_id == rdev->mode_info.crtcs[i]->pll_id) { +			/* one other crtc is using this pll don't turn +			 * off the pll +			 */ +			goto done; +		} +	} +  	switch (radeon_crtc->pll_id) {  	case ATOM_PPLL1:  	case ATOM_PPLL2: @@ -1674,7 +1791,8 @@ static void atombios_crtc_disable(struct drm_crtc *crtc)  	default:  		break;  	} -	radeon_crtc->pll_id = -1; +done: +	radeon_crtc->pll_id = ATOM_PPLL_INVALID;  }  static const struct drm_crtc_helper_funcs atombios_helper_funcs = { @@ -1723,6 +1841,6 @@ void radeon_atombios_init_crtc(struct drm_device *dev,  		else  			radeon_crtc->crtc_offset = 0;  	} -	radeon_crtc->pll_id = -1; +	radeon_crtc->pll_id = ATOM_PPLL_INVALID;  	drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs);  } diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 7712cf5ab33..3623b98ed3f 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -577,30 +577,25 @@ int radeon_dp_get_panel_mode(struct drm_encoder *encoder,  	struct radeon_device *rdev = dev->dev_private;  	struct radeon_connector *radeon_connector = to_radeon_connector(connector);  	int panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE; +	u16 dp_bridge = radeon_connector_encoder_get_dp_bridge_encoder_id(connector); +	u8 tmp;  	if (!ASIC_IS_DCE4(rdev))  		return panel_mode; -	if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) == -	    ENCODER_OBJECT_ID_NUTMEG) -		panel_mode = DP_PANEL_MODE_INTERNAL_DP1_MODE; -	else if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) == -		 ENCODER_OBJECT_ID_TRAVIS) { -		u8 id[6]; -		int i; -		for (i = 0; i < 6; i++) -			id[i] = radeon_read_dpcd_reg(radeon_connector, 0x503 + i); -		if (id[0] == 0x73 && -		    id[1] == 0x69 && -		    id[2] == 0x76 && -		    id[3] == 0x61 && -		    id[4] == 0x72 && -		    id[5] == 0x54) +	if (dp_bridge != ENCODER_OBJECT_ID_NONE) { +		/* DP bridge chips */ +		tmp = radeon_read_dpcd_reg(radeon_connector, DP_EDP_CONFIGURATION_CAP); +		if (tmp & 1) +			panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE; +		else if ((dp_bridge == ENCODER_OBJECT_ID_NUTMEG) || +			 (dp_bridge == ENCODER_OBJECT_ID_TRAVIS))  			panel_mode = DP_PANEL_MODE_INTERNAL_DP1_MODE;  		else -			panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE; +			panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE;  	} else if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { -		u8 tmp = radeon_read_dpcd_reg(radeon_connector, DP_EDP_CONFIGURATION_CAP); +		/* eDP */ +		tmp = radeon_read_dpcd_reg(radeon_connector, DP_EDP_CONFIGURATION_CAP);  		if (tmp & 1)  			panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE;  	} diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index f9bc27fe269..6e8803a1170 100644 --- a/drivers/gpu/drm/radeon/atombios_encoders.c +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -1379,6 +1379,8 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode)  	struct drm_device *dev = encoder->dev;  	struct radeon_device *rdev = dev->dev_private;  	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); +	struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder); +	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;  	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);  	struct radeon_connector *radeon_connector = NULL;  	struct radeon_connector_atom_dig *radeon_dig_connector = NULL; @@ -1390,19 +1392,37 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode)  	switch (mode) {  	case DRM_MODE_DPMS_ON: -		/* some early dce3.2 boards have a bug in their transmitter control table */ -		if ((rdev->family == CHIP_RV710) || (rdev->family == CHIP_RV730) || -		    ASIC_IS_DCE41(rdev) || ASIC_IS_DCE5(rdev)) { -			if (ASIC_IS_DCE6(rdev)) { -				/* It seems we need to call ATOM_ENCODER_CMD_SETUP again -				 * before reenabling encoder on DPMS ON, otherwise we never -				 * get picture -				 */ -				atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0); +		if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE5(rdev)) { +			if (!connector) +				dig->panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE; +			else +				dig->panel_mode = radeon_dp_get_panel_mode(encoder, connector); + +			/* setup and enable the encoder */ +			atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0); +			atombios_dig_encoder_setup(encoder, +						   ATOM_ENCODER_CMD_SETUP_PANEL_MODE, +						   dig->panel_mode); +			if (ext_encoder) { +				if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev)) +					atombios_external_encoder_setup(encoder, ext_encoder, +									EXTERNAL_ENCODER_ACTION_V3_ENCODER_SETUP);  			}  			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); -		} else { +		} else if (ASIC_IS_DCE4(rdev)) { +			/* setup and enable the encoder */ +			atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0); +			/* enable the transmitter */ +			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0);  			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0); +		} else { +			/* setup and enable the encoder and transmitter */ +			atombios_dig_encoder_setup(encoder, ATOM_ENABLE, 0); +			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0); +			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); +			/* some early dce3.2 boards have a bug in their transmitter control table */ +			if ((rdev->family != CHIP_RV710) || (rdev->family != CHIP_RV730)) +				atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0);  		}  		if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) {  			if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { @@ -1420,10 +1440,19 @@ 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: -		if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE5(rdev)) +		if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE5(rdev)) { +			/* disable the transmitter */  			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); -		else +		} else if (ASIC_IS_DCE4(rdev)) { +			/* disable the transmitter */ +			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT, 0, 0); +			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); +		} else { +			/* disable the encoder and transmitter */  			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT, 0, 0); +			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); +			atombios_dig_encoder_setup(encoder, ATOM_DISABLE, 0); +		}  		if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) {  			if (ASIC_IS_DCE4(rdev))  				atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0); @@ -1740,13 +1769,34 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)  	struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);  	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);  	struct drm_encoder *test_encoder; -	struct radeon_encoder_atom_dig *dig; +	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;  	uint32_t dig_enc_in_use = 0; -	/* DCE4/5 */ -	if (ASIC_IS_DCE4(rdev)) { -		dig = radeon_encoder->enc_priv; -		if (ASIC_IS_DCE41(rdev)) { +	if (ASIC_IS_DCE6(rdev)) { +		/* DCE6 */ +		switch (radeon_encoder->encoder_id) { +		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: +			if (dig->linkb) +				return 1; +			else +				return 0; +			break; +		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: +			if (dig->linkb) +				return 3; +			else +				return 2; +			break; +		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: +			if (dig->linkb) +				return 5; +			else +				return 4; +			break; +		} +	} 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) @@ -1848,10 +1898,12 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,  	struct drm_device *dev = encoder->dev;  	struct radeon_device *rdev = dev->dev_private;  	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); -	struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder);  	radeon_encoder->pixel_clock = adjusted_mode->clock; +	/* need to call this here rather than in prepare() since we need some crtc info */ +	radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); +  	if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE4(rdev)) {  		if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT))  			atombios_yuv_setup(encoder, true); @@ -1870,38 +1922,7 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,  	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:  	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:  	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: -		if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE5(rdev)) { -			struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); -			struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - -			if (!connector) -				dig->panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE; -			else -				dig->panel_mode = radeon_dp_get_panel_mode(encoder, connector); - -			/* setup and enable the encoder */ -			atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0); -			atombios_dig_encoder_setup(encoder, -						   ATOM_ENCODER_CMD_SETUP_PANEL_MODE, -						   dig->panel_mode); -		} else if (ASIC_IS_DCE4(rdev)) { -			/* disable the transmitter */ -			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); -			/* setup and enable the encoder */ -			atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0); - -			/* enable the transmitter */ -			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); -		} else { -			/* disable the encoder and transmitter */ -			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); -			atombios_dig_encoder_setup(encoder, ATOM_DISABLE, 0); - -			/* setup and enable the encoder and transmitter */ -			atombios_dig_encoder_setup(encoder, ATOM_ENABLE, 0); -			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0); -			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); -		} +		/* handled in dpms */  		break;  	case ENCODER_OBJECT_ID_INTERNAL_DDI:  	case ENCODER_OBJECT_ID_INTERNAL_DVO1: @@ -1922,14 +1943,6 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,  		break;  	} -	if (ext_encoder) { -		if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev)) -			atombios_external_encoder_setup(encoder, ext_encoder, -							EXTERNAL_ENCODER_ACTION_V3_ENCODER_SETUP); -		else -			atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE); -	} -  	atombios_apply_encoder_quirks(encoder, adjusted_mode);  	if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) { @@ -2116,7 +2129,6 @@ static void radeon_atom_encoder_prepare(struct drm_encoder *encoder)  	}  	radeon_atom_output_lock(encoder, true); -	radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);  	if (connector) {  		struct radeon_connector *radeon_connector = to_radeon_connector(connector); @@ -2137,6 +2149,7 @@ static void radeon_atom_encoder_prepare(struct drm_encoder *encoder)  static void radeon_atom_encoder_commit(struct drm_encoder *encoder)  { +	/* need to call this here as we need the crtc set up */  	radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_ON);  	radeon_atom_output_lock(encoder, false);  } @@ -2177,14 +2190,7 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder)  	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:  	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:  	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: -		if (ASIC_IS_DCE4(rdev)) -			/* disable the transmitter */ -			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); -		else { -			/* disable the encoder and transmitter */ -			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); -			atombios_dig_encoder_setup(encoder, ATOM_DISABLE, 0); -		} +		/* handled in dpms */  		break;  	case ENCODER_OBJECT_ID_INTERNAL_DDI:  	case ENCODER_OBJECT_ID_INTERNAL_DVO1: diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index e585a3b947e..e93b80a6d4e 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1229,24 +1229,8 @@ void evergreen_agp_enable(struct radeon_device *rdev)  void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save)  { -	save->vga_control[0] = RREG32(D1VGA_CONTROL); -	save->vga_control[1] = RREG32(D2VGA_CONTROL);  	save->vga_render_control = RREG32(VGA_RENDER_CONTROL);  	save->vga_hdp_control = RREG32(VGA_HDP_CONTROL); -	save->crtc_control[0] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET); -	save->crtc_control[1] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET); -	if (rdev->num_crtc >= 4) { -		save->vga_control[2] = RREG32(EVERGREEN_D3VGA_CONTROL); -		save->vga_control[3] = RREG32(EVERGREEN_D4VGA_CONTROL); -		save->crtc_control[2] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET); -		save->crtc_control[3] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET); -	} -	if (rdev->num_crtc >= 6) { -		save->vga_control[4] = RREG32(EVERGREEN_D5VGA_CONTROL); -		save->vga_control[5] = RREG32(EVERGREEN_D6VGA_CONTROL); -		save->crtc_control[4] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET); -		save->crtc_control[5] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET); -	}  	/* Stop all video */  	WREG32(VGA_RENDER_CONTROL, 0); @@ -1357,47 +1341,6 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s  	/* Unlock host access */  	WREG32(VGA_HDP_CONTROL, save->vga_hdp_control);  	mdelay(1); -	/* Restore video state */ -	WREG32(D1VGA_CONTROL, save->vga_control[0]); -	WREG32(D2VGA_CONTROL, save->vga_control[1]); -	if (rdev->num_crtc >= 4) { -		WREG32(EVERGREEN_D3VGA_CONTROL, save->vga_control[2]); -		WREG32(EVERGREEN_D4VGA_CONTROL, save->vga_control[3]); -	} -	if (rdev->num_crtc >= 6) { -		WREG32(EVERGREEN_D5VGA_CONTROL, save->vga_control[4]); -		WREG32(EVERGREEN_D6VGA_CONTROL, save->vga_control[5]); -	} -	WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 1); -	WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 1); -	if (rdev->num_crtc >= 4) { -		WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 1); -		WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 1); -	} -	if (rdev->num_crtc >= 6) { -		WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 1); -		WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 1); -	} -	WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, save->crtc_control[0]); -	WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, save->crtc_control[1]); -	if (rdev->num_crtc >= 4) { -		WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, save->crtc_control[2]); -		WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, save->crtc_control[3]); -	} -	if (rdev->num_crtc >= 6) { -		WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, save->crtc_control[4]); -		WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, save->crtc_control[5]); -	} -	WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); -	WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); -	if (rdev->num_crtc >= 4) { -		WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); -		WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); -	} -	if (rdev->num_crtc >= 6) { -		WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); -		WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); -	}  	WREG32(VGA_RENDER_CONTROL, save->vga_render_control);  } @@ -1986,10 +1929,18 @@ static void evergreen_gpu_init(struct radeon_device *rdev)  	if (rdev->flags & RADEON_IS_IGP)  		rdev->config.evergreen.tile_config |= 1 << 4;  	else { -		if ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) -			rdev->config.evergreen.tile_config |= 1 << 4; -		else +		switch ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) { +		case 0: /* four banks */  			rdev->config.evergreen.tile_config |= 0 << 4; +			break; +		case 1: /* eight banks */ +			rdev->config.evergreen.tile_config |= 1 << 4; +			break; +		case 2: /* sixteen banks */ +		default: +			rdev->config.evergreen.tile_config |= 2 << 4; +			break; +		}  	}  	rdev->config.evergreen.tile_config |= 0 << 8;  	rdev->config.evergreen.tile_config |= diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c index c16554122cc..e44a62a07fe 100644 --- a/drivers/gpu/drm/radeon/evergreen_cs.c +++ b/drivers/gpu/drm/radeon/evergreen_cs.c @@ -788,6 +788,13 @@ static int evergreen_cs_track_validate_texture(struct radeon_cs_parser *p,  	case V_030000_SQ_TEX_DIM_1D_ARRAY:  	case V_030000_SQ_TEX_DIM_2D_ARRAY:  		depth = 1; +		break; +	case V_030000_SQ_TEX_DIM_2D_MSAA: +	case V_030000_SQ_TEX_DIM_2D_ARRAY_MSAA: +		surf.nsamples = 1 << llevel; +		llevel = 0; +		depth = 1; +		break;  	case V_030000_SQ_TEX_DIM_3D:  		break;  	default: @@ -961,13 +968,15 @@ static int evergreen_cs_track_check(struct radeon_cs_parser *p)  	if (track->db_dirty) {  		/* Check stencil buffer */ -		if (G_028800_STENCIL_ENABLE(track->db_depth_control)) { +		if (G_028044_FORMAT(track->db_s_info) != V_028044_STENCIL_INVALID && +		    G_028800_STENCIL_ENABLE(track->db_depth_control)) {  			r = evergreen_cs_track_validate_stencil(p);  			if (r)  				return r;  		}  		/* Check depth buffer */ -		if (G_028800_Z_ENABLE(track->db_depth_control)) { +		if (G_028040_FORMAT(track->db_z_info) != V_028040_Z_INVALID && +		    G_028800_Z_ENABLE(track->db_depth_control)) {  			r = evergreen_cs_track_validate_depth(p);  			if (r)  				return r; diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index d3bd098e4e1..79347855d9b 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -1277,6 +1277,8 @@  #define   S_028044_FORMAT(x)                           (((x) & 0x1) << 0)  #define   G_028044_FORMAT(x)                           (((x) >> 0) & 0x1)  #define   C_028044_FORMAT                              0xFFFFFFFE +#define	    V_028044_STENCIL_INVALID			0 +#define	    V_028044_STENCIL_8				1  #define   G_028044_TILE_SPLIT(x)                       (((x) >> 8) & 0x7)  #define DB_Z_READ_BASE					0x28048  #define DB_STENCIL_READ_BASE				0x2804c diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 9945d86d900..853800e8582 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -574,10 +574,18 @@ static void cayman_gpu_init(struct radeon_device *rdev)  	if (rdev->flags & RADEON_IS_IGP)  		rdev->config.cayman.tile_config |= 1 << 4;  	else { -		if ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) -			rdev->config.cayman.tile_config |= 1 << 4; -		else +		switch ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) { +		case 0: /* four banks */  			rdev->config.cayman.tile_config |= 0 << 4; +			break; +		case 1: /* eight banks */ +			rdev->config.cayman.tile_config |= 1 << 4; +			break; +		case 2: /* sixteen banks */ +		default: +			rdev->config.cayman.tile_config |= 2 << 4; +			break; +		}  	}  	rdev->config.cayman.tile_config |=  		((gb_addr_config & PIPE_INTERLEAVE_SIZE_MASK) >> PIPE_INTERLEAVE_SIZE_SHIFT) << 8; diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 637280f541a..d79c639ae73 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -3789,3 +3789,23 @@ static void r600_pcie_gen2_enable(struct radeon_device *rdev)  		WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl);  	}  } + +/** + * r600_get_gpu_clock - return GPU clock counter snapshot + * + * @rdev: radeon_device pointer + * + * Fetches a GPU clock counter snapshot (R6xx-cayman). + * Returns the 64 bit clock counter snapshot. + */ +uint64_t r600_get_gpu_clock(struct radeon_device *rdev) +{ +	uint64_t clock; + +	mutex_lock(&rdev->gpu_clock_mutex); +	WREG32(RLC_CAPTURE_GPU_CLOCK_COUNT, 1); +	clock = (uint64_t)RREG32(RLC_GPU_CLOCK_COUNT_LSB) | +	        ((uint64_t)RREG32(RLC_GPU_CLOCK_COUNT_MSB) << 32ULL); +	mutex_unlock(&rdev->gpu_clock_mutex); +	return clock; +} diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index ca87f7afaf2..f37676d7f21 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -47,18 +47,23 @@ struct r600_cs_track {  	u32			npipes;  	/* value we track */  	u32			sq_config; +	u32			log_nsamples;  	u32			nsamples;  	u32			cb_color_base_last[8];  	struct radeon_bo	*cb_color_bo[8];  	u64			cb_color_bo_mc[8]; -	u32			cb_color_bo_offset[8]; -	struct radeon_bo	*cb_color_frag_bo[8]; /* unused */ -	struct radeon_bo	*cb_color_tile_bo[8]; /* unused */ +	u64			cb_color_bo_offset[8]; +	struct radeon_bo	*cb_color_frag_bo[8]; +	u64			cb_color_frag_offset[8]; +	struct radeon_bo	*cb_color_tile_bo[8]; +	u64			cb_color_tile_offset[8]; +	u32			cb_color_mask[8];  	u32			cb_color_info[8];  	u32			cb_color_view[8];  	u32			cb_color_size_idx[8]; /* unused */  	u32			cb_target_mask;  	u32			cb_shader_mask;  /* unused */ +	bool			is_resolve;  	u32			cb_color_size[8];  	u32			vgt_strmout_en;  	u32			vgt_strmout_buffer_en; @@ -311,7 +316,15 @@ static void r600_cs_track_init(struct r600_cs_track *track)  		track->cb_color_bo[i] = NULL;  		track->cb_color_bo_offset[i] = 0xFFFFFFFF;  		track->cb_color_bo_mc[i] = 0xFFFFFFFF; +		track->cb_color_frag_bo[i] = NULL; +		track->cb_color_frag_offset[i] = 0xFFFFFFFF; +		track->cb_color_tile_bo[i] = NULL; +		track->cb_color_tile_offset[i] = 0xFFFFFFFF; +		track->cb_color_mask[i] = 0xFFFFFFFF;  	} +	track->is_resolve = false; +	track->nsamples = 16; +	track->log_nsamples = 4;  	track->cb_target_mask = 0xFFFFFFFF;  	track->cb_shader_mask = 0xFFFFFFFF;  	track->cb_dirty = true; @@ -348,11 +361,9 @@ static int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)  	volatile u32 *ib = p->ib.ptr;  	unsigned array_mode;  	u32 format; +	/* When resolve is used, the second colorbuffer has always 1 sample. */ +	unsigned nsamples = track->is_resolve && i == 1 ? 1 : track->nsamples; -	if (G_0280A0_TILE_MODE(track->cb_color_info[i])) { -		dev_warn(p->dev, "FMASK or CMASK buffer are not supported by this kernel\n"); -		return -EINVAL; -	}  	size = radeon_bo_size(track->cb_color_bo[i]) - track->cb_color_bo_offset[i];  	format = G_0280A0_FORMAT(track->cb_color_info[i]);  	if (!r600_fmt_is_valid_color(format)) { @@ -375,7 +386,7 @@ static int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)  	array_check.group_size = track->group_size;  	array_check.nbanks = track->nbanks;  	array_check.npipes = track->npipes; -	array_check.nsamples = track->nsamples; +	array_check.nsamples = nsamples;  	array_check.blocksize = r600_fmt_get_blocksize(format);  	if (r600_get_array_mode_alignment(&array_check,  					  &pitch_align, &height_align, &depth_align, &base_align)) { @@ -420,7 +431,8 @@ static int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)  	}  	/* check offset */ -	tmp = r600_fmt_get_nblocksy(format, height) * r600_fmt_get_nblocksx(format, pitch) * r600_fmt_get_blocksize(format); +	tmp = r600_fmt_get_nblocksy(format, height) * r600_fmt_get_nblocksx(format, pitch) * +	      r600_fmt_get_blocksize(format) * nsamples;  	switch (array_mode) {  	default:  	case V_0280A0_ARRAY_LINEAR_GENERAL: @@ -441,7 +453,7 @@ static int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)  			 * broken userspace.  			 */  		} else { -			dev_warn(p->dev, "%s offset[%d] %d %d %d %lu too big (%d %d) (%d %d %d)\n", +			dev_warn(p->dev, "%s offset[%d] %d %llu %d %lu too big (%d %d) (%d %d %d)\n",  				 __func__, i, array_mode,  				 track->cb_color_bo_offset[i], tmp,  				 radeon_bo_size(track->cb_color_bo[i]), @@ -458,6 +470,51 @@ static int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)  	tmp = S_028060_PITCH_TILE_MAX((pitch / 8) - 1) |  		S_028060_SLICE_TILE_MAX(slice_tile_max - 1);  	ib[track->cb_color_size_idx[i]] = tmp; + +	/* FMASK/CMASK */ +	switch (G_0280A0_TILE_MODE(track->cb_color_info[i])) { +	case V_0280A0_TILE_DISABLE: +		break; +	case V_0280A0_FRAG_ENABLE: +		if (track->nsamples > 1) { +			uint32_t tile_max = G_028100_FMASK_TILE_MAX(track->cb_color_mask[i]); +			/* the tile size is 8x8, but the size is in units of bits. +			 * for bytes, do just * 8. */ +			uint32_t bytes = track->nsamples * track->log_nsamples * 8 * (tile_max + 1); + +			if (bytes + track->cb_color_frag_offset[i] > +			    radeon_bo_size(track->cb_color_frag_bo[i])) { +				dev_warn(p->dev, "%s FMASK_TILE_MAX too large " +					 "(tile_max=%u, bytes=%u, offset=%llu, bo_size=%lu)\n", +					 __func__, tile_max, bytes, +					 track->cb_color_frag_offset[i], +					 radeon_bo_size(track->cb_color_frag_bo[i])); +				return -EINVAL; +			} +		} +		/* fall through */ +	case V_0280A0_CLEAR_ENABLE: +	{ +		uint32_t block_max = G_028100_CMASK_BLOCK_MAX(track->cb_color_mask[i]); +		/* One block = 128x128 pixels, one 8x8 tile has 4 bits.. +		 * (128*128) / (8*8) / 2 = 128 bytes per block. */ +		uint32_t bytes = (block_max + 1) * 128; + +		if (bytes + track->cb_color_tile_offset[i] > +		    radeon_bo_size(track->cb_color_tile_bo[i])) { +			dev_warn(p->dev, "%s CMASK_BLOCK_MAX too large " +				 "(block_max=%u, bytes=%u, offset=%llu, bo_size=%lu)\n", +				 __func__, block_max, bytes, +				 track->cb_color_tile_offset[i], +				 radeon_bo_size(track->cb_color_tile_bo[i])); +			return -EINVAL; +		} +		break; +	} +	default: +		dev_warn(p->dev, "%s invalid tile mode\n", __func__); +		return -EINVAL; +	}  	return 0;  } @@ -566,7 +623,7 @@ static int r600_cs_track_validate_db(struct radeon_cs_parser *p)  		ntiles = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1;  		nviews = G_028004_SLICE_MAX(track->db_depth_view) + 1; -		tmp = ntiles * bpe * 64 * nviews; +		tmp = ntiles * bpe * 64 * nviews * track->nsamples;  		if ((tmp + track->db_offset) > radeon_bo_size(track->db_bo)) {  			dev_warn(p->dev, "z/stencil buffer (%d) too small (0x%08X %d %d %d -> %u have %lu)\n",  					array_mode, @@ -746,6 +803,12 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)  	 */  	if (track->cb_dirty) {  		tmp = track->cb_target_mask; + +		/* We must check both colorbuffers for RESOLVE. */ +		if (track->is_resolve) { +			tmp |= 0xff; +		} +  		for (i = 0; i < 8; i++) {  			if ((tmp >> (i * 4)) & 0xF) {  				/* at least one component is enabled */ @@ -764,8 +827,10 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)  	}  	/* Check depth buffer */ -	if (track->db_dirty && (G_028800_STENCIL_ENABLE(track->db_depth_control) || -		G_028800_Z_ENABLE(track->db_depth_control))) { +	if (track->db_dirty && +	    G_028010_FORMAT(track->db_depth_info) != V_028010_DEPTH_INVALID && +	    (G_028800_STENCIL_ENABLE(track->db_depth_control) || +	     G_028800_Z_ENABLE(track->db_depth_control))) {  		r = r600_cs_track_validate_db(p);  		if (r)  			return r; @@ -1229,9 +1294,15 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  		break;  	case R_028C04_PA_SC_AA_CONFIG:  		tmp = G_028C04_MSAA_NUM_SAMPLES(radeon_get_ib_value(p, idx)); +		track->log_nsamples = tmp;  		track->nsamples = 1 << tmp;  		track->cb_dirty = true;  		break; +	case R_028808_CB_COLOR_CONTROL: +		tmp = G_028808_SPECIAL_OP(radeon_get_ib_value(p, idx)); +		track->is_resolve = tmp == V_028808_SPECIAL_RESOLVE_BOX; +		track->cb_dirty = true; +		break;  	case R_0280A0_CB_COLOR0_INFO:  	case R_0280A4_CB_COLOR1_INFO:  	case R_0280A8_CB_COLOR2_INFO: @@ -1310,16 +1381,21 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  				dev_err(p->dev, "Broken old userspace ? no cb_color0_base supplied before trying to write 0x%08X\n", reg);  				return -EINVAL;  			} -			ib[idx] = track->cb_color_base_last[tmp];  			track->cb_color_frag_bo[tmp] = track->cb_color_bo[tmp]; +			track->cb_color_frag_offset[tmp] = track->cb_color_bo_offset[tmp]; +			ib[idx] = track->cb_color_base_last[tmp];  		} else {  			r = r600_cs_packet_next_reloc(p, &reloc);  			if (r) {  				dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg);  				return -EINVAL;  			} -			ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);  			track->cb_color_frag_bo[tmp] = reloc->robj; +			track->cb_color_frag_offset[tmp] = (u64)ib[idx] << 8; +			ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); +		} +		if (G_0280A0_TILE_MODE(track->cb_color_info[tmp])) { +			track->cb_dirty = true;  		}  		break;  	case R_0280C0_CB_COLOR0_TILE: @@ -1336,16 +1412,35 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)  				dev_err(p->dev, "Broken old userspace ? no cb_color0_base supplied before trying to write 0x%08X\n", reg);  				return -EINVAL;  			} -			ib[idx] = track->cb_color_base_last[tmp];  			track->cb_color_tile_bo[tmp] = track->cb_color_bo[tmp]; +			track->cb_color_tile_offset[tmp] = track->cb_color_bo_offset[tmp]; +			ib[idx] = track->cb_color_base_last[tmp];  		} else {  			r = r600_cs_packet_next_reloc(p, &reloc);  			if (r) {  				dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg);  				return -EINVAL;  			} -			ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);  			track->cb_color_tile_bo[tmp] = reloc->robj; +			track->cb_color_tile_offset[tmp] = (u64)ib[idx] << 8; +			ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); +		} +		if (G_0280A0_TILE_MODE(track->cb_color_info[tmp])) { +			track->cb_dirty = true; +		} +		break; +	case R_028100_CB_COLOR0_MASK: +	case R_028104_CB_COLOR1_MASK: +	case R_028108_CB_COLOR2_MASK: +	case R_02810C_CB_COLOR3_MASK: +	case R_028110_CB_COLOR4_MASK: +	case R_028114_CB_COLOR5_MASK: +	case R_028118_CB_COLOR6_MASK: +	case R_02811C_CB_COLOR7_MASK: +		tmp = (reg - R_028100_CB_COLOR0_MASK) / 4; +		track->cb_color_mask[tmp] = radeon_get_ib_value(p, idx); +		if (G_0280A0_TILE_MODE(track->cb_color_info[tmp])) { +			track->cb_dirty = true;  		}  		break;  	case CB_COLOR0_BASE: @@ -1490,7 +1585,7 @@ unsigned r600_mip_minify(unsigned size, unsigned level)  }  static void r600_texture_size(unsigned nfaces, unsigned blevel, unsigned llevel, -			      unsigned w0, unsigned h0, unsigned d0, unsigned format, +			      unsigned w0, unsigned h0, unsigned d0, unsigned nsamples, unsigned format,  			      unsigned block_align, unsigned height_align, unsigned base_align,  			      unsigned *l0_size, unsigned *mipmap_size)  { @@ -1518,7 +1613,7 @@ static void r600_texture_size(unsigned nfaces, unsigned blevel, unsigned llevel,  		depth = r600_mip_minify(d0, i); -		size = nbx * nby * blocksize; +		size = nbx * nby * blocksize * nsamples;  		if (nfaces)  			size *= nfaces;  		else @@ -1557,13 +1652,14 @@ static int r600_check_texture_resource(struct radeon_cs_parser *p,  u32 idx,  					      u32 tiling_flags)  {  	struct r600_cs_track *track = p->track; -	u32 nfaces, llevel, blevel, w0, h0, d0; -	u32 word0, word1, l0_size, mipmap_size, word2, word3; +	u32 dim, nfaces, llevel, blevel, w0, h0, d0; +	u32 word0, word1, l0_size, mipmap_size, word2, word3, word4, word5;  	u32 height_align, pitch, pitch_align, depth_align; -	u32 array, barray, larray; +	u32 barray, larray;  	u64 base_align;  	struct array_mode_checker array_check;  	u32 format; +	bool is_array;  	/* on legacy kernel we don't perform advanced check */  	if (p->rdev == NULL) @@ -1581,12 +1677,28 @@ static int r600_check_texture_resource(struct radeon_cs_parser *p,  u32 idx,  			word0 |= S_038000_TILE_MODE(V_038000_ARRAY_1D_TILED_THIN1);  	}  	word1 = radeon_get_ib_value(p, idx + 1); +	word2 = radeon_get_ib_value(p, idx + 2) << 8; +	word3 = radeon_get_ib_value(p, idx + 3) << 8; +	word4 = radeon_get_ib_value(p, idx + 4); +	word5 = radeon_get_ib_value(p, idx + 5); +	dim = G_038000_DIM(word0);  	w0 = G_038000_TEX_WIDTH(word0) + 1; +	pitch = (G_038000_PITCH(word0) + 1) * 8;  	h0 = G_038004_TEX_HEIGHT(word1) + 1;  	d0 = G_038004_TEX_DEPTH(word1); +	format = G_038004_DATA_FORMAT(word1); +	blevel = G_038010_BASE_LEVEL(word4); +	llevel = G_038014_LAST_LEVEL(word5); +	/* pitch in texels */ +	array_check.array_mode = G_038000_TILE_MODE(word0); +	array_check.group_size = track->group_size; +	array_check.nbanks = track->nbanks; +	array_check.npipes = track->npipes; +	array_check.nsamples = 1; +	array_check.blocksize = r600_fmt_get_blocksize(format);  	nfaces = 1; -	array = 0; -	switch (G_038000_DIM(word0)) { +	is_array = false; +	switch (dim) {  	case V_038000_SQ_TEX_DIM_1D:  	case V_038000_SQ_TEX_DIM_2D:  	case V_038000_SQ_TEX_DIM_3D: @@ -1599,29 +1711,25 @@ static int r600_check_texture_resource(struct radeon_cs_parser *p,  u32 idx,  		break;  	case V_038000_SQ_TEX_DIM_1D_ARRAY:  	case V_038000_SQ_TEX_DIM_2D_ARRAY: -		array = 1; +		is_array = true;  		break; -	case V_038000_SQ_TEX_DIM_2D_MSAA:  	case V_038000_SQ_TEX_DIM_2D_ARRAY_MSAA: +		is_array = true; +		/* fall through */ +	case V_038000_SQ_TEX_DIM_2D_MSAA: +		array_check.nsamples = 1 << llevel; +		llevel = 0; +		break;  	default:  		dev_warn(p->dev, "this kernel doesn't support %d texture dim\n", G_038000_DIM(word0));  		return -EINVAL;  	} -	format = G_038004_DATA_FORMAT(word1);  	if (!r600_fmt_is_valid_texture(format, p->family)) {  		dev_warn(p->dev, "%s:%d texture invalid format %d\n",  			 __func__, __LINE__, format);  		return -EINVAL;  	} -	/* pitch in texels */ -	pitch = (G_038000_PITCH(word0) + 1) * 8; -	array_check.array_mode = G_038000_TILE_MODE(word0); -	array_check.group_size = track->group_size; -	array_check.nbanks = track->nbanks; -	array_check.npipes = track->npipes; -	array_check.nsamples = 1; -	array_check.blocksize = r600_fmt_get_blocksize(format);  	if (r600_get_array_mode_alignment(&array_check,  					  &pitch_align, &height_align, &depth_align, &base_align)) {  		dev_warn(p->dev, "%s:%d tex array mode (%d) invalid\n", @@ -1647,24 +1755,17 @@ static int r600_check_texture_resource(struct radeon_cs_parser *p,  u32 idx,  		return -EINVAL;  	} -	word2 = radeon_get_ib_value(p, idx + 2) << 8; -	word3 = radeon_get_ib_value(p, idx + 3) << 8; - -	word0 = radeon_get_ib_value(p, idx + 4); -	word1 = radeon_get_ib_value(p, idx + 5); -	blevel = G_038010_BASE_LEVEL(word0); -	llevel = G_038014_LAST_LEVEL(word1);  	if (blevel > llevel) {  		dev_warn(p->dev, "texture blevel %d > llevel %d\n",  			 blevel, llevel);  	} -	if (array == 1) { -		barray = G_038014_BASE_ARRAY(word1); -		larray = G_038014_LAST_ARRAY(word1); +	if (is_array) { +		barray = G_038014_BASE_ARRAY(word5); +		larray = G_038014_LAST_ARRAY(word5);  		nfaces = larray - barray + 1;  	} -	r600_texture_size(nfaces, blevel, llevel, w0, h0, d0, format, +	r600_texture_size(nfaces, blevel, llevel, w0, h0, d0, array_check.nsamples, format,  			  pitch_align, height_align, base_align,  			  &l0_size, &mipmap_size);  	/* using get ib will give us the offset into the texture bo */ @@ -1677,7 +1778,6 @@ static int r600_check_texture_resource(struct radeon_cs_parser *p,  u32 idx,  		return -EINVAL;  	}  	/* using get ib will give us the offset into the mipmap bo */ -	word3 = radeon_get_ib_value(p, idx + 3) << 8;  	if ((mipmap_size + word3) > radeon_bo_size(mipmap)) {  		/*dev_warn(p->dev, "mipmap bo too small (%d %d %d %d %d %d -> %d have %ld)\n",  		  w0, h0, format, blevel, nlevels, word3, mipmap_size, radeon_bo_size(texture));*/ diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index 4b116ae75fc..fa6f37099ba 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h @@ -66,6 +66,14 @@  #define	CC_RB_BACKEND_DISABLE				0x98F4  #define		BACKEND_DISABLE(x)				((x) << 16) +#define R_028808_CB_COLOR_CONTROL			0x28808 +#define   S_028808_SPECIAL_OP(x)                       (((x) & 0x7) << 4) +#define   G_028808_SPECIAL_OP(x)                       (((x) >> 4) & 0x7) +#define   C_028808_SPECIAL_OP                          0xFFFFFF8F +#define     V_028808_SPECIAL_NORMAL                     0x00 +#define     V_028808_SPECIAL_DISABLE                    0x01 +#define     V_028808_SPECIAL_RESOLVE_BOX                0x07 +  #define	CB_COLOR0_BASE					0x28040  #define	CB_COLOR1_BASE					0x28044  #define	CB_COLOR2_BASE					0x28048 @@ -92,6 +100,20 @@  #define R_028094_CB_COLOR5_VIEW                      0x028094  #define R_028098_CB_COLOR6_VIEW                      0x028098  #define R_02809C_CB_COLOR7_VIEW                      0x02809C +#define R_028100_CB_COLOR0_MASK                      0x028100 +#define   S_028100_CMASK_BLOCK_MAX(x)                  (((x) & 0xFFF) << 0) +#define   G_028100_CMASK_BLOCK_MAX(x)                  (((x) >> 0) & 0xFFF) +#define   C_028100_CMASK_BLOCK_MAX                     0xFFFFF000 +#define   S_028100_FMASK_TILE_MAX(x)                   (((x) & 0xFFFFF) << 12) +#define   G_028100_FMASK_TILE_MAX(x)                   (((x) >> 12) & 0xFFFFF) +#define   C_028100_FMASK_TILE_MAX                      0x00000FFF +#define R_028104_CB_COLOR1_MASK                      0x028104 +#define R_028108_CB_COLOR2_MASK                      0x028108 +#define R_02810C_CB_COLOR3_MASK                      0x02810C +#define R_028110_CB_COLOR4_MASK                      0x028110 +#define R_028114_CB_COLOR5_MASK                      0x028114 +#define R_028118_CB_COLOR6_MASK                      0x028118 +#define R_02811C_CB_COLOR7_MASK                      0x02811C  #define CB_COLOR0_INFO                                  0x280a0  #	define CB_FORMAT(x)				((x) << 2)  #       define CB_ARRAY_MODE(x)                         ((x) << 8) @@ -602,6 +624,9 @@  #define RLC_HB_WPTR                                       0x3f1c  #define RLC_HB_WPTR_LSB_ADDR                              0x3f14  #define RLC_HB_WPTR_MSB_ADDR                              0x3f18 +#define RLC_GPU_CLOCK_COUNT_LSB				  0x3f38 +#define RLC_GPU_CLOCK_COUNT_MSB				  0x3f3c +#define RLC_CAPTURE_GPU_CLOCK_COUNT			  0x3f40  #define RLC_MC_CNTL                                       0x3f44  #define RLC_UCODE_CNTL                                    0x3f48  #define RLC_UCODE_ADDR                                    0x3f2c @@ -1397,6 +1422,9 @@  #define   S_0280A0_TILE_MODE(x)                        (((x) & 0x3) << 18)  #define   G_0280A0_TILE_MODE(x)                        (((x) >> 18) & 0x3)  #define   C_0280A0_TILE_MODE                           0xFFF3FFFF +#define     V_0280A0_TILE_DISABLE			0 +#define     V_0280A0_CLEAR_ENABLE			1 +#define     V_0280A0_FRAG_ENABLE			2  #define   S_0280A0_BLEND_CLAMP(x)                      (((x) & 0x1) << 20)  #define   G_0280A0_BLEND_CLAMP(x)                      (((x) >> 20) & 0x1)  #define   C_0280A0_BLEND_CLAMP                         0xFFEFFFFF diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 5431af29240..59a15315ae9 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -142,21 +142,6 @@ struct radeon_device;  /*   * BIOS.   */ -#define ATRM_BIOS_PAGE 4096 - -#if defined(CONFIG_VGA_SWITCHEROO) -bool radeon_atrm_supported(struct pci_dev *pdev); -int radeon_atrm_get_bios_chunk(uint8_t *bios, int offset, int len); -#else -static inline bool radeon_atrm_supported(struct pci_dev *pdev) -{ -	return false; -} - -static inline int radeon_atrm_get_bios_chunk(uint8_t *bios, int offset, int len){ -	return -EINVAL; -} -#endif  bool radeon_get_bios(struct radeon_device *rdev);  /* @@ -300,6 +285,7 @@ struct radeon_bo_va {  	uint64_t			soffset;  	uint64_t			eoffset;  	uint32_t			flags; +	struct radeon_fence		*fence;  	bool				valid;  }; @@ -1533,6 +1519,7 @@ struct radeon_device {  	unsigned 		debugfs_count;  	/* virtual memory */  	struct radeon_vm_manager	vm_manager; +	struct mutex			gpu_clock_mutex;  };  int radeon_device_init(struct radeon_device *rdev, @@ -1733,11 +1720,11 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v);  #define radeon_pm_finish(rdev) (rdev)->asic->pm.finish((rdev))  #define radeon_pm_init_profile(rdev) (rdev)->asic->pm.init_profile((rdev))  #define radeon_pm_get_dynpm_state(rdev) (rdev)->asic->pm.get_dynpm_state((rdev)) -#define radeon_pre_page_flip(rdev, crtc) rdev->asic->pflip.pre_page_flip((rdev), (crtc)) -#define radeon_page_flip(rdev, crtc, base) rdev->asic->pflip.page_flip((rdev), (crtc), (base)) -#define radeon_post_page_flip(rdev, crtc) rdev->asic->pflip.post_page_flip((rdev), (crtc)) -#define radeon_wait_for_vblank(rdev, crtc) rdev->asic->display.wait_for_vblank((rdev), (crtc)) -#define radeon_mc_wait_for_idle(rdev) rdev->asic->mc_wait_for_idle((rdev)) +#define radeon_pre_page_flip(rdev, crtc) (rdev)->asic->pflip.pre_page_flip((rdev), (crtc)) +#define radeon_page_flip(rdev, crtc, base) (rdev)->asic->pflip.page_flip((rdev), (crtc), (base)) +#define radeon_post_page_flip(rdev, crtc) (rdev)->asic->pflip.post_page_flip((rdev), (crtc)) +#define radeon_wait_for_vblank(rdev, crtc) (rdev)->asic->display.wait_for_vblank((rdev), (crtc)) +#define radeon_mc_wait_for_idle(rdev) (rdev)->asic->mc_wait_for_idle((rdev))  /* Common functions */  /* AGP */ diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index f4af2431043..18c38d14c8c 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -255,13 +255,10 @@ extern int rs690_mc_wait_for_idle(struct radeon_device *rdev);   * rv515   */  struct rv515_mc_save { -	u32 d1vga_control; -	u32 d2vga_control;  	u32 vga_render_control;  	u32 vga_hdp_control; -	u32 d1crtc_control; -	u32 d2crtc_control;  }; +  int rv515_init(struct radeon_device *rdev);  void rv515_fini(struct radeon_device *rdev);  uint32_t rv515_mc_rreg(struct radeon_device *rdev, uint32_t reg); @@ -371,6 +368,7 @@ void r600_kms_blit_copy(struct radeon_device *rdev,  			unsigned num_gpu_pages,  			struct radeon_sa_bo *vb);  int r600_mc_wait_for_idle(struct radeon_device *rdev); +uint64_t r600_get_gpu_clock(struct radeon_device *rdev);  /*   * rv770,rv730,rv710,rv740 @@ -389,11 +387,10 @@ void r700_cp_fini(struct radeon_device *rdev);   * evergreen   */  struct evergreen_mc_save { -	u32 vga_control[6];  	u32 vga_render_control;  	u32 vga_hdp_control; -	u32 crtc_control[6];  }; +  void evergreen_pcie_gart_tlb_flush(struct radeon_device *rdev);  int evergreen_init(struct radeon_device *rdev);  void evergreen_fini(struct radeon_device *rdev); @@ -472,5 +469,6 @@ int si_vm_bind(struct radeon_device *rdev, struct radeon_vm *vm, int id);  void si_vm_unbind(struct radeon_device *rdev, struct radeon_vm *vm);  void si_vm_tlb_flush(struct radeon_device *rdev, struct radeon_vm *vm);  int si_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib); +uint64_t si_get_gpu_clock(struct radeon_device *rdev);  #endif diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index b1e3820df36..d67d4f3eb6f 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -452,7 +452,7 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev,  	}  	/* Fujitsu D3003-S2 board lists DVI-I as DVI-D and VGA */ -	if ((dev->pdev->device == 0x9802) && +	if (((dev->pdev->device == 0x9802) || (dev->pdev->device == 0x9806)) &&  	    (dev->pdev->subsystem_vendor == 0x1734) &&  	    (dev->pdev->subsystem_device == 0x11bd)) {  		if (*connector_type == DRM_MODE_CONNECTOR_VGA) { @@ -1263,6 +1263,8 @@ bool radeon_atom_get_clock_info(struct drm_device *dev)  union igp_info {  	struct _ATOM_INTEGRATED_SYSTEM_INFO info;  	struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2; +	struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6; +	struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7;  };  bool radeon_atombios_sideport_present(struct radeon_device *rdev) @@ -1390,27 +1392,50 @@ static void radeon_atombios_get_igp_ss_overrides(struct radeon_device *rdev,  	struct radeon_mode_info *mode_info = &rdev->mode_info;  	int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);  	u16 data_offset, size; -	struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 *igp_info; +	union igp_info *igp_info;  	u8 frev, crev;  	u16 percentage = 0, rate = 0;  	/* get any igp specific overrides */  	if (atom_parse_data_header(mode_info->atom_context, index, &size,  				   &frev, &crev, &data_offset)) { -		igp_info = (struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 *) +		igp_info = (union igp_info *)  			(mode_info->atom_context->bios + data_offset); -		switch (id) { -		case ASIC_INTERNAL_SS_ON_TMDS: -			percentage = le16_to_cpu(igp_info->usDVISSPercentage); -			rate = le16_to_cpu(igp_info->usDVISSpreadRateIn10Hz); +		switch (crev) { +		case 6: +			switch (id) { +			case ASIC_INTERNAL_SS_ON_TMDS: +				percentage = le16_to_cpu(igp_info->info_6.usDVISSPercentage); +				rate = le16_to_cpu(igp_info->info_6.usDVISSpreadRateIn10Hz); +				break; +			case ASIC_INTERNAL_SS_ON_HDMI: +				percentage = le16_to_cpu(igp_info->info_6.usHDMISSPercentage); +				rate = le16_to_cpu(igp_info->info_6.usHDMISSpreadRateIn10Hz); +				break; +			case ASIC_INTERNAL_SS_ON_LVDS: +				percentage = le16_to_cpu(igp_info->info_6.usLvdsSSPercentage); +				rate = le16_to_cpu(igp_info->info_6.usLvdsSSpreadRateIn10Hz); +				break; +			}  			break; -		case ASIC_INTERNAL_SS_ON_HDMI: -			percentage = le16_to_cpu(igp_info->usHDMISSPercentage); -			rate = le16_to_cpu(igp_info->usHDMISSpreadRateIn10Hz); +		case 7: +			switch (id) { +			case ASIC_INTERNAL_SS_ON_TMDS: +				percentage = le16_to_cpu(igp_info->info_7.usDVISSPercentage); +				rate = le16_to_cpu(igp_info->info_7.usDVISSpreadRateIn10Hz); +				break; +			case ASIC_INTERNAL_SS_ON_HDMI: +				percentage = le16_to_cpu(igp_info->info_7.usHDMISSPercentage); +				rate = le16_to_cpu(igp_info->info_7.usHDMISSpreadRateIn10Hz); +				break; +			case ASIC_INTERNAL_SS_ON_LVDS: +				percentage = le16_to_cpu(igp_info->info_7.usLvdsSSPercentage); +				rate = le16_to_cpu(igp_info->info_7.usLvdsSSpreadRateIn10Hz); +				break; +			}  			break; -		case ASIC_INTERNAL_SS_ON_LVDS: -			percentage = le16_to_cpu(igp_info->usLvdsSSPercentage); -			rate = le16_to_cpu(igp_info->usLvdsSSpreadRateIn10Hz); +		default: +			DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);  			break;  		}  		if (percentage) diff --git a/drivers/gpu/drm/radeon/radeon_atpx_handler.c b/drivers/gpu/drm/radeon/radeon_atpx_handler.c index 98724fcb008..2a2cf0b88a2 100644 --- a/drivers/gpu/drm/radeon/radeon_atpx_handler.c +++ b/drivers/gpu/drm/radeon/radeon_atpx_handler.c @@ -30,57 +30,8 @@ static struct radeon_atpx_priv {  	/* handle for device - and atpx */  	acpi_handle dhandle;  	acpi_handle atpx_handle; -	acpi_handle atrm_handle;  } radeon_atpx_priv; -/* retrieve the ROM in 4k blocks */ -static int radeon_atrm_call(acpi_handle atrm_handle, uint8_t *bios, -			    int offset, int len) -{ -	acpi_status status; -	union acpi_object atrm_arg_elements[2], *obj; -	struct acpi_object_list atrm_arg; -	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL}; - -	atrm_arg.count = 2; -	atrm_arg.pointer = &atrm_arg_elements[0]; - -	atrm_arg_elements[0].type = ACPI_TYPE_INTEGER; -	atrm_arg_elements[0].integer.value = offset; - -	atrm_arg_elements[1].type = ACPI_TYPE_INTEGER; -	atrm_arg_elements[1].integer.value = len; - -	status = acpi_evaluate_object(atrm_handle, NULL, &atrm_arg, &buffer); -	if (ACPI_FAILURE(status)) { -		printk("failed to evaluate ATRM got %s\n", acpi_format_exception(status)); -		return -ENODEV; -	} - -	obj = (union acpi_object *)buffer.pointer; -	memcpy(bios+offset, obj->buffer.pointer, obj->buffer.length); -	len = obj->buffer.length; -	kfree(buffer.pointer); -	return len; -} - -bool radeon_atrm_supported(struct pci_dev *pdev) -{ -	/* get the discrete ROM only via ATRM */ -	if (!radeon_atpx_priv.atpx_detected) -		return false; - -	if (radeon_atpx_priv.dhandle == DEVICE_ACPI_HANDLE(&pdev->dev)) -		return false; -	return true; -} - - -int radeon_atrm_get_bios_chunk(uint8_t *bios, int offset, int len) -{ -	return radeon_atrm_call(radeon_atpx_priv.atrm_handle, bios, offset, len); -} -  static int radeon_atpx_get_version(acpi_handle handle)  {  	acpi_status status; @@ -198,7 +149,7 @@ static int radeon_atpx_power_state(enum vga_switcheroo_client_id id,  static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev)  { -	acpi_handle dhandle, atpx_handle, atrm_handle; +	acpi_handle dhandle, atpx_handle;  	acpi_status status;  	dhandle = DEVICE_ACPI_HANDLE(&pdev->dev); @@ -209,13 +160,8 @@ static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev)  	if (ACPI_FAILURE(status))  		return false; -	status = acpi_get_handle(dhandle, "ATRM", &atrm_handle); -	if (ACPI_FAILURE(status)) -		return false; -  	radeon_atpx_priv.dhandle = dhandle;  	radeon_atpx_priv.atpx_handle = atpx_handle; -	radeon_atpx_priv.atrm_handle = atrm_handle;  	return true;  } diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c index 501f4881e5a..d306cc8fdea 100644 --- a/drivers/gpu/drm/radeon/radeon_bios.c +++ b/drivers/gpu/drm/radeon/radeon_bios.c @@ -32,6 +32,7 @@  #include <linux/vga_switcheroo.h>  #include <linux/slab.h> +#include <linux/acpi.h>  /*   * BIOS.   */ @@ -98,16 +99,81 @@ static bool radeon_read_bios(struct radeon_device *rdev)  	return true;  } +#ifdef CONFIG_ACPI  /* ATRM is used to get the BIOS on the discrete cards in   * dual-gpu systems.   */ +/* retrieve the ROM in 4k blocks */ +#define ATRM_BIOS_PAGE 4096 +/** + * radeon_atrm_call - fetch a chunk of the vbios + * + * @atrm_handle: acpi ATRM handle + * @bios: vbios image pointer + * @offset: offset of vbios image data to fetch + * @len: length of vbios image data to fetch + * + * Executes ATRM to fetch a chunk of the discrete + * vbios image on PX systems (all asics). + * Returns the length of the buffer fetched. + */ +static int radeon_atrm_call(acpi_handle atrm_handle, uint8_t *bios, +			    int offset, int len) +{ +	acpi_status status; +	union acpi_object atrm_arg_elements[2], *obj; +	struct acpi_object_list atrm_arg; +	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL}; + +	atrm_arg.count = 2; +	atrm_arg.pointer = &atrm_arg_elements[0]; + +	atrm_arg_elements[0].type = ACPI_TYPE_INTEGER; +	atrm_arg_elements[0].integer.value = offset; + +	atrm_arg_elements[1].type = ACPI_TYPE_INTEGER; +	atrm_arg_elements[1].integer.value = len; + +	status = acpi_evaluate_object(atrm_handle, NULL, &atrm_arg, &buffer); +	if (ACPI_FAILURE(status)) { +		printk("failed to evaluate ATRM got %s\n", acpi_format_exception(status)); +		return -ENODEV; +	} + +	obj = (union acpi_object *)buffer.pointer; +	memcpy(bios+offset, obj->buffer.pointer, obj->buffer.length); +	len = obj->buffer.length; +	kfree(buffer.pointer); +	return len; +} +  static bool radeon_atrm_get_bios(struct radeon_device *rdev)  {  	int ret;  	int size = 256 * 1024;  	int i; +	struct pci_dev *pdev = NULL; +	acpi_handle dhandle, atrm_handle; +	acpi_status status; +	bool found = false; + +	/* ATRM is for the discrete card only */ +	if (rdev->flags & RADEON_IS_IGP) +		return false; -	if (!radeon_atrm_supported(rdev->pdev)) +	while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { +		dhandle = DEVICE_ACPI_HANDLE(&pdev->dev); +		if (!dhandle) +			continue; + +		status = acpi_get_handle(dhandle, "ATRM", &atrm_handle); +		if (!ACPI_FAILURE(status)) { +			found = true; +			break; +		} +	} + +	if (!found)  		return false;  	rdev->bios = kmalloc(size, GFP_KERNEL); @@ -117,9 +183,10 @@ static bool radeon_atrm_get_bios(struct radeon_device *rdev)  	}  	for (i = 0; i < size / ATRM_BIOS_PAGE; i++) { -		ret = radeon_atrm_get_bios_chunk(rdev->bios, -						 (i * ATRM_BIOS_PAGE), -						 ATRM_BIOS_PAGE); +		ret = radeon_atrm_call(atrm_handle, +				       rdev->bios, +				       (i * ATRM_BIOS_PAGE), +				       ATRM_BIOS_PAGE);  		if (ret < ATRM_BIOS_PAGE)  			break;  	} @@ -130,6 +197,12 @@ static bool radeon_atrm_get_bios(struct radeon_device *rdev)  	}  	return true;  } +#else +static inline bool radeon_atrm_get_bios(struct radeon_device *rdev) +{ +	return false; +} +#endif  static bool ni_read_disabled_bios(struct radeon_device *rdev)  { @@ -476,6 +549,61 @@ static bool radeon_read_disabled_bios(struct radeon_device *rdev)  		return legacy_read_disabled_bios(rdev);  } +#ifdef CONFIG_ACPI +static bool radeon_acpi_vfct_bios(struct radeon_device *rdev) +{ +	bool ret = false; +	struct acpi_table_header *hdr; +	acpi_size tbl_size; +	UEFI_ACPI_VFCT *vfct; +	GOP_VBIOS_CONTENT *vbios; +	VFCT_IMAGE_HEADER *vhdr; + +	if (!ACPI_SUCCESS(acpi_get_table_with_size("VFCT", 1, &hdr, &tbl_size))) +		return false; +	if (tbl_size < sizeof(UEFI_ACPI_VFCT)) { +		DRM_ERROR("ACPI VFCT table present but broken (too short #1)\n"); +		goto out_unmap; +	} + +	vfct = (UEFI_ACPI_VFCT *)hdr; +	if (vfct->VBIOSImageOffset + sizeof(VFCT_IMAGE_HEADER) > tbl_size) { +		DRM_ERROR("ACPI VFCT table present but broken (too short #2)\n"); +		goto out_unmap; +	} + +	vbios = (GOP_VBIOS_CONTENT *)((char *)hdr + vfct->VBIOSImageOffset); +	vhdr = &vbios->VbiosHeader; +	DRM_INFO("ACPI VFCT contains a BIOS for %02x:%02x.%d %04x:%04x, size %d\n", +			vhdr->PCIBus, vhdr->PCIDevice, vhdr->PCIFunction, +			vhdr->VendorID, vhdr->DeviceID, vhdr->ImageLength); + +	if (vhdr->PCIBus != rdev->pdev->bus->number || +	    vhdr->PCIDevice != PCI_SLOT(rdev->pdev->devfn) || +	    vhdr->PCIFunction != PCI_FUNC(rdev->pdev->devfn) || +	    vhdr->VendorID != rdev->pdev->vendor || +	    vhdr->DeviceID != rdev->pdev->device) { +		DRM_INFO("ACPI VFCT table is not for this card\n"); +		goto out_unmap; +	}; + +	if (vfct->VBIOSImageOffset + sizeof(VFCT_IMAGE_HEADER) + vhdr->ImageLength > tbl_size) { +		DRM_ERROR("ACPI VFCT image truncated\n"); +		goto out_unmap; +	} + +	rdev->bios = kmemdup(&vbios->VbiosContent, vhdr->ImageLength, GFP_KERNEL); +	ret = !!rdev->bios; + +out_unmap: +	return ret; +} +#else +static inline bool radeon_acpi_vfct_bios(struct radeon_device *rdev) +{ +	return false; +} +#endif  bool radeon_get_bios(struct radeon_device *rdev)  { @@ -484,6 +612,8 @@ bool radeon_get_bios(struct radeon_device *rdev)  	r = radeon_atrm_get_bios(rdev);  	if (r == false) +		r = radeon_acpi_vfct_bios(rdev); +	if (r == false)  		r = igp_read_bios_from_vram(rdev);  	if (r == false)  		r = radeon_read_bios(rdev); diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 576f4f6919f..f75247d42ff 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -719,6 +719,34 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde  	return i2c;  } +static struct radeon_i2c_bus_rec radeon_combios_get_i2c_info_from_table(struct radeon_device *rdev) +{ +	struct drm_device *dev = rdev->ddev; +	struct radeon_i2c_bus_rec i2c; +	u16 offset; +	u8 id, blocks, clk, data; +	int i; + +	i2c.valid = false; + +	offset = combios_get_table_offset(dev, COMBIOS_I2C_INFO_TABLE); +	if (offset) { +		blocks = RBIOS8(offset + 2); +		for (i = 0; i < blocks; i++) { +			id = RBIOS8(offset + 3 + (i * 5) + 0); +			if (id == 136) { +				clk = RBIOS8(offset + 3 + (i * 5) + 3); +				data = RBIOS8(offset + 3 + (i * 5) + 4); +				/* gpiopad */ +				i2c = combios_setup_i2c_bus(rdev, DDC_MONID, +							    (1 << clk), (1 << data)); +				break; +			} +		} +	} +	return i2c; +} +  void radeon_combios_i2c_init(struct radeon_device *rdev)  {  	struct drm_device *dev = rdev->ddev; @@ -755,30 +783,14 @@ void radeon_combios_i2c_init(struct radeon_device *rdev)  	} else if (rdev->family == CHIP_RS300 ||  		   rdev->family == CHIP_RS400 ||  		   rdev->family == CHIP_RS480) { -		u16 offset; -		u8 id, blocks, clk, data; -		int i; -  		/* 0x68 */  		i2c = combios_setup_i2c_bus(rdev, DDC_CRT2, 0, 0);  		rdev->i2c_bus[3] = radeon_i2c_create(dev, &i2c, "MONID"); -		offset = combios_get_table_offset(dev, COMBIOS_I2C_INFO_TABLE); -		if (offset) { -			blocks = RBIOS8(offset + 2); -			for (i = 0; i < blocks; i++) { -				id = RBIOS8(offset + 3 + (i * 5) + 0); -				if (id == 136) { -					clk = RBIOS8(offset + 3 + (i * 5) + 3); -					data = RBIOS8(offset + 3 + (i * 5) + 4); -					/* gpiopad */ -					i2c = combios_setup_i2c_bus(rdev, DDC_MONID, -								    (1 << clk), (1 << data)); -					rdev->i2c_bus[4] = radeon_i2c_create(dev, &i2c, "GPIOPAD_MASK"); -					break; -				} -			} -		} +		/* gpiopad */ +		i2c = radeon_combios_get_i2c_info_from_table(rdev); +		if (i2c.valid) +			rdev->i2c_bus[4] = radeon_i2c_create(dev, &i2c, "GPIOPAD_MASK");  	} else if ((rdev->family == CHIP_R200) ||  		   (rdev->family >= CHIP_R300)) {  		/* 0x68 */ @@ -2321,7 +2333,10 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)  			connector = (tmp >> 12) & 0xf;  			ddc_type = (tmp >> 8) & 0xf; -			ddc_i2c = combios_setup_i2c_bus(rdev, ddc_type, 0, 0); +			if (ddc_type == 5) +				ddc_i2c = radeon_combios_get_i2c_info_from_table(rdev); +			else +				ddc_i2c = combios_setup_i2c_bus(rdev, ddc_type, 0, 0);  			switch (connector) {  			case CONNECTOR_PROPRIETARY_LEGACY: diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index 8a4c49ef0cc..b4a0db24f4d 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -278,6 +278,30 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)  	return 0;  } +static void radeon_bo_vm_fence_va(struct radeon_cs_parser *parser, +				  struct radeon_fence *fence) +{ +	struct radeon_fpriv *fpriv = parser->filp->driver_priv; +	struct radeon_vm *vm = &fpriv->vm; +	struct radeon_bo_list *lobj; + +	if (parser->chunk_ib_idx == -1) { +		return; +	} +	if ((parser->cs_flags & RADEON_CS_USE_VM) == 0) { +		return; +	} + +	list_for_each_entry(lobj, &parser->validated, tv.head) { +		struct radeon_bo_va *bo_va; +		struct radeon_bo *rbo = lobj->bo; + +		bo_va = radeon_bo_va(rbo, vm); +		radeon_fence_unref(&bo_va->fence); +		bo_va->fence = radeon_fence_ref(fence); +	} +} +  /**   * cs_parser_fini() - clean parser states   * @parser:	parser structure holding parsing context. @@ -290,11 +314,14 @@ static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error)  {  	unsigned i; -	if (!error) +	if (!error) { +		/* fence all bo va before ttm_eu_fence_buffer_objects so bo are still reserved */ +		radeon_bo_vm_fence_va(parser, parser->ib.fence);  		ttm_eu_fence_buffer_objects(&parser->validated,  					    parser->ib.fence); -	else +	} else {  		ttm_eu_backoff_reservation(&parser->validated); +	}  	if (parser->relocs != NULL) {  		for (i = 0; i < parser->nrelocs; i++) { @@ -388,7 +415,6 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev,  	if (parser->chunk_ib_idx == -1)  		return 0; -  	if ((parser->cs_flags & RADEON_CS_USE_VM) == 0)  		return 0; diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c index 711e95ad39b..8794744cdf1 100644 --- a/drivers/gpu/drm/radeon/radeon_cursor.c +++ b/drivers/gpu/drm/radeon/radeon_cursor.c @@ -67,7 +67,8 @@ static void radeon_hide_cursor(struct drm_crtc *crtc)  	if (ASIC_IS_DCE4(rdev)) {  		WREG32(RADEON_MM_INDEX, EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset); -		WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT)); +		WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) | +		       EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2));  	} else if (ASIC_IS_AVIVO(rdev)) {  		WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset);  		WREG32(RADEON_MM_DATA, (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT)); @@ -94,7 +95,8 @@ static void radeon_show_cursor(struct drm_crtc *crtc)  	if (ASIC_IS_DCE4(rdev)) {  		WREG32(RADEON_MM_INDEX, EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset);  		WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_EN | -		       EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT)); +		       EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) | +		       EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2));  	} else if (ASIC_IS_AVIVO(rdev)) {  		WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset);  		WREG32(RADEON_MM_DATA, AVIVO_D1CURSOR_EN | diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 742af8244e8..7a3daebd732 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1009,6 +1009,7 @@ int radeon_device_init(struct radeon_device *rdev,  	atomic_set(&rdev->ih.lock, 0);  	mutex_init(&rdev->gem.mutex);  	mutex_init(&rdev->pm.mutex); +	mutex_init(&rdev->gpu_clock_mutex);  	init_rwsem(&rdev->pm.mclk_lock);  	init_rwsem(&rdev->exclusive_lock);  	init_waitqueue_head(&rdev->irq.vblank_queue); @@ -1050,7 +1051,7 @@ int radeon_device_init(struct radeon_device *rdev,  	if (rdev->flags & RADEON_IS_AGP)  		rdev->need_dma32 = true;  	if ((rdev->flags & RADEON_IS_PCI) && -	    (rdev->family < CHIP_RS400)) +	    (rdev->family <= CHIP_RS740))  		rdev->need_dma32 = true;  	dma_bits = rdev->need_dma32 ? 32 : 40; @@ -1345,12 +1346,15 @@ retry:  		for (i = 0; i < RADEON_NUM_RINGS; ++i) {  			radeon_ring_restore(rdev, &rdev->ring[i],  					    ring_sizes[i], ring_data[i]); +			ring_sizes[i] = 0; +			ring_data[i] = NULL;  		}  		r = radeon_ib_ring_tests(rdev);  		if (r) {  			dev_err(rdev->dev, "ib ring test failed (%d).\n", r);  			if (saved) { +				saved = false;  				radeon_suspend(rdev);  				goto retry;  			} diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index dcea6f01ae4..8c593ea82c4 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -59,9 +59,14 @@   *   2.15.0 - add max_pipes query   *   2.16.0 - fix evergreen 2D tiled surface calculation   *   2.17.0 - add STRMOUT_BASE_UPDATE for r7xx + *   2.18.0 - r600-eg: allow "invalid" DB formats + *   2.19.0 - r600-eg: MSAA textures + *   2.20.0 - r600-si: RADEON_INFO_TIMESTAMP query + *   2.21.0 - r600-r700: FMASK and CMASK + *   2.22.0 - r600 only: RESOLVE_BOX allowed   */  #define KMS_DRIVER_MAJOR	2 -#define KMS_DRIVER_MINOR	17 +#define KMS_DRIVER_MINOR	22  #define KMS_DRIVER_PATCHLEVEL	0  int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);  int radeon_driver_unload_kms(struct drm_device *dev); diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index 7b737b9339a..2a59375dbe5 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -131,7 +131,7 @@ int radeon_fence_emit(struct radeon_device *rdev,   */  void radeon_fence_process(struct radeon_device *rdev, int ring)  { -	uint64_t seq, last_seq; +	uint64_t seq, last_seq, last_emitted;  	unsigned count_loop = 0;  	bool wake = false; @@ -158,13 +158,15 @@ void radeon_fence_process(struct radeon_device *rdev, int ring)  	 */  	last_seq = atomic64_read(&rdev->fence_drv[ring].last_seq);  	do { +		last_emitted = rdev->fence_drv[ring].sync_seq[ring];  		seq = radeon_fence_read(rdev, ring);  		seq |= last_seq & 0xffffffff00000000LL;  		if (seq < last_seq) { -			seq += 0x100000000LL; +			seq &= 0xffffffff; +			seq |= last_emitted & 0xffffffff00000000LL;  		} -		if (seq == last_seq) { +		if (seq <= last_seq || seq > last_emitted) {  			break;  		}  		/* If we loop over we don't want to return without diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index b3720054614..bb3b7fe05cc 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -814,7 +814,7 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev,  		return -EINVAL;  	} -	if (bo_va->valid) +	if (bo_va->valid && mem)  		return 0;  	ngpu_pages = radeon_bo_ngpu_pages(bo); @@ -859,11 +859,27 @@ int radeon_vm_bo_rmv(struct radeon_device *rdev,  		     struct radeon_bo *bo)  {  	struct radeon_bo_va *bo_va; +	int r;  	bo_va = radeon_bo_va(bo, vm);  	if (bo_va == NULL)  		return 0; +	/* wait for va use to end */ +	while (bo_va->fence) { +		r = radeon_fence_wait(bo_va->fence, false); +		if (r) { +			DRM_ERROR("error while waiting for fence: %d\n", r); +		} +		if (r == -EDEADLK) { +			r = radeon_gpu_reset(rdev); +			if (!r) +				continue; +		} +		break; +	} +	radeon_fence_unref(&bo_va->fence); +  	mutex_lock(&rdev->vm_manager.lock);  	mutex_lock(&vm->mutex);  	radeon_vm_bo_update_pte(rdev, vm, bo, NULL); @@ -934,7 +950,7 @@ int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm)  }  /** - * radeon_vm_init - tear down a vm instance + * radeon_vm_fini - tear down a vm instance   *   * @rdev: radeon_device pointer   * @vm: requested vm @@ -952,12 +968,15 @@ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm)  	radeon_vm_unbind_locked(rdev, vm);  	mutex_unlock(&rdev->vm_manager.lock); -	/* remove all bo */ +	/* remove all bo at this point non are busy any more because unbind +	 * waited for the last vm fence to signal +	 */  	r = radeon_bo_reserve(rdev->ring_tmp_bo.bo, false);  	if (!r) {  		bo_va = radeon_bo_va(rdev->ring_tmp_bo.bo, vm);  		list_del_init(&bo_va->bo_list);  		list_del_init(&bo_va->vm_list); +		radeon_fence_unref(&bo_va->fence);  		radeon_bo_unreserve(rdev->ring_tmp_bo.bo);  		kfree(bo_va);  	} @@ -969,6 +988,7 @@ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm)  		r = radeon_bo_reserve(bo_va->bo, false);  		if (!r) {  			list_del_init(&bo_va->bo_list); +			radeon_fence_unref(&bo_va->fence);  			radeon_bo_unreserve(bo_va->bo);  			kfree(bo_va);  		} diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index 84d04524573..1b57b0058ad 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -134,25 +134,16 @@ void radeon_gem_object_close(struct drm_gem_object *obj,  	struct radeon_device *rdev = rbo->rdev;  	struct radeon_fpriv *fpriv = file_priv->driver_priv;  	struct radeon_vm *vm = &fpriv->vm; -	struct radeon_bo_va *bo_va, *tmp;  	if (rdev->family < CHIP_CAYMAN) {  		return;  	}  	if (radeon_bo_reserve(rbo, false)) { +		dev_err(rdev->dev, "leaking bo va because we fail to reserve bo\n");  		return;  	} -	list_for_each_entry_safe(bo_va, tmp, &rbo->va, bo_list) { -		if (bo_va->vm == vm) { -			/* remove from this vm address space */ -			mutex_lock(&vm->mutex); -			list_del(&bo_va->vm_list); -			mutex_unlock(&vm->mutex); -			list_del(&bo_va->bo_list); -			kfree(bo_va); -		} -	} +	radeon_vm_bo_rmv(rdev, vm, rbo);  	radeon_bo_unreserve(rbo);  } diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 1d73f16b5d9..414b4acf694 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -29,6 +29,7 @@  #include "drm_sarea.h"  #include "radeon.h"  #include "radeon_drm.h" +#include "radeon_asic.h"  #include <linux/vga_switcheroo.h>  #include <linux/slab.h> @@ -167,17 +168,39 @@ static void radeon_set_filp_rights(struct drm_device *dev,  int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)  {  	struct radeon_device *rdev = dev->dev_private; -	struct drm_radeon_info *info; +	struct drm_radeon_info *info = data;  	struct radeon_mode_info *minfo = &rdev->mode_info; -	uint32_t *value_ptr; -	uint32_t value; +	uint32_t value, *value_ptr; +	uint64_t value64, *value_ptr64;  	struct drm_crtc *crtc;  	int i, found; -	info = data; +	/* TIMESTAMP is a 64-bit value, needs special handling. */ +	if (info->request == RADEON_INFO_TIMESTAMP) { +		if (rdev->family >= CHIP_R600) { +			value_ptr64 = (uint64_t*)((unsigned long)info->value); +			if (rdev->family >= CHIP_TAHITI) { +				value64 = si_get_gpu_clock(rdev); +			} else { +				value64 = r600_get_gpu_clock(rdev); +			} + +			if (DRM_COPY_TO_USER(value_ptr64, &value64, sizeof(value64))) { +				DRM_ERROR("copy_to_user %s:%u\n", __func__, __LINE__); +				return -EFAULT; +			} +			return 0; +		} else { +			DRM_DEBUG_KMS("timestamp is r6xx+ only!\n"); +			return -EINVAL; +		} +	} +  	value_ptr = (uint32_t *)((unsigned long)info->value); -	if (DRM_COPY_FROM_USER(&value, value_ptr, sizeof(value))) +	if (DRM_COPY_FROM_USER(&value, value_ptr, sizeof(value))) { +		DRM_ERROR("copy_from_user %s:%u\n", __func__, __LINE__);  		return -EFAULT; +	}  	switch (info->request) {  	case RADEON_INFO_DEVICE_ID: @@ -337,7 +360,7 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)  		return -EINVAL;  	}  	if (DRM_COPY_TO_USER(value_ptr, &value, sizeof(uint32_t))) { -		DRM_ERROR("copy_to_user\n"); +		DRM_ERROR("copy_to_user %s:%u\n", __func__, __LINE__);  		return -EFAULT;  	}  	return 0; diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index d5fd615897e..94b4a1c1289 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -1025,9 +1025,11 @@ static int radeon_crtc_mode_set(struct drm_crtc *crtc,  static void radeon_crtc_prepare(struct drm_crtc *crtc)  { +	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);  	struct drm_device *dev = crtc->dev;  	struct drm_crtc *crtci; +	radeon_crtc->in_mode_set = true;  	/*  	* The hardware wedges sometimes if you reconfigure one CRTC  	* whilst another is running (see fdo bug #24611). @@ -1038,6 +1040,7 @@ static void radeon_crtc_prepare(struct drm_crtc *crtc)  static void radeon_crtc_commit(struct drm_crtc *crtc)  { +	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);  	struct drm_device *dev = crtc->dev;  	struct drm_crtc *crtci; @@ -1048,6 +1051,7 @@ static void radeon_crtc_commit(struct drm_crtc *crtc)  		if (crtci->enabled)  			radeon_crtc_dpms(crtci, DRM_MODE_DPMS_ON);  	} +	radeon_crtc->in_mode_set = false;  }  static const struct drm_crtc_helper_funcs legacy_helper_funcs = { diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index f380d59c576..d56978949f3 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -275,6 +275,7 @@ struct radeon_crtc {  	u16 lut_r[256], lut_g[256], lut_b[256];  	bool enabled;  	bool can_tile; +	bool in_mode_set;  	uint32_t crtc_offset;  	struct drm_gem_object *cursor_bo;  	uint64_t cursor_addr; diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 1f1a4c803c1..9024e722283 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -52,11 +52,7 @@ void radeon_bo_clear_va(struct radeon_bo *bo)  	list_for_each_entry_safe(bo_va, tmp, &bo->va, bo_list) {  		/* remove from all vm address space */ -		mutex_lock(&bo_va->vm->mutex); -		list_del(&bo_va->vm_list); -		mutex_unlock(&bo_va->vm->mutex); -		list_del(&bo_va->bo_list); -		kfree(bo_va); +		radeon_vm_bo_rmv(bo->rdev, bo_va->vm, bo);  	}  } @@ -136,6 +132,7 @@ int radeon_bo_create(struct radeon_device *rdev,  	acc_size = ttm_bo_dma_acc_size(&rdev->mman.bdev, size,  				       sizeof(struct radeon_bo)); +retry:  	bo = kzalloc(sizeof(struct radeon_bo), GFP_KERNEL);  	if (bo == NULL)  		return -ENOMEM; @@ -149,8 +146,6 @@ int radeon_bo_create(struct radeon_device *rdev,  	bo->surface_reg = -1;  	INIT_LIST_HEAD(&bo->list);  	INIT_LIST_HEAD(&bo->va); - -retry:  	radeon_ttm_placement_from_domain(bo, domain);  	/* Kernel allocation are uninterruptible */  	down_read(&rdev->pm.mclk_lock); diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index ec79b375043..43c431a2686 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -706,6 +706,7 @@ int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *ring, unsig  	if (radeon_debugfs_ring_init(rdev, ring)) {  		DRM_ERROR("Failed to register debugfs file for rings !\n");  	} +	radeon_ring_lockup_update(ring);  	return 0;  } diff --git a/drivers/gpu/drm/radeon/reg_srcs/r600 b/drivers/gpu/drm/radeon/reg_srcs/r600 index 5e659b034d9..20bfbda7b3f 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/r600 +++ b/drivers/gpu/drm/radeon/reg_srcs/r600 @@ -744,15 +744,6 @@ r600 0x9400  0x00028C38 CB_CLRCMP_DST  0x00028C3C CB_CLRCMP_MSK  0x00028C34 CB_CLRCMP_SRC -0x00028100 CB_COLOR0_MASK -0x00028104 CB_COLOR1_MASK -0x00028108 CB_COLOR2_MASK -0x0002810C CB_COLOR3_MASK -0x00028110 CB_COLOR4_MASK -0x00028114 CB_COLOR5_MASK -0x00028118 CB_COLOR6_MASK -0x0002811C CB_COLOR7_MASK -0x00028808 CB_COLOR_CONTROL  0x0002842C CB_FOG_BLUE  0x00028428 CB_FOG_GREEN  0x00028424 CB_FOG_RED diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index a12fbcc8ccb..aa8ef491ef3 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -281,12 +281,8 @@ int rv515_debugfs_ga_info_init(struct radeon_device *rdev)  void rv515_mc_stop(struct radeon_device *rdev, struct rv515_mc_save *save)  { -	save->d1vga_control = RREG32(R_000330_D1VGA_CONTROL); -	save->d2vga_control = RREG32(R_000338_D2VGA_CONTROL);  	save->vga_render_control = RREG32(R_000300_VGA_RENDER_CONTROL);  	save->vga_hdp_control = RREG32(R_000328_VGA_HDP_CONTROL); -	save->d1crtc_control = RREG32(R_006080_D1CRTC_CONTROL); -	save->d2crtc_control = RREG32(R_006880_D2CRTC_CONTROL);  	/* Stop all video */  	WREG32(R_0068E8_D2CRTC_UPDATE_LOCK, 0); @@ -311,15 +307,6 @@ void rv515_mc_resume(struct radeon_device *rdev, struct rv515_mc_save *save)  	/* Unlock host access */  	WREG32(R_000328_VGA_HDP_CONTROL, save->vga_hdp_control);  	mdelay(1); -	/* Restore video state */ -	WREG32(R_000330_D1VGA_CONTROL, save->d1vga_control); -	WREG32(R_000338_D2VGA_CONTROL, save->d2vga_control); -	WREG32(R_0060E8_D1CRTC_UPDATE_LOCK, 1); -	WREG32(R_0068E8_D2CRTC_UPDATE_LOCK, 1); -	WREG32(R_006080_D1CRTC_CONTROL, save->d1crtc_control); -	WREG32(R_006880_D2CRTC_CONTROL, save->d2crtc_control); -	WREG32(R_0060E8_D1CRTC_UPDATE_LOCK, 0); -	WREG32(R_0068E8_D2CRTC_UPDATE_LOCK, 0);  	WREG32(R_000300_VGA_RENDER_CONTROL, save->vga_render_control);  } diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index c053f819377..0139e227e3c 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -1639,11 +1639,19 @@ static void si_gpu_init(struct radeon_device *rdev)  		/* XXX what about 12? */  		rdev->config.si.tile_config |= (3 << 0);  		break; -	} -	if ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) -		rdev->config.si.tile_config |= 1 << 4; -	else +	}	 +	switch ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) { +	case 0: /* four banks */  		rdev->config.si.tile_config |= 0 << 4; +		break; +	case 1: /* eight banks */ +		rdev->config.si.tile_config |= 1 << 4; +		break; +	case 2: /* sixteen banks */ +	default: +		rdev->config.si.tile_config |= 2 << 4; +		break; +	}  	rdev->config.si.tile_config |=  		((gb_addr_config & PIPE_INTERLEAVE_SIZE_MASK) >> PIPE_INTERLEAVE_SIZE_SHIFT) << 8;  	rdev->config.si.tile_config |= @@ -3960,3 +3968,22 @@ void si_fini(struct radeon_device *rdev)  	rdev->bios = NULL;  } +/** + * si_get_gpu_clock - return GPU clock counter snapshot + * + * @rdev: radeon_device pointer + * + * Fetches a GPU clock counter snapshot (SI). + * Returns the 64 bit clock counter snapshot. + */ +uint64_t si_get_gpu_clock(struct radeon_device *rdev) +{ +	uint64_t clock; + +	mutex_lock(&rdev->gpu_clock_mutex); +	WREG32(RLC_CAPTURE_GPU_CLOCK_COUNT, 1); +	clock = (uint64_t)RREG32(RLC_GPU_CLOCK_COUNT_LSB) | +	        ((uint64_t)RREG32(RLC_GPU_CLOCK_COUNT_MSB) << 32ULL); +	mutex_unlock(&rdev->gpu_clock_mutex); +	return clock; +} diff --git a/drivers/gpu/drm/radeon/sid.h b/drivers/gpu/drm/radeon/sid.h index 7869089e876..ef4815c27b1 100644 --- a/drivers/gpu/drm/radeon/sid.h +++ b/drivers/gpu/drm/radeon/sid.h @@ -698,6 +698,9 @@  #define RLC_UCODE_ADDR                                    0xC32C  #define RLC_UCODE_DATA                                    0xC330 +#define RLC_GPU_CLOCK_COUNT_LSB                           0xC338 +#define RLC_GPU_CLOCK_COUNT_MSB                           0xC33C +#define RLC_CAPTURE_GPU_CLOCK_COUNT                       0xC340  #define RLC_MC_CNTL                                       0xC344  #define RLC_UCODE_CNTL                                    0xC348  |