diff options
| -rw-r--r-- | linux-core/radeon_gem.c | 180 | ||||
| -rw-r--r-- | shared-core/radeon_cp.c | 2 | ||||
| -rw-r--r-- | shared-core/radeon_drv.h | 1 | 
3 files changed, 180 insertions, 3 deletions
| diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index c0218a3f..58162e52 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -707,6 +707,176 @@ int radeon_alloc_gart_objects(struct drm_device *dev)  } +static bool avivo_get_mc_idle(struct drm_device *dev) +{ +	drm_radeon_private_t *dev_priv = dev->dev_private; + +	if (dev_priv->chip_family >= CHIP_R600) { +		/* no idea where this is on r600 yet */ +		return true; +	} else if (dev_priv->chip_family == CHIP_RV515) { +		if (radeon_read_mc_reg(dev_priv, RV515_MC_STATUS) & RV515_MC_STATUS_IDLE) +			return true; +		else +			return false; +	} else if (dev_priv->chip_family == CHIP_RS600) { +		if (radeon_read_mc_reg(dev_priv, RS600_MC_STATUS) & RS600_MC_STATUS_IDLE) +			return true; +		else +			return false; +	} else if ((dev_priv->chip_family == CHIP_RS690) || +		   (dev_priv->chip_family == CHIP_RS740)) { +		if (radeon_read_mc_reg(dev_priv, RS690_MC_STATUS) & RS690_MC_STATUS_IDLE) +			return true; +		else +			return false; +	} else { +		if (radeon_read_mc_reg(dev_priv, R520_MC_STATUS) & R520_MC_STATUS_IDLE) +			return true; +		else +			return false; +	} +} + + +static void avivo_disable_mc_clients(struct drm_device *dev) +{ +	drm_radeon_private_t *dev_priv = dev->dev_private; +	uint32_t tmp; +	int timeout; + +	radeon_do_wait_for_idle(dev_priv); + +	RADEON_WRITE(AVIVO_D1VGA_CONTROL, RADEON_READ(AVIVO_D1VGA_CONTROL) & ~AVIVO_DVGA_CONTROL_MODE_ENABLE); +	RADEON_WRITE(AVIVO_D2VGA_CONTROL, RADEON_READ(AVIVO_D2VGA_CONTROL) & ~AVIVO_DVGA_CONTROL_MODE_ENABLE); + +	tmp = RADEON_READ(AVIVO_D1CRTC_CONTROL);	 +	RADEON_WRITE(AVIVO_D1CRTC_CONTROL, tmp & ~AVIVO_CRTC_EN); + +	tmp = RADEON_READ(AVIVO_D2CRTC_CONTROL);	 +	RADEON_WRITE(AVIVO_D2CRTC_CONTROL, tmp & ~AVIVO_CRTC_EN); + +	tmp = RADEON_READ(AVIVO_D2CRTC_CONTROL); + +	udelay(1000); + +	timeout = 0; +	while (!(avivo_get_mc_idle(dev))) { +		if (++timeout > 100000) { +			DRM_ERROR("Timeout waiting for memory controller to update settings\n"); +			DRM_ERROR("Bad things may or may not happen\n"); +		} +		udelay(10); +	} +} + +static inline u32 radeon_busy_wait(struct drm_device *dev, uint32_t reg, uint32_t bits, +				  unsigned int timeout) +{ +	drm_radeon_private_t *dev_priv = dev->dev_private; +	u32 status; + +	do { +		udelay(10); +		status = RADEON_READ(reg); +		timeout--; +	} while(status != 0xffffffff && (status & bits) && (timeout > 0)); + +	if (timeout == 0) +		status = 0xffffffff; +	      +	return status; +} + +/* Wait for vertical sync on primary CRTC */ +static void radeon_wait_for_vsync(struct drm_device *dev) +{ +	drm_radeon_private_t *dev_priv = dev->dev_private; +	uint32_t       crtc_gen_cntl; +	int ret; + +	crtc_gen_cntl = RADEON_READ(RADEON_CRTC_GEN_CNTL); +	if ((crtc_gen_cntl & RADEON_CRTC_DISP_REQ_EN_B) || +	    !(crtc_gen_cntl & RADEON_CRTC_EN)) +		return; + +	/* Clear the CRTC_VBLANK_SAVE bit */ +	RADEON_WRITE(RADEON_CRTC_STATUS, RADEON_CRTC_VBLANK_SAVE_CLEAR); + +	radeon_busy_wait(dev, RADEON_CRTC_STATUS, RADEON_CRTC_VBLANK_SAVE, 2000); + +} + +/* Wait for vertical sync on primary CRTC */ +static void radeon_wait_for_vsync2(struct drm_device *dev) +{ +	drm_radeon_private_t *dev_priv = dev->dev_private; +	uint32_t       crtc2_gen_cntl; +	struct timeval timeout; + +	crtc2_gen_cntl = RADEON_READ(RADEON_CRTC2_GEN_CNTL); +	if ((crtc2_gen_cntl & RADEON_CRTC2_DISP_REQ_EN_B) || +	    !(crtc2_gen_cntl & RADEON_CRTC2_EN)) +		return; + +	/* Clear the CRTC_VBLANK_SAVE bit */ +	RADEON_WRITE(RADEON_CRTC2_STATUS, RADEON_CRTC2_VBLANK_SAVE_CLEAR); + +	radeon_busy_wait(dev, RADEON_CRTC2_STATUS, RADEON_CRTC2_VBLANK_SAVE, 2000); +} + +static void legacy_disable_mc_clients(struct drm_device *dev) +{ +	drm_radeon_private_t *dev_priv = dev->dev_private; +	uint32_t old_mc_status, status_idle; +	uint32_t ov0_scale_cntl, crtc_ext_cntl, crtc_gen_cntl, crtc2_gen_cntl; +	uint32_t status; + +	radeon_do_wait_for_idle(dev_priv); + +	if (dev_priv->flags & RADEON_IS_IGP) +		return; + +	old_mc_status = RADEON_READ(RADEON_MC_STATUS); + +	/* stop display and memory access */ +	ov0_scale_cntl = RADEON_READ(RADEON_OV0_SCALE_CNTL); +	RADEON_WRITE(RADEON_OV0_SCALE_CNTL, ov0_scale_cntl & ~RADEON_SCALER_ENABLE); +	crtc_ext_cntl = RADEON_READ(RADEON_CRTC_EXT_CNTL); +	RADEON_WRITE(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl | RADEON_CRTC_DISPLAY_DIS); +	crtc_gen_cntl = RADEON_READ(RADEON_CRTC_GEN_CNTL); + +	radeon_wait_for_vsync(dev); + +	RADEON_WRITE(RADEON_CRTC_GEN_CNTL, +		     (crtc_gen_cntl & ~(RADEON_CRTC_CUR_EN | RADEON_CRTC_ICON_EN)) | +		     RADEON_CRTC_DISP_REQ_EN_B | RADEON_CRTC_EXT_DISP_EN); + +	if (!(dev_priv->flags & RADEON_SINGLE_CRTC)) { +		crtc2_gen_cntl = RADEON_READ(RADEON_CRTC2_GEN_CNTL); + +		radeon_wait_for_vsync2(dev); +		RADEON_WRITE(RADEON_CRTC2_GEN_CNTL, +			     (crtc2_gen_cntl &  +			      ~(RADEON_CRTC2_CUR_EN | RADEON_CRTC2_ICON_EN)) | +			     RADEON_CRTC2_DISP_REQ_EN_B); +	} + +	udelay(500); + +	if (radeon_is_r300(dev_priv)) +		status_idle = R300_MC_IDLE; +	else +		status_idle = RADEON_MC_IDLE; + +	status = radeon_busy_wait(dev, RADEON_MC_STATUS, status_idle, 200000); +	if (status == 0xffffffff) { +		DRM_ERROR("Timeout waiting for memory controller to update settings\n"); +		DRM_ERROR("Bad things may or may not happen\n"); +	} +} + +  void radeon_init_memory_map(struct drm_device *dev)  {  	drm_radeon_private_t *dev_priv = dev->dev_private; @@ -776,6 +946,14 @@ void radeon_init_memory_map(struct drm_device *dev)  	else  		dev_priv->fb_location = (dev_priv->mc_fb_location & 0xffff) << 16; +	/* updating mc regs here */ +	if (radeon_is_avivo(dev_priv)) +		avivo_disable_mc_clients(dev); +	else +		legacy_disable_mc_clients(dev); + +	radeon_write_fb_location(dev_priv, dev_priv->mc_fb_location); +  	if (radeon_is_avivo(dev_priv)) {  		if (dev_priv->chip_family >= CHIP_R600)   			RADEON_WRITE(R600_HDP_NONSURFACE_BASE, (dev_priv->mc_fb_location << 16) & 0xff0000); @@ -783,8 +961,6 @@ void radeon_init_memory_map(struct drm_device *dev)  			RADEON_WRITE(AVIVO_HDP_FB_LOCATION, dev_priv->mc_fb_location);  	} -	radeon_write_fb_location(dev_priv, dev_priv->mc_fb_location); -  	dev_priv->fb_location = (radeon_read_fb_location(dev_priv) & 0xffff) << 16;  	dev_priv->fb_size =  		((radeon_read_fb_location(dev_priv) & 0xffff0000u) + 0x10000) diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 8fc43756..63957cd7 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -356,7 +356,7 @@ static int radeon_do_wait_for_fifo(drm_radeon_private_t * dev_priv, int entries)  	return -EBUSY;  } -static int radeon_do_wait_for_idle(drm_radeon_private_t * dev_priv) +int radeon_do_wait_for_idle(drm_radeon_private_t * dev_priv)  {  	int i, ret; diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 96f9a98c..82d9d001 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -491,6 +491,7 @@ extern struct drm_buf *radeon_freelist_get(struct drm_device * dev);  extern int radeon_wait_ring(drm_radeon_private_t * dev_priv, int n); +extern int radeon_do_wait_for_idle(drm_radeon_private_t * dev_priv);  extern int radeon_do_cp_idle(drm_radeon_private_t * dev_priv);  extern int radeon_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv); | 
